{"id":17801,"date":"2010-07-10T00:01:00","date_gmt":"2010-07-10T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2010\/07\/10\/hey-scripting-guy-weekend-scripter-getting-closure-with-the-getnewclosure-method\/"},"modified":"2010-07-10T00:01:00","modified_gmt":"2010-07-10T00:01:00","slug":"hey-scripting-guy-weekend-scripter-getting-closure-with-the-getnewclosure-method","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-weekend-scripter-getting-closure-with-the-getnewclosure-method\/","title":{"rendered":"Hey, Scripting Guy! Weekend Scripter: Getting Closure with the GetNewClosure Method"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p>Microsoft Scripting Guy Ed Wilson here. The first weekend after vacation&mdash;ah! During my one-on-one meeting with my manager this past week, Steve asked me, &ldquo;How is it going?&rdquo; I replied, &ldquo;I need a vacation from my vacation.&rdquo; That tends to be the rule with me rather than the exception. I seldom get to vacate on vacation. This year was no exception; between woodworking classes, visits with old high school buddies, surprise birthday parties for cousins, and visits with my brother, nephew, and mom, I did not get to finish Alexandre Dumas&rsquo; book, <a href=\"http:\/\/en.wikipedia.org\/wiki\/Twenty_Years_After\">Twenty Years After<\/a>. In addition, all the hustle and bustle of vacation seriously hampered my Windows PowerShell script writing. <\/p>\n<p>It is the weekend, and there&rsquo;s no vacation to disturb my leisure. The Scripting Wife is planning on heading over to her friend&rsquo;s house for some kind of party. I did not bother to ask if I was invited for fear that I might actually be expected to make an appearance. Therefore, after a quick breakfast, with teapot in hand I made a beeline to my office. <\/p>\n<p>Windows PowerShell 2.0 introduced many new cmdlets, but the changes were extended under the covers as well. One such addition is the <strong>GetNewClosure<\/strong> method from the <strong>ScriptBlock<\/strong> class. A script block in Windows PowerShell is code inside curly brackets. The <strong>If<\/strong> statement, <strong>foreach<\/strong> statement, <strong>switch<\/strong> statement, and functions all use script blocks. But it can be easier than that to create. Here, for example is a very simple script block. <\/p>\n<p><span style=\"background-color: #f5f5f5\">PS C:\\&gt; {&#8220;hi&#8221;} | gm <br \/>TypeName: System.Management.Automation.ScriptBlock <br \/>Name MemberType Definition <br \/>&#8212;- &#8212;&#8212;&#8212;- &#8212;&#8212;&#8212;- <br \/>Equals Method bool Equals(System.Object obj) <br \/>GetHashCode Method int GetHashCode() <br \/>GetNewClosure Method scriptblock GetNewClosure() <br \/>GetPowerShell Method powershell GetPowerShell(Params System.Object[] a&#8230; <br \/>GetSteppablePipeline Method System.Management.Automation.SteppablePipeline Ge&#8230; <br \/>GetType Method type GetType() <br \/>Invoke Method System.Collections.ObjectModel.Collection[psobjec&#8230; <br \/>InvokeReturnAsIs Method System.Object InvokeReturnAsIs(Params System.Obje&#8230; <br \/>ToString Method string ToString() <br \/>Attributes Property System.Collections.Generic.List`1[[System.Attribu&#8230; <br \/>File Property System.String File {get;} <br \/>IsFilter Property System.Boolean IsFilter {get;set;} <br \/>Module Property System.Management.Automation.PSModuleInfo Module &#8230; <br \/>StartPosition Property System.Management.Automation.PSToken StartPositio&#8230; <br \/>PS C:\\&gt;<\/span><\/p>\n<p>You will notice that when you have the curly brackets, you have an instance of a <strong>System.Management.Automation.ScriptBlock<\/strong> .NET Framework class, and the members of that class are available to you. One of the methods is the <strong>GetNewClosure<\/strong> method. But what does it actually do?<\/p>\n<p>The easiest way to figure out what the <strong>GetNewClosure<\/strong> method does is to illustrate it with a bit of code. The first code will run without the <strong>GetNewClosure<\/strong>, and the second run will be with the <strong>GetNewClosure<\/strong>. <\/p>\n<p><strong>Get-WithoutNewClosure.ps1<\/strong><\/p>\n<p><span style=\"background-color: #f5f5f5\">function Test-Function ([int]$x) <br \/>{ <br \/>Write-Debug &#8220;In Function value of `$x $x&#8221; <br \/>Return { <br \/>param([int]$y) $y + $x <br \/>write-debug &#8220;In Script Block `$x $x `$y $y&#8221;} <br \/>} <br \/>Write-Debug &#8220;Preparing to call test-function and pass value of 2&#8221; <br \/>$m2 = Test-Function 2 <br \/>write-debug &#8220;The value of `$m2 after call function $m2. The value of `$x $x `$y $y&#8221; <br \/>Write-Debug &#8220;Preparing to call test-function and pass value of 5&#8221; <br \/>$m5 = Test-Function 5 <br \/>Write-debug &#8220;The value of `$m5 after call function $m5. The value of `$x $x `$y $y&#8221; <br \/>Write-Debug &#8220;Invoke `&amp;`$m2 and pass vlaue of 3&#8221; <br \/>&amp;$m2 3 #expected: 5 actual: 3 <br \/>Write-debug &#8220;After invoke `&amp;`$m2 and pass value of 3 `$x equals $x `$y equals $y&#8221; <br \/>Write-debug &#8220;Invoke `&amp;`$m5 and pass value of 6&#8221; <br \/>&amp;$m5 6 #expected: 11 actual: 6 <br \/>Write-debug &#8220;After invoke `&amp;`$m5 and pass value of 6 `$x equals $x `$y equals $y&#8221;<\/span><\/p>\n<p>When the script is run, the following output is displayed:<\/p>\n<p><span style=\"background-color: #f5f5f5\">PS C:\\Users\\ed.NWTRADERS&gt; C:\\data\\ScriptingGuys\\2010\\HSG_7_5_10\\Get-WithoutNewClosure.ps1 <br \/>DEBUG: Preparing to call test-function and pass value of 2 <br \/>DEBUG: In Function value of $x 2 <br \/>DEBUG: The value of $m2 after call function <br \/>param([int]$y) <br \/>$y + $x <br \/>write-debug &#8220;In Script Block `$x $x `$y $y&#8221;. The value of $x $y <br \/>DEBUG: Preparing to call test-function and pass value of 5 <br \/>DEBUG: In Function value of $x 5 <br \/>DEBUG: The value of $m5 after call function <br \/>param([int]$y) <br \/>$y + $x <br \/>write-debug &#8220;In Script Block `$x $x `$y $y&#8221;. The value of $x $y <br \/>DEBUG: Invoke &amp;$m2 and pass vlaue of 3 <br \/>3 <br \/>DEBUG: In Script Block $x $y 3 <br \/>DEBUG: After invoke &amp;$m2 and pass value of 3 $x equals $y equals <br \/>DEBUG: Invoke &amp;$m5 and pass value of 6 <br \/>6 <br \/>DEBUG: In Script Block $x $y 6 <br \/>DEBUG: After invoke &amp;$m5 and pass value of 6 $x equals $y equals<\/span><\/p>\n<p>Before running the script, it is important to set the <strong>$DebugPreference<\/strong> variable to <strong>&ldquo;continue&rdquo;<\/strong> as shown here:<\/p>\n<p><span style=\"background-color: #f5f5f5\">$DebugPreference = &#8220;continue&#8221;<\/span><\/p>\n<p>What happens is the <strong>Test-Function<\/strong> function returns a script block. Inside the script block, the variables <strong>$x<\/strong> and <strong>$y<\/strong> do not have any value. When the <strong>$m2<\/strong> and <strong>$m5<\/strong> variables are invoked, the script block code that was returned the first time is executed. The value of <strong>$x<\/strong> is still null, but the value of <strong>$y<\/strong> contains the value that was passed to it. This is shown here:<\/p>\n<p><span style=\"background-color: #f5f5f5\">DEBUG: Invoke &amp;$m2 and pass vlaue of 3 <br \/>3 <br \/>DEBUG: In Script Block $x $y 3 <br \/>DEBUG: After invoke &amp;$m2 and pass value of 3 $x equals $y equals <br \/>DEBUG: Invoke &amp;$m5 and pass value of 6 <br \/>6 <br \/>DEBUG: In Script Block $x $y 6 <br \/>DEBUG: After invoke &amp;$m5 and pass value of 6 $x equals $y equals<\/span><\/p>\n<p>When the <strong>GetNewClosure<\/strong> method is added to the script block, the value that was passed the first time the <strong>Test-Function<\/strong> was called is retained. The Get-WithNewClosure.ps1 script is shown here.<\/p>\n<p><strong>Get-WithNewClosure.ps1<\/strong><\/p>\n<p><span style=\"background-color: #f5f5f5\">function Test-Function ([int]$x) <br \/>{ <br \/>Write-Debug &#8220;In Function value of `$x $x&#8221; <br \/>Return { <br \/>param([int]$y) $y + $x <br \/>write-debug &#8220;In Script Block `$x $x `$y $y&#8221;}.GetNewClosure() <br \/>} <br \/>Write-Debug &#8220;Preparing to call test-function and pass value of 2&#8221; <br \/>$m2 = Test-Function 2 <br \/>write-debug &#8220;The value of `$m2 after call function $m2. The value of `$x $x `$y $y&#8221; <br \/>Write-Debug &#8220;Preparing to call test-function and pass value of 5&#8221; <br \/>$m5 = Test-Function 5 <br \/>Write-debug &#8220;The value of `$m5 after call function $m5. The value of `$x $x `$y $y&#8221; <br \/>Write-Debug &#8220;Invoke `&amp;`$m2 and pass vlaue of 3&#8221; <br \/>&amp;$m2 3 #expected: 5 actual: 3 <br \/>Write-debug &#8220;After invoke `&amp;`$m2 and pass value of 3 `$x equals $x `$y equals $y&#8221; <br \/>Write-debug &#8220;Invoke `&amp;`$m5 and pass value of 6&#8221; <br \/>&amp;$m5 6 #expected: 11 actual: 6 <br \/>Write-debug &#8220;After invoke `&amp;`$m5 and pass value of 6 `$x equals $x `$y equals $y&#8221;<\/span><\/p>\n<p>The results of running the script are shown here:<\/p>\n<p><span style=\"background-color: #f5f5f5\">PS C:\\Users\\ed.NWTRADERS&gt; C:\\data\\ScriptingGuys\\2010\\HSG_7_5_10\\Get-WithNewClosure.ps1 <br \/>DEBUG: Preparing to call test-function and pass value of 2 <br \/>DEBUG: In Function value of $x 2 <br \/>DEBUG: The value of $m2 after call function <br \/>param([int]$y) <br \/>$y + $x <br \/>write-debug &#8220;In Script Block `$x $x `$y $y&#8221;. The value of $x $y <br \/>DEBUG: Preparing to call test-function and pass value of 5 <br \/>DEBUG: In Function value of $x 5 <br \/>DEBUG: The value of $m5 after call function <br \/>param([int]$y) <br \/>$y + $x <br \/>write-debug &#8220;In Script Block `$x $x `$y $y&#8221;. The value of $x $y <br \/>DEBUG: Invoke &amp;$m2 and pass vlaue of 3 <br \/>5 <br \/>DEBUG: In Script Block $x 2 $y 3 <br \/>DEBUG: After invoke &amp;$m2 and pass value of 3 $x equals $y equals <br \/>DEBUG: Invoke &amp;$m5 and pass value of 6 <br \/>11 <br \/>DEBUG: In Script Block $x 5 $y 6 <br \/>DEBUG: After invoke &amp;$m5 and pass value of 6 $x equals $y equals<\/span><\/p>\n<p>When the <strong>GetNewClosure<\/strong> method is added to the script block, it causes the script block to remember the values that were passed the first time. This is shown here:<\/p>\n<p><span style=\"background-color: #f5f5f5\">DEBUG: Invoke &amp;$m2 and pass vlaue of 3 <br \/>5 <br \/>DEBUG: In Script Block $x 2 $y 3 <br \/>DEBUG: After invoke &amp;$m2 and pass value of 3 $x equals $y equals <br \/>DEBUG: Invoke &amp;$m5 and pass value of 6 <br \/>11 <br \/>DEBUG: In Script Block $x 5 $y 6 <br \/>DEBUG: After invoke &amp;$m5 and pass value of 6 $x equals $y equals<\/span><\/p>\n<p>The following image shows the Windows PowerShell ISE after the Get-WithNewClosure.ps1 script has run.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1462.clip_image002_03F8C4EB.jpg\"><\/a><\/p>\n<p><img decoding=\"async\" style=\"max-width: 500px;border: 0px\" alt=\"Image of Windows PowerShell ISE after script has run\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2010\/july\/hey0710\/wes-07-10-01-01.jpg\" width=\"600\" height=\"481\" \/><\/p>\n<p>This technique can be really useful when creating functions that contain other script blocks. For example, it could be useful when writing a function that creates another function on the fly. In addition, it can solve problems that in Windows PowerShell 1.0 necessitated polluting the global variable namespace. <\/p>\n<p>If you want to know exactly what we will be looking at tomorrow, follow us on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\">Twitter<\/a> or <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\">Facebook<\/a>. If you have any questions, send e-mail to us at <a href=\"mailto:scripter@microsoft.com\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/strong><\/p>\n<p><strong><br \/><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Microsoft Scripting Guy Ed Wilson here. The first weekend after vacation&mdash;ah! During my one-on-one meeting with my manager this past week, Steve asked me, &ldquo;How is it going?&rdquo; I replied, &ldquo;I need a vacation from my vacation.&rdquo; That tends to be the rule with me rather than the exception. I seldom get to vacate [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[3,4,134,61,45],"class_list":["post-17801","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-scripting-guy","tag-scripting-techniques","tag-troubleshooting","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Microsoft Scripting Guy Ed Wilson here. The first weekend after vacation&mdash;ah! During my one-on-one meeting with my manager this past week, Steve asked me, &ldquo;How is it going?&rdquo; I replied, &ldquo;I need a vacation from my vacation.&rdquo; That tends to be the rule with me rather than the exception. I seldom get to vacate [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/17801","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\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=17801"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/17801\/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=17801"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=17801"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=17801"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}