Tuesday, April 07, 2009

PowerShell, Getting the Value Out of a ScriptBlock

When you are doing a little advanced scripting and passing scriptblocks around, one of the problems I encountered was how to execute the scriptblock in a pipeline and get the value out of it. Say you want the user to be able to enter a scriptblock and compare your data to the value returned from it – how is that done?

Executing a scriptblock is easy using the &-operator

$sb={"Hello World!"}
&$sb





 



You can also use the invoke method -




$sb.invoke()





If you want to have a filtering scriptblock e.g. comparing a value with a scriptblock (not its value), I found it easy and logical to use where(-object) -




$sb={$_.name –like ‘note*’}
dir $env:windir | where $sb
# or
if (dir $env:windir | where $sb) {"Slipped through filter, go on"}





But what if you want to execute it, feeding in values from the pipeline to get new values? (Often you would only send in one value at a time). The answer is foreach(-object) -




$sb={$_.name.toupper()}
dir $env:windir note* | foreach $sb





When can this be useful? In numerous places, I would say. What if you have some getter script, with these arguments -




Get-XXX –dateproperty <property>
–value <value|scriptblock>
filter <scriptblock>





 


If this case the code is something like (pseudo code) -




get-object | where &$filter| foreach {
if ($value –is [scriptblock]) {
$compareto=$_ | foreach $value
else {
$compareto=$value
}
if ($_.$dateproperty –gt $value) {
“ok”
}
}



 


The user can then either stick it a value or calculate a value using the scriptblock – and that based on the data from the object itself and before the comparison is made -



# Getting files accessed after January 1st
get-xxx–dateproperty lastAccessTime –value ([datetime] "2009-01-01")
# Getting files accessed 90 days after it was modified
get-xxx–dateproperty lastaccesstime –value {$_.lastwritetime.adddays(90)}





The latter example was not possible without parsing a scriptblock.

No comments: