Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell ScriptBlock variable scope

I'm having trouble understanding scopes within ScriptBlocks. 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 $Message1s.

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
like image 549
wensveen Avatar asked Feb 03 '17 10:02

wensveen


People also ask

Are variables scoped in PowerShell?

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.

What does Scriptblock do in PowerShell?

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.

How do you access global variables in PowerShell?

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.

What is $Global in PowerShell?

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.


1 Answers

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
like image 118
Joey Avatar answered Oct 05 '22 16:10

Joey