12

It seems that invoking a PowerShell script block (by invoking the .Invoke() method) always produces a collection. Specifically, a collection of type

System.Collections.ObjectModel.Collection`1[[System.Management.Automation.PSObject, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]

Even invoking an empty script block ({}.Invoke()) returns a collection. Invoking the same script block using the call operator (&) produces the normally expected return (either a scalar or [object[]]).

This turns out to be convenient if you need a collection instead of an array, but it seems kind of counterintuitive.

Does anyone know why it behaves this way?

I knew there are two different invocations, .Invoke() and .InvokeReturnAsIs() from reading the language spec. That's were I first noticed it.

I just don't understand the reasoning behind the naming convention and the way the mechanics of it appear to work. Looking at the documentation, what I would have thought would be the default invocation method is not what is used when the script block is invoked in PowerShell. It appears that .InvokeReturnAsIs() just returns a stream of objects, and then PowerShell wraps it into an object array if there's more than one object, as scalar if there's only one object, or creates a null object if there are none, as if there's an implicit pipeline there. Using .Invoke() returns a collection, always, and PowerShell leaves it as a collection.

3 Answers 3

12

Looks to be the difference between these two methods:

Invoke - Invokes the script block with the specified arguments, returning the results as PSObject objects.

InvokeReturnAsIs - Runs the script block with the specified arguments. This method returns the raw (unwrapped) result objects so that it can be more efficient.

http://msdn.microsoft.com/en-us/library/system.management.automation.scriptblock_methods(v=vs.85).aspx

Invoke

$code = {"a"}
$code.Invoke().Gettype().FullName

Output:

System.Collections.ObjectModel.Collection`1[[System.Management.Automation.PSObject, System.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]

InvokeReturnAsIs

$code.InvokeReturnAsIs().GetType().FullName

Output:

System.String
Sign up to request clarification or add additional context in comments.

Comments

8

My guess is that the team wanted to be consistent with the PowerShell.Invoke() API, which returns a Collection<PSObject>. This C# signature makes it easier for clients to consume 0, 1 or N returned values and not have to worry about checking for null and whether the returned object was wrapped or not.

From the .NET Design Guidelines:

DO NOT return null values from collection properties or from methods returning collections. Return an empty collection or an empty array instead.

You could say then why not just return object. Then I would have to against null or not and then I'd have to test to see if it implemented ICollection to determine if I had a scalar or collection. From a C# dev's point of view, this is a spew (pardon the rhyme). :-)

Comments

1

Because that is what it is designed to do, and there is an alternate!

Invoke - Invokes the script block with the specified arguments, returning the results as (collection of) PSObject objects.

InvokeReturnAsIs - Runs the script block with the specified arguments. This method returns the raw (unwrapped) result objects so that it can be more efficient.

Also, {}.invoke() returns null, so I don't know where you got the impressions that even that returns a collection.

http://msdn.microsoft.com/en-us/library/system.management.automation.scriptblock.invokereturnasis(v=vs.85).aspx

2 Comments

I got the idea that it ruturns as collection when I did this: ({}.invoke).gettype()
Get-Member -InputObject ({}.invoke()) shows that it too returns a collection; conversely, $null -eq {}.Invoke() returns $False. The collection returned is empty, which is why it produces no output in the console.

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.