Question:
I want all of the functions in my module to default to $ErrorActionPreference = 'Stop'
. Is it possible without modifying all the functions?
I have a file per function.
Answer:
Assuming that your module is a script module, i.e., implemented in PowerShell code:
Important:
- Modules have their own stack of scopes that is independent of the scopes of non-module code (and other modules’). While this provides isolation from the caller’s environment that is generally useful, it also means that the caller’s
$ErrorActionPreference
value never takes effect for script-module functions (unless you directly run from the global scope, which modules also see) – but it does so for compiled cmdlets. This highly problematic behavior is discussed in this GitHub issue. - Even though you therefore currently cannot control a script module’s error behavior from the caller by way of
$ErrorActionPreference
, by setting (overriding)$ErrorActionPreference
in your module you’re closing that door permanently. - However, using the
-ErrorAction
common parameter for a specific call instead of the$ErrorActionPreference
preference variable will still override your module-global$ErrorActionPreference
value, because, behind the scenes, PowerShell translates the-ErrorAction
argument to a function-local$ErrorActionPreference
variable with that value. - The
-ErrorAction
and$ErrorActionPreference
mechanisms are plagued by inconsistencies and obscure behaviors – this GitHub docs issue provides a comprehensive overview of PowerShell’s error handling.
I want all of the functions in my module to default to
$ErrorActionPreference = 'Stop'
. Is it possible without modifying all the functions?
Yes – simply place $ErrorActionPreference = 'Stop'
in your RootModule
*.psm1
file’s top-level code. (The RootModule
entry of a module’s manifest file (*.psd1
) specifies a module’s main module – see the docs).
- If you don’t have a
RootModule
entry that references a.psm1
file, simply create a.psm1
file in your module folder (typically named for the enclosing module) with content$ErrorActionPreference = 'Stop'
, and reference it from theRootModule
entry – see this answer for background information.
Unless overridden by the caller by using the common -ErrorAction
parameter when calling your module’s functions (assuming they are advanced functions), your module’s top-level $ErrorActionPreference
value will be in effect for all of your module’s functions, except if your function directly emits a statement-terminating error[1], in which case it is the caller’s $ErrorActionPreference
value that matters.
If your module is a binary module, i.e., exports compiled cmdlets (typically implemented in C#):
Compiled cmdlets don’t have their own scope – they run in the caller’s scope. It is therefore the caller’s $ErrorActionPreference
that matters, which can be overridden on a per-call basis with common parameter -ErrorAction
, but only for non-terminating errors.
As with advanced functions in script modules, directly emitted statement-terminating errors[1] are always subject to the caller’s $ErrorActionPreference
value, even if -ErrorAction
is used. (Note that binary cmdlets do not emit script-terminating errors).
[1] Statement-terminating errors occur in the following scenarios:
- Directly, to abort execution of the enclosing cmdlet or advanced function/script:
- When a binary cmdlet encounters a severe error that prevents it from continuing, it reports such an error with the
ThrowTerminatingError()
method (or just throws an exception). - An advanced PowerShell function/script would similarly have to use
$PSCmdlet.ThrowTerminatingError()
, which, however, is rare in practice; the typically usedThrow
statement creates a script-terminating error instead, which by default also terminates the entire thread, i.e., also terminates the caller and all its callers.
- When a binary cmdlet encounters a severe error that prevents it from continuing, it reports such an error with the
- Indirectly, in PowerShell code:
- When an expression causes a runtime error, such as
1 / 0
or'a,b' -split ',', 'NotAnInt'
. - When a .NET method call throws an exception, such as
[int]::Parse('NotAnInt')
- When, inside an advanced function/script, another cmdlet or advanced function / script is called that itself directly emits a statement-terminating error.
- Note that advanced functions/scripts cannot relay statement-terminating errors as such:
- By default (with
$ErrorActionPreference
containing'Continue'
, possibly just in the local scope) the expression’s / other command’s terminating error effectively becomes a non-terminating error from the caller’s perspective. - With
$ErrorActionPreference
set to'Stop'
, the originally statement-terminating error is promoted to a script-terminating error.
- By default (with
- When an expression causes a runtime error, such as