I recently wrote a PowerShell script that works great - however, I'd like to now upgrade the script and add some error checking / handling - but I've been stumped at the first hurdle it seems. Why won't the following code work?
try { Remove-Item "C:\somenonexistentfolder\file.txt" -ErrorAction Stop } catch [System.Management.Automation.ItemNotFoundException] { "item not found" } catch { "any other undefined errors" $error[0] } finally { "Finished" }
The error is caught in the second catch block - you can see the output from $error[0]
. Obviously I would like to catch it in the first block. What am I missing?
A try statement can include multiple catch blocks for the different specified error types. The finally keyword is followed by a statement list that runs every time the script is run, even if the try statement ran without error or an error was caught in a catch statement. Note that pressing CTRL + C stops the pipeline.
Try/Catch/Finally The Try, Catch, and Finally blocks in PowerShell allow us to capture terminating errors. The Try block contains the code you'd like to execute, and catch any potential errors that happen. The Catch block contains the code you'd like to execute after a terminating error has occurred.
catch statement is comprised of a try block and either a catch block, a finally block, or both. The code in the try block is executed first, and if it throws an exception, the code in the catch block will be executed. The code in the finally block will always be executed before control flow exits the entire construct.
“try” is a PowerShell block that you want PowerShell to monitor for errors. When any error occurs during the script execution, it will immediately stop at that point and move onto the Catch block if the error is a terminating error.
-ErrorAction Stop
is changing things for you. Try adding this and see what you get:
Catch [System.Management.Automation.ActionPreferenceStopException] { "caught a StopExecution Exception" $error[0] }
That is very odd.
I went through ItemNotFoundException
's base classes and tested the following multiple catch
es to see what would catch it:
try { remove-item C:\nonexistent\file.txt -erroraction stop } catch [System.Management.Automation.ItemNotFoundException] { write-host 'ItemNotFound' } catch [System.Management.Automation.SessionStateException] { write-host 'SessionState' } catch [System.Management.Automation.RuntimeException] { write-host 'RuntimeException' } catch [System.SystemException] { write-host 'SystemException' } catch [System.Exception] { write-host 'Exception' } catch { write-host 'well, darn' }
As it turns out, the output was 'RuntimeException'
. I also tried it with a different exception CommandNotFoundException
:
try { do-nonexistent-command } catch [System.Management.Automation.CommandNotFoundException] { write-host 'CommandNotFoundException' } catch { write-host 'well, darn' }
That output 'CommandNotFoundException'
correctly.
I vaguely remember reading elsewhere (though I couldn't find it again) of problems with this. In such cases where exception filtering didn't work correctly, they would catch the closest Type
they could and then use a switch
. The following just catches Exception
instead of RuntimeException
, but is the switch
equivalent of my first example that checks all base types of ItemNotFoundException
:
try { Remove-Item C:\nonexistent\file.txt -ErrorAction Stop } catch [System.Exception] { switch($_.Exception.GetType().FullName) { 'System.Management.Automation.ItemNotFoundException' { write-host 'ItemNotFound' } 'System.Management.Automation.SessionStateException' { write-host 'SessionState' } 'System.Management.Automation.RuntimeException' { write-host 'RuntimeException' } 'System.SystemException' { write-host 'SystemException' } 'System.Exception' { write-host 'Exception' } default {'well, darn'} } }
This writes 'ItemNotFound'
, as it should.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With