tags:

views:

27

answers:

1

I am trying to figure out how ScriptBlock.GetNewClosure() works. Based on this thread (see Stej's answer) I have this code:

$i = 1
$block1 = 
{
    $i
}

$i = 2
$block2 = 
{
    $i
}

$i = 3
$block3 = 
{
    $i
}


& $block1
& $block2
& $block3

The output is:

3
3
3

which is expected, because when the ScriptBlocks are executed the current $i value is used. This can be changed using GetNewClosure():

$i = 1
$block1 = 
{
    $i
}.GetNewClosure()

$i = 2
$block2 = 
{
    $i
}.GetNewClosure()

$i = 3
$block3 = 
{
    $i
}.GetNewClosure()


& $block1
& $block2
& $block3

This time the output is:

1
2
3

This is good, but when I try to star the ScriptBlocks as jobs:

$i = 1
$block1 = 
{
    $i
}.GetNewClosure()

$i = 2
$block2 = 
{
    $i
}.GetNewClosure()

$i = 3
$block3 = 
{
    $i
}.GetNewClosure()


$job1 = Start-Job $block1
$job1 | Wait-Job 
$job1 | Receive-Job

$job2 = Start-Job $block2
$job2 | Wait-Job 
$job2 | Receive-Job

$job3 = Start-Job $block3
$job3 | Wait-Job 
$job3 | Receive-Job

There is no output. Searching for an answer, I found this thread, where x0n says that jobs are executed in a dynamic module. Modules have isolated sessionstate, and share access to globals. PowerShell closures only work within the same sessionstate / scope chain

Does this mean that $i is not accessible from jobs? When I test its value:

$i = 1
$block1 = 
{
    $i -eq $null
}.GetNewClosure()

$i = 2
$block2 = 
{
    $i -eq $null
}.GetNewClosure()

$i = 3
$block3 = 
{
    $i -eq $null
}.GetNewClosure()


$job1 = Start-Job $block1
$job1 | Wait-Job 
$job1 | Receive-Job

$job2 = Start-Job $block2
$job2 | Wait-Job 
$job2 | Receive-Job

$job3 = Start-Job $block3
$job3 | Wait-Job 
$job3 | Receive-Job

$ is equal to null.

+3  A: 

Yes, it means that $i is not accessible from jobs in this way. Unfortunately. So, use another way: for example, param in a script block to be invoked as a job and ArgumentList parameter of Start-Job:

$i = 42
$block1 =
{
    param($i)
    $i * 2
}

$job1 = Start-Job $block1 -ArgumentList $i
$job1 | Wait-Job | Receive-Job

Output:

84

P.S. It is reported that GetNewClosure also does not work with Register-ObjectEvent: https://connect.microsoft.com/PowerShell/feedback/details/541754/getnewclosure-doesnt-work-on-register-objectevent

Roman Kuzmin
Thank you for the answer. Is this behavior documented by Microsoft?
Uros Calakovic
Well, I would say it is a legal feature but the documentation about it might be better. BTW, instead of `param` in a script block you can just use `$args`.
Roman Kuzmin
Thank you again.
Uros Calakovic