Skip to content
AgileLogics
6 min read

try, catch, and finally

Prerequisites: Errors: terminating and non-terminating

try/catch handles terminating errors:

try {
  $result = 10 / 0
  'This line does not run'
} catch {
  "Caught: $($_.Exception.Message)"
} finally {
  'Finally always runs'
}
Caught: Attempted to divide by zero.
Finally always runs
  • Inside catch, $_ is the error record; $_.Exception.Message is the message.
  • finally runs whether or not an error happened — for cleanup like closing connections or deleting temp files.

catch doesn't see non-terminating errors

try {
  Get-Item missing.txt
  'try block finished'
} catch {
  'caught it'
}
'---'
try {
  Get-Item missing.txt -ErrorAction Stop
  'try block finished'
} catch {
  'caught it'
}
Get-Item: C:\demo\script.ps1:2
Line |
   2 |    Get-Item missing.txt
     |    ~~~~~~~~~~~~~~~~~~~~
     | Cannot find path 'C:\demo\missing.txt' because it does not
     | exist.
try block finished
---
caught it

Without -ErrorAction Stop, the error isn't terminating, so catch never runs. Always add -ErrorAction Stop to cmdlets inside try (or set $ErrorActionPreference = 'Stop').

Catching specific exceptions

function Read-Config {
  param([string]$Path)
  try {
    Get-Content $Path -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop
  } catch [System.Management.Automation.ItemNotFoundException] {
    "No config at $Path, using defaults"
  } catch [System.ArgumentException] {
    "Config at $Path is not valid JSON"
  } catch {
    "Unexpected: $($_.Exception.GetType().Name)"
  }
}

Set-Content bad.json '{ "port": '
Read-Config missing.json
Read-Config bad.json
No config at missing.json, using defaults
Config at bad.json is not valid JSON

Catch blocks are checked in order; list the most specific types first. To find a type to catch, look at $_.Exception.GetType().FullName in a general catch.

throw

function Set-Discount {
  param([double]$Percent)
  if ($Percent -lt 0 -or $Percent -gt 50) {
    throw "Discount must be between 0 and 50, got $Percent"
  }
  "Discount set to $Percent%"
}

Set-Discount 20
try { Set-Discount 80 } catch { "Error: $_" }
Discount set to 20%
Error: Discount must be between 0 and 50, got 80

In a catch block, throw on its own rethrows the current error — after logging it, for example.

Common mistakes

  • An empty catch { } that hides every problem. At minimum, log the error.
  • Forgetting -ErrorAction Stop and assuming catch will run.