9

Today I noticed an interested behavior of PowerShell and I made the following code to show it. When you run:

function test()
{
    $a = @(1,2);
    Write-Host $a.gettype()
    return $a;
}

$b = test
Write-Host $b.gettype();

What you got is:

System.Object[]
System.Object[]

However when you change the code to:

function test()
{
    $a = @(1);
    Write-Host $a.gettype()
    return $a;
}

$b = test
Write-Host $b.gettype();

You will got:

System.Object[]
System.Int32

Can someone provide some more details on this "feature"? Seems the PowerShell specification did not mention this.

Thanks.


BTW, I tested the code on PowerShell version 2, 3 & 4.

3 Answers 3

6

Powershell automatically "unwraps" arrays in certain situations, in your case the assignment:

PS> (test).GetType()
System.Object[]

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Int32                                    System.ValueType

PS> $b = test
System.Object[]
PS> $b.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Int32                                    System.ValueType

You can get around by explicitly introducing an array in the assignment:

$b = ,(test)
Sign up to request clarification or add additional context in comments.

4 Comments

Is there a way to enforce this in the function definition, rather than in the caller?
@Scott: Not that I'm aware of. Keep in mind that PowerShell is a scripting language, and is built around consuming and producing lists of values – something the pipeline does naturally. The only places I found so far where being able to treat arrays as arrays would be valuable were those in which you depart from PowerShell's strengths and try writing C#-style code instead of a pipeline (or pass around arrays of arrays instead of arrays of objects, which follows down the same path). So overall I'd say it isn't even an oversight or design error that doing this is cumbersome.
Agreed, for the most part. There are pockets of Powershell where type is important. My scenario: I'm writing a small Powershell module to wrap an internal WCF endpoint in cmdlets that use New-WebServiceProxy. The proxy methods take input as a custom type generated with the proxy client, and I have a helper method to build them. It's troublesome when I expect my helper to give me back an array and it gives me a single element or null. Now the calling code needs to know the internal dynamic type to generate its own empty array.
Not in the function definition, but there is a way to do this within a function. Use a comma in the function's return statement: return ,$value . Somehow this preserves a single-element array even thru assignment. see
0

Declare the variable as an array before using it.
Then use += when invoking the function.

Whatever you return, it will be considered as an array.

function test
{
    return [int]1
}

$b = @()
$b += test

$b.GetType()

Result:

IsPublic IsSerial Name                                     BaseType                                                                                                                      
-------- -------- ----                                     --------                                                                                                                      
True     True     Object[]                                 System.Array   

Another way of doing:
$b = @(test)

Comments

-2

It's telling you that it is an object, because technically it is.

PS C:\Users\Administrator> $arr = @(1,2,3,4,5)
PS C:\Users\Administrator> $arr.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Note that the BaseType is System.Array

But when you output it using Write-Host, it just tells you that it is a System.Object[]

PS C:\Users\Administrator> Write-Host $arr.GetType()
System.Object[]

Like that.

So it makes logical sense that we can run the following command, based on the table above, to find out the BaseType:

PS C:\Users\Administrator> Write-Host $arr.GetType().BaseType
System.Array

1 Comment

It tells them that it's an object array; note the [].

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.