Welcome to MSDN Blogs Sign in | Join | Help

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

Published Saturday, April 14, 2007 9:35 PM by PowerShellTeam

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: Controlling the Scope of Variables

Maybe we should start our powershell software development a bit easier :) The Private statement in VBScript is concerned with classes; we’re going to take the liberty of extending the definition of Private here, primarily because we aren’t going to talk about classes. Instead of talking about private variables in terms of classes, we’re going to talk about private variables in terms of scope.

In Windows PowerShell all you have to do is set the scope to Private. For example, this command creates a variable named $a with the scope set to private. Note that, when specifying a scope, you do not preface the variable name with a $; however, in your commands you will still refer to this variable as $a.

Here’s the command:

$Private:a = 5

Because this is a private variable it will be available only in the scope in which it was created. If you type $a from the command prompt you’ll get back the value of $a. However, if you run a script that simply echoes back the value of $a you won’t get back anything; that’s because, as a private variable, $a is not available outside the command shell scope.

Saturday, April 14, 2007 4:55 PM by netvance

# re: PS blogger

Dear PS,

   Do you have an email address?

Saturday, April 14, 2007 5:16 PM by james beard

# Interesting Finds: April 15, 2007

Sunday, April 15, 2007 10:44 AM by Jason Haley

# re: Controlling the Scope of Variables

First let me say that PowerShell has REALLY helped me and my company.

We have used the tool to do some very interesting things!

Kudos to the entire PSH development team.

But the scoping rules described above are 'unexpected'.

>"This is soooo powerful."

Yes, it is powerful, but it is also error-prone.  Along with

"GOTO considered harmful" we have over the years learned that

global variables are harmful if not used carefully and sparingly.

Being able to control the scope of variables and avoid unintended

access to variables is something that experienced programmers

have come to rely upon.

It could be that my concern is due to my use of PowerShell in a

manner that is not entirely as the authors intended.

I'm using it as a scripting language (on steroids!) and not so

much as a "shell".   Used as a shell, the above scoping concepts

are surely powerful and helpful.  But when my scripts get to be

a couple hundred lines of code, I begin to have reservations

about the PowerShell scoping rules.  

Yes, the scoping rules allow some very clever tasks to be accomplished.

I suppose 'with power comes responsibility' and we just need

to be diligent in our use of scoping prefixes ($global:foo).

Thursday, April 19, 2007 11:50 AM by Clift Norris

# Fun with Paths

Jeffrey wrote a great post for wizards about the scope of variables in PowerShell, so to maintain balance,

Friday, April 27, 2007 5:21 PM by Windows PowerShell

# Line Count with PowerShell

Starting to get the hang of PowerShell. Today I wanted to quickly count the number of lines in some source

Tuesday, October 23, 2007 12:18 AM by code-o-rama

# re: Controlling the Scope of Variables

First off, excellent article.  It's exactly the answer to what I was wondering about scoping in PowerShell.

Clift, if you're still following this, what is your concern, specifically?  All variables are local in scope by default, so it's not like all variables are being made global, and anyone who is familiar with a scripting language should be familiar with the concept of having variables inherit down the scope.  I don't think anyone will be accidentally setting up-scoped variables, given the default syntax, so am I missing something (entirely possible)?

Monday, June 23, 2008 11:33 PM by Tim Johnson

Leave a Comment

(required) 
required 
(required) 
 
Page view tracker