WMI-Scripting

Das Ereignisprotokoll

Auch wenn in der Regel über die Anwendung Ereignisanzeige auf das Ereignisprotokoll zugegriffen wird, gibt es auch Fälle, in denen Skripts die bessere Lösung sind. Das gilt vor allem für das Troubleshooting, wenn mögliche relevante Ereignisse bekannt sind und zusammen mit anderen Systeminformationen ausgewertet werden sollen, um die Ursache von Problemen zu erkennen und sie unter Umständen sogar zu beseitigen. So könnten beispielsweise Statusinformationen von Diensten zusätzlich erfragt werden.
Typischerweise wird man solche Anwendungen allerdings nicht isoliert entwickeln, sondern beispielsweise als Erweiterungen von Anwendungen wie dem Microsoft Operations Manager (MOM).

Listing 3: Ein Skript für das Auslesen von Ereignisinformationen
strComputer = "."
Set wbemServices = GetObject("winmgmts:\\" & strComputer)
Set wbemObjectSet = wbemServices.InstancesOf("Win32_NTLogEvent")
For Each wbemObject In wbemObjectSet
WScript.Echo "Logdatei: " & wbemObject.LogFile & vbCrLf & _
"Satznummer: " & wbemObject.RecordNumber & vbCrLf & _
"Typ: " & wbemObject.Type & vbCrLf & _
"Erstellt am: " & wbemObject.TimeGenerated & vbCrLf & _
"Quelle: " & wbemObject.SourceName & vbCrLf & _
"Kategorie: " & wbemObject.Category & vbCrLf & _
"Kategorieinfo: " & wbemObject.CategoryString & vbCrLf & _
"Ereignis: " & wbemObject.EventCode & vbCrLf & _
"Benutzer: " & wbemObject.User & vbCrLf & _
"Computer: " & wbemObject.ComputerName & vbCrLf & _
"Nachricht: " & wbemObject.Message & vbCrLf
Next

Bild 4: Einträge aus dem Ereignisprotokoll können ebenfalls mit Hilfe von Skripts abgefragt werden.
Bild 4: Einträge aus dem Ereignisprotokoll können ebenfalls mit Hilfe von Skripts abgefragt werden.

Das Listing 3 enthält ein einfaches Beispiel für eine solche Anwendung. Es ist aber auch ein gutes Beispiel dafür, wann die Grundstruktur an ihre Grenzen stößt. Sie sollten das Skript – wenn überhaupt – nur in der Form

cscript skriptname.vbs

ausführen. Da es alle Ereignisse ausliest und für jedes Ereignis eine Ausgabe erzeugt, werden bei Verwendung von wscript.exe unter Umständen mehrere tausend Fenster angezeigt. Sie können allerdings den Windows Scripting Host (WSH) über den Task-Manager beenden, falls Sie mit dieser Situation konfrontiert werden sollten. Aber auch an der Befehlszeile erhalten Sie keine nutzbaren Ergebnisse mehr. Sie müssen in diesem Fall also unbedingt mit Abfragen arbeiten. Am einfachsten geht das, indem solche Abfragen in das Basisskript integriert werden (Listing 4). Natürlich könnten die Informationen beispielsweise für die Ereignis-ID auch aus Eingabefeldern übernommen werden.

Listing 4: Das Skript mit einer Abfrage
strComputer = "."
Set wbemServices = GetObject("winmgmts:\\" & strComputer)
Set wbemObjectSet = wbemServices.InstancesOf("Win32_NTLogEvent")
For Each wbemObject In wbemObjectSet
If wbemObject.LogFile = "Application" AND wbemObject.Eventcode = 1058 Then
WScript.Echo "Logdatei: " & wbemObject.LogFile & vbCrLf & _
"Satznummer: " & wbemObject.RecordNumber & vbCrLf & _
"Typ: " & wbemObject.Type & vbCrLf & _
"Erstellt am: " & wbemObject.TimeGenerated & vbCrLf & _
"Quelle: " & wbemObject.SourceName & vbCrLf & _
"Kategorie: " & wbemObject.Category & vbCrLf & _
"Kategorieinfo: " & wbemObject.CategoryString & vbCrLf & _
"Ereignis: " & wbemObject.EventCode & vbCrLf & _
"Benutzer: " & wbemObject.User & vbCrLf & _
"Computer: " & wbemObject.ComputerName & vbCrLf & _
"Nachricht: " & wbemObject.Message & vbCrLf
End If
Next

Das Skript unterscheidet sich bisher nur minimal vom vorigen. Hier ist allerdings die Frage, ob man nicht mit der Methode ExecQuery wesentlich einfacher und besser arbeiten könnte. Das modifizierte Skript hätte in diesem Fall das Aussehen aus Listing 5.

Listing 5: Das Skript bei Verwendung von ExecQuery
strComputer = "."
Set wbemServices = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set wbemObjectSet = wbemServices.ExecQuery("SELECT * From Win32_NTLogEvent Where
LogFile = 'Application' AND EventCode = 1058")
For Each wbemObject In wbemObjectSet
WScript.Echo "Logdatei: " & wbemObject.LogFile & vbCrLf & _
"Satznummer: " & wbemObject.RecordNumber & vbCrLf & _
"Typ: " & wbemObject.Type & vbCrLf & _
"Erstellt am: " & wbemObject.TimeGenerated & vbCrLf & _
"Quelle: " & wbemObject.SourceName & vbCrLf & _
"Kategorie: " & wbemObject.Category & vbCrLf & _
"Kategorieinfo: " & wbemObject.CategoryString & vbCrLf & _
"Ereignis: " & wbemObject.EventCode & vbCrLf & _
"Benutzer: " & wbemObject.User & vbCrLf & _
"Computer: " & wbemObject.ComputerName & vbCrLf & _
"Nachricht: " & wbemObject.Message & vbCrLf
Nex

Die Struktur ändert sich dadurch kaum. Die zusätzliche Angabe von root\cimv2 wäre nicht zwingend erforderlich. Interessant ist vor allem die Auswahl. Man vermeidet dadurch Schleifen und arbeitet stattdessen mit WQL (WMI Query Language), also der speziellen SQL-Variante bei WMI. Die Ausgabe ist identisch. Innerhalb der Abfragen lassen sich auch Variablen einsetzen. Damit werden die Skripts deutlich übersichtlicher. Ein Beispiel findet sich in Listing 6.

Listing 6: Die verstärkte Nutzung von Variablen
strComputer = "."
strNameSpace = "\root\cimv2"
strQueryClass = "Win32_NTLogEvent"
strQueryWhere = "LogFile = 'Application' AND EventCode = 1058"
Set wbemServices = GetObject("winmgmts:\\" & strComputer & strNameSpace)
Set wbemObjectSet = wbemServices.ExecQuery("SELECT * From " & strQueryClass & "
Where " & strQueryWhere)
For Each wbemObject In wbemObjectSet
WScript.Echo "Logdatei: " & wbemObject.LogFile & vbCrLf & _
"Satznummer: " & wbemObject.RecordNumber & vbCrLf & _
"Typ: " & wbemObject.Type & vbCrLf & _
"Erstellt am: " & wbemObject.TimeGenerated & vbCrLf & _
"Quelle: " & wbemObject.SourceName & vbCrLf & _
"Kategorie: " & wbemObject.Category & vbCrLf & _
"Kategorieinfo: " & wbemObject.CategoryString & vbCrLf & _
"Ereignis: " & wbemObject.EventCode & vbCrLf & _
"Benutzer: " & wbemObject.User & vbCrLf & _
"Computer: " & wbemObject.ComputerName & vbCrLf & _
"Nachricht: " & wbemObject.Message & vbCrLf
Next

In diesem Fall gibt es zu Beginn verschiedene Definitionen. Die Variablen werden in den beiden Set-Anweisungen verwendet und sorgen dafür, dass auf die gewünschten Daten zugegriffen wird. Diese Struktur des Skripts hat den großen Vorteil, dass es leichter modifiziert werden kann, weil es übersichtlicher ist. Auch ein Ausbau beispielsweise mit Eingabefeldern, in denen die Where-Klausel der Abfrage eingegeben wird, ist wesentlich einfacher zu bewerkstelligen.

Die Klasse Win32_NTLogEvent ist nur eine von mehreren Klassen rund um die Ereignisprotokollierung.
Insgesamt kennt WMI hier fünf Klassen:

  • Win32_NTEventlogFile ist die Klasse, mit der direkt auf die Dateien, die für die Ereignisprotokollierung verwendet werden, zugegriffen werden kann.

  • Win32_NTLogEvent wird wie beschrieben für den Zugriff auf die Informationen in den Protokolldateien verwendet.

  • Win32_NTLogEventComputer stellt die Beziehung zwischen einem Computer und einem Eintrag her.

  • Win32_NTLogEventLog stellt die Beziehung zwischen einem Eintrag und einer Protokolldatei her.

  • Win32_NTLogEventUser stellt die Beziehung zwischen einem Eintrag und einem Benutzer her. In den Skripts werden in der Regel nur die beiden erstgenannten Klassen benötigt.