tags:

views:

39

answers:

3

I am bit confused of the behaviour of the script below:

Test.ps1:

param(
    [array]$Value = $(throw "Give me a value")
)

Write-Host $Value 
$Value | Get-Member -MemberType Method
$Value.ToUpper()

Running the script:

PS C:\Temp> .\weird.ps1 test
TypeName: System.String
Name MemberType Definition
—- ———- ———-
…
ToUpper Method string ToUpper(), string ToUpper(System.Globalization.CultureInfo culture)
…
Method invocation failed because [System.Object[]] doesn’t contain a method named ‘ToUpper’.
At C:\Temp\weird.ps1:6 char:15
+ $Value.ToUpper <<<< ()
+ CategoryInfo : InvalidOperation: (ToUpper:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound

Why do I get a MethodNotFound exception? Get-Member clearly says it is a string.

+1  A: 

What's happening here is that the variable $value is typed to Object[] in the script. The call to Get-Member works because you are piping the value into the function. Hence instead of seeing the array it sees the values in the array which are indeed typed to String. This can be viewed by using the following Get-Member call without piping

Get-Member -MemberType Method -InputObject $value

This is also why ToUpper correctly fails (it's an array not a String).

JaredPar
Thanks for a good explanation!
Peter Moberg
+1  A: 

$Value is actually an array, because that is how you declare the parameter in your param block.

driis
+1  A: 

When you pipe a collection of anything in powershell, it gets "unrolled" and sent one by one to the right hand side of the bar (pipe) character. This means that the contents of the array get sent to get-member. Get-member only accepts the first item sent to it, so it shows you the members of the string. Your parameter is of type [array], so the parameter binder sets $value to an array of length 1, containing your string "test."

Example:

ps> @(1,"hello",3) | gm
... shows members of int32

ps> @("hello", 1, 3) | gm
... shows members of string

In order to see the members of an array when you pipe it, you should wrap it in another array, so it becomes the unrolled item:

ps> ,@("hello", 1, 3) | gm
... shows members of array

The leading comma "," creates a wrapping array.

-Oisin

x0n