PowerShell Scoping - Revisited
- Details
- Written by David Corrales
- Last Updated: 14 November 2017
- Created: 10 April 2013
- Hits: 11884
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:
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:
First Rule of PowerShell Scoping Article
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.