Hey, Scripting Guy! How Can I Use $ErrorActionPreference to Control Cmdlet Handling of Errors?
Hey, Scripting Guy! One thing I liked about using VBScript is that I could add On Error Resume Next to the top of a script, and all my problems with the script went away. It was like magic, and I used it to fix many of my scripts. I really miss this capability in Windows PowerShell.
Microsoft Scripting Guy Ed Wilson here. It is Monday morning. Generally, I love Mondays. Although if the truth were told, they are not that much different from Saturdays or Thursdays. A day of scripting is after all a day of scripting, and that means they are all good! Those of you who follow the Scripting Guys on Twitter or Facebook know that you are quite likely to find either Craig or me hanging out over the weekend. This weekend was a bit different. I have been in contact with a professional woodworker who studied with James Krenov at the College of the Redwoods. We sent e-mail back and forth, and he agreed to give me private lessons in his studio. It made for an excellent weekend, but because his studio is several hundred miles away, I am a bit tired this morning. In fact, this morning is an unplanned coffee morning. I have my French press sitting beside my Zune HD, and I am sipping a cup of Peaberry Kona coffee from Kauai, which has a rich, nutty taste with hints of cherry and nutmeg. Whereas I normally put a cinnamon stick in a cup of coffee (a habit I picked up while I was teaching VBScript in Lisbon, Portugal), I feel to do so with this excellent coffee would almost be an insult. The same is true of loading it down with sugar and milk. Therefore, I drink this coffee unadorned. Speaking of Kauai, in addition to having excellent coffee, there is great scuba diving there. The following photograph is one I took during a trip there.
MW, you can achieve something similar to On Error Resume Next by assigning the string SilentlyContinue to the $ErrorActionPreference automatic variable. The reason I say it is similar is that it does not hide all errors. For example, if I try to create an object that does not exist, such as the infamous foo, Windows PowerShell generates an error (in spite of all the examples of this in various programming books). The error seen here tells you it cannot find the type for foo, and that the assembly containing this type is not loaded:
PS C:> New-Object foo
New-Object : Cannot find type [foo]: make sure the assembly containing this type is loaded.
At line:1 char:11
+ New-Object <<<< foo
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
To hide this error, set the value of the automatic variable $ErrorActionPreference to SilentlyContinue, as seen here:
PS C:> $ErrorActionPreference = “silentlycontinue”
PS C:> New-Object foo
This command does not suppress all errors. For example, if I generate a divide-by-zero error, an error appears. Windows PowerShell generates the error regardless of the setting for the $ErrorActionPreference automatic variable. The following code illustrates this:
PS C:> 1/0
Attempted to divide by zero.
At line:1 char:3
+ 1/ <<<< 0
+ CategoryInfo : NotSpecified: (:) , ParentContainsErrorRecordException
+ FullyQualifiedErrorId : RuntimeException
PS C:> $ErrorActionPreference = silentlycontinue
The term ‘silentlycontinue’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:42
+ $ErrorActionPreference = silentlycontinue <<<<
+ CategoryInfo : ObjectNotFound: (silentlycontinue:String) , CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
The difference in behavior is because the $ErrorActionPreference automatic variable controls reporting from cmdlets and not system errors. In addition, it is i
mportant to remember that the $ErrorActionPreference automatic variable is only valid for –not terminating errors. So what is the difference between a terminating error and a nonterminating error? A terminating error is raised by a cmdlet (by calling the ThrowTerminatingError method) when the error is so bad that the cmdlet would not be able to continue processing the pipeline or in some cases the entire script. Generally, these will be syntax errors.
A nonterminating error is one that is not so bad that it would halt the execution of the cmdlet or the script. For example, attempting to read a text file that does not exist does not mean that the Get-Content cmdlet will stop working. If you give it the path to a file that does exist, it will work just fine as shown here:
PS C:> Get-Content foo
Get-Content : Cannot find path ‘C:foo’ because it does not exist.
At line:1 char:12
+ Get-Content <<<< foo
+ CategoryInfo : ObjectNotFound: (C:foo:String) [Get-Content], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
PS C:> Get-Content C:fsoComputers.txt
Therefore, you may wish to hide the error message from the first command by using the $ErrorActionPreference automatic variable. This is shown here:
PS C:> $ErrorActionPreference = “SilentlyContinue”
PS C:> Get-Content foo
PS C:> Get-Content C:fsoComputers.txt
You may wish to see the error messages, perhaps because you are writing a script and you wish to ensure that all the dependencies for the script are in place. When I was teaching VBScript classes all over the world, I would often have students raise their hands during lab time, and state that their script was not working properly, but they were not seeing any errors. I did not even need to leave my desk; I simply told them to comment out the On Error Resume Next line of code. One of the unfortunate things about many of the scripts seen on the Script Center is the constant use of On Error Resume Next, because it hides errors and actually encourages bad practices. I understand why it is there, because you do not want beginners to face many errors when they are taking their first steps into scripting. But at some point, you need to turn it off and fix the script. There is no problem using the command, if you know why the command is used.
By default, the value of $ErrorActionPreference is set to Continue which means that an error will be displayed, but the script (or command) will attempt to continue. There are in fact four values that can be assigned to the $ErrorActionPreference variable: SilentlyContinue, Continue, Stop, and Inquire.
If the value of $ErrorActionPreference is set to Stop, a script will halt execution at the failed command–-even if the subsequent commands would have worked. The following image illustrat
es this concept.
If I would like the user of my script to be prompted for the correct behavior of the error action, I can use the inquire setting. When running from within the Windows PowerShell ISE, a dialog box displays and asks you what action to take. This is shown in the following image.
The dialog box is a bit confusing, but the title of the dialog box is Confirm. Therefore, it states the file does not exist, and it is asking you to confirm if you want to continue processing the script, suspend the script, or halt the command. If you click Yes, the error will be displayed, and the script continues running. This is shown in the following image.
When you run the script from the Windows PowerShell shell (as opposed to the ISE), you are prompted inside the shell with a Confirm prompt as shown in the following image.
MW, that is all there is to using the $ErrorActionPreference variable to control cmdlet handling of errors. Error Handling Week will continue tomorrow.
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at firstname.lastname@example.org or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys