Error handling with PowerShell

Jordan Hammond fun headshot
Jordan Hammond|Updated March 21, 2023
Error Handling With PowerShell
Error Handling With PowerShell

Encountering errors is all part of the PowerShell routine. Well, unless you’re like me, in which case you’ve never encountered a scripting error. In fact, I had to force the scripts in this article to error out just so I could see what it feels like. Dialing back the heavy amounts of sarcasm for a moment, what should we do when we encounter scripting errors? We embark on the ancient battle that has gone on for generations called “error handling.”

What is error handling?

Error handling is the action of dealing with or “handling” errors encountered in a script. It involves dealing with both unexpected and expected errors. With proper foresight and testing, a script should account for the majority of errors it could encounter. Anticipating, detecting, and addressing conditions that could result in an error is the sign of a seasoned script writer.

Terminating versus nonterminating errors in PowerShell

While there are probably thousands of ways a PowerShell script can encounter an error, the key is to know the distinction between terminating and nonterminating errors. Terminating errors are known as exceptions. Exceptions terminate the current execution process or are caught by a Try, Catch, and Finally block (which we’ll cover a bit later). On the other hand, nonterminating errors write the encountered error to the pipeline, then continue executing the script.

ErrorAction in PowerShell

When PowerShell encounters an error, the default behavior is to continue executing the script if it can. This behavior is set with the global variable $ErrorActionPreference. By default, this variable is set to Continue, but you can set several other options. Error behavior can also be set per command using the -ErrorAction common parameter, which is available to every PowerShell command. Here are the options available with the $ErrorActionPreference and -ErrorAction parameters:

  • Continue: Writes the error to the pipeline and continues executing the command or script. This is the default behavior in PowerShell.

  • Ignore: Suppresses error messages and continues executing the command. The errors are never written to the error stream.

  • Inquire: Pauses the execution of the command and asks the user how to proceed. Cannot be set globally with the $ErrorActionPreference variable.

  • SilentlyContinue: Suppresses error messages and continues executing the command. The errors are still written to the error stream, which you can query with the $Error automatic variable.

  • Stop: Displays the error and stops executing the command. This option also generates an ActionPreferenceStopException object to the error stream.

  • Suspend: Suspends a workflow that can later be resumed. The Suspend option is only available to workflows.

I appreciate that the default behavior of PowerShell is set to continue executing the script or command after encountering a nonterminating error. This behavior sets it apart from many other programming languages. But there are times when you’ll want to take advantage of the -ErrorAction options to deal with an error instead of pretending it doesn’t exist (which is what I do with most of my problems).

Anticipating errors in a PowerShell script

One of the most useful skills to develop when writing scripts is the ability to anticipate errors you could encounter. Anticipating errors and proactively addressing them produces highly dependable scripts.

For example, if you write a script that depends on an external file to function properly, it’s feasible to assume a situation where that file no longer exists, its path has changed, or the file name has changed.

Another example is a script that connects to a remote endpoint and returns information. What happens if that remote endpoint is offline and the connection fails?

The more you work with PowerShell, the easier it is to anticipate the types of errors you could encounter and handle them proactively. Now, if I could just anticipate my typing errers …

PowerShell error handling example

Error handling with PowerShell helps ensure that an unexpected exception does not let a script continue to cause issues. Let’s take a look at a script that makes sure only cool people have access to all the cool stuff. (See Get-Content.)

$GroupMembership = Get-ADGroupMember -Identity "Cool Users" $UpdatedCoolList = Get-Content \\FileShare\Location\CoolPeople.csv Foreach($Person in $GroupMembership){ If($UpdatedCoolList -notcontains $Person){ Remove-ADGRoupMember -Identity "Cool Users" -User $Person } }

Works great! However, Kris Powell found out about the cool list. Angry at being left off the list, he performs an action that proves we are right to keep him out. He deletes CoolPeople.csv.

Next time the script runs, we get an exception:

PowerShell image

With a blank $UpdatedCoolList variable, it removes everyone’s access — very not cool, Kris.

ErrorAction example in PowerShell

Before we deal with Kris’s sabotage, let’s look at an example of the -ErrorAction parameter in use. We can use -ErrorAction Stop to turn a nonterminating error into a terminating exception.

$UpdatedCoolList = Get-Content \\FileShare\Location\CoolPeople.csv -ErrorAction Stop

You can also set the default action of all errors to stop by setting the error action global variable.

$ErrorActionPreference = "Stop".

Setting the global variable is generally frowned upon. You have much more control if you set the parameter on each command rather than setting it globally. Just remember, in most cases, a cmdlet generates a nonterminating exception, but error handling with PowerShell requires a terminating exception to work.

Try/Catch/Finally

After the -ErrorAction is set to Stop, we can wrap it in a Try/Catch block. Try is where we run the command, and Catch is what runs if Try encounters a terminating exception. (See Out-File.)

Try { $UpdatedCoolList = Get-Content \\FileShare\Location\CoolPeople.csv -ErrorAction Stop } Catch { $_.Exception | Out-File C:\cool_log\krisdidit.log -Append Break }

In this script block, we captured the exception and put it in a log file. Break was used to exit the script so it would not continue. If we had left the Catch block empty, it would absorb the error and continue the script.

The last piece of the error handling with a Try/Catch/Finally block is the Finally. This is used to provide actions that always run before exiting the script (or continuing on). It is mostly used for cleanup. You can use it to close database connections, remove files, or close file locks. Finally allows you to revert any changes done as a result of the script, whether an exception is encountered or not.

Conclusion

That’s it for the basics. Whenever you are dealing with elements that are volatile or out of your control, error handling is a great way to make sure that your script won’t cause problems if things go wrong.

If you’re looking for ways to test your newly developed skills, check out PDQ Deploy and Inventory. With Deploy and Inventory, you can run scripts remotely on all your endpoints in a flash — or just deploy scripts to the people on your cool list. The choice is yours.

Jordan Hammond fun headshot
Jordan Hammond

Jordan had spent his life wondering why tasks he didn’t like to do had no options to complete themselves. Eventually he had to make that happen on his own. It turned out that he enjoyed making tasks complete themselves, and PDQ thought that is something he should talk about on the internet.

Related articles