Windows Administration with PowerShell #8: Error Handling
Read Post 1: Introduction, Post 2: Useful Cmdlets, Post 3: Organizing Your Code, Post 4: Authoring Cmdlets and Working with REST APIs, Post 5: Working with WMI, Post 6: Enforcing Absence of an Application , Post 7: Working With MRI Installers)
In any language, error handling is a very important aspect of the development process and provides a variety of benefits. These benefits increase exponentially the more complex your script gets, and allow for a better user experience and future support of your code. Luckily, PowerShell facilitates this through a variety of different methodologies.
ErrorActionPreference and the ErrorAction Parameter
ErrorActionPreference is a variable in PowerShell that dictates how your script will respond when encountering an error. Available configurations for ErrorActionPreference are as follows:
- Stop - Terminate the action and throw an exception
- Inquire - Prompt the user to determine whether or not the script should continue
- Continue - Display an error message and continue with execution of the script
- SilentlyContinue - Do not display an error message and continue with the execution of the script
When you don’t want to set an action for an entire script, you can utilize the ErrorAction parameter to set the desired action for specific cmdlets. How and when you should use each configuration is dependent on the functionality of your script and the type of error you expect to encounter. For example, let’s say you have a script which runs on multiple machines and searches for the presence of a particular registry key. If present, the script will execute some action that requires the result returned. Running the Get-ChildItem cmdlet will get you the required information as shown below:
The problem, however, occurs when the registry does not exist. This cmdlet will return an error, but will not stop the rest of the script from executing:
Since the rest of the actions in your script would require the result from Get-ItemProperty, you would want the script to stop execution once the error is encountered. This can be accomplished using the ErrorActionPreference parameter as demonstrated below:
Once you have defined the way your script should react to errors, you may want to “handle” those errors in a variety of different ways. Sometimes you just want to manipulate the error output into something more readable, and other times you may want to execute some cleanup actions prior to terminating script execution. These scenarios can all be handled using the Try-Catch-Finally block.
Think of this in three separate components:
- Try - Code that needs to be executed
- Catch - Code that should execute in the case of failure of code in the try block
- Finally - Code that should execute regardless of the outcome of the code in the try block
When utilizing a try block, you will need to define either a catch or finally block:
It is important to note that the code in the catch block will only be executed if any of the code in the try block throws a terminating error. As mentioned above, Get-ItemProperty will not throw a terminating error by default. Since we defined the ErrorAction parameter when using the cmdlet as stop, the error that is thrown will terminate the script, thus triggering the catch block.
The difference between using catch as the second block versus using finally is whether or not the error that is returned is suppressed. Any code inside the finally block will execute regardless of the errors that are thrown. You can also use the finally block in conjunction with catch:
In this scenario, the exit code needs to be returned regardless of whether or not there is an error. As such, we put that particular line of code inside the finally block. What exactly is returned will be determined by whether or not the code in the try block executes successfully.
Catching Specific Errors
The catch block also allows you to handle specific errors. This gives you the granularity to react to errors according to what they are. See the code below as an example:
Notice that there are three catch blocks. In the first two, we are handling very specific errors while the third block catches anything else that may pop up.
Manipulating Error Messages
Thrown exceptions contain a lot of useful information, however, there is also information that makes the format in which the exception is returned hard to read:
Luckily, you can manipulate the output of these exceptions to output only the information you find relevant. When errors are thrown, they are stored inside the $error variable. Note: this variable is an array and will store any errors encountered during the execution of a script. But if the errors are terminating the script, what scenario would cause multiple errors in the $error array? All errors will be found here, including non-terminating errors. Therefore, it is important to note when working with this variable that you may need to account for multiple errors.
Using our trusty Get-Member cmdlet, you can take a look at the properties available for the error you want to work with:
You can continue to explore the property sets using Get-Member to find the information you want to output. In our case, we want the error message and the line in which the error occurred. This information lives inside the Exception and InvocationInfo properties respectively:
Handling your errors will make troubleshooting and supporting your scripts much easier down the road. However, when running these scripts across multiple endpoints where do you store all this output? Logging is the answer. Next week, we will go over some tips and tricks that will continue to help make supporting your solutions easier.
Facing growing threats and a rapidly expanding attack surface, understaffed and alert-fatigued organizations need more efficient ways to eliminate their exposure to vulnerabilities. Automox is a modern cyber hygiene platform that closes the aperture of attack by more than 80% with just half the effort of traditional solutions.
Cloud-native and globally available, Automox enforces OS & third-party patch management, security configurations, and custom scripting across Windows, Mac, and Linux from a single intuitive console. IT and SecOps can quickly gain control and share visibility of on-prem, remote and virtual endpoints without the need to deploy costly infrastructure.
Experience modern, cloud-native patch management today with a 15-day free trial of Automox and start recapturing more than half the time you're currently spending on managing your attack surface. Automox dramatically reduces corporate risk while raising operational efficiency to deliver best-in-class security outcomes, faster and with fewer resources.