{"id":1051,"date":"2014-07-05T00:01:00","date_gmt":"2014-07-05T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2014\/07\/05\/weekend-scripter-using-try-catch-finally-blocks-for-powershell-error-handling\/"},"modified":"2014-07-05T00:01:00","modified_gmt":"2014-07-05T00:01:00","slug":"weekend-scripter-using-try-catch-finally-blocks-for-powershell-error-handling","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-using-try-catch-finally-blocks-for-powershell-error-handling\/","title":{"rendered":"Weekend Scripter: Using Try, Catch, Finally Blocks for PowerShell Error Handling"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft PFE, Ashley McGlone, talks about using Try, Catch, Finally blocks for error handling in Windows PowerShell.\nMicrosoft Scripting Guy, Ed Wilson, is here. Today&rsquo;s guest blogger is Ashley McGlone, a Microsoft premier field engineer. Ashley is a popular speaker at our Windows PowerShell Saturday events. He regularly blogs about Active Directory and Windows PowerShell at <a href=\"https:\/\/aka.ms\/GoateePFE\" target=\"_blank\">Goatee PFE<\/a>. You can follow him on Twitter as @GoateePFE. Take it away, Ashley&#8230;\nWhy do scripts have errors? That is a long philosophical debate, and there is more than one correct answer. The generally accepted answer is that they are written by humans, and humans are not perfect. Even when considering all of the reasons there are errors in scripts, the root cause is usually a difference in expectations. I expect the code or data to be X, but really it is Y. And that is why we need error handling.\nThere are many ways to handle errors in Windows PowerShell, including:<\/p>\n<ul>\n<li>$Error.Clear(); Do-Something; If ($Error) {..} Else {..}<\/li>\n<li>Trap<\/li>\n<li>$ErrorActionPreference<\/li>\n<\/ul>\n<p><b>Try, Catch, Finally<\/b> is similar to a Trap block. Trap blocks generally catch any errors in the scope of the entire script or function. The beauty of <b>Try, Catch, Finally<\/b> is that it is like a localized Trap for a specific block of commands. This gives you great flexibility in your error handling. It generally works like this:<\/p>\n<p style=\"margin-left:30px\">Try {<\/p>\n<p style=\"margin-left:30px\">&nbsp;# Do something tricky<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">Catch {<\/p>\n<p style=\"margin-left:30px\">&nbsp;# Run this if a terminating error occurred in the Try block<\/p>\n<p style=\"margin-left:30px\">&nbsp;# The variable $_ represents the error that occurred<\/p>\n<p style=\"margin-left:30px\">&nbsp;$_<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">Finally {<\/p>\n<p style=\"margin-left:30px\">&nbsp;# Always run this at the end<\/p>\n<p style=\"margin-left:30px\">}\n<b>Tip<\/b>&nbsp; Introduced in Windows PowerShell 3.0, you can use CTRL-J in the ISE to insert a <strong>Try, Catch, Finally<\/strong> snippet template to save you some typing.\nWe can also catch multiple errors. Here is an example from the ISE snippet:<\/p>\n<p style=\"margin-left:30px\">try<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;1\/0<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">catch [DivideByZeroException]<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;Write-Host &#8220;Divide by zero exception&#8221;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">catch [System.Net.WebException],[System.Exception]<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;Write-Host &#8220;Other exception&#8221;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">finally<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;Write-Host &#8220;cleaning up &#8230;&#8221;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<h2>Finding .NET exceptions to catch<\/h2>\n<p>Following the <b>Catch<\/b> keyword, you can add .NET exception types as shown in the previous script example. (Fancy programmers call errors &ldquo;exceptions.&rdquo;) These are optional. So where can I find that fanciness to put after the <b>Catch<\/b>? You can sometimes find these on MSDN. For me, the fastest way is using this little trick:<\/p>\n<p style=\"margin-left:30px\">$Error[0] | fl * -Force&nbsp;\nLook at the following example output when we try to divide by zero. Then notice the <b>$Error<\/b> output from the second command. Usually, the .NET exception follows the &lsquo;&#8211;&gt;&rsquo; in the output:<\/p>\n<p style=\"margin-left:30px\">PS C:&gt; 1\/0<\/p>\n<p style=\"margin-left:30px\">Attempted to divide by zero.<\/p>\n<p style=\"margin-left:30px\">At line:1 char:1<\/p>\n<p style=\"margin-left:30px\">+ 1\/0<\/p>\n<p style=\"margin-left:30px\">+ ~~~<\/p>\n<p style=\"margin-left:30px\">&nbsp;+ CategoryInfo&nbsp; &nbsp;: NotSpecified: (:) [], RuntimeException<\/p>\n<p style=\"margin-left:30px\">&nbsp;+ FullyQualifiedErrorId : RuntimeException\n&nbsp;<\/p>\n<p style=\"margin-left:30px\">PS C:&gt; $Error[0] | fl * -Force<\/p>\n<p style=\"margin-left:30px\">PSMessageDetails &nbsp;:<\/p>\n<p style=\"margin-left:30px\">Exception&nbsp;&nbsp; &nbsp;: System.Management.Automation.RuntimeException: Attempted to divide by zero. &#8211;&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.DivideByZeroException: Attempted to divide by zero.<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212; End of inner exception stack trace &#8212;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Management.Automation.IntOps.Divide(Int32 lhs, Int32 rhs)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at&nbsp; &nbsp;System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)<\/p>\n<p style=\"margin-left:30px\">TargetObject&nbsp; &nbsp;:<\/p>\n<p style=\"margin-left:30px\">CategoryInfo&nbsp; &nbsp;: NotSpecified: (:) [], RuntimeException<\/p>\n<p style=\"margin-left:30px\">FullyQualifiedErrorId : RuntimeException<\/p>\n<p style=\"margin-left:30px\">ErrorDetails&nbsp; &nbsp;:<\/p>\n<p style=\"margin-left:30px\">InvocationInfo&nbsp; : System.Management.Automation.InvocationInfo<\/p>\n<p style=\"margin-left:30px\">ScriptStackTrace &nbsp;: at &lt;ScriptBlock&gt;, &lt;No file&gt;: line 1<\/p>\n<p style=\"margin-left:30px\">PipelineIterationInfo : {}\nThat&rsquo;s how we find what to catch (or trap) when handling errors. You have to produce the error once, get the exception string from the extended <b>$Error<\/b> details, and then put that into square brackets following <b>Catch<\/b>. In this case either of the following would work:<\/p>\n<p style=\"margin-left:30px\">catch [DivideByZeroException]<\/p>\n<p style=\"margin-left:30px\">catch [System.DivideByZeroException]\nThis works for most error handling situations.\nTap&#8230;tap&#8230;tap&#8230;Is this thing on?\nSometimes <b>Try, Catch, Finally<\/b> will not catch your error. That&rsquo;s because there are two kinds of errors in Windows PowerShell: terminating and non-terminating. For example, when I type:<\/p>\n<p style=\"margin-left:30px\">PS C:&gt; dir HKLM:\nI get errors in the middle of the output, but it keeps going. That is called a non-terminating error. However, if I try to divide by zero as in the previous example, that is a terminating error that stops the entire script.\nYou can force errors to terminate and hit your <b>Catch<\/b> block by using either of these methods:<\/p>\n<ul>\n<li>$ErrorActionPreference = &lsquo;Stop&rsquo;<\/li>\n<li>Use the common parameter: -ErrorAction Stop<\/li>\n<\/ul>\n<p>In the interest of time, I will refer you to this previous blog post for a good explanation about how this works: <a href=\"http:\/\/blogs.technet.comhttps:\/\/devblogs.microsoft.com\/scripting\/scripting-games-powershell-wrap-up-2\/\" target=\"_blank\">2014 Winter PowerShell Scripting Games Wrap Up #2<\/a>.<\/p>\n<h2>How I&rsquo;ve used Try, Catch, Finally<\/h2>\n<p>Most of my scripting revolves around the Active Directory module. Recently I was trying to use <b>Get-ADObject<\/b> with the <b>ErrorAction<\/b> parameter. Unfortunately, the cmdlet did not seem to obey the <b>ErrorAction<\/b> common parameter very well.<\/p>\n<p style=\"margin-left:30px\"># No joy<\/p>\n<p style=\"margin-left:30px\">$a = Get-ADObject -Identity $Id -Properties $Prop -ErrorAction SilentlyContinue\nI need this functionality, because sometimes the object I was querying may not exist. This syntax would break the script if an error occurred, ignoring the <b>ErrorAction<\/b> parameter. To work around this, I enclosed the offending line of script in a <b>Try<\/b> block, and then I handled the error in the <b>Catch<\/b> block. Here is what I used:<\/p>\n<p style=\"margin-left:30px\">try {<\/p>\n<p style=\"margin-left:30px\">&nbsp;$a = Get-ADObject -Identity $Id -Properties $Prop<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">catch {<\/p>\n<p style=\"margin-left:30px\">&nbsp;$a = $null<\/p>\n<p style=\"margin-left:30px\">}\nNotice that I left off the optional <b>Finally<\/b> block. This code met my needs perfectly.\nI hope you&rsquo;ve enjoyed learning about <b>Try, Catch, Finally<\/b> today. Don&rsquo;t forget to read the Help for more information:<\/p>\n<p style=\"margin-left:30px\">PS C:&gt; Get-Help about_Try_Catch_Finally\nSee these Windows PowerShell Help topics for related information:<\/p>\n<ul>\n<li>about_Preference_Variables<\/li>\n<li>about_CommonParameters<\/li>\n<li>about_Throw<\/li>\n<li>about_Trap<\/li>\n<\/ul>\n<p>~Ashley\nI invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft PFE, Ashley McGlone, talks about using Try, Catch, Finally blocks for error handling in Windows PowerShell. Microsoft Scripting Guy, Ed Wilson, is here. Today&rsquo;s guest blogger is Ashley McGlone, a Microsoft premier field engineer. Ashley is a popular speaker at our Windows PowerShell Saturday events. He regularly blogs about Active Directory and Windows [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[313,68,56,3,4,61,45],"class_list":["post-1051","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-ashley-mcglone","tag-error-handling","tag-guest-blogger","tag-scripting-guy","tag-scripting-techniques","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft PFE, Ashley McGlone, talks about using Try, Catch, Finally blocks for error handling in Windows PowerShell. Microsoft Scripting Guy, Ed Wilson, is here. Today&rsquo;s guest blogger is Ashley McGlone, a Microsoft premier field engineer. Ashley is a popular speaker at our Windows PowerShell Saturday events. He regularly blogs about Active Directory and Windows [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/1051","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=1051"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/1051\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=1051"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=1051"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=1051"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}