{"id":72152,"date":"2015-07-15T00:01:00","date_gmt":"2015-07-15T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2015\/07\/15\/use-powershell-strict-mode-for-debugging\/"},"modified":"2019-02-18T09:46:59","modified_gmt":"2019-02-18T16:46:59","slug":"use-powershell-strict-mode-for-debugging","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-strict-mode-for-debugging\/","title":{"rendered":"Use PowerShell Strict Mode for Debugging"},"content":{"rendered":"<p><b style=\"font-size:12px\">Summary<\/b><span style=\"font-size:12px\">: Ed Wilson, Microsoft Scripting Guy, talks about using strict mode in Windows PowerShell for debugging purposes.<\/span>\nMicrosoft Scripting Guy, Ed Wilson, is here. One of the cool things about Windows PowerShell is that it can take being ignored or being used carelessly and sloppily, and it still seems to work fine. I mean, in the old days with VBScript, it was common to use Option Explicit to force you to declare all of the variables that you were going to use in the script. In Windows PowerShell, no one seems to do this&hellip;at all.\nThe bad thing is that if I run a script (say in the Windows PowerShell ISE) and the variable increments, if I do not set it to a known number (say 0), or even if I initialize it as $null, each time the script runs, the value of the variable changes. This can be bad for consistent results.\nSo when I have a script that is important and that I want to make sure will always run consistently, I like to initialize my variables&mdash;that is, declare them and set them to an initial value.\nHere is what I am talking about. The first time I run the following code, I print &ldquo;less than four&rdquo; several times:<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;<\/p>\n<p style=\"margin-left:30px\">For ($i = 1; $i -le 5; $i++)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp; $a<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp; $a += $i<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; If ($a -le 4) {&#8220;Less than four&#8221;}}<\/p>\n<p style=\"margin-left:30px\">0<\/p>\n<p style=\"margin-left:30px\">Less than four<\/p>\n<p style=\"margin-left:30px\">1<\/p>\n<p style=\"margin-left:30px\">Less than four<\/p>\n<p style=\"margin-left:30px\">3<\/p>\n<p style=\"margin-left:30px\">6<\/p>\n<p style=\"margin-left:30px\">10<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;&nbsp;\nBut the second time I run the script, I never reach that <b>If<\/b> line because the value of <b>$a<\/b> starts off greater than four:<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;<\/p>\n<p style=\"margin-left:30px\">For ($i = 1; $i -le 5; $i++)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp; $a<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp; $a += $i<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; If ($a -le 4) {&#8220;Less than four&#8221;}}<\/p>\n<p style=\"margin-left:30px\">15<\/p>\n<p style=\"margin-left:30px\">16<\/p>\n<p style=\"margin-left:30px\">18<\/p>\n<p style=\"margin-left:30px\">21<\/p>\n<p style=\"margin-left:30px\">25<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;&nbsp;\nThe way to correct the problem is to initialize <b>$a<\/b> as equal to <b>0 <\/b>(zero) at the beginning of the script. Now, every time I run the script, I get the correct output:<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;$a = 0<\/p>\n<p style=\"margin-left:30px\">For ($i = 1; $i -le 5; $i++)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp; $a<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp; $a += $i<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; If ($a -le 4) {&#8220;Less than four&#8221;}}<\/p>\n<p style=\"margin-left:30px\">0<\/p>\n<p style=\"margin-left:30px\">Less than four<\/p>\n<p style=\"margin-left:30px\">1<\/p>\n<p style=\"margin-left:30px\">Less than four<\/p>\n<p style=\"margin-left:30px\">3<\/p>\n<p style=\"margin-left:30px\">6<\/p>\n<p style=\"margin-left:30px\">10<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;$a = 0<\/p>\n<p style=\"margin-left:30px\">For ($i = 1; $i -le 5; $i++)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp; $a<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp; $a += $i<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; If ($a -le 4) {&#8220;Less than four&#8221;}}<\/p>\n<p style=\"margin-left:30px\">0<\/p>\n<p style=\"margin-left:30px\">Less than four<\/p>\n<p style=\"margin-left:30px\">1<\/p>\n<p style=\"margin-left:30px\">Less than four<\/p>\n<p style=\"margin-left:30px\">3<\/p>\n<p style=\"margin-left:30px\">6<\/p>\n<p style=\"margin-left:30px\">10<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;&nbsp;\nIt might be useful to be able to force Windows PowerShell to tell me that I am using an uninitialized variable. I can easily do this by using Windows PowerShell and the <b>Set-StrictMode<\/b> cmdlet.<\/p>\n<h2>Using the Set-StrictMode cmdlet<\/h2>\n<p class=\"CodeBlockHead\">Here is a simple script, I used yesterday in <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2015\/07\/14\/more-powershell-script-tracing-and-strict-mode.aspx\" target=\"_blank\">More PowerShell Script Tracing and Strict Mode<\/a> that will help illustrate using <b>Set-StrictMode<\/b>:<\/p>\n<p class=\"CodeBlockHead\">SimpleTypingErrorNotReported.ps1<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">$a = 2<br \/> $b = 5<br \/> $d = $a + $b<br \/> &#8220;The value of `$c is: $c&#8221;<\/p>\n<p class=\"Normalunindented\">The <b>Set-StrictMode<\/b> cmdlet can also be used to enable strict mode. It has the advantage of being scope aware. Whereas the <b>Set-PSDebug<\/b> cmdlet applies globally, if the <b>Set-StrictMode<\/b> cmdlet is used inside a function, it enables strict mode for only the function.<\/p>\n<p class=\"Normalunindented\">There are two modes of operation that can be defined when using the <b>Set-StrictMode<\/b> cmdlet. The first is <b>&ndash;version 1<\/b>, which behaves the same as the <b>Set-PSDebug -Strict<\/b> command except that scope awareness is enforced. This is shown here:<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">PS C:\\&gt; Set-StrictMode -version 1<br \/> PS C:\\&gt; C:\\fso SimpleTypingError.ps1<br \/> The variable &#8216;$c&#8217; cannot be retrieved because it has not been set.<br \/> At C:\\fso\\SimpleTypingError.ps1:4 char:28<br \/> + &#8216;The value of $c is: &#8216; + $c &lt;&lt;&lt;&lt;<br \/> &nbsp;&nbsp;&nbsp; + CategoryInfo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : InvalidOperation: (c:Token) [], RuntimeException<br \/> &nbsp;&nbsp;&nbsp; + FullyQualifiedErrorId : VariableIsUndefined<br \/> PS C:\\&gt;\nThe <b>Set-StrictMode<\/b> cmdlet is not able to detect the uninitialized variable contained in the expanding string that is shown in the SimpleTypingErrorNotDetected.ps1 script.\nWhen <b>&ndash;version 2<\/b> is enacted, the technique of calling a function like a method is stopped. The AddTwoError.ps1 script passes two values to the <b>add-two<\/b> function via method notation. Because method notation is allowed when calling functions, no error is normally generated.\nBut method notation of passing parameters for functions only works when there is a single value to pass to the function. To pass multiple parameters, function notation must be used, as shown here:<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">add-two 1 2\nAnother way to call the <b>add-two<\/b> function correctly is to use the parameter names when passing the values, for example:<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">add-two -a 1 -b 2\nEither of the two syntaxes would produce the correct result. The method notation of calling the function displays incorrect information but does not generate an error. An incorrect value being returned from a function with no error being generated can take a significant amount of time to debug. The method notation of calling the <b>add-two<\/b> function is used in the AddTwoError.ps1 script, and it is shown here:<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">add-two(1,2)\nWhen the script is run and the <b>Set-StrictMode -version 2<\/b> command has not been enabled, no error is generated. The output seems to be confusing because the result of adding the two variables <b>$a<\/b> and <b>$b<\/b> is not displayed:<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">PS C:\\&gt; C:\\fso\\AddTwoError.ps1<br \/> 1<br \/> 2<br \/> PS C:\\&gt;\nWhen the <b>Set-StrictMode -version 2<\/b> command is entered and the AddTwoError.ps1 script is run, an error is generated. The error that is generated states that the function was called as if it were a method. The error points to the exact line where the error occurred and shows the function call that caused the error. The function call is preceded with a plus sign (<b>+<\/b>) followed by the name of the function, followed by four arrows that indicate what was passed to the function. The error message is shown here:<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">PS C:\\&gt; Set-StrictMode -version 2<br \/> PS C:\\&gt; C:\\fso\\AddTwoError.ps1<br \/> The function or command was called as if it were a method. Parameters should be<br \/> &nbsp;separated by spaces. For information about parameters, see the about_Parameters Help topic.<br \/> At C:\\FSO\\AddTwoError.ps1:7 char:8<br \/> + add-two &lt;&lt;&lt;&lt; (1,2)<br \/> &nbsp;&nbsp;&nbsp; + CategoryInfo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : InvalidOperation: (:) [], RuntimeException<br \/> &nbsp;&nbsp;&nbsp; + FullyQualifiedErrorId : StrictModeFunctionCallWithParens<br \/> PS C:\\&gt;\nThe complete AddTwoError.ps1 script is shown here:<\/p>\n<p class=\"CodeBlockHead\" style=\"margin-left:30px\">AddTwoError.ps1<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">Function add-two ($a,$b)<br \/> {<br \/> &nbsp;$a + $b<br \/> }<\/p>\n<p> add-two(1,2)\nWhen you specify <b>Set-StrictMode<\/b> for Windows PowerShell version 2.0, it checks the following items:<\/p>\n<ul>\n<li>References to uninitialized variables, directly and from within expanded strings<\/li>\n<li>References to nonexistent properties of an object<\/li>\n<li>Functions that are called like methods<\/li>\n<li>Variables without a name<\/li>\n<\/ul>\n<p>If you specify <b>Set-StrictMode<\/b> for Windows PowerShell version 1.0, it only checks for references to uninitialized variables.\nIf you are not sure whether you want to use strict mode for Windows PowerShell versions 2.0 , 3.0, 4.0, or 5.0 (there are no changes since strict mode 2), an easy way to solve the problem is to use the value <b>Latest<\/b>. By using <b>Latest<\/b> for the value of the <b>-version<\/b> parameter, you always ensure that your script will use the latest strict mode rules. This technique is shown here:<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">Set-StrictMode -version latest\nOne issue that can arise with using <b>Latest<\/b> is that you do not know what the latest changes might do to your script, and a new set of rules might break your script. Therefore, it is generally safer to use <b>&ndash;version 1<\/b> or <b>&ndash;version 2<\/b> when looking for specific types of protection.\nTo turn off strict mode, use the <b>&ndash;Off<\/b> parameter:<\/p>\n<p class=\"CodeBlock\" style=\"margin-left:30px\">Set-StrictMode -Off\nThat is all there is to using Windows PowerShell strict mode. Debugging Week will continue tomorrow when I will talk about more cool stuff.\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.\n<b>Ed Wilson, Microsoft Scripting Guy<\/b><span style=\"font-size:12px\">&nbsp;<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Ed Wilson, Microsoft Scripting Guy, talks about using strict mode in Windows PowerShell for debugging purposes. Microsoft Scripting Guy, Ed Wilson, is here. One of the cool things about Windows PowerShell is that it can take being ignored or being used carelessly and sloppily, and it still seems to work fine. I mean, in [&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":[294,3,4,45],"class_list":["post-72152","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-debugging","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Ed Wilson, Microsoft Scripting Guy, talks about using strict mode in Windows PowerShell for debugging purposes. Microsoft Scripting Guy, Ed Wilson, is here. One of the cool things about Windows PowerShell is that it can take being ignored or being used carelessly and sloppily, and it still seems to work fine. I mean, in [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/72152","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=72152"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/72152\/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=72152"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=72152"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=72152"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}