Die meisten Leute, die zum ersten Mal von Monad hören, haben zwei Fragen: Was ist Monad, und - die wichtigere - was kann ich damit machen?
Mit der ersten Frage ("Was ist Monad?") werden wir uns in diesem Artikel nicht beschäftigen. Wenn Sie sich nicht sicher sind, was Monad ist, dann sollten Sie unser Interview mit Jeffrey Snover, dem Chief Architect für die Windows "Monad" Shell, lesen. Wir kümmern uns hier um die zweite Frage: "Was kann ich mit Monad machen?" - und zwar aus Sicht eines Systemadministrators. Es gibt zwar andere Ressourcen zu Monad, aber diese wenden sich normalerweise an Entwickler statt an Systemadministratoren. Dieser Artikel soll Ihnen ein besseres Verständnis dazu vermitteln, was Sie mit Monad machen können.
Anmerkung: OK - einige Leute haben tatsächlich noch eine dritte Frage: "Warum Monad?" Monad ist der Microsoft-Codename für ein Produkt. Der Begriff Monad wurde vom Wissenschaftler, Mathematiker und Philosoph Gottfried Leibniz eingeführt. Dieser definiert Monads als "erhebliche Formulare des Seins, die den geistigen Atomen entsprechend sind, ewig, unzerlegbar, einzeln und ihren eigenen Gesetzen folgend und nicht aufeinander einwirkend, aber jedes, welches das vollständige Universum in vorher festgesetzter Harmonie reflektiert".
Wow.
Sagen wir einfach, Monad ist eine Skripting-Technologie und belassen es dabei.
Also, was können Sie nun mit Monad anfangen? Zum ersten können Sie Monad für den Zugriff auf WMI und auf WMI-Daten nutzen. Sehen wir uns ein Skript an, das Sie möglicherweise kennen. Ein VBScript, das Informationen über die Klasse Win32_Process abfragt und die Attribute Name und WorkingSetSize für jedes Element der zurückgegebenen Collection ausgibt:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer &"\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Process")
For Each objItem in colItems
Wscript.Echo objItem.Name, objItem.WorkingSetSize
NextOk, hören Sie auf zu gähnen. Wir wissen, Sie haben dieses Skript (oder ein ziemlich ähnliches) bereits hundert Mal gesehen. Aber genau darum geht es - Sie kennen es und wissen, was es macht. Sehen wir uns nun ein Monad-Skript an, das genau das Gleiche macht:
$strComputer = "."
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" -computername $strComputer
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.WorkingSetSize
}Es gibt offensichtlich ein paar Unterschiede in der Syntax, die wir gleich genauer besprechen werden. Trotz dieser Unterschiede können Sie jedoch wahrscheinlich beim Betrachten dieses Skriptes halbwegs feststellen, was es macht. Hier ist also ein weiteres Beispiel. Können Sie erkennen, was dieses Skript macht?
$strComputer = "."
$colItems = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername $strComputer
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.State
}Genau: Dieses Monad-Skript gibt die Attribute Name und State für jeden Dienst aus (also für alle Instanzen der Klasse Win32_Service). Wie Sie selbst sehen können, ist es sehr einfach festzustellen, was ein Monad-Skript macht. Dinge wie WMI-Klassen, Namespaces und Computernamen werden einfach ausgeschrieben.
Natürlich ist es eine Sache, ein Skript zu lesen, und eine andere, eins zu schreiben. Schließlich können auch eine ganze Menge Leute Bücher lesen, aber nur ziemlich weniger welche schreiben (nicht, dass es die restlichen davon abhalten würde, zu schreiben). Bevor Sie also Ihr eigenes Monad-Skript zur Abfrage von WMI-Daten schreiben können, müssen Sie zumindest einige Details der Monad-Skriptsprache kennen. Machen Sie sich jedoch keine Sorgen. Letztendlich ist das der Grund, aus dem wir Scripting Guys überhaupt da sind.
Lassen Sie uns das Einfachste zuerst erledigen. In der ersten Zeile weisen wir den Wert Punkt (.) zu einer Variable $strComputer zu:
$strComputer = "."
Diese Zeile entspricht fast vollständig unserem VBScript-Skript. Einziger Unterschied ist, dass der Variablenname mit einem Dollarzeichen beginnt ($). Warum? Nun, ganz einfach darum, weil Monad dies so verlangt. Variablennamen müssen mit einem $ beginnen.
Kommen wir nun zum get-wmiobject-Cmdlet (wir erklären gleich, was ein Cmdlets ist). Wie der Name schon zeigt, dient get-wmiobject für den Zugriff auf WMI und auf WMI-Daten. Das Cmdlet versucht, Skriptautoren von der Komplexität hinter dem Aufbauen von WMI-Verbindungen abzuschirmen. Dies wird erreicht, indem die stumpfsinnigeren Teile des Monikers winmgmts: einfach maskiert werden. Sie müssen nur noch ein paar leere Felder eintragen:
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" -computername $strComputer
Wie Sie sehen, finden Sie alles wieder, was auch in einem VBScript-Skript auftaucht. Das Einzige, was Monad macht, ist den ganzen unübersichtlichen Rest zu entfernen und das Angeben von bestimmten Dingen wie der WMI-Klasse und dem Namespace etwas klarer zu machen. In diesem Fall rufen wir eine Collection von WMI-Daten ab und speichern diese in der Variable $colItems. Hierzu rufen wir einfach get-wmiobject mit den folgenden Parametern auf:
| Parameter | Beschreibung |
-class | Name der WMI-Klasse, auf die wir zugreifen wollen (in diesem Fall Win32_Process). |
-namespace | Der WMI-Namespace, in der sich die Klasse befindet. Wenn die Klasse im Namespace root\cimv2 liegt, können Sie diesen Parameter auslassen, da dieser Namespace der Standardwert ist. |
-computername | Der Computer, mit dem wir uns verbinden wollen. Wenn der Parameter nicht angegeben wird, fragt das Skript den lokalen Computer ab. |
Natürlich gibt es weitere Parameter. Wir werden später noch über einen dieser zusätzlichen Parameter sprechen (-filter).
Sie sehen also, so schrecklich ist das Ganze nicht. Wenn Sie auf die Klasse StdRegProv (im Namespace root\default) auf dem Remotecomputer atl-fs-99 zugreifen wollen, dann verwenden Sie die folgenden Parameter:
$colItems = get-wmiobject -class "StdRegProv" -namespace "root\default" -computername "atl-fs-99"
Einfacher kann es wirklich nicht mehr gehen.
Ok, gehen wir einen Schritt weiter. In einem VBScript-Skript rufen wir eine Collection mit Daten ab und gehen diese dann mit einer For/Each-Schleife durch. In einem Monad-Skript machen wir das Gleiche. Der entsprechende Code sieht so aus:
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.WorkingSetSize
}Stören Sie sich nicht an der Syntax. Auch wenn sie sich offensichtlich von VBScript unterscheidet, ist sie deshalb nicht zwingend schwerer. Sie ist einfach, naja, anders. Die Schleife beginnt mit dem Befehl foreach - gefolgt von den entsprechenden Kriterien in Klammern. Mit VBScript würden wir das so formulieren:
For Each objItem in colItems
Mit Monad sieht das Gleiche so aus:
foreach ($objItem in $colItems)
Und hier gibt es noch einen kleinen Unterschied. Mit VBScript beenden wir die Schleife mit Next:
For Each objItem in colItems
Wscript.Echo objItem.Name, objItem.WorkingSetSize
NextMit Monad machen wir das nicht so. Hier gibt es keinen Next-Befehl. Stattdessen fassen wir den auszuführenden Code in geschweifte Klammern ein:
{
write-host $objItem.Name, $objItem.WorkingSetSize
}In diesem Fall wollen wir die Werte der Attribute Name und WorkingSetSize ausgeben. Hierzu nutzen wir write-host - ein Cmdlet, das Daten in die Eingabeaufforderung schreibt (sehr ähnlich wie das auch Wscript.Echo macht). Das Cmdlet hat ein paar Möglichkeiten, die Wscript.Echo fehlen. Ein Beispiel dazu finden Sie im Artikel Träumen Skriptautoren von lila Text?. In unserem Beispielskript geben wir nur die Werte aus. Wenn wir wollten, können wir noch Beschriftungen hinzufügen:
write-host "Name: " $objItem.Name write-host "Working Set Size: " $objItem.WorkingSetSize
Ziemlich simpel, oder? Und beachten wir, dass wir die einzelnen Elemente nicht mal verknüpfen müssen. In einem VBScript-Skript hätten wir ein kaufmännisches Und verwenden müssen:
Wscript.Echo "Name: " & objItem.Name
Mit Monad ist das nicht erforderlich. Ein gültiges Monad-Skript sieht zum Beispiel so aus:
$Number = 4 write-host "1" 2 "3" $Number 5
Wir geben Strings, Zahlen und eine Variable mit einem einzigen Aufruf von write-host aus. Und zwar ohne irgendwelche Verkettungen. Die Ausgabe sieht so aus:
1 2 3 4 5
Das ist genau das, was wir uns erhofft haben. Monad ist außerdem flexibel. Wenn Sie es zum Beispiel einfacher finden, die einzelnen Elemente durch Kommas zu trennen, dann können Sie die Zeile so abändern:
$Number = 4 write-host "1", 2, "3", $Number, 5
Sie haben die Wahl.
Dass Sie das Und weglassen können, ist ein nettes kleines Feature. Aber um ehrlich zu sein, in unserem Beispiel-Skript ist der Unterschied zwischen Monad und VBScript ungefähr so groß wie der Unterschied zwischen amerikanischem und britischem Englisch. Sie werden beides nie miteinander verwechseln, und es wird immer ein paar Wörter und Aussprüche geben, die sich unterscheiden oder verschieden verwendet werden. Aber ein Amerikaner versteht so ziemlich alles, was ein Brite sagt. Genauso versteht ein VBScript-Autor so ziemlich alles in einem Monad-Skript. Und genau dieser Punkt führt uns zu einer ziemlich offensichtlichen Frage.
Das ist tatsächlich eine ziemlich gute Frage. Wenn ein Monad-Skript, das WMI-Informationen abfragt, genau wie ein VBScript-Skript arbeitet, warum dann mit Monad beschäftigen? Die Wahrheit ist: Bei einfachen WMI-Skripten gibt es tatsächlich keinen zwingenden Grund, mit Monad zu arbeiten. Es macht überhaupt keinen Unterschied, welche Sprache Sie verwenden.
Die Unterschiede bleiben so lange klein, wie Sie nicht ein paar ausgefallen Sachen machen wollen. Hier fängt Monad tatsächlich an, interessant zu werden. WMI gibt die Daten zum Beispiel immer nach der Schlüsseleigenschaft wortiert zurück (eine Eigenschaft, die jede Instanz einer Klasse eindeutig identifiziert). Bei der Klasse Win32_Process handelt es sich hier um das Attribut Handle. Das bedeutet, dass die Prozessinformationen immer nach diesem Attribut sortiert sind. Sie möchten Sie alphabetisch oder nach ihrer Größe sortieren? Schade. Das ist nur mit WMI nicht möglich.
Und als würde dies nicht ausreichen, verfügt VBScript noch nicht mal über eine standardmäßige Funktion, um Daten zu sortieren. Das heißt nicht, dass Sie nicht sortieren können. Es bedeutet nur, dass Sie eine andere Skripting-Technologie nutzen müssen. Das folgende VBScript-Skript verwendet ADO (ActiveX Data Objects), um die Prozessinformationen zu sortieren:
Const adVarChar = 200
Const MaxCharacters = 255
Const adFldIsNullable = 32
Const adInteger = 3
Set DataList = CreateObject("ADOR.Recordset")
DataList.Fields.Append "ProcessName", adVarChar, MaxCharacters, adFldIsNullable
DataList.Fields.Append "WorkingSetSize", adInteger, adFldIsNullable
DataList.Open
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colProcesses = objWMIService.ExecQuery("Select * From Win32_Process")
For Each objProcess in colProcesses
DataList.AddNew
DataList("ProcessName") = objProcess.Name
DataList("WorkingSetSize") = objProcess.WorkingSetSize
DataList.Update
Next
DataList.Sort = "WorkingSetSize"
DataList.MoveFirst
Do Until DataList.EOF
Wscript.Echo DataList.Fields.Item("ProcessName"),_
DataList.Fields.Item("WorkingSetSize")
DataList.MoveNext
LoopEtwas verwirrend, aber es funktioniert. Wie geht nun Monad mit dem gleichen Problem um?
Ohne COM-Objekte (Anwendungen, die ihre Funktionalität in Skripten nutzbar machen) wäre VBScript nicht sehr nützlich. Tatsächlich wären Sie nicht zu viel mehr in der Lage, als einen Winkel zu berechnen oder den absoluten Wert von -545. Dies liegt daran, dass VBScript nur über wenige Funktionen verfügt. Alles Nützliche ist über COM-Objekte implementiert (zum Beispiel in unserem vorherigen Beispiel WMI und ADO).
Monad kann ebenfalls COM-Objekte nutzen. Letztendlich fragt get-wmiobject auch nur den WMI-Dienst ab. Zusätzlich zu den COM-Objekten stellt Monad jedoch einige Cmdlets zur Verfügung. Cmdlets sind Programmiermodule, die das Gleiche wie COM-Objekte machen: Sie stellen ihre Funktionalität für Skriptautoren zur Verfügung. Cmdlets sind jedoch enger mit Monad integriert als COM-Objekte. Daher können Sie Objekte und Daten einfacher von einem Cmdlet an ein anderes "weiterreichen".
Was bedeutet das? Wir zeigen es Ihnen. Es folgt ein Monad-Skript, das die Prozessinformationen nach deren Größe sortiert:
$strComputer = "."
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" `
-computername $strComputer | sort "WorkingSetSize"
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.WorkingSetSize
}Anmerkung: Bei Monad steht das Zeichen ` für einen Zeilenumbruch. Es entspricht dem Unterstrich (_) bei WSH und VBScript.
Ob Sie es glauben oder nicht - das ist das gesamte Skript. Und nein, Sie haben den restlichen Code nicht versehendlich übersehen. Mit Monad gibt es keinen weiteren Code. Dies liegt daran, dass wir das sort-object (oder sort) zum Sortieren nutzen können. Sehen Sie sich diesen Code an:
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" ` -computername $strComputer | sort "WorkingSetSize"
Wie Sie sehen, gibt es am Ende der Abfrage diesen komisch aussehenden Code: | sort "WorkingSetSize". Das | ist das Pipeline-Zeichen. Das bedeutet, dass wir alles von der linken Seite des Zeichens an das Cmdlet auf der rechten Seite übergeben möchten (Pipeline). In diesem Fall möchten wir die Prozessinformationen aus der WMI-Abfrage an das Cmdlet übergeben.
Und was macht das Cmdlet mit den Informationen? Man glaubt es kaum - es sortiert die Daten nach jedem beliebigen Parameter (in diesem Fall WorkingSetSize):
Hier noch ein kleiner Trick: Das sort-Cmdlet sortiert die Daten normalerweise in aufsteigender Reihenfolge. Mit dem Parameter -descending können Sie die Sortierreihenfolge jedoch umkehren:
$strComputer = "."
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" `
-computername $strComputer | sort -descending "WorkingSetSize"
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.WorkingSetSize
}Hier kommt ein weiteres Szenario, das von Zeit zu Zeit auftritt: Nehmen wir an, Sie möchten feststellen, welcher von fünf Prozessen der größte ist. Ist das mit VBScript möglich?
Darauf können Sie wetten. Natürlich ist das möglich. Natürlich brauchen wir wieder unser Recordset von oben und diesmal noch etwas zusätzlichen Code:
Const adVarChar = 200
Const MaxCharacters = 255
Const adFldIsNullable = 32
Const adInteger = 3
Set DataList = CreateObject("ADOR.Recordset")
DataList.Fields.Append "ProcessName", adVarChar, MaxCharacters, adFldIsNullable
DataList.Fields.Append "WorkingSetSize", adInteger, adFldIsNullable
DataList.Open
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colProcesses = objWMIService.ExecQuery("SELECT * FROM Win32_Process")
For Each objProcess in colProcesses
DataList.AddNew
DataList("ProcessName") = objProcess.Name
DataList("WorkingSetSize") = objProcess.WorkingSetSize
DataList.Update
Next
DataList.Sort = "WorkingSetSize DESC"
DataList.MoveFirst
i = 1
Do Until i = 6
Wscript.Echo DataList.Fields.Item("ProcessName"),_
DataList.Fields.Item("WorkingSetSize")
DataList.MoveNext
i = i + 1
LoopUnd hier ist nun das entsprechende Monad-Skript:
$strComputer = "."
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" `
-computername $strComputer | sort –descending "WorkingSetSize" | select-object –first 5
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.WorkingSetSize
}Warum ist das Monad-Skript so viel kleiner? Sie erraten es: Monad stellt ein Cmdlet zur Verfügung (select-object), mit dem Sie eine Untermenge der Objekte einer Collection auswählen können (oder in der Sprache von Monad: aus der Pipeline). Beachten wir, dass wir dieses Mal ein Pipeline-Paar haben. Nachdem wir die Daten sortiert haben, übergeben wir sie an eine zweite Pipeline. In der zweiten Pipeline wählen wir die ersten fünf Elemente der Collection mit select-object aus (select-object -first 5). So einfach ist das. Was, wenn wir die ersten drei Prozesse mit der kleinsten Größe haben wollen? Eine Möglichkeit wäre, einfach die letzten drei Elemente der collection auszuwählen:
$strComputer = "."
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" `
-computername $strComputer | sort –descending "WorkingSetSize" | select-object –last 3
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.WorkingSetSize
}Ziemlich cool, oder?
Die letzte Möglichkeit, die wir Ihnen zeigen wollen, ist das Filtern von Daten. Monad ist nicht besser (oder schlechter) im Filtern von Daten als VBScript. Es soll nur der Vollständigkeit halber erwähnt werden.
Mit VBScript fügen Sie einfach eine Where-Bedingung zur WQL-Abfrage hinzu. Wenn Sie zum Beispiel alle Prozesse mit einer Größe von mehr als 3.000.000 Byte haben wollen, dann sieht das so aus:
Set colItems = objWMIService.ExecQuery _
("Select * From Win32_Process Where WorkingSetSize > 3000000")Bei Monad wird hierzu der Parameter -filter von get-wmiobject verwendet:
$strComputer = "."
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" `
-computername $strComputer –filter "WorkingSetSize > 3000000"
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.WorkingSetSize
}Wie Sie sehen, entspricht das ganze einer Where-Bedingung - nur ohne das Schlüsselwort Where: –filter "WorkingSetSize > 3000000".
Auch der AND- und OR-Operator kann im –filter-Parameter verwendet werden. Wenn sie zum Beispiel alle Instanzen von Word suchen, die größer als 3.000.000 Byte sind, dann sieht das unter VBScript so aus:
Set colItems = objWMIService.ExecQuery _
("Select * From Win32_Process Where WorkingSetSize > 3000000 AND Name = 'winword.exe'")Das Monad-Gegenstück sieht folgendermaßen aus:
$strComputer = "."
$colItems = get-wmiobject -class "Win32_Process" -namespace "root\cimv2" `
-computername $strComputer –filter "WorkingSetSize > 3000000 AND Name='winword.exe'"
foreach ($objItem in $colItems) {
write-host $objItem.Name, $objItem.WorkingSetSize
}Das soll für heute alles sein. Wir werden jedoch das Script Center regelmäßig mit weiteren Artikeln über Monad auf dem Laufenden halten. Wenn es ein Thema gibt, das Sie besonders interessiert, dann schreiben Sie uns doch eine Email unter scripter@microsoft.com (bitte nur in Englisch). Wir sehen zu, was sich machen lässt.