Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat determines whether the Powershell pipeline will unroll a collection?
    text
    copied!<pre><code># array C:\&gt; (1,2,3).count 3 C:\&gt; (1,2,3 | measure).count 3 # hashtable C:\&gt; @{1=1; 2=2; 3=3}.count 3 C:\&gt; (@{1=1; 2=2; 3=3} | measure).count 1 # array returned from function C:\&gt; function UnrollMe { $args } C:\&gt; (UnrollMe a,b,c).count 3 C:\&gt; (UnrollMe a,b,c | measure).count 1 C:\&gt; (1,2,3).gettype() -eq (UnrollMe a,b,c).gettype() True </code></pre> <p>The discrepancy with HashTables is <a href="http://huddledmasses.org/powershell-and-hashtable-oddities/" rel="noreferrer">fairly well known</a>, although the <a href="http://technet.microsoft.com/en-us/library/dd315369.aspx" rel="noreferrer">official documentation</a> only mentions it obliquely (via example).</p> <p>The issue with functions, though, is news to me. I'm kind of shocked it hasn't bitten me before now. Is there some guiding principle we scripters can follow? I know that when writing cmdlets in C# there's an <a href="http://msdn.microsoft.com/en-us/library/ms568370(VS.85).aspx" rel="noreferrer">overload of WriteObject</a> where you can control enumeration explicitly, but AFAIK there's no such construct in the Posh language itself. As the final example shows, the Posh interpreter seems to believe there is no difference in the type of objects being piped. I suspect there may be some Object vs PSObject weirdness under the hood, but that's of little use when you're writing pure Posh and expect the script language to "just work."</p> <p>/ EDIT /</p> <p>Keith is correct to point out that in my example, I'm passing in a single string[] argument rather than 3 string arguments. In other words, the reason Measure-Object says Count=1 is because it's seeing a single array-of-arrays whose first element is @("a", "b", "c"). Fair enough. This knowledge allows you to work around the issue in several ways:</p> <pre><code># stick to single objects C:\&gt; (UnrollMe a b c | measure).count 3 # rewrite the function to handle nesting C:\&gt; function UnrollMe2 { $args[0] } C:\&gt; (UnrollMe2 a,b,c | measure).count 3 # ditto C:\&gt; function UnrollMe3 { $args | %{ $_ } } C:\&gt; (UnrollMe3 a,b,c | measure).count 3 </code></pre> <p>However, it doesn't explain everything...</p> <pre><code># as seen earlier - if we're truly returning @( @("a","b","c") ) why not count=1? C:\&gt; (UnrollMe a,b,c).count 3 # our theory must also explain these results: C:\&gt; ((UnrollMe a,b,c) | measure).count 3 C:\&gt; ( @(@("a","b","c")) | measure).count 3 C:\&gt; ((UnrollMe a,b,c d) | measure).count 2 </code></pre> <p>From what I can extrapolate there's another rule in play: if you have an array with exactly one element AND the parser is in <a href="http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6058.entry" rel="noreferrer">expression mode</a>, then the interpreter will "unwrap" said element. Any more subtleties I'm missing?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload