Scopes in PowerShell

Scopes in PowerShell

Powershell logo

In many programming languages, there is the concept of scope. Defined as what variables and functions are available in what context. An example is if a variable is available to every function within a PowerShell script, or just a single defined function. PowerShell Scopes encompass several different scopes that can be used such as Global, Local, or Script scopes.

What are the PowerShell Scopes?

As mentioned in the introduction, there are several primary scopes. These are global, local, and script and tell PowerShell what variables and functions are available in what context. When referencing scopes, you usually use scope prefixes to reach variables outside the current, local, scope. This is easiest to understand through examples.

Global Scope

Global scope means that a variable will be available for all functions and commands regardless of location, such as $MyVar = $True or $Global:MyVar = $True. Upon launching PowerShell, all initial variables are globally scoped. If there are no child scopes, global is the same as local and script scope until child scopes exist.

# This is in the Global scope
$MyVar = $True

Function Test-VariableScope {
	# When a variable is not found in the current scope, look up till it is found
	Write-Host "Global Scope: $MyVar"
	# Redefine the variable in the Local scope
	$MyVar = $False
	Write-Host "Local Scope: $MyVar"
	Write-Host "Global Scope: $($Global:MyVar)"
}

Test-VariableScope

# Since the Locally scoped variable does not exist anymore, return the Global scope
Write-Host "Global Scope: $MyVar"

Local Scope

The current scope is always local, and therefore the default scope as well. When no scope modifier is used on a variable, the scope is local such as $MyVar = $True. The local scope can be hard to understand as this scope is relative to the current location and a local variable can be in different scopes at the same time.

# This is in the Local scope (and Global scope since at root of script)
$MyVar = $True
Write-Host "Local Scope: $MyVar"
Write-Host "Local Scope Explicit: $($Local:MyVar)"
Function Test-VariableScope {
	# This variable is in the Local scope relative to Test-VariableScope
	$MyVar = $False
	Write-Host "Local Scope: $MyVar"
	Write-Host "Local Scope (Explicit): $($Local:MyVar)"
}

Test-VariableScope
# This variable is back to the local scope initially defined
Write-Host "Local Scope: $MyVar"
Write-Host "Local Scope Explicit: $($Local:MyVar)"

When you dot-source a script, such as . my-script.ps1, you will add the entire output of that script to the local scope!

Script Scope

Finally, the script scope is a bit more complicated. It is either the nearest ancestor script file scope or global scope if not run in a script file such as $script:var = $true. Global, Script, and Local scope are the same for the $MyVar = $True variable when used in a single script, and even in functions.

# This is in the Script scope including Script and Local scope
$MyVar = $True
Write-Host "Script Scope: $($Script:MyVar)"

Function Test-VariableScope {
	# This variable is in the Local scope relative to Test-VariableScope
  $MyVar = $False
  # The Script scope references the same as $MyVar variable initially defined
	Write-Host "Script Scope: $($Script:MyVar)"
}

Test-VariableScope
# This variable is back to the Script scope initially defined
Write-Host "Script Scope: $($Script:MyVar)"

Unlike dot-sourcing a script which adds everything to the local scope, using the & call operator will run the script, but leave everything in the script scope which is relative to the script itself.

What is the Private, Using, Workflow, and AllScope options?

Along with the general scopes, there are several options that can modify the visibility or availability of variables. So what are these different options with scopes?

The Private Scope Modifier

When you define a variable or alias as private, the variable or alias is only visible and modifiable from within that context. As you can see from the example below, the private version of the

Remove-Variable TestVar
Remove-Variable TestVar2
Remove-Variable TestVar3

# Two ways to create a private variable, note that this is an Option and not a Scope (applied to a scoped variable)
New-Variable -Name 'TestVar' -Value $True -Scope 'Global' -Option 'Private'
$Private:TestVar2 = $True

Write-Host "Global Scope (TestVar): $TestVar"
Write-Host "Global Scope (TestVar2): $TestVar"

$TestVar3 = $True

Function Test-Function {
  # Since the first two variables are private they are not seen
  Write-Host "Local Scope (TestVar): $TestVar"
  Write-Host "Local Scope (TestVar2): $TestVar2"
  # TestVar3 does not exist locally so PowerShell looks up and finds a non-Private variable in Global
  Write-Host "Local Scope (TestVar3): $TestVar3"
}

Test-Function

What is the Using Modifier?

This is a special variable that is used by the cmdlets and constructs Invoke-Command, Start-Job, Start-ThreadJob, or ForEach-Object -Parallel. This will only work with Invoke-Command when it is being run on a remote computer such as with the ComputerName parameter.

# Normally the LocalCSVData variable will not be available to the scriptblock running on the remote computer without the Using modifier.
$LocalCSVData = Import-CSV -Path 'mydata.csv'

Invoke-Command -ComputerName 'RemoteComputer' -ScriptBlock {
	$Using:LocalCSVData | ForEach-Object {
		...do something...
	}
}

Workflow and AllScope

Although much less used, there are two additional modifiers. The Workflow modifier is used to reference variables in a PowerShell Workflow (not available in PowerShell Core/7). The AllScope modifier will make a variable available in all scopes. This also means that if the variable is modified in a child scope it will reflect in the root scopes. This is one way to avoid having to prefix a variable with global when attempting to reference it in child scopes.

Conclusion

Scopes are useful to limiting the visibility and availability of variables, functions, and aliases. Scopes can also be troublesome when it is not clear what scope a variable is in. Hopefully this article sheds some light on how scopes are used in PowerShell and what you can do with them!

Technology