Hosting der Windows PowerShell in .NET-Anwendungen

Der Dotnet-Doktor  –  0 Kommentare

Die Windows PowerShell zeichnet sich oft durch prägnante Befehle aus, zum Beispiel

gps | where { $_.ws -gt 1MB } | sort ws -desc | select -first 15   

Dieser Befehl bedeutet: Hole die Liste aller Prozesse, filtere diejenigen aus, die mehr als ein MByte Speicher nutzen, sortiere die Liste absteigend nach der Speichernutzung und begrenze die Liste auf die ersten 15.

Auch viele Microsoft-Services und -Server unterstützen Commandlets, ein gutes Beispiel ist das Commandlet New-Mailbox" zum Anlegen von Postfächern für Microsoft Exchange.

Windows PowerShell basiert auf .NET, und daher kann man PowerShell als Skriptumgebung auch innerhalb von .NET-Anwendungen (C#, Visual Basic, C++/CLI, F#, u.v.a.m.) nutzen.

Das Listing zeigt eine Hilfsmethode zum Ausführen eines PowerShell-Befehls in einer .NET-Anwendung. Voraussetzung ist es, die System.Management.Automation.dll zu referenzieren und ein using System.Management.Automation ist auch hilfreich. Die Methode liefert die Ergebnisobjekte im Rückgabewert und über den Out-Parameter-Status aufgetretene Fehler. Zentral ist in der Methode die Instanziierung der Klasse PowerShell mit der statische Methode Create(), die Übergabe der Befehle mit AddScript() und die Ausführung mit Invoke().

  public Collection<PSObject> Run(string Command, out string Status)
{
string e = "";
PowerShell ps = PowerShell.Create();

// Befehl hinzufügen
ps.AddScript(Command);
   // Befehl ausführen
Collection<PSObject> ErgebnisMenge = ps.Invoke();
   // Fehler?
if (ps.Streams.Error.Count == 0)
{ // Nein
Status = "OK";
return ErgebnisMenge;
}
else
{ // Es gab einen Fehler
foreach (var dr in ps.Streams.Error)
{
e += dr.Exception.Message;
}
Status = e;
return null;
}
}

Das zweite Listing zeigt den Aufruf der Hilfsmethode an einem Beispiel. Es lassen sich wahlweise Befehlsketten oder ein Pfad zu einer PowerShell-Skriptdatei übergeben.

   string Status = "";
string Demo = (gps | where { $_.ws -gt 1MB } | sort ws -desc
| select -first 15 ");
var ErgebnisMenge = new WPSHostLib.WPSHost().Run(Demo, out Status);
   if (Status != "OK")
{
Console.WriteLine("Fehler: " + Status);
}
else
{
// Ergebnismenge darstellen
foreach (System.Management.Automation.PSObject Ergebnis in ErgebnisMenge)
{
Console.WriteLine(
"{0,-24}{1,-10}{2}",
Ergebnis.Members["ProcessName"].Value,
Ergebnis.Members["Id"].Value,
Ergebnis.Members["WorkingSet64"].Value);
}
}

Für einen Kunden schreibe ich gerade einen Webservice, der PowerShell-Skripte auf einem Application Server ausführt. Die obige Hilfsroutine ist dabei ein wesentlicher Baustein.