You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cmdlet.ThrowTerminatingError() is not affected by -ErrorAction #14819
If a cmdlet uses ThrowTerminatingError() then that ErrorRecord is not affected by the common -ErrorAction parameter. However, it is affected by $ErrorActionPreference. This inconsistency is not a regression from Windows PowerShell 5.1, but is a cause of lots of user confusion. Note that -ErrorAction Break DOES work because the code explicitly checks for that, but other values are not checked.
I've always been confused as to what WriteError() and ThrowTemrinatingError() was for. I always assumed the latter was meant for exceptions and shouldn't be affected by either -ErrorAction or $ErrorActionPreference but it would be good to get some further clarification in the docs or at least the .NET docs for these methods.
I do think a change here would in the long run be an overall positive change, and I'd like to see it personally.
I'm not sure what you could actually change here without causing some real weird breaks though. It seems like a significantly higher risk than what y'all would typically go for.
Eliminate statement-terminating errors altogether and have only one kind of terminating error: runspace-terminating ones (what I've been calling "script-terminating" error for simplicity, given that not every PowerShell user knows or needs to know what a runspace is); that is, .ThrowTerminatingError() would then terminate the runspace by default as well, just like throw already does.
Honestly, I'm not even sure if statement-terminating errors were ever meant to be introduced as such. Certainly, their elimination would make this particular headache go away and greatly simplify error handling overall.
Given the breaking nature of this change, it needs to be opt-in, via a new preference variable, say $PSErrorHandling, with enumeration values Legacy (default, old behavior) and Standard (new behavior), following the pattern proposed for the breaking change needed to fix argument-passing to external programs - see Native invocation using ArgumentList #14692 (comment)
This would additionally provide the opportunity to properly integrate error handling with respect to native applications, instead of introducing a separate $PSNativeCommandErrorAction preference variable - see the native error-handling RFC: https://github.com/PowerShell/PowerShell-RFC/pull/277/files
I'm not even sure if statement-terminating errors were ever meant to be
They are absolutely by design. Statement terminating exceptions are intended to mimic shell semantics. An error in a pipeline (optionally) writes a message then terminates the pipeline and sets $?.
Now PowerShell error objects are much richer than traditional shell errors so one of the scenarios we had in mind was error recovery/remediation based on the contents of the error records. For example, if you're deleting a lot of files and there are some failures, the error records record which files were not deleted and why. This allows you to take additional actions in the script to delete those files.
Error disposition is also much richer in PowerShell through -ErrorAction and $ErrorActionPreference. Unfortunately rich semantics also imply additional complexity. The more choices you can make implies more things to think about.
PowerShell 1.0 also had trap (taken collectively from the Posix shell, Perl 6 and VB.) Trap has the interesting characteristic that it allows you to resume execution after an exception at the next statement in the current lexical context.
Unfortunately trap was difficult to use when dealing with typical "programmer" scenarios so in PowerShell V2 we introduced try/catch . Now you have even more choices. This becomes especially tricky when you start to (inevitably) blend the various semantics.
And one more dimension of complexity - expressions vs commands. For performance reasons, an expression is not evaluated in the context of the pipeline processor so it has slightly different error semantics.
Philosophically, our goal was such that if you wrote shell-style code, then you would get (enhanced) shell semantics and if you wrote programmer-style code (implied by the use of try/catch) then you would get (mostly) programmer semantics.
This doesn't mean that there aren't bugs (there are) or that we got the design totally right. However, tweaking the existing semantics without a total scenario review is unlikely to make things better, just different implying new confusion not less confusion. I do think it would be interesting to do the full scenario review and see if a new "error mode" makes sense. (Note: if we did an error mode it would have to be a compile-time switch i.e. #requires rather than yet another runtime preference variable.)
I've been calling "script-terminating" error for simplicity
Yes - this is the preferred terminology. 'Runspace terminating' is inaccurate as the error doesn't "terminate" the runspace, just the currently executing set of statements i.e. the script.
The full phrase "the current thread of execution" is unfortunately sorta needed there as it doesn't actually terminate the thread (in 99.99% of cases). It's difficult to come up with good terminology for this. Maybe "call stack terminating"? That's going to be mostly meaningless to a lot of folks probably.
Reacted by Bruce Payette and Rain Sallow (/u/ta11ow)
Bruce Payette (@BrucePay), there are multiple problematic aspects with PowerShell's current error handling, so why not take this opportunity to perform the full scenario review you propose:
The lack of integration of native-executable calls into PowerShell's error handling.
The complexity stemming from multiple constructs, as you've discussed.
The surprising asymmetries around the two types of terminating errors that exist, which is what prompted creation of this issue:
-ErrorAction only affects non-terminating errors, while $ErrorActionPreference also affects statement-terminating errors (promotes them to script-terminating ones).
A binary cmdlet can only throw a statement-terminating error.
PowerShell code can only throw a script-terminating error, with throw (unless you go out of your way - available in an advanced script/functions only - to call $PSCmdlet.ThrowTerminatingError(), which is both obscure and cumbersome).
As you state, a change in this area would inevitably be breaking and require an opt-in; a concern regarding a #require directive would again be to ensure lexical scoping rater than the usual dynamic one that affects all descendant scopes - the same issue that just came up in the context of #14747 (comment).
Statement terminating exceptions are intended to mimic shell semantics.
It is the non-terminating errors that mimic shell semantics, while offering additional features (log of errors in $Error, per-command error collection with -ErrorVariable).
cmd.exe offers no terminating errors at all, whereas POSIX-compatible shells offer the equivalent of $ErrorActionPreference = 'Stop', i.e. script-terminating errors via set -e (which is often eschewed in favor or per-call error handling with || exit; we now offer something similar, but with more cumbersome syntax (|| $(exit $LASTEXITCODE) or, if throw is sufficient, || $(throw)).
These shells themselves have no concept of statement-terminating errors (although individual executables can choose to abort pipeline processing by closing their end of the pipe prematurely).
PowerShell's statement-terminating errors offer a way to abort a pipeline instantly, as a whole, in case an error condition so severe is encountered that further pipeline processing makes no sense. Statement-terminating errors also occur in expressions, such as when .NET methods throw an exception.
The question is whether it is helpful to by default terminate only the pipeline / statement being executed.
To me, it isn't: given that it indicates an error condition that is severe, the more sensible behavior is to terminate the script.
That is, we can make do without the concept of a statement-terminating error and only have one type of terminating error: the script-terminating error:
This amounts to a substantial conceptual simplification that automatically makes the above-mentioned asymmetries go away.
Those who want a script-terminating error to be in effect only statement(-block)-terminating can and should use try / catch (or trap, but my sense is that it is rarely used anymore).
I believe that this, along with integrating external-executable calls (treat nonzero exit codes as non-terminating errors, but escalate to script-terminating with $ErrorActionPreference = 'Stop', with the selective exceptions discussed in the Native Command Error Handling RFC), would go a long way toward solving the current problems.
Perhaps the better approach is to give up the quest for a more accurate term, given that the official one should be the friendly "script-terminating", and that with the right interpretation of "script" (a PowerShell thread's implicit top-level script block, right?) it is even defensible as technically accurate.
When talking about implementation, "pipeline" is probably the word to use there. It would be confusing to use in documentation, but a pipeline is sort of the rawest measurement of a unit of execution in PowerShell.
For example, this code:
PowerShell.Create().AddCommand("Get-ChildItem").Invoke()// or more similar to what ConsoleHost does:usingvarpipeline=runspace.CreatePipeline();pipeline.Commands.Add(newCommand("Get-ChildItem",isScript:false));pipeline.Invoke();
There's no script there, it's just a pipeline processor that looks up the command info and creates a command processor.
None of this is to say that "script-terminating" isn't the right term to use for docs, I honestly don't know. Just giving you the full picture.
Are you referring to the fact that in an interactive session the underlying exception is caught, which thereby prevents termination?
I would say that is generally a good way to look at it, and probably a good way to present it when not talking about implementation specifics.
If we were being the absolute strictest of nitpicky, the thread is only terminated when one of these happens:
The Runspace is set to PSThreadOptions.ReuseThread and is GCed
The Runspace is set to PSThreadOptions.UseNewThread and the current top level pipeline is completed (successfully or otherwise)
The Runspace is set to PSThreadOptions.UseCurrentThread and an exception is not caught by the caller
ReuseThread is what most hosts (including ConsoleHost) use. Since execution is actually handled on a different thread controlled by the Runspace object, the actual thread itself won't really terminate.
(P.S. I wrote this before your second post but then got distracted. I still haven't read the second one FYI, so sorry if my delayed answer equated to more work or something)
@PowerShell/powershell-committee reviewed this, we agree that the intent of ThrowTerminatingError() is not to be affected by either -ErrorAction nor $ErrorActionPreference which is only intended to elevate non-terminating errors to be statement terminating and this is a bug. However, we are concerned about breaking existing scripts that may be depending upon this behavior which has been there since at least PowerShell 2.0. Since 7.2 is a LTS, we would not take a change here, but can revisit for 7.3 at the earliest.
intended to elevate non-terminating errors to be statement terminating and this is a bug.
No, -ErrorAction Stop and $ErrorActionPreference = 'Stop' elevate errors to script-terminating (fatal ) ones, not to statement-terminating ones - and that is part of the asymmetry discussed previously.
That is, if we resolved this simply by making $ErrorActionPreference = 'Stop' no longer act on statement-terminating errors, we'd just be introducing a different asymmetry:
It would mean taking away the ability to use $ErrorActionPreference = 'Stop' to abort on errors of any type, which is a common and useful idiom, because statement-terminating errors would then be exempt.
Conversely, this means that the only way to elevate a statement-terminating error to a script-terminating (fatal) one would then be to wrap individual statements (or groups) explicitly in try { ... } catch { throw } - or to use trap { break }, but trap seems to have fallen out of favor.
I may have mentioned this before, but if we simplified the model to only two types of errors: fatal (the current script-terminating ones) and non-fatal (non-terminating), these asymmetries and headaches would go away.
(The word "terminating" is now problematic, given the ambiguity of the scope of the termination).
Since a breaking change is required either way, I suggest breaking things in a more useful manner.
Michael Klement (@mklement0) I agree it may be worth while to consider a proposal that is breaking, but would avoid user confusion for the next "10 years". We should certainly continue that conversation.
The @PowerShell/powershell-committee did discuss the need to use try..catch or trap to elevate an error, but that is the current originally intended design and we were not considering in that discussion a major break
Understood, Steve Lee (@SteveL-MSFT), but my point was that even limiting ourselves to fixing the bug (from the perspective of the original design intent):
results in (different) behavior that is still unhelpful.
does amount to a major break.
To put it differently: we have a major break on our hands either way (which will require an opt-in); the bug fix is not worth making, and I suggest taking the opportunity to get it right for the next "10 years".
Following discussions in #19500 there's a clarification / pedantic point to add.
That issue concerns something different - if the current $errorActionPreference in a function, set by -ErrorAction or inherited from the caller, is silently continue throw is considered to be caught and handled silently, and execution continues.
But it also strayed into -ErrorAction working / not working and ErrorActionPreference.
I think the initial post mis-explains the behaviour
consider this code
function foo {
[CmdletBinding()]
Param( $p)
$ErrorActionPreference ="SilentlyContinue"
if ($P -gt 1) {
$err_rec = [System.Management.Automation.ErrorRecord]::new("Oops","",7,$null)
$PSCmdlet.ThrowTerminatingError($err_rec)
}
"Something bad happens if $p >1 "
}
It sets$ErrorActionPreference - so, according to the initial description, we would expect the error to be supressed but in practice:
> foo 2
foo: Oops
Whatever this error is returned to does what $errorActionPreference says it should do. So if the function is called from a second function:
function bar {
[CmdletBinding()]
Param( $p)
$ErrorActionPreference
foo $p
"returned to bar"
}
Execution continues back in the calling function after printing the error if the preference is continue.
bar 2
Continue
foo:
Line |
19 | foo $p
| ~~~~~~
| Oops
returned to bar
Execution continues back in the calling function WITHOUT printing the error if the preference is SILENTLYcontinue.
bar 2 -ErrorAction SilentlyContinue
SilentlyContinue
returned to bar
And it stops without printing "returned to bar" if the preference is STOP.
If I change the first function to use throw the message "returned to bar" isn't printed
function foo {
[CmdletBinding()]
Param( $p)
if ($P -gt 1) {
$err_rec = [System.Management.Automation.ErrorRecord]::new("Oops","",7,$null)
throw $err_rec
}
"Something bad happens if $p >1 "
}
bar 2
Continue
InvalidOperation:
Line |
6 | throw $err_rec
| ~~~~~~~~~~~~~~
| Oops
but if the error-action-preference is silentlycontinue the throw is caught immediately.
bar 2 -errorAction SilentlyContinue
SilentlyContinue
Something bad happens if 2 >1
returned to bar
This creates problems for people writing and calling functions.
For writers calling $pscmdlet.ThrowTerminatingError() side steps -ErrorAction (think of that as "do X when an error is thrown to you" and the ThrowTerminatingError as "throw an error to your caller") , and throw stops other code running in the calling script - so without try{} Catch{} any clean up is missed.
For callers-ErrorAction silently continue works for some errors, but for a throw it can cause the function code to continue and do something harmful (e.g. in $x = get-thingName; if (-not $x) {throw} ; delete-thing -name "$x*"
-errorAction SilentlyContinue would delete every thing) .
Continuing discussions in #19500 The following idea occurred to me.
-ErrrorAction is a common parameter like , for example -WhatIf
The way that some cmdlets raise errors is not impacted by $ErrorActionPreference, but that does change how the caller processes the error that it receives. Therefore in a cmdlet like Invoke-WebRequest, -ErrorAction does nothing.
Therefore a [cmdletbinding(SupportsErrorAction=$false)] / [cmdletbinding(LocalErrorAction='Stop')] declaration would allow us to prevent the common parameter appearing then it has no effect (as with SupportsShouldProcess and -WhatIf) and prevent $ErrorActionPreference defeating a throw statement.
I haven't thought through all the possible wrinkles with this, but it might ease the problem.
microsoft-github-policy-service commented on Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commented on Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
Activity
jborean93 commentedon Feb 16, 2021
I've always been confused as to what
WriteError()andThrowTemrinatingError()was for. I always assumed the latter was meant for exceptions and shouldn't be affected by either-ErrorActionor$ErrorActionPreferencebut it would be good to get some further clarification in the docs or at least the .NET docs for these methods.mklement0 commentedon Feb 17, 2021
Jordan Borean (@jborean93), please see MicrosoftDocs/PowerShell-Docs#1583
SeeminglyScience commentedon Feb 17, 2021
I do think a change here would in the long run be an overall positive change, and I'd like to see it personally.
I'm not sure what you could actually change here without causing some real weird breaks though. It seems like a significantly higher risk than what y'all would typically go for.
mklement0 commentedon Feb 17, 2021
Here's a possible way forward:
Eliminate statement-terminating errors altogether and have only one kind of terminating error: runspace-terminating ones (what I've been calling "script-terminating" error for simplicity, given that not every PowerShell user knows or needs to know what a runspace is); that is,
.ThrowTerminatingError()would then terminate the runspace by default as well, just likethrowalready does.Given the breaking nature of this change, it needs to be opt-in, via a new preference variable, say
$PSErrorHandling, with enumeration valuesLegacy(default, old behavior) andStandard(new behavior), following the pattern proposed for the breaking change needed to fix argument-passing to external programs - see Native invocation usingArgumentList#14692 (comment)$PSNativeCommandErrorActionpreference variable - see the native error-handling RFC: https://github.com/PowerShell/PowerShell-RFC/pull/277/filesbpayette commentedon Feb 25, 2021
Some history/context:
Michael Klement (@mklement0) wrote:
They are absolutely by design. Statement terminating exceptions are intended to mimic shell semantics. An error in a pipeline (optionally) writes a message then terminates the pipeline and sets
$?.Now PowerShell error objects are much richer than traditional shell errors so one of the scenarios we had in mind was error recovery/remediation based on the contents of the error records. For example, if you're deleting a lot of files and there are some failures, the error records record which files were not deleted and why. This allows you to take additional actions in the script to delete those files.
Error disposition is also much richer in PowerShell through
-ErrorActionand$ErrorActionPreference. Unfortunately rich semantics also imply additional complexity. The more choices you can make implies more things to think about.PowerShell 1.0 also had
trap(taken collectively from the Posix shell, Perl 6 and VB.) Trap has the interesting characteristic that it allows you to resume execution after an exception at the next statement in the current lexical context.Unfortunately
trapwas difficult to use when dealing with typical "programmer" scenarios so in PowerShell V2 we introducedtry/catch. Now you have even more choices. This becomes especially tricky when you start to (inevitably) blend the various semantics.And one more dimension of complexity - expressions vs commands. For performance reasons, an expression is not evaluated in the context of the pipeline processor so it has slightly different error semantics.
Philosophically, our goal was such that if you wrote shell-style code, then you would get (enhanced) shell semantics and if you wrote programmer-style code (implied by the use of
try/catch) then you would get (mostly) programmer semantics.This doesn't mean that there aren't bugs (there are) or that we got the design totally right. However, tweaking the existing semantics without a total scenario review is unlikely to make things better, just different implying new confusion not less confusion. I do think it would be interesting to do the full scenario review and see if a new "error mode" makes sense. (Note: if we did an error mode it would have to be a compile-time switch i.e.
#requiresrather than yet another runtime preference variable.)Yes - this is the preferred terminology. 'Runspace terminating' is inaccurate as the error doesn't "terminate" the runspace, just the currently executing set of statements i.e. the script.
mklement0 commentedon Feb 25, 2021
SeeminglyScience commentedon Feb 25, 2021
The full phrase "the current thread of execution" is unfortunately sorta needed there as it doesn't actually terminate the thread (in 99.99% of cases). It's difficult to come up with good terminology for this. Maybe "call stack terminating"? That's going to be mostly meaningless to a lot of folks probably.
mklement0 commentedon Feb 25, 2021
mklement0 commentedon Feb 25, 2021
Bruce Payette (@BrucePay), there are multiple problematic aspects with PowerShell's current error handling, so why not take this opportunity to perform the full scenario review you propose:
The lack of proper documentation and official terminology, which Our Error Handling, Ourselves - time to fully understand and properly document PowerShell's error handling MicrosoftDocs/PowerShell-Docs#1583 addresses, but it's obviously no substitute for official documentation.
The lack of integration of native-executable calls into PowerShell's error handling.
The complexity stemming from multiple constructs, as you've discussed.
The surprising asymmetries around the two types of terminating errors that exist, which is what prompted creation of this issue:
-ErrorActiononly affects non-terminating errors, while$ErrorActionPreferencealso affects statement-terminating errors (promotes them to script-terminating ones).throw(unless you go out of your way - available in an advanced script/functions only - to call$PSCmdlet.ThrowTerminatingError(), which is both obscure and cumbersome).As you state, a change in this area would inevitably be breaking and require an opt-in; a concern regarding a
#requiredirective would again be to ensure lexical scoping rater than the usual dynamic one that affects all descendant scopes - the same issue that just came up in the context of #14747 (comment).It is the non-terminating errors that mimic shell semantics, while offering additional features (log of errors in
$Error, per-command error collection with-ErrorVariable).cmd.exeoffers no terminating errors at all, whereas POSIX-compatible shells offer the equivalent of$ErrorActionPreference = 'Stop', i.e. script-terminating errors viaset -e(which is often eschewed in favor or per-call error handling with|| exit; we now offer something similar, but with more cumbersome syntax (|| $(exit $LASTEXITCODE)or, ifthrowis sufficient,|| $(throw)).These shells themselves have no concept of statement-terminating errors (although individual executables can choose to abort pipeline processing by closing their end of the pipe prematurely).
PowerShell's statement-terminating errors offer a way to abort a pipeline instantly, as a whole, in case an error condition so severe is encountered that further pipeline processing makes no sense. Statement-terminating errors also occur in expressions, such as when .NET methods throw an exception.
The question is whether it is helpful to by default terminate only the pipeline / statement being executed.
To me, it isn't: given that it indicates an error condition that is severe, the more sensible behavior is to terminate the script.
That is, we can make do without the concept of a statement-terminating error and only have one type of terminating error: the script-terminating error:
try/catch(ortrap, but my sense is that it is rarely used anymore).I believe that this, along with integrating external-executable calls (treat nonzero exit codes as non-terminating errors, but escalate to script-terminating with
$ErrorActionPreference = 'Stop', with the selective exceptions discussed in the Native Command Error Handling RFC), would go a long way toward solving the current problems.SeeminglyScience commentedon Feb 25, 2021
When talking about implementation, "pipeline" is probably the word to use there. It would be confusing to use in documentation, but a pipeline is sort of the rawest measurement of a unit of execution in PowerShell.
For example, this code:
There's no script there, it's just a pipeline processor that looks up the command info and creates a command processor.
None of this is to say that "script-terminating" isn't the right term to use for docs, I honestly don't know. Just giving you the full picture.
I would say that is generally a good way to look at it, and probably a good way to present it when not talking about implementation specifics.
If we were being the absolute strictest of nitpicky, the thread is only terminated when one of these happens:
Runspaceis set toPSThreadOptions.ReuseThreadand is GCedRunspaceis set toPSThreadOptions.UseNewThreadand the current top level pipeline is completed (successfully or otherwise)Runspaceis set toPSThreadOptions.UseCurrentThreadand an exception is not caught by the callerReuseThreadis what most hosts (includingConsoleHost) use. Since execution is actually handled on a different thread controlled by theRunspaceobject, the actual thread itself won't really terminate.(P.S. I wrote this before your second post but then got distracted. I still haven't read the second one FYI, so sorry if my delayed answer equated to more work or something)
2 remaining items
SteveL-MSFT commentedon Mar 3, 2021
@PowerShell/powershell-committee reviewed this, we agree that the intent of
ThrowTerminatingError()is not to be affected by either-ErrorActionnor$ErrorActionPreferencewhich is only intended to elevate non-terminating errors to be statement terminating and this is a bug. However, we are concerned about breaking existing scripts that may be depending upon this behavior which has been there since at least PowerShell 2.0. Since 7.2 is a LTS, we would not take a change here, but can revisit for 7.3 at the earliest.mklement0 commentedon Mar 4, 2021
Steve Lee (@SteveL-MSFT)
No,
-ErrorAction Stopand$ErrorActionPreference = 'Stop'elevate errors to script-terminating (fatal ) ones, not to statement-terminating ones - and that is part of the asymmetry discussed previously.That is, if we resolved this simply by making
$ErrorActionPreference = 'Stop'no longer act on statement-terminating errors, we'd just be introducing a different asymmetry:It would mean taking away the ability to use
$ErrorActionPreference = 'Stop'to abort on errors of any type, which is a common and useful idiom, because statement-terminating errors would then be exempt.Conversely, this means that the only way to elevate a statement-terminating error to a script-terminating (fatal) one would then be to wrap individual statements (or groups) explicitly in
try { ... } catch { throw }- or to usetrap { break }, buttrapseems to have fallen out of favor.I may have mentioned this before, but if we simplified the model to only two types of errors: fatal (the current script-terminating ones) and non-fatal (non-terminating), these asymmetries and headaches would go away.
(The word "terminating" is now problematic, given the ambiguity of the scope of the termination).
Since a breaking change is required either way, I suggest breaking things in a more useful manner.
SteveL-MSFT commentedon Mar 4, 2021
Michael Klement (@mklement0) I agree it may be worth while to consider a proposal that is breaking, but would avoid user confusion for the next "10 years". We should certainly continue that conversation.
The @PowerShell/powershell-committee did discuss the need to use
try..catchortrapto elevate an error, but that is the current originally intended design and we were not considering in that discussion a major breakmklement0 commentedon Mar 6, 2021
Understood, Steve Lee (@SteveL-MSFT), but my point was that even limiting ourselves to fixing the bug (from the perspective of the original design intent):
To put it differently: we have a major break on our hands either way (which will require an opt-in); the bug fix is not worth making, and I suggest taking the opportunity to get it right for the next "10 years".
jhoneill commentedon Apr 15, 2023
Following discussions in #19500 there's a clarification / pedantic point to add.
That issue concerns something different - if the current $errorActionPreference in a function, set by -ErrorAction or inherited from the caller, is silently continue
throwis considered to becaughtand handled silently, and execution continues.But it also strayed into
-ErrorActionworking / not working and ErrorActionPreference.I think the initial post mis-explains the behaviour
consider this code
It sets
$ErrorActionPreference- so, according to the initial description, we would expect the error to be supressed but in practice:Whatever this error is returned to does what
$errorActionPreferencesays it should do. So if the function is called from a second function:Execution continues back in the calling function after printing the error if the preference is continue.
Execution continues back in the calling function WITHOUT printing the error if the preference is SILENTLYcontinue.
And it stops without printing "returned to bar" if the preference is STOP.
As already pointed out by Michael Klement (@mklement0) et al. "terminating" errors have multiple varieties
If I change the first function to use
throwthe message "returned to bar" isn't printedbut if the error-action-preference is
silentlycontinuethe throw is caught immediately.This creates problems for people writing and calling functions.
For writers calling
$pscmdlet.ThrowTerminatingError()side steps-ErrorAction(think of that as "do X when an error is thrown to you" and theThrowTerminatingErroras "throw an error to your caller") , andthrowstops other code running in the calling script - so without try{} Catch{} any clean up is missed.For callers
-ErrorAction silently continueworks for some errors, but for a throw it can cause the function code to continue and do something harmful (e.g. in$x = get-thingName; if (-not $x) {throw} ; delete-thing -name "$x*"-errorAction SilentlyContinue would delete every thing) .
jhoneill commentedon Apr 18, 2023
Continuing discussions in #19500 The following idea occurred to me.
-ErrrorActionis a common parameter like , for example-WhatIf$ErrorActionPreference, but that does change how the caller processes the error that it receives. Therefore in a cmdlet likeInvoke-WebRequest,-ErrorActiondoes nothing.[cmdletbinding(SupportsErrorAction=$false)]/[cmdletbinding(LocalErrorAction='Stop')]declaration would allow us to prevent the common parameter appearing then it has no effect (as withSupportsShouldProcessand-WhatIf) and prevent$ErrorActionPreferencedefeating a throw statement.I haven't thought through all the possible wrinkles with this, but it might ease the problem.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 23, 2023
This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.