So I was
reading up on PowerShell arrays on this TechNet site:
It gives
a brief introduction to PowerShell arrays and illustrates how powerful they
are. However, arrays in PowerShell are a curious beast indeed and in some cases
they can deceive you, so I thought I'd give some additional insights into it in
the hopes it may save you from struggling with them for too long.
Let's
start with the basics. One thing you can do with arrays is concatenation:
$a =
1,2,3
$a += 4
Now $a is
1,2,3,4. Neat.
But wait
a minute… let's try changing this example a bit
$a =
CommandThatReturnsIntegers
$a += 4
If
CommandThatReturnsIntegers returns 1,2,3 then everything works as expected. But
what if it just returns 1?
$a = 1
$a += 4
Now $a is
5… oops? What just happened? Well, in essence we expected an array from
CommandThatReturnsIntegers but instead it gave us an integer. Well, we could
fix it such that it always returns @(1) instead of 1, then we get:
$a = @(1)
$a += 4
Now $a is
1,4. But what if we don't control the output of CommandThatReturnsIntegers,
then we are out of luck with this approach…
An
alternative is to use the comma operator, like this:
$a = 1
$a = $a,4
$a now is
1,4 as we would like it to be.
Let's try
that with a starting array
$a =
1,2,3
$a = $a,4
Again,
when evaluated $a is 1,2,3,4 as expected. Everything looks fine right?
Now try
this:
$a.count
2? Wait a
minute it evaluated to 1,2,3,4 yet the number of elements in the array is 2?
Let's see
what we find when we look under the hood..
$a | % {
"$_" }
Here I'm
telling PowerShell to produce a string representation of the content of every
element in the array. The output is:
1 2 3
4
So, as
you may have guessed already underneath the hood $a is an array of arrays.
This is a
common source of trouble when piping inputs to other commands. We would expect
to evaluate the command on each element not each nested array.
As an
example we might want to sum the values using:
$a |
measure -Sum
However,
this raises the exception:
Input object
"System.Object[]" is not numeric.
But then
why does $a evaluate to 1,2,3,4 when we first looked at it? The reason is that
PowerShell is invoking black magic to unroll the nested array on our behalf
when we evaluate it!
That's
pretty bad and causes much deception in PowerShell-land. But there's a plus
side to this, we can leverage (abuse?) PowerShell's black magic to unroll the
array for us, using the following syntax:
$b = $a |
% { $_ }
Now $b is
a truly flattened array. We can test this using:
$a | % {
$_ } | measure -Sum
Which now
gives us the expected value of 10.
The
benefit of this syntax is that it will work regardless of $a is a single
element, an array or a nested array.
In
conclusion when working with arrays take care and try to understand what goes
on underneath the hood. If you end up in a situation where the array is not
behaving as expected, do not rely on evaluating it in PowerShell to inspect
it's structure. Instead, use $a | % { "$_" } to see what it actually
holds. In case you are working with arrays and concatenation, make sure to
build your command robust by unrolling the input arrays using $a | % { $_ }.
Heya, your last bit of sample code is buggy (referring to $a instead of $b, but then using -Sum which is not counting the objects in the array) but this also shows the outcome does not match what you say it does. ForEach-Object does not unroll arrays. This blog post is misleading.
ReplyDeletecanlı sex hattı
ReplyDeletejigolo arayan bayanlar
heets
GYMT