Error Handling in Windows PowerShell Scripts

PowerShell Error
PowerShell Error

Windows PowerShell is a very powerful and extremely useful tool in today’s IT.  But when it comes to complex PowerShell scripts to automate tasks to make your job a little easier, handling errors properly will go a long way.  Error handling shouldn’t just be limited to big and complex scripts, short scripts benefit a lot also if unexpected events are handled properly so things don’t go south.

There are two types of errors you should worry about in PowerShell — Terminating and Non-terminating errors.  Terminating errors are serious errors during execution that brings the script to a complete stop.  Some examples of this are non-existent cmdlets, syntax errors or other fatal errors.  Non-terminating errors, on the other hand, are not so serious errors that allow execution to continue despite failures.  Examples of this are file not found errors or permission issues.  Non-terminating errors cannot be caught by default but you can treat them as terminating errors to catch and do something about them.  You can also catch specific exceptions in which case you would like to perform specific actions, but you will have to know the name of the exceptions to catch them individually (no examples are provided because these are not common).

Try, Catch and Finally Blocks

The Try block defines a section of a script to be monitored for errors.  That means, if an errors occurs within the Try block, it is first saved to the $Error automatic variable.  PowerShell will then search for a Catch block that handles the error properly.  If a matching Catch block is not found, PowerShell will continue to search for it in the parent scope.

After a Catch block is completes or it no matching Catch block or Trap statement is found, it continues to the Finally block (if used).  Use the Finally block to free resources used by a script after the Try and Catch blocks.  The Finally block runs whether the script inside the Try block fails or not.  It also runs if CTRL+C is used to stop the script or if an Exit keyword stops the script from within a Catch block.

Examples

Catching a Non-Terminating Error

$strUsers = Get-Content C:\UserList.txt

In this example, we are attempting to read a file which may or may not exist.  If the file does not exist, PowerShell will still continue execution of the script but without values in the $strUsers variable, it may fail later.  So to force PowerShell to treat this as a Terminating error, you need to tell it using the ErrorAction parameter.  By specifying -ErrorAction Stop, you ensure that all errors that are thrown by the cmdlet are caught.

$strUsers = Get-Content C:\UserList.txt -ErrorAction Stop

Catching a Terminating Error

Continuing from the previous example, we are attempting to read a file which may or may not exist, this is how we would structure the Try and Catch blocks.  We put the attempt to read the file inside the Try block and in case it fails we send an email message notifying someone that it failed from the Catch block which then terminates the script.

Try
{
     $strUsers = Get-Content C:\UserList.txt -ErrorAction Stop
}
Catch
{
     Send-MailMessage -From script@acme.Com -To admin@acme.Com -Subject "File Read Failed!" -SmtpServer mail.acme.com
     Break
}

Using a Finally Block

You can also add a Finally block after the Catch block to execute something that needs to run regardless of what happens inside the Try block.  So here we get the current date and time stamp and output that to a log file so we can keep track of all the file read attempts.

Try
{
     $strUsers = Get-Content C:\UserList.txt -ErrorAction Stop
}
Catch
{
     Send-MailMessage -From script@acme.Com -To admin@acme.Com -Subject "File Read Failed!" -SmtpServer mail.acme.com
     Break
}
Finally
{
     $execTime = Get-Date
     "File read attempt at $execTime" | out-file c:\logs\userlist.log -append
}