Summary: Ed Wilson, Microsoft Scripting Guy, talks about understanding non-terminating errors in Windows PowerShell.
Hey, Scripting Guy! Yesterday in Error Handling: Two Types of Errors, you were talking about terminating errors and how you can use Try/Catch/Finally with those, but you did not really say what a non-terminating error is. Can you talk about that for a little bit please?
—SK
Hello SK,
Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sitting here sipping a cup of English Breakfast tea with a cinnamon stick in it, and munching on a piece of baklava. You see, we just celebrated my birthday weekend, and instead of baking a cake, the Scripting Wife headed out to my favorite Egyptian Café, and picked up some homemade baklava.
When I was in Egypt, I never had baklava. I always thought it was more of a Greek thing. But hey, it works. This little café does an excellent job making baklava, and as it turns out, it is an amazing birthday cake—just a little hard on the candles. It is about a perfect combination with English Breakfast tea. It's a little sticky, but lots of things in life are sticky—like trying to figure out the difference between a terminating and a non-terminating error in Windows PowerShell.
Try/Catch/Finally…doesn’t work
So, I write some code and try to catch an error, but it doesn't work. What’s up with that? Well, if Try/Catch/Finally does not work, there are a few potential problems. The first is that the Catch may be trying to catch something that does not actually happen. For example, if I try to catch an error related to a process that does not exist, but that process does in fact exist, the Catch will not trigger.
So, if I want to catch all errors that occur, I will catch a [System.Exception] because that is the root of all errors. Here is the Catch block I use:
Catch [System.Exception] {"Caught the exception"}
The next thing to realize is that if I try something, and it does not generate a terminating error, it will not move into the Catch block anyway. This is because the default for $ErrorActionPreference (what Windows PowerShell will do when an error arises) is to continue to the next command.
In reality, this means that if an error occurs and Windows PowerShell can recover from it, it will attempt to execute the next command. But it will let you know the error occurred by displaying the error to the console.
If I want to see what Windows PowerShell will do when a non-terminating error arises, I look at the value of the $ErrorActionPreference variable, for example:
PS C:\> $ErrorActionPreference
Continue
Here is a Try statement that tries to do something. It will get a directory list of a missing folder. But because that folder is missing, it will generate an error. Here is the Try/Catch/Finally block:
Try {dir c:\missingFolder }
Catch [System.Exception] {"Caught the exception"}
Finally {$error.Clear() ; "errors cleared"}
When I run the code, and error message appears in the Windows PowerShell console output. It also says that the errors are cleared, which is command that is written into the Finally block. But the System.Exception error was not caught because the “Caught the Exception” string was not emitted. This output is shown here:
If I look at the $Error variable, I see that there are, in fact, no errors there. So the $Error.Clear() command did take place. This is shown here:
PS C:\> $Error
PS C:\> $Error.Count
0
PS C:\>
But, why did the Directory not found error message appear? Because the ErrorAction Preference is set to Continue:
PS C:\> $ErrorActionPreference
Continue
One way to force the error to stop Windows PowerShell, instead of permitting it to continue to the next line, is to change the ErrorAction preference from Continue to Stop. I can do this at the cmdlet level. I use the –ErrorAction automatic parameter from the Get-ChildItem cmdlet (Dir is an alias), and I change it to Stop. This causes the error to terminate the Windows PowerShell execution and forces it to the Catch block. Here is the change:
Try {dir c:\missingFolder -ErrorAction Stop}
Catch [System.Exception] {"Caught the exception"}
Finally {$error.Clear() ; "errors cleared"}
Here is the output:
Note This entire error issue could have been avoided by using tab completion in the first place. This is because C:\missingfolder does not exist, and if I had used tab complete for the directory, I would have seen that it did not appear. By “doing the right thing” in the first place, I could have avoided the complexity of structured error handling—at least for this script.
SK, that is all there is to understanding non-terminating errors. Error Handling Week will continue tomorrow when I will talk about forcing non-terminating errors to terminate.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
Informative article on non-termination errors. For me it was difficult to search since I did not even know that there are non-termination errors as well. Thanks to Google and the Scripting Guy !