PowerShell is the primary command line and scripting language used by Windows operating systems. It lets you run programs and perform system management tasks from the terminal, and it is widely used by system administrators and developers to automate their workflows.
Error Handling is an important part of any scripting and automation. If something goes wrong, your PowerShell scripts shouldn’t just crash — they should identify that an error has occurred, and take action to retry the task, or alert you that something has gone wrong so that you can find and fix the cause.
This guide will provide you with a detailed understanding of Powershell error handling, including types of errors, error handling techniques, examples of how to implement error handling in your scripts, and best practices for throwing, catching, logging, and responding to errors.
Understanding the types of errors in PowerShell
There are two types of errors that you need to handle differently to ensure that your PowerShell scripts are reliable.
Terminating errors halts the execution of your command or script when they occur. These are usually exceptions and can be handled using try/catch blocks (explained later in this article). The causes of terminating errors include syntax errors (when you mistype a command or provide invalid parameters) and internal errors in the application or command you are running.
Non-terminating errors do not halt the execution of your command or script — your PowerShell script will continue running after the error is encountered. Usually, non-terminating errors will display an error message before execution resumes and must be handled differently to terminating errors so that they do not cause your scripts to malfunction if their expected output is required later. Non-terminating errors may be caused by network timeouts, missing files, or permissions issues that, while not a critical exception or error in execution itself, will result in unintended behaviour if not handled.
Basic PowerShell error handling concepts (try, catch, finally, and $ErrorActionPreference)
Terminating errors and exceptions are thrown (the error occurs) and caught (code is executed to handle the error). Uncaught errors will cause execution of your Powershell script to halt. By encapsulating your code in try, catch, and finally blocks, you can manage these kinds of errors.
If code that is run in a try block throws an error, the block of code in the corresponding catch block will be run to handle the error (allowing execution to continue if appropriate). Any cleanup tasks that you want to run whether an error occurred or not can be added to a finally block. This is demonstrated with a full code example further down this page.
Handling non-terminating errors is done differently, as an error isn’t thrown to halt execution, and thus can’t be caught. Instead, the error is stored in the $Error variable, an array of errors that can be accessed at any point in your PowerShell scripts to see if a preceding statement generated a non-terminating error, as shown in this example:
Get-ChildItem -Path "C:fake_path" if ($Error) { Write-Host "Error occurred: $($Error[0])" # Display the most recent error as a string $Error.Clear() # Clear the error }
Above, the Get-ChildItem PowerShell command generates a non-terminating error if the filesystem path it is supplied does not exist (in this case C:fake_path). The error is recorded in the $Error variable, which is then checked and handled.
If you want to assign error output from a particular command to a custom variable, you can use the -ErrorVariable parameter (note that in this case, the error variable is not an array):
Get-ChildItem -Path "C:fake_path" -ErrorVariable customError if ($customError) { Write-Host "Error occurred: $customError" # Display the error as a string }
You can also turn non-terminating errors into terminating errors and handle them with try/catch blocks. You can do this for every non-terminating error encountered in your script by setting the global $ErrorActionPreference variable to Stop:
$ErrorActionPreference = “Stop”
Or, if you only want to do so for errors for a single command, you can set the -ErrorAction Parameter:
Get-ChildItem -Path "C:fake_path" -ErrorAction Stop
Implementing try/catch/finally blocks in PowerShell
Below is an example PowerShell script that demonstrates the syntax and structure of try/catch/finally blocks, showing how to use multiple catch blocks for different exception types, and how to use a finally block to clean up and handle any remaining errors. First, here’s a single error being handled using a try/catch block:
try { # Attempt a file operation that fails Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop } catch { Write-Host "Exception caught: $($_.Exception.Message)" }
You can also handle multiple different types of potential errors in a single try block, handling each with its own catch block:
try { # Each of the below commands will throw a terminating error of a different type Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop # Attempt a file operation that fails to throw a ItemNotFoundException $null.fakeFunction() # Attempt to run a non-existent method on a null object to throw a RuntimeException $divideZero = 1/0 # Divide by zero to throw an exception that won't be specifically caught } catch [System.Management.Automation.ItemNotFoundException] { # Catch the specific error thrown by Get-Content Write-Host "Item not found exception caught: $($_.Exception.Message)" } catch [System.Management.Automation.RuntimeException] { # Catch the specific error thrown by $null.fakeFunction Write-Host "Runtime exception caught: $($_.Exception.Message)" } catch { # Catch all other errors # General catch block for any other exceptions Write-Host "General exception caught: $($_.Exception.Message)" } finally { # The finally block is always executed whether an exception was thrown or not. Write-Host "Executing the finally block." $Error.Clear() # This could, for example, be used to clean up non-terminating errors. }
The purpose of each statement is explained in the code so that you can see the full context of how try, catch, and finally statements work together. Note that as multiple terminating errors occur in the same try block, only the first error will be caught, handled, and then the finally block will be executed. Once this error is fixed, subsequent errors will be caught when the script is executed.
Advanced error handling techniques and examples
It is also possible to nest try/catch blocks, so that errors ‘bubble’ up through them. This lets you handle specific errors in inner try/catch blocks, and handle any uncaught or re-thrown errors, even ones from inside your inner catch blocks, in your outer blocks. For example, you could use nested blocks to handle specific errors, and then use a single outer block to catch and log all errors rather than repeating the code to log them in every inner catch block.
try { # Beginning of the outer catch block try { # Beginning of the inner catch block # Include potentially error-causing code here Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop } catch [System.Management.Automation.ItemNotFoundException] { # Catch statement for the inner catch block that specifically handles ItemNotFoundException Write-Host "Inner try block file not found exception caught: $($_.Exception.Message)" } catch { # Catch statement for the inner catch block that handles all other exceptions Write-Host "Inner try block exception caught: $($_.Exception.Message)" throw # Re-throw the exception so that it will bubble up to the outer try/catch block } } catch { # Catch statement for the outer catch block Write-Host "Outer try block exception caught: $($_.Exception.Message)" # Handle all errors re-thrown in the inner catch blocks here for clean up, logging, and alerting tasks }
Note in the above example, the ItemNotFoundException is not re-thrown, so it won’t bubble up to be caught by the outer catch block.
As you start expanding your PowerShell scripts to cover your own use cases, you will likely want to be able to introduce your own custom exceptions and PowerShell error records:
try { $customException = New-Object Exception "This is a custom error!" # Create and throw a custom error # Create a custom Error Record $customErrorRecord = New-Object System.Management.Automation.ErrorRecord ( $customException, "CustomErrorID", [System.Management.Automation.ErrorCategory]::NotSpecified, # Sets the ErrorRecord category to NotSpecified $null # Specify no specific target object for this error ) throw $customErrorRecord } catch { # Catch and handle the custom error record Write-Host "Error Message: $($_.Exception.Message)" Write-Host "Error ID: $($_.FullyQualifiedErrorId)" }
Above, you can see that no target object is specified (as it is set to $null). You could instead replace this with a file path or other reference and add further detail to the exception text to make the custom error more informative.
Best practices in PowerShell error handling
There are several best practices you should follow when writing your PowerShell scripts to ensure that error handling is effective:
- Write clear and predictable error messages: Your error messages should be descriptive and include enough detail from the Exception or ErrorRecord object to identify the specific cause of an error.
- Ensure that your scripts can continue running (or exit gracefully) if an error is encountered: If your scripts are running other tasks, you may want to handle the error while they continue on. Errors that prevent your script from continuing should cause your script to exit with an exit code, and the result of any errors should be logged and reported.
- Regularly test your error handling and reporting infrastructure: Your PowerShell automatons are useless if they fail without you realizing it. Regularly test your scripts by introducing errors to make sure that your error handling works, the details are logged, and that you are alerted.
Error handling is an important feature of PowerShell scripting and is helpful while you develop your scripting and automation skills. Properly implementing error handling, including correctly throwing errors, using try/catch/finally blocks and leveraging $ErrorActionPreference will help you learn PowerShell syntax, and give you better insight into any problems your scripts encounter, and help you better manage them.