PowerShell und WMI, Teil 2

01.01.2007 von Martin Kuppinger
Die grundlegenden Funktionen der Windows PowerShell im Zusammenspiel mit WMI (Windows Management Instrumentation), die im ersten Teil der Artikelserie vorgestellt wurden, bilden die Basis für einige Beispiele, die die Anwendung der Windows PowerShell für das WMI-Scripting verdeutlichen sollen.

Wie schon im ersten Teil der Serie deutlich wurde, muss man sich im Vergleich zu VBScript stark umstellen, wenn man mit der PowerShell arbeitet. Genau so offensichtlich ist aber, dass sich viele Aufgabenstellungen mithilfe der PowerShell sehr viel einfacher lösen lassen als mit VBScript, weil es sehr mächtige Methoden gibt.

Diese werden bei der PowerShell als cmdlets bezeichnet, weil sie bestimmte Befehle bereitstellen und modular erweiterbar sind.

Serie

Teil 1

Grundlagen zum Scripting von WMI mit der PowerShell

Teil 2

Erste Beispiele

Die Basis

Wenn man mit den Grundkonzepten von WMI vertraut ist, also ein gewisses Gefühl für die Klassen und die Namespaces gewonnen hat, dann ist die Umstellung von VBScript zu PowerShell in der WMI-Programmierung nicht allzu schwierig. Um sich erst einmal eine Liste von WMI-Klassen anzeigen zu lassen, verwendet man den Befehl

get-wmiobject –list

Die dabei erzeugte Liste (Bild 1) ist allerdings ausgesprochen lang und unübersichtlich. Daher bietet es sich an, hier gleich ein bisschen zu filtern.

Bild 1: Die Ausgabe einer Liste der WMI-Objekte, die mit der PowerShell genutzt werden können.

So kann man sich beispielsweise auf die Win32- Provider innerhalb von WMI beschränken, die ja besonders häufig verwendet werden. Ein Ansatz für diese Filterung wäre

get-wmiobject –list | where {$_.Name –like "Win32*"}

Spätestens hier wird der Reiz von WMI deutlich: Durch das Piping der Ausgabe der Liste als Eingabe für die Where-Bedingung kann man mit sehr geringem Aufwand Informationen filtern.

Bild 2: Eine gefilterte Liste mit der Ausgabe nur noch einzelner Klassen von WMI.

Daneben gibt es, wie in den bisher erschienenen Artikeln rund um WMI bereits gezeigt, noch etliche andere Ansätze, um eine Weiterverarbeitung von Ausgaben durchzuführen. Auch in diesem Artikel werden noch andere Varianten vorgestellt. Da man beim Operator –like auch zwei Wildcards einsetzen kann, lässt sich auch nach dem Text innerhalb einer Zeichenkette suchen. Man könnte also beispielsweise mit

get-wmiobject –list | where {$_.Name –like"*Process*"}

auch eine Liste von WMI-Klassen erzeugen, in denen die Zeichenkette Process enthalten ist. Das dürften alle Klassen sein, die man für die Überwachung von Prozessen in der einen oder anderen Form verwenden kann. Diese Liste ist übrigens schon recht übersichtlich, wie man in Bild 2 erkennen kann.

Ein erster Vergleich

Vergleicht man VBScript und die PowerShell, wird deutlich, dass die beiden Ansätze doch recht ähnlich aussehen – zumindest solange man keine spezielleren Funktionen wie eben die Filterung nutzen möchte. Ein Standardskript für die Abfrage auf WMI hat in VBScript ungefähr die folgende Form, in diesem Fall für eine Liste von Diensten mit ihrem Zustand:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" &
strComputer &"\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From
Win32_Service")
For Each objItem in colItems
Wscript.Echo objItem.Name, objItem.State
Next

Das gleiche Ergebnis lässt sich bei der PowerShell etwas einfacher erreichen, wie das folgende, minimal kürzere Skript deutlich macht.

$strComputer = "."
$colItems = get-wmiobject -class "Win32_Service" -
namespace "root\cimv2" -computername $strComputer
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.State
}

In beiden Fällen wird zunächst eine Variable definiert, über die der Fokus auf das lokale System gesetzt wird. Anschließend erfolgt eine Abfrage. Bei VBScript sind dazu zwei Schritte erforderlich, weil man zunächst auf WMI zugreifen und anschließend eine Abfrage durchführen muss. Bei der PowerShell läuft das in einem Schritt. Hier werden bei dem bereits bekannten Cmdlet getwmiobject nur Parameter angegeben, in diesem Fall die Klasse, der Namespace und der Computername. Die beiden letztgenannten Parameter sind allerdings Standardwerte, auf die man daher auch hätte verzichten können.

Das Ergebnis wird in beiden Fällen in eine Variable gespeichert, die mit einer weiteren Anweisung verarbeitet wird. Bei PowerShell wird also mal nicht mit dem Piping gearbeitet. In beiden Fällen wird eine Schleife durchlaufen, in der eine Ausgabe der Informationen erfolgt. Bis auf die etwas unterschiedliche Syntax ist der Ansatz gleich. Die beiden Beispiele zeigen, dass es in einfacheren Fällen keine großen Unterschiede zwischen der Nutzung von VBScript und der PowerShell gibt. Es gibt aber für beide Ansätze des Scripting gute Gründe.

So ist es beispielsweise relativ einfach, mit VBScript auch Office-Anwendungen anzubinden und sie zu steuern. Das liegt ganz einfach daran, dass man in beiden Fällen mit der gleichen Programmiersprache und einem ähnlichen Objektmodell arbeitet. Bei Verwendung der PowerShell liegen die Vorteile dagegen darin, dass man die Ergebnisse beispielsweise einfacher filtern und sortieren kann. Es ist also nicht so, dass eine Sprache generell besser und die andere weniger gut geeignet wäre. Entscheidend ist immer, was man erreichen möchte.

Mehr Details

Ziemlich spannend ist die Menge an Details, die man mit Abfragen ermitteln kann. Das wird an einer Abfrage wie

get-wmiobject Win32_process –filter ‘Name = "powershell.exe"’ | gm –membertype "Method,Property"

deutlich. Die Ergebnisse finden sich in Bild 3. Hier sind gleich zwei Dinge interessant. Mit der Option –filter erfolgt eine Filterung, die zwar nicht so flexibel ist wie die Möglichkeiten bei where, aber dafür noch einfacher. Damit wird also zunächst eine Liste der Prozesse erzeugt, die powershell. exe heißen. Solange diese nur einmal ausgeführt wird, ist es auch nur ein Prozess.

Bild 3: Die Ausgabe von Detailinformationen zu einem WMI-Objekt mit den unterstützten Methoden und Eigenschaften.

Das Ergebnis wird anschließend mit dem Cmdlet gm verarbeitet. Es steht für get-member und könnte auch entsprechend ausgeschrieben werden. Es listet Methoden, Eigenschaften und andere Informationen zu einem Objekt auf. Als Ergebnis wird also eine Liste der Methoden und Eigenschaften von powershell.exe ausgegeben. Mit nur einer Zeile kann man in der PowerShell eine beeindruckende Menge an Detailinformationen erhalten.

Weitere Möglichkeiten

Auch die Fähigkeit der PowerShell zur Ausgabe von formatierten Listen ist erfreulich. So kann man beispielsweise die Informationen zu laufenden Prozessen in Form einer Tabelle ausgeben lassen, indem man das Ergebnis durch das Cmdlet Format-table verarbeiten lässt:

get-wmiobject –list | where {$_.Name –like"Win32_Process*"} | Format-Table

Da die Anzahl der Spalten, die ausgegeben werden, reichlich lang ist, kann man dabei aber auch eine Auswahl treffen. Ein Beispiel dafür ist:

get-wmiobject Win32_process | where {$_.Handles –gt100} | select-object name,handles | format-table

In diesem Fall wird zunächst eine Abfrage nach der Liste der WMI-Prozesse durchgeführt. In dieser Liste werden die Prozesse ausgewählt, die mindestens 100 Handles gesetzt haben. Anschließend werden nur die Spalten name und handles selektiert, um diese in einer Tabelle auszugeben.

Sortierung

Eine Sortierung ist nun ebenfalls schnell erreicht mit

get-wmiobject Win32_process | where {$_.Handles –gt 100} | select-object name,handles | sort handles | format-table

In diesem Fall wird aufsteigend sortiert. Dabei wird das Cmdlet sort oder, genauer, sort-object verwendet. Falls die Ausgabe in absteigender Reihenfolge erfolgen soll, braucht es noch einen zusätzlichen Parameter:

get-wmiobject Win32_process | where {$_.Handles –gt 100} | select-object name,handles | sort –descending handles | format-table

Man muss dabei nur darauf achten, dass man die Feldnamen korrekt schreibt. Fehler werden von der PowerShell teilweise sofort gemeldet. Manchmal werden sie aber auch schlicht ignoriert, indem eine Spalte nicht angezeigt oder die Sortierreihenfolge eben nicht angepasst wird. Um sich übrigens mit den Details zu einzelnen Cmdlets vertraut zu machen, kann man immer den Befehl

help <name des cmdlets>

verwenden. Es werden dann detaillierte Informationen zum gewünschten Cmdlet angezeigt. Wenn man bis ans Ende blättert, finden sich jeweils auch Beispiele, die besonders nützlich sind, weil an ihnen die Verwendung der Cmdlets meist sehr viel schneller verständlich wird als an den recht ausführlichen Erläuterungen zu Beginn der jeweiligen Hilfetexte. Letztere braucht man vor allem, wenn man Cmdlets über die Basisfunktionen hinaus voll ausnutzen möchte.

Wie geht es weiter?

Diese Beispiele machen deutlich, wie einfach man Informationen über WMI auslesen und formatieren kann – und doch kratzt man damit nur an der Oberfläche dessen, was mit der PowerShell alles möglich ist.Deshalb wollen wir im folgenden Beitrag auch noch mehr Beispiele vorstellen.

Neben weiteren Anwendungsbereichen für das WMI-Scripting werden zusätzliche Techniken für das Scripting mit der Windows PowerShell erläutert.