I'm having trouble understanding scopes within ScriptBlock
s. I was counting on some kind of closure-like system, but I can't seem to get it working.
I have a ScriptBlock
that takes a param
and returns another ScriptBlock
:
$sb1 = {
Param($Message1);
Write-Host $Message1;
{
Param($Message2);
Write-Host ($Message1 + " " + $Message2);
}
}
To get the inner ScriptBlock
I can invoke $sb1
with $sb2 = & $sb1 -Message1 "Message1"
. This echoes Message1
so we know the param
is bound.
Now I can invoke $sb2
with & $sb2 -Message2 "Message2"
. I would have expected Message1 Message2
, but it just writes Message2
instead.
Is there any way to access the $Message1
variable? I can't use a local or script variable, because there will multiple instances of the inner scriptblock with different $Message1
s.
This is the actual output from the actual shell:
PS C:\> $h1 = { Param($Message1); Write-Host $Message1; { Param($Message2); Write-Host ($Message1 + " " + $Message2); } }
PS C:\> $h2 = & $h1 -Message1 "Message1"
Message1
PS C:\> $h2
Param($Message2); Write-Host ($Message1 + " " + $Message2);
PS C:\> & $h2 -Message2 "Message2"
Message2
PowerShell scope protects variables and other artifacts by limiting where they can be read and modified. Scope levels protect items that should not be changed. PowerShell has the following scopes available: Global: This scope is available when you open a PowerShell console or create a new runspace or session.
In the PowerShell programming language, a script block is a collection of statements or expressions that can be used as a single unit. A script block can accept arguments and return values. A script block returns the output of all the commands in the script block, either as a single object or as an array.
To declare a PowerShell global variable, simply use the below syntax. $global: myVariable ="This is my first global variable." If you choose not to give any value to it, you can explicitly assign a null value to it.
Global: The scope that is in effect when PowerShell starts or when you create a new session or runspace. Variables and functions that are present when PowerShell starts have been created in the global scope, such as automatic variables and preference variables.
You need to explicitly create a closure:
$sb1 = {
Param($Message1);
Write-Host $Message1;
{
Param($Message2);
Write-Host ($Message1 + " " + $Message2);
}.GetNewClosure()
}
It then works for me:
PS> $2 = & $sb1 One
One
PS> & $2 Two
One Two
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With