Welcome to MSDN Blogs Sign in | Join | Help

Flexible pipelining with ScriptBlock Parameters

PSMDTAG:FAQ: How can I pipeline data to a parameter which does not accept pipeline input?
PSMDTAG:FAQ: What are ScriptBlock Parameters?

One of the foundation concepts of Windows PowerShell is pipelining objects instead of text.  What happens is that when an upstream command generates an object, the PowerShell engine examines the data requirements of the next pipeline element and then binds the pipeline object to it.  That binding can either be:

  • Accepts Pipeline Input - BYVALUE
  • Accepts Pipeline Input - BYPROPERTYNAME

You can see this when you look at the Parameter section of the help for any cmdlet.  Take a look at the Help for Get-Process, you see the following:

-inputObject <Process[]>
    The object on which to act

    Required?                     true
    Position?                     named
    Default value
    Accepts pipeline input?       true (ByValue)
    Accepts wildcard characters?  false


-id <Int32[]>
    The Id number of the process

    Required?                     true
    Position?                     named
    Default value                 null
    Accepts pipeline input?       true (ByPropertyName)
    Accepts wildcard characters?  false

The engine attempts to bind the pipeline object BYVALUE first and if that fails, it tries to bind it BYPROPERTYNAME (which is to say - see if the pipeline object has a property with this name [ID] and if it can be cast to this datatype [INT32]). 

Here is the point:  The cmdlet developer decides which parameters can be pipelined and whether they can be pipelined by value or by propertyname.  They do this based upon their view of the common scenarios and the benefit/risks of this binding.  Imagine the incomprehensibility and potential disasters that would arise if all parameters accepted pipeline input!  The point is that as a Cmdlet developer, caution is your friend.

But here is the point: Cmdlet developers don't know everything and even if they did, there is not always a clear consensus of what should be pipelinable.  Case in point: take a look at the parameters for Get-WMIObject - none of its parameters can take input from the pipeline.

In a recently newsgroup posting (Suggestion: Get-WmiObject reading computer names from input stream) Alex and MOW tried various things to get this to work.  MOW wanted to have a file (Computers.csv) of the form:

Computername,Class
localhost,win32_operatingsystem
foo,win32_share

and then be able to do the following:
PS> Import-Csv computers.csv |Get-WmiObject

Of course this does not work because Get-WMIObject does not accept pipeline input.  At this point you have 2 solutions: foreach and scriptblock parameters.

FOREACH

This should be pretty obvious:

PS> Import-Csv computers.csv | foreach {
>> Get-Wmiobject -computerName $_.ComputerName `
>> -Class $_.Class  }

ScriptBlock Parameters

This is not so obvious.  If you specify a Scriptblock as the value of a parameter on a commandline you have one of 2 situation - you specified it for a parameter which takes a ScriptBlock or it doesn't.  If it does, the PowerShell engine passes the ScriptBlock to the parameter.  If it doesn't, they you've just used yourself a SCRIPTBLOCK PARAMETER.  What happens is this case is that this SCRIPTBLOCK will be run for each and every object in the pipeline and the results will be bound to this parameter.  That means the following produces the same results as the foreach example above:

PS> Import-Csv Computers.csv |
>> Get-WmiObject -ComputerName {$_.ComputerName} -Class {$_.Class}

ScriptBlock parameters provide you as simple, powerful mechanism to get pipelining of parameters where the cmdlet author has not already provided this for you.

Enjoy!
Jeffrey Snover
Windows PowerShell Architect

PSMDTAG:INTERNAL: How parameterbinding works
PSMDTAG:PHILOSOPHY: Cmdlets should only allow pipelining of parameters that are safe to pipeline, the engine can allow the user to override that via ScriptBlock parameters.

 

Published Friday, June 23, 2006 5:02 AM by PowerShellTeam
Filed under: , ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: Flexible pipelining with ScriptBlock Parameters

Now that is going to come in very handy as we move along.

PS amazes me more-an-more eac day.  Keep up the exceellent blogs Jeffery/PS-Team.

Friday, June 23, 2006 9:22 PM by jvierra

# re: Flexible pipelining with ScriptBlock Parameters

I think you have forgotten to mention one of the most important(well in my personal opinion that is) that when you use "scriptblock parameter", only one instance of cmdlet is run while one or more instances are run when using "foreach"... Did i get that correct?

Ah, another one, I am not sure if I am remembering this correct that, there is a gotcha when it comes to passing a script block as a parameter that, you can't use scriptblock parameter on a parameter which accepts an object of type PSObject.(is it also a case for PSCustomObjects?)
Saturday, June 24, 2006 10:44 AM by dontBotherMeWithSpam

# re: Flexible pipelining with ScriptBlock Parameters

>  only one instance of cmdlet is run while one or more instances are run when using "foreach"...

That is absolutely correct and you are also correct that this can be a critical difference.  Imagine the case where a Cmdlet opens a DB connections, puts each object into the DB and then closes the connection.  If this Cmdlet is in a foreach block - it will open and close the connection for every object where as using ScriptBlock parameters, you only have 1 instance of the Cmdlet so it opens and closes the connection once.

Correct as well on the restriction.  Scriptblocks work on parameters which are not of type SCRIPTBLOCK or OBJECT. I haven't looked at the code but I don't believe that there is a problem with PSObject types.  

Jeffrey Snover
Windows PowerShell Architect
Sunday, June 25, 2006 12:59 AM by PowerShellTeam

# re: Flexible pipelining with ScriptBlock Parameters

Maybe not the right place for this question, but this is the most close topic to my current problem.
I have created own cmdlet, which works fine in the defautl PowerShell host. It accepts various parameters from command line and the "target" item names from the pipeline.
Now I am trying to create custom PS Host application. And here I cannot supply a list of "target" objects - I always get parameter binding exceptions.
SDK is almost empty... Could you help me?
Monday, June 26, 2006 10:06 AM by Boris Verkhovykh

# re: Flexible pipelining with ScriptBlock Parameters

> Imagine the case where a Cmdlet opens a DB connections, puts each object into the DB and then closes the connection

Ah, now that's a case I have never though of where I could make use of this feature!

Thank you for clearing up there and for the post, Jeffrey.
Monday, June 26, 2006 12:44 PM by dontBotherMeWithSpam

# Cmdlets vs. APIs

Some people have asked the question, "Why Cmdlets?". If you already have a reasonable API, what is the

Monday, July 02, 2007 9:01 PM by Windows PowerShell

# Cmdlets vs. APIs

Some people have asked the question, &quot;Why Cmdlets?&quot;. If you already have a reasonable API,

Monday, July 02, 2007 9:55 PM by Noticias externas

# Tyler Byrd News &raquo; Blog Archive &raquo; Cmdlets vs. APIs

Monday, October 22, 2007 12:22 AM by Tyler Byrd News » Blog Archive » Cmdlets vs. APIs

# Uriah Smith &raquo; Blog Archive &raquo; Cmdlets vs. APIs

Monday, January 21, 2008 2:17 PM by Uriah Smith » Blog Archive » Cmdlets vs. APIs

# $MindWarpingPower = $Cmdlets + $ScriptBlock_Parameters

A while ago I blogged about the power of Flexible Pipeling Scriptblock parameters .&#160; The mechanics

Sunday, April 20, 2008 7:59 PM by Windows PowerShell

Leave a Comment

(required) 
required 
(required) 
 
Page view tracker