A sad thing about PowerShell is that function and scriptblocks are dynamically scoped.
But there is another thing that surprised me is that variables behave as a copy-on-write within an inner scope.
$array=@("g") function foo() { $array += "h" Write-Host $array } & { $array +="s" Write-Host $array } foo Write-Host $array
The output is:
g s g h g
Which makes dynamic scoping a little bit less painful. But how do I avoid the copy-on-write?
PowerShell scope protects variables and other artifacts by limiting where they can be read and modified. Scope levels protect items that should not be changed. PowerShell has the following scopes available: Global: This scope is available when you open a PowerShell console or create a new runspace or session.
The “$_” is said to be the pipeline variable in PowerShell. The “$_” variable is an alias to PowerShell's automatic variable named “$PSItem“. It has multiple use cases such as filtering an item or referring to any specific object.
Global: The scope that is in effect when PowerShell starts or when you create a new session or runspace. Variables and functions that are present when PowerShell starts have been created in the global scope, such as automatic variables and preference variables.
The Script scope is a useful place to store variables which must be shared without exposing the variable to the Global scope (and therefore to anyone with access to the session). For example, the following short script stores a version number in a script-level variable.
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:
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 as global
.(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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With