A bit about Scriptblocks

When scripting with MSH one of the most useful things to know about are scriptblocks (lambda functions). Scriptblocks are compiled bits of MSH script which you can pass around and invoke whenever you feel like it. They turn out to be so useful that if you look at the cmdlets you’ll find a few that take scriptblocks (foreach-object, where-object, time-expression, select-object, format-table ). So how do we create scriptblocks? Well, if you’ve ever used foreach-object you already know how to do it. Simply write some MSH inside { } and you’re done. You can invoke them using & or “.” for dot sourcing. Pipeline input will be in $input and your arguments will be in $args. Here’s a quick demo:

MSH>$script = { write-host "The scriptblock has been invoked."; write-host "Pipe: $input"; write-host "Args: $args" }
MSH>1,2,3 | & $script 4 5 6
The scriptblock has been invoked.
Pipe: 1 2 3
Args: 4 5 6
MSH>function InvokeTheScript([scriptblock]$myScript) { & $myScript }
MSH>InvokeTheScript $script
The scriptblock has been invoked.
Pipe:
Args:
MSH>InvokeTheScript { 1 + 1 }
2
MSH>1,2 | foreach-object $script
The scriptblock has been invoked.
Pipe: 1
Args:
The scriptblock has been invoked.
Pipe: 2
Args:

Funny how that function declaration has something resembling a scriptblock after the parameters huh? Well… if you were to look at the function provider you’d quickly find out that it is indeed a scriptblock. A named scriptblock, but a scriptblock nonetheless.

MSH>get-item function:\InvokeTheScript | get-member

TypeName: System.Management.Automation.FunctionInfo

Name MemberType Definition
---- ---------- ----------
Equals Method System.Boolean Equals(Object obj)
get_CommandType Method System.Management.Automation.CommandTypes get_CommandType()
get_Definition Method System.String get_Definition()
get_Name Method System.String get_Name()
get_Options Method System.Management.Automation.ScopedItemOptions get_Options()
get_ScriptBlock Method System.Management.Automation.ScriptBlock get_ScriptBlock()
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
set_Options Method System.Void set_Options(ScopedItemOptions value)
ToString Method System.String ToString()
MshDrive NoteProperty System.Management.Automation.DriveInfo MshDrive=Function
MshIsContainer NoteProperty System.Boolean MshIsContainer=False
MshPath NoteProperty System.String MshPath=Microsoft.Management.Automation.Core\Function::InvokeTheScript
MshProvider NoteProperty System.Management.Automation.ProviderInfo MshProvider=Microsoft.Management.Automation.C...
CommandType Property System.Management.Automation.CommandTypes CommandType {get;}
Definition Property System.String Definition {get;}
Name Property System.String Name {get;}
Options Property System.Management.Automation.ScopedItemOptions Options {get;set;}
ScriptBlock Property System.Management.Automation.ScriptBlock ScriptBlock {get;}

MSH>(get-item function:\InvokeTheScript).ScriptBlock
param([scriptblock]$myScript) & $myScript

I’d give you some really good examples of scriptblock usage but I don’t know any. JK, of course. Actually, a long time ago one of our PMs used scriptblocks in such an excellent way so I’ll just point you guys to his post about it.

https://www.proudlyserving.com/archives/2005/07/monad_and_rss_p_2.html

- Marcel

Comments

  • Anonymous
    December 19, 2005
    Actually, an example of how (if possible) to write a C# method that consumed a scriptblock would be useful for something I've been thinking of on the side.
  • Anonymous
    April 25, 2006

    After reading Marcel's introductory piece on ScriptBlock, I decided to rewrite an old script...