Today I had to pass a long list of parameters to a Cmdlet inside a PowerShell job. At first it looked like this, which seemed rather horrbile (i.e. unreadable) to me.
$argList = @() $argList += $VMName $argList += $nic1Mac $argList += $OSDOperatingSystemType $argList += $strNetSpd $argList += $strDomain $argList += $strEmail $argList += $DODNSSuffix $argList += $Gateway $argList += $IpAddr $argList += $Subnet $argList += $PrimDNS $argList += $SeconDNS $argList += $SCCMSiteCode $argList += $targetCollectionName $argList += $strAppTree $argList += $strAppProf $argList += $strBypassChoose $argList += $CumulusWinFeatures $Job = Start-Job -Credential $CredentialSccm -ScriptBlock { Register-SccmVirtualMachine -static -strADName $args[0] -strnmac $args[1] -OSDOperatingSystemType $args[2] -strNetSpd $args[3] -strDomain $args[4] -strEmail $args[5] -DODNSSuffix $args[6] -DOgateway $args[7] -DOipAddress $args[8] -DOsubnetMask $args[9] -DOStaticDNS1 $args[10] -DOStaticDNS2 $args[11] -SCCMSiteCode $args[12] -targetCollectionName $args[13] -strAppTree $args[14] -strAppProf $args[15] -strBypassChoose $args[16] -CumulusWinFeatures $args[17]} -ArgumentList $argList; $null = Wait-Job -Job $job;
There had to be a cleaner approach to this – and so it was … there are some samples around the Internet on how to use the Start-Job Cmdlet and pass parameters to it, I actually had to play a little bit with it before I got it to work the way I wanted.
So here is some very simplified sample code using Write-Host
(using PowerShell 3.0):
#Create hashtable with parameters and their values $Arguments = @{ Object="Testing..."; ForegroundColor="Red"; BackgroundColor="DarkGray" } #Start the Job and pass its parameters. $Job = Start-Job -ScriptBlock { PARAM($Parameters); Write-Host @Parameters; } -ArgumentList $Arguments #Get the results of the Job Receive-Job $Job
So instead of specifying every parameter explicitly I used Splatting (which we already described in a previous post Use splatting to simplify Cmdlet development) to pass the parameters to the script. So you still have to define a hashtable once, but this comes in a much more readable way. This approach really shines, especially when you have a long list of named parameters as it was the case with my example above.
The only ‘tricky’ part is to not only specify ‘ArgumentList’ as a parameter to ‘Start-Job’, but also place a ‘PARAM’ block inside the script block of ‘Start-Job’.
As a side note:
It is not necessary to name the parameter inside the ‘PARAM’ block differently from the variable you specify in ‘ArgumentList’
Start-Job -ScriptBlock {PARAM($Arguments); Write-Host @Arguments} -ArgumentList $Arguments
Side note: if you want to convert your existing scripts into a scriptblock you can do so like this:
$scriptText = Get-Content -Raw -Encoding Default -Path '.\myScript.ps1'; $scriptBlock = [scriptblock]::Create($scriptText); Start-Job $scriptBlock -ArgumentList $Arguments
With this you can test your script(block)s independently from your Start-Job
invocation and more easily maintain your code.
Do you know an even easier way to call ‘Start-Job’ with loads of parameters? Any suggestions and feedback welcome!