13

In PowerShell, what is the difference between throw $ErrorMsg and $PScmdlet.ThrowTerminatingError($ErrorMsg)?

Are they same or different? If they are different which one is preferable?

Seth
  • 1,176
  • 13
  • 32
Samselvaprabu
  • 15,364
  • 28
  • 124
  • 218

1 Answers1

19

Throw creates a script-terminating (runspace-terminating) error, whereas $PScmdlet.ThrowTerminatingError() creates a statement-terminating error.

Note: These aren't official terms (the docs currently only vaguely reference terminating errors in the abstract, without scope), but they're useful for describing the de-facto behavior.

In short: By default,

  • a script-terminating error terminates the entire runspace, i.e., the running script and all its callers, with no further statements getting executed.

    • The only way to intercept them is by using a try / catch statement (or, less commonly, a trap statement).
  • whereas a statement-terminating error terminates only the current statement (the function calling $PScmdlet.ThrowTerminatingError() and the statement it is a part of, which is often a pipeline), with execution continuing with the next statement.

    • They too can be intercepted with try / catch (or trap), or ignored with the $ErrorActionPreference preference variable set to SilentlyContinue; by contrast, the -ErrorAction common parameter has no effect on them.

    • Conversely, you can promote them to script-terminating errors with $ErrorActionPreference = 'Stop', despite the docs claiming that $ErrorActionPreference pertains only to nonterminating errors, the 3rd error type.

For more information, see this (unofficial) overview of PowerShell's error handling.

As for guidance when to use which type of error:

  • There is little guidance as to when to use Throw in the about_Throw help topic; an example use case is given in which Throw is used to abort a function/script in the absence of a mandatory parameter, as an alternative to PowerShell's default behavior of prompting for it.

    • Just be aware that Throw, i.e., throwing a script-terminating error terminates the entire runspace (the running script and any of its callers), unless caught.
  • The Cmdlet Error Reporting article only discusses cmdlet-internal use with respect to when to report statement-terminating (called just "terminating" in the article) vs. nonterminating errors.

    • A concise summary of the article can be found in this answer.

Given the latter, you could argue that advanced functions - since they're like cmdlets - should at most report statement-terminating errors and that Throw (script-terminating errors) should be limited to scripts, but note that that contradicts the use of Throw to enforce mandatory parameters.

Perhaps the problematic distinction between script-terminating and statement-terminating errors is ultimately unintentional and perhaps the original intent was to only ever have script-terminating ones, which would explain why all the current documentation only ever talks about terminating errors in the abstract, without even mentioning the distinction.

mklement0
  • 312,089
  • 56
  • 508
  • 622
  • I prefer to use script-terminating errors 99% of the time. That's simply how exceptions are supposed to work. I realize though, since it's a shell, there are some cases were it might make sense to just write to stderr instead, mostly in pipeline situations when processing multiple items. But to me, that's the "exception" - pun intended ;) – marsze Oct 23 '21 at 10:30
  • 1
    Agreed, @marsze. It wouldn't be officially admitted, but I still suspect that the _statement_-terminating errors were an accident, as also suggested by the fact that the docs never distinguishing between these two subtypes of terminating errors. Whatever the history may be, to me the elimination of statement-terminating errors in favor of only having script-terminating ones makes sense - but it's unlikely that this will happen. – mklement0 Oct 23 '21 at 14:27