[NoBrainer] How to easily pass parameters to a script in a PowerShell job

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!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: