When planning for exception handling, I’ve recently learned that forcing execution to stop by setting $erroractionpreference to ‘Stop’ or by using the –erroraction common parameter requires some special handling.
First let’s see what doesn’t work even though it seems like it should. Handling a normal terminating error is fairly straightforward:
Here we encountered an exception, got the exception’s type by inspecting the first element in the typenames member of the first error record’s exception’s base object, and then used that type name to catch the exception. This worked whether or not we specified the –ea or –erroraction parameter. This works because a ParameterBindingException is a terminating error. However, let’s see what happens when we try the same thing with an error that isn’t of terminating error family:
Hmm, bugger. We tried the same pattern, but this time it just doesn’t work. But…why? Without getting too long winded about it, I tried looking back through the automatic $error variable but couldn’t find an answer. So I tried a different tactic:
Aha! When we use –erroraction stop, the terminating exception isn’t the error that was encountered but an exception of type System.Management.Automation.ActionPreferencesStopException! But…wait, if that’s true, how do we know what type of error was encountered? Almost inexplicably the automatic variable $_ is set to the error record of the error that was encountered. If you know why, please share in the comments or send me an e-mail. Anyway, we can use that to re-throw the error as a terminating exception that can be caught and handled:
Basically we just wrap our command that makes use of the –erroraction stop inside two try/catch blocks. The inner block is used to trap the ActionPreferenceStopException generated by the erroraction parameter. In the inner catch block we throw the exception for the error that was caught which is then caught by the outer catch block statements and can the be handled. So, let’s finish with a generic pattern that one could turn into a code snippet or something:
001
002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 |
try
{ try { # Command that uses -erroraction stop or $erroractionpreference = 'Stop' } # Here we catch the Exception generated by the ErrorAction "Stop" # Only necessary if there is any processing we want to do if the # exception is of type ActionPreferenceStopExecution, # otherwise this block can be deleted catch [System.Management.Automation.ActionPreferenceStopException] { # Error Handling specific to ActionPreferenceStopException goes here # Rethrow the "real" exception as a terminating error Throw $_.exception } # All errors are caught and rethrown to the outer try/catch block # as terminating errors to be handled. catch { Throw $_.exception } } # Here we can resume exception type handling as usual catch #[System.Management.Automation.ItemNotFoundException] { "Got it!" } |
And with that, Happy Friday!