-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Description
For the larger context, see Our Error Handling, Ourselves - time to fully understand and properly document PowerShell's error handling.
-
The documentation (
about_Preference_Variablesandabout_Throw) only makes the distinction between non-terminating and terminating errors, neglecting to distinguish between the two fundamentally different types of terminating errors:- statement-terminating errors, as generated by some cmdlets and by .NET exceptions
- script-terminating errors, as generated with the
Throwkeyword or potentially by escalation via-ErrorActionor$ErrorActionPreference.
-
The documentation mistakenly claims that
$ErrorActionPreferenceexclusively applies to non-terminating errors, whereas it controls the behavior of both types of terminating errors too.
On a personal note, the conflation of the two types of terminating errors in the documentation has caused me years of confusion.
The sample cmdlet used below that generates a terminating error is courtesy of @PetSerAl.
Statement-terminating errors
Steps to reproduce
# Define New-TerminatingError cmdlet whose sole purpose is to generate a
# statement-terminating error.
Add-Type '
using System.Management.Automation;
[Cmdlet("New", "TerminatingError")]
public class NewTerminatingErrorCmdlet : Cmdlet {
protected override void ProcessRecord() {
ThrowTerminatingError(new ErrorRecord(new System.Exception(), "Error", ErrorCategory.NotSpecified, null));
}
}' -PassThru | % Assembly | Import-Module
# Per the documentation, this should only affect *non-terminating* errors.
$ErrorActionPreference = 'Stop'
# Should only terminate the statement (pipeline), not the script.
New-TerminatingError | % {} -End { 'end of pipeline' }
'end of script'Expected behavior
Note: Expected based on the current documentation - arguably, the actual behavior makes more sense.
New-TerminatingError : Exception of type 'System.Exception' was thrown.
...
end of script
Actual behavior
$ErrorActionPreference = 'Stop' did take effect for the pipeline-terminating error and aborted the script:
New-TerminatingError : Exception of type 'System.Exception' was thrown.
...
Script-terminating errors
# Per the documentation, this should only affect *non-terminating* errors.
$ErrorActionPreference = 'SilentlyContinue'
# Should abort the script, irrespective of the $ErrorActionPreference value, according
# to the documentation.
Throw "I'm outta here"
'end of script'Expected behavior
The script should be aborted, and the error message passed to Throw should be displayed.
I'm outta here
...
Actual behavior
$ErrorActionPreference = 'SilentlyContinue' caused the Throw statement to be ignored.
Note that, according to the documentation, Ignore is an invalid value for $ErrorActionPreference and should only be used with the -ErrorAction common parameter.
However, it is accepted and somewhat takes effect: it ignores the Throw error, yet still records it in $Error.
end of script
Environment data
PowerShell Core v6.0.0-beta.4 on macOS 10.12.5
PowerShell Core v6.0.0-beta.4 on Ubuntu 16.04.2 LTS
PowerShell Core v6.0.0-beta.4 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Windows PowerShell v5.1.15063.413 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)