To throw an exception with a message in PowerShell, put your text after the throw keyword. It stops the script right there, and a try/catch block can read the text back from $_.Exception.Message:
throw "Disk C: on DEN-FS02 is 95% full."
A plain string is enough most of the time. Below I’ll show what the error looks like in PowerShell 7 and Windows PowerShell 5.1, plus typed exceptions, Write-Error, rethrowing, and the one setting that quietly turns throw off.
Throw an exception with a custom message
A good spot for throw is a check inside one of your PowerShell functions. Here the function refuses to continue when a disk is almost full, and the caller catches it:
function Test-DiskSpace {
param([string]$Server, [int]$PercentUsed)
if ($PercentUsed -ge 90) {
throw "Disk C: on $Server is $PercentUsed% full. Free up space before the backup."
}
"$Server is OK at $PercentUsed%"
}
Test-DiskSpace -Server 'SEA-FS01' -PercentUsed 72
try {
Test-DiskSpace -Server 'DEN-FS02' -PercentUsed 95
'This line never runs'
}
catch {
"Caught: $($_.Exception.Message)"
}
Output:
SEA-FS01 is OK at 72%
Caught: Disk C: on DEN-FS02 is 95% full. Free up space before the backup.
The first server passes. For the second, throw ends the function, skips the rest of the try block, and jumps to catch. Pair it with if and else statements so it only fires on the bad case.
Write the message for the person who reads it at 2 AM: name the object, the value, and what to do next. “Something went wrong” helps nobody.
What does an uncaught throw look like?
If nothing catches the exception, PowerShell prints the message and stops the script. The two versions format it differently. Here’s the script:
$server = 'DEN-FS02'
throw "Disk C: on $server is 95% full."
'This line never runs'
PowerShell 7 uses its concise error view. It shows the line and puts your message at the bottom:
Exception: C:\psfaqs\uncaught.ps1:2
Line |
2 | throw "Disk C: on $server is 95% full."
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Disk C: on DEN-FS02 is 95% full.
Windows PowerShell 5.1 prints your message first, then the position, CategoryInfo and FullyQualifiedErrorId. For a string, the error ID is the message itself:

In both versions, ‘This line never runs’ really never runs. The error also lands in $Error[0], which is covered in PowerShell error variables.
Throw a specific exception type with a message
A string always becomes a generic RuntimeException. When callers need to react differently to different problems, throw a .NET exception type and pass your message to its constructor:
function Import-OrderFile {
param([string]$Path)
if ([string]::IsNullOrWhiteSpace($Path)) {
throw [System.ArgumentException]::new('Pass the path of an order CSV file.', 'Path')
}
if (-not (Test-Path -Path $Path)) {
throw [System.IO.FileNotFoundException]::new("Order file not found: $Path", $Path)
}
"Importing $Path"
}
foreach ($file in '', 'C:\psfaqs\orders-2026-10.csv') {
try {
Import-OrderFile -Path $file
}
catch [System.IO.FileNotFoundException] {
"Missing file -> $($_.Exception.FileName)"
}
catch [System.ArgumentException] {
"Bad argument -> $($_.Exception.Message)"
}
}
Output:
Bad argument -> Pass the path of an order CSV file. (Parameter 'Path')
Missing file -> C:\psfaqs\orders-2026-10.csv

That output is from PowerShell 7. Windows PowerShell 5.1 runs on .NET Framework, so ArgumentException puts the parameter name on its own line, “Parameter name: Path”, instead of “(Parameter ‘Path’)”.
FileNotFoundException also keeps the path in its FileName property. The check itself uses Test-Path, which returns False for a missing file instead of failing.
Order matters in the catch list. PowerShell runs only the first block that matches, and FileNotFoundException inherits from IOException, so put the more specific type first.
The short form throw [System.IO.FileNotFoundException] 'Order file not found' works too. The ::new() form needs PowerShell 5.0 or later, which every supported version has.
How do I get the exception message in a catch block?
Inside catch, $_ (or $PSItem) is an ErrorRecord. These are the properties I print most often:
try {
throw 'Payroll export for Seattle failed: 3 rows have no employee ID.'
}
catch {
"Message: $($_.Exception.Message)"
"Type: $($_.Exception.GetType().FullName)"
"Category: $($_.CategoryInfo.Category)"
"ErrorId: $($_.FullyQualifiedErrorId)"
"Line: $($_.InvocationInfo.ScriptLineNumber)"
"As string: $_"
}
Output:
Message: Payroll export for Seattle failed: 3 rows have no employee ID.
Type: System.Management.Automation.RuntimeException
Category: OperationStopped
ErrorId: Payroll export for Seattle failed: 3 rows have no employee ID.
Line: 2
As string: Payroll export for Seattle failed: 3 rows have no employee ID.
For a thrown string, the type is RuntimeException, the category is OperationStopped, and the error ID is the message. Putting $_ inside a string gives you the message, which is handy for writing errors to a log file.
$_.InvocationInfo.ScriptLineNumber tells you where it happened, and $_.ScriptStackTrace lists the function calls that led there. For finally blocks and catching errors from cmdlets, see try and catch in PowerShell.
Throw vs Write-Error -ErrorAction Stop
Write-Error is the other way to report a problem. By default it’s non-terminating: it writes the error and the function keeps going, so catch never fires. Add -ErrorAction Stop and it behaves like a terminating error:
function Get-Invoice {
[CmdletBinding()]
param([int]$Number)
Write-Error "Invoice $Number was not found."
"Get-Invoice kept going after Write-Error"
}
try { Get-Invoice -Number 5521 2>$null } catch { 'Caught without Stop' }
try {
Get-Invoice -Number 5521 -ErrorAction Stop
}
catch {
"Caught with Stop: $($_.Exception