Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable scoping in PowerShell

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?

like image 382
mathk Avatar asked Feb 17 '12 09:02

mathk


People also ask

Are variables scoped in PowerShell?

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.

What does $_ in PowerShell mean?

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.

What is $Global in PowerShell?

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.

What is scope script?

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.


2 Answers

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.

like image 139
Anton Avatar answered Oct 05 '22 12:10

Anton


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.

like image 24
Richard Avatar answered Oct 05 '22 10:10

Richard