PowerShell Error Handling and Why You Should Care

PowerShell Error Handling and Why You Should Care

  • Comments 15
  • Likes

Summary: Learn how to use error handling in your Windows PowerShell scripts.

Microsoft Scripting Guy, Ed Wilson, is here. Guest Blogger Week continues with Bhargav Shukla.

Photo of Bhargav Shukla

Bhargav Shukla is a senior premier field engineer—unified communications, with his primary focus on the Exchange Server platform. Bhargav has been in IT since the beginning of his career 14 years ago. Before joining Microsoft, he managed to work on almost any technology an IT consultant would be required to know, including Active Directory, Exchange, RSA Security, VMware, Citrix, and Cisco. He also holds industry certifications such as Microsoft Certified Master: Exchange 2010, VMware Certified Professional, Citrix CCEA, RSA: CSE, and Cisco CCNA/CCDA. He started working on scripting with small DOS batch scripts in his early career, and he learned to be a better scripter with new scripting languages. From batch files to VBScript and on to Windows PowerShell, he has written many scripts to address specific needs and reusable functions for repetitive code. When he is not working with customers, Bhargav leads the Philadelphia Area Exchange Server User Group, shares his knowledge on his blog and twitter, plays chess, and flies model airplanes.

Bhargav's contact information:
Blog: Random thoughts of an Exchange PFE Blog
Twitter: bhargavs

When I was judging the scripts submitted for Scripting Games 2011, I noticed that most beginners’ scripts had a common theme, which resembles the scripts I created in my beginner days when I was learning scripting.

It isn’t an accident, nor it is something that all beginners should have known and overlooked. It’s more of a mindset. I remember writing scripts as a beginner, and most of my scripts stayed strict to the goals—I want to accomplish x. The scripts were coded to do only that, and they basically looked like a set of commands strung together with minimally required logic.

As I started writing more scripts, I realized that I was spending more time troubleshooting my scripts when they didn’t work as expected outside of my confined specs. I did not have control over where the scripts are run. I did not have control over environments. I made assumptions that weren’t always true.

As my scripts matured, they included error handling. The more scripts I wrote, the time I spent on actual code decreased, and the time I spent on error handling increased. I wouldn’t claim that all my scripts now run everywhere and as expected, but I can assure you that they inform the user of the unexpected, and sometimes how to handle it when the unexpected is encountered.

The purpose of this post is to familiarize you to the world of error handling in Windows PowerShell. It’s not aimed at advanced error handling or at covering all possible scenarios, but rather to give you the tools to get started. So let’s dive in.

What is error handling?

When the code (your script in this case) encounters something unexpected, it usually fails. The failure usually means the task that you intended to finish with a successful execution of your script, didn’t complete. Writing more code to address what to do when an error is encountered is error handling.

Most of the time, when you write a script and test it in different environments (such as running it on a different machine, using the noprofile switch, or having your friend test it on his laptop), it is very likely that you will see errors. Sometimes when you are writing scripts, you will anticipate that certain things will not work if certain conditions are not met. These examples help you write necessary code to handle anticipated and unexpected errors.

You can write the code so that errors can be handled during execution. Some examples are to ask the user for input; to create a missing folder; or simply to record the error, inform the user, and stop the execution.

How does PowerShell help you handle errors?

Windows PowerShell offers you few ways to learn about an error. The first one I would like to mention is the Error object. Because Windows PowerShell is so very much in love with objects, even an error that a code or a cmdlet encounters is stored in an object. (See how I refrained from using an exclamation point…because this shouldn’t be a surprise? J)

The next best thing (after Swiss cheese) in error handling is the error variable called $error. Every time an error is encountered, the error object is stored in $error variable.

When you start Windows PowerShell, this variable is initialized and contains nothing, which is expected if you started PowerShell and everything in your profile worked without generating an error.

Now, let’s try something that would result in an error:

Get-Item afilethatdoesntexist.txt

You will be greeted with the expected error message.

Now let’s look at the error variable:

PS C:\Temp> $error

Get-Item : Cannot find path 'C:\Temp\afilethatdoesntexist.txt' because it does not exist.

At line:1 char:9

+ Get-Item <<<<  afilethatdoesntexist.txt

    + CategoryInfo          : ObjectNotFound: (C:\Temp...doesntexist.txt:String) [Get-Item], ItemNotFoundExcep

   tion

    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand

So even if your unruly coworker didn’t want you to see the error on screen and cleared screen before calling you to help, you can now see the error that was generated. How cool is that?

The error variable is, however, a circular buffer. It keeps a number of errors in the buffer, and then at its defined capacity, it discards the oldest error objects as new error objects are added. By default, this number is set to 256. If you want to change it, you can simply define it by changing MaximumErrorcount variable. Let’s say you want to set the maximum error objects that are stored to 500—all you need to do is run the following:

$MaximumErrorCount = 500

Another thing I need to mention here is that the errors are stored top down in the array. What I mean by that is that the last error generated is first one in the list. If you want to only see the last error that was generated, you can simply run:

$error[0]

Now you may be thinking, “Great, I know what the error variable is and how to use it in my script, but how do I know that the error was not generated by my script? How do I ensure that the error wasn’t already there when script execution started?”

There are many ways you can approach this. An ugly way is to know the number of errors that are stored in variable before the script starts by using $error.count, and then compare it along the way to see if the number increases. This might work, but it will certainly fail you if the circular buffer is full. In that case, your $error.count will remain the same, even if new errors are generated.

Another way is to clear the error variable when you start. Just run $error.clear(). A downside of this method is that you lose all the errors that were generated before you clear the error variable.

A much better way to handle this is the common parameter called ErrorVariable. When you run any cmdlet, you have the ability to use ErrorVariable, and then store the error that the cmdlet generates in a user-defined variable.

Let’s try the same error-prone command that we tried before—this time with ErrorVariable.

Get-Item afilethatdoesntexist.txt –errorvariable myerrorvariable

Now let’s look at variable that we asked it to create for us.

PS C:\temp> $myerrorvariable

Get-Item : Cannot find path 'C:\temp\afilethatdoesntexist.txt' because it does not exist.

At line:1 char:9

+ Get-Item <<<<  afilethatdoesntexist.txt -errorvariable myerrorvariable

    + CategoryInfo          : ObjectNotFound: (C:\temp\afilethatdoesntexist.txt:String) [Get-Item], ItemNotFoundExcept

   ion

    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand

Now within your scripts, you can refer to the variable that you created and handle errors appropriately. But we haven’t talked about handling errors just yet!

Before we do, I want to talk about a couple other error variables. These variables help you determine whether a command was successful. One such variable is $?. In the sequence of events we have been through so far, the last command resulted in an error. So if I run $?, here is what I will see:

PS C:\temp> $?

False

If you haven’t noticed already, $? is a Boolean value. All it tells you is if the last command was successful (True) or unsuccessful (False, as in our case).

Here’s a test to see if you were paying attention. Answer the question honestly, without trying it in your PowerShell window if you were following along. What will be the value of $? Did you answer it correctly?

The next variable is LastExitCode. If you were following along, try to see if the variable exists by typing $laste<tab>. You will notice that the variable name didn’t expand. It’s not an accident that the variable doesn’t exist. We did encounter errors along the way though, didn’t we? Should this variable exist?

The answer is in the definition of this variable. The variable only applies to external commands and scripts. All we ran previously are built-in Windows PowerShell cmdlets. That explains why the variable doesn’t exist yet.

Let’s try this then. Try to ping localhost. When you do, try to look at $LastExitCode as shown here.

PS C:\temp> $LASTEXITCODE

0

Now try to ping a non-existent computer. What should be the value of $lastexitcode?

Zero indicates that the last execution of the script or external command was successful. However, unlike $?, it’s not a binary. When the execution ends in error, the variable doesn’t always have to be 1. It could be any integer that the external command or script returned.

Also, remember that when external command or script is run, $? will not always tell you a true story. Let’s see why. Create a script that has nothing but one line—our favorite error generating command:

Get-Item afilethatdoesntexist.txt

Now run the script and see the output. You will notice that the host shows you the error. You will also notice that $error contains the error object that was generated by the command in the script. But $? Is set to TRUE! Oh, and don’t try this in the order I mentioned because it will skew the results of $?.

So can you tell me why $? Is set to True? Because your script ran successfully as far as Windows PowerShell is concerned. Every step in script was executed—whether it resulted in an error or not. And that was successful in doing what the script told Windows PowerShell to do. It doesn’t necessarily mean that the commands within script didn’t generate any error. See how quickly it gets confusing? And we haven’t started to go deep yet!

And did you have a, “Wait…what?” moment when I said “…any integer that the external command or script returned”? Yes, your scripts can return an integer exitcode that you define. If you want to try, just modify the script that you created above and add this line.

Exit 123

Run the script, and look at the value of LastExitCode. Isn’t that cool? Making up your own exit code?

When I was talking to Ed about blog ideas, we discussed that I should write about error handling because I was very adamant about it in rating the scripts. I felt that at least errors that are expected must be handled by the submitted scripts, even if they are in Beginner events.

Well, I am already exhausted trying to write about error handling, and we haven’t even scratched the surface. I bet you are too, just trying to keep up with me.

Thank you, Bhargav, for an excellent introduction to error handling.

For additional information on Error Handling in Windows PowerShell scripts, refer to this series of Hey Scripting Guy! blogs.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Great article, Bhargav!

    And my favorite "topic of research"!!!

    You probably should add a second (or more) part(s)!

    We should have a look at try-catch-finally-blocks and at terminating versus not-terminating errors, the idea behind them and when which technique or a combination of both may be applied to a script in order to avoid "invisible errors" paasing by!

    Great introduction and right: beginners trend to ignore error handling and later on you might focus on that topic more and more ... for your own interest!

    kind regards, Klaus

  • This is a good post about the different variables and objects that store errors. Will there be a follow-up post that explains how to "handle" these errors? Something along the lines of "my script generated an error, now what?"

  • Yes, we will be publishing more articles on Error handling series. Stay tuned.

  • This was a very helpful post!  I didn't know about the $? variable.  Thanks!!

  • Great article!  I'll admit I never used error handling in my first round of scripts but have found it more and more useful, especially for automating software installs with SCCM.  I especially am fond of the lastexitcode section since msiexec spits out great error codes!

  • Thanks everyone for your comment. I did mention earlier that we will be publishing next article in series. It has been a while but rest assured, second installment is in works. No specific dates, but when it comes out, it will be worth reading!

    Keep the comments coming.

  • Nice post! Really a nice discussion is done by you. I agree everything you say. In the my opinion,it is more useful to the programmer to the common mistake in the programming. It also described the windows power cell programming errors which is very useful to know the programmer. I hope to you to present this type of the post in the future also.

    <a href="ecommercesoftwarereviewss.com/">ecommerce reviews</a>

    Thanking you.

  • This was a very helpful post! Also I didn't know about the $? variable.  Thanks!

  • $Error is NOT a circular buffer, as you already described, it is a push down stack with the item exceeding $MaximumErrorCount being discarded. That is why $Error[0] is always the last powershell command error that occured. It would be great if the article could be corrected so that those who do not read all the posts have factual information.

    en.wikipedia.org/.../Circular_buffer

  • Thanks for this useful good article.

  • Good one Bhargav, it refreshes my memory. Thank you

  • Thank you Bhargav, very good article.

  • Please correct me if I'm wrong (and I may very well be). But today I was trying to manage errors and discovered that the custom error variable appears to hold objects of different types. So for error #1, I had to access the error message like this: $customerror.exception and for error #2 I needed to use $customerror.message to get the same condensed error message.  I want to catch those errors and put them in a GUI for my user. But I don't know how many types there are, or what the properties of each type might be. How do you handle this?

  • Bhargav this is an excelent article. It would be interesting to know how errors could be handled when using the invoke-command cmdlet. The –errorvariable myerrorvariable does not catch errors generated by this cmdlet, neither do $? and $Lastexitcode but $Error does.

    Perhaps I'm missing something or is this the exeception to the rule?

    Regards,

    Luc

  • Thanks for the post. It is very good.
    But while I am using error variable nothing is captured like "Luc".
    say example I have tired the following command with non valid input.

    get-mailbox testuser -ev err

    Please help me to use ErrorVariable.