Tuesday, August 4, 2020

Stupid Citrix Trick #8: Forcing A Powershell Function To Return An Array

Problem: You want to return an array object from a Powershell function as an array under all circumstances.

Solution: No one's a bigger fan of Powershell than me. It's not perfect but it's powerful, flexible, and can use lots of other programming environments natively, like WMI objects and the .Net framework.  But today I found one super-duper stupid thing it does that made my blood boil with the heat of a thousand suns.

Specifically if you return an array from a function, and the array only has one element, than just that variable is returned.  So if you have an array of strings containing only a single value, that value will be returned as a string.

Why is this a big deal?  Because ArrayC = ArrayA + ArrayB behaves differently if you are adding two arrays than if you're adding a string object to an array.  Let's run through an example.

Let's pretend we have a couple of functions, GetArrayA and GetArrayB.  These functions just return an array containing three values:

function GetArrayA
{
   $Array = @("1", "2", "3")
   Return  $Array
}

function GetArrayB
{
   $Array = @("40", "50", "60")
   Return  $Array
}

$A = GetArrayA
$B = GetArrayB

$C = $A + $B

So what is the expected value of $C?  Here's what you'd expect:

1
2
3
40
50
60

And you'd be right, that is the value of $C.  Now let's make one small change:

function GetArrayA
{
   $Array = @("1")
   Return  $Array
}

function GetArrayB
{
   $Array = @("40", "50", "60")
   Return  $Array
}

$A = GetArrayA
$B = GetArrayB

$C = $A + $B


Now the array $A only contains a single entry.  You would expect the contents of $C to look like this:

1
40
50
60

But you would be wrong.  Here's what you would actually get:

140
50
60

WHYYYY would it do such a thing?  Because the function GetArrayA did not return an array.  Since the array held only a single entry, it returned that object, a string, instead of the array.  And you can confirm that with the .GetType() function.  It then appended that string object to the first entry in array $B and went on its merry way.

You'd think when I realized this, realized that my code was correct but Powershell was sabotaging me, that I would've been relieved, but instead my wrath burned with the fire of a thousand suns. I trusted Powershell, Powershell was my friend, and suddenly it turned around and stabbed me in the back.

However there's a simple solution.  You just have to use a type declaration on the variables that will hold the array values, like this:

[array]$A = GetArrayA
[array]$B = GetArrayB

Despite the title of this post you're not actually forcing the function to return an array, you're forcing the variable to receive an array.  Which means you use that function frequently, you'll have to update a lot of code! But at least it WILL work.

I found that solution here:

https://stackoverflow.com/questions/11107428/how-can-i-force-powershell-to-return-an-array-when-a-call-only-returns-one-objec

If this helps even one of you avoid the painful consequences, then my suffering was worthy it.