Powershell function creation with Set-Item and GetNewClosure

743 views Asked by At

I am attempting to build a function that can itself create functions through the Set-Item command where I pass a scriptblock for the new function to the -Value parameter of Set-Item. I'm running into an issue where using GetNewClosure on the scriptblock doesn't seem to be working and I just don't know what I'm doing wrong.

In the code below, first I'm creating a function manually (testFunc) which works as intended, in that setting $x to 2 after the function creation will not cause the function to return 2; instead it returns 1 because that was the value of $x at the time the function was created. But when I try to do the same through the make-function function, the behavior changes.

I'm sure I'm overlooking something small.

> $x = 1
> $block = {$x}.GetNewClosure()
> Set-Item function:global:testFunc -Value $block
> testFunc
1 

> $x = 2
> testFunc
1 # still 1 because of GetNewClosure - this is expected behavior

> $x = 1
> function make-function { $block2 = {$x}.GetNewClosure()
       Set-Item function:global:testFunc2 -Value $block2
  }
> make-function
> testFunc2
1 

> $x = 2
> testFunc2
2 # Why is it not returning 1 in this case? 
1

There are 1 answers

2
Keith Hill On BEST ANSWER

The clue is in the MSDN docs but it is subtle:

Any local variables that are in the context of the caller are copied into the module.

GetNewClosure() appears to capture "only" local variables i.e those from the caller's current scope. So try this:

function Make-Function {
   $x = $global:x
   $function:global:testFunc2 = {$x}.GetNewClosure()
}

BTW you can see what variables are captured by GetNewClosure() into the newly created dynamic module by executing:

$m = (Get-Command testFunc2).Module
& $m Get-Variable -Scope 0