Controlling the Scope of Variables

<Wizard Warning – this topic is for wizards. Non-wizards may get confused or hurt themselves.>


PowerShell is …. well … powerful. I don’t think most people have picked up on exactly how powerful it really is. There is nothing wrong with that, we are all about solving problems so if you can get your problem solved using simple techniques – that is the best of all worlds. That said, there are a number of sophisticated applications that are enabled when you explore the power of the tool. Quest’s PowerGui and Full Armor’s PowerShell enabled Workflow tool are two great examples of where someone used the power of the system to do some mind-bendingly wonderful stuff.


So with all that, let’s talk about variables and scopes.


When you create a variable, it is available in that scope and any child scopes. The example below shows how you can define a variable in one scope and access it in a child scope (by calling a function t1) and how it is available in all child scopes (by calling a function t2 which then calls a t1):


PS> function t1 {“X = $x”}
PS> t1
X =
PS> $x=”test”
PS> $x
test
PS> t1
X = test
PS> function t2 { t1 }
PS> t2
X = test
PS>


What is going on here is that each function has a “scope” (stack frame) where variables, aliases, drives, and functions get set. When you access one of these, we look for it in the current scope, if it is there, we use it, if it is not there, we look at the parent’s scope (and upwards until we find the entity or reach to top).


BTW – take a minute to let that soak in. It is not just variables that get set in the scope – we do the same thing for aliases, drives, and functions. Here is an example to illustrate that:


PS> Set-Alias Run-Test Get-Date
PS> Run-Test

Saturday, April 14, 2007 12:16:10 PM


PS> function t1 { Run-Test}
PS> function t2 { Set-Alias Run-Test Get-Location; t1 }
PS> t2

Path
—-
C:\ps


PS> #Notice that Run-Test got OVERRIDDEN vs OVERWRITTEN!
PS> Run-Test

Saturday, April 14, 2007 12:17:51 PM


PS>


This is soooo powerful.


You usually use the syntax above to set variables but this is really just a bit a syntactic sugar for the Set-Variable Cmdlet. The following statements are all equivalent:


PS> $x=5
PS> $x
5
PS> Set-Variable -Name x -Value 5
PS> $x
5
PS> Set-Variable -Name x -Value 5 -Scope 0
PS> $x
5
PS>


Notice the last parameter of the last Set-Variable command (-SCOPE). Let’s explore that a little:


PS> Get-Help Set-Variable -Param Scope

-scope <string>
Specifies the scope from which aliases should be exported. This can be a na
med scope: “global”, “local”, or “script”, or it can be a number relative t
o the current scope (0 through the number of scopes where 0 is the current
scope and 1 is its parent).

Required? false
Position? named
Default value local
Accept pipeline input? false
Accept wildcard characters? false


BTW –Did you realize that you can get help on individual parameters? Is that cool or what? 10,000 thanks to the superstars at Exchange that forced us to prioritize doing a good job on Help.


So now let me show you a couple of examples that you just need to look at, re-read the help above and soak in what is going on:


PS> $x=”Parent”
PS> function t1 {$x}
PS> t1
Parent
PS> # Now we have the function set the variable before reporting it.
PS> # You’ll see that it OVERRIDES the parent.
PS> function t1 {Set-Variable -Name x -Value “Child” -Scope 0; $x}
PS> t1
Child
PS> $x
Parent
PS>
PS> # Now we’ll change the value of SCOPE to 1
PS> # You’ll see that it now OVERWRITES the parent!
PS> function t1 {Set-Variable -Name x -Value “Child” -Scope 1; $x}
PS> t1
Child
PS> #Now watch what happed to $x in the parent scope!
PS> $x
Child


Now be aware, if you provide a “2” to –SCOPE, you’ll set the variable in the grandparent scope and so on.


This is a very powerful technique for metaprogramming scenarios but you can get yourself in trouble if you are not careful.


Cheers!


Jeffrey Snover [MSFT]
Windows Management Partner Architect
Visit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx