PowerShell Scoping – Revisited

April 10th, 2013 by David Corrales
Last updated on April 10th, 2013

 

Yes, we said we would not speak of it again, but a user post provided a good example of the change in scoping rules between PowerShell V2 and V3.

This particular user had a question about GUI controls on our new PowerShell GUIs forum and provided an example GUI script. In the example, the user declared a function inside an event script block:


$OnLoadFormEvent={
#TODO: Initialize Form Controls here

    $t = dir c:\PowerShell\ 
    $t2 = dir c:\Scoping\
    
    function outTextBox1($textOut)
    {
        $richtextbox1.Text = $richtextbox1.Text + $textOut    
    }
}

This script block is called when the GUI Window is about to display.

Inside another script block the user calls the same function:

$button1_Click={
    outTextBox1 $t
}

This script block is called when a button is pressed.

Can you spot the potential scoping issues?

Now let’s look at how PowerShell V2 and V3 handle this situation.

PowerShell V2

The funny thing is when you run the GUI script in PowerShell V2,  the script runs and you are able to successfully call the function from the button_Click script block despite the function being declared locally in OnLoadFormEvent script block. I would consider this a bug in V2 but it works nonetheless.

Note: In this case, OnLoadFormEvent script block is always executed before the button is pressed. If this wasn’t the case, and the Click script block was called before the OnLoadFormEvent script block, then the function would have never been declared and the call would result in an error.

 

PowerShell V3

Now if you run the same script in PowerShell V3, the function call in the second script block results in an error no matter the order you call the script blocks:

image

This occurs because the outTextBox1 in V3 is treated as a local scope function instead of a script scope function as in V2. In addition, the $t variable will return a null value for the very same reason.

 

How do you resolve this?

You can resolve this issue by either:

1. Specify the scope of the function when you declare it.

function script:outTextBox1($textOut)
{
    $richtextbox1.Text = $richtextbox1.Text + $textOut    
}

2. Better still is to move the declaration of the function outside of the event script block (that is unless you are  exclusively using it in the same event script block).

 

The updated script:

#declare the function before you call it
function outTextBox1($textOut)
{
    $richtextbox1.AppendText($textOut)    
}

$OnLoadFormEvent={
#TODO: Initialize Form Controls here
    $script:t = dir c:\PowerShell\ 
    $script:t2 = dir c:\Scoping\
}

$button1_Click={
    outTextBox1 $script:t
}

As you can see I moved the declaration outside of the script block and I updated the variables to use the script scope. In addition, I took the liberty of improving the outTextBox1 function as well.

 

Related Links:

Original Forum Post:

http://www.sapien.com/forums/viewtopic.php?f=21&t=6473&sid=b346662857f3ce0f5ed18ce0a6ed447d

 

First Rule of PowerShell Scoping Blog Article:

http://www.sapien.com/blog/2013/03/06/first-rule-of-powershell-scoping-rules/

 

 
[Google+]   [Facebook]   [LinkedIn]   [StumbleUpon]   [Digg]   [Reddit]   [Google Bookmark]  

Tags: , , , , ,