try and catch powershell is PowerShell’s structured error-handling construct that intercepts terminating exceptions in a try block, routes them to a typed catch block, and optionally runs a finally block for resource cleanup. It is the primary mechanism for production-grade script resilience.
# Minimal structure
try {
# Risky code here
}
catch {
# Handles any terminating error
Write-Host "Error caught: $_"
}
Syntax Reference
Tested on Windows Server 2022 with PowerShell 7.4, and Windows 10/11 with PowerShell 5.1.
# With specific error type and finally block
try {
Get-Item "C:MissingFile.txt" -ErrorAction Stop
}
catch [System.IO.FileNotFoundException] {
Write-Host "File not found."
}
catch {
Write-Host "Other error: $($_.Exception.Message)"
}
finally {
# Always executes — even on exception
Write-Host "Cleanup complete."
}
# Using throw inside try
try {
if (-not (Test-Path $path)) {
throw "Path does not exist: $path"
}
}
catch {
Write-Error $_.Exception.Message
}
# Global trap alternative (less granular)
trap { Write-Host "Global trap caught: $_"; continue }
1/0 # Division by zero triggers trap
Rapid Reference Cheat Sheet
| Action | CLI Command / Pattern | Key Flag | Impact / Result |
|---|---|---|---|
| Catch any terminating error | catch { } |
N/A | Catches all exception types inside try |
| Catch specific exception type | catch [System.IO.IOException] { } |
N/A | Only traps that error class; others bubble up |
| Convert non-terminating to terminating | Get-Item "X" -ErrorAction Stop |
-ErrorAction Stop |
Forces catch to trigger for cmdlets that normally produce non-terminating errors |
| Set global error preference | $ErrorActionPreference = "Stop" |
N/A | Makes all statements treat errors as terminating; overridable per cmdlet |
| Access exception details | $_.Exception.Message |
N/A | Provides human-readable error text inside catch block |
| Throw a custom error | throw "Custom error message" |
N/A | Generates a script-terminating error handled by catch or trap |
| Free resources regardless of outcome | finally { } |
N/A | Runs after try or catch; closes file handles, DB connections, etc. |
| BOOL-flag success pattern | if ( -not $PingTest.PingSucceeded ) { throw } |
N/A | Explicit error trigger based on custom condition |
Advanced Implementation & Parameters
Terminating vs Non-Terminating Errors
PowerShell distinguishes two error categories. Terminating errors (e.g., throw, type mismatch, -ErrorAction Stop) are caught by try/catch. Non-terminating errors (e.g., Get-ChildItem on an inaccessible subpath) are written to the error stream but do not trigger a catch block unless you explicitly use -ErrorAction Stop or set $ErrorActionPreference = "Stop".
The $Error automatic variable stores all non-terminating errors as a stack. To inspect the most recent error outside of a catch block:
$Error[0].Exception.Message
Multiple Catch Blocks and Error Typing
You can specify multiple catch blocks for distinct exception types. Place derived classes before general classes; otherwise the first matching block catches all. PowerShell wraps every exception in System.Management.Automation.RuntimeException, so explicit type filters must be ordered correctly.
try {
Get-Mailbox -Identity "nonexistent" -ErrorAction Stop
}
catch [Microsoft.Exchange.Management.Tasks.ManagementObjectNotFoundException] {
Write-Host "Mailbox not found."
}
catch [System.UnauthorizedAccessException] {
Write-Host "Access denied."
}
catch {
Write-Host "Unexpected error: $($_.Exception.GetType().FullName)"
}
ErrorAction and $ErrorActionPreference
Cmdlets respect -ErrorAction at the statement level. The preference variable $ErrorActionPreference applies to the entire scope. Common values: Stop, Continue (default), SilentlyContinue, Ignore, Inquire. Setting SilentlyContinue or Ignore suppresses throw-generated errors.
Finally Block
The finally block executes regardless of whether an exception was thrown or caught. It is the correct place to close file handles, database connections, or release COM objects. The finally block runs before the script terminates.
Error Resolution & Troubleshooting
| Error / Condition | Root Cause | Remediation |
|---|---|---|
catch does not trigger for Get-Item on a missing file |
Cmdlet produces non-terminating error by default | Add -ErrorAction Stop to the cmdlet inside try. |
Exception caught in wrong catch block |
Derived class placed after general class in ordering | Reorder catch blocks: most specific type first, catch { } last. |
throw inside catch is not caught by outer try |
Outer catch expects specific type or $ErrorActionPreference is set to SilentlyContinue |
Use throw $_ to re-throw the original exception; verify preference value. |
finally does not release file handle |
Resource not disposed in finally; handle held by variable still in scope | Explicitly Close() or Dispose() in finally, then Remove-Variable. |
| Script termination on error without any catch | $ErrorActionPreference = "Stop" globally set, no try/catch surrounding |
Wrap statements in try/catch or revert preference to Continue for non-critical sections. |
| Nested try/catch still stops script | Inner catch re-throws error (throw $_), and outer block does not have matching catch |
Add a general catch { } at the outermost scope, or do not re-throw. |
Common Code Smells and Fixes
Pattern — using boolean flag to indicate success:
try {
Get-Mailbox "user" -ErrorAction Stop
$success = $true
}
catch {
$success = $false
}
if ($success) { Write-Host "Mailbox retrieved." }
This is a valid pattern for catch-and-continue workflows. The flag allows subsequent logic to proceed without nesting inside the try block.
Pattern — silent retry on transitory error:
$retries = 3
do {
try {
Get-Content "\serversharefile.txt" -ErrorAction Stop
break
}
catch {
$retries--
Start-Sleep -Seconds 2
}
} while ($retries -gt 0)
Production-Grade Implementation
In unattended automation and CI/CD pipelines (Azure DevOps, GitHub Actions with PowerShell tasks), unhandled errors fail jobs. Enforce strict error handling with -ErrorAction Stop on every cmdlet that can fail and encapsulate all business logic in try/catch/finally. To minimize latency in try and catch powershell execution, avoid using catch blocks for flow control on non-exceptional paths — prefer if/else with Test-Path or -ErrorAction SilentlyContinue with manual $? checks for expected states. Reserve catch for genuine exception handling.
Security and Least Privilege: Never log or expose $_.Exception.Message directly to end users without sanitization — internal paths, server names, and credentials may leak. Write errors to a secure log file and present a generic message to the console. Use Write-Error inside catch to propagate structured errors to the calling pipeline without exposing internals.
# Secure error handling pattern
$logPath = "C:securelogsscript.log"
try {
Get-ADUser "jdoe" -ErrorAction Stop
}
catch {
# Log full exception internally
"$(Get-Date) ERROR: $($_.Exception.Message)" | Out-File $logPath -Append
# Expose only a sanitized message to console
Write-Warning "User retrieval failed. Administrator has been notified."
}
Performance consideration: If you expect a high volume of non-critical failures (e.g., network timeouts in a loop), consider -ErrorAction SilentlyContinue with selective $Error.RemoveAt(0) to avoid unbounded growth of the $Error stack. Use try/catch only for exceptions that genuinely require a different code path.
Frequently Asked Questions
What is the difference between `-ErrorAction Stop` and `try/catch` in PowerShell?
`-ErrorAction Stop` converts non-terminating errors to terminating; `try/catch` handles terminating errors. Combine both: try { Get-Item "nonexistent.txt" -ErrorAction Stop } catch { "Caught: $_" }
When should I use the `-ErrorVariable` parameter alongside `try/catch`?
Use `-ErrorVariable` to capture non-terminating error records into a variable for post‑block analysis. Example: try { Get-ChildItem "C:Missing" -ErrorVariable errs -ErrorAction SilentlyContinue; if ($errs) { throw "Manual failure" } } catch { "Caught: $_" }
How do I fix “Exception calling ‘Method’ with ‘N’ argument(s): …” inside a `try/catch` block?
Verify method signature, argument types, and object state. Example debugging: try { [System.IO.Path]::GetInvalidFileNameChars() } catch { Write-Host "Exception: $($_.Exception.Message)"; break } Pre‑validate inputs with if ($obj -eq $null) before invoking methods.
Does `try/catch` work identically on Windows PowerShell, PowerShell Core (Linux/macOS), and Azure Cloud Shell?
Yes – `try/catch/finally` syntax is consistent across all platforms since PowerShell 4. Example that works everywhere: try { Get-Service -Name "NonExistent" -ErrorAction Stop } catch [Microsoft.PowerShell.Commands.ServiceCommandException] { "Service not found" } Note: Module‑specific exception types may differ; always catch [System.Management.Automation.RuntimeException] for generic coverage.
What is the fastest way to catch all terminating errors (including script‑wide) with `try/catch` in PowerShell?
Set $ErrorActionPreference = 'Stop' at script top, then wrap entire logic in a single try{}catch{}. Example: $ErrorActionPreference = 'Stop'; try { Get-Item "bad.txt"; Get-Content "missing.log" } catch { "Global catch: $_"; $ErrorActionPreference = 'Continue' }

Command Line Expert & Software Engineer
Welcome! I’m Thomas Heinrich, a software engineer and system administrator with a deep passion for the Command Line Interface (CLI). With years of experience navigating the terminal, building backend architectures, and automating server deployments, I created this space to share practical, real-world terminal knowledge.
Whether you are a beginner taking your first steps in a Linux environment or a seasoned DevOps engineer looking to optimize your deployment scripts, you will find actionable solutions here. My goal is to help you ditch the mouse, speed up your workflow, and harness the full power of the command line.