/flags/powershell/erroraction-stop-try-catch
PowerShell -ErrorAction Stop: why try/catch does not catch the error
- tool
- PowerShell
- command
- any cmdlet or advanced function
- flag
- -ErrorAction (-ea)
- default
- Continue (from $ErrorActionPreference)
try { Get-Item missing.txt } catch { ... } does not run the catch block, because most cmdlet errors are non-terminating: the cmdlet writes the error and carries on, and try only reacts to terminating errors. Add -ErrorAction Stop to the command (or set $ErrorActionPreference = 'Stop' for the whole script) to turn its errors into terminating ones that catch receives.
try {
Get-Item -Path missing.txt -ErrorAction Stop
} catch {
Write-Warning "Failed: $($_.Exception.Message)"
}Non-terminating vs terminating
try { Get-Item missing.txt 2>$null; 'try block went on after the error' } catch { 'caught' }
try { Get-Item missing.txt -ErrorAction Stop; 'not printed' } catch { "caught: $($_.Exception.GetType().Name)" }
$ErrorActionPreference = 'Stop'
try { Get-Item missing.txt } catch { 'caught with $ErrorActionPreference = Stop' }Output
try block went on after the error caught: ItemNotFoundException caught with $ErrorActionPreference = Stop
-ErrorAction values
| Value | Effect |
|---|---|
| Continue (default) | print the error, continue with the next item and command |
| Stop | turn the error into a terminating one; try/catch and trap see it |
| SilentlyContinue | do not print; the error is still added to $Error |
| Ignore | do not print and do not add to $Error (not allowed in $ErrorActionPreference) |
| Inquire | ask the user what to do (fails in non-interactive sessions) |
| Break (PowerShell 7.1+) | enter the debugger |
Useful parts of the error record
try { Get-Item missing.txt -ErrorAction Stop }
catch {
'Type: ' + $_.Exception.GetType().FullName
'Id: ' + $_.FullyQualifiedErrorId
'Category: ' + $_.CategoryInfo.Category
}Output
Type: System.Management.Automation.ItemNotFoundException Id: PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand Category: ObjectNotFound
Catch a specific type with catch [System.Management.Automation.ItemNotFoundException] { ... } before a general catch { ... }.
When to use it
Add -ErrorAction Stop to every command inside a try block whose failure should change what the script does next: a file that must exist, a connection that must succeed, a user that must be found before you modify it. Without it, the script prints red text, carries on with empty variables, and fails later with a less useful message such as You cannot call a method on a null-valued expression.
Per item or all at once
Set-Content present.txt 'x'
'--- one try around the whole command:'
try { Get-Item absent1.txt, present.txt -ErrorAction Stop | ForEach-Object Name } catch { 'stopped at the first error' }
'--- one try per item:'
foreach ($f in 'absent2.txt', 'present.txt') {
try { (Get-Item $f -ErrorAction Stop).Name } catch { "skipped $f" } finally { "done $f" }
}
'--- collect errors and continue:'
Get-Item absent3.txt, present.txt -ErrorAction SilentlyContinue -ErrorVariable failed | ForEach-Object Name
'errors collected: ' + $failed.CountOutput
--- one try around the whole command: stopped at the first error --- one try per item: skipped absent2.txt done absent2.txt present.txt done present.txt --- collect errors and continue: present.txt errors collected: 1
The finally block runs whether or not an error occurred, which makes it the place for cleanup such as Disconnect-ExchangeOnline or closing a file.
Scope of the preference variable
-ErrorAction affects one command. $ErrorActionPreference affects every command in the current scope and in the scopes it creates, such as functions and script blocks you call. A function that sets it changes only its own behaviour.
Pitfalls
2>$nullis not error handling. It hides the message but the error is still non-terminating and still added to$Error.- Catching everything. A bare
catchalso catches typing mistakes in thetryblock. Print$_.Exception.Messageand$_.InvocationInfo.PositionMessagewhile developing. - Exit codes. A script that ends inside
catchwithoutexit 1returns 0 to the caller (scheduler or CI). Add an explicitexitwith a non-zero code when the failure must be visible.
FAQ
Should I set $ErrorActionPreference = 'Stop' at the top of every script?
It is a common choice for automation, because any failed cmdlet then stops the script instead of letting it continue with missing data. Wrap the steps that may fail in try/catch so you control the message and the exit code.
Does -ErrorAction Stop stop the whole pipeline at the first failed item?
Yes. With Stop, the first error ends the command, so the remaining items are not processed. Put the try/catch inside a foreach loop to handle each item separately.
How do I collect errors without stopping?
Use -ErrorAction SilentlyContinue with -ErrorVariable name. The command processes every item, and the variable holds the error records to report afterwards.
Sources
- learn.microsoft.comlearn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_commonparameters
- learn.microsoft.comlearn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally
- learn.microsoft.comlearn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables