Skip to main content
SysAdmin Shell Scripting Essentials

Try and Catch PowerShell: Syntax, Examples, and Best Practices

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
See also  Jenkins Cron — Verified Syntax, Examples & Troubleshooting

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.
See also  linux show processes: ps command reference with examples

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.

See also  Gogs Install: Deploy Self-Hosted Git Server on Linux | CLI

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' }