cheat sheet

PowerShell Built-in Variables

Complete reference for every automatic and preference variable built into PowerShell — $_, $Error, $MyInvocation, $PSCmdlet, $Host, $PSVersionTable, $ExecutionContext, and all preference variables that tune runtime behaviour.

PowerShell Built-in Variables — Automatic & Preference Variables

What it is

PowerShell ships with two categories of built-in variables that are always in scope without any Import-Module or declaration: automatic variables set and maintained by the runtime (e.g. $_, $Error, $MyInvocation), and preference variables that let you tune runtime behaviour (e.g. $ErrorActionPreference, $VerbosePreference). Unlike environment variables ($env:*), these live in PowerShell's variable scope tree and reset or persist according to documented rules. The alternative — environment variables — are process-level strings that survive process boundaries but carry no type information.

Core automatic variables

Automatic variables are created and updated by PowerShell itself; assigning to most of them is either silently ignored or raises an error. They are the primary way to access pipeline context, command results, and session state without invoking a cmdlet.

powershell
$_          # Current pipeline object (alias: $PSItem)
$null       # Null value — assigning to $null discards output
$true       # Boolean true
$false      # Boolean false
$args       # Array of arguments passed to a script/function without param()
$input      # Enumerator of piped input to a function or script block
$OFS        # Output field separator (default: single space)
$$          # PID of the last executed native command's process
$^          # First token of the last executed command line
$?          # Boolean success/failure status of the last command

Output: (none — variable reference table; evaluate interactively to see values)

powershell
# $_ in a pipeline
1..5 | Where-Object { $_ -gt 3 }

Output:

code
4
5
powershell
# $args in a simple function without param()
function Greet { "Hello, $($args[0])!" }
Greet "Alice Dev"

Output:

code
Hello, Alice Dev!
powershell
# $? immediately after a command
Get-Item "C:\Windows"
$?

Output:

graphql
True

Error and exit-code variables

$Error is a fixed-size circular ring buffer (default 256 entries) that PowerShell appends to after every non-terminating error; $Error[0] is always the most recent. $LASTEXITCODE holds the numeric exit code of the most recently invoked native executable and is distinct from $?, which reflects PowerShell cmdlet success. Use both together when wrapping native tools.

powershell
$Error               # ArrayList — all errors this session, newest first
$Error[0]            # Most recent ErrorRecord
$Error[0].Exception  # Underlying .NET exception object
$Error[0].InvocationInfo.Line   # Source line that caused it
$Error[0].FullyQualifiedErrorId # Stable identifier for the error kind
$Error.Count         # Number of stored errors
$Error.Clear()       # Flush the error buffer

Output: (none — property access; values depend on session state)

powershell
# Trigger an error and inspect it
Get-Item "C:\nonexistent" -ErrorAction SilentlyContinue
$Error[0].Exception.Message

Output:

lua
Cannot find path 'C:\nonexistent' because it does not exist.
powershell
# Native exit code vs PowerShell $?
cmd /c "exit 42"
$LASTEXITCODE
$?

Output:

graphql
42
True

Version and host variables

$PSVersionTable is a read-only hashtable exposing the PowerShell build metadata; it is the canonical way to gate version-specific code paths. $Host exposes the hosting application object (terminal or ISE), including its UI.RawUI sub-object for controlling window title, colors, and buffer size.

powershell
$PSVersionTable                      # Hashtable: PSVersion, PSEdition, OS, Platform, …
$PSVersionTable.PSVersion            # [System.Version] — compare with -ge/-lt
$PSVersionTable.PSVersion.Major      # Integer major version (7 for PS 7.x)
$PSVersionTable.PSEdition            # "Core" (PS 7+) or "Desktop" (Windows PS 5.1)
$PSVersionTable.OS                   # OS description string
$PSVersionTable.Platform             # "Win32NT" | "Unix" | "MacOSX"

Output: (none — property reference; run $PSVersionTable at the prompt to see values)

powershell
$PSVersionTable

Output:

diff
Name                           Value
----                           -----
PSVersion                      7.4.2
PSEdition                      Core
GitCommitId                    7.4.2
OS                             Microsoft Windows 10.0.22631
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
powershell
$Host                             # PowerShell host application object
$Host.Name                        # e.g. "ConsoleHost" or "Windows PowerShell ISE Host"
$Host.Version                     # Host application version (not PS engine version)
$Host.UI.RawUI.WindowTitle        # Get/set terminal window title
$Host.UI.RawUI.ForegroundColor    # Current foreground color
$Host.UI.RawUI.BackgroundColor    # Current background color
$Host.UI.RawUI.BufferSize         # Console buffer dimensions
$Host.Runspace                    # The current runspace

Output: (none — property access; assignments have no console output)

powershell
# Change terminal title from a script
$Host.UI.RawUI.WindowTitle = "Deploy — myhost"

Output: (none — sets the title bar text silently)

powershell
$PSCulture     # Current input culture, e.g. "en-US"
$PSUICulture   # Current UI culture for localized messages
$PID           # PID of the current PowerShell process
$IsWindows     # $true on Windows (PS 6+)
$IsLinux       # $true on Linux
$IsMacOS       # $true on macOS
$IsCoreCLR     # $true on .NET Core / .NET 5+

Output: (none — read-only boolean/string properties)

Script and path introspection

These variables are set fresh each time a script or function executes, making them the safe way to build relative paths inside a script regardless of the caller's working directory.

powershell
$PSScriptRoot     # Absolute path of the directory containing the current script
$PSCommandPath    # Full path of the current script file
$MyInvocation     # Rich object: how, where, and by whom this code was invoked

Output: (none — set by the runtime when a script runs; empty in the interactive prompt)

powershell
# Inside C:\scripts\deploy.ps1
"Script dir : $PSScriptRoot"
"Script path: $PSCommandPath"

Output:

yaml
Script dir : C:\scripts
Script path: C:\scripts\deploy.ps1
powershell
# $MyInvocation members
$MyInvocation.MyCommand.Name        # Name of the running command, function, or script
$MyInvocation.MyCommand.Path        # Full path if it is a .ps1 file
$MyInvocation.BoundParameters       # [hashtable] explicitly passed parameter values
$MyInvocation.UnboundArguments      # Extra positional arguments
$MyInvocation.InvocationName        # How the command was typed (alias vs full name)
$MyInvocation.Line                  # Full command line string that triggered this code
$MyInvocation.ScriptLineNumber      # Line number in the source file
$MyInvocation.OffsetInLine          # Column offset on that line

Output: (none — property reference; values depend on calling context)

Advanced function variables

$PSCmdlet is only available inside [CmdletBinding()] advanced functions and grants access to ShouldProcess, ShouldContinue, WriteVerbose, and other API entry points. $PSBoundParameters is a dictionary of parameter-name → value pairs for only the parameters the caller explicitly supplied; parameters with defaults that were not passed are absent, making it safe to splat onto child commands.

powershell
function Remove-Widget {
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [string]$Name,
        [string]$Reason = "no reason given"
    )

    # ShouldProcess respects -WhatIf and -Confirm
    if ($PSCmdlet.ShouldProcess($Name, "Remove widget")) {
        "Removing $Name because $Reason"
    }

    # Splat only what the caller supplied
    $PSBoundParameters.Remove("Reason") | Out-Null
    # Set-Widget @PSBoundParameters  # forward without extra keys
}

Output: (none — function definition; call with -WhatIf to preview)

powershell
Remove-Widget -Name "gadget-7" -WhatIf

Output:

csharp
What if: Performing the operation "Remove widget" on target "gadget-7".
powershell
# $PSBoundParameters only contains explicitly passed params
function Show-Params {
    [CmdletBinding()]
    param([string]$A, [int]$B = 99)
    $PSBoundParameters
}
Show-Params -A "hello"

Output:

css
Key Value
--- -----
A   hello
powershell
$PSCmdlet.ParameterSetName   # Active parameter set name
$PSCmdlet.MyInvocation       # Same data as $MyInvocation
$PSCmdlet.WriteVerbose("…")  # Emit a VERBOSE stream message
$PSCmdlet.WriteDebug("…")    # Emit a DEBUG stream message
$PSCmdlet.WriteWarning("…")  # Emit a WARNING stream message
$PSCmdlet.WriteError(…)      # Emit a non-terminating error
$PSCmdlet.ThrowTerminatingError(…)  # Emit a terminating error

Output: (none — method reference)

Execution context ($ExecutionContext)

$ExecutionContext exposes the host's EngineIntrinsics object, which gives access to session state, the invocation API, and the path resolver from within a script. It is rarely needed in everyday scripting but is essential when writing host applications, module initializers, or dynamic argument completers.

powershell
$ExecutionContext                                    # EngineIntrinsics object
$ExecutionContext.Host                              # Same object as $Host
$ExecutionContext.SessionState                      # SessionState — variables, functions, aliases
$ExecutionContext.SessionState.Path                 # PathIntrinsics (Resolve-Path equivalent)
$ExecutionContext.InvokeCommand                     # CommandIntrinsics — invoke arbitrary commands
$ExecutionContext.InvokeProvider                    # ProviderIntrinsics — filesystem, registry, env

Output: (none — property reference; inspect interactively)

powershell
# Resolve a path relative to the current location
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath(".\logs")

Output:

makefile
C:\Users\Alice Dev\logs
powershell
# List all variables in the current scope via SessionState
$ExecutionContext.SessionState.PSVariable.GetAll() | Select-Object Name | Sort-Object Name

Output:

markdown
Name
----
ConfirmPreference
DebugPreference
Error
ErrorActionPreference
…

Preference variables

Preference variables control how PowerShell output streams — verbose, debug, warning, information, error, and progress — are displayed or suppressed. Accepted values are Continue (show), SilentlyContinue (suppress, no record), Stop (make terminating), Inquire (prompt user), and Ignore (suppress, no $Error entry). Set them locally inside a function to avoid leaking changes into the caller's scope.

powershell
$ErrorActionPreference      # Default: "Continue"         — non-terminating errors
$WarningPreference          # Default: "Continue"
$VerbosePreference          # Default: "SilentlyContinue"
$DebugPreference            # Default: "SilentlyContinue"
$InformationPreference      # Default: "SilentlyContinue" — PS 5+
$ProgressPreference         # Default: "Continue"         — progress bars
$ConfirmPreference          # Default: "High"             — ShouldProcess threshold
$WhatIfPreference           # Default: $false             — enables -WhatIf globally

Output: (none — variable reference)

powershell
# Suppress progress bars (speeds up Invoke-WebRequest in scripts)
$ProgressPreference = "SilentlyContinue"
Invoke-WebRequest "https://example.com" -OutFile result.html
$ProgressPreference = "Continue"

Output: (none — file written silently, no progress bar drawn)

powershell
# Elevate non-terminating errors to terminating
$ErrorActionPreference = "Stop"
try {
    Get-Item "C:\nonexistent"
} catch {
    "Caught: $($_.Exception.Message)"
} finally {
    $ErrorActionPreference = "Continue"
}

Output:

lua
Caught: Cannot find path 'C:\nonexistent' because it does not exist.
powershell
# Enable verbose output without the -Verbose flag
$VerbosePreference = "Continue"
Write-Verbose "Connecting to myhost…"
$VerbosePreference = "SilentlyContinue"

Output:

vbnet
VERBOSE: Connecting to myhost…

PowerShell 7.x preference and style variables

PowerShell 7.x introduces several additional preference variables that do not exist in Windows PowerShell 5.1. The most consequential is $PSNativeCommandUseErrorActionPreference (7.3+, on by default in 7.4+) which finally bridges the gap between native-tool exit codes and PowerShell's $ErrorActionPreference — when $true, any native command that exits non-zero raises an error subject to the usual preference rules. $PSStyle (7.2+) is the typed replacement for raw ANSI escape sequences and lets you change rendering of error text, formatting tables, table headers, and progress bars at runtime.

powershell
# Make a failing native command terminate the script
$PSNativeCommandUseErrorActionPreference = $true
$ErrorActionPreference = 'Stop'
try {
    robocopy C:\src C:\dst /MIR  # robocopy uses non-zero "success" codes — caution!
} catch {
    "Native command failed with exit code $LASTEXITCODE"
}
$PSNativeCommandUseErrorActionPreference = $false

Output:

bash
Native command failed with exit code 16
powershell
# Inspect and modify $PSStyle (PS 7.2+)
$PSStyle.OutputRendering          # Host | PlainText | Ansi
$PSStyle.Formatting.Error         # ANSI escape string used for error text
$PSStyle.Formatting.TableHeader   # Used in Format-Table headers
$PSStyle.Progress.View            # Classic | Minimal (7.2+)

Output:

code
Host
[31;1m
[32;1m
Minimal
powershell
# Force plain-text output (useful when piping to a file or non-ANSI consumer)
$PSStyle.OutputRendering = 'PlainText'
Get-ChildItem | Out-File listing.txt
$PSStyle.OutputRendering = 'Host'

Output: (none — file written without escape codes)

VariableAvailable sincePurpose
$PSStyle7.2Typed ANSI style controller for errors, formatting, progress
$PSNativeCommandUseErrorActionPreference7.3 (default $true in 7.4+)Make non-zero native exits respect $ErrorActionPreference
$PSNativeCommandArgumentPassing7.3Legacy / Standard / Windows — controls native argv quoting
$ErrorView5.1 (NormalView default), 7.2+ ConciseView defaultSwitch between NormalView, ConciseView, CategoryView, DetailedView
$MaximumHistoryCount1.0Lines retained in Get-History (default 4096)

Output and formatting variables

These variables adjust how PowerShell formats collections and joins array items when they are cast to strings. They are infrequently modified but can produce surprising output when inherited from a parent scope.

powershell
$OFS                           # Output field separator; default " " (space)
$FormatEnumerationLimit        # Max items in format views before "…"; default 4
$MaximumHistoryCount           # Session history buffer size; default 4096
$OutputEncoding                # Encoding for native command stdout (System.Text.Encoding)
$PSModuleAutoLoadingPreference # "All" | "None" | "ModuleQualified"
$PSDefaultParameterValues      # [hashtable] cmdlet:param → default value

Output: (none — variable reference)

powershell
# $OFS changes how arrays render when cast to string
$OFS = ", "
"$( 1..5 )"
$OFS = " "   # restore

Output:

code
1, 2, 3, 4, 5
powershell
# $PSDefaultParameterValues — set defaults for any cmdlet
$PSDefaultParameterValues = @{
    "Format-Table:AutoSize"         = $true
    "Invoke-WebRequest:UseBasicParsing" = $true
    "Get-ChildItem:Force"           = $true
}
# Now every Get-ChildItem call behaves as if you passed -Force
Get-ChildItem C:\Users\Alice Dev\

Output:

scss
(hidden files and folders are now visible)

Common pitfalls

  1. $null equality order — always write $null -eq $result, not $result -eq $null; arrays on the left short-circuit incorrectly with the reversed form.
  2. $? resets after every statement — capture it on the very next line; any subsequent expression overwrites it.
  3. $LASTEXITCODE vs $? for native tools$? is $true even when a native tool returns non-zero; check $LASTEXITCODE -ne 0 for executables like git, python, curl.
  4. $PSBoundParameters omits defaults — a parameter with a default value is absent from $PSBoundParameters unless the caller explicitly passed it; never check it for optional-with-default parameters.
  5. $Error persists session-wide$Error[0] can be stale from an earlier unrelated command; combine -ErrorVariable myErr with -ErrorAction SilentlyContinue to capture errors from a specific call.
  6. $ProgressPreference in scripts — leaving it at Continue inside scripts causes Invoke-WebRequest and Copy-Item to draw TUI progress bars that drastically slow output redirection; always set it to SilentlyContinue in non-interactive scripts.
  7. Modifying $? accidentally — any expression between your command and the $? check — even a comment-free if — will reset $?.

Real-world recipes

Version gate at script start

powershell
#Requires -Version 7
if ($PSVersionTable.PSVersion.Major -lt 7) {
    throw "Requires PowerShell 7+. Installed: $($PSVersionTable.PSVersion)"
}
if (-not $IsWindows) { throw "Windows-only script." }

Output: (none — throws on version mismatch)

Script-relative config loading

Load a JSON config from the same directory as the running script, regardless of where the caller's working directory is.

powershell
$configPath = Join-Path $PSScriptRoot "config.json"
$config     = Get-Content $configPath -Raw | ConvertFrom-Json
Write-Host "Loaded config from $configPath"

Output:

arduino
Loaded config from C:\scripts\config.json

Splat only caller-supplied parameters

Forward a subset of the caller's parameters to a child cmdlet without accidentally including defaults or internal switches.

powershell
function Invoke-Deploy {
    [CmdletBinding()]
    param([string]$Environment, [string]$Version, [switch]$DryRun)

    $passThrough = $PSBoundParameters.Clone()
    $passThrough.Remove("DryRun") | Out-Null
    if ($DryRun) { $passThrough["WhatIf"] = $true }
    Start-Deployment @passThrough
}

Output: (none — function definition)

Silent parallel web downloads

Suppress progress bars and stop on first error across multiple downloads.

powershell
$ProgressPreference    = "SilentlyContinue"
$ErrorActionPreference = "Stop"

$urls = @(
    "https://example.com/file1.csv",
    "https://example.com/file2.csv"
)

try {
    $urls | ForEach-Object -Parallel {
        Invoke-WebRequest $_ -OutFile (Split-Path $_ -Leaf)
        "Downloaded $_"
    } -ThrottleLimit 4
} catch {
    "Failed: $($_.Exception.Message)"
} finally {
    $ProgressPreference    = "Continue"
    $ErrorActionPreference = "Continue"
}

Output:

arduino
Downloaded https://example.com/file1.csv
Downloaded https://example.com/file2.csv

Sources

  • Microsoft Learn — about_Automatic_Variables (7.6) — authoritative list of every automatic variable in the 7.6 LTS branch.
  • Microsoft Learn — about_Preference_Variables (7.6) — covers $PSNativeCommandUseErrorActionPreference, $PSStyle, and the default-changes from earlier versions.
  • Microsoft Learn — about_ANSI_Terminals — full surface of the $PSStyle typed controller.
  • Microsoft Learn — What's New in PowerShell 7.6 — release notes for the LTS branch backing these defaults.