about Scopes - PowerShell (2024)

  • Article

Short description

Explains the concept of scope in PowerShell and shows how to set and changethe scope of elements.

Long description

PowerShell protects access to variables, aliases, functions, and PowerShelldrives (PSDrives) by limiting where they can be read and changed. PowerShelluses scope rules to ensure that you don't make unintentional changes to itemsin other scopes.

Scope rules

When you start PowerShell, the host (pwsh.exe) creates a PowerShell runspace.Host processes can have multiple runspaces. Each runspace has its own sessionstate and scope containers. Session state and scopes can't be accessed acrossrunspace instances.

The following are the basic rules of scope:

  • Scopes may nest. An outer scope is referred to as a parent scope. Any nestedscopes are child scopes of that parent.
  • An item is visible in the scope that it was created and in any child scopes,unless you explicitly make it private.
  • You can declare variables, aliases, functions, and PowerShell drives for ascope outside of the current scope.
  • An item that you created within a scope can be changed only in the scope inwhich it was created, unless you explicitly specify a different scope.
  • When code running in a runspace references an item, PowerShell searches thescope hierarchy, starting with the current scope and proceeding through eachparent scope. If the item isn't found, a new item is created in the currentscope. If it finds a match, the value of the item is retrieved from the scopewhere is was found. If you change value, the item copied to the current scopeso that the change only affects the current scope.
  • If you explicitly create an item that shares its name with an item in adifferent scope, the original item might be hidden by the new item, but itisn't overridden or changed.

Parent and child scopes

You can create a new child scope by calling a script or function. The callingscope is the parent scope. The called script or function is the child scope.The functions or scripts you call may call other functions, creating ahierarchy of child scopes whose root scope is the global scope.

Note

Functions from a module don't run in a child scope of the calling scope.Modules have their own session state that's linked to the scope in which themodule was imported. All module code runs in a module-specific hierarchy ofscopes that has its own root scope. For more information, see theModules section of this article.

When a child scope is created, it includes all the aliases and variables thathave the AllScope option, and some automatic variables. This option isdiscussed later in this article.

Unless you explicitly make the items private, the items in the parent scope areavailable to the child scope. Items that you create or change in a child scopedon't affect the parent scope, unless you explicitly specify the scope when youcreate the items.

To find the items in a particular scope, use the Scope parameter ofGet-Variable or Get-Alias.

For example, to get all the variables in the local scope, type:

Get-Variable -Scope local

To get all the variables in the global scope, type:

Get-Variable -Scope global

When a reference is made to a variable, alias, or function, PowerShell searchesthe current scope. If the item isn't found, the parent scope is searched. Thissearch is repeated all they way up to the global scope. If a variable isprivate in a parent scope, the search through continues through the scopechain. Example 4 shows the the effect of a private variable in a scopesearch.

PowerShell scopes names

PowerShell defines names for some scopes to allow easier access to that scope.PowerShell defines the following named scopes:

  • Global: The scope that's in effect when PowerShell starts or when youcreate a new session or runspace. Variables and functions that are presentwhen PowerShell starts, such as automatic variables and preference variables,are created in the global scope. The variables, aliases, and functions inyour PowerShell profiles are also created in the global scope. The globalscope is the root parent scope in a runspace.
  • Local: The current scope. The local scope can be the global scope or anyother scope.
  • Script: The scope that's created while a script file runs. The commandsin the script run in the script scope. For the commands in a script, thescript scope is the local scope.

For cmdlets that support scopes, scopes can be referred to by a number thatdescribes the relative position of one scope to another. Scope 0 denotes thecurrent (local) scope, scope 1 is the current scope's parent, scope 2 is thecurrent scope's grandparent. This pattern continues until you reach the rootscope.

Scope modifiers

A variable, alias, or function name can include any one of the followingoptional scope modifiers:

  • global: - Specifies that the name exists in the Global scope.

  • local: - Specifies that the name exists in the Local scope. The currentscope is always the Local scope.

  • private: - Specifies that the name is Private and only visible to thecurrent scope.

    Note

    private: isn't a scope. It's an option that changes theaccessibility of an item outside of the scope in which it's defined.

  • script: - Specifies that the name exists in the Script scope.Script scope is the nearest ancestor script file's scope or Global ifthere is no nearest ancestor script file.

  • using: - Used to access variables defined in another scope while runningscripts via cmdlets like Start-Job and Invoke-Command.

  • workflow: - Specifies that the name exists within a workflow. Note:Workflows aren't supported in PowerShell v6 and higher.

  • <variable-namespace> - A modifier created by a PowerShell PSDriveprovider. For example:

    NamespaceDescription
    Alias:Aliases defined in the current scope
    Env:Environment variables defined in the current scope
    Function:Functions defined in the current scope
    Variable:Variables defined in the current scope

The default scope for scripts is the script scope. The default scope forfunctions and aliases is the local scope, even if they're defined in ascript.

Using scope modifiers

To specify the scope of a new variable, alias, or function, use a scopemodifier.

The syntax for a scope modifier in a variable is:

$[<scope-modifier>:]<name> = <value>

The syntax for a scope modifier in a function is:

function [<scope-modifier>:]<name> {<function-body>}

The following command, which doesn't use a scope modifier, creates a variablein the current or local scope:

$a = "one"

To create the same variable in the global scope, use the scope global:modifier:

$global:a = "one"Get-Variable a | Format-List *

Notice the Visibility and Options property values.

Name : aDescription :Value : oneVisibility : PublicModule :ModuleName :Options : NoneAttributes : {}

Compare that to a private variable:

$private:pVar = 'Private variable'Get-Variable pVar | Format-List *

Using the private scope modifier sets the Options property to Private.

Name : pVarDescription :Value : Private variableVisibility : PublicModule :ModuleName :Options : PrivateAttributes : {}

To create the same variable in the script scope, use the script: scopemodifier:

$script:a = "one"

You can also use a scope modifier with functions. The following functiondefinition creates a function in the global scope:

function global:Hello { Write-Host "Hello, World"}

You can also use scope modifiers to refer to a variable in a different scope.The following command refers to the $test variable, first in the local scopeand then in the global scope:

$test$global:test

The using: scope modifier

Using is a special scope modifier that identifies a local variable in a remotecommand. Without a modifier, PowerShell expects variables in remote commands tobe defined in the remote session.

The using scope modifier is introduced in PowerShell 3.0.

For any script or command that executes out of session, you need the usingscope modifier to embed variable values from the calling session scope, so thatout of session code can access them. The using scope modifier is supported inthe following contexts:

  • Remotely executed commands, started with Invoke-Command using theComputerName, HostName, SSHConnection or Session parameters(remote session)
  • Background jobs, started with Start-Job (out-of-process session)
  • Thread jobs, started via Start-ThreadJob or ForEach-Object -Parallel(separate thread session)

Depending on the context, embedded variable values are either independentcopies of the data in the caller's scope or references to it. In remote andout-of-process sessions, they're always independent copies.

For more information, see about_Remote_Variables.

In thread sessions, they're passed by reference. This means it's possible tomodify child scope variables in a different thread. To safely modify variablesrequires thread synchronization.

For more information see:

  • Start-ThreadJob
  • ForEach-Object

Serialization of variable values

Remotely executed commands and background jobs run out-of-process.Out-of-process sessions use XML-based serialization and deserialization to makethe values of variables available across the process boundaries. Theserialization process converts objects to a PSObject that contains theoriginal objects properties but not its methods.

For a limited set of types, deserialization rehydrates objects back to theoriginal type. The rehydrated object is a copy of the original object instance.It has the type properties and methods. For simple types, such asSystem.Version, the copy is exact. For complex types, the copy isimperfect. For example, rehydrated certificate objects don't include theprivate key.

Instances of all other types are PSObject instances. The PSTypeNamesproperty contains the original type name prefixed with Deserialized, forexample, Deserialized.System.Data.DataTable

The AllScope Option

Variables and aliases have an Option property that can take a value ofAllScope. Items that have the AllScope property become part of any childscopes that you create, although they aren't retroactively inherited by parentscopes.

An item that has the AllScope property is visible in the child scope, andit's part of that scope. Changes to the item in any scope affect all thescopes in which the variable is defined.

Managing scope

Several cmdlets have a Scope parameter that lets you get or set (create andchange) items in a particular scope. Use the following command to find all thecmdlets in your session that have a Scope parameter:

Get-Help * -Parameter scope

To find the variables that are visible in a particular scope, use the Scopeparameter of Get-Variable. The visible variables include global variables,variables in the parent scope, and variables in the current scope.

For example, the following command gets the variables that are visible in thelocal scope:

Get-Variable -Scope local

To create a variable in a particular scope, use a scope modifier or theScope parameter of Set-Variable. The following command creates a variablein the global scope:

New-Variable -Scope global -Name a -Value "One"

You can also use the Scope parameter of the New-Alias, Set-Alias, orGet-Alias cmdlets to specify the scope. The following command creates analias in the global scope:

New-Alias -Scope global -Name np -Value Notepad.exe

To get the functions in a particular scope, use the Get-Item cmdlet when youare in the scope. The Get-Item cmdlet doesn't have a Scope parameter.

Note

For the cmdlets that use the Scope parameter, you can also refer toscopes by number. The number describes the relative position of one scope toanother. Scope 0 represents the current, or local, scope. Scope 1 indicatesthe immediate parent scope. Scope 2 indicates the parent of the parent scope,and so on. Numbered scopes are useful if you have created many recursivescopes.

Using dot-source notation with scope

Scripts and functions follow the rules of scope. You create them in aparticular scope, and they affect only that scope unless you use a cmdletparameter or a scope modifier to change that scope.

But, you can add the contents of a script or function to the current scopeusing dot-source notation. When you run a script or function using dot-sourcenotation, it runs in the current scope. Any functions, aliases, and variablesin the script or function are added to the current scope.

For example, to run the Sample.ps1 script from the C:\Scripts directory inthe script scope (the default for scripts), just enter the full path to thescript file on the command line.

c:\scripts\sample.ps1

A script file must have a .ps1 file extension to be executable. Files thathave spaces in their path must be enclosed in quotes. If you try to execute thequoted path, PowerShell displays the contents of the quoted string instead ofrunning the script. The call operator (&) allows you to execute the contentsof the string containing the filename.

Using the call operator to run a function or script runs it in script scope.Using the call operator is no different than running the script by name.

& c:\scripts\sample.ps1

You can read more about the call operator in about_Operators.

To run the Sample.ps1 script in the local scope type a dot and a space (. )before the path to the script:

. c:\scripts\sample.ps1

Now, any functions, aliases, or variables defined in the script are added tothe current scope.

Restricting without scope

PowerShell has some options and features that are similar to scope and mayinteract with scopes. These feature may be confused with scope or the behaviorof scope.

Sessions, modules, and nested prompts are self-contained environments, notchild scopes of the global scope in the session.

Sessions

A session is an environment in which PowerShell runs. When you create a sessionon a remote computer, PowerShell establishes a persistent connection to theremote computer. The persistent connection lets you use the session formultiple related commands.

Because a session is a contained environment, it has its own scope, but asession isn't a child scope of the session in which it was created. Thesession starts with its own global scope. This scope is independent of theglobal scope of the session. You can create child scopes in the session. Forexample, you can run a script to create a child scope in a session.

Modules

You can use a PowerShell module to share and deliver PowerShell tools. A moduleis a unit that can contain cmdlets, scripts, functions, variables, aliases, andother useful items. Unless explicitly exported (using Export-ModuleMember orthe module manifest), the items in a module aren't accessible outside themodule. Therefore, you can add the module to your session and use the publicitems without worrying that the other items might override the cmdlets,scripts, functions, and other items in your session.

By default, modules are loaded into the root-level (global) scope of therunspace. Importing a module doesn't change the scope.Within the session, modules have their own scope. Consider the followingmodule C:\temp\mod1.psm1:

$a = "Hello"function foo { "`$a = $a" "`$global:a = $global:a"}

Now we create a global variable $a, give it a value and call the functionfoo.

$a = "Goodbye"foo

The module declares the variable $a in the module scope then the functionfoo outputs the value of the variable in both scopes.

$a = Hello$global:a = Goodbye

Modules create parallel scope containers linked to the scope in which they wereimported. Items exported by the module are available starting at thescope-level in which they are imported. Items not exported from the module areonly available within the module's scope container. Functions in the module canaccess items in the scope in which they were imported as well as items in themodule's scope container.

If you load Module2 from within Module1, Module2 is loaded intothe scope container of Module1. Any exports from Module2 are placed in thecurrent module scope of Module1. If you use Import-Module -Scope local,then the exports are placed into the current scope object rather than at thetop level. If you are in a module and load another module usingImport-Module -Scope global (or Import-Module -Global), that module and itsexports are loaded into the global scope instead of the module's local scope.The WindowsCompatibility feature does this to import proxy modules into theglobal session state.

Nested prompts

Nested prompts don't have their own scope. When you enter a nested prompt, thenested prompt is a subset of the environment. But, you remain within the localscope.

Scripts do have their own scope. If you are debugging a script, and you reach abreakpoint in the script, you enter the script scope.

Private option

Aliases and variables have an Option property that can take a value ofPrivate. Items that have the Private option can be viewed and changed inthe scope in which they're created, but they can't be viewed or changed outsidethat scope.

For example, if you create a variable that has a private option in the globalscope and then run a script, Get-Variable commands in the script don'tdisplay the private variable. Using the global scope modifier in this instancedoesn't display the private variable.

You can use the Option parameter of the New-Variable, Set-Variable,New-Alias, and Set-Alias cmdlets to set the value of the Option property toPrivate.

Visibility

The Visibility property of a variable or alias determines whether you cansee the item outside the container, in which it was created. A container couldbe a module, script, or snap-in. Visibility is designed for containers in thesame way that the Private value of the Option property is designed forscopes.

The Visibility property takes the Public and Private values. Items thathave private visibility can be viewed and changed only in the container inwhich they were created. If the container is added or imported, the items thathave private visibility can't be viewed or changed.

Because visibility is designed for containers, it works differently in a scope.

  • If you create an item that has private visibility in the global scope, youcan't view or change the item in any scope.
  • If you try to view or change the value of a variable that has privatevisibility, PowerShell returns an error message.

You can use the New-Variable and Set-Variable cmdlets to create a variablethat has private visibility.

Examples

Example 1: Change a variable value only in a script

The following command changes the value of the $ConfirmPreference variable ina script. The change doesn't affect the global scope.

First, to display the value of the $ConfirmPreference variable in the localscope, use the following command:

PS> $ConfirmPreferenceHigh

Create a Scope.ps1 script that contains the following commands:

$ConfirmPreference = "Low""The value of `$ConfirmPreference is $ConfirmPreference."

Run the script. The script changes the value of the $ConfirmPreferencevariable and then reports its value in the script scope. The output shouldresemble the following output:

The value of $ConfirmPreference is Low.

Next, test the current value of the $ConfirmPreference variable in the currentscope.

PS> $ConfirmPreferenceHigh

This example shows that changes to the value of a variable in the script scopedoesn't affect the variable`s value in the parent scope.

Example 2: View a variable value in different scopes

You can use scope modifiers to view the value of a variable in the local scopeand in a parent scope.

First, define a $test variable in the global scope.

$test = "Global"

Next, create a Sample.ps1 script that defines the $test variable. In thescript, use a scope modifier to refer to either the global or local versions ofthe $test variable.

In Sample.ps1:

$test = "Local""The local value of `$test is $test.""The global value of `$test is $global:test."

When you run Sample.ps1, the output should resemble the following output:

The local value of $test is Local.The global value of $test is Global.

When the script is complete, only the global value of $test is defined in thesession.

PS> $testGlobal

Example 3: Change the value of a variable in a parent scope

Unless you protect an item using the Private option or another method, you canview and change the value of a variable in a parent scope.

First, define a $test variable in the global scope.

$test = "Global"

Next, create a Sample.ps1 script that defines the $test variable. In thescript, use a scope modifier to refer to either the global or local versions ofthe $test variable.

In Sample.ps1:

$global:test = "Local""The global value of `$test is $global:test."

When the script is complete, the global value of $test is changed.

PS> $testLocal

Example 4: Creating a private variable

A variable can be made private by using the private: scope modifier or bycreating the variable with the Option property set to Private. Privatevariables can only be viewed or changed in the scope in which they werecreated.

In this example, the ScopeExample.ps1 script creates five functions. Thefirst function calls the next function, which creates a child scope. One of thefunctions has a private variable that can only be seen in the scope in which itwas created.

PS> Get-Content ScopeExample.ps1# Start of ScopeExample.ps1function funcA { "Setting `$funcAVar1 to 'Value set in funcA'" $funcAVar1 = "Value set in funcA" funcB}function funcB { "In funcB before set -> '$funcAVar1'" $private:funcAVar1 = "Locally overwrite the value - child scopes can't see me!" "In funcB after set -> '$funcAVar1'" funcC}function funcC { "In funcC before set -> '$funcAVar1' - should be the value set in funcA" $funcAVar1 = "Value set in funcC - Child scopes can see this change." "In funcC after set -> '$funcAVar1'" funcD}function funcD { "In funcD before set -> '$funcAVar1' - should be the value from funcC." $funcAVar1 = "Value set in funcD" "In funcD after set -> '$funcAVar1'" '-------------------' ShowScopes}function ShowScopes { $funcAVar1 = "Value set in ShowScopes" "Scope [0] (local) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 0 -ValueOnly)'" "Scope [1] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 1 -ValueOnly)'" "Scope [2] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 2 -ValueOnly)'" "Scope [3] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 3 -ValueOnly)'" "Scope [4] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 4 -ValueOnly)'"}funcA# End of ScopeExample.ps1PS> .\ScopeExample.ps1

The output shows the value of the variable in each scope. You can see that theprivate variable is only visible in funcB, the scope in which it was created.

Setting $funcAVar1 to 'Value set in funcA'In funcB before set -> 'Value set in funcA'In funcB after set -> 'Locally overwrite the value - child scopes can't see me!'In funcC before set -> 'Value set in funcA' - should be the value set in funcAIn funcC after set -> 'Value set in funcC - Child scopes can see this change.'In funcD before set -> 'Value set in funcC - Child scopes can see this change.' - should be the value from funcC.In funcD after set -> 'Value set in funcD'-------------------Scope [0] (local) $funcAVar1 = 'Value set in ShowScopes'Scope [1] (parent) $funcAVar1 = 'Value set in funcD'Scope [2] (parent) $funcAVar1 = 'Value set in funcC - Child scopes can see this change.'Scope [3] (parent) $funcAVar1 = 'Locally overwrite the value - child scopes can't see me!'Scope [4] (parent) $funcAVar1 = 'Value set in funcA'

As shown by the output from ShowScopes, you can access variables from otherscopes using Get-Variable and specifying a scope number.

Example 5: Using a local variable in a remote command

For variables in a remote command created in the local session, use the usingscope modifier. PowerShell assumes that the variables in remote commands werecreated in the remote session.

The syntax is:

$using:<VariableName>

For example, the following commands create a $Cred variable in the localsession and then use the $Cred variable in a remote command:

$Cred = Get-CredentialInvoke-Command $s {Remove-Item .\Test*.ps1 -Credential $using:Cred}

The using scope modifier was introduced in PowerShell 3.0.

See also

  • about_Variables
  • about_Environment_Variables
  • about_Functions
  • about_Script_Blocks
  • Start-ThreadJob
about Scopes - PowerShell (2024)
Top Articles
Latest Posts
Article information

Author: Trent Wehner

Last Updated:

Views: 5528

Rating: 4.6 / 5 (76 voted)

Reviews: 83% of readers found this page helpful

Author information

Name: Trent Wehner

Birthday: 1993-03-14

Address: 872 Kevin Squares, New Codyville, AK 01785-0416

Phone: +18698800304764

Job: Senior Farming Developer

Hobby: Paintball, Calligraphy, Hunting, Flying disc, Lapidary, Rafting, Inline skating

Introduction: My name is Trent Wehner, I am a talented, brainy, zealous, light, funny, gleaming, attractive person who loves writing and wants to share my knowledge and understanding with you.