Sunday, October 21, 2007

Call-Method v2

This is a follow-up article to Call-Method.

When PowerShell pipes a collection or array, it unwraps the object and passes the individual items in the collection/array. This is normally a very useful behavior, but if you pipe to function like Get-Member and Call-Method, you do not always get
what you want. Let me show how it works -


# Construct an array
$array=1,2,3

# Pass the array down the pipeline
# Gettype will be called 3 times for each integer
# in the array
$array | cm gettype

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

# Wrap array with the array operator. This changes
# nothing as the array operator only creates an array
# if there is none
@($array) | cm gettype

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

# Pass an array with the first argument being our
# array - this works
,$array | cm gettype

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

# Use the updated Call-Method and use the InputObject
# argument - like the one found on Get-Member
cm gettype -InputObject $array

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


## This is the updated Call-Method function

function Call-Method($method,$InputObject) {
begin {
if ($inputObject) {
$m=$inputObject.$method
$m.invoke($args)
}
}
process {
if ($_) {
$m=$_.$method
$m.invoke($args)
}
}
}
new-alias -force cm Call-Method

1 comment:

Doug Finke said...

Very cool.

I would change the call-method to this.

function cm($method, $InputObject)
{
begin {
function doit($target) {
$m=$target.$method
$m.invoke($args)
}
}

process { if ($_) { doit($_) } }
end { if($InputObject) { doit($InputObject) } }
}