One of the key parts of any good PowerShell script is error handling. Even in the shortest script, being able to handle errors helps to ensure that an unexpected event will not go on to wreck the system you are working on.
The first requirement is to understand the types of errors that can occur during execution.
Terminating vs. Non-Terminating Errors:
When either type of error occurs during execution, it is logged to a global variable called $error. This variable is a collection of PowerShell Error Objects with the most recent error at index 0. On a freshly initialized PowerShell instance (no errors have occurred yet) the $error variable is ready and waiting as an empty collection:
PS C:\> $error.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True ArrayList System.Object PS C:\> $error.Count 0
Error Action Preference:
PowerShell halts execution on terminating errors, as mentioned before. For non-terminating errors we have the option to tell PowerShell how to handle these situations. This is where the error action preference comes in. Error Action Preference allows us to specify the desired behavior for a non-terminating error; it can be scoped at the command level or all the way up to the script level.
Available choices for error action preference:
Example: Set the preference at the script scope to Stop, place the following near the top of the script file:
Example: Set the preference at the cmdlet level to Inquire, add error action switch (or alias EA):
Try/Catch/Finally Blocks:
The Try, Catch, and Finally statements allow us to control script flow when we encounter errors. The statements behave similar to the statements of the same name found in C# and other languages.
The behavior of try/catch is to catch terminating errors (exceptions). This means Non-terminating (operational) errors inside a try block will not trigger a Catch*. If you would like to catch all possible errors (terminating and non-terminating) – then simply set the error action preference to Stop. Remember that Stop error action forces a non-terminating error to behave like a terminating error, which means it can then be trapped in a catch block. Here is an example:
You might be wondering how I found the type name for the previous exception. The possible exceptions for cmdlets are not usually documented, so you may need to find them on your own. When an exception occurs you can look up the error in the $error collection, or while inside a catch block under the $_ variable. Call the GetType() method on the base exception to extract the FullName property. Like shown here:
Handling Errors from non-PowerShell processes:
What happens when your script needs to run an external process from PowerShell and you want to know if it succeeded? An example would be a cmdline tool such as robocopy.exe. It’s an external application that returns an exit code upon completion. But since it is an external process, its errors will not be caught in your try/catch blocks.
To trap this exit code utilize the $LastExitCode PowerShell variable.
When the launched process exits, PowerShell will write the exit code directly to $LastExitCode. In most cases an exit code of 0 means success, and 1 or greater indicates a failure. Check the external tool's documentation to verify of course.
Here it is seen in action: