Server-Überwachung mit ASP

09.09.2003 von THOMAS WOELFER 
Mittels WMI lassen sich Windows 2000 und 2003 per Script-Programmierung verwalten. Dieser Beitrag zeigt, wie Sie zusammen mit ASP-Seiten des IIS ganz einfach eine Webkonsole zum Management Ihrer Server realisieren.

Der IIS und Windows 2000/2003 sind auch über entfernte Workstations administrierbar. Das Problem dabei ist, dass man sich dazu auf die Sicherheitsmechanismen von Windows verlassen muss - und außerdem viel Vertrauen in die Sicherheit der Fernwartungsmechanismen des Systems haben sollte. Doch selbst wenn man dieses Vertrauen aufbringt, reichen die gebotenen Möglichkeiten oft einfach nicht aus.

Das ist aber kein wirkliches Problem, denn beim IIS kann man sich mit Hilfe von Scripts behelfen. Praktisch alles, was mit den fertigen Windows-Tools möglich ist, lässt sich genauso per Script und Webseiten umsetzen. Die Schlüsselworte sind hier ASP und WMI: Damit lässt sich eine Menge erreichen - so zum Beispiel der Zusammenbau eines webbasierten Task- und eines Dienste-Managers, wie im Folgenden erläutert.

ASP - also Active Server Pages - sind vermutlich jedem ein Begriff, der sich mit Windows-basierten Servern auseinander setzt. Der Begriff WMI hingegen erklärungsbedürftig: Bei WMI handelt es sich um das "Windows Management Instrumentation"-Interface, das bei Windows 2000/2003 und XP von Haus aus enthalten ist, aber gleichermaßen für Windows 9x und NT zur Verfügung steht. Im Wesentlichen ist WMI Microsofts Implementierung von WBEM (Web-based Enterprise Management) beziehungsweise des Common Information Model (CIM), das von der Distributed Management Task Force (DMTF) entwickelt wurde.

Wenn man einmal über diese vielen Abkürzungen hinwegsieht, findet man bei WMI einen recht großen Satz an Möglichkeiten zur Verwaltung von Rechnern per Script. Diese sind in einem konsistenten und erweiterbaren Interface zusammengefasst, das von verschiedenen Sprachen aus benutzbar ist. Dazu gehört nicht nur C++, wie man vielleicht erwarten würde, sondern WMI ist auch von den Script-Sprachen Jscript und VBScript verwendbar. Damit steht WMI auch innerhalb von ASP-Seiten zur Verfügung.

Fernwartung per WMI

Mit WMI können Rechner nicht nur lokal, sondern auch über das Netz verwaltet werden. Dazu bietet WMI eine SQL-ähnliche Abfragesprache, mit der man Informationen über einen bestimmten Rechner aufruft. Außerdem ist es nicht nur möglich, von vornherein festgelegte Informationen abzufragen - man kann zudem herausfinden, welche Informationen überhaupt vorhanden sind. Bei reinem SQL lässt sich das zum Beispiel mit show tables und describe TableName erledigen. In unserem Beispiel wird allerdings davon ausgegangen, dass der betroffene Rechner allein im Netz hängt. Daher wird nur dieser Rechner selbst betrachtet und per ASP-Seiten verwaltet.

Das WMI bietet Zugriff auf eine große Menge an Objekten. Ein solches Objekt ist zum Beispiel eine Festplatte in einem bestimmten System. Alle Objekte befinden sich dabei in Container-Objekten, so sind zum Beispiel alle Festplatten eines Systems über den Festplatten-Container ansprechbar. Über den Inhalt des Containers können Sie iterieren und so die einzelnen Objekte erreichen. Wie das nun genau geschieht, hängt von der verwendeten Sprache ab.

Ferner stellt WMI für jedes Objekt einen Satz an Eigenschaften zur Verfügung. Diese lassen sich auslesen und zu großen Teilen auch setzen. Eine der Eigenschaften einer Festplatte ist zum Beispiel ihre Größe - hier handelt es sich allerdings um eine nicht veränderbare Eigenschaft. Den Namen (Laufwerksbuchstaben) einer Festplatte hingegen kann man sehr wohl per WMI festlegen.

Darüber hinaus steht für jedes Objekt ein Satz an Methoden zur Verfügung, die sich auf das Objekt anwenden lassen: Im Falle eines Verzeichnisses auf einer NTFS-formatierten Partition ist das zum Beispiel die Methode Compress(), die das Verzeichnis komprimiert.

Objekte dieser Art stellt WMI bei Windows in sehr großer Zahl zur Verfügung: Praktisch jede Aufgabe, die man mit der MMC und den darin enthaltenen Tools ausführen kann, lässt sich auch per WMI durchführen. Darüber hinaus steht noch eine Untermenge der Win32-API zur Verfügung: Diese können beispielsweise Prozesse beenden oder starten.

So weit zur Theorie. Im Fall von Webseiten funktioniert die Praxis im Wesentlichen so, wie Sie das von ASP-Scripts bereits gewohnt sind. Der zentrale Unterschied ist die Methode, mit der die zu nutzenden Objekte erzeugt werden. Genauer gesagt die Art und Weise, in der die das Objekt beschreibenden Parameter für die GetObject()-Methode zusammengesetzt werden.

Einige einfache Beispiele für WMI

Die folgenden Beispiele gehen davon aus, dass Sie die ASP-Seiten auf einem Server Ihrer Wahl installieren und eben diesen Server administrieren möchten. Wie gesagt bietet WMI zwar auch Möglichkeiten zur Administration entfernter Rechner, darauf wird aber nicht weiter eingegangen.

Noch ein Hinweis vorweg: Aus Sicherheitsgründen sind WMI-Objekte per ASP nur dann zugänglich, wenn sich die ASP-Seite in einem Bereich auf Ihrem Server befindet, der ausschließlich über die "Integrierte Windows Authentifizierung" erreicht werden kann. Befinden sich die Seiten in einem Bereich, der auch mit anderen Formen der Authentifizierung sichtbar ist, so wird beim Versuch, die WMI-Objekte zu benutzen, ein entsprechender Fehler generiert.

Bevor wir das große Beispiel in Form des Dienste- und Task-Managers angehen, zunächst ein paar einfache Modelle, die sich fallweise an anderer Stelle als Werkzeuge gebrauchen lassen.

IP-Konfiguration auslesen

Angenommen Sie würden gerne Informationen über die IP-Konfiguration des entfernten Rechners auslesen. Dazu der folgende Beispielcode (in einer Produktionsumgebung wäre es natürlich sinnvoll, den Quellcode um passende Fehlerbehandlungen zu erweitern):

<%
set IPConfigSet = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery ("SELECT IPAddress, DefaultIPGateway FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled=TRUE")

for each IPConfig in IPConfigSet
Response.Write " IP-Addresse: " & IPConfig.IPAddress(i)
Response.Write "Default IP Gateway: " & IPConfig.DefaultIPGateway(i)
Next
%>

Zunächst erzeugen Sie ein Container-Objekt mit dem Namen IPConfigSet. Dieses Set enthält alle zur Abfrage passenden Objekte. In diesem Fall sind das Objekte des Typs Win32_NetworkAdapterConfiguration - also Konfigurationen von Netzwerkkarten, die eingeschaltet sind (Enabled = True). Von diesen Objekten werden aber nicht alle Informationen, sondern nur die IP-Adresse und das DefaultGateway erfragt.

Dann iteriert das Script über alle Elemente des zurückgelieferten Containers. Bei VBScript unter ASP ist das mit dem Konstrukt for each sehr einfach. In jedem Schleifendurchlauf können Sie ein Objekt mit dem Namen IPConfig verwenden; dieses Objekt hat die beiden ausgewählten Eigenschaften: IPAdress und DefaultIPGateway. Diese beiden Eigenschaften geben Sie dann mit Response.Write aus: Fertig ist die IP-Informationsseite.

Festplattenplatz mit WMI ermitteln

Als zweites Beispiel soll hier die bereits angesprochene Festplatte ins Spiel kommen: Ob und wie voll die Festplatten im Server sind, ist immer eine wichtige Information, etwa wenn die HTTP-Kompression des IIS verwendet wird. Dieses Script verhilft zur benötigten Information:

<%
Set DiskSet = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery("select FreeSpace,Size,Name from Win32_LogicalDisk where DriveType=3")

for each Disk in DiskSet
Response.Write "Laufwerk " + Disk.Name + " hat noch " + Disk.FreeSpace + " von " + Disk.Size + "Byte frei. "
Next
%>

Ähnlich wie beim ersten Beispiel wird hier zunächst eine Sammlung von Elementen ermittelt. Allerdings ist die Abfrage hier etwas komplizierter, denn es sollen nicht alle Elemente vom Typ Win32_LogicalDisk erfragt werden, sondern nur eine Untergruppe. Wie bei einem normalen SQL-Statement grenzen Sie diese Untergruppe auch bei WMI mit der Klausel where ein, in diesem Fall mit where DriveType=3. Dadurch liefert WMI nur lokale Festplatten. Andernfalls enthält das Resultat auch Disketten-, CD/DVD- und Netzwerklaufwerke. Das ist in diesem Fall aber überflüssig.

An Informationen erfragen Sie nur den freien Platz (FreeSpace), die Größe (Size) sowie den Laufwerksbuchstaben (Name) der Platte. Diese Informationen werden danach wiederum mit Response.Write angezeigt.

Bei beiden einführenden Beispielen haben Sie nun gesehen, dass Sie sich in der WMI-Abfrage auch auf Teile der zur Verfügung stehenden Eigenschaften beschränken können. Das ist hilfreich - noch besser wäre es aber zu wissen, welches denn die verfügbaren Eigenschaften sind. Wie das zu erreichen ist, zeigt das dritte Beispiel, und zwar anhand aller auf dem Rechner laufenden Prozesse.

Vorhandene Eigenschaften erfragen

Um alle verfügbaren Eigenschaften abzufragen, bedient man sich der Eigenschaft Properties. Dabei handelt es sich um einen Container, den Sie verwenden können, um über alle Eigenschaften eines Objekts zu iterieren - auch ohne diese beim Namen zu kennen. Bei jedem Iterationsschritt erhalten Sie dann eine einzelne Eigenschaft, und diese wiederum hat die beiden Eigenschaften Name und Value. Damit werden die Bezeichnung und der zugehörige Wert erfragt.

<%
for each Process in GetObject("winmgmts:{impersonationLevel=impersonate}").InstancesOf ("Win32_process")
Response.Write Process.Name & "<br><ul>

for each Prop in Process.Properties_
Response.Write "<li>" & Prop.Name & "=" & Prop.Value
next
next
%>

Hier verwenden Sie zunächst eine andere Art, die Objekte zu ermitteln. Gewünscht sind alle Objekte vom Typ Prozess, und diese erhalten Sie per InstancesOf("Win32_process"). Danach können Sie über diese Gruppe der Objekte iterieren und zeigen mit

Response.Write Process.Name

zunächst die Bezeichnung des Prozesses an. Danach ermitteln Sie mit

for each Prop in Process.Properties_

die Gruppe der zu diesem Prozess gehörenden Eigenschaften und können auch diese dann mit Response.Write anzeigen.

Echte Administration per WMI

So viel zu den Fingerübungen - hier noch zwei konkrete Beispieltools. Dabei handelt es sich um einen webbasierten Task-Manager und Dienste-Manager. Der Task-Manager ist in der Lage, alle laufenden Prozesse anzuzeigen. Dabei wird der Name des Prozesses, sein Pfad auf der Festplatte, die Größe des Working Set sowie die Anzahl der zu diesem Prozess gehörenden Threads ausgegeben. Ferner können Sie alle Prozesse über die Webseite beenden. Daher bitte Vorsicht: Die Webseite funktioniert ähnlich wie der Task-Manager von Windows, beendet jedoch die Prozesse ohne Rückfrage - nur handelt es sich eben um Prozesse auf Ihrem Server!

Der Dienste-Manager bietet als Funktionsumfang eine Untermenge des normalen Dienste-Managers von Windows. Er zeigt alle vorhandenen Dienste an und gibt dabei für jeden Dienst aus, ob dieser in Betrieb ist oder nicht. Darüber hinaus können Sie laufende Dienste beenden und nicht laufende Dienste starten. Damit die ganze Sache übersichtlich bleibt, wird die Webseite mit den laufenden Diensten alle zehn Sekunden neu aufgebaut. Beide Scripts können Sie in einer ausführlichen Version bei www.tecChannel.de (webcode: windowscompact) herunterladen und verwenden. Den Task-Manager finden Sie unter dem Namen "taskmgr.asp" und den Dienste-Manager unter dem Namen "services.asp". Beide Programme benötigen noch ein paar Hilfsdateien: Zum Testen kopieren Sie einfach alle Dateien in ein gemeinsames Verzeichnis, das im IIS über die Windows-Authentifizierung geschützt ist.

Ein Task-Manager mit ASP

Beim Task-Manager handelt es sich zunächst um eine ganz normale Webseite mit eingebetteten ASP-Befehlen:

<html><head><title>Task-Manager</TITLE>

</head><body>
<%
if not request.queryString("kill") =""
then KillProcess Request.QueryString("kill")
end if

ListProcesses
%>
</body></html>

Der ASP-Code prüft zunächst, ob die Seite mit einem Parameter aufgerufen wurde - und zwar mit dem Parameter Kill. Ist das der Fall, enthält er die Prozess-ID des zu beendenden Prozesses, und der Code ruft die Funktion KillProcess() auf. Danach rufen Sie die Funktion ListProcesses auf, die sich um die Anzeige der laufenden Prozesse kümmert.

Hier also die Funktion ListProcesses (ebenfalls in stark gekürzter Version):

sub ListProcesses
for each Process in GetObject("winmgmts:{impersonationLevel=impersonate}").InstancesOf ("Win32_process")
Response.Write "Process.Caption & "-" & _
Process.ProcessID & "-" & _
Process.ExecutablePath & "-" & _
Process.WorkingSetSize & "-" & _
Process.ThreadCount & "-" & _
"<a href=taskmgr.asp?kill=" & Process.ProcessID & ">Beenden</a>" & "<br>"
next
end sub

Zunächst ermitteln Sie, wie aus dem einleitenden Beispiel bekannt, mit InstancesOf("Win32_process") die Liste aller Prozesse. Ein Prozess hat eine recht große Zahl an Eigenschaften, für den Task-Manager sind aber nur Prozess-ID, Name, Pfad, Speichernutzung und die Anzahl der Threads interessant. Diese Informationen werden einfach ausgegeben und dann mit einem Link auf die gleiche ASP-Datei ergänzt. Dieser Link wird an den Text "Beenden" gebunden und enthält für den Parameter Kill die Prozess-ID des zugehörigen Prozesses. Wenn Sie auf diesen Link klicken, wird die Seite erneut angefordert und im bereits erläuterten Codeteil dann KillProcess() aufgerufen.

Hier also die Funktion KillProcess:

function KillProcess( strProcessID)
dim Process
set Process = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery ("select * from Win32_Process where ProcessID='" & strProcessID & "'")
Process.Terminate
end function

Diese Funktion ermittelt über die Prozess-ID das zugehörige Prozessobjekt. Die Methode Terminate des Objekts beendet den Prozess ohne Rückfrage: Bevor Sie irgendetwas auf Ihrem Server beenden, sollten Sie sicherstellen, dass es sich dabei auch wirklich um den richtigen Prozess handelt. Tritt beim Beenden des Prozesses ein Fehler auf, wird eine entsprechende Meldung angezeigt, die den Grund für das Problem angibt.

Der Dienste-Manager mit ASP

Beim Dienste-Manager handelt es sich um ein ähnliches Programm wie beim Task-Manager, daher ist eine ausführliche Erläuterung nicht notwendig. Die wichtigsten Unterschiede sind:

Der Dienste-Manager zeigt keine Prozesse, sondern Dienste an, und daher müssen die zugehörigen Objekte anders erfragt werden. Dies geschieht ebenfalls mit InstancesOf,, jedoch mit den Instanzen vom Typ Win32_service.

Da es sich um Dienste handelt, haben diese auch andere Eigenschaften als Prozesse. Der Dienste-Manager zeigt die Startart des Dienstes sowie dessen aktuellen Zustand an. Dabei ist der Dienste-Manager nicht ganz vollständig, denn der Beispielcode geht davon aus, dass sich ein Dienst entweder im Zustand "laufend" oder im Zustand "angehalten" befindet. Das ist aber eigentlich nicht vollständig - wenn Sie das Programm für sich erweitern möchten, sollten Sie auch Zustände wie "wird gerade angehalten" oder "pausiert" berücksichtigen.

Ein Dienst wird nicht mit Terminate() angehalten, sondern mit der Methode stopService. Dementsprechend dient startService zum Starten eines Dienstes.

Die Anwendungsmöglichkeiten für WMI sind praktisch unbegrenzt: Zusammen mit ein bisschen ASP können Sie damit einfach Ihre ganz persönliche Server-Verwaltung zusammenstellen: Für das Administrieren sind die Beispielprogramme mit Sicherheit der erste Schritt ins webbasierte Admin-Leben. Natürlich sind Sie nicht auf ASP festgeschrieben: Sind die Scripts erst einmal erstellt, so ist es ein Leichtes, den ASP-Code in VBScript umzuwandeln - und damit haben Sie Webseiten, die Sie auch ohne einen IIS auf jedem Rechner ausführen können, um diesen lokal zu verwalten. (mha)