Powershell - how to pre-evaluate variables in a scriptblock for Start-Job
Asked Answered
B

4

21

I want to use background jobs in Powershell.

How to make variables evaluated at the moment of ScriptBlock definition?

$v1 = "123"
$v2 = "asdf"

$sb = {
    Write-Host "Values are: $v1, $v2"
}

$job = Start-Job -ScriptBlock $sb

$job | Wait-Job | Receive-Job

$job | Remove-Job

I get printed empty values of $v1 and $v2. How can I have them evaluated in (passed to) the scriptblock and so to the background job?

Bakery answered 7/11, 2013 at 11:22 Comment(0)
F
41

One way is to use the [scriptblock]::create method to create the script block from an expanadable string using local variables:

$v1 = "123"
$v2 = "asdf"

$sb = [scriptblock]::Create("Write-Host 'Values are: $v1, $v2'")

$job = Start-Job -ScriptBlock $sb

Another method is to set variables in the InitializationScript:

$Init_Script = {
$v1 = "123"
$v2 = "asdf"
}

$sb = {
    Write-Host "Values are: $v1, $v2"
}

$job = Start-Job -InitializationScript $Init_Script -ScriptBlock $sb 

A third option is to use the -Argumentlist parameter:

$v1 = "123"
$v2 = "asdf"

$sb = {
    Write-Host "Values are: $($args[0]), $($args[1])"
}

$job = Start-Job  -ScriptBlock $sb -ArgumentList $v1,$v2
Foofaraw answered 7/11, 2013 at 11:50 Comment(3)
good use of -InitializationScript, I wasn't aware of that one.Quinque
Commenting here in case someone is searching for an answer to why Register-ScheduledJob complains about a variable in the -ScriptBlock param. Errors seen are Cannot bind argument to parameter 'server' because it is an empty string. and to resolve it, I used $script = [ScriptBlock]::Create("") then Register-ScheduledJob -ScriptBlock $script and its confirmed working by using Get-ScheduledJob | Select *Fransiscafransisco
[scriptblock]::Create - note: You can block variables from evaluation by escaping them. ex: $varToEvaluate ='foo'; [scriptblock]::Create("`$_.$varToEvaluate") Results in : $_.fooBacteriolysis
M
18

The simplest solution (which requires V3 or greater) looks like this:

$v1 = "123"
$v2 = "asdf"

$sb = {
     Write-Host "Values are: $using:v1, $using:v2"
}

$job = Start-Job -ScriptBlock $sb

You can think of $using as working roughly like an explicit param() block and passing -ArgumentList, only PowerShell handles that for you automatically.

Muckraker answered 7/11, 2013 at 20:38 Comment(1)
$using worked fine for me. I wonder how to pass global variables that way. Will $using:global:v1 work?Foam
Q
4

Declare the values as parameters in the script block, then pass them in using -ArgumentList

$v1 = "123"
$v2 = "asdf"

$sb = {
    param
    (
        $v1,
        $v2
    )
    Write-Host "Values are: $v1, $v2"
}

$job = Start-Job -ScriptBlock $sb -ArgumentList $v1, $v2

$job | Wait-Job | Receive-Job

$job | Remove-Job
Quinque answered 7/11, 2013 at 11:48 Comment(0)
P
2

I'm not at a computer to validate, but this should work:

$sb = {
    param($p1,$p2)
    Write-Host "Values are: $p1, $p2"
}

$job = Start-Job -ScriptBlock $sb -ArgumentList $v1,$v2

I'll double check this when I get into work.

Piteous answered 7/11, 2013 at 11:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.