Variable scoping in PowerShell
The PowerShell scopes article (about_Scopes) is nice, but too verbose, so this is quotation from my article:
In general, PowerShell scopes are like .NET scopes. They are:
- Global is public
- Script is internal
- Private is private
- Local is current stack level
- Numbered scopes are from 0..N where each step is up to stack level (and 0 is Local)
Here is simple example, which describes usage and effects of scopes:
$test = 'Global Scope'Function Foo { $test = 'Function Scope' Write-Host $Global:test # Global Scope Write-Host $Local:test # Function Scope Write-Host $test # Function Scope Write-Host (Get-Variable -Name test -ValueOnly -Scope 0) # Function Scope Write-Host (Get-Variable -Name test -ValueOnly -Scope 1) # Global Scope}Foo
As you can see, you can use $Global:test like syntax only with named scopes, $0:test will be always $null.
You can use scope modifiers or the *-Variable
cmdlets.
The scope modifiers are:
global
used to access/modify at the outermost scope (eg. the interactive shell)script
used on access/modify at the scope of the running script (.ps1
file). If not running a script then operates asglobal
.
(For the -Scope
parameter of the *-Variable
cmdlets see the help.)
Eg. in your second example, to directly modify the global $array
:
& { $global:array +="s" Write-Host $array}
For more details see the help topic about_scopes.
Not just varibles. When this says "item" it means variables, functions, aliases, and psdrives. All of those have scope.
LONG DESCRIPTION Windows PowerShell protects access to variables, aliases, functions, and Windows PowerShell drives (PSDrives) by limiting where they can be read and changed. By enforcing a few simple rules for scope, Windows PowerShell helps to ensure that you do not inadvertently change an item that should not be changed. The following are the basic rules of scope: - An item you include in a scope is visible in the scope in which it was created and in any child scope, unless you explicitly make it private. You can place variables, aliases, functions, or Windows PowerShell drives in one or more scopes. - An item that you created within a scope can be changed only in the scope in which it was created, unless you explicitly specify a different scope.
The copy on write issue you're seeing is because of the way Powershell handles arrays. Adding to that array actually destroys the original array and creates a new one. Since it was created in that scope, it is destroyed when the function or script block exits and the scope is disposed of.
You can explicitly scope varibles when you update them, or you can use [ref] objects to do your updates, or write your script so that you're updating a property of an object or a hash table key of an object or hash table in a parent scope. This does not create a new object in the local scope, it modifies the object in the parent scope.