In PowerShell, try/catch runs the code in try and jumps to catch when a terminating error happens. For cmdlets, add -ErrorAction Stop so their errors reach the catch block:
try {
$orders = Import-Csv -Path C:\psfaqs\Try\orders-2026-09.csv -ErrorAction Stop
"Loaded $($orders.Count) orders"
}
catch {
"Failed. $($_.Exception.Message)"
}
Output:
Failed. Could not find file 'C:\psfaqs\Try\orders-2026-09.csv'.

Inside catch, $_ is the error record, and $_.Exception.Message is the readable message. Below I explain why catch sometimes doesn’t run, catch specific error types, clean up with finally and throw your own errors.
Why catch doesn’t run without -ErrorAction Stop
Most cmdlet errors are non-terminating. PowerShell reports them and carries on, so try never notices:
$ran = 'no'
try { Get-Content -Path C:\psfaqs\Try\missing.csv 2>$null } catch { $ran = 'yes' }
"Without -ErrorAction Stop, catch ran: $ran"
$ran = 'no'
try { Get-Content -Path C:\psfaqs\Try\missing.csv -ErrorAction Stop } catch { $ran = 'yes' }
"With -ErrorAction Stop, catch ran: $ran"
Output:
Without -ErrorAction Stop, catch ran: no
With -ErrorAction Stop, catch ran: yes
-ErrorAction Stop turns that one error into a terminating error. To do it for a whole script, set $ErrorActionPreference = 'Stop' at the top.
Catch specific error types
Add several catch blocks, each with an exception type. PowerShell uses the first one that matches, and a plain catch at the end handles the rest:
$tests = @(
{ Get-Content -Path C:\psfaqs\Try\missing.csv -ErrorAction Stop }
{ [int]'ten' }
{ $count = 0; 150 / $count }
)
foreach ($test in $tests) {
try { & $test }
catch [System.Management.Automation.ItemNotFoundException] { "File not found: $($_.Exception.GetType().Name)" }
catch [System.Management.Automation.PSInvalidCastException] { "Bad number: $($_.Exception.GetType().Name)" }
catch [System.DivideByZeroException] { "Divide by zero: $($_.Exception.GetType().Name)" }
catch { "Something else: $($_.Exception.GetType().FullName)" }
}
Output:
File not found: ItemNotFoundException
Bad number: PSInvalidCastException
Divide by zero: DivideByZeroException

To find the type name for your own catch, print $_.Exception.GetType().FullName in a plain catch first.
Use finally for cleanup
finally runs whether try succeeded or failed. It’s the right place to close connections, delete temp files or stop a timer:
foreach ($file in 'orders.csv', 'missing.csv') {
try {
$rows = Import-Csv -Path "C:\psfaqs\Try\$file" -ErrorAction Stop
"$file loaded $($rows.Count) rows"
}
catch { "$file failed" }
finally { " Cleanup ran for $file" }
}
Output:
orders.csv loaded 2 rows
Cleanup ran for orders.csv
missing.csv failed
Cleanup ran for missing.csv
finally even runs when you press Ctrl+C during try. Microsoft covers the details in about_Try_Catch_Finally.
Get error details inside catch
The error record carries much more than the message. These are the properties I log most often:
try {
Get-Content -Path C:\psfaqs\Try\missing.csv -ErrorAction Stop
}
catch {
"Type: $($_.Exception.GetType().FullName)"
"Category: $($_.CategoryInfo.Category)"
"Error ID: $($_.FullyQualifiedErrorId)"
"Line: $($_.InvocationInfo.ScriptLineNumber)"
}
Output:
Type: System.Management.Automation.ItemNotFoundException
Category: ObjectNotFound
Error ID: PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
Line: 2

Every error also lands in $Error, newest first. PowerShell error variables covers $Error and -ErrorVariable.
Throw your own errors
Use throw when your script finds a problem PowerShell wouldn’t flag, such as too few rows. The caller catches it like any other error:
function Import-Orders {
param([string]$Path)
$orders = @(Import-Csv -Path $Path -ErrorAction Stop)
if ($orders.Count -lt 3) { throw "Only $($orders.Count) orders in $Path. Expected at least 3." }
$orders
}
try { Import-Orders -Path C:\psfaqs\Try\orders.csv }
catch { "Failed. $($_.Exception.Message)" }
Output:
Failed. Only 2 orders in C:\psfaqs\Try\orders.csv. Expected at least 3.
Inside a catch block, a bare throw passes the same error up to the caller. Throwing exceptions with a message has more patterns.
Frequently Asked Questions
How do I use try catch in PowerShell?
Put the risky code in try { } and the handling code in catch { }. Add -ErrorAction Stop to cmdlets inside try.
Why is my PowerShell catch block not working?
The error is non-terminating. Add -ErrorAction Stop to the cmdlet, or set $ErrorActionPreference = ‘Stop’.
How do I get the error message in catch?
Use $_.Exception.Message. $_ is the full error record.
Can I catch different errors separately?
Yes. Add catch blocks with types, such as catch [System.Management.Automation.ItemNotFoundException], then a plain catch.
When does the finally block run?
Always: after try succeeds, after catch handles an error and even when you press Ctrl+C. See Microsoft’s about_CommonParameters.
More on handling errors: