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

PrefixScopeExample
$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: EN
Without 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.

Leave a Comment

Your email address will not be published. Required fields are marked *