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.

 

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

- Marcel

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]