views:

74

answers:

1

In experimenting with scriptblocks, I was attempting to use a scriptblock parameter with an advanced function and noticed that it performs differently than when supplied to a compiled cmdlet.

In reviewing this blog post from the PowerShell Team blog, it appears that the PowerShell engine should be evaluating the scriptblock if a scriptblock is not a valid input for the parameter. It seems that when calling the function with a scriptblock parameter, it attempts to convert a scriptblock to the parameters type directly, rather than evaluating the scriptblock based on the current object in the pipeline.

My intention is to duplicate behavior like:

Import-CSV somecsv.csv | get-wmiobject -class {$_.class} -Computer {$_.computer}

for advanced functions.

Example script:

$sb = {throw "If there was an error, the scriptblock was evaluated!"}

function test ()
{
  param (
    [Parameter()]
    [string]
    $ThisShouldBeEvaluatedForEachItem,
    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]
    $FullName
 )  

 process 
 {  
  write-host $Fullname, $ThisShouldBeEvaluatedForEachItem
 }
} 
Get-ChildItem | test -ThisShouldBeEvaluatedForEachItem $sb

Is this the intended behavior or am I headed in the wrong direction?

Based on Keith's response, I added ValueFromPipeline and ValueFromPipelineByPropertyName (in two separate tests) to the Parameter attribute for the ThisShouldBeEvaluatedForEachItem parameter. Doing that makes the example work, though it seems to defeat the stated purpose of scriptblock parameters from the Team Blog post.

+4  A: 

If the parameter is ValueFromPipeline or ValueFromPipelineByPropertyName then PowerShell will evaluate the Scriptblock and try to coerce the result to the parameter type. We got this info from the PowerShell team a while back:

ScriptBlock arguments are passed as is (as a ScriptBlock) when the parameter type is Object, ScriptBlock, or a type deriving from ScriptBlock, or collections of these types.

We only invoke the ScriptBlock argument during parameter binding when there is pipeline input and there was no trivial way to bind the ScriptBlock directly.

Keith Hill
Actually, it does seem to work properly with ValueFromPipelineByPropertyName as well, as long as the parameter that has the scriptblock is noted to come from the pipeline. See my updated question. Thanks Keith.
Steven Murawski
Sorry, I added that to the example above.. I forgot that in my earlier cut/paste. The above was my initial trial. I'll clarify the intention above.
Steven Murawski
Doh. Yes it works. That's what I call a "self-induced mock" on my part. :-)
Keith Hill
Thanks Keith. I appreciate the help!
Steven Murawski