{"id":1994,"date":"2015-05-12T00:00:00","date_gmt":"2015-05-12T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/a-plethora-of-powershell-pitfalls-part-2\/"},"modified":"2017-09-28T13:09:27","modified_gmt":"2017-09-28T13:09:27","slug":"a-plethora-of-powershell-pitfalls-part-2","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/a-plethora-of-powershell-pitfalls-part-2\/","title":{"rendered":"A Plethora of PowerShell Pitfalls: Part 2"},"content":{"rendered":"<ul class=\"series-articles\">\n<li>\n<p><a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/a-plethora-of-powershell-pitfalls\/\">A Plethora of PowerShell Pitfalls<\/a> Part 1: Pesky Parameter Problems<\/p>\n<\/li>\n<li class=\"series-articles--active\">\n<p>A Plethora of PowerShell Pitfalls Part 2:\u00a0 A Portion of Potential Puzzles<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/the-poster-of-the-plethora-of-powershell-pitfalls\/\">The Poster for a Plethora of PowerShell Pitfalls: Pretty Powerful Panaceas<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>A Portion of Potential Puzzles<\/h2>\n<p>In the <a href=\"http:\/\/www.simple-talk.com\/sysadmin\/powershell\/a-plethora-of-powershell-pitfalls\/\">previous installment<\/a><span class=\"MsoHyperlink\"> of the Plethora of PowerShell Pitfalls<\/span>, you had a chance to test your PowerShell acumen against issues with parameter assignments in PowerShell, both direct and across function-calling boundaries. This article rounds out my top ten pitfalls with a few more challenges regarding constructing commands in PowerShell. To reiterate from last time, here are my suggested guidelines for moving forward:<\/p>\n<ul>\n<li>First, try to answer the short list of questions <em>without executing the code<\/em>. Exercise your mental muscles. Give it some thought. Try to figure out the <strong><em>what<\/em><\/strong>.<\/li>\n<li>Next, go ahead and execute the code to see if you were right. If not, now given the answers, see if you understand the <strong><em>why<\/em><\/strong>.<\/li>\n<li>Finally, continue reading through the answers and explanations to reveal the <strong><em>what<\/em><\/strong> and the <strong><em>why<\/em><\/strong>.<\/li>\n<\/ul>\n<h2>The Questions<\/h2>\n<p>Try to answer these questions <i>before<\/i> executing the code.<\/p>\n<h3>Question 1<\/h3>\n<p>Here is \u00a0a function <b>Count-Args<\/b> that merely returns the count of the number of arguments passed to it&#8230;<\/p>\n<pre>function Count-Args()\r\n{\r\n\u00a0\u00a0\u00a0 $args.Count\r\n} \r\n<\/pre>\n<p>&#8230;so, for example, invoking <code> Count-Args 1 2 \"\" <\/code> &#8221; <code>abc\"<\/code> <code> r<\/code>eturns the value 4.<\/p>\n<p>Now assume you have an equivalent executable program ( <b>CountArgs.exe<\/b>) that performs the same function: What then is the result of executing this statement? (a copy of CountArgs.exe is is provided in a link at the bottom of the article in case you&#8217;d like to try this out)<\/p>\n<pre class=\"lang:ps theme:powershell-output\">\u00a0PS&gt; .\\CountArgs.exe  1  2  \"\"  \"abc\"<\/pre>\n<h3>Question 2<\/h3>\n<p>Consider a function that outputs the concatenation of its two arguments:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">function f([string]$a, [string]$b)\r\n{\r\n\u00a0\u00a0\u00a0 $a + $b\r\n}\r\n\t<\/pre>\n<p>What is the output of this code?<\/p>\n<pre>PS&gt; $item1 = 'abc'\r\nPS&gt; $item2 = '123456'\r\nPS&gt; f $item1 item2 \r\n<\/pre>\n<h3>Question 3<\/h3>\n<p>You have created the <b>Greetings.psm1 <\/b>PowerShell module containing only this function:<\/p>\n<pre>function Send-Greetings()\r\n{\r\n\u00a0\u00a0\u00a0 \"Hello, world\"\r\n} \r\n<\/pre>\n<p>You import the module (which is in your current directory) and run the function:<\/p>\n<pre>PS&gt; Import-Module .\\Greetings.psm1\r\nPS&gt; Send-Greetings\r\nHello, world\r\n<\/pre>\n<p>Only then do you realize that you meant to say &#8220;everyone&#8221; instead of &#8220;world&#8221;, so you open Greetings.psm1, change &#8220;world&#8221; to &#8220;everyone&#8221;, save the file, then rerun the same two lines. What is the output now?<\/p>\n<pre>PS&gt; Import-Module .\\Greetings.psm1\r\nPS&gt; Send-Greetings\r\n<\/pre>\n<h3>Question 4<\/h3>\n<p>Define a simple array, then display all its items, and finally display the first two items:<\/p>\n<pre>PS&gt; $myArray = 1,2,3,4,5\r\nPS&gt; $myArray\r\n1\r\n2\r\n3\r\n4\r\n5\r\nPS&gt; $myArray | Select-Object -First 2\r\n1\r\n2\r\n<\/pre>\n<p>Similarly, for a hash table, define its key\/value pairs, and then display the hash table contents:<\/p>\n<pre>PS&gt; $myHashTable = @{\"alpha\" = 1; \"beta\" = 2; \"gamma\" = 'a string' }\r\n\tPS&gt; $myHashTable\r\nName\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Value\r\n----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ----- \r\nalpha\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 1\r\nbeta\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2 \r\ngamma\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 a string\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \r\n\t<\/pre>\n<p>What is the output when you execute this?<\/p>\n<pre>PS&gt; $myHashTable | Select-Object -First 2<\/pre>\n<h2><a id=\"Toc414818189\"><\/a>The Answers<\/h2>\n<p>As with most endeavors, the more you put in the more you get out, so have a go at answering the above questions before continuing on to the answers. Each exposition below repeats the question but this time with the answer. Challenge yourself yet a second time: see if you can figure out why you get the given answer before reading the subsequent explanation.<\/p>\n<h2>Question 1: Beware the Empty String in Positional Parameters<\/h2>\n<div class=\"question\">\n<p>We have a function <b>Count-Args<\/b> that merely returns the count of the number of arguments passed to it&#8230;<\/p>\n<pre>function Count-Args()\r\n{\r\n\u00a0\u00a0\u00a0 $args.Count\r\n} \r\n<\/pre>\n<p>&#8230;so, for example, invoking <code> Count-Args 1 2 \"\" <\/code> &#8221; <code>abc\"<\/code> <code> r<\/code>eturns the value 4.<\/p>\n<p>Now assume you have an equivalent executable program ( <b>CountArgs.exe<\/b>) that performs the same function: What then is the result of executing this statement?<\/p>\n<pre class=\"lang:ps theme:powershell-output\">\u00a0PS&gt; .\\CountArgs.exe  1  2  \"\"  \"abc\"<\/pre>\n<p><b> <i>Answer:<\/i> <\/b><\/p>\n<pre>\t3\r\n<\/pre>\n<\/div>\n<p>In DOS, some commands are <i>built-in<\/i> to the shell, like <b>dir<\/b> and <b>echo<\/b>, and some are <i>external applications<\/i> or <i>executables<\/i>, like <b>ping.exe<\/b> and <b>ipconfig.exe<\/b>. In PowerShell, you have three tiers instead of two: <i> cmdlets<\/i>, <i>scripts<\/i>, and <i>executables<\/i>. If you pass-from a DOS shell-an empty string as one of several arguments to an executable, that empty string is, quite naturally, one of those arguments. However, if you do the same from a PowerShell window, that empty string vanishes! That does not sound too good, but wait-it gets worse! While you could rationalize that as a PowerShell difference to be aware of, it is not quite as simple as that. PowerShell is inconsistent: if you pass an empty string to a PowerShell cmdlet or to a PowerShell script, then it <i>keeps<\/i> that empty string.<\/p>\n<p>Let&#8217;s look closer. The versatile <a href=\"https:\/\/pscx.codeplex.com\/\">PowerShell Community Extensions module<\/a> (PSCX) contains a collection of supplemental cmdlets to make you more productive in PowerShell, but it also contains a diagnostic utility called echoargs.exe (located in C:\\Program Files (x86)\\PowerShell Community Extensions\\Pscx3\\pscx\\Apps on my machine once I installed PSCX). Consider this command executed both in DOS and in PowerShell-I have omitted the path to the executable for brevity:<\/p>\n<pre class=\"\">C:\\&gt; echoargs word \"two words\" \"\" 123\r\nPS&gt; echoargs word \"two words\" \"\" 123<\/pre>\n<p>That clearly passes four arguments to the <b> echoargs<\/b> executable. But examine the results: DOS sees four arguments but the empty string argument is invisible to PowerShell!<\/p>\n<table>\n<thead>\n<tr>\n<td>\n<p><b> DOS<\/b><\/p>\n<\/td>\n<td>\n<p><b> PowerShell<\/b><\/p>\n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<p>Arg 0 is &lt;word&gt;<\/p>\n<p>Arg 1 is &lt;two words&gt;<\/p>\n<p>Arg 2 is &lt;&gt; <b> # correct<\/b><\/p>\n<p>Arg 3 is &lt;123&gt;<\/p>\n<\/td>\n<td>\n<p>Arg 0 is &lt;word&gt;<\/p>\n<p>Arg 1 is &lt;two words&gt;<\/p>\n<p>Arg 2 is &lt;123&gt; <b> # wrong<\/b><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4>\u00a0 <b>The Fix<\/b><\/h4>\n<p>To make PowerShell behave correctly in this regard, it is necessary to use PowerShell&#8217;s <i>verbatim parameter<\/i> (see section 8.2, Pipeline Statements, in the <a href=\"http:\/\/www.microsoft.com\/en-us\/download\/details.aspx?id=36389\">PowerShell Language Specification<\/a> ) that effectively makes anything after it on the command line act like a DOS command line.<\/p>\n<div class=\"note\">\n<p>Author&#8217;s note: the below should read <em>PS&gt; echoargs hyphen hyphen percent<\/em><\/p>\n<\/div>\n<table>\n<thead>\n<tr>\n<td>\n<p><b> PowerShell with verbatim parameter<\/b><\/p>\n<p><b> PS&gt; echoargs &#8211;% word &#8220;two words&#8221; &#8220;&#8221; 123<\/b><\/p>\n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<p>Arg 0 is &lt;word&gt;<\/p>\n<p>Arg 1 is &lt;two words&gt;<\/p>\n<p>Arg 2 is &lt;&gt; <b> # correct<\/b><\/p>\n<p>Arg 3 is &lt;123&gt;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Thus, using the verbatim parameter is a reasonable fix-when you know you have an empty string on the command line. But what about when you <i>don&#8217;t<\/i> know that you have one? We are back to the original problem-the empty string disappears!<\/p>\n<table>\n<thead>\n<tr>\n<td>\n<p><b> PowerShell with empty string disguised in a variable<\/b><\/p>\n<p><b> PS&gt; $myVariable = &#8220;&#8221; <br \/>\n PS&gt; echoargs word &#8220;two words&#8221; $myVariable 123 <\/b><\/p>\n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<p>Arg 0 is &lt;word&gt;<\/p>\n<p>Arg 1 is &lt;two words&gt;<\/p>\n<p>Arg 2 is &lt;123&gt; <b> # wrong<\/b><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0Unfortunately, the verbatim parameter cannot fix this case, because <b>$myVariable<\/b> is no longer being parsed by PowerShell:<\/p>\n<div class=\"note\">\n<p>Author&#8217;s note: the below should read <em>PS&gt; echoargs hyphen hyphen percent<\/em><\/p>\n<\/div>\n<table>\n<thead>\n<tr>\n<td>\n<p><b> PowerShell with empty string disguised in a variable<\/b><\/p>\n<p><b> PS&gt; $myVariable = &#8220;&#8221; <br \/>\n PS&gt; echoargs &#8211;% word &#8220;two words&#8221; $myVariable 123 <\/b><\/p>\n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<p>Arg 0 is &lt;word&gt;<\/p>\n<p>Arg 1 is &lt;two words&gt;<\/p>\n<p>Arg 2 is &lt;$empty&gt; <b> # wrong<\/b><\/p>\n<p>Arg 3 is &lt;123&gt;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0The fix for this case is to use a peculiar quoting trick (kudos to Keith Hill for this):<\/p>\n<table>\n<thead>\n<tr>\n<td>\n<p><b> PowerShell with escaped, quoted empty string disguised in a variable<\/b><\/p>\n<p><b> PS&gt; $myVariable = &#8220;&#8221; <br \/>\n PS&gt; echoargs word &#8220;two words&#8221; `&#8221;$myVariable`&#8221; 123 <\/b><\/p>\n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<p>Arg 0 is &lt;word&gt;<\/p>\n<p>Arg 1 is &lt;two words&gt;<\/p>\n<p>Arg 2 is &lt;&gt; <b> # correct<\/b><\/p>\n<p>Arg 3 is &lt;123&gt;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"quote\">Know Your Arguments <br \/>\n When Passing To an External <br \/>\n Application (a .exe file)<\/div>\n<p>\u00a0While ugly, this last technique works both for variables and for literals, and does not constrain the rest of your line to be DOS-like, so it is the best choice for a challenging situation. (For even more on this, see this <a href=\"http:\/\/stackoverflow.com\/q\/23640434\/115690\">StackOverflow post<\/a>.)<\/p>\n<h2>Question 2: Beware the String, Too<\/h2>\n<div class=\"question\">\n<p>Consider a function that outputs the concatenation of its two arguments:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">function f([string]$a, [string]$b)\r\n{\r\n\u00a0\u00a0\u00a0 $a + $b\r\n}\r\n\t<\/pre>\n<p>What is the output of this code?<\/p>\n<pre>PS&gt; $item1 = 'abc'\r\nPS&gt; $item2 = '123456'\r\nPS&gt; f $item1 item2 \r\n<\/pre>\n<h4>Answer:<\/h4>\n<pre>\tabcitem2<\/pre>\n<\/div>\n<p>PowerShell is used by some as a powerful <i> scripting<\/i> language. By others, it is used as a powerful <i>shell<\/i> language. Because it is both, however, there are occasions where its convenience as a shell language causes problem when you are scripting. Consider this typical shell command:<\/p>\n<pre>Get-ChildItem  *.tmp,*.txt <\/pre>\n<p>\u00a0If I typed <b>dir<\/b> instead of <b>Get-ChildItem<\/b>, that would also work just fine in a DOS shell; if I used <b>ls<\/b>, it would also work fine in a Linux shell. But there is something rather peculiar about it if you think from the perspective of a programming language-the string constants (*.tmp and *.txt) are not quoted! That is, many conventional programming languages would require something like this:<\/p>\n<pre>Get-ChildItem  \"*.tmp\",\"*.txt\" <\/pre>\n<p>\u00a0And that is <i>also<\/i> just fine in PowerShell. Unlike conventional programming languages, quotes around a string constant are often not necessary, to make typing shell commands more convenient. The downside of all this, though, is that if you meant to type a variable (e.g. <b>$stuff<\/b>) but accidentally omitted the dollar sign, then you might not get any complaint from PowerShell because it will just be taken as an unquoted string constant. Consider:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$one = \"t.*\"\r\n\"one\",\"two\",\"three\" | select-string $one\r\n<\/pre>\n<p>That will return &#8220;two&#8221; and &#8220;three&#8221;. But omit the <b>$<\/b> on the last argument like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$one = \"t.*\"\r\n\"one\",\"two\",\"three\" | select-string one\r\n<\/pre>\n<p>&#8230;and there is <i>no<\/i> error. The return value is quite different though; it returns &#8220;one&#8221;.<\/p>\n<div class=\"quote\">Never Assume Your <br \/>\n \u00a0Code Works- <br \/>\n Verify That it Does<\/div>\n<h4><b>The Fix<\/b><\/h4>\n<p>Aye, there&#8217;s the rub. There is no &#8220;strict&#8221; switch or other automatic checking capability to detect such a situation; you will need to resort to the old-fashioned way: code review, unit tests, etc.<\/p>\n<h2>Question 3: Your Code Changes are Ignored<\/h2>\n<div class=\"question\">\n<p>You have created the <b>Greetings.psm1 <\/b>PowerShell module containing only this function:<\/p>\n<pre>function Send-Greetings()\r\n{\r\n\u00a0\u00a0\u00a0 \"Hello, world\"\r\n} \r\n<\/pre>\n<p>You import the module (which is in your current directory) and run the function:<\/p>\n<pre>PS&gt; Import-Module .\\Greetings.psm1\r\nPS&gt; Send-Greetings\r\nHello, world\r\n<\/pre>\n<p>Only then do you realize that you meant to say &#8220;everyone&#8221; instead of &#8220;world&#8221;, so you open Greetings.psm1, change &#8220;world&#8221; to &#8220;everyone&#8221;, save the file, then rerun the same two lines. What is the output now?<\/p>\n<pre>PS&gt; Import-Module .\\Greetings.psm1\r\nPS&gt; Send-Greetings\r\n<\/pre>\n<h4><b>Answer:<\/b><\/h4>\n<pre>\tHello, world<\/pre>\n<\/div>\n<p>Once you start writing your own PowerShell functions, you will soon realize that you need to organize your functions into modules for ease of use and ease of maintenance. So let&#8217;s say you have a module called MyGoodStuff. You would load this module for use with the Import-Module command:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Import-Module `\r\n \u00a0\u00a0\u00a0\u00a0\u00a0 work\/myModules\/MyGoodStuff.psd1<\/pre>\n<p>\u00a0You then proceed to exercise some function contained within that module and realize there is a bug. You correct that bug, save the file, then re-import the module:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Import-Module `\r\n \u00a0\u00a0\u00a0\u00a0\u00a0  work\/myModules\/MyGoodStuff.psd1<\/pre>\n<p>\u00a0You try your function again, confident your bug has been fixed&#8230; but without ever seeing your code, I can guarantee that your function will still fail.<\/p>\n<p><b>The Fix<\/b><\/p>\n<p>The problem is not your code, it is your command. Once you load a module into a given PowerShell session, attempting to reload it normally will not do anything. You either need to unload the module then reload it:<\/p>\n<div class=\"quote\">Read the Fine Print <br \/>\n (the documentation) <br \/>\n \u00a0on Standard Cmdlets <br \/>\n to Avoid Surprises<\/div>\n<pre class=\"lang:ps theme:powershell-ise\">Remove-Module MyGoodStuff \r\nImport-Module work\/myModules\/MyGoodStuff.psd1 \r\n\t<\/pre>\n<p>\u00a0Or you can do it in a single command by adding the <b>-Force<\/b> parameter:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Import-Module  -Force  work\/myModules\/MyGoodStuff.psd1\u00a0 <\/pre>\n<h2>Question 4: Piping a Hash Table<\/h2>\n<div class=\"question\">\n<p>Define a simple array, then display all its items, and finally display the first two items:<\/p>\n<pre>PS&gt; $myArray = 1,2,3,4,5\r\nPS&gt; $myArray\r\n1\r\n2\r\n3\r\n4\r\n5\r\nPS&gt; $myArray | Select-Object -First 2\r\n1\r\n2\r\n<\/pre>\n<p>Similarly, for a hash table, define its key\/value pairs, and then display the hash table contents:<\/p>\n<pre>PS&gt; $myHashTable = @{\"alpha\" = 1; \"beta\" = 2; \"gamma\" = 'a string' }\r\n\tPS&gt; $myHashTable\r\nName\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Value\r\n----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ----- \r\nalpha\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 1\r\nbeta\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2 \r\ngamma\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 a string\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \r\n\t<\/pre>\n<p>What is the output when you execute this?<\/p>\n<pre>PS&gt; $myHashTable | Select-Object -First 2<\/pre>\n<h4>Answer<\/h4>\n<pre>Name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Value\r\n----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ----- \r\nalpha\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 1\r\nbeta\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2 \r\ngamma\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 a string\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \r\n<\/pre>\n<\/div>\n<p>Many PowerShell cmdlets are designed so that the output of one cmdlet may be used as the input to another cmdlet by using a <i>pipeline<\/i>. A cmdlet that generates suitable output to do this is simply one that outputs a stream of objects of a single type (or a set of compatible types). Typically, such a stream can be visualized as just an array. This example uses an explicit array of simple integers piped to <b>ForEach-Object<\/b>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">1,  2,  3,  4,  5  |  ForEach-Object  { Write-Output \"Number is $PSItem\" } <\/pre>\n<p>\u00a0&#8230;or this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$myArray = 1, 2, 3, 4, 5\r\n$myArray | ForEach-Object { $PSItem }\r\n\t<\/pre>\n<p>The output of a suitable cmdlet works the same way-here the output of <b>Get-Process<\/b> is a stream of <b> System.Diagnosis.Process<\/b> objects, and that output is piped to <b>Select-Object<\/b> where it reports just the specified properties from each object:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-Process  |  Select-Object  ProcessName,  Id <\/pre>\n<p>This convenient and powerful pipelining mechanism runs into a problem, though, when you have another common PowerShell data structure, a hash table. A hash table is essentially a dictionary: you can look up a value by its key. They are easy to create and easy to use. Consider this hash table:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$myHashTable= @{\"alpha\" =1; \"beta\" =2; \"gamma\" = 'a string' }<\/pre>\n<p>\u00a0You could then reference <b> $myHashTable[&#8216;alpha&#8217;]<\/b>, or even <b>$myHashTable.alpha<\/b>, to retrieve the value 1, while <b>$myHashTable.beta<\/b> returns the value 2, and <b>$myHashTable.gamma<\/b> returns &#8220;a string&#8221;.<\/p>\n<p>What seems to follow naturally, then, is that you should be able to do this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$myHashTable| ForEach-Object { $PSItem } <\/pre>\n<p>Compare what happens with an <i>array<\/i> vs. what happens with a <i>hash table<\/i>&#8230; and it looks like it worked just fine. (Note that <b>%{$_}<\/b> is just an abbreviation for <b> ForEach-Object { $PSItem}<\/b> )<\/p>\n<table>\n<thead>\n<tr>\n<td>&nbsp;<\/td>\n<td>Array<\/td>\n<td>Array through pipe<\/td>\n<td colspan=\"2\">HashTable<\/td>\n<td colspan=\"2\">HashTable through pipe<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><i>Input<\/i><\/td>\n<td>$myArray<\/td>\n<td>$myArray | %{$_}<\/td>\n<td colspan=\"2\">$myHashTable<\/td>\n<td colspan=\"2\">$myHashTable | %{$_}<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"5\"><i> Output<\/i><\/td>\n<td>1<\/td>\n<td>1<\/td>\n<td>Name<\/td>\n<td>Value<\/td>\n<td>Name<\/td>\n<td>Value<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>2<\/td>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>3<\/td>\n<td>alpha<\/td>\n<td>1<\/td>\n<td>alpha<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>4<\/td>\n<td>4<\/td>\n<td>beta<\/td>\n<td>2<\/td>\n<td>beta<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>5<\/td>\n<td>5<\/td>\n<td>gamma<\/td>\n<td>a string<\/td>\n<td>gamma<\/td>\n<td>a string<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>But looks can be deceiving! Let&#8217;s take just the first item in the pipeline and see what happens:<\/p>\n<table>\n<thead>\n<tr>\n<td>&nbsp;<\/td>\n<td>Array in pipe<\/td>\n<td colspan=\"2\">HashTable in pipe<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><em>Input<\/em><\/td>\n<td>$myArray | Select -First 1<\/td>\n<td colspan=\"2\">$myHashTable | Select -First 1<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"5\"><em>Output<\/em><\/td>\n<td rowspan=\"5\">1<\/td>\n<td>Name<\/td>\n<td>Value<\/td>\n<\/tr>\n<tr>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<\/tr>\n<tr>\n<td>alpha<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>beta<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>gamma<\/td>\n<td>a string<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0The first item of an array is just the first item of an array; no surprises there. But the first item fed through the pipeline with a hash table is the <i>entire<\/i> hash table! As it turns out, that is by design: a hash table passes through the pipeline <i>as a single object<\/i>.<\/p>\n<h4><b>The Fix<\/b><\/h4>\n<p>In order to feed individual key\/value pairs from a hash table one at a time, you need to explicitly use the hash table&#8217;s enumerator. This will turn the single hash table object into a collection of <b>DictionaryEntry<\/b> objects. You obtain the enumerator with the hash table&#8217;s <b>GetEnumerator<\/b> method. The next table shows the difference. At left you can see that using the enumerator on the entire hash table yields identical results to what you have already seen-so it is certainly no worse(!)-but is it better? At right, you can see that, yes, when we try to take just the first item, that is exactly what it does!<\/p>\n<table>\n<thead>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">HashTable<\/td>\n<td colspan=\"2\">HashTable in pipe<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><em>Input<\/em><\/td>\n<td colspan=\"2\">$myHashTable.GetEnumerator() | % {$_}<\/td>\n<td colspan=\"2\">$myHashTable.GetEnumerator() | Select -First 1<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"5\"><em>Output<\/em><\/td>\n<td>Name<\/td>\n<td>Value<\/td>\n<td>Name<\/td>\n<td>Value<\/td>\n<\/tr>\n<tr>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<\/tr>\n<tr>\n<td>alpha<\/td>\n<td>1<\/td>\n<td>alpha<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>beta<\/td>\n<td>2<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>gamma<\/td>\n<td>a string<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0Having successfully placed a stream of <b> DictionaryEntry<\/b> objects in the pipeline, you can now handle hash tables with more dexterity. Say, for example, you want to sort a hash table by its keys in reverse order. Without the enumerator, it fails because, as you now know, it passes the entire hash table as a single object. With the enumerator, we have <b>DictionaryEntry<\/b> objects, each of which has a <b>Key<\/b> and a <b>Value<\/b> property, so we can specify a sort on the <b>Key<\/b> in a descending order:<\/p>\n<table>\n<thead>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">Sort Without Enumerator<\/td>\n<td colspan=\"2\">Sort With Enumerator<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><em>Input<\/em><\/td>\n<td colspan=\"2\">$myHashTable | Sort-Object -Descending<\/td>\n<td colspan=\"2\">$myHashTable.GetEnumerator() | Sort-Object -Property Key -Descending<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"5\"><em>Output<\/em><\/td>\n<td>Name<\/td>\n<td>Value<\/td>\n<td>Name<\/td>\n<td>Value<\/td>\n<\/tr>\n<tr>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<td>&#8212;<\/td>\n<\/tr>\n<tr>\n<td>alpha<\/td>\n<td>1<\/td>\n<td>gamma<\/td>\n<td>a string<\/td>\n<\/tr>\n<tr>\n<td>beta<\/td>\n<td>2<\/td>\n<td>beta<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>gamma<\/td>\n<td>a string<\/td>\n<td>alpha<\/td>\n<td>1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0Finally, consider the standard filtering\/projection operation, performed with <b>Where-Object<\/b>. Applied to an array, you get a smaller array:<\/p>\n<table>\n<thead>\n<tr>\n<td>\n<p><b>\u00a0<\/b><\/p>\n<\/td>\n<td>\n<p><b>Whole Array<\/b><\/p>\n<\/td>\n<td>\n<p><b>Filtered Array<\/b><\/p>\n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<p><i> Input<\/i><\/p>\n<\/td>\n<td>\n<p>$myArray<\/p>\n<\/td>\n<td>\n<p>$myArray | Where { $_ -gt 3 }<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p><i> Output<\/i><\/p>\n<\/td>\n<td>\n<p>1<\/p>\n<p>2<\/p>\n<p>3<\/p>\n<p>4<\/p>\n<p>5<\/p>\n<\/td>\n<td>\n<p>4<\/p>\n<p>5<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0It would be handy if we could similarly filter a hash table and just get a smaller hash table. But since PowerShell requires that the first step is to convert the hash table to a collection of <b>DictionaryEntry<\/b> object, the challenge is to convert the list of <b>DictionaryEntry<\/b> objects, after filtering, back to a hash table. PowerShell does not provide any built-in way to do this, though. Jeffrey Hicks posted a useful function to convert general objects to a hash table (<a href=\"http:\/\/jdhitsolutions.com\/blog\/2013\/01\/convert-powershell-object-to-hashtable-revised\/\">Convert PowerShell Object To Hashtable, revised<\/a>) but for our purposes, this is all you need:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">function ConvertTo-HashTable\r\n{\r\n\u00a0\u00a0\u00a0 [CmdletBinding()]\r\n\u00a0\r\n\u00a0\u00a0\u00a0 param(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [Parameter(Position=0, Mandatory, ValueFromPipeline,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HelpMessage='Please specify an object')]\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [System.Collections.DictionaryEntry]$InputObject\r\n\u00a0\u00a0\u00a0 )\r\n\u00a0\r\n\u00a0\u00a0\u00a0 BEGIN {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $newHash = @{}\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 PROCESS {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $newHash[$InputObject.Key] = $InputObject.Value \r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 END {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $newHash\r\n\u00a0\u00a0\u00a0 }\r\n} \r\n<\/pre>\n<table>\n<thead>\n<tr>\n<td>\n<p><b>\u00a0<\/b><\/p>\n<\/td>\n<td>\n<p><b>Raw Filter<\/b><\/p>\n<\/td>\n<td>\n<p><b>Filter Then Convert to HashTable<\/b><\/p>\n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2186-img60.gif\" alt=\"2186-img60.gif\" \/><\/td>\n<td><code> $result = $myHashTable.GetEnumerator() |<\/code> <code> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Where-Object Key -eq \"gamma\"<\/code> <code> $result.GetType().Name<\/code><\/td>\n<td><code> $result = $myHashTable.GetEnumerator() |<\/code> <code> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Where-Object Key -eq \"gamma\" |<\/code> <code> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ConvertTo-HashTable<\/code> <code> $result.GetType().Name<\/code><\/td>\n<\/tr>\n<tr>\n<td><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2186-img5E.gif\" alt=\"2186-img5E.gif\" \/><\/td>\n<td>\n<p>DictionaryEntry<\/p>\n<p>&#8230;or Object[]<\/p>\n<p>&#8230;or <i> error!<\/i><\/p>\n<\/td>\n<td>\n<p>Hashtable<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"quote\">When Working <br \/>\n with a Hash Table, <br \/>\n Remember its <br \/>\n Enumerator<\/div>\n<p>\u00a0If you have read my previous installment of <a href=\"http:\/\/www.simple-talk.com\/sysadmin\/powershell\/a-plethora-of-powershell-pitfalls\/\">A Plethora of PowerShell Pitfalls<\/a>, and specifically the section on what I call <i>The Conundrum of None, One, or Many<\/i>, you will recall that I explained that the <i>type<\/i> of object returned depends on the <i>quantity<\/i> of objects returned. Indeed, at left above the return type could be (depending on your <b>Where-Object<\/b> predicate) either <b>DictionaryEntry<\/b> as shown, or it could be <b>Object[]<\/b>, or it could even be an error! Conveniently, the <b>ConvertTo-HashTable<\/b> function exercised at right above does not care how many objects it gets: it will always return a hash table!<\/p>\n<p>(With thanks to Klaus Graefensteiner in his post &#8220;When PowerShell hash table magic backfires&#8221; for making me think more about this whole topic.<\/p>\n<h2>Conclusion<\/h2>\n<p>PowerShell has been around for some time now, but it is still fairly new to a lot of people. Often developers try to glean just enough understanding to get through a given task at hand. But PowerShell offers some unique challenges that could cause problems without a thorough understanding of the mechanics and semantics. I have tried to illuminate some of these here. Besides keeping an eye out for these, try to reduce your potential for subtle errors by letting PowerShell help you: Use PowerShell&#8217;s strict mode, use strong typing (which is quite optional in PowerShell!), use modules for encapsulation, and write unit tests (see my article on PowerShell unit tests with Pester <a href=\"http:\/\/www.simple-talk.com\/sysadmin\/powershell\/practical-powershell-unit-testing-getting-started\/\">here<\/a>).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are some pitfalls in PowerShell for the unwary. Many people who are learning PowerShell come across quirks that can cause frustration. Michael Sorens continues his series, warning abut the most common PowerShell pitfalls and explains how to avoid them.&hellip;<\/p>\n","protected":false},"author":221868,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[35],"tags":[4635,4871],"coauthors":[6802],"class_list":["post-1994","post","type-post","status-publish","format-standard","hentry","category-powershell","tag-powershell","tag-sysadmin"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1994","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221868"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1994"}],"version-history":[{"count":30,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1994\/revisions"}],"predecessor-version":[{"id":73495,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1994\/revisions\/73495"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1994"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1994"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1994"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1994"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}