Looking at a Get-WebFile script over on PoshCode, http://poshcode.org/3226, I noticed this strange-to-me contraption:
$URL_Format_Error = [string]\"...\"
Wri
Important: There are 2 types of terminating errors, which the current help topics unfortunately conflate:
statement-terminating errors, as reported by cmdlets in certain non-recoverable situations and by expressions in which a .NET exception / a PS runtime error occurs; only the statement is terminated, and script execution continues by default.
script-terminating errors (more accurately: runspace-terminating), as either triggered by Throw
or by escalating one of the other error types via error-action preference-variable / parameter value Stop
.
Unless caught, they terminate the current runspace (thread); that is, they terminate not just the current script, but all its callers too, if applicable).
For a comprehensive overview of PowerShell's error handling, see this GitHub documentation issue.
The remainder of this post focuses on non-terminating vs. statement-terminating errors.
To complement the existing helpful answers with a focus on the core of the question: How do you choose whether to report a statement-terminating or non-terminating error?
Cmdlet Error Reporting contains helpful guidelines; let me attempt a pragmatic summary:
The general idea behind non-terminating errors is to allow "fault-tolerant" processing of large input sets: failure to process a subset of the input objects should not (by default) abort the - potentially long-running - process as a whole, allowing you to inspect the errors and reprocess only the failed objects later - as reported via the error records collected in automatic variable $Error
.
Report a NON-TERMINATING error, if your cmdlet / advanced function:
$PSCmdlet.WriteError()
to report a non-terminating error (Write-Error
, unfortunately, doesn't cause $?
to be set to $False
in the caller's scope - see this GitHub issue).$?
tells you whether the most recent command reported at least one non-terminating error.
$?
being $False
can either mean that any (nonempty) subset of input objects weren't properly processed, possibly the entire set.$ErrorActionPreference
and/or common cmdlet parameter -ErrorAction
can modify the behavior of non-terminating errors (only) in terms of error output behavior and whether non-terminating errors should be escalated to script-terminating ones.Report a STATEMENT-TERMINATING error in all other cases.
$PSCmdlet.ThrowTerminatingError()
in order to generate a statement-terminating error.Throw
keyword generates a script-terminating error that aborts the entire script (technically: the current thread).try/catch
handler or trap
statement may be used (which cannot be used with non-terminating errors), but note that even statement-terminating errors by default do not prevent the rest of the script from running. As with non-terminating errors, $?
reflects $False
if the previous statement triggered a statement-terminating error.Sadly, not all of PowerShell's own core cmdlets play by these rules:
While unlikely to fail, New-TemporaryFile (PSv5+) would report a non-terminating error if it failed, despite not accepting pipeline input and only producing one output object - this has been corrected as of at least PowerShell [Core] 7.0, however: see this GitHub issue.
Resume-Job 's help claims that passing an unsupported job type (such as a job created with Start-Job
, which is not supported, because Resume-Job
only applies to workflow jobs) causes a terminating error, but that's not true as of PSv5.1.