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.
$_ # 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)
# $_ in a pipeline
1..5 | Where-Object { $_ -gt 3 }
Output:
4
5
# $args in a simple function without param()
function Greet { "Hello, $($args[0])!" }
Greet "Alice Dev"
Output:
Hello, Alice Dev!
# $? immediately after a command
Get-Item "C:\Windows"
$?
Output:
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.
$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)
# Trigger an error and inspect it
Get-Item "C:\nonexistent" -ErrorAction SilentlyContinue
$Error[0].Exception.Message
Output:
Cannot find path 'C:\nonexistent' because it does not exist.
# Native exit code vs PowerShell $?
cmd /c "exit 42"
$LASTEXITCODE
$?
Output:
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.
$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)
$PSVersionTable
Output:
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
$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)
# Change terminal title from a script
$Host.UI.RawUI.WindowTitle = "Deploy — myhost"
Output: (none — sets the title bar text silently)
$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.
$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)
# Inside C:\scripts\deploy.ps1
"Script dir : $PSScriptRoot"
"Script path: $PSCommandPath"
Output:
Script dir : C:\scripts
Script path: C:\scripts\deploy.ps1
# $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.
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)
Remove-Widget -Name "gadget-7" -WhatIf
Output:
What if: Performing the operation "Remove widget" on target "gadget-7".
# $PSBoundParameters only contains explicitly passed params
function Show-Params {
[CmdletBinding()]
param([string]$A, [int]$B = 99)
$PSBoundParameters
}
Show-Params -A "hello"
Output:
Key Value
--- -----
A hello
$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.
$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)
# Resolve a path relative to the current location
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath(".\logs")
Output:
C:\Users\Alice Dev\logs
# List all variables in the current scope via SessionState
$ExecutionContext.SessionState.PSVariable.GetAll() | Select-Object Name | Sort-Object Name
Output:
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.
$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)
# 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)
# Elevate non-terminating errors to terminating
$ErrorActionPreference = "Stop"
try {
Get-Item "C:\nonexistent"
} catch {
"Caught: $($_.Exception.Message)"
} finally {
$ErrorActionPreference = "Continue"
}
Output:
Caught: Cannot find path 'C:\nonexistent' because it does not exist.
# Enable verbose output without the -Verbose flag
$VerbosePreference = "Continue"
Write-Verbose "Connecting to myhost…"
$VerbosePreference = "SilentlyContinue"
Output:
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.
# 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:
Native command failed with exit code 16
# 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:
Host
[31;1m
[32;1m
Minimal
# 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)
| Variable | Available since | Purpose |
|---|---|---|
$PSStyle | 7.2 | Typed ANSI style controller for errors, formatting, progress |
$PSNativeCommandUseErrorActionPreference | 7.3 (default $true in 7.4+) | Make non-zero native exits respect $ErrorActionPreference |
$PSNativeCommandArgumentPassing | 7.3 | Legacy / Standard / Windows — controls native argv quoting |
$ErrorView | 5.1 (NormalView default), 7.2+ ConciseView default | Switch between NormalView, ConciseView, CategoryView, DetailedView |
$MaximumHistoryCount | 1.0 | Lines 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.
$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)
# $OFS changes how arrays render when cast to string
$OFS = ", "
"$( 1..5 )"
$OFS = " " # restore
Output:
1, 2, 3, 4, 5
# $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:
(hidden files and folders are now visible)
Common pitfalls
$nullequality order — always write$null -eq $result, not$result -eq $null; arrays on the left short-circuit incorrectly with the reversed form.$?resets after every statement — capture it on the very next line; any subsequent expression overwrites it.$LASTEXITCODEvs$?for native tools —$?is$trueeven when a native tool returns non-zero; check$LASTEXITCODE -ne 0for executables likegit,python,curl.$PSBoundParametersomits defaults — a parameter with a default value is absent from$PSBoundParametersunless the caller explicitly passed it; never check it for optional-with-default parameters.$Errorpersists session-wide —$Error[0]can be stale from an earlier unrelated command; combine-ErrorVariable myErrwith-ErrorAction SilentlyContinueto capture errors from a specific call.$ProgressPreferencein scripts — leaving it atContinueinside scripts causesInvoke-WebRequestandCopy-Itemto draw TUI progress bars that drastically slow output redirection; always set it toSilentlyContinuein non-interactive scripts.- Modifying
$?accidentally — any expression between your command and the$?check — even a comment-freeif— will reset$?.
Real-world recipes
Version gate at script start
#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.
$configPath = Join-Path $PSScriptRoot "config.json"
$config = Get-Content $configPath -Raw | ConvertFrom-Json
Write-Host "Loaded config from $configPath"
Output:
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.
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.
$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:
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
$PSStyletyped controller. - Microsoft Learn — What's New in PowerShell 7.6 — release notes for the LTS branch backing these defaults.