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, explicitthrow.) - 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/catchunless 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 Stopis needed forcatch - [ ] You know where to find the last error's details
Next: Troubleshooting.