PowerShell jobs are a powerful tool for running processes in the background. You have to remember that a PowerShell job runs in a separate process that only exists for the duration of the job. The results are returned to your process when the job finishes.
A user on the forum asked about passing variables into jobs. He’d done this:
$w = ‘1..10’
Invoke-Expression $w
and got the expected result
1
2
3
4
5
6
7
8
9
10
He then tried this
Start-Job -ScriptBlock { Invoke-Expression $w}
But the job said
Cannot bind argument to parameter ‘Command’ because it is null.
+ CategoryInfo : InvalidData: (:) [Invoke-Expression], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.InvokeExpre
ssionCommand
+ PSComputerName : localhost
Irrespective of whether using Invoke-Expression is a good idea and I’ll cover that in a future post the job fails because its failing to find $w because the job is running in a separate PowerShell process and $w doesn’t exist.
The simplest answer is to make the job self contained
Start-Job -ScriptBlock { $w = ‘1..10’; Invoke-Expression $w}
Everything is in the script block passed to the job and therefore passed to the new PowerShell process.
Alternatively, you can pass the variable $w into the script block
Start-Job -ScriptBlock { param($w) Invoke-Expression $w} -ArgumentList $w
You need to define a param block on the script block and pass the $w variable to it using the –Argumentlist parameter on start-job.
Another option introduced with PowerShell 3.0 us the $using scope modifier
Start-Job -ScriptBlock { Invoke-Expression $using:w}
Which is another way to say use the $w variable from the current scope
You can find out more on $using from about_scopes, about_Remote_Variables