PowerShell Variable Scope
In PowerShell, every variable lives inside a boundary called a scope. The scope determines where a variable exists and which parts of the script can read or change it. Understanding scope prevents hard-to-find bugs where a variable seems to disappear or holds an unexpected value.
What Is Scope?
Think of scope like rooms in a house. A variable created in the kitchen (a function) stays in the kitchen. The living room (the main script) cannot see it unless someone opens the door (passes the value out explicitly).PowerShell has four main scopes:+---------------------------+ | Global Scope | ← Entire PowerShell session | +---------------------+ | | | Script Scope | | ← Inside a .ps1 file | | +---------------+ | | | | | Local Scope | | | ← Inside a function | | | (Function) | | | | | +---------------+ | | | +---------------------+ | +---------------------------+
The Four Scope Levels
1. Global Scope
Variables in the global scope exist throughout the entire PowerShell session. They are available in scripts, functions, and the command line.$Global:appName = "MyApp" Write-Output $Global:appName # Output: MyApp
2. Script Scope
Variables defined at the top level of a.ps1 file belong to the script scope. Functions inside the same script can read these variables, but they cannot automatically change them.
# script.ps1
$scriptVersion = "2.0"
function ShowVersion {
Write-Output $scriptVersion # Reads from script scope — works fine
}
ShowVersion # Output: 2.0
3. Local Scope
Every function creates its own local scope. Variables defined inside a function die when the function ends. They are invisible to the rest of the script.
function GetTotal {
$total = 100 # Local to this function
Write-Output $total
}
GetTotal # Output: 100
Write-Output $total # Output: (nothing — $total does not exist here)
4. Private Scope
A private variable is visible only in the current scope and completely hidden from child scopes — even from functions called inside the same block.
$Private:secret = "hidden"
function TryToRead {
Write-Output $secret # Cannot see the private variable
}
TryToRead # Output: (blank)
How PowerShell Resolves Variables
When PowerShell looks up a variable, it searches from the innermost scope outward — like a stack of transparent plates, looking down through each layer until it finds the variable.
Step 1: Look in current (local) scope
↓ Not found?
Step 2: Look in parent scope
↓ Not found?
Step 3: Look in script scope
↓ Not found?
Step 4: Look in global scope
↓ Not found?
Result: Variable is empty ($null)
Scope Modifier Prefix Table
| Prefix | Scope | Example |
|---|---|---|
$Global: | Entire session | $Global:counter = 0 |
$Script: | Current .ps1 file | $Script:config = "prod" |
$Local: | Current block/function | $Local:name = "Alice" |
$Private: | Current scope only | $Private:key = "xyz" |
Modifying a Parent Variable from a Function
By default, a function cannot change a variable that belongs to its parent scope. Two approaches solve this:Approach 1: Use the Global Modifier
$count = 0
function AddOne {
$Global:count = $Global:count + 1
}
AddOne
Write-Output $count # Output: 1
Approach 2: Use Script Modifier
$Script:total = 50
function DoubleTotal {
$Script:total = $Script:total * 2
}
DoubleTotal
Write-Output $Script:total # Output: 100
Common Scope Mistake and Fix
# MISTAKE — Trying to change a parent variable without a modifier
$price = 10
function ApplyDiscount {
$price = 5 # Creates a NEW local variable, does not change the original
}
ApplyDiscount
Write-Output $price # Output: 10 (unchanged!)
# FIX — Use Script modifier
$price = 10
function ApplyDiscount {
$Script:price = 5 # Now actually changes the script-level variable
}
ApplyDiscount
Write-Output $price # Output: 5
Scope with Dot Sourcing
When a script runs normally, its variables stay in their own script scope. Dot sourcing (.) runs a script in the current scope instead — meaning variables from that script become available in the calling scope.# File: settings.ps1 $theme = "Dark" $language = "EN"
# Main script . .\settings.ps1 # Dot source the settings file Write-Output $theme # Output: Dark Write-Output $language # Output: ENWithout the dot,
$theme and $language would be invisible in the main script.Checking Variable Scope with Get-Variable
# List all variables in the current scope Get-Variable # Check a specific variable and its scope Get-Variable -Name count -Scope Global
Real-World Example: Counter Across Function Calls
$Script:callCount = 0
function TrackCall {
$Script:callCount++
Write-Output "Function called $Script:callCount time(s)"
}
TrackCall # Output: Function called 1 time(s)
TrackCall # Output: Function called 2 time(s)
TrackCall # Output: Function called 3 time(s)
The script-level variable persists between function calls, making it ideal for counters, flags, and configuration values.Summary
Scope controls where a variable can be seen and changed. PowerShell searches from local to global when looking up a variable. Use scope modifiers ($Global:, $Script:, $Private:) to control access deliberately. Avoid using global variables for everything — tight scope keeps scripts reliable, readable, and bug-free.