As the name implies, PowerShell is much more powerful than the standard Windows command prompt. With that power comes a greater possibility of confusing errors. If your script suddenly fails, you may not know where to begin looking for what went wrong. This is where PowerShell's error handling comes in handy.

If you're familiar with other languages, you probably know the basics of error handling, but there are some aspects specific to PowerShell you'll need to know. There are four parts to error handling in PowerShell: the Error Action parameter, Try/Catch blocks, the Error Variable parameter, and logging.

PowerShell Error Handling the Easy Way

The first step in handling PowerShell errors is dealing with something that stops your script in its tracks. If the failure does not affect the rest of your script, it might be best just to tell PowerShell to ignore errors and move on.

On the other hand, it is not always clear when a given cmdlet throws a terminating error. Some cmdlets return an error but do not stop your script. This could leave you waiting for your script to complete while it outputs nonsense.

This is where the -ErrorAction parameter comes in. You use this to force a cmdlet to handle the error the way you want. If you are modifying an existing script, you append it to the end of the cmdlet line.

        Get-ChildItem -Path "~\Documents\*.jpg" -Recurse -ErrorAction Stop
    

Obviously, if you are using the Get-ChildItem cmdlet on its own, this error does not do much for you. However, if you want to do anything with the data, it would be good to stop the script, so you know the search failed and why. Alternatively, if you are doing multiple searches, change the parameter from Stop to SilentlyContinue, so the script continues if a search fails. If you want to see what the error is, you can use Continue as the parameter instead.

        Get-ChildItem -Path "~\Documents\*.jpg" -Recurse -ErrorAction SilentlyContinue
    

If you would rather have the option of controlling what happens each time your script runs, you can change it to Inquire. When your cmdlet hits a snag, it gives options: Yes, Yes For All, Halt Command, Suspend, or Help.

Simple PowerShell error handling using ErrorAction

This option is a bit more flexible but does mean errors cause your script to wait for your input. That's fine if you're using PowerShell to send an email or some other simple task, but it might not be something you want when you're running a long process overnight.

PowerShell Error Handling the Powerful Way

The ErrorAction parameter addresses your errors in an uncomplicated way. However, if you are looking for a bit more control over errors, PowerShell still has you covered. Using Try/Catch, we can now branch the script when cmdlets return an error.

Error handling in PowerShell using try/catch

As the name suggests, Try/Catch is made up of two parts. (There is technically a third, but we will get to that in a minute.) The first is the Try section. You are going to run your normal code in this section. You are still going to use the -ErrorAction parameter, but it can only be set as Stop. This flag ensures that your cmdlet triggers the Catch---even if it does not have a terminating error.

        Try{
  Get-Process "Cortana" -ErrorAction Stop
}

Try can also prevent other cmdlets from running if the search fails. In this case, if you were sending the Get-Process results to Stop-Process, a failed search prevents the second cmdlet from running.

So now that you've created a try block of cmdlets, what do you want to do when it fails? Using the Catch half, you are going to define this.

        Catch{
  Write-Host "Process Not Found"
}

As with the ErrorAction parameter, when you are doing something a bit more complex Catch will be useful for more than giving a plain language failure, especially when you are doing something a bit more complex. (In the example above, the failure is forced by using the app name, and not the process name.) So make sure that you play with the Try block to create a search/action you need. You can use the Catch block for your script to email you if it fails.

The third part comes in handy if you want something to run regardless of whether your cmdlet succeeds or not. For this, you can use the Finally block. You add this after Try and Catch and log when a section of your script ends.

The Error Variable and Logging

Your script now controls how it handles errors and how it responds to them. You can use it as a scheduled task, or at least run it when you are not at your desk. However, how can you investigate a failed script? With the -ErrorVariable parameter your cmdlet's errors write to a custom variable.

This is an alternative to the system $Error variable, which contains all the errors from the current session.

Your cmdlet needs to get a bit longer. First, define a variable, something like $SearchError will do for the example. When you call SearchError in the ErrorVariable parmeter, you don't use the dollar sign.

Even though you're calling a variable you created, due to the way the parameter works you call it without the dollar sign. Then add that to the end of the line.

        Get-ChildItem -Path "~\Documents\*.jpg" -Recurse -ErrorAction Continue -ErrorVariable SearchError
    

If you add a + in front of the variable name, you can add to the variable rather than replace it outright. That gets you the same behavior as the global error variable. Instead, you can use this output and Try/Catch to write custom output, and time stamp it.

PowerShell error logging

To make this work, create a text file right after you set the error variable. Do this with the New-Item cmdlet. You may want to use the Inquire option for the ErrorAction parameter. This lets you add to an existing log when the New-Item cmdlet fails.

        $SearchLog = New-Item "~\SearchLog.txt" -type file -ErrorAction Inquire
    

Now when you build your Try/Catch block, you can use the Catch to log to a text file. You use Get-Date to create the timestamp. The formatting can be tricky so be sure to copy that from the example.

        Try{
  Get-ChildItem -Path "~\Documents\*.jpg" -Recurse -ErrorAction Stop -ErrorVariable SearchError
}
Catch{
  Add-Content -Path $SearchLog -Value "$(Get-Date -Format dd-MM-yy-hh_mm_ss) Files not found returned error: $SearchError"
}

Repeat that as needed for all your cmdlets, and you now have a nice log of any errors. If you want to track things that run successfully you can add a similar Add-Content at the end of the Try block.

This logging only runs when your Try cmdlet succeeds. You can then log your errors and successes with time stamps. The logging now lets you know everything that your script has done, success or failure.

PowerShell Isn't Your Only Option

While PowerShell is a handy tool for plenty of Windows tasks, it can be tough to learn. It's also not suited for everything. If you're doing system maintenance on your computer or checking the integrity of a file, PowerShell is handy. On the other hand, if you're looking to run a script to download files from the internet or some more general task, you have other options.

For example, if you come from a Unix or Linux background, you may be more comfortable using the bash shell. Thanks to the Windows Subsystem for Linux, you can now easily use bash and other Linux tools on your Windows 10 computer. If that sounds perfect to you, look no further than our guide to getting the bash shell running on Windows 10.