Skip to content

Error Handling

Scope: terminating vs non-terminating errors, try/catch, and $ErrorActionPreference. All examples were run with PowerShell 7.5.

Two kinds of errors

This is the concept everything else hangs on:

  • Terminating errors stop execution — caught by try/catch. (Syntax errors, .NET exceptions, explicit throw.)
  • Non-terminating errors report the problem and keep going — the default for most cmdlet failures (file not found, one bad item in a batch). NOT caught by try/catch unless you promote them.
try {
    Get-ChildItem "C:\nope" -ErrorAction Stop
} catch {
    Write-Host "Caught: $($_.Exception.Message)"
}

-ErrorAction Stop promotes a non-terminating error to terminating so catch sees it. Without it, the catch block never runs and the script continues.

try / catch / finally

try {
    $data = Get-Content "config.json" -Raw -ErrorAction Stop
    $config = $data | ConvertFrom-Json
} catch {
    Write-Error "Failed to load config: $($_.Exception.Message)"
    exit 1
} finally {
    Write-Host "Done attempting load."
}

$_ in the catch block is the error object; $_.Exception.Message is the human-readable part. finally always runs — cleanup goes here.

$ErrorActionPreference: the global dial

$ErrorActionPreference = "Stop"   # make everything terminating

Values: Continue (default — report and go on), Stop (everything terminates), SilentlyContinue (swallow), Inquire (ask). Setting it to "Stop" at the top of a script is the PowerShell equivalent of Bash's set -e — failures become catchable everywhere without per-command flags.

Prefer -ErrorAction on individual commands when you want surgical control; use the preference variable for script-wide policy.

throw and Write-Error

if (-not $ApiKey) {
    throw "ApiKey is required."
}

throw creates a terminating error with your message. Write-Error writes a non-terminating one (continues unless action is Stop).

The $Error list

$Error[0]   # the most recent error, in full
$Error.Clear()

Every error is appended to $Error (newest first). When something failed three commands ago and you need the details, look here.

Checking success without exceptions

Remove-Item "old.txt" -ErrorAction SilentlyContinue
if ($?) {
    Write-Host "removed (or wasn't there)"
}

$? is $true if the last command succeeded. With SilentlyContinue, expected failures (file already gone) don't spam the screen.

The decision table

Situation Do this
Cmdlet might fail, you want catch -ErrorAction Stop + try/catch
Whole script should fail fast $ErrorActionPreference = "Stop" at top
Expected failure, don't care -ErrorAction SilentlyContinue + check $?
Your own validation failure throw "clear message"
Cleanup that must run finally block

Check

  • [ ] You can explain terminating vs non-terminating in one sentence
  • [ ] You know why -ErrorAction Stop is needed for catch
  • [ ] You know where to find the last error's details

Next: Troubleshooting.