Monday, February 05, 2007 7:11 PM
bart
A first introduction to Windows PowerShell runspaces
Dear blogging friends, I'm back from some blog silence due to other priorities during last weeks . Although it will take some time to get back up to speed in the blogosphere, I decided to leave you no longer hungry for some cool stuff and posted this simple warming-up sample of Windows PowerShell runspaces.
Runspaces in a few words
One of the coolest things about Windows PowerShell is the fact that the entire command line processor and pipeline infrastructure can be hosted by applications other than the PowerShell.exe executable itself. Basically, that's what the MMC 3.0 layering on top of Windows PowerShell is all about, which has been fully realized in the Exchange Server 2007 product. In this and upcoming posts I want to show you how you can leverage the power of all this magic in your own applications, allowing you to realize such a layering yourself: build cmdlets and host the PS engine!
A simple snap-in
In order to illustrate the use of a runspace, we need to create some snap-in first (or you could reuse an existing one). Please revisit my previous posts on Windows PowerShell for more information on the creation of cmdlets; in this post I'll assume you know what a cmdlet is and how you create a parameterized one. Below you can find the code for a snap-in containing two cmdlets which are rather self-explanatory:
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.ComponentModel;
namespace DemoSnapIn
{
[Cmdlet(VerbsCommon.Get, "Greeting")]
public class SayHelloCmdlet : PSCmdlet
{
private string name;
[Parameter(Mandatory = true, Position = 0)]
public string Name
{
get { return name; }
set { name = value; }
}
protected override void ProcessRecord()
{
this.WriteObject("Hello " + name);
}
}
[Cmdlet(VerbsCommon.Get, "Permutations")]
public class PermutationGeneratorCmdlet : PSCmdlet
{
private string _string;
[Parameter(Mandatory = true, Position = 0)]
public string String
{
get { return _string; }
set { _string = value; }
}
protected override void ProcessRecord()
{
foreach (string s in GetPermutations(_string))
WriteObject(s);
}
static void Swap(StringBuilder sb, int i, int j)
{
char t = sb[i];
sb[i] = sb[j];
sb[j] = t;
}
static IEnumerable<string> GetPermutations(string s)
{
int len = s.Length;
StringBuilder sb = new StringBuilder(len);
sb.Append(s);
return GetPermutations(sb, 0, len - 1);
}
static IEnumerable<string> GetPermutations(StringBuilder sb, int b, int e)
{
if (b == e)
yield return sb.ToString();
else
{
for (int i = 0; i <= e - b; i++)
{
Swap(sb, b, b + i);
foreach (string r in GetPermutations(sb, b + 1, e))
yield return r;
Swap(sb, b + i, b);
}
}
}
}
[RunInstaller(true)]
public class MySnapIn : PSSnapIn
{
public override string Name
{
get { return "DemoSnapIn"; }
}
public override string Description
{
get { return "Sample snap-in"; }
}
public override string Vendor
{
get { return "Bart"; }
}
}
}
Note: the permutation searcher is just a simple straightforward implementation to illustrate cmdlets that produce multiple results; please ignore the algorithm used which has a bit of a quick-n-dirty fashion :-)
Put the code above in a C# class library project, add a reference to System.Management.Automation (you might want to copy the System.Management.Automation.dll file from the GAC to some folder in order to reference it - recall the GAC can be found under %windir%\assembly\GAC_MSIL through the command-line); compile the whole thing (preferably with a strong name) and open up a VS2005 command-line (under Windows Vista launched using "Run as Administrator" in order to have the necessary privileges to write to the registry, a task executed by installutil.exe). In the command-prompt, navigate to the bin\Debug or bin\Release folder (according to the build type you chose) and execute installutil.exe -i DemoSnapIn.dll (assuming the assembly is named DemoSnapIn.dll of course):
Next, open Windows PowerShell and check whether the registration was successful by calling get-pssnapin -registered:
You should be able to call both the get-greetings and get-permutations cmdlets once you have added the snap-in to the shell:
Hosting a runspace
Time to call the cmdlets from inside another application. To illustrate this, create a new console application in C#, add a reference to System.Management.Automation (you might want to copy the System.Management.Automation.dll file from the GAC to some folder in order to reference it - recall the GAC can be found under %windir%\assembly\GAC_MSIL through the command-line). Next, add the following code:
using System;
using System.Management.Automation.Runspaces;
using System.Management.Automation;
namespace DemoCmdHost
{
class Program
{
const string name = "Bart";
const string perm = "Abc";
static void Main(string[] args)
{
RunspaceConfiguration config = RunspaceConfiguration.Create();
PSSnapInException ex;
config.AddPSSnapIn("DemoSnapIn", out ex);
if (ex != null)
throw ex;
using (Runspace rs = RunspaceFactory.CreateRunspace(config))
{
rs.Open();
Pipeline p = rs.CreatePipeline();
Command cmd = new Command("get-greeting");
cmd.Parameters.Add("Name", name);
p.Commands.Add(cmd);
Console.WriteLine(p.Invoke()[0].BaseObject as string);
}
using (Runspace rs = RunspaceFactory.CreateRunspace(config))
{
rs.Open();
Pipeline p = rs.CreatePipeline();
Command cmd = new Command("get-permutations");
cmd.Parameters.Add("String", perm);
p.Commands.Add(cmd);
foreach (PSObject o in p.Invoke())
Console.WriteLine(o.BaseObject);
}
}
}
}
That's it! Here's the result you should get:
More will follow later. Take a look at the Windows SDK documentation for Windows PowerShell too.
Calling all Windows Vista users - Download Windows PowerShell now
Over here:
Del.icio.us |
Digg It |
Technorati |
Blinklist |
Furl |
reddit |
DotNetKicks
Filed under: Windows PowerShell