Beruflich Dokumente
Kultur Dokumente
Handbuch (Teil 1)
Anmerkung:
•Wenn Sie jetzt schon den Faden verloren haben - zum Beispiel, weil Sie sich nicht sicher
sind, was Scripting überhaupt sein soll - dann stellen Sie sich Scripte so vor:
•Stellen Sie manchmal fest, dass Sie immer dieselben Befehle für dieselben Aufgaben
verwenden? Erwischen Sie sich dabei, wie Sie oft auf die gleichen Schalter in den gleichen
Assistenten klicken, um einen Vorgang auf vielen Computern oder für viele Benutzer
durchzuführen?
•Scripte helfen Ihnen dabei, solche wiederholenden Arbeiten zu automatisieren. Ein Script ist
eine Datei, die die zur Durchführung einer Aufgabe notwendigen Schritte beschreibt.
Nachdem Sie das Script erstellt haben, können Sie es "ausführen" - es führt die Schritte dann
für Sie durch und spart Ihnen viel Zeit und Energie. Sie müssen das Script nur einmal
erstellen und können es dann so oft wie nötig benutzen.
Um dieses sieben Zeilen lange Script schreiben zu können, müssen Sie also über eine
ziemlich große Menge an Wissen verfügen. Kein Wunder, dass viele Leute denken, dass
Scripting schwer ist.
Die Wahrheit ist aber, um ein Script wie dieses schreiben zu können, müssen Sie COM und
Automatisation nicht vollständig verstehen. Nehmen Sie an, dass, was Sie wirklich möchten,
ist ein Script, dass die Namen aller im Moment auf einem Computer ausgeführten Prozesse
zurückgibt statt die Namen aller installierten Dienste. Ein solches Script sieht so aus:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & _
"{impersonationLevel=Impersonate}!\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Process")
For Each objItem in colItems
Wscript.Echo objItem.Name
Next
Was hat sich im Vergleich zum vorherigen Script geändert? Nichts - und genau darum geht
es. Schauen Sie genau hin - es gibt einen fett gedruckten Eintrag (Win32_Process). Das ist der
einzige Teil, der sich gegenüber dem vorherigen Script geändert hat. Haben Sie schon mehr
über COM-Monikers oder WMI-Objektpfade gelernt? Wahrscheinlich nicht. Sie können jetzt
aber dieses grundlegende Script nehmen und es so verändern, dass es die von Ihnen
gewünschten Informationen zurückgibt. Wie wäre es mit den installierten Grafikkarten?
Versuchen Sie dieses Script:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & _
"{impersonationLevel=Impersonate}!\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from
Win32_VideoController")
For Each objItem in colItems
Wscript.Echo objItem.Name
Next
Sind alle Scripte so einfach? Nein, leider nicht. Und in diesen Beispielen werden einige
Probleme einfach nicht beachtet (zum Beispiel "Woher weiß ich, dass es
Win32_VideoController und nicht Win32_VideoCard heißt?' oder 'Was ist, wenn ich mehr als
nur den Namen der Grafikkarte wissen möchte?'). Der Punkt ist nicht, dass Sie Scripte
schreiben können ohne irgendetwas zu wissen. Der Punkt ist, Sie können Scripte schreiben
ohne alles wissen zu müssen. Wenn Sie sich mit COM-Monikern und WMI-Objektpfaden
auskennen, bevor Sie Ihr erstes Script schreiben, dann ist das super. Wenn Sie es vorziehen,
sich einfach mit dem Schreiben von Scripten beschäftigen möchten - zum Beispiel indem Sie
auf den Beispielen dieses Buches aufbauen - dann ist das ebenso in Ordnung.
Systemanforderungen
Dieses Buch setzt Computer voraus, die unter einem der Microsoft® Windows® 2000-
Betriebssysteme oder höher ausgeführt werden. Zusätzlich zu Windows 2000 sollte die
Windows Script Host-Version 5.6 installiert werden. Diese wurde nach Windows 2000
veröffentlicht. Einige Scripte dieses Buches benötigen Features der Version 5.6. Weitere
Informationen zur Version 5.6 des WSH finden Sie im Kapitel DerWSH dieses Buches.
Anmerkung:
•Wenn Sie nicht die Version 5.6 des WSH installiert haben, finden Sie die Installationsdateien
unter http://www.microsoft.com/windows/reskits/webresources. Wenn Sie nicht sicher sind,
welche Version installiert ist, dann finden Sie weitere Informationen im Kapitel Der WSH.
Wenn Sie mit mehreren Betriebssystemen arbeiten - zum Beispiel Windows 2000 und
Windows XP - sollten Sie außerdem Windows 2000 Service Pack 2 installieren. Ohne dieses
Server Pack könnten Scripte unter Windows 2000 keine Informationen von Windows XP-
Computern abfragen.
Außerdem ist es für die meisten der Scripte erforderlich, dass Sie mit administrativen Rechten
angemeldet sind - zum Beispiel für die meisten WMI- und ADSI-Scripte. Wenn Sie mit einem
Script einen Remotecomputer abfragen möchten, dann benötigen Sie auch auf diesem
administrative Rechte.
Außer diesen Voraussetzungen benötigen Sie keine phantasievollen Scripting-Tools, Editoren
oder Entwicklungsumgebungen (IDE - Integrated Development Environment). Wenn Sie
Notepad installiert haben, dann reicht dies schon aus, um Scripte zu schreiben.
Übersicht zu VBScript
Microsoft® Visual Basic® Scripting Edition (VBScript) wird oftmals als "bloße"
Scriptsprache missverstanden. Dies impliziert, dass eine Scriptsprache Systemadministratoren
bei der Verwaltung von Hunderten oder Tausenden von Computern wenig nützt. Die Realität
sieht jedoch ganz anders aus. In Kombination mit weiteren Technologien - zum Beispiel
Windows Script Host (WSH), Windows Management Instrumentation (WMI) und Active
Directory Service Interfaces (ASDI) - wird VBScript zu einer mächtigen Sprache zur
Erstellung von Werkzeugen zur Systemadministration. Mit VBScript, WMI und ADSI
können Sie ein Script von ca. 10.000 Zeilen schreiben, mit dem Sie einen Großteil eines
Computers verwalten können.
Was VBScript aber wirklich nützlich macht, ist die Möglichkeit ein Script in wenigen
Minuten zu schreiben statt eine komplizierte und umfangreiche Lösung zu entwickeln.
Das dreizeilige Script 2.1 zeigt Ihnen zum Beispiel, wie viel freier Platz noch unter Laufwerk
C vorhanden ist.
Script 2.1: Abfragen des freien Speicherplatzes unter einem Laufwerk über VBScript
Methoden aufrufen
Sie können die Funktionalitäten von Automatisationsobjekten in Ihren eigenen Scripten
verwenden. So sind Sie in der Lage, viel mächtigere Scripte zu schreiben, als wenn Sie nur
auf die Funktionalität einer Scriptsprache eingeschränkt wären. Es ist zum Beispiel mit
VBScript nicht möglich, ein Diagramm zu erstellen. Über die Automatisation können Sie sich
eine solche Fähigkeit jedoch von Microsoft Excel ausleihen.
Automatisationsobjekte stellen normalerweise sowohl Methoden als auch Attribute zur
Verfügung (das muss jedoch nicht immer so sein). Über Methoden können die möglichen
Aktionen eines Objektes durchgeführt werden. Script 2.2 verwendet zum Beispiel die
Automatisation, um auf die Methoden von zwei unterschiedlichen COM-Objekten
zuzugreifen - so führt es zwei unterschiedlichen Aktionen aus. Diese zwei Methoden sind:
•
Die Methode Get - sie steht über das WMI-Objekt SWbemServices zur Verfügung. Diese
Methode ruft Informationen über ein bestimmtes Objekt ab.
•
Die Methode Echo - sie steht über das WSH-Objekt zur Verfügung. Diese Methode zeigt
Informationen auf dem Monitor an. Wenn ein Script in einer Eingabeaufforderung ausgeführt
wird (wenn es also mit CScript.exe ausgeführt wird), dann werden diese Informationen in der
Eingabeaufforderung ausgegeben. Wenn das Script mit Wscript.exe ausgeführt wird, dann
werden die Informationen in einem eigenen Nachrichtenfenster ausgegeben.
Anmerkung:
•
Statt Wscript.Echo kann zur Anzeige von Informationen auch die VBScript-Funktion
Msgbox verwendet werden:
•
Msgbox objLogicalDisk.FreeSpace
•
In diesem Buch wird jedoch immer Wscript.Echo statt Msgbox verwendet. Dies liegt daran,
dass die Funktion Msgbox die Informationen immer als grafisches Nachrichtenfenster
ausgibt. In diesem Nachrichtenfenster muss der Benutzer immer auf den Schalter OK
klicken, bevor das Script weiter ausgeführt wird. Bei Scripten zur Systemadministration, die
möglicherweise eine große Menge an Informationen anzeigen, könnte dieses Verfahren recht
mühsam werden - außerdem könnte das Script nicht automatisch ausgeführt werden. Im
Gegensatz dazu zeigt Wscript.Echo die Informationen zeilenweise in der
Eingabeaufforderung an (vorausgesetzt, das Script wird unter CScript ausgeführt).
Attribute Abfragen
Die Attribute eines Objektes sind für administrative Scripte sehr wichtig, denn viele Objekte
stellen tatsächliche Objekte dar. In Zeile 3 von Script 2.2 wird zum Beispiel das Attribut
FreeSpace abgefragt - und zwar über dieselbe Punkt-Notation, wie beim Aufrufen von
Methoden.
objLogicalDisk.FreeSpace
Variablen
Script 2.2 funktioniert exakt so wie erwartet. Wenn es ausgeführt wird, dann zeigt es den
freien Speicherplatz von Laufwerk C an. Das heißt jedoch nicht, dass das Script nicht noch
verbessert werden kann. Das Attribut FreeSpace gibt den freien Speicherplatz zum Beispiel in
Byte zurück. Da Festplattenplatz jedoch typischerweise in Gigabyte angegeben wird, ist die
Ausgabe oft schwer zu interpretieren. In Abbildung 2.1 sehen Sie ein Beispiel zur Ausgabe
des Scripts, bei dem noch ca. 2,88 GB freier Speicherplatz zur Verfügung steht.
Konstanten
Seite 23 von 394
In Script 2.3 wird die MB-Zahl durch die Division des Attributes FreeSpace durch den
hardcodierten Wert 1048576 errechnet. "Hardcodierter"-Wert bedeutet, dass der Wert direkt
im Script enthalten ist (und nicht zum Beispiel dynamisch berechnet wird). Hardcodierte-
Werte werden oft auch als Literale bezeichnet, da Sie nichts anderes als diesen Wert
repräsentieren.
In einem kleinen Script wie diesem sind hardcodierte Literale kein Problem. In einem großen
Script kann es jedoch zu zwei Problemen kommen:
Zum einen mag es in einem kleinen Script klar sein, dass 1048576 der Wert ist, der zur
Konvertierung von Byte in MB verwendet wird. In einem größeren Script - zum Beispiel in
einem, das viele nicht ganz so eindeutige Berechnungen verwendet - könnte dies weniger klar
ersichtlich sein. Und zwar ganz besonders, wenn das Script von mehreren Administratoren
verwendet und verändert wird. Sie wissen vielleicht, wofür die Zahl 1048576 steht, aber ein
anderer Administrator weiß das möglicherweise nicht.
Wenn ein Script oft geändert werden muss, dann führt dies zu einem zweiten Problem.
Literal-Werte können dazu führen, dass eine Änderung mehr Aufwand erfordert. Nehmen wir
an, unser Scriptcode zur Konvertierung von Byte in MB wird an fünf oder sechs
unterschiedlichen Stellen im Script verwendet. Wenn Sie sich nun später dazu entscheiden
eine Konvertierung in GB statt in MB durchzuführen, dann müssen Sie alle fünf oder sechs
Stellen im Script ändern.
Ein Weg, um solche Probleme zu umgehen, sind Konstanten. Konstanten speichern ebenso
wie Variablen Daten. Im Gegensatz zu Variablen kann eine Konstante jedoch nach ihrer
Definition (also nachdem ein Wert zur Konstante zugewiesen wurde) nicht mehr verändert
werden. So wird vermieden, dass der Wert der Konstante zum Beispiel versehentlich
verändert wird.
In 2.5 wird in Zeile 1 eine Konstante mit dem Namen CONVERSION_FACTOR definiert.
Ihr wird der Wert 1048576 zugewiesen. Später in Zeile 4 wird die Bytezahl in MB
konvertiert. Statt des Literalwertes 1048576 wird jedoch die Konstante
CONVERSION_FACTOR verwendet. Das Ergebnis ist das gleiche wie vorher. Script 2.5 ist
jedoch viel einfacher zu lesen und zu verstehen.
Zeichenketten
Collections (Sammlungen)
Bis zu diesem Punkt haben die Scripte nur den freien Festplattenplatz von Laufwerk C auf
einem Computer abgefragt. Hierzu wurde das Attribut DeviceID (eine Eigenschaft von der
Klasse Win32_LogicalDisk) im Script hardcodiert.
Seite 28 von 394
Einige Computer, zum Beispiel Server, verfügen jedoch über mehrere Laufwerke. In einem
solchen Fall gibt Ihnen das Script nur einen Teil der benötigten Informationen zurück, da Sie
möglicherweise den freien Speicherplatz für alle Laufwerke abfragen möchten.
Hierbei gibt es jedoch ein Problem: Wie viele Laufwerke sind auf dem abgefragten Computer
installiert? Theoretisch könnten Sie versuchen, den freien Speicherplatz aller Laufwerke von
C bis Z abzufragen. Wenn der Computer aber zum Beispiel kein Laufwerk E verwendet, dann
wird das Script fehlschlagen. Auch wenn Sie einen solchen Fehler über eine
Fehlerbehandlung abfangen könnten, wäre das Script lang und schwer zu lesen und zu
pflegen. Ein solches Script wäre außerdem extrem ineffizient; denn auch wenn ein Computer
nur über ein einzelnes Laufwerk verfügt, würde es trotzdem versuchen, alle Laufwerke von C
bis Z abzufragen.
Glücklicherweise geben Automatisationsobjekte Informationen oftmals in Form von
Collections (Sammlungen) zurück. Wie Briefmarken- oder Münzsammlungen sind
Automatisationssammlungen einfach eine Gruppe von Objekten. Script 2.8 verwendet zum
Beispiel die WMI-Methode InstancesOf (Zeile 4), um nicht nur ein einzelnes Laufwerk
zurückzugeben, sondern eine Sammlung von allen auf dem Computer installierten
Laufwerken. Wenn der Computer über vier Laufwerke verfügt (C, D, E und F), dann enthält
die Collection vier Einträge - einen für jedes Laufwerk.
For Each
Der Ausdruck For Each bietet Ihnen einen einfachen Weg, alle Objekte in einer Collection
durchzugehen. Im Gegensatz zum Ausdruck For Next, der später besprochen wird, müssen
Sie für For Each nicht wissen, wie viele Elemente in der Collection enthalten sind. Stattdessen
beginnt For Each einfach mit dem ersten Element der Collection und geht diese durch, bis das
letzte Element erreicht ist.
Eine typische For-Each-Schleife sieht so aus:
For Each objLogicalDisk In colLogicalDisk
Wscript.Echo objLogicalDisk.DeviceID
Next
Die einzelnen Teile einer solchen Schleife werden in Tabelle 2.2 beschrieben.
Tipp: Es gibt keinen einfachen Weg, nicht die gesamte Collection durchgehen zu müssen. Sie
können Ihre Scripte allerdings effizienter machen, indem Sie die Menge von Elementen in
einer Collection einschränken. Ihre WMI-Abfrage könnte zum Beispiel nur die Instanzen der
Klasse Win32_DiskDrive zurückgeben, bei denen der Laufwerksbuchstabe G ist. In diesem
Fall enthält die Collection nur ein Element. Somit wird das Durchgehen der Collection
schneller und effizienter.
Schleifen
Scripte, die Systemressourcen überwachen, müssen typischerweise in bestimmten Intervallen
Daten sammeln. Den freien Festplattenplatz möchten Sie zum Beispiel sicher in regelmäßigen
Intervallen überwachen - zum Beispiel einmal pro Woche, einmal pro Tag oder einmal pro
Stunde.
Wenn der Zeitraum zwischen den Datensammlungen relativ groß ist, können Sie das Script
als geplanten Task ausführen.
Wenn Sie aber zum Beispiel alle 10 Sekunden die Prozessorauslastung messen möchten, und
zwar so lange, bis Sie 500 Messungen vorgenommen haben, dann möchten Sie wohl kaum
500 Tasks planen. Stattdessen führen Sie ein einzelnes Script aus, das die 500 Messungen für
Sie vornimmt.
For Next
Ein Weg, um ein Script die gleichen Aktionen mehrmals durchführen zu lassen, ist es die
Aktionen (Befehl) in eine For-Next-Schleife einzuschließen.
Anmerkung:
•
Sie können auch einen beliebigen anderen Startpunkt auswählen (zum Beispiel 314 oder
6912 statt 1). Ihr Script wird jedoch besser lesbar und wartbar sein, wenn Sie mit 1 beginnen.
Die For-Next-Schleife benötigt eine Schleifenvariable (auch Zähler genannt). Dieser Zähler
speichert, wie oft die Schleife bereits durchlaufen wurde. Im folgenden Beispiel wird zum
Beispiel die Variable i als Zähler verwendet. Der Zähler beginnt bei 1 und führt den
Codeblock in der For Next-Schleife aus. Nachdem alle Befehle in der Schleife ausgeführt
wurden, wird der Zähler automatisch um Eins erhöht. Das bedeutet, dass i nun den Wert 2 hat.
Das Script springt nun zurück zum Anfang der Schleife und prüft, ob der Wert 2 noch
unterhalb der gewünschten Schleifenzahl ist. Da er das ist, wird der Code in der Schleife ein
weiteres Mal ausgeführt. Der Zähler wird wieder um Eins auf 3 erhöht, usw.
For i = 1 to 5
Wscript.Echo i
Next
Entscheidungen treffen
Einer der primären Gründe für den Einsatz von Scripten in der Systemadministration ist, dass
sie die Notwendigkeit für einen Eingriff durch die Administratoren verringern sollen. Das bis
jetzt entwickelte Script kann zwar schon eine ganze Menge, aber der Systemadministrator
muss noch immer die Ausgabe des Scripts interpretieren. Er muss weiterhin selbst
entscheiden, ob der Plattenplatz zu gering wird oder nicht. Das Script kann jedoch so
verbessert werden, dass es nur dann eine Benachrichtigung ausgibt, wenn der Plattenplatz
unter eine bestimmte Grenze fällt. Mit einem solchen Ansatz werden die Administratoren
benachrichtigt, wenn der Plattenplatz zur Neige geht. Wenn sie keine Benachrichtigungen
erhalten, dann ist alles in Ordnung.
VBScript bietet Ihnen einige Programmierkonstrukte, die es Scripten ermöglichen
"Entscheidungen zu treffen". Das Script kann bestimmte Daten analysieren und dann auf
Basis dieser Daten eine bestimmte Aktion durchführen.
Die einfachste Form eine Entscheidung ist das If-Then-Statement. Es vergleicht einen
bestimmten Wert mit einen anderen Wert (zum Beispiel, ob der freie Speicherplatz kleiner als
100 MB ist). Wenn der Vergleich wahr ist (zum Beispiel, wenn nur noch 99 MB freier Platz
zur Verfügung steht), dann führt das Script eine bestimmte Aktion durch. Wenn der Vergleich
nicht wahr ist, dann passiert nichts.
Script 2.10 ist ein Beispiel für einen solchen Vorgang. In Zeile 8 prüft das Script ob der freie
Speicherplatz kleiner als 100 MB ist (indem es den Wert mit der Konstante
WARNING_THRESHOLD vergleicht). Wenn diese Bedingung wahr ist, dann wird der
Befehl hinter dem If-Then-Statement ausgeführt. Diesen finden Sie in Zeile 9. Er gibt eine
Nachricht aus.
Wenn die Bedingung falsch ist, dann wird Zeile 9 nicht ausgeführt. Stattdessen wird mit Zeile
10, dem Ende des If-Then-Blocks, weitergemacht.
Eingabe
Script 2.12 wurde für eine Organisation entwickelt, in der sich die Computer-Infrastruktur
wahrscheinlich nicht ändern wird. Es muss wohl kaum erwähnt werden, dass eine solche
statische Infrastruktur eher die Ausnahmen als die Regel darstellt. In den meisten
Organisationen gibt es eine viel dynamischere Umgebung. Auch wenn heute nur drei Server
überwacht werden müssen (atl-dc-01, atl-dc-02, atl-dc-03), so gibt es doch keine Garantie
dafür, dass sich dies nicht in Zukunft ändert.
Aus diesem Grund möchten wir die Computernamen nicht fest in das Script integrieren
(hardcodieren). Eine solche Vorgehensweise führt oft zu Problemen:
•
Fehlende Flexibilität - Script 2.12 fragt nur die Computer atl-dc-01, atl-dc-02 und atl-dc-03
ab. Wenn Sie den freien Plattenplatz von Computer atl-dc-04 abfragen möchten, dann
cscript FreeDiskSpace.vbs
Argumente sind alle Informationen, die Sie noch an diesen Befehl anhängen. Ein Befehl mit
drei Argumenten (ein Computername ist jeweils ein Argument) sieht zum Beispiel so aus:
Fehlerbehandlung
Script 2.13 enthält einen potentiellen Fehler. Nehmen wird einmal an, der Benutzer gibt einen
ungültigen Computernamen als Argument an. Wenn das Script dann versucht eine
Verbindung mit diesem Computer aufzubauen, wird dies mit der Fehlermeldung "Der
Remoteservercomputer existiert nicht oder ist nicht verfügbar: ,GetObjekt'" abgebrochen.
Solche Fehler sind natürlich in allen bis jetzt in diesem Kapitel vorgestellten Scripten möglich
- auch wenn die Computernamen fest eingetragen (hardcodiert) wurden. Schließlich kann ein
Script nicht zwischen einem ungültigen Computernamen und einem gültigen
Computernamen, der nur im Moment nicht über das Netzwerk erreichbar ist, unterscheiden.
Stellen Sie sich zum Beispiel vor, Computer atl-dc-01 aus Script 2.12 ist im Moment nicht
erreichbar. In diesem Fall wird das Script bei der Abfrage dieses Computers mit einer
Fehlermeldung abbrechen. Leider werden auch die beiden anderen Computer nicht mehr
abgefragt - selbst wenn diese einwandfrei zu erreichen sind (das Script wird ja schon beim
ersten Computer wegen des Fehlers beendet).
Das beschriebene Verhalten ist ein gutes Beispiel für einen Laufzeitfehler - ein Fehler, der
erst nach dem Start des Scripts auftritt (im Gegensatz zu einem Syntaxfehler - zum Beispiel
einem falsch geschriebenen Befehl, der bereits vor der Ausführung der ersten Scriptzeile
auftritt). Um sich vor solchen Laufzeitfehlern zu schützen, können Sie den VBScript-Befehl
zur Fehlerbehandlung On Error Resume Next in Ihren Scripten verwenden.
Ohne eine Fehlerbehandlung wird das Script bei einem Laufzeitfehler sofort angehalten. Mit
Fehlerbehandlung wird das Script nicht angehalten. Stattdessen wird versucht, einfach die
nächste Zeile des Scripts auszuführen. Die Scriptzeile, die den Fehler generiert hat, wird
einfach ignoriert.
Das Err-Objekt
Der Befehl On Error Resume Next bewirkt, dass das Script nach einem Laufzeitfehler weiter
ausgeführt wird. Hierbei gibt es jedoch mindestens zwei potentielle Probleme. Ersten wird
keine Fehlermeldung angezeigt. Sie merken also nicht, dass ein Fehler aufgetreten ist und
können nicht feststellen, ob das Script fehlgeschlagen ist.
Und zweitens könnte es ja sein, dass Sie nicht möchten, dass das Script nach einem Fehler
weiter ausgeführt wird. Stellen Sie sich folgende Script-Funktionalität vor, die den Befehl On
Error Resume Next verwendet:
Wscript.Echo Err.Description
Number Ein Integer-Wert (Ganzzahl), der den aufgetretenen Fehler eindeutig identifiziert.
Es kann sich um eine VBScript-Fehlernummer oder um die Fehlernummer eines
Automatisationsobjektes handeln. Die Herkunft der Fehlernummer können Sie
über das Attribut Source feststellen.
Source Klassenname oder ProgID (Programmatic Identifier) des Objektes, das den Fehler
verursacht hat. Wenn VBScript den Fehler verursacht hat, dann enthält das
Attribut den Wert 'Laufzeitfehler in Microsoft VBScript'. Wenn ein
Automatisationsobjekt den Fehler verursacht hat, dann finden Sie hier die ProgID
dieses Objektes (zum Beispiel 'Word.Application').
Wenn ein Script gestartet wird, dann weist VBScript dem Attribut Number den Standardwert
0 zu. Wenn ein Fehler auftritt, dann wir dem Attribut sofort die Fehlernummer zugewiesen.
Wenn Sie also den Wert des Attributes Number regelmäßig abfragen, dann können Sie
feststellen, ob ein Fehler aufgetreten ist. Sie können Ihr Script zum Beispiel so gestalten, dass
es nach einem Verbindungsversuch mit einem Remotecomputer den Fehlerstatus im Attribut
Number prüft. Wenn Err.Number nicht mit 0 ist, dann ist irgendein Fehler aufgetreten - und
Seite 39 von 394
Sie können davon ausgehen, dass der Verbindungsversuch mit dem Remotecomputer
fehlgeschlagen ist. Ihr Script kann dann hierauf reagieren.
Script 2.14 implementiert eine solche Fehlerbehandlung. In Zeile 1 wird die
Fehlerbehandlung erst einmal durch On Error Resume Next aktiviert. In Zeile 10 wird eine
For-Each-Schleife verwendet, um die Servernamen durchzugehen. In Zeile 11 versucht das
Script jeweils eine Verbindung mit dem Server aufzubauen.
Was passiert nun, wenn einer der Server nicht erreichbar ist? In Zeile 11 versucht das Script
auf den Server zuzugreifen. Wenn die Verbindung erfolgreich war, dann wird kein Fehler
generiert. In diesem Fall steht in Err.Number noch immer der Wert 0. Wenn der
Verbindungsversuch jedoch fehlschlägt, dann wird ein Fehler generiert. In Err.Number steht
dann eine Fehlernummer.
In einem solchen Fall steht der Befehl On Error Resume Next sicher, dass das Script in der
nächsten Zeile weiter ausgeführt wird. In Zeile 12 prüft das Script den Wert in Err.Number.
Wenn dieser Wert nicht 0 ist (wenn also ein Fehler aufgetreten ist), dann gibt das Script den
Wert in Err.Description aus. Danach geht es mit einem neuen Schleifendurchlauf normal
weiter. Wenn der Wert in Err.Number jedoch 0 ist, dann bedeutet das, dass die Verbindung
erfolgreich war. In diesem Fall fragt das Script den verfügbaren Plattenplatz ab und startet
dann ganz normal einen weiteren Schleifendurchlauf mit dem nächsten Servernamen.
Fehler löschen
Script 2.14 verwendet in Zeile 14 die Methode Clear, um die Attribute des Err-Objektes
explizit zurückzusetzen. Dies ist wichtig, da sich diese Attribute ansonsten nur dann ändern
würden, wenn ein anderer Fehler auftritt. Wenn kein Fehler auftritt, dann würden die Werte
der Attribute gleich bleiben. Das Script würde also bei jedem Durchlauf einen Fehler
erkennen - auch dann, wenn gar kein Fehler aufgetreten ist (der Wert des Attributes
Err.Number ist ja nicht 0).
Mit der Methode Clear umgehen Sie dieses Problem, indem Sie alle Attribute des Err-
Objektes auf die Standardwertezurücksetzen (Number ist 0, Source und Description sind leer).
VBScript-Referenz
Die erste Hälfte dieses Kapitels hat Sie mit den grundlegenden Konzepten hinter VBScript
vertraut gemacht. Sie haben einen ersten Einblick darin erhalten, welche Aufgaben Sie mit
VBScript durchführen können - besonders im Hinblick auf die Verwendung von ADSI und
WMI. Die zweite Hälfte dieses Kapitels ist mehr als Standardreferenz gedacht. Es
konzentriert sich auf die Methoden und Funktionen von VBScript, die für
Systemadministratoren am nützlichsten sind. Es handelt sich nicht um eine umfassende
Übersicht aller Dinge, die Sie mit VBScript machen können. Wenn Sie so eine Auflistung
benötigen, so finden Sie diese im MSDN unter
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/script56/html/vtoriVBScript.asp?frame=true (englischsprachig). Die folgenden Abschnitte
besprechen nur eine Untermenge aller VBSCript-Funktionen und -Methoden. Diese werden in
einem Kontext verwendet, der Sie bei der Entwicklung von Scripten zur
Systemadministration unterstützen soll.
Zeilenumbrüche in VBScript
Viele Script- und Programmiersprachen interessieren sich nicht dafür, ob der Code in eine
physikalische Zeile oder in viele Zeilen geschrieben wurde. Das folgende Microsoft®
JScript®- Codebeispiel umfasst beispielsweise zwar neun Zeilen - JScript behandelt es aber
trotzdem wie eine einzige Zeile (und damit auch wie einen einzigen Befehl). Das liegt daran,
dass JScript ein Zeilenende an einem bestimmten Zeichen erkennt (dem Semikolon). Die
tatsächlichen Zeilen (also die Zeilenumbrüche) sind für JScript vollkommen irrelevant.
var
objWMI
=
new
Enumerator
(GetObject("winmgmts:")
.
InstancesOf("Win32_process"))
;
Ein Ähnliches Stück Code in VBScript wird dagegen zu einem Syntax-Error führen:
Set
Option Explicit
Dim intFirstNumber ' First number in our simple equation
Dim intSecondNumber ' Second number in our simple equation
Dim intTotal ' Sum of intFirstNumber and intSecondNumber
Wenn Sie das Script mit Wscript ausführen, dann sehen Sie ein Nachrichtenfenster, das wie
in Abbildung 2.11 aussieht.
Wscript.Echo ' 1' & VbTab & ' 2' & VbTab & ' 3'
Wscript.Echo 'A' & VbTab & 'B' & VbTab & 'C'
Wscript.Echo 'D' & VbTab & 'E' & VbTab & 'F'
Wenn Sie das Script mit Cscript ausführen, dann sieht seine Ausgabe in der
Eingabeaufforderung so aus:
123
ABC
DEF
Scripte, die in VBScript geschrieben werden, können auch nur auf die vordefinierten
Konstanten von VBScript zugreifen. Sie haben keinen Zugriff auf die vordefinierten
Konstanten von WMI, ADSI, der Script-Laufzeitbibliothek oder externen
Automatisationsobjekten. Alle VBSCript-Konstanten (zum Beispiel VbCrLf oder VbYesNo)
können Sie nutzen, ohne diese vorher definieren zu müssen. Wenn Sie jedoch WMI- oder
ADSI-Konstanten nutzen möchten, dann müssen Sie diese vorher selbst definieren.
Das Objekt Drive aus der Script-Laufzeitbibliothek verfügt zum Beispiel über die Konstante
mit dem Namen Fixed. Da VBScript jedoch auf die Konstanten dieses
Automatisationsobjektes keinen Zugriff hat, müssen Sie die Konstante Fixed selbst mit einem
entsprechenden Wert definieren.
Wenn Sie die Konstante nicht vorher definieren, dann wird das Script einen Fehler
produzieren oder fehlerhaft arbeiten. Wenn Sie zum Beispiel versuchen das folgende Script
auszuführen, dann wird es alles Mögliche machen. Es wird jedoch nicht die reparierten
Laufwerke abfragen:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set colDiskDrives = objFSO.Drives
For Each objDiskDrive in colDiskDrives
If objDiskDrive.DriveType = Fixed then
Typumwandlung
Scriptsprachen scheinen nur für den Entwickler typlos zu sein. Intern müssen auch
Scriptsprachen mit Datentypen arbeiten. Wenn sie auf einen einfachen Ausdruck wie x = a +
b trifft, dann muss die Scriptsprache aus diesem Ausdruck zum Beispiel die Datentypen von a
und b herleiten. Mit anderen Worten: Die Scriptsprache muss die beiden Werte vom Typ
Variant nehmen und Werte vom Typ Integer (Ganzzahl) oder String (Zeichenkette) aus ihnen
machen. Nachdem die Datentypen hergeleitet wurden, kann die Rechenoperation
durchgeführt werden.
Da der Wert von Typ Variant temporär in einen neuen Datentyp umgewandelt wird, wird
diese Herleitung der Datentypen Typumwandlung genannt. Die Typumwandlung basiert auf
bestimmen Regeln. Sie funktioniert in den allermeisten Fällen automatisch und problemlos.
Die Typumwandlung kann jedoch auch zu Problemen führen. Das folgende Script ist ein
Beispiel hierfür:
intFirstNumber = InputBox("Erste Zahl eingeben:")
intSecondNumber = InputBox("Zweite Zahl eingeben:")
Anmerkung: Die unter VBScript verwendeten Datums- und Zeitformate unterscheiden sich
deutlich von denen, die in WMI verwendet werden. Mehr zu den Formaten in WMI erfahren
Sie im Kapitel WM- Scripting in diesem Buch.
#9/3/2002#
•
Datum- und Zeitformate, wie sie durch Ihre Systemeinstellungen festgelegt sind - Wenn
Ihre Systemeinstellungen beispielsweise auf Deutsch festgelegt sind, dann können Sie für das
Datum 6. Januar 2002 zum Beispiel die folgenden Schreibweisen verwenden:
•
6/1/2002
•
6,1,2002
•
6-1-2002
•
6.1.2002
•
Bei der Einstellung English (USA) ist hingegen die letzte Schreibweise ungültig. Außerdem
wären die Werte von Tag und Monat vertauscht. Der 6. Januar 2002 würde zum Beispiel so
dargestellt. 1/6/2002
Anmerkung: Um die auf Ihrem Computer eingestellten Formate zu prüfen, öffnen Sie die
Regions- und Sprachoptionen in der Systemsteuerung. Dort klicken Sie dann auf
Anpassen und wählen die Registerkarte Datum oder Uhrzeit.
Das folgende Script erstellt einen Array mit Werten und geht den Array dann durch. Es
verwendet die Funktion IsDate,um festzustellen, ob es sich bei den Werten des Arrays um
Daten handelt. Die Rückgabe der Funktion wird dem Benutzer angezeigt.
DateArray = Array("6/1/2002", "Juni 1, 2002", "6", "6/1")
For Each dtmDate in DateArray
If IsDate(dtmDate) = 0 Then
Wscript.Echo dtmDate & " ist kein gültiges Datum."
Else
Wscript.Echo dtmDate & " ist ein gültiges Datum."
End If
Next
Wenn Sie das Script mit CScript ausführen, erhalten Sie folgende Ausgabe:
6/1/2002 ist ein gültiges Datum.
Juni 1, 2002 ist ein gültiges Datum.
6 ist kein gültiges Datum.
6/1 ist ein gültiges Datum.
Anmerkung: Warum ist 6/1 ein gültiges Datum? Die Funktion IsDate versucht aus dem
übergebenen Wert ein gültiges Datum zu konstruieren. Der Wert 6/1 kann als Tag/Monat
interpretiert werden. Daher hängt IsDate einfach das aktuelle Jahr an und kommt zum
Ergebnis Tag/Monat/Jahr.
1 - Januar
2 - Februar
3 - März
4 - April
5 - Mai
6 - Juni
7 - Juli
8 - August
9 - September
10 - Oktober
11 - November
12 - Dezember
y Tag des Jahres - hierbei steht 1 für den 1. Januar und 365 für den 31. Dezember
(bei Schaltjahren 366). Der 1. Februar wäre zum Beispiel der Wert 32, da er der
zweiunddreißigste Tag des Jahres ist.
d Tag - gibt den Tag des Monats zurück. Für den 17. April würden Sie zum Beispiel
1 - Sonntag
2 - Montag
3 - Dienstag
4 - Mittwoch
5 - Donnerstag
6 - Freitag
7 - Samstag
Wenn Sie möchten, könnten Sie angeben, dass die Woche mit einem anderen Tag
als Sonntag beginnt. Weitere Informationen hierzu finden Sie weiter unten in
diesem Kapitel.
ww Woche des Jahres - hierbei steht 1 für die erste Woche im Januar und 52 für die
letzte Woche im Dezember. Auch hier können Sie die erste Woche des Jahres nach
Ihrem Wünschen festlegen.
h Stunde - Gibt die Stunde im 24-Stunden-Format zurück. Für den Zeitraum
zwischen 00:00 Uhr und 01:00 Uhr wird der Wert 0 zurückgegeben.
n Minute
s Sekunde
Den von der Funktion DatePart zurückgegebenen Wert können Sie zum Beispiel einer
Variablen zuweisen. Die folgende Codezeile extrahiert zum Beispiel das Jahr aus dem
aktuellen Datum und weist dieses der Variable CurrentYear zu:
CurrentYear = DatePart("yyyy", Date)
In diesem Beispiel werden die folgenden Parameter verwendet:
•
'yyyy" - gibt an, dass das Jahr aus dem Datum extrahiert werden soll. Dieser Parameter muss
immer in Anführungszeichen eingeschlossen werden.
•
Date - gibt das Datum an, aus dem der angegebene Teil extrahiert werden soll. In diesem
Fall wird für diesen Parameter die Funktion Date angegeben, die das aktuelle Datum
zurückgibt. Sie können natürlich auch ein tatsächliches Datum angeben. Denken Sie daran,
dass solche Datumswerte in Doppelkreuze eingeschlossen werden müssen (zum Beispiel
'6/1/2002'). Die folgenden beiden Codezeilen geben zum Beispiel das Jahr 1977 zurück:
DateToCheck = #8/15/1977#
CurrentYear = DatePart('yyyy' , DateToCheck)
1 Wscript.Echo Now
2 Wscript.Echo "Jahr: " & DatePart("yyyy" , Now)
3 Wscript.Echo "Quartal: " & DatePart("q", Now)
4 Wscript.Echo "Monat: " & DatePart("m" , Now)
5 Wscript.Echo "Tag des Jahres: " & DatePart("y" , Now)
6 Wscript.Echo "Tag: " & DatePart("d" , Now)
7 Wscript.Echo "Wochentag: " & DatePart("w" , Now)
8 Wscript.Echo "Woche des Jahrs: " & DatePart("ww" , Now)
9 Wscript.Echo "Stunde: " & DatePart("h", Now)
10Wscript.Echo "Minute: " & DatePart("n" , Now)
11Wscript.Echo "Sekunde: " & DatePart("s" , Now)
Wenn das Script am 14. März 2004 um 20:45:20 ausgeführt wird, dann produziert es folgende
Ausgabe:
14.03.2004 20:45:20
Jahr: 2004
Quartal: 1
Monat: 3
Tag des Jahres: 74
Tag: 14
Wochentag: 1
Woche des Jahrs: 12
Stunde: 20
Minute: 45
Sekunde: 20
Wenn Sie für die Funktion DatePart unvollständige Parameter verwenden, wird keine
Fehlermeldung ausgegeben. Es könnte jedoch sein, dass Sie nicht das erwartete Resultat
erhalten. Die folgende Codezeile gibt zum Beispiel den Wert 1899 zurück:
Wscript.Echo DatePart("yyyy", "8:00")
Diese Codezeile gibt den Wert 0 zurück:
Wscript.Echo DatePart("h", "12/1/2002")
Optionen von DatePart
Standardmäßig ist unter VBScript die erste Woche des Jahres die Woche mit dem 1. Januar.
Sie können dieses Verhalten jedoch mit den in der folgenden Tabelle gezeigten Werten
ändern.
Tabelle 2.8: Parameter für die Einstellung "Erste Woche des Jahres"
Konstante WertBeschreibung
vbUseSystem 0 Verwendet die National Language Support API, um die erste Woche
des Jahres auf Basis der Regional- und Spracheinstellungen
festzulegen.
1 - Sonntag
2 - Montag
3 - Dienstag
4 - Mittwoch
5 - Donnerstag
6 - Freitag
7 - Samstag
Year Gibt das Jahr zurück.
Um diese Funktionen zu verwenden, reicht es, sie einfach mit dem Datum- oder Zeitwert als
Parameter aufzurufen. Das folgende Script führt dies zum Beispiel mit dem aktuellen Datum
und der Uhrzeit durch:
CurrentDate = Now
Wscript.Echo "Jahr: " & VbTab & VbTab & Year(CurrentDate)
Wscript.Echo "Monat: " & VbTab & VbTab & Month(CurrentDate)
Wscript.Echo "Tag: " & VbTab & VbTab & Day(CurrentDate)
Wscript.Echo "Wochentag: " & VbTab & Weekday(CurrentDate)
Wscript.Echo "Stunde: " & VbTab & VbTab & Hour(CurrentDate)
Wscript.Echo "Minute: " & VbTab & Minute(CurrentDate)
Wscript.Echo "Sekunde: " & VbTab & Second(CurrentDate)
Wenn Sie das Script über CScript ausführen, erhalten Sie zum Beispiel folgende Ausgabe:
Jahr: 2004
Monat: 3
Tag: 14
Wochentag: 1
Stunde: 21
Minute: 17
Sekunde: 37
In der Systemadministration ist das Berechnen von Zeiträumen genauso wichtig wie das
Feststellen von Daten - zum Beispiel wenn Sie wissen möchten, welcher Tag in 180 Tagen
von heute an ist, oder wenn Sie wissen möchten, wie lange ein Dienst zwischen Start und
Ende ausgeführt wurde.
Anmerkung: Abhängig von den verwendeten Daten könnte es auch sein, dass Sie eine
negative Zahl erhalten. Dies passiert, wenn das Startdatum hinter dem Enddatum liegt. Wenn
Sie keinen negativen Wert erhalten möchten, dann können Sie dies mit der Funktion Abs
vermeiden. Sie gibt Ihnen den absoluten Wert einer Zahl zurück. Der Aufruf würde dann
folgendermaßen aussehen: Abs(DateDiff('d', '7/1/2002', '1/18/2002').
Mit DateDiff erhalten Sie möglicherweise unterschiedliche Ergebnisse, abhängig davon, ob
Sie den Paramter 'w' oder 'ww' verwenden. Der Parameter 'w' berechnet die Anzahl der
Wochen zwischen zwei Daten auf Basis des Tages des Startdatums. Der 18. Januar 2002 fiel
zum Beispiel auf einen Freitag. Mit dem Parameter "w" berechnet DateDiff die Zahl der
Freitage zwischen diesem Datum und einem anderen Datum. Im Gegensatz dazu berechnet
DateDiff mit dem Parameter "ww" die Wochen auf Basis der Sonntage zwischen den beiden
Daten.
Mit DateDiff können Sie auch feststellen, wie lange Ihr Script zur Ausführung benötig hat.
Hierzu weisen Sie einfach in der ersten Zeile einer Variable den Rückgabewert der Funktion
Now zu. Sie enthält nun die Uhrzeit des Scriptstarts. Am Ende des Scripts berechnen Sie die
Differenz zwischen der Zeit in der Variable und dem Rückgabewert der Funktion Now.
Das folgende Script fragt den freien Plattenplatz für alle Laufwerke des lokalen Computers ab
und misst die Zeit, die es zur Ausführung benötigt:
Start = Now
Set objWMIService = GetObject("winmgmts://")
Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
For Each objLogicalDisk In colLogicalDisk
Wscript.Echo objLogicalDisk.DeviceID & " " & objLogicalDisk.FreeSpace
Wscript.Echo WeekDayName(Day('1/9/2002'))
Diese Codezeile gibt den Wert Sonntag zurück. Mit einem weiteren optionalen
Parameter können Sie sich die Abkürzung von den Namen des Wochentages
zurückliefern lassen. Hängen Sie den Parameter True einfach hinter den
Wochentag an:
Wscript.Echo MonthName(Month('9/1/2002'))
Diese Codezeile gibt den Wert September zurück. Mit einem weiteren
optionalen Parameter können Sie sich die Abkürzung von den Namen des
Monats zurückliefern lassen. Hängen Sie den Parameter True einfach hinter
den Monat an:
Das folgende Codestück gibt den Wert 24 zurück, da der String Dies ist ein Test-
String 24 Zeichen lang ist.
TestString = "Dies ist ein Test-String" Wscript.Echo Len(TestString)
Left Gibt eine bestimmte Anzahl von Zeichen zurück. Die zurückgegebenen Zeichen
beginnen mit dem ersten Zeichen des Strings und setzen sich nach rechts bis zum
Ende des Strings fort. Sie müssen zwei Parameter angeben: den String und die
Anzahl der zurückzugebenden Zeichen.
Das folgende Codestück gibt den String Die zurück, da dies die ersten drei Zeichen
des Strings Dies ist ein Test-Stringsind.
TestString = "Dies ist ein Test-String" Wscript.Echo Left(TestString, 3)
Right Gibt eine bestimmte Zahl von Zeichen zurück. Die zurückgegebenen Zeichen
beginnen mit dem letzten Zeichen des Strings und setzen sich nach links bis zum
Anfang des Strings fort. Sie müssen zwei Parameter angeben: den String und die
Anzahl der zurückzugebenden Zeichen.
Das folgende Codestück gibt den String ing zurück, da dies die letzten drei Zeichen
des Strings Dies ist ein Test-Stringsind.
TestString = "Dies ist ein Test-String" Wscript.Echo Right(TestString, 3)
Mid Gibt eine bestimmte Zahl von Zeichen zurück. Die zurückgegebenen Zeichen
beginnen an der als Parameter angegebenen Position und setzten sich zum Ende des
Strings fort (von links nach rechts). Sie müssen drei Parameter angeben: den String,
die Startposition im String (zum Beispiel 5, um beim fünften Zeichen des Strings zu
beginnen) und die Anzahl der zurückzugebenden Zeichen.
Das folgende Codestück gibt den String ist_ zurück (der Unterstrich steht für ein
Leerzeichen), da dies die Zeichen an den Positionen 6, 7, 8 und 9 sind.
TestString = "Dies ist ein Test-String" Wscript.Echo Mid(TestString, 6, 4)
Space Fügt die angegebene Anzahl von Leerzeichen in einen String ein. Das folgende
Codestück fügt zum Beispiel 10 Leerzeichen zwischen Dies ist ein und Test-String
ein.
Wscript.Echo "Dies ist ein" & Space(10) _ & "Test-String"
LTrim Entfernt alle Leerzeichen am Anfang eines Strings.
TestString = " This is a test string " Wscript.Echo LTrim(TestString)
RTrim Entfernt alle Leerzeichen am Ende eines Strings.
TestString = " This is a test string " Wscript.Echo RTrim(TestString)
Trim Entfernt alle Leerzeichen am Anfang und am Ende eines Strings. Das folgende
Codestück wandelt den String " Dies ist ein Teststring " zum Beispiel in den String
"Dies ist ein Test-String" um.
TestString = " This is a test string " Wscript.Echo Trim(TestString)
Tabellarische Ausgaben
Die Funktionen zur Stringbearbeitungen sind besonders bei der Erstellung von tabellarischen
Ausgaben sehr nützlich. Ein Beispiel hierfür sehen Sie in Script 2.18. Es verwendet die
Funktionen Len und Space, um eine Tabelle zu erstellen, in der zwei Dienste und deren Status
angezeigt werden. Das Script geht folgendermaßen vor:
1.Es setzt den Wert von vier Variablen - zwei für die Namen der Dienste und zwei für deren
Status.
2.Es stellt mit der Funktion Len die Länge des Strings in der ersten Variable fest und speichert
diesen Wert in der Variable NameLength. "Warndienst" hat zum Beispiel 10 Zeichen -
daher wird in NameLength der Wert 10 gespeichert.
3.Das Script subtrahiert den Wert in NameLength von 20 (der Spaltenbreite der Spalte für die
Dienstnamen) und speichert das Ergebnis in der Variable SpacesToAdd. Für den
"Warndienst" wäre das 10 (20-10).
4.Es schreibt den Namen des Dienstes in die Variable DisplayName und hängt so viele
Leerzeichen an, dass der String in dieser Variable 20 Zeichen lang ist. Für den "Warndienst"
wären das zum Beispiel 10 zusätzliche Leerzeichen (der Wert in der Variable
SpacesToAdd). Diese Leerzeichen werden über die Funktion Space hinzugefügt.
1 Service1 = "Warndienst"
2 State1 = "Wird ausgeführt"
3 Service2 = "DHCP-Client"
4 State2 = "Angehalten"
5
6 NameLength = Len(Service1)
7 SpacesToAdd = 20 - NameLength
8 DisplayName = Service1 & Space(SpacesToAdd)
9 Wscript.Echo DisplayName & State1
10
11Display = ""
12
13NameLength = Len(Service2)
14SpacesToAdd = 20 - NameLength
15DisplayName = Service2 & Space(SpacesToAdd)
16Wscript.Echo DisplayName & State2
Wenn Sie das Script unter CScript ausführen, dann erhalten Sie die folgende Ausgabe:
Warndienst Wird ausgeführt
DHCP-Client Angehalten
Text in Nachrichtenfenster formatieren
Wenn Sie es vorziehen, Text in Nachrichtenfenstern auszugeben, dann werden Sie feststellen,
dass es hier sehr viel schwerer ist den Text in Spalten auszugeben - wenn nicht gar
unmöglich. Das liegt an den unterschiedlichen Scripten in der Eingabeaufforderung und im
Nachrichtenfenster. In der Eingabeaufforderung wird eine nichtproportionale Schrift
verwendet. Das bedeutet, dass alle Zeichen (auch die Leerzeichen) gleich breit sind. In
Abbildung 2.14 sehen Sie, dass die Buchstaben i, j und l genauso breit sind wie m, v und w.
Anmerkung: Die Funktion InStr wurde für einfache Stringbearbeitung entwickelt. Wenn Sie
komplexere Aktionen mit einem String durchführen müssen, dann verwenden Sie reguläre
Ausdrücke. Die Verwendung von regulären Ausdrücken liegt jedoch nicht im Themenbereich
dieses Buches. Weitere Informationen hierzu finden Sie unter
http://www.microsoft.com/windows/reskits/webresources (englischsprachig).
Das folgende Codestück konvertiert den String Ulf Dornheck Busscher in den String
ulf dornheck busscher.
UserName = "Ulf Dornheck Busscher" Wscript.Echo LCase(UserName)
UCase Konvertiert alle alphabetischen Zeichen in Großbuchstaben.
Das folgende Codestück konvertiert den String Ulf Dornheck Busscher in den String
ULF DORNHECK BUSSCHER.
UserName = "Ulf Dornheck Busscher" Wscript.Echo UCase(UserName)
Rechenreihenfolge
Die meisten Berechnungen, die Sie als Systemadministrator vornehmen werden, sind sehr
einfach - zum Beispiel eine Division durch 1,024, um Byte in KB umzurechnen. Trotzdem
müssen Sie vielleicht gelegentlich Berechnungen durchführen, die mehr als eine Rechenart
verwenden (zum Beispiel zwei Werte addieren und das Ergebnis durch einen weiteren Wert
teilen). Daher müssen Sie wissen, in welcher Reihenfolge VBScript Berechnungen
durchführt.
Rechenoperationen (Addition, Subtraktion, Multiplikation und Division) werden von
VBScript nicht gleichwertig behandelt. Stattdessen führt VBScript diese in der folgenden
Reihenfolge durch:
1.Division
2.Multiplikation
3.Addition
4.Subtraktion
Warum ist das für Sie wichtig? Schauen Sie sich folgendes Script an. Es addiert zwei Werte,
multipliziert diese mit einem dritten, subtrahiert einen vierten und dividiert durch einen
fünften:
Seite 69 von 394
Wscript.Echo 1 + 2 * 3 - 4 / 5
Wenn Sie das Script ausführen, dann wird der Wert 6,2 ausgegeben. Und so kommt es zu
diesem Wert:
1.Da die Division Vorrang vor allen anderen Rechenoperationen hat, dividiert VBScript als
erstes 4 durch 5. Die verbleibende Berechnung sieht nach diesem Schritt so aus:
1 + 2 * 3 - 0.8
2.Als nächstes wird multipliziert: 2 und 3 ergibt 6. Die verbleibende Berechnung sieht so aus:
1 + 6 - 0.8
3.Die Addition ist die nächste Berechnung; 1 und 6 ergibt 7
7 - 0.8
4.Als letztes wird die Subtraktion durchgeführt: 7 minus 0,8 ist 6,2.
Nun könnte es natürlich sein, dass dies nicht die von Ihnen gewünschte Rechenreihenfolge ist.
Stattdessen wollten Sie folgende Berechnung durchführen:
1.Addition 1 + 2
2.Ergebnis mit 3 multiplizieren
3.4 subtrahieren
4.Ergebnis durch 5 dividieren
Damit dies so passiert, müssen Sie Klammern verwenden. Sie zeigen VBScript die richtige
Rechenreihenfolge. Klammern haben immer Vorrang - egal welche Rechenoperation
verwendet wird. Wenn mehrere verschachtelte Klammern verwendet werden, dann werden
die Berechnungen immer von der innersten Klammer zur äußersten Klammer durchgeführt
(die innerste Klammer wird also als erstes berechnet).
Wscript.Echo (((1 + 2) * 3) - 4) / 5
Wenn Sie statt der Zahl der Nachkommastellen den Wert -1 verwenden,
dann werden die Einstellungen aus den Regional- und Spracheinstellung des
Computers verwendet.
Führende Null. Mögliche Werte:
Prozentwerte formatieren
Manchmal sind Prozentwerte nützlicher als reine Zahlen. Die Maximalgröße des
Ereignisprotokolls kann zum Beispiel von Computer zu Computer unterschiedlich sein. Daher
wissen Sie nach der Abfrage der aktuellen Größe des Ereignisprotokolls (zum Beispiel über
WMI) nicht, wie voll das Protokoll tatsächlich ist. Besser wäre es, die prozentuale Auslastung
des Ereignisprotokolls abzufragen.
Wenn Sie Prozentwerte abfragen, dann sollten Sie diese auch als Prozentwerte anzeigen.
Wenn das Ereignisprotokoll zum Beispiel maximal 5.000.000 Byte groß werden kann und die
aktuelle Größe 3.127.354 Byte ist, dann können Sie 3.127.354 durch 5.000.000 teilen. Sie
erhalten als Ergebnis den Wert 0,6254708 zurück. Dieses Ergebnis wäre als Prozentwert
(63%) viel aussagekräftiger.
Die Funktion FormatPercent konvertiert eine Zahl in einen Prozentwert; das bedeutet, dass
sie die Zahl mit 100 multipliziert und ein Prozentzeichen anhängt. FormatPercent akzeptiert
die gleichen Formatierungsparameter wie FormatNumber:
•
Nachkommastellen
•
Führende Null bei Kommawerten, die kleiner als 1 und größer als -1 sind
Do Loop
Eine Do-Loop-Schleife ermöglicht es Ihnen dieselben Befehle so lange auszuführen, bis eine
bestimmte Bedingung eingetreten ist - zum Beispiel, wenn Sie den freien Festplattenplatz so
lange überwachen möchten, bis dieser unter einen bestimmten Wert fällt. Im Gegensatz zur
For-Next-Schleife können Sie mit der Do-Loop-Schleife Befehle für einen bestimmten
Zeitraum ausführen.
VBScript unterstützt zwei Arten von Do-Loop-Schleifen: Do Until und Do While. Die Do-
Until-Schleife wird so lange ausgeführt, bis eine bestimmte Bedingung zutrifft (wahr ist). Das
folgende Script verwendet das Objekt FileSystemObject, um eine Textdatei zu öffnen und
diese dann Zeile für Zeile auszulesen. Hierzu ist der Code zum Auslesen der Textzeilen in
einer Schleife platziert. Diese wird so lange ausgeführt, bis (until) das Ende der Datei (Ende
des Textstreams - End Of Stream) erreicht ist. Die Bedingung für diese Schleife sieht so aus:
Do Until objTextFile.AtEndOfStream
Diesen Befehl können Sie auch so lesen: "Führe die Schleife so lange aus, bis das Ende der
Datei erreicht ist".
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
("c:\test.txt", ForReading)
Do Until objTextFile.AtEndOfStream
strNextLine = objTextFile.Readline
Abbildung 2.18: Das Nachrichtenfenster zeigt an, dass ein Fehler aufgetreten ist
Wie Sie sehen können, wurde die Schleife beendet, bevor die Ergebnisausgabe durchgeführt
wird.
Entscheidungen treffen
Ein Script wird normalerweise sequenziell ausgeführt. Das heißt, Zeile 1 wird abgearbeitet,
dann Zeile 2, Zeile 3 usw. bis die letzte Zeile abgearbeitet wurde.
Im Allgemeinen wird das Schreiben von Scripten durch diese Tatsache einfacher. Nachdem
ein Script gestartet wurde, können Sie davon ausgehen, dass es alle Zeilen korrekt ausführt
Nein Ja Ja
If Then ElseIf
Systemadministratoren müssen oft Entweder/Oder-Entscheidungen treffen. Entweder der
Computer hat genügend Festplattenplatz oder nicht. In solchen Situationen bietet Ihnen das If-
Then-Else-Konstrukt eine optimale Möglichkeit eine Bedingung mit minimalem
Programmieraufwand zu implementieren.
Natürlich kann es sein, dass es mehr als zwei mögliche Bedingungen gibt. Stellen Sie sich
zum Beispiel vor, Sie möchten die Wartung von Festplatten nach den folgenden Kriterien
entscheiden:
•
Ein Laufwerk mit weniger als 100 MB verfügbarem Speicherplatz benötigt Ihre sofortige
Aufmerksamkeit.
•
Um ein Laufwerk mit weniger als 250 MB und mehr als 100 MB freiem Speicherplatz
können Sie sich bei Gelegenheit kümmern.
•
Ein Laufwerk mit mehr als 250 MB freiem Speicherplatz benötigt keine Aufmerksamkeit.
Um mehrere Alternativen zu implementieren, können Sie den If-Then-Else-Befehl verwenden.
Mit diesem prüft das Script ganz normal die Bedingung (zum Beispiel x = 1). Wenn diese
wahr ist, dann führt das Script die entsprechende Aktion aus. Wenn die Bedingung jedoch
nicht wahr ist, dann können Sie eine zweite Bedingung prüfen lassen. Die Syntax hierzu sieht
so aus:
ElseIf x = 2 Then
Sie können so viele ElseIf-Befehle verwenden, wie Sie möchten. Statt des letzten ElseIf-
Befehls, verwenden Sie einen einfachen Else-Befehl.
Das folgende Script zeigt - abhängig von den folgenden Bedingungen - jeweils
unterschiedliche Meldungen an
•
Weniger als 100 MB verfügbarer Speicherplatz
•
Weniger als 250 MB und mehr als 100 MB freier Speicherplatz
•
Mehr als 250 MB freier Speicherplatz
If FreeMegabytes <= 100 Then
Wscript.Echo Computer.Name & " benötigt sofortige Aufmerksamkeit."
ElseIf FreeMegabytes < 250 Then
Wscript.Echo Computer.Name & " sollten Sie so schnell wie möglich
überprüfen."
Else
Wscript.Echo Computer.Name & " verfügt über genügend Speicherplatz."
Select Case
Der Befehl Select-Case ist eine strukturiertere Alternative zum Befehl If-Then-ElseIf. Wenn
Sie mehr als drei Bedingungen überprüfen müssen, dann ist er meistens schneller und
einfacher zu implementieren. Das folgende Script verwendet den Select-Case-Befehl zum
Beispiel, um die WMI-Rückgabewerte zum Druckerstatus auszuwerten:
Select Case PrinterStatus
Case 1 strCurrentState = "Other"
Case 2 strCurrentState = "Unknown"
Case 3 strCurrentState = "Idle"
Case 4 strCurrentState = "Printing"
Case 5 strCurrentState = "Warming Up"
End Select
Die gleiche Aufgabe mit If-Then-ElseIf-Befehlen zu lösen führt zu einem mehr als doppelt so
langen Script, dass schwer zu lesen ist:
If PrinterStatus = 1 Then
strCurrentState = "Other"
ElseIf PrinterStatus = 2 Then
strCurrentState = "Unknown"
ElseIf PrinterStatus = 3 Then
strCurrentState = "Idle"
ElseIf PrinterStatus = 4 Then
strCurrentState = "Printing"
ElseIf PrinterStatus = 5 Then
strCurrentState = "Warming Up"
End Select
Der Select-Case-Befehl wird folgendermaßen verwendet:
1.Beginnen Sie den Befehlsblock mit dem Befehl Select Case und dem Namen der Variable,
die Sie auswerten möchten.
2.Fügen Sie für jeden potentiellen Wert der Variable einen Case-Befehl ein. Diesem Case-
Befehl muss dann jeweils der Scriptcode folgen, der ausgeführt werden soll, wenn die
Variable den mit Case angegebenen Wert enthält.
3.Beenden Sie den Select-Case-Block mit einem abschließenden End-Select-Befehl.
Wenn keine der Case-Bedingungen zutrifft, dann können Sie diesen Fall mit einem
abschließenden Case-Else-Befehl abfangen:
Select Case PrinterStatus
Case 1 strCurrentState = "Other"
Case 2 strCurrentState = "Unknown"
Case 3 strCurrentState = "Idle"
Case 4 strCurrentState = "Printing"
Case 5 strCurrentState = "Warming Up"
Case Else strCurrentState = "Status cannot be determined."
End Select
Außerdem haben Sie die Möglichkeit, die Case-Bedingung in eine eigene Zeile zu schreiben.
Dieser Zeile können dann beliebig viele Zeilen mit Anweisungen für diesen Fall folgen:
Case 1
strCurrentState = "Other"
Wscript.Echo strCurrentState
Arrays
Scripte sind wohl am nützlichsten, wenn Sie dieselbe Aufgabe mehrfach ausführen können.
Wenn Sie zum Beispiel nur über einen Computer verfügen, dann ist es nicht sehr mühsam,
das Snap-In Dienste aufzumachen, und einfach zu schauen, welche Dienste installiert sind.
Ein Script hierfür zu schreiben dürfte wohl deutlich länger dauern. Wenn Sie jedoch 100
Computer betreuen, dann ziehen Sie es sicher vor, wenn ein Script diese Aufgabe für Sie
erledigt.
Wenn ein Script Informationen von 100 Computern abfragen soll, dann muss es natürlich
deren Namen irgendwo speichern. Außerdem muss es sich merken können, von welchen
Computern es bereits Informationen abgefragt hat und von welchen nicht. Ein Standardweg
zur Speicherung solcher Informationen ist die Verwendung von Arrays (Felder). Ein Array ist
ein bestimmter Variablentyp, der mehrere Werte speichern kann.
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colRunningServices = objWMIService.ExecQuery _
("SELECT * FROM Win32_Service")
Eein Recordset kann im Gegensatz dazu mit der folgenden einzelnen Codezeile sortiert
werden:
DisconnectedRecordset.Sort = 'FileSize'
Fehlerbehandlung
VBScript stellt Ihnen ein relativ einfaches Verfahren zur Behandlung von Laufzeitfehlern zur
Verfügung. Laufzeitfehler sind alle Fehler, die nicht vom Compiler abgefangen werden
können und daher erst nach dem Scriptstart auftreten. Das nächste Script produziert zum
Beispiel einen Syntaxfehler, da der Befehl Wscript.Echo falsch geschrieben ist. Der Compiler
kann die Codezeile nicht interpretieren. Bevor ein Script ausgeführt wird, wird jede Zeile des
Scripts von der Script-Engine eingelesen und auf korrekte Syntax geprüft. Bevor das gesamte
Script nicht so geprüft wurde, wird keine Zeile des Scripts ausgeführt. Daher wird die
Fehlermeldung sofort ausgegeben - auch wenn der Fehler erst in Zeile 3 auftritt:
Fehlerbehandlung in COM-Objekten
Ein Problem, weswegen die Fehlerbehandlung schwieriger wird, ist die Tatsache, dass Scripte
normalerweise COM-Objekte verwenden. Wenn im COM-Objekt selbst ein Fehler auftritt,
bemerkt VBScript dies zwar - es ist möglicherweise jedoch nicht festzustellen, was den Fehler
ausgelöst hat. Im folgenden Script versucht WMI zum Beispiel eine Bindung zum nicht
existierenden Drucker TestPrinter aufzubauen - dies führt natürlich zu einem Fehler. Das
Script versucht dann die Fehlernummer und die Fehlerbeschreibung abzufangen und
anzuzeigen:
On Error Resume Next
Set Test = GetObject _
("Winmgmts:root\cimv2:Win32_Printer.Name='TestPrinter'")
Wscript.Echo Err.Number & VbTab & Err.Description
Wenn Sie das Script ausführen, dann erhalten nicht etwa eine normale VBScript-
Fehlernummer mit vier Ziffern oder eine Fehlerbeschreibung - stattdessen wird das
Nachrichtenfenster aus Abbildung 2.23 angezeigt.
Prozeduren
Die ersten Administrationsscripte, die Sie schreiben, werden wahrscheinlich sehr einfach sein
- sie führen eine einzelne Aufgabe aus und sind dann beendet. Ein Beispiel hierfür wäre ein
Script, das sich mit einem Computer verbindet, eine Liste mit allen auf diesem Computer
ausgeführten Diensten abfragt und dann endet. Vielleicht verwenden Sie ein zweites Script,
das bestimmte Dienste auf einem Computer startet, und ein drittes Script, das bestimmte
Dienste beendet.
Wenn Sie mehr Erfahrung gewinnen, dann fangen Sie wahrscheinlich an, komplexere Scripte
zu schreiben - zum Beispiel indem Sie mehrere Scripte kombinieren. Statt drei separate
Scripte zum Verwalten von Diensten zu verwenden, schreiben Sie ein Script, das drei
unterschiedliche Aufgaben ausführen kann. Für ein solches Script könnten Sie beispielsweise
Kommandozeilenparameter verwenden:
•
Wenn Sie den Parameter /info angeben, dann gibt das Script Informationen über die
ausgeführten Dienste zurück.
Funktionen
Wie Subroutinen auch, fassen Funktionen Codestücke zusammen - sie sollten jedoch einen
Wert zurückgeben. Leider kümmert sich VBScript nicht darum, ob die Funktion auch
tatsächlich einen Wert zurückgibt.
Wenn Sie eine Funktion deklarieren, erstellt VBScript automatisch eine Variable, die
denselben Namen wie die Funktion hat - in dieser Variable wird der Rückgabewert der
Funktion gespeichert. Das folgende Script verwendet zum Beispiel den Befehl Wscript.Echo
ThisDate. ThisDate ist der Name einer Funktion, die das aktuelle Datum zurückgibt. Für
VBScript bedeutet das:
•
Der Befehl Wscript.Echo ThisDate führt zwei Aufgaben aus:
•
Erst wird die Funktion ThisDate aufgerufen - diese schreibt das aktuelle Datum in die zur
Funktion gehörende Variable ThisDate.
•
Nachdem die Funktion vollständig ausgeführt wurde, verwendet der Befehl Wscript.Echo
den Wert der Variable, um das Datum auszugeben.
•
Obwohl der Befehl Option Explicit verwendet wird und die Variable nie deklariert wurde,
kommt es zu keinem Fehler. Dies liegt daran, dass die Variable zusammen mit der Funktion
von VBScript deklariert und initialisiert wird.
Option Explicit
Wscript.Echo ThisDate
Function ThisDate
ThisDate = Date
End Function
Bedenken Sie, dass dieser Ansatz nur mit Funktionen und nicht mit Subroutinen funktioniert.
Das folgende Script führt zu einem Laufzeitfehler, da VBScript das Datum nicht zum Namen
der Subroutine zuweisen kann:
Wscript.Echo ThisDate
Sub ThisDate
Abbildung 2.26: In einer Funktion einem Parameter einen neuen Wert zuweisen
In vielen Scripten ist es völlig egal, ob die Funktion den Wert von x ändert. Wenn Sie jedoch
den Originalwert von x später noch benötigen, dann geraten Sie möglicherweise in
Schwierigkeiten.
Standardmäßig werden Variablen unter VBScript bei Funktionsaufruf by reference (als
Referenz) übergeben. Das bedeutet, dass die Funktion nicht den Wert erhält, der in der
Variable gespeichert ist, sondern einen Zeiger auf die Speicherstelle, in der der Wert der
Variable gespeichert ist. Daher greift die Funktion natürlich auch auf den Originalwert selbst
zu.
Um sicherzustellen, dass der Wert einer Variable nicht in einer Funktion geändert wird,
übergeben Sie den entsprechenden Parameter by value (als Wert). In diesem Fall erhält die
Funktion nicht einen Zeiger auf die Speicherstelle der Originalvariable, sondern nur den Wert,
der in dieser gespeichert ist. Wenn die Funktion an diesem Wert Änderungen vornimmt, dann
sind die Originalspeicherstelle (die Originalvariable) und deren Wert hiervon nicht betroffen.
Um eine Variable by value zu übergeben, verwenden Sie das Schlüsselwort ByVal in der
Funktionsdefinition. Das folgende Script übergibt den Parameter x auf diese Art:
x = 100
Wscript.Echo ModifyValue(x) & VbTab & x
Function ModifyValue(ByVal x)
ModifyValue = x / 25
x = 99
End Function
Die Ausgabe des Scripts sehen Sie in Abbildung 2.27. Wie Sie sehen, wird die Variable x
nicht verändert. Auch wenn es so scheint, dass ihr Wert in der Funktion auf 99 gesetzt wird.
In Wirklichkeit arbeitet die Funktion nur mit einer Kopie der Originalvariablen - deren Wert
wird auf 99 gesetzt. Nachdem die Funktion beendet ist wird diese Kopie verworfen.
Rekursion
Rekursion ist eine Programmiertechnik, bei der eine Subroutine oder Funktion sich selbst
aufruft. Möglicherweise haben Sie schon einmal ein Bild gesehen, bei der sich der Fotograf in
einem Spiegel selbst fotografiert hat - der Fotograf fotografiert sein Spiegelbild, dass ein
Spiegelbild fotografiert, dass wiederum sein Spiegelbild fotografiert usw. Bei der Rekursion
passiert genau das gleiche: Subroutine A ruft Subroutine A auf, die wiederum Subroutine A
aufruft, die wiederum Subroutine A aufruft usw.
Auch wenn das Konzept der Rekursion sehr bizarr erscheint und schwer zu verstehen ist,
handelt es sich doch um ein wichtiges Konzept. Nehmen wird zum Beispiel an, Sie möchten
alle Dateien in einem Ordner auflisten. Auf den ersten Blick ganz einfach - aber was machen
Sie, wenn der Ordner weitere Unterordner enthält? Und was, wenn diese wiederum
Unterordner enthalten? In diesem Fall haben Sie mit der Rekursion die Möglichkeit alle
Ordner zu durchlaufen - auch wenn Sie die Ordnerstruktur nicht kennen.
Um die in Abbildung 2.28 zu sehende Ordnerstruktur zu durchlaufen, beginnen Sie beim
Ordner Scripte und listen alle Unterordner auf. Für jeden der Unterordner listen Sie wiederum
alle Unterordner auf, usw.
COM-Objekte
Bei COM (Component Object Model) handelt es sich um einen Standardweg für
Anwendungen (.exe-Dateien) und Bibliotheken (.dll-Dateien), um ihre Funktionalität anderen
Anwendungen zur Verfügung zu stellen. Ohne COM müsste jeder, der die
Systemadministration automatisieren will, ein erfahrener C++- oder Visual Basic-
Programmierer sein und sich mit den Windows APIs (Application Programming Interfaces)
auskennen.
COM-Komponenten sind Dateien (normalerweise .exe- oder .dll-Dateien), die
Beschreibungen der Objekte enthalten, die eine Komponente zur Verfügung stellt (diese
Beschreibungen werden auch Klassen genannt). Wenn Sie ein COM-Objekt in einem Script
erstellen (dieser Prozess wird auch als Instanzierung bezeichnet), dann erstellen Sie eine neue
Kopie dieses Objektes (eine Instanz) auf Basis der Objektbeschreibung (Klasse). Nachdem
die Instanz erstellt wurde, können Sie auf die Eigenschaften, Methoden und Ereignisse
zugreifen, die vom neuen Objekt zur Verfügung gestellt werden.
Objekte, die ihre Funktionalität so über COM zur Verfügung stellen, werden auch COM-
Server genannt. Anwendungen oder Scripte, die diese Funktionalitäten nutzen, werden als
COM-Clients bezeichnet. Wenn Sie zum Beispiel ein Script schreiben, das WMI verwendet,
Der COM-Prozess
Als Scriptautor müssen Sie nur wissen wie Sie eine Referenz auf ein Automatisationsobjekt
erstellen. Sie müssen sich keine Sorgen über das Auffinden oder das Laden des Objekts
machen, da dies das Windows-Betriebssystem für Sie erledigt. Dennoch ist es nützlich, wenn
Sie wissen was passiert, wenn Sie in Ihrem Script die Methode CreateObject verwenden.
Die Referenzierung eines COM-Objektes ist sogar relativ simpel. Wenn Sie eine Anwendung
oder eine Bibliothek installieren, die eine Objektklasse zur Verfügung stellt, dann registriert
sich diese selbst im Betriebssystem. Bei dieser Registrierung teilt die Komponente dem
Betriebssystem folgendes mit:
•
Dass es einen neuen COM-Server gibt.
•
Die Objektklassen, die der neue COM-Server zur Verfügung stellt.
Hierzu werden Registrierungsschlüssel unter dem Pfad HKEY_CLASSES_ROOT der
Registrierung erstellt. Unter den neuen Registrierungsschlüsseln gibt es einen, der den
Programmatic Identifier (ProgID) für jede neue Objektklasse definiert. Die ProgID ist ein
kurzer String, der den Namen der Objektklasse angibt. Sie wird von den Methoden
CreateObject und GetObject verwendet, um das Objekt anzugeben, das Sie erstellen möchten.
In der folgenden Codezeile ist die ProgID zum Beispiel Excel.Application:
Set TestObject = CreateObject("Excel.Application")
Bei der ProgID handelt es sich um die Information, die das Betriebssystem benötigt, um das
COM-Objekt zu finden und zu instanzieren.
Servermodus
Wenn ein Objekt über eine ausführbare Datei erstellt wird, dann wird die Anwendung in
einem speziellen Modus gestartet - dem Servermodus oder auch Embedded-Mode. In diesem
Modus wir die Anwendung ausgeführt und ist voll funktionsfähig, es werden nur keine GUI-
Elemente angezeigt (Sie können trotzdem über den Taskmanager prüfen, ob die Anwendung
ausgeführt wird). Der Servermodus ermöglicht es die Anwendung zu verwenden ohne dass
der Benutzer hierdurch gestört wird.
Auch wenn der Servermodus oft sehr nützlich ist, möchten Sie vielleicht doch manchmal die
Benutzerschnittstelle einer Anwendung anzeigen (zum Beispiel, wenn Sie Daten im Internet
Explorer anzeigen). Wenn dies der Fall ist, dann müssen Sie dies dem COM-Objekt über den
entsprechenden Befehl mitteilen. Das folgende Script erstellt zum Beispiel eine Instanz des
Internet Explorer und verwendet die Eigenschaft Visible des Objektes, um die Anwendung für
den Benutzer sichtbar zu machen:
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
Bindung
Mit Bindung wird die Art bezeichnet, auf die ein Script oder eine Anwendung auf ein COM-
Objekt zugreift. Wenn Sie eine Objektreferenz auf ein Automatisationsobjekt erstellen, dann
muss VBScript prüfen, ob das Objekt existiert und dass die Methoden und Eigenschaften, auf
die Sie zureifen, vom Objekt zur Verfügung gestellt und korrekt verwendet werden. Dieser
Prozess wird Bindung genannt.
COM unterstützt zwei Arten der Bindung: die frühe Bindung (early) und die späte Bindung
(late). Bei der frühen Bildung werden Objekt, Eigenschaften und Methoden bereits bei der
Compilierung der Anwendung überprüft. Wenn es zu diesem Zeitpunkt bereits Probleme gibt,
schlägt die Compilierung fehl. Die frühe Bindung ist schneller als die späte Bindung, da das
Abbildung 2.29: Automatisationsobjekt, dass auch nach der Beendigung des Scripts
noch weiter ausgeführt wird
Bei Out-Of-Process-Servern müssen Sie normalerweise zum Entfernen aus dem Speicher eine
Methode des Objekts verwenden (um diese Methode zu finden, werden Sie meistens in der
Dokumentation des Objekts nachschlagen müssen) - bei Microsoft Word handelt es sich bei
dieser Methode um Quit. Das folgende Script erstellt eine Instanz von Microsoft Word und
entfernt diese sofort wieder aus dem Speicher:
Set TestObject = CreateObject("Word.Application")
TestObject.Quit
Das Schlüsselwort Nothing
WSH-Übersicht
Die meisten Leute, die sich zum ersten Mal mit dem Windows Script Host (WSH)
beschäftigen, sind leicht irritiert. Was genau ist WSH? Handelt es sich um eine Sprache wie
VBScript oder JScript? Nein - auch wenn der WSH das Ausführen von Programmen
ermöglicht, die in einer dieser Sprachen geschrieben wurden. Handelt es sich um ein
Objektmodell wie WMI oder ADSI? Nein - der WSH stellt zwar ein einfaches Objektmodell
zur Verfügung, aber ist nicht seine primäre Aufgabe.
Was ist also der WSH? Wie der Name schon sagt, ist der WSH ein Script Host. Ein Script
Host ist ein Programm, dass eine Umgebung zur Verfügung stellt, in der ein Benutzer Scripte
ausführen kann. Diese Scripte können durchaus in unterschiedlichen Sprachen geschrieben
sein.
Wahrscheinlich haben Sie bereits andere Script Hosts verwendet. Zum Beispiel Microsoft®
Internet Explorer - dieser Script Host führt Scripte aus, die das Dynamic-HTML-
Objektmodell verwenden. Oder Shell-Programme (zum Beispiel C Shell, Bourne Shell und
Korn Shell) - auch sie ermöglichen es Ihnen Scripte zu schreiben. Auch jede
Eingabeaufforderung können Sie sich als Script Host vorstellen. Sie ermöglicht es Ihnen
schließlich Script auszuführen, die in der "Batchsprache" geschrieben sind.
Der WSH ist ein eher ungewöhnlicher Script Host. Im Gegensatz zu den oben erwähnten
Script Hosts ist der WSH nicht auf eine bestimmte Scriptsprache oder auf bestimmte
Objektmodelle eingeschränkt.
Die Funktionalität des WSH kann man in vier Hauptbereiche unterteilen. Diese Bereiche
werden im Rest des Kapitels ausführlich besprochen.
•
Die standardmäßige Fähigkeit, Administrationsaufgaben durchzuführen.
•
Die Fähigkeit, COM-Objekte zu verwenden.
•
Die Fähigkeit, Standard-Programmierungsfeatures einer WSH-kompatiblen Scriptsprache zu
nutzen.
•
Die Fähigkeit, Kommandozeilentools zu verwenden.
Anmerkung: Aufgrund der nützlichen zusätzlichen Funktionalitäten sollten Sie den WSH auf
jeden Fall auf Version 5.6 aktualisieren - egal, ob Sie die Scripte in diesem Kapitel ausführen
möchten oder nicht.
Um die installierte WSH-Version abzufragen, geben Sie in einer Eingabeaufforderung einfach
cscript ein und drücken die Eingabetaste. Wenn Sie Version 5.6 installiert haben, dann sollten
Sie die folgende Ausgabe sehen:
C:\WINDOWS>cscript
Microsoft (R) Windows Script Host, Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Alle Rechte vorbehalten.
Die gleichen Informationen können Sie auch mit Hilfe eines Scripts abrufen:
Wscript.Echo Wscript.Version
Die gleichen Informationen können Sie auch mit Hilfe eines Scripts abrufen:
Wscript.Echo Wscript.Version
Weitere Informationen zur WSH-Version 5.6 finden sie unter
http://msdn.microsoft.com/library/default.asp?url=/downloads/list/webdev.asp
(englischsprachig). Dort können Sie auch die aktuelle Version des WSH herunterladen.
Die WSH-Architektur
Wenn Sie Auto fahren lernen, müssen Sie nicht erst eine Ausbildung als Kfz-Mechaniker
machen. Wenn Sie zwischen Gas- und Bremspedal unterscheiden können und verstehen, wie
das Lenkrad funktioniert, dann sind Sie wahrscheinlich auch in der Lage von A nach B zu
fahren.
Wenn wir davon ausgehen, dass Sie nie wieder mit einem Auto fahren, nachdem Sie an Punkt
B angekommen sind, reicht dieses Wissen sicher auch aus. Was ist jedoch, wenn Sie
regelmäßig fahren möchten? In diesem Fall könnte es recht nützlich sein, wenn Sie etwas
Seite 109 von 394
darüber wissen, wie ein Auto funktioniert - und warum es möglicherweise nicht funktioniert.
Sie sollten wissen, dass ein Auto Benzin benötigt, dass in die Reifen Luft gehört und dass
Batterien leer werden können. Wenn Sie diese grundlegenden Informationen nicht kennen,
dann werden Sie möglicherweise einige unangenehme Überraschungen erleben.
Das gleiche gilt für Scripting. Wenn Sie nur ein Script benötigen, um den Warndienst auf dem
lokalen Computer anzuhalten, dann benötigen Sie dieses Buch nicht. Stattdessen können Sie
sich folgendes Script kopieren:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colServices = objWMIService.ExecQuery _
("SELECT * FROM Win32_Service WHERE Name = 'Alerter'")
For Each objService in colServices
errReturnCode = objService.StopService()
Next
Was passiert aber, wenn Sie einen anderen Dienst anhalten möchten? Oder wenn Sie einen
Dienst auf einem Remotecomputer anhalten möchten? Was, wenn Sie den Warndienst starten
möchten? Wenn Sie bestehende Scripte verändern oder eigene Scripte entwickeln möchten,
dann müssen Sie auch wissen, wie diese Scripte arbeiten - und für dieses Verständnis sind
Grundkenntnisse der WSH-Architektur unerlässlich.
Anmerkung: Sie sollten es auch vermeiden, Scripte mit einer Textverarbeitung zu erstellen
und diese dann in einen Texteditor zu kopieren. Es gibt keine Garantie dafür, dass bei diesem
Kopiervorgang tatsächlich nur unformatierter Text eingefügt wird. Probleme durch
formatierten Text sind oft schwer zu finden, da ein Zeichen möglicherweise nur unformatiert
aussieht.
Das Script kann in jeder Scriptsprache geschrieben werden, für die eine entsprechende
Scripting Language Engine installiert ist. Sie sollten die Datei mit der Dateierweiterung
speichern, die der Scriptsprache zugeordnet ist. In Tabelle 3.1 sehen Sie drei Beispiele zu
Scriptsprachen und deren Dateierweiterungen.
Anmerkung: Es auch dann möglich ein Script auszuführen, wenn Sie nicht die Standard-
Dateierweiterung verwendet haben. Weitere Informationen hierzu erhalten Sie später in
diesem Kapitel.
Nachdem Sie das Script in Notepad eingegeben und gespeichert haben, können Sie es
ausführen. Ein Vorteil von Scripting ist hierbei: Sie müssen das Script nicht erst kompilieren
oder weitere Dateien erstellen. Stattdessen starten Sie es im einfachsten Fall mit einem
Doppelklick. Geben Sie zum Beispiel die beiden folgenden Zeilen in Notepad ein:
Set objNetwork = Wscript.CreateObject("Wscript.Network")
Wscript.Echo objNetwork.ComputerName
Speichern Sie die Datei mit der Dateiendung .vbs, und Sie haben ein Script erstellt, das Ihnen
den Namen des lokalen Computers zurückgibt.
Anmerkung: Sie können den Script Host dazu zwingen eine bestimmte Scripting Language
Engine zu verwenden, indem Sie den Kommandozeilenschalter //E: verwenden (siehe Tabelle
3.2). Auf diese Art können Sie jede beliebige Dateierweiterung für Ihre Scriptdateien
verwenden.
Das WSH-Objektmodell
Meist wird von WSH als einzelnes Objekt gesprochen. In Wahrheit setzt sich der WSH
jedoch aus mehreren Komponenten zusammen - zum Beispiel aus dem standardmäßig
verfügbaren Objekt WScript und den drei COM-Objekten WshShell, WshNetwork und
WshController. Diese Objekte werden zusammen als WSH-Objekte bezeichnet.
In Abbildung 3.2 sehen Sie das WSH-Objektmodell. Die einzelnen Elemente des Diagrams
werden in diesem Kapitel besprochen.
WSH-Script ausführen
Wenn Sie mehrere Leute fragen wie sie Word starten, dann werden Sie wahrscheinlich einige
unterschiedliche Antworten erhalten - zum Beispiel indem Sie im Startmenü auf Word
klicken, indem Sie in einer Eingabeaufforderung winword.exe eingeben oder über eine
Tastenkombination. Egal welche Methode Sie auch verwenden, dass Ergebnis ist immer das
gleiche: Word wird gestartet.
Auch für das Ausführen von WSH-Scripten gibt es mehrere Möglichkeiten. Administrative
Scripte können zum Beispiel als Anmeldescript oder über einen geplanten Task ausgeführt
werden. Andere Scripte können über eine Eingabeaufforderung oder über einen Doppelklick
gestartet werden. In vielen Fällen macht es keinen Unterschied wie ein Script gestartet wird -
in anderen Fällen kann es jedoch ein sehr großer Unterschied sein.
Wenn Sie die Beispiele in diesem Kapitel nachvollziehen, dann wird empfohlen die Scripte in
einer Kommandozeile über CScript auszuführen. Dies geschieht aus zwei Gründen: Erstens
können Scripte unter CScript externe Programme starten und deren Ausgaben
weiterverarbeiten, und zweitens werden die Ausgaben im der Eingabeaufforderung statt in
Script Host-Optionen
Sowohl CScript als auch WScript akzeptieren einige Parameter. Diese legen fest, wie ein
Script ausgeführt wird oder ändern die Konfiguration der WSH-Umgebung. Einige Optionen
werden von beiden Script Host verwendet - CScript verfügt jedoch auch über ein paar
Optionen, die von WScript nicht verwendet werden (zum Beispiel //logo und //nologo).
Wenn der WSH installiert wird, dann ist WScript der Standardhost. Er wird verwendet, wenn
Sie ein Script nicht explizit über CScript oder WScript starten. Um den Standardhost auf
CScript zu konfigurieren, verwenden Sie folgenden Befehl:
cscript //H:cscript
Um den Standardhost wieder auf WScript zu setzen, verwenden Sie diesen Befehl:
wscript //H:wscript
Tabelle 3.2 zeigt die am häufigsten verwendeten WSH-Parameter.
Wenn der Script Debugger nicht installiert ist, tritt kein Fehler auf -
stattdessen wird das Script einfach weiter ausgeführt.
//E:engine Führt das Script über eine bestimmte Script Engine aus. Neben
anderen Dingen haben Sie mit diesem Schalter die Möglichkeit,
beliebige Dateierweiterungen für Ihre Scripte zu verwenden. Ohne
den Parameter //E können Sie Script nur dann starten, wenn diese
eine der registrierten Dateierweiterungen verwenden. Wenn Sie zum
Beispiel versuchen den folgenden Befehl auszuführen, erhalten Sie
eine Fehlermeldung:
cscript test.admin
Wenn Sie das Script jedoch mit dem Parameter //E starten, wird es
korrekt ausgeführt:
Die Option //nologo wird oft verwendet, wenn die Ausgaben des
Scripts in eine Textdatei umgeleitet werden.
//S Legt die Optionen Timeout und Logo dauerhaft für den aktuellen
Benutzer fest. Der folgende Befehl stellt zum Beispiel sicher, dass
das Logo unter CScript garnicht mehr angezeigt wird:
Diese Einstellung können Sie auch ändern, indem Sie mit der
rechten Maustaste auf die Scriptdatei klicken und dann zur
Registerkarte Eigenschaften wechseln.
//T:nn Legt die maximale Anzahl an Sekunden fest, die ein Script
ausgeführt wird (die Standardeinstellung ist ohne Einschränkung).
//X Startet das Programm im Microsoft Script Debugger. Wenn
der Script Debugger nicht installiert ist, dann wird das Script
ganz normal ausgeführt.
//? Zeigt eine Beschreibung der Kommandozeilenparameter an.
Hierbei handelt es sich um die Informationen, die Sie in
dieser Tabelle sehen.
WSH-Objekte
In der WSH-Umgebung stehen Ihnen standardmäßig das Objekt WScript und drei COM-
Objekte zur Verfügung (WshShell, WshNetwork und WshController). Einige der Aufgaben,
die Sie mit diesen Objekten durchführen können, lassen sich jedoch leichter mit anderen
Technologien erledigen - zum Beispiel mit WMI und ADSI.
Das Objekt WshShell stellt Ihnen zum Beispiel eine Methode mit dem Namen RegRead zur
Verfügung. Über diese Methode können Sie einen Registrierungseintrag auslesen. Sie
funktioniert sehr gut, wenn Sie den Registrierungsschlüssel, den das Script auslesen soll,
vorher schon kennen - zum Beispiel wenn Sie feststellen möchten, welches Hintergrundbild
ein Benutzer verwendet. Das folgende WSH-Script führt diese Aufgabe problemlos aus:
Set WshShell = WScript.CreateObject("WScript.Shell")
strWallpaper = WshShell.RegRead "HKCU\Control Panel\Desktop\Wallpaper"
Wscript.Echo strWallpaper
Was aber, wenn es um eine etwas weniger genau definierte Aufgabe geht? Zum Beispiel um
das Auflisten aller Einträge unter einem bestimmten Schlüssel? In einem solchen Fall nützt
Ihnen WSH ziemlich wenig. Stattdessen sollten Sie den WMI-Anbieter StdRegistry
verwenden - er listet alle Einträge unter einem bestimmten Schlüssel auf. Eine solche WMI-
Abfrage ist in diesem Fall deutlich einfacher umzusetzen.
Außerdem funktioniert WMI in den meisten Fällen auf Remotecomputern genauso wie auf
dem lokalen Computer. Der WSH arbeitet hingegen nur auf den lokalen Computern. Um
WSH-Scripte auf Remotecomputern auszuführen, müssen Sie zwei Scripte erstellen: das
Script, das ausgeführt werden soll, und ein Script, das dieses Script auf dem Remotecomputer
startet.
Trotzdem gibt es einige Fälle, in denen Sie möglicherweise dennoch auf die WSH-Objekte
statt auf WMI zurückgreifen. Reine WSH-Scripte werden zum Beispiel auch von Computern
unter Windows NT 4.0 und Windows 98 unterstützt - dies ist bei WMI und ADSI nicht der
Fall.
Tabelle 3.3: Funktionen, die Ihnen über das Objekt WScript zur Verfügung stehen
Kategorie Methoden oder Eigenschaften
Verwenden von COM-Objekten CreateObject, GetObject
Eingaben und Ausgaben Echo, StdOut, StdIn, StdErr
Arbeiten mit KommandozeilenargumentenArguments
Scriptausführung steuern Quit, Sleep, Timeout, Interactive
WSH-Umgebungsinformationen abfragen Application, BuildVersion, FullName, Name,
Path, ScriptFullName, ScriptName, Version
Ereignisse verarbeiten CreateObject, GetObject, ConnectObject,
DisconnectObject
COM-Objekte verwenden
Wenn Sie eine Information benötigen, dann können Sie diese zum Beispiel in einer
öffentlichen Bibliothek finden. Sie werden jedoch wahrscheinlich nicht in die Bibliothek
gehen, ein zufälliges Buch auswählen, und in diesem Buch die gewünschte Information
erwarten. Stattdessen müssen Sie das Buch finden, dass Ihnen diese Information zur
Verfügung stellt.
Genauso funktionieren auch COM-Objekte. Es gibt wahrscheinlich für fast alle
administrativen Aufgaben ein passendes COM-Objekt. Sie können jedoch ein COM-Objekt
nicht einfach verwenden. Objekte stellen nämlich nur ganz bestimmte Funktionalitäten zur
Verfügung. Genauso, wie Sie ein Buch nicht lesen können, bevor Sie es gefunden haben,
können Sie ein COM-Objekt nicht einfach verwenden. Stattdessen müssen Sie das Objekt erst
in Ihr Script einbinden. Das WScript-Objekt stellt Ihnen hierzu zwei Methoden zur
Verfügung: CreateObject und GetObject.
1Wscript.Echo "The version of WSH on this computer is: " & WScript.Version
Das WScript-Objekt verfügt außerdem über Eigenschaften, die es Ihrem Script ermöglicht,
auf drei Objekte zuzugreifen, die Eingabe- und Ausgabefunktionalitäten zur Verfügung
stellen: StdOut, StdIn und StdErr. Diese Objekte verfügen wiederum über eigene Methoden
und Eigenschaften - diese sehen Sie in Abbildung 3.6. Ein Script kann normalerweise nur
dann auf die Methoden StdOut, StdIn und StdErr zugreifen, wenn es unter CScript ausgeführt
wird.
Script 3.3: Ausgabe von drei Nachrichten über die Methode Echo
Wscript.StdOut.Write "ABCD"
Wscript.StdOut.Write "EFGHIJKLMN"
Wscript.StdOut.Write "OPQRSTUV"
Wscript.StdOut.Write "WXYZ"
ABCDEFGHIJKLMNOPQRSTUVWXYZ
WriteLine WriteLine arbeitet genauso wie WScript.Echo. Der angehängte
Parameter wird auf dem Bildschirm ausgegeben, und es wird ein
Zeilenumbruch angehängt. Das folgende Script führt wiederum
vier Ausgaben durch:
Wscript.StdOut.WriteLine "ABCD"
Wscript.StdOut.WriteLine "EFGHIJKLMN"
Wscript.StdOut.WriteLine "OPQRSTUV"
Wscript.StdOut.WriteLine "WXYZ"
ABCD
EFGHIJKLMN
OPQRSTUV
WXYZ
Script 3.4 zeigt eine Nachricht über die Methoden Write und WriteLine des Objektes
StdOut.TextStream an.
atl-wk-01
Informationen abgefragt.
Wenn Sie statt der Methode StdOut die Methode Wscript.Echo verwenden würden, sähe die
Ausgabe so aus:
Benutzer:
FABRIKAM
\
kenmeyer
atl-wk-01
Informationen abgefragt.
Eingaben über StdIn entgegennehmen
Do Until Wscript.StdIn.AtEndOfLine
strInput = Wscript.StdIn.Read(3)
Wscript.Echo strInput
Loop
Wenn Sie 'abcdefghijklmnopqrstuvwxyz' eingeben, wird die
Ausgabe so aussehen:
abc
def
ghi
jkl
mno
pqr
stu
vwx
yz
ReadLine Liest eine Zeile ein. ReadLine ist besonders dann sehr nützlich,
wenn der Benutzer Eingaben machen soll. Es liest alle Eingaben,
bis der Benutzer die Taste ENTER drückt:
strInput = Wscript.StdIn.ReadLine
Wscript.Echo strInput
Wenn Sie 'abcdefghijklmnopqrstuvwxyz' eingeben, sieht die
Ausgabe des Scripts so aus:
abcdefghijklmnopqrstuvwxyz
ReadAll Liest die gesamten Ausgaben eines Kommandozeilentools,
einer Batchdatei oder eines Shellbefehls ein.
Skip Überspringt die angegebene Anzahl von Zeichen. Das folgende
Script überspringt zum Beispiel die ersten 23 Zeichen der Eingabe
Wscript.StdIn.Skip(23)
Do Until Wscript.StdIn.AtEndOfLine
strInput = Wscript.StdIn.Read(1)
Wscript.Echo strInput
Do Until Wscript.StdIn.AtEndOfLine
strInput = Wscript.StdIn.Read(1)
Wscript.Echo strInput
Loop
AtEndOfStream Ein Boolean-Wert, der anzeigt, ob das Ende der Eingabe erreicht
wurde. Er zeigt einem Script zum Beispiel das Ende von
einem Kommandozeilentool, von einer Batchdatei oder den
von einem über einen Shellbefehl ausgegebenen Text an.
Mit StdIn können Sie Eingaben von Benutzern entgegennehmen. Hierzu gehen Sie
folgendermaßen vor:
1.Verwenden Sie die Methode Write, um eine Eingabeaufforderung anzuzeigen (zum Beispiel
"Bitte geben Sie Ihren Namen ein:"). Mit dieser Methode stellen Sie sicher, dass die
Eingabeaufforderung und die Eingabe des Benutzers in derselben Zeile angezeigt werden
(bei einer Ausgabe mit Write wird kein Zeilenumbruch an die Ausgabe angehängt). Eine
solche Ausgabe sieht dann zum Beispiel so aus (der Unterstrich repräsentiert den Cursor):
C:\Scripts Please enter your name: _
2.Verwenden Sie dann die Methode ReadLine, um die Eingaben des Benutzers einzulesen,
und speichern Sie diese Eingaben in einer Variablen. Mit ReadLine werden die Eingaben so
lange eingelesen, bis der Benutzer ENTER drückt. Wenn Sie zum Beispiel Klaus Meyer
eingeben und dann ENTER drücken, dann wird in der Variable der Wert "Klaus Meyer"
gespeichert. Mit ReadLine können Sie allerdings nicht mehr als 254 Zeichen am Stück
einlesen.
Stellen Sie sich zum Beispiel vor, Sie möchten ein Script erstellen, das Zahlen aus dem
dezimalen Format in das hexadezimale Format konvertiert. Sie müssen den Benutzer eine
Anmerkung: Vielleicht ist Ihnen aufgefallen, das die Eigenschaft Length mit der Methode
Count gleichbedeutend ist. Die Eigenschaft Length wurde nur aufgenommen, um der
ECMAScript-Sprachspezifikation zu entsprechen (Standard ECMA-262), auf der auch JScript
basiert. Auch wenn Sie unter VBScript sowohl Count als auch Length verwenden können,
müssen Sie unter JScript explizit Length verwenden.
•
Item(n) - Gibt das Element mit der angegebenen Indexnummer (n) der Collection
WshArguments zurück.
Unbenannte Kommandozeilenargumente
Unbenannte (Unnamed) Argumente bestehen nur aus einem einzelnen Wert. Solange die
Reihenfolge der Argumente nicht egal ist (zum Beispiel, wenn drei Computernamen
angegeben werden und es egal ist, welcher Computer als Erstes abgefragt wird), müssen die
Argumente in der vom Script erwarteten Reihenfolge angegeben werden.
Unbenannte Argumente können Sie in den folgenden Fällen verwenden:
•
Wenn das Script nur ein oder zwei Argumente verwendet - zum Beispiel den Namen eines
Ordners. In diesem Fall gibt es keinen Grund, benannte (Named) Argumente zu verwenden.
•
Wenn im Script alle Argumente gleich behandelt werden - wenn Sie zum Beispiel die
Ereignisprotokolle auf bestimmten Computern abfragen wollen, dann können Sie für die
Computernamen unbenannte Argumente verwenden.
Wenn Sie ein Script mit unbenannten Argumenten ausführen, dann werden diese von WSH in
der Collection WshArguments gespeichert - und zwar in der Reihenfolge, in der Sie bei
Scriptstart angegeben wurden. Sie können im Script über die Indexnummern auf die
Argumente zugreifen. Diese beginnen bei 0.
Script 3.7 verwendet die Collection-Arguments zur Anzeige der verwendeten Argumente.
1strServer = WScript.Arguments.Item(0)
2strPacketSize = WScript.Arguments.Item(1)
3strTimeout = WScript.Arguments.Item(2)
4
Benannte Kommandozeilenargumente
Wie das vorhergehende Beispiel zeigt, ist die Reihenfolge der Argumente bei unbenannten
Argumenten für die erfolgreiche Ausführung des Scripts entscheidend. Der Aufruf des Scripts
wird so unnötig kompliziert. Der Benutzer muss sich nicht nur an die Parameter, sondern auch
noch an deren Reihenfolge erinnern. Kommt es in diesem Zusammenhang zu einem Fehler,
schlägt das Script fehl.
Um den Aufruf von Scripten mit mehreren Argumenten zu vereinfachen, können Sie benannte
Argumente verwenden. Benannte Argumente sind die Argumente, die aus einem Namen und
einem dazugehörigen Wert bestehen (zum Beispiel /s:DCServer01). Sie können in jeder
beliebigen Reihenfolge angegeben werden.
Ein benanntes Argument beginnt im mit einem Slash (/) und dem Namen des Arguments.
Dann folgt durch einen Doppelpunkt vom Namen getrennt der Wert des Arguments. Die
folgende Befehlszeile führt ein Script mit dem Namen ServerTest.vbs mit zwei benannten
Argumenten aus:
ServerTest.vbs /Server:HRServer01 /Timeout:3000
Der Name des ersten Arguments lautet Server - sein Wert ist HRServer01. Der Name des
zweiten Arguments lautet Timeout und sein Wert ist 3000. Diese beiden Argumente könnten
auch in umgekehrter Reihenfolge angegeben werden:
1iNumberOfArguments = WScript.Arguments.Count
2If iNumberOfArguments >= 2 And iNumberOfArguments <= 4 Then
3 Wscript.Echo iNumberOfArguments & " arguments entered. " & _
4 "Gültige Argumentzahl."
1 iNumberOfArguments = WScript.Arguments.Count
2 Set colNamedArguments = WScript.Arguments.Named
3
4 If Not colNamedArguments.Exists("Server") Then
5 Wscript.Echo "Verwendung: /Server:<servername> ist
6 erforderlich."
7 Wscript.Quit
8 ElseIf iNumberOfArguments >= 2 Or iNumberOfArguments <= 4 Then
9 Wscript.Echo iNumberOfArguments & " Argumente angegeben"
10 Wscript.Echo "inklusive Servername: " & _
11 colNamedArguments.Item("Server")
12Else
13 Wscript.Echo "Verwendung: Geben Sie 2 bis 4 Argumente an."
14 Wscript.Quit
End If
Die folgende Befehlszeile versucht das Script ohne das Argument Server auszuführen:
CheckReqArgs.vbs 1000 300
Das Script produziert die folgende Ausgabe:
Verwendung: /Server:<servername> ist erforderlich.
Die nächste Befehlszeile startet das Script mit dem erforderlichen Argument:
CheckReqArgs.vbs /Server:HRServer01 1000 300
Das Script produziert die folgende Ausgabe:
3 Argumente angegeben
Inklusive Servername: HRServer01
1 strComputer = "."
2 Set objWMIService = GetObject("winmgmts:" _
3 & "{impersonationLevel=impersonate}!\\" & strComputer &
4 "\root\cimv2")
5 Do While True
6 Set colDisks = objWMIService.ExecQuery _
7 ("SELECT * FROM Win32_LogicalDisk")
8 For Each objDisk in colDisks
9 Wscript.Echo "DeviceID: " & objDisk.DeviceID
10 Wscript.Echo "Freier Festplattenplatz: " & objDisk.FreeSpace
11 Next
12 Wscript.Sleep 300000
Loop
Anmerkung: Das Script wird unendlich ausgeführt. Um es zu beenden, müssen Sie den
Prozess beenden, unter dem das Script ausgeführt wird (WScript.exe oder CScript.exe).
1Wscript.Timeout = 5
2Wscript.Sleep 60000
3Wscript.Echo "Script is finished."
WSH-Umgebungsvariablen abfragen
Das Objekt WScript stellt über einige Eigenschaften Informationen zur Verfügung, die Ihnen
zum Beispiel mitteilen, welcher Script Host verwenden wurde und welches Script ausgeführt
wurde. Diese Metadaten sehen Sie in Tabelle 3.7.
Anmerkung: Warum nur die letzten 11 Zeichen? Der Wert von FullName hängt davon ab,
wo der WSH installiert wurde - er könnte "C:\Winnt\System32\CScript.exe" oder auch
"E:\Windows\System32\Wscript.exe" sein. Die letzten 11 Zeichen enthalten jedoch immer
den Text 'Wscript.exe' oder 'Cscript.exe'.
Das folgende Codestück prüft, welcher Script Host installiert ist und beendet das Script, wenn
es sich im WSCRIPT.EXE handelt:
If UCase(Right(Wscript.FullName, 11)) = "WSCRIPT.EXE" Then
Wscript.Echo "Dieses Script muss unter CScript ausgeführt werden."
Wscript.Quit
End If
Script 3.14 zeigt alle verfügbaren WSH-Umgebungsinformationen an.
Programme ausführen
Eine wichtige Lektion, die Sie über Scripting lernen müssen ist: Scripting ist nicht die
Antwort auf Ihre gesamten administrativen Anforderungen.
Erstens deckt Scripting nicht 100 Prozent aller administrativen Aufgaben ab - Sie sind zum
Beispiel nicht in der Lage, die Offline-Eigenschaften von Ordnern festzulegen. Eine solche
Aufgabe müssen Sie weiterhin über die GUI oder über Net.exe durchführen.
Und zweitens gibt es keinen Grund ein Script zu schreiben, wenn es bereits ein Tool gibt, das
Ihren Bedürfnissen entspricht. Nehmen wir an, Sie benötigen eine Liste der in einem Ordner
auf dem lokalen Computer gespeicherten Dateien. Sie können entweder viel Zeit aufwenden,
um ein entsprechendes Script zu schreiben - oder Sie können den Befehl dir eingeben.
WSH-Scripte können zwar Aufgaben automatisieren, sie ersetzten jedoch nicht alle
Kommandozeilentools und Batchdateien, die Sie bis jetzt verwendet haben. Wenn Sie eine
Batchdatei für eine Aufgabe haben, dann gibt es keinen Grund ein Script zu erstellen, das die
gleiche Aufgabe ausführt.
Andererseits möchten Sie möglicherweise die Fähigkeiten einer Batchdatei mit den
Möglichkeiten der WSH-Scriptumgebung kombinieren. Stellen Sie sich zum Beispiel vor,
dass Sie ein Programm zum Aufräumen der Festplatte nur dann ausführen wollen, wenn der
freie Platz auf der Festplatte unter einen bestimmten Wert sinkt. Dies ist mit einer Batchdatei
schwer möglich - mit einem WSH-Script jedoch ganz einfach. Den freien Festplattenplatz
können Sie über das Objekte FileSystemObject oder über WMI abfragen und dann das
Programm zum Aufräumen der Festplatte starten.
Ein Vorteil des WSH ist es, dass Sie sich nicht zwischen WSH oder Batchdatei und
Kommandozeilentools entscheiden müssen. Mit dem WSH schließen sich die beiden Ansätze
nicht gegenseitig aus - stattdessen ergänzen sie sich gegenseitig. Sie können zum Beispiel die
Methoden Run und Exec des Objekts WshShell verwenden, um Batchdateien oder
Kommandozeilentools auszuführen.
Tabelle 3.9: Werte für den Parameter Window-Stil der Methode Run
WertBeschreibung
0 Verstecktes Fenster
1 Aktiviert das Fenster und zeigt es an. Wenn das Fenster
minimiert oder maximiert ist, werden Originalgröße und
-position des Fensters wiederhergestellt.
2 Aktiviert das Fenster und zeigt es minimiert an.
3 Aktiviert das Fenster und zeigt es maximiert an.
4 Zeigt das Fenster mit seiner letzten Größe und Position an.
Das aktive Fenster bleibt aktiv.
5 Aktiviert das Fenster und zeigt es mit seiner aktuellen
Größe und Position an.
6 Minimiert das Fenster und aktiviert das nächste Fenster in Z-Reihenfolge.
Bei der Z-Reihenfolge handelt es sich um eine Liste, in der die
Fenster aktiviert werden. Sie können die Liste sehen, wenn Sie ALT+TAB drücken.
7 Zeigt das Fenster minimiert an. Das aktive Fenster bleibt aktiv.
8 Zeigt das Fenster in seinem Zustand an. Das aktive Fenster bleibt aktiv.
9 Aktiviert das Fenster und zeigt es an. Wen das Fenster minimiert
oder maximiert ist, dann werden seine Originalgröße und
-position wiederhergestellt.
10 Setzt den Anzeigezustand des Fensters auf Basis des
1Const MAXIMIZE_WINDOW = 3
2Set objShell = WScript.CreateObject("WScript.Shell")
3objShell.Run "notepad.exe", MAXIMIZE_WINDOW
Anmerkung: Der Parameter Windows-Stil wird nicht von allen Anwendungen verarbeitet.
Die Systemsteuerung (control.exe) wird zum Beispiel immer in der gleichen Form geöffnet -
egal welcher Fensterstil im Script definiert wurde.
Die Methode Run akzeptiert noch einen dritten Parameter. Dieser muss ein Boolean-Wert
(also nur True oder False) sein. Wenn der Wert False ist (die Standardeinstellung), dann
kümmert sich Run nicht darum, ob das Programm ausgeführt wird. Wenn der Wert auf True
gesetzt ist, dann wartet das Script darauf, dass das Programm beendet wurde. Wenn Sie den
Wert auf False setzen, dann können Sie also gleich mehrere Programme starten.
Das folgende Script führt den Windows-Taschenrechner aus und wartet dann, bis dieser
beendet wurde. Erst dann wird die nächste Zeile ausgeführt. Wenn der Taschenrechner nicht
geschlossen wird, dann wird Zeile 3 nicht ausgeführt:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("calc.exe"),1,True
Wscript.Echo "Script completed."
Anmerkung: Der WSH verfolgt die gestarteten Instanzen von Programmen. Wenn Sie den
Taschenrechner zum Beispiel über ein Script starten, und dann den Taschenrechner noch
einmal per Hand starten, dann wird das Script erst dann weiter ausgeführt, wenn Sie die vom
Script gestartete Instanz des Taschenrechners beenden.
Script 3.16: Ausführen einer Anwendung und Zugriff auf deren Ausgabe
ALT
STRG
HOCHSTELLTASTE
Ctrl + 9
Anmerkung: Auch wenn Sie keine Eigenschaften angeben, wird ein Symbol auf dem
Desktop erstellt. Hierbei handelt es sich dann jedoch nicht um eine funktionierende
Verknüpfung - wenn Sie doppelt auf das Symbol klicken passiert nichts (Sie erhalten nicht
einmal eine Fehlermeldung). Für eine funktionierende Verknüpfung müssen Sie mindestens
die Eigenschaft TargetPath definieren.
URL-Verknüpfungen erstellen
Zum Erstellen von URL-Verknüpfungen sind die gleichen drei Schritte erforderlich:
1.Eine Instanz des Objekts WshURLShortcut über die Methode CreateShortcut() erstellen.
Der Methode muss der Pfad für die neue Verknüpfungsdatei übergeben werden.
2.Festlegen der Eigenschaften des neuen WshURLShortcut-Objekts.
3.Aufrufen der Methode WshURLShortcut.Save.
Script 3.18 erstellt eine Verknüpfung auf dem Desktop, die auf die MSDN®-Website
verweist. Diese Verknüpfung ist nur für die Benutzer sichtbar, die das Script ausgeführt
haben. Das liegt daran, dass sie im Desktopordner des angemeldeten Benutzers, und nicht im
Desktopordner für alle Benutzer erstellt wird.
Anmerkung: Über die Collection SpecialFolders können Sie zwar den Pfad des Ordners
abfragen, Sie haben jedoch keine Möglichkeit, diese Ordner oder deren Inhalte zu ändern.
Hierzu können Sie zum Beispiel das Objekt FileSystemObject verwenden. Weitere
Informationen zu diesem Objekt finden Sie im Kapitel Script Runtime Primer.
Umgebungsvariablen
Der Windows-Shellprozess verwendet einige Umgebungsvariablen, deren Inhalte Ihnen in
Ihrem Script nützen können:
Vorsicht: Wenn Sie mit Ihrem Script Änderungen an der Registrierung vornehmen, dann
kann dies zu Problemen führen oder sogar eine Neuinstallation von Windows erforderlich
machen. Daher sollten Sie vor einer Registrierungsänderung eine Sicherung vornehmen.
Weitere Informationen finden Sie in der Registrierungsreferenz im Microsoft Windows 2000
Server Resource Kit unter http://www.microsoft.com/windows2000/techinfo/reskit/en-
us/default.asp?url=/windows2000/techinfo/reskit/en-us/regentry/default.asp
(englischsprachig).
Registrierungseinträge lesen
Die Registrierung ist die primäre Konfigurationsdatenbank von Windows - die korrekte
Ausführung vieler Betriebssystemkomponenten hängt von Registrierungseinstellungen ab.
Als Systemadministrator verbringen Sie wahrscheinlich des Öfteren Zeit damit, Werte in der
Registrierung zu überprüfen. Diese Registrierungswerte können Sie entweder direkt über ein
Tool wie regedit.exe oder über ein Script mit der Methode WshShell.RegRead auslesen.
In den meisten Fällen benötigen Sie hierzu nur zwei Dinge: Erstens eine Instanz des Objekts
Wscript.Shell und zweitens die Methode RegRead. Die Betriebssystemversion wird zum
Beispiel unter dem Registeriungsschlüssel HKLM\Software\Microsoft\Windows
NT\CurrentVersion\CurrentVersion gespeichert - Sie können sie über das folgende Script
abfragen:
Set objShell = WScript.CreateObject("WScript.Shell")
sngVersion = objShell.RegRead _
("HKLM\Software\Microsoft\Windows NT\CurrentVersion\CurrentVersion")
Wscript.Echo sngVersion
Datentypen in der Registrierung
Jeder in der Registrierung gespeicherte Wert hat einen eindeutigen Datentyp. In Tabelle 3.15
sehen Sie die von WSH unterstützten Registrierungstypen und die VBScript-Datentypen, in
die diese von RegRead übersetzt werden.
Anmerkung: Unglücklicherweise haben Sie mit dem WSH keine Möglichkeit, den Datentyp
eines Registrierungseintrages vor dem Auslesen festzustellen - über WMI ist dies jedoch
möglich.
Script 3.27 verwendet die Methode RegRead, um einen Registrierungswert vom Datentyp
Multistring (REG_MULTI_SZ) auszulesen. Die Informationen werden als String-Array
zurückgegeben, der in einer For-Each-Schleife ausgegeben wird.
Anmerkung: Der Datentyp REG_MULTI_SZ wird von der Methode RegWrite nicht
unterstützt.
Registrierungseinträge löschen
Anmerkung: Mit SendKeys können Sie auch wiederholte Tastatureingaben simulieren. Wenn
Sie zum Beispiel 10x die Taste a simulieren möchten, dann können Sie {a 10} als Parameter
verwenden. Zwischen dem Zeichen und der Zahl muss sich in diesem Fall zwingend ein
Leerzeichen befinden. Es ist jedoch nicht möglich mehrere Tastatureingaben zu wiederholen.
Der Parameter {dog 10} führt also zu einem Fehler.
Sie sollten daran denken, dass eine Tastatureingabe nicht die optimale Möglichkeit ist, um
eine Anwendung zu kontrollieren. Wenn Sie mit einer Anwendung arbeiten, die nicht COM-
fähig ist, dann leisten sie natürlich gute Dienste - und in allen anderen Fällen sollten Sie
jedoch versuchen, die COM-Objekte zu verwenden.
Mit SendKeys können eine Menge unterschiedlicher Probleme auftreten:
•
Es kann schwer sein, die Tastatureingaben an das richtige Fenster zu schicken.
•
Da die Zielanwendung im GUI-Modus ausgeführt wird, ist es möglich, dass ein Benutzer die
Anwendung einfach schließt. Unglücklicherweise bricht das Script in einem solchen Fall
jedoch nicht ab - die Tastatureingaben werden einfach an eine falsche Anwendung geschickt.
1 Const iNormalFocus = 1
2 Set objShell = WScript.CreateObject("WScript.Shell")
3 objShell.Run "mmc.exe",iNormalFocus
4
5 Wscript.Sleep 300
6
7 objShell.AppActivate "Konsole1"
8 Wscript.Sleep 100
9 objShell.SendKeys "^m"
10Wscript.Sleep 100
11objShell.SendKeys "{TAB}"
12Wscript.Sleep 100
13objShell.SendKeys "{TAB}"
14Wscript.Sleep 100
15objShell.SendKeys "{TAB}"
1Const TIMEOUT = 5
1 Const TIMEOUT = 5
2 Const POPUP_TITLE = "Symbole und Schalter "
3 Set objShell = WScript.CreateObject("WScript.Shell")
4 objShell.Popup "Stop / Abbrechen, Wiederholen und Ignorieren ", _
5 TIMEOUT,POPUP_TITLE,vbCritical+vbAbortRetryIgnore
6
7 objShell.Popup "Fragezeichen/ Ja, Nein und Abbrechen ", _
8 TIMEOUT,POPUP_TITLE,vbQuestion+vbYesNoCancel
9
10objShell.Popup "Ausrufungszeichen / Ja und Nein ", _
11 TIMEOUT,POPUP_TITLE,vbExclamation+vbYesNo
12
13objShell.Popup "Information / Wiederholen und Abbrechen ", _
14 TIMEOUT,POPUP_TITLE,vbInformation+vbRetryCancel
In den Zeilen 4-14 wird die Methode WshShell.Popup vier Mal aufgerufen, um
Nachrichtenfenstern mit unterschiedlichen Symbolen und Schaltern anzuzeigen. Als dritter
Parameter wird immer die Konstante POPUP_TITLE übergeben - der Titel der
Nachrichtenfenster lautet daher immer Symbole und Schalter. Als vierter Parameter werden
Konstanten für die unterschiedlichen Schalter und Symbole übergeben. Die beiden
Konstanten werden einfach addiert.
1Const TIMEOUT = 5
2Set objShell = WScript.CreateObject("WScript.Shell")
3
4objShell.Popup "Kein Standarschalter." _
5 ,TIMEOUT,,vbAbortRetryIgnore
6
7objShell.Popup "Wiederholen ist der Standardschalter." _
8 ,TIMEOUT,,vbAbortRetryIgnore+vbDefaultButton2
Benutzereingaben abfragen
Ein Vorteil der Methode Popup ist, dass Sie dem Benutzer eine Auswahl ermöglichen
können. Das bedeutet natürlich auch, dass sich Ihr Script darum kümmern muss, auf welchen
Schalter der Benutzer geklickt hat. Popup gibt hierzu einen Integerwert zurück (wenn das
Fenster durch den Timeout-Wert geschlossen wird, ist der Rückgabewert -1). Eine Auflistung
der Rückgabewerte für die einzelnen Schalter finden Sie in Tabelle 3.20.
Die folgenden beiden Codezeilen prüfen beide, ob der Benutzer auf den Schalter OK geklickt
hat:
If intClicked = 1
If intClicked = vbOK
Tabelle 3.20: Konstanten für Schalter
WertKonstanteSchalter
1 VbOK OK
2 VbCancel Abbrechen (bei OK, Abbrechen)
3 VbAbort Abbrechen (bei Wiederholen, Abbrechen, Ignorieren)
4 VbRetry Wiederholen
5 VbIgnore Ignorieren
6 VbYes Ja
7 VbNo Nein
Script 3.35 zeigt ein Nachrichtenfenster mit den Schaltern Ja und Nein an. Es stellt dem
Benutzer über das Objekt FileSystemObject Informationen über den Host zur Verfügung, über
1 Const TIMEOUT = 7
2 Set objShell = WScript.CreateObject("WScript.Shell")
3 Set objFS = WScript.CreateObject("Scripting.FileSystemObject")
4
5 strPath = Wscript.FullName
6 strFileVersion = objFS.GetFileVersion(strPath)
7
8 iRetVal = objShell.Popup(Wscript.FullName & vbCrLf & _
9 "File Version: " & _
10 strFileVersion & vbCrLf & _
11 "Möchten Sie mehr wissen?" _
12 ,TIMEOUT,"Weitere Informationen?",vbYesNo + vbQuestion)
13
14Select Case iRetVal
15 Case vbYes
16 Set objFile = objFS.GetFile(strPath)
17 objShell.Popup WScript.FullName & vbCrLf & vbCrLf & _
18 "Dateiversion: " & strFileVersion & vbCrLf & _
19 "Dateigröße: " & Round((objFile.Size/1024),2) & _
20 " KB" & vbCrLf & _
21 "Erstellungsdatum: " & objFile.DateCreated & vbCrLf & _
22 "Letzte Änderung: " & objFile.DateLastModified & _
23 vbCrLf,TIMEOUT
24 Wscript.Quit
25 Case vbNo
26 Wscript.Quit
27 Case -1
28 WScript.StdOut.WriteLine "Time-Out"
29 Wscript.Quit
30End Select
EnumNetworkDrives
RemoveNetworkDrive
Arbeiten mit Netzwerkdruckern AddPrinterConnection
AddWindowsPrinterConnection
EnumPrinterConnections
SetDefaultPrinter
RemovePrinterConnection
Informationen über den angemeldetenComputerName
Benutzer abrufen
UserDomain
UserName
WshNetwork ist Teil des Windows Script Host-Objektmodells (wshom.ocx). Das
Objektmodell von WshNetwork sehen Sie in Abbildung 3.15. Über die Methoden
EnumNetworkDrives und EnumPrinterConnections des Objekts erhalten Sie unter anderem
das Objekt WshCollection zurück.
Netzwerkdrucker hinzufügen
Es gibt zwei Methoden zum Hinzufügen von Netzwerkdruckern:
AddWindowsPrinterConnection und AddPrinterConnection.
Mit der Methode AddWindowsPrinterConnection fügen Sie Windows-basierte Drucker hinzu
(zum Beispiel so wie über den Assistenten Drucker hinzufügen der Systemsteuerung), und mit
der Methode AddPrinterConnection fügen Sie eine MS-DOS-basierten Drucker hinzu.
Script 3.40: Zuordnen von Netzwerklaufwerken abhängig von der Domäne des
Benutzers
Vorsicht: Wenn Sie die Registrierung über ein Script ändern, kann es leicht zu Problemen
kommen - Ihr System könnte beschädigt werden oder es könnte sogar eine komplette
Neuinstallation erforderlich werden. Bevor Sie Registrierungsänderungen über ein Script
vornehmen, sollten Sie das Script ausführlich testen und die Registrierung auf den
Zielcomputern sichern. Weitere Informationen zu Registrierungsänderungen über Scripte
finden Sie in der Registry Reference des Windows 2000 Server Resource Kit unter
http://www.microsoft.com/reskit (englischsprachig).
Script 3.41 verwendet den WMI-Provider Registry, um den Eintrag Remote zur Registrierung
des in der Variable strComputer definierten Computers hinzuzufügen und diesen auf den
Wert 1 zu setzen.
1 strRemoteComputer = "RASServer01"
2 strWorkerScript = "MapNetworkDrive.vbs"
3 Set objWshController = WScript.CreateObject("WshController")
4 Set objRemoteScript = _
5 objWshController.CreateScript(strWorkerScript, strRemoteComputer)
6 objRemoteScript.Execute
7
8 Do While Not objRemoteScript.Status = 2
9 Wscript.Sleep(100)
10 Wscript.Echo "Remote script not yet complete."
11Loop
Anmerkung: Ein Remotezugriff ist kein interaktiver Prozess - das bedeutet, dass
Remotescripte keine GUI-Elemente auf dem Remotecomputer anzeigen können. Wenn Sie
dies versuchen, schlägt das Script fehl oder produziert unerwartete Ergebnisse - ein
Nachrichtenfenster ist zum Beispiel nicht zu sehen.
1 strRemoteComputer = "RASServer01"
2 strWorkerScript = "CreateTextFilMapNetworkDrive.vbs"
3
4 Set objWshController = WScript.CreateObject("WshController")
5 Set objRemoteScript =_
6 objWshController.CreateScript(strWorkerScript, strRemoteComputer)
7 Wscript.ConnectObject objRemoteScript, "Remote_"
8 objRemoteScript.Execute
9
10Do While Not objRemoteScript.Status = 2
11 Wscript.Sleep(100)
12Loop
13
14Sub Remote_Start
15 Wscript.Echo "Start des Remotescripts."
16End Sub
17
18Sub Remote_Error
19 Wscript.Echo "Fehler im Remotescript."
20 objRemoteScript.Terminate
21 Wscript.Quit
22End Sub
23
24Sub Remote_End
25 Wscript.Echo "Beendigung des Remotescripts."
26End Sub
Wenn alles wie erwartet funktioniert, werden nur die Ereignisse Start und End ausgelöst - im
Fall eines Fehlers wird das Ereignis Error ausgelöst. Weitere Informationen zur Abfrage von
weiteren Fehlerdetails finden Sie im folgenden Abschnitt.
1 strRemoteComputer = "RASServer01"
2 strWorkerScript = "CreateTestFile.vbs"
3
4 Set objWshController = WScript.CreateObject("WshController")
5 Set objRemoteScript =_
6 objWshController.CreateScript(strWorkerScript, strRemoteComputer)
7 Wscript.ConnectObject objRemoteScript, "Remote_"
8 objRemoteScript.Execute
9
10Do While Not objRemoteScript.Status = 2
11 Wscript.Sleep(100)
12Loop
13
14
15Sub Remote_Error
16 Wscript.Echo "Fehler im Remotescript."
17 Set objError = objRemoteScript.Error
18 Wscript.Echo "Character :" & objError.Character
19 Wscript.Echo "Description :" & objError.Description
20 Wscript.Echo "Line :" & objError.Line
21 Wscript.Echo "Number :" & objError.Number
22 Wscript.Echo "Source :" & objError.Source
23 Wscript.Echo "Source Text :" & objError.SourceText
Wichtig: Sicherheit betrifft noch andere Elemente. Es stimmt zwar, dass Hacker oft mit
Scripten arbeiten, aber sie stellen nicht die einzige Sicherheitsbedrohung dar. Auch
ausführbare Dateien und Batchdateien können missbraucht werden. Die in diesem Kapitel
besprochenen Techniken können als Teil eines Sicherheitsplans eingesetzt werden - sie sollten
jedoch nicht den ganzen Sicherheitsplan darstellen.
wscript.exe DeleteFiles.vbs
cscript.exe DeleteFiles.vbs
Trotzdem gibt Ihnen die Methode ein wenig zusätzliche Sicherheit - die Benutzer haben
immerhin die Möglichkeit, die Ausführung eines potentiell gefährlichen Scripts abzubrechen.
Ohne diese Option würde das Script einfach ohne Warnung gestartet.
Die Registrierungsanpassung können Sie mit der folgenden Batchdatei vornehmen:
reg copy HKCR\VBSFile\Shell HKCR\VBSFile\bkupShell /s /f
reg delete HKCR\VBSFile\Shell /f
reg add HKCR\VBSfile\ /v NoOpen /t REG_SZ /d " Führen Sie dieses Script
nicht aus, wenn
es nicht von der IT-Abteilung freigegeben wurde."
Die Standardfunktionalität können Sie mit der folgenden Batchdatei wiederherstellen:
reg copy HKCR\VBSFile\bkupShell HKCR\VBSFile\Shell /s /f
reg delete HKCR\VBSFile\bkupShell /f
reg delete HKCR\VBSFile /v NoOpen /f
Die Batchdatei führt die folgenden Schritte durch:
Wichtig: Wenn Sie die Warnmeldung verwenden, könnte dies zu Problemen bei An- und
Abmeldescripten führen - nämlich dann, wenn bei der Scriptausführung die Warnmeldung
angezeigt wird. Um dieses Problem zu umgehen, können Sie das Script zum Beispiel aus
einer Batchdatei heraus starten.
Script Laufzeitbibliothek-Übersicht
Es gibt zwei primäre Microsoft-Scriptsprachen: Microsoft Visual Basic Scripting Edition
(VBScript) und Microsoft JScript. Diese wurden ursprünglich als clientseitige Scriptsprachen
für den Microsoft Internet Explorer entworfen. Daher gibt es einige Einschränkungen bei den
beiden Sprachen. Weder VBScript noch JScript verfügen zum Beispiel über Methoden, um
Dateioperationen wie das Kopieren, Verschieben oder Löschen von Dateien durchzuführen.
Diese Einschränkungen wurden ursprünglich zum Schutz der Kunden durchgeführt: Die
meisten Besucher einer Website fänden es sicher nicht sehr nett, wenn ein Script auf einer
Webseite Dateien von ihrer Festplatte löschen würde.
Die Scripting-Technologie hat sich jedoch von einer clientseitigen Technologie, die
hauptsächlich für Webseitenelemente verwendet wurde, deutlich weiterentwickelt. Mit der
Einführung von ASP (Active Server Pages) benötigten Webentwickler, die Möglichkeit
Dateioperationen durchzuführen - und mit der Einführung des WSH (Windows Script Host)
wurden Dateioperationen außerhalb des Webbrowsers erforderlich.
Als Reaktion auf diese Anforderungen veröffentlichte Microsoft die Script Runtime Library.
Hierbei handelt es sich um eine einzelne DLL (dynamic-link library) mit dem Namen
scrrun.dll, die Scriptautoren in die Lage versetzt, mit dem Dateisystem zu arbeiten. Sie
implementiert die folgenden Möglichkeiten:
•
Abrufen von Informationen über Elemente des Dateisystems (inklusive Laufwerke, Dateien
und Ordner)
•
Kopieren, Verschieben und Löschen von Dateien und Ordnern
•
Erstellen, Lesen und Schreiben von Textdateien
Außerdem ermöglicht die Script Runtime Library das Erstellen von Dictionaries
(Datenstrukturen, die wie Collections funktionieren) und das Kodieren von Scripten (kodierte
Scripte können nicht ohne weiteres gelesen werden und schützen so Ihr geistiges Eigentum).
14
25
3Set objFSO = CreateObject("Scripting.FileSystemObject")
4Set colDrives = objFSO.Drives
5For Each objDrive in colDrives
6 Wscript.Echo "Laufwerksbuchstabe: " & objDrive.DriveLetter
7Next
Eine komplette Liste aller Eigenschaften des Objekts FileSystemObject finden Sie in Tabelle
4.2 weiter unten in diesem Kapitel.
1 - Wechsellaufwerk
2 - Festplatte
3 - Netzlaufwerk
4 - CD-ROM
5 - RAM-Laufwerk
FreeSpace Im Gegensatz zu AvailableSpace gibt diese Eigenschaft den gesamten zur
Verfügung stehenden freien Festplattenplatz in Byte zurück.
FileSystem Der Typ des verwendeten Dateisystems (FAT, FAT 32, NTFS).
IsReady Gibt an, ob auf das Laufwerk zugegriffen werden kann. Wenn sich zum
Beispiel keine CD im CD-Laufwerk oder keine Diskette im Diskettenlaufwerk
Anmerkung: Mit WMI gibt es solche Probleme nicht. Wenn sich kein Medium im Laufwerk
befindet schlägt das Script hier nicht fehl - stattdessen gibt WMI den freien Speicherplatz
einfach mit Null an.
Anmerkung: Das Objekt FileSystemObject kann nur Ordner auf dem lokalen Computer
erstellen. Wenn Sie Ordner auf einem Remotecomputer erstellen müssen, dann müssen Sie
das Objekt WshController verwenden. Alternativ können Sie den Ordner lokal erstellen und
ihn dann über WMI auf den Remotecomputer verschieben (den Ordner müssen Sie jedoch
über FileSystemObject erstellen, da WMI keine Ordner erstellen kann).
Anmerkung: Die Methode CopyFolder hält in dem Moment an, in dem sie auf einen Fehler
stößt - auch wenn der Befehl On Error Resume Next verwendet wird. Wenn also von 100 zu
kopierenden Ordnern erst drei kopiert wurden, bevor ein Fehler auftritt, dann werden die
restlichen 97 Ordner nicht mehr kopiert.
Script 4.9 verwendet die Methode CopyFolder, um die Inhalte von C:\Scripts nach C:\FSO zu
kopieren. Hierbei werden alle bestehenden Ordner im Zielordner überschrieben. Es wird kein
Ordner mit dem Namen C:\FSO\Scripts erstellt - stattdessen enthält der Ordner C:\FSO alle
Anmerkung: Da es sich bei CopyFolder um einen einzelnen Vorgang handelt, gibt es keine
Möglichkeit, ihren Fortschritt zu überwachen. Sie können nur abwarten, bis die
Kopieroperation beendet ist. Wenn Sie den Fortschritt der Kopieroperation überwachen
möchten, dann sollten Sie stattdessen das Objekt Shell.Application verwenden. Dieses Objekt
wird im Abschnitt Dateien und Ordner besprochen.
Ordner umbenennen
Das Objekt FileSystemObject stellt keine Methode zum Umbenennen von Ordnern zu
Verfügung. Sie können eine solche Operation jedoch über die Methode MoveFolder
durchführen. Stellen wir uns vor, Sie haben den folgenden Pfad:
C:\Scripts\PerformanceMonitoring\Servers\Domain Controllers\Current Logs
Wenn Sie den Ordner über den Windows Explorer umbenennen, bleibt der Pfad gleich - das
Einzige, was sich ändert, ist der letzte Teil:
C:\Scripts\PerformanceMonitoring\Servers\Domain Controllers\Archived
Logs
Mit MoveFolder können Sie das gleiche erreichen, indem Sie den Ordner von
C:\Scripts\PerformanceMonitoring\Servers\Domain Controllers\Current Logs nach
C:\Scripts\PerformanceMonitoring\Servers\Domain Controllers\Archived Logs verschieben.
Das Endergebnis ist exakt das gleiche.
Script 4.11 verwendet MoveFolder, um den Ordner C:\FSO\Samples in C:\FSO\Scripts
umzubenennen.
12
23
3Const DeleteReadOnly = True
4Set objFSO = CreateObject("Scripting.FileSystemObject")
5objFSO.DeleteFile("C:\FSO\*.txt"), DeleteReadOnly
Tipp: Was wenn Sie alle Dateien außer den schreibgeschützten löschen möchten? In diesem
Fall rufen Sie über die Eigenschaft Files des Folder-Objekts eine Liste aller Dateien ab und
gehen diese durch. Hierbei können Sie für jede Datei abfragen, ob sie schreibgeschützt ist und
sie gegebenenfalls löschen.
Textdateien erstellen
Sie haben die Möglichkeit mit vorhandenen Dateien zu arbeiten oder neue Textdateien
anzulegen. Um eine neue Textdatei anzulegen benötigen Sie eine Instanz des Objekts
FileSystemObject. Mit diesem rufen Sie dann die Methode CreateTexFile auf, und übergeben
ihr den Dateinamen der neuen Datei als Parameter.
Script 4.32 erstellt eine neue Textdatei mit dem Namen ScriptLog.txt im Ordner C:\FSO.
Anmerkung: Die von GetTempName generierten Dateien sind nicht auf jeden Fall eindeutig.
Dies liegt teilweise an dem zur Generierung der Dateinamen verwendeten Algorithmus und
teilweise an der endlichen Zahl der möglichen Dateinamen. Die generierten Dateinamen
haben immer acht Zeichen - die ersten drei Zeichen sind immer rad. Es gibt also nur 9.894
eindeutige Dateinamen. Wenn Sie mehr Dateinamen erzeugen, kommt es zwangsläufig zu
Dubletten.
Script 4.34 demonstriert die Verwendung von GetTempName bei der Erstellung einer Datei.
Das Script geht folgendermaßen vor:
1.Es erstellt eine Instanz von FileSystemObject.
2.Es erstellt in der Variablen strPath eine Referenz auf den Ordner, in dem die Datei erstellt
werden soll (C:\FSO).
3.Es verwendet die Methode GetTempName, um einen eindeutigen Dateinamen zu erstellen.
4.Es verwendet die Methode BuildPath, um den Ordnernamen mit dem Dateinamen zu
kombinieren und so einen vollständigen Pfad für die neue Datei zu erstellen. Dieser Pfad
wird in der Variable strFullName gespeichert.
5.Es ruft die Methode CreateTextFile auf und verwendet die Variable strFullName aus dem
Parameter für die Methode.
Nachdem die Datei erstellt wurde, schließt das Script diese sofort wieder. In einem
Produktionsscript würde das Script nun in die Datei schreiben.
Wenn Sie versuchen im Modus ForReading in eine Datei zu schreiben, erhalten Sie den
Fehler 'Falscher Dateimodus'. Auch wenn Sie versuchen andere Dateien als Textdateien zu
öffnen, kommt es zu diesem Fehler (auch bei HTML- und XML-Dateien handelt es sich um
Textdateien).
Als zweiten Parameter können Sie entweder den Wert (zum Beispiel 1) oder eine Konstante
(zum Beispiel ForReading) angeben. Das folgende Script demonstriert beide Methoden:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
1Const ForReading = 1
2Set objFSO = CreateObject("Scripting.FileSystemObject")
3Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", ForReading)
4strContents = objFile.ReadAll
5Wscript.Echo strContents
6objFile.Close
Zeilenweises Lesen einer Textdatei
Seite 224 von 394
Bei der Systemadministration haben Sie es meist mit Textdateien zu tun, die als
'Datenbankersatz' verwendet werden. Jede Textzeile ist hier ein Datensatz. Ein Script könnte
zum Beispiel die Servernamen, auf die es zugreifen soll, aus der Textdatei lesen. Diese
Textdatei wird dann so oder ähnlich aussehen:
atl-dc-01
atl-dc-02
atl-dc-03
atl-dc-04
In einem solchen Fall möchten Sie die Textdatei wahrscheinlich zeilenweise auslesen. Hierzu
steht Ihnen die Methode ReadLine zur Verfügung. Sie verwenden die Methode, indem Sie
eine Do-Loop-Schleife so lange ausführen, bis die Eigenschaft AtEndOfStream den Wert True
hat (das bedeutet, dass das Ende der Datei erreicht wurde). In der Schleife lesen Sie jeweils
eine einzelne Textzeile über die Methode ReadLine ein und führen die gewünschte Aktion
aus.
Script 4.39 demonstriert dieses Verfahren, indem es die Datei C:\FSO\ServerList.txt öffnet
und diese dann zeilenweise einliest.
Script 4.39: Zeilenweises Einlesen einer Datei über die Methode ReadLine
In Textdateien schreiben
Textdateien sind eine sehr gute Möglichkeit Daten dauerhaft zu speichern. Außerdem können
Sie die von einem Script ausgeführten Aktionen in einer Textdatei protokollieren - dies ist
gerade beim Erstellen von Scripten und bei der Fehlersuche sehr praktisch.
Um in eine Datei zu schreiben, muss ein Script folgendermaßen vorgehen:
1.Es erstellt eine Instanz von FileSystemObject.
2.Es verwendet die Methode OpenTextFile, um eine Datei zu öffnen. Hierbei gibt es zwei
Möglichkeiten:
•
ForWriting (2) - In diesem Modus werden die vorhanden Dateien der Textdatei mit den
neuen Daten überschrieben.
•
ForAppending (8) - In diesem Modus werden die neuen Dateien an die bestehenden Daten
1Const ForWriting = 2
2Set objFSO = CreateObject("Scripting.FileSystemObject")
3Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", ForWriting)
4objFile.Write Now
5objFile.Close
Neue Daten an bestehende Daten anhängen
Stellen Sie sich vor, Sie können die Protokolldateien aus dem Beispiel oben nur einmal in der
Woche überprüfen. In diesem Fall möchten Sie sicher nicht, dass das Protokoll vom Vortag
mit dem aktuellen Protokoll überschrieben wird. Stattdessen soll das Script die aktuellen
Daten an die alten Daten anhängen.
Dies können Sie durchführen, indem Sie die Textdatei im Modus ForAppending öffnen. Statt
die Daten zu überschreiben, werden die neuen Daten am Ende der Datei angehängt. Script
4.43 schreibt zum Beispiel das aktuelle Datum und die Uhrzeit in eine Textdatei. Da die Datei
aber im Modus ForAppending geöffnet wird, werden diese neuen Daten an die alten
angehängt. Bei jeder Ausführung kommt so eine Zeile zur Textdatei hinzu. Die Textdatei
sieht nach einigen Ausführungen des Scripts zum Beispiel so aus:
6/25/2002 8:49:47 AM
6/25/2002 8:49:48 AM
6/25/2002 8:50:33 AM
6/25/2002 8:50:35 AM
Script 4.43: Daten an eine Textdatei anhängen
1Const ForAppending = 8
2Set objFSO = CreateObject("Scripting.FileSystemObject")
3Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", ForAppending)
4objFile.WriteLine Now
Das Dictionary-Objekt
Oftmals erhält ein Script Informationen von einer externen Quelle - zum Beispiel aus einer
Textdatei oder einer Datenbank. Diese Informationen müssen irgendwo gespeichert werden.
Natürlich haben Sie die Möglichkeit solche Informationen in einzelnen Variablen oder in
einem Array zu speichern - sehr effektiv ist dies jedoch nicht. Die Alternative wäre ein
Dictionary-Objekt (ein Verzeichnis-Objekt).
Ein Dictionary-Objekt funktioniert wie ein assoziativer Array. Das heißt, es speichert Wert
und Schlüssel in Paaren. Ein Beispiel soll dies verdeutlichen. Ein Array speichert Werte so
(die Zahl stellt den Arrayindex dar):
0 - München
1 - Hannover
2 - Wiesbaden
Ein Dictionary-Objekt könnte die Werte zum Beispiel so speichern:
Bayern - München
Niedersachsen - Hannover
Hessen - Wiesbaden
Alternativ können Sie sich ein Dictionary-Objekt auch wie ein Telefonbuch vorstellen. Es
speichert Namen und die dazugehörigen Telefonnummern. Über die Namen können Sie dann
die Telefonnummern abrufen.
Stellen Sie sich vor, das Script verwendet mehrere Argumente. Sie können diese Argumente
zwar in einem Array speichern, das Dictionary-Objekt bietet jedoch mehrere Vorteile
gegenüber einem Array:
•
Sie müssen nicht festlegen, wie viele Objekte gespeichert werden sollen. Bei einem Array
müssen Sie das Array im Voraus erstellen (oder später vergrößern).
•
Sie müssen keine Indexnummer zum Zugriff auf ein Element verwenden. Stattdessen können
Sie über einen Schlüssel(begriff) auf das Element zugreifen (im Beispiel oben wären das die
Bundesländer - sprich: 'Gib mir die Landeshauptstadt von Hessen zurück' statt "Gib mir das
Element mit der Nummer 2').
Damit ist das Dictionary-Objekt ideal um Informationen zu speichern und diese später wieder
abzufragen.
1Const TextMode = 1
2Set objDictionary = CreateObject("Scripting.Dictionary")
3objDictionary.CompareMode = TextMode
Wenn das Dictionary-Objekt bereits Elemente enthält, können Sie die Eigenschaft
CompareMode nicht mehr verändern. Das liegt daran, weil es sonst zu Inkonsistenzen im
Dictionary-Objekt kommen könnte (zum Beispiel wenn Einträge vorhanden sind, die mit dem
neuen Modus nicht kompatibel sind). Die folgenden Schlüssel könnten im Modus Binär zum
Beispiel im gleichen Dictionary-Objekt gespeichert werden:
apple
ADSI-Überblick
Die Administration von Verzeichnisdiensten über Scripte ist nicht wirklich schwer. Von den
ganzen hierfür erforderlichen Scripting-Fähigkeiten ist ADSI sogar die am einfachsten zu
erlernende.
Warnung: Führen Sie Script 5.1 nicht in einer Produktionsumgebung aus. Sie legen sonst
1.000 Benutzerkonten in dieser Domäne an.
Auf langsamen Domänencontrollern kann das Script bis zu fünf Minuten für seine
Ausführung benötigen.
ADSI-Scripting-Grundlagen
Wir werden uns Scriptbeispiele für die oben definierten grundlegenden Kategorien anschauen
- Erstellen, Ändern, Lesen und Löschen. So werden Sie ein besseres Verständnis für ADSI-
Scripting entwickeln.
Primäre ADSI-Scripting-Kategorien
Erstellen einer OU
Script 5.2 erstellt eine OU mit dem Namen HR in der Domäne na.fabrikam.com. Allen
verpflichtenden Attributen einer OU werden von Active Directory automatisch Werte
zugewiesen. Daher ist dieser Schritt in Script 5.2 nicht erforderlich.
Um die OU zu erstellen, führt das Script die folgenden Schritte aus:
1.Es baut eine Verbindung mit dem Domänen-Container na.fabrikam.com auf.
2.Es erstellt eine OU mit dem Namen HR.
3.Es übermittelt die neue OU an Active Directory.
1Set objUser = _
2 GetObject("LDAP://cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com")
3objUser.Put "description", "HR employee"
4objUser.SetInfo
Ein Attribut eines Benutzerkontos ändern
Script 5.7 ändert das Attribut description der Gruppe mit dem Namen Atl-Users in der OU HR
der Domäne na.fabrikam.com. Dem Attribut wird der Wert Atlanta users zugewiesen. Hierzu
führt das Script die folgenden Aufgaben durch:
1.Es verbindet sich mit dem Gruppenobjekt Atl-Users in der OU HR der Domäne
na.fabrikam.com.
2.Es ändert das Attribut des Objekts, indem es ihm den Wert Atlanta users zuweist.
3.Es überträgt die Änderungen an der Gruppe an Active Directory.
Wichtig: Die nach den Scripten gezeigten Ausgaben werden von CScript erstellt. Wenn Sie
die Scripte ausführen, sollten Sie daher sicherstellen, dass diese unter CScript ausgeführt
werden. Einige der folgenden Scripte erzeugen eine größere Menge an Ausgaben. Wenn Sie
diese Scripte unter WScript ausführen, werden sie eine große Menge an Nachrichtenfenstern
erzeugen.
1Set objGroup = _
2 GetObject("LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com")
3Wscript.Echo objGroup.Get("description")
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, erhalten Sie die folgende
Ausgabe:
Atlanta users
Aus den Scripten in diesem Abschnitt lassen sich die folgenden wichtigen Erkenntnisse
gewinnen:
•
Sie führen alle die gleichen grundlegenden Schritte aus: eine Verbindung mit dem Active
Directory-Objekt aufbauen und ein Attribut des Objekts lesen.
•
Sie verwenden alle die gleiche Methode (Get) - egal welche Klasse das zu lesende Objekt
hat.
Wie Sie in diesem Abschnitt gesehen haben, funktioniert das Lesen von Attributen bei allen
Objekten gleich.
Abbildung 5.1: Schritte zur Durchführung von grundlegenden Aufgaben über ADSI
Mit Abbildung 5.1 und den zwölf gezeigten Scripten können wir nun die folgenden Regeln im
Bezug auf ADSI-Scripte definieren:
•
Unabhängig von der auszuführenden Aufgabe ist Schritt Eins immer die Verbindung (das
Binden) mit einem Objekt oder Container.
Achtung: Bei den ADSI-Providern wird zwischen Groß- und Kleinschreibung unterschieden.
WinNT und winnt ist also in diesem Fall nicht gleichwertig.
Die Funktion GetObject von VBScript verwendet den Provider, um die richtige ADSI-DLL
zu laden - dies ist notwendig, damit das Script auf die entsprechenden Informationen (zum
Beispiel in Active Directory oder in der lokalen Sicherheitsdatenbank) zugreifen kann. Wenn
die DLL geladen ist, dann wird mit dem zweiten Teil des Parameters ADsPath (dem Pfad zum
entsprechenden Objekt) eine Bindung mit dem Objekt aufgebaut.
Anmerkung: Mit Ausnahme des Containers Domain Controllers ist der Typ aller
Standardcontainer einer Active Directory-Domäne (zum Bespiel Computer, Benutzer und
Built-in) CN und nicht OU.
Den wert der einzelnen Pfadteile (attribut=wert)legen Sie beim Erstellen eines Objekts fest.
Nehmen wir zum Beispiel einmal an, wir arbeiten mit dem Benutzer MyerKen in der OU HR
in der Domäne na.fabrikam.com. In Tabelle 5.1 sehen Sie die einzelnen Objektklassen,
Attributtypen und Werte für den DN dieses Benutzers
("cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com").
Fortgeschrittene ADSI-Scripting-Techniken
Anmerkung: Weitere Informationen dazu, wie Sie feststellen können, ob ein Attribut ein
Einzel- oder Mutiwert-Attribut ist, finden Sie im Abschnitt Die Active Directory-Architektur
weiter unten in diesem Kapitel.
Das Lesen und Ändern eines Multiwert-Attributs funktioniert genau wie das Lesen und
Ändern eines Einzelwert-Attributs: das Script erstellt eine Bindung an das Objekt, es
verwendet eine Methode zum Ändern oder Lesen des Attributs und übermittelt dann die
Änderungen an Active Directory.
Tipp:
•
Um die Arbeit mit ADSI-Scripten einfacher zu gestalten, sollten Sie die Parameterwerte von
PutEx als Konstanten anlegen:
•
ADS_PROPERTY_CLEAR = 1
•
ADS_PROPERTY_UPDATE = 2
•
ADS_PROPERTY_APPEND = 3
•
ADS_PROPERTY_DELETE = 4
Im gesamten Rest dieses Kapitels werden diese Konstanten für die Methode PutEx verwendet.
Das Ändern von Multiwert-Attributen wird über drei grundlegende Schritte durchgeführt (das
Definieren der Konstanten ist ein optionaler Schritt).
1.Eine Bindung an das Active Directory-Objekt erstellen, das Sie ändern möchten.
2.Die entsprechende Aufgabe durchführen.
3.Die Änderungen an Active Directory übertragen.
Das erste Script im nächsten Abschnitt ändert die Mitglieder einer Gruppe über das
Mulitwert-Attribut member der Gruppe. Das Script aktualisiert alle Einträge, fügt einen
Eintrag hinzu, löscht einen Eintrag und löscht alle Einträge - und zwar in genau dieser
Reihenfolge.
Einschränkungen bei Änderungen über die Methode PutEx
Mit PutEx können Sie keine doppelten Einträge zu einem Multiwert-Attribut hinzufügen.
Wenn Sie einen solchen Vorgang versuchen, erhalten Sie keine Fehlermeldung - wenn Sie
jedoch später die Methode SetInfo aufrufen, schlägt das Script fehl und teilt Ihnen mit, dass
das Objekt bereits vorhanden ist.
Wenn Sie versuchen für ein objektabhängiges Attribut ein nicht vorhandenes Objekt angeben,
gibt PutEx eine Fehlermeldung zurück (zum Beispiel, wenn Sie versuchen den DN eines
Benutzerkontos zu einer Gruppe hinzuzufügen, das es nicht gibt).
1Const ADS_PROPERTY_UPDATE = 2
2Set objGroup = GetObject _
1Const ADS_PROPERTY_APPEND = 3
2Set objGroup = GetObject _
3 ("LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com")
4
5objGroup.PutEx ADS_PROPERTY_APPEND, _
6 "member", Array("cn=YoungRob,ou=R&D,dc=NA,dc=fabrikam,dc=com")
7
8objGroup.SetInfo
Einen Eintrag aus einem Multiwert-Attribut einer Gruppe löschen
Vorausgesetzt, dass Script 5.14 und Script 5.15 ausgeführt wurde, löscht Script 5.16 einen
Eintrag aus dem Attribut member der Gruppe. Die Gruppe hat danach nur noch zwei
Mitglieder. Hierzu führt das Script die folgenden Schritte aus:
1.Es definiert die Konstante ADS_PROPERTY_DELETE auf den Wert 4 (löschen).
2.Es baut eine Bindung zur Gruppe Atl-Users in der OU HR der Domäne na.fabrikam.com
auf.
3.Es löscht einen Eintrag aus dem Attribut. Hierzu verwendet es die Konstante
ADS_PROPERTY_DELETE und den DN des Benutzerobjekts MyerKen.
4.Es übermittelt die Änderung an Active Directory.
Da nur der eine Eintrag gelöscht wurde, bleiben alle anderen Einträge im Attribut members
der Gruppe erhalten.
Script 5.16: Löschen eines Eintrags aus dem Attribut member einer Gruppe
1Const ADS_PROPERTY_CLEAR = 1
2Set objGroup = GetObject _
3 ("LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com")
4
5objGroup.PutEx ADS_PROPERTY_CLEAR,"member", 0
6
7objGroup.SetInfo
Multiwert-Attribute eines Benutzerkontos aktualisieren
Die Änderung von Multiwert-Attributen eines Active Directory-Objekts funktioniert
unabhängig vom Typ des Objekts immer gleich. Um dies zu demonstrieren, aktualisiert Script
5.18 die Multiwert-Attribute url und otherTelephone des Benutzerkontos MyerKen. Hierzu
führt das Script die folgenden Schritte durch:
1.Es definiert die Konstante ADS_PROPERTY_UPDATE mit dem Wert 2. Diese Konstante
wird später für die Methode PutEx verwendet.
Der Wert 2 bedeutet, dass die Einträge eines Multiwert-Attributs aktualisiert werden.
2.Es baut eine Bindung zum Benutzerobjekt MyerKen in der OU HR der Domäne
na.fabrikam.com auf.
3.Es aktualisiert die Attribute url und otherTelephone. Im Gegensatz zum Attribut member
einer Gruppe können Sie in diese beiden Attribute beliebige Werte schreiben.
4.Es überträgt die Änderungen an der Gruppe an Active Directory.
Da PutEx mit dem Parameter 2 (aktualisieren) aufgerufen wurde, werden die vorhandenen
Einträge die neuen ersetzt.
Script 5.18: Aktualisieren der Attribute url und otherTelephone eines Benutzerkontos
Wichtig: Auch die Methode Get kann Einträge eines Multiwert-Attributs zurückgeben.
Trotzdem sollten Sie es nur für Einzelwert-Attribute verwenden. Weitere Informationen zu
diesem Thema finden Sie im Abschnitt Cachen von Daten.
Um die Inhalte eines Arrays anzuzeigen, benötigen Sie Scriptcode, der die Elemente des
Arrays durchgeht. Eine For-Each-Schleife ist hierzu ideal geeignet.
Wenn wir die benötigte Schleife einmal außer Acht lassen, benötigen Sie zwei Schritte, um
einen Multiwert-Attribut auszulesen:
1.Verbinden mit dem Active Directory-Objekt, dessen Attribute Sie lesen möchten.
2.Lesen von einem oder mehreren Attributen.
Der Unterschied in diesem Schritt liegt in der Verwendung der Methode GetEx statt Get wie
bei einem Einzelwert-Attribut. Außerdem wird eine For-Each-Schleife verwendet, um den
zurückgegebenen Array durchzugehen und dessen Inhalte anzuzeigen.
Script 5.20: Auslesen der Attribute url und otherTelephone eines Benutzerkontos
Wichtig: Ein Attribut, das keinen Wert enthält, wird von ADSI nicht berücksichtigt. Daher
werden solche Attribute niemals in den lokalen Zwischenspeicher eingelesen.
In allen bisherigen Beispielen wurde vorgeschlagen, für Einzelwert-Attribute die Methode
Get und für Multiwert-Attribute die Methode GetEx zu verwenden. Mit dieser Methode
müssen Sie nicht erst prüfen, ob es sich beim Rückgabewert um einen String oder um ein
Variant-Array handelt. Wenn Sie jedoch wissen, dass das abzufragende Attribut ein
Einzelwert-Attribut ist oder wenn es sich um ein Multiwert-Attribut handelt, bei dem Sie die
Anzahl der Einträge kennen, dann ist die Methode Get deutlich effizienter als die Methode
GetEx.
Wenn ein Attribut noch nicht in den lokalen Zwischenspeicher geladen wurde, dann ruft die
Methode Get bei ihrer Verwendung explizit die Methode GetInfo auf. Als Ergebnis lädt
GetInfo die meisten Attribute in den lokalen Zwischenspeicher - mit Ausnahme von
operativen Attributen und Attributen, die sich bereits im Zwischenspeicher befinden.
Operative Attribute sind die Attribute, deren Werte nicht gespeichert sind, sondern erst dann
vom Domänencontroller berechnet werden, wenn Sie abgefragt werden - das Attribut
canonicalName ist zum Beispiel ein solches Attribut.
Wenn Sie die Methode Get danach erneut verwenden, dann wird das gelesene Attribut aus
dem Zwischenspeicher gelesen - GetInfo wird nicht erneut aufgerufen.
Wie die Methode GetEx Attribute abfragt
Die Methode GetEx gibt die Werte des abgefragten Attributs immer als Variant-Array zurück.
Daher müssen Sie auch immer eine For-Each-Schleife zur Abfrage der Werte verwenden.
Wenn Sie nicht wissen, ob Sie es mit einem Einzelwert- oder Multiwert-Attribut zu tun
haben, dann kann es einfacher sein, die Methode GetEx statt Get zu verwenden. Sie erhalten
dann alle Attributwerte als Variant-Array und können alle Aufrufe gleich handhaben.
Wenn sich das Attribut noch nicht im Zwischenspeicher befindet, ruft auch die Methode
GetEx intern die Methode GetInfo auf. Attribute, die sich bereits im Zwischenspeicher
befinden, werden auch durch einen expliziten Aufruf von GetInfo nicht überschrieben.
1Set objGroup = _
2 GetObject("LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com")
3objGroup.GetInfo
Sie sollten mit dem Aufruf von GetInfo vorsichtig sein – alle Änderungen, die im
Zwischenspeicher an Attributen vorgenommen wurden und die noch nicht an Active
Directory übermittelt wurden, gehen mit dem Aufruf verloren. Sie sollten also sicherstellen,
dass Sie vor dem Aufruf von GetInfo alle Änderungen mit SetInfo übermittelt haben. In Zeile
2 des folgenden Codes wird das Attribut description auf den Wert Human Resources gesetzt
(natürlich nur im lokalen Zwischenspeicher). In Zeile 3 wird dann der lokale
Zwischenspeicher an Active Directory übertragen.
1 Const ADS_PROPERTY_UPDATE = 2
2 Set objOU = GetObject("LDAP://OU=HR,dc=NA,dc=fabrikam,dc=com")
3 Set objUserCopy = objOU.Create("user", "cn=BarrAdam")
4 objUserCopy.Put "sAMAccountName", "barradam"
5 objUserCopy.SetInfo
6
7 Set objUserTemplate = _
8 GetObject("LDAP://cn=HuffArlene,ou=HR,dc=NA,dc=fabrikam,dc=com")
9
10arrSVAttributes = Array("description", "department", _
11 "company", "wWWHomePage")
12arrMVAttributes = Array("url", "otherTelephone")
13
14For Each strAttrib in arrSVAttributes
15 strValue = objUserTemplate.Get(strAttrib)
16 objUserCopy.Put strAttrib, strValue
17Next
18
19For Each strAttrib in arrMVAttributes
20 arrValue = objUserTemplate.GetEx(strAttrib)
21 objUserCopy.PutEx ADS_PROPERTY_UPDATE, strAttrib, arrValue
22Next
23
24objUserCopy.SetInfo
Aus den Scripten dieses Abschnitts können wir die folgenden wichtigen Schlussfolgerungen
ziehen:
•
Zum Kopieren von Active Directory-Objekten sind drei Schritte nötig: ein Objekt erstellen,
Attribute aus dem Vorlagen-Objekt lesen und die Attribute in das neue Objekt schreiben.
•
Es gibt keine Methode, um eine direkte Kopie zu erstellen.
Suchen
Unter VBScript steht Ihnen als Abfragetechnologie ADO (ActiveX® Data Objects) zur
Verfügung. ADO verwendet den ADSI OLE DB-Provider, um Informationen ausActive
Directory zu lesen. OLE DB ist eine Schnittstellensammlung, die einen Zugriff auf viele
unterschiedliche Datenbanken - inklusive Active Directory - ermöglicht. Die Informationen,
die von ADO über den ADSI-OLE DB-Provider zurückgegeben werden, können nur gelesen
werden - das Schreiben ist nicht möglich. Trotzdem können Sie natürlich mit den
Informationen, die Sie über ADO erhalten, weitere ADSI-Methoden zur Änderung von Active
Directory-Daten verwenden.
An einer Abfrage sind normalerweise drei ADO-Objekte beteiligt:
•
Connection - Dieses Objekt stellt über den ADSI-OLE DB-Provider eine Verbindung
zwischen dem ADSI-Script und Active Directory zur Verfügung.
•
Command - Dieses Objekt ermöglicht es dem Script eine Abfrage gegen Active Directory
durchzuführen.
•
RecordSet - Dieses Objekt nimmt die Abfrageergebnisse vom Command-Objekt entgegen.
10.Ausführen der Abfrage über die Methode Execute des Command-Objekts und Zuweisen
des Rückgabewerts an das RecordSet-Objekt (Zeile 9).
Der Abfragestring gibt Einträge mit einem einzelnen Feld (dem Feld name) zurück.
11.Verwenden einer While-Wend-Schleife, um alle Elemente des Objekts objRecordSet
anzuzeigen. Um jeweils zum nächsten Element des RecordSet-Objekts zu gelangen, wird
die Methode MoveNext verwendet.
12.Schließen des Connection-Objekts.
Script 5.28: Suchen nach den Namen aller Objekt in der Domäne
Anmerkung: Eine komplette Liste der Suchoptionen und der anderen Eigenschaften von
ADO finden Sie unter dem Link Active Directory Programmer's Guide unter
http://www.microsoft.com/windows/reskits/webresources.
Script 5.29: Suchen nach den Namen und DNs aller Objekte eine Domäne
Seite 276 von 394
1 Set objConnection = CreateObject("ADODB.Connection")
2 objConnection.Open "Provider=ADsDSOObject;"
3
4 Set objCommand = CreateObject("ADODB.Command")
5 objCommand.ActiveConnection = objConnection
6
7 objCommand.CommandText = _
8 "<LDAP://dc=NA,dc=fabrikam,dc=com>;;distinguishedName,name;subtree"
9
10Set objRecordSet = objCommand.Execute
11
12While Not objRecordSet.EOF
13 Wscript.Echo objRecordSet.Fields("Name")
14 Wscript.Echo "[" & _
15 objRecordSet.Fields("distinguishedName") & "]"
16 objRecordSet.MoveNext
17Wend
18
19objConnection.Close
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, dann gibt es die Namen und
den DN aller Objekte in der Domäne aus. Die Ausgabe sollte ungefähr so aussehen:
na
[dc=NA,DC=fabrikam,DC=com]
Builtin
[CN=Builtin,dc=NA,DC=fabrikam,DC=com]
Administrators
[CN=Administrators,CN=Builtin,dc=NA,DC=fabrikam,DC=com]
Users
[CN=Users,CN=Builtin,dc=NA,DC=fabrikam,DC=com]
...
S-1-5-11
[CN=S-1-5-11,CN=ForeignSecurityPrincipals,dc=NA,DC=fabrikam,DC=com]
Program Data
[CN=Program Data,dc=NA,DC=fabrikam,DC=com]
Microsoft
[CN=Microsoft,CN=Program Data,dc=NA,DC=fabrikam,DC=com]
Die Suche auf einen bestimmten Objekttyp einschränken
Wenn Sie die Suche einschränken möchten, dann sollten Sie die Attribute objectClass oder
objectCategory verwenden.
Jedes Active Directory-Objekt verfügt über ein Einzelwert-Attribut mit dem Namen
objectCategory. In diesem Attribut ist der DN der Klasse hinterlegt, von der das Objekt
abgeleitet wurde. Das Attribut objectCategory einer Gruppe hat zum Beispiel den Wert
cn=Group,cn=Schema,cn=Configuration,dc=fabrikam,dc=com. Um mit dem Ergebnissatz
nur Gruppenobjekte zurückzuerhalten, geben Sie die Filterbedingung
(objectCategory=Group) im Filter-Teil des Suchstrings mit an.
Außerdem verfügt jedes Active Directory-Objekt über ein Multiwert-Attribut mit dem Namen
objectClass. Dieses Attribut enthält eine sortierte Liste der gesamten Klassenhierarchie, von
der das Active Directory-Objekt abgeleitet wurde. Um zum Beispiel die Abfrage auf
Computer- und Benutzerobjekte einzuschränken, können Sie den Filter objectClass=user
verwenden. Warum auch Computerobjekte? In der Active Directory-Hierarchie ist die Klasse
Computer eine Unterklasse der Klasse user.
Script 5.30: Suchen nach den Namen und den DNs aller Computerobjekt in der Domäne
Script 5.31: Suchen nach den Namen und DNs aller Computerobjekte in der
Gesamtstruktur
1 ADS_CHASE_REFERRALS_SUBORDINATE = &h20
2 Set objConnection = CreateObject("ADODB.Connection")
3 objConnection.Open "Provider=ADsDSOObject;"
4
5 Set objCommand = CreateObject("ADODB.Command")
6 objCommand.ActiveConnection = objConnection
7
8 objCommand.Properties("Chase Referrals") = _
9 ADS_CHASE_REFERRALS_SUBORDINATE
10
11objCommand.CommandText = _
12 "<LDAP://dc=fabrikam,dc=com>;(objectCategory=computer);" & _
13 "distinguishedName,name,isCriticalSystemObject;subtree"
14
15Set objRecordSet = objCommand.Execute
16
17While Not objRecordSet.EOF
18 Wscript.Echo objRecordSet.Fields("Name")
19 Wscript.Echo "isCriticalSystemObject: " & _
20 objRecordSet.Fields("isCriticalSystemObject")
21 Wscript.Echo "[" & _
22 objRecordSet.Fields("distinguishedName") & "]"
23 objRecordSet.MoveNext
24Wend
25
26objConnection.Close
Wenn Sie das Script in der Stammdomäne (fabrikam.com) ausführen, gibt es die Namen, den
DN und den Boolean-Wert von isCriticalSystemObject jedes Computerobjekts in der
Gesamtstruktur aus. Die Ausgabe könnte zum Beispiel so aussehen:
SEA-DC-01
isCriticalSystemObject: True
Anmerkung: Eine Sortierung nach einem Attribut, dass einen DN speichert ist, nicht
möglich. Wenn Sie dies versuchen, erhalten Sie einen leeren Ergebnissatz.
Script 5.34 demonstriert die Sortierung des Ergebnissatzes. Es fragt die Attribute name,
distinguishedName und whenCreated aller Computerobjekte der Gesamtstruktur ab und
sortiert die Ergebnisliste nach dem Attribut whenCreated.
Die folgenden Änderungen wurden gegenüber den bisherigen Scripten dieses Abschnitts
vorgenommen:
•
Der Eigenschaft Sort On wird der Wert whenCreated zugewiesen (Zeile 7).
•
Das Attribute whenCreated wird mit in den Abfragestring aufgenommen (Zeile 11).
Beachten Sie, dass das Script den Moniker GC verwendet. Dies funktioniert nur deshalb,
weil die abgefragten drei Attribute alle vom globalen Katalog-Server gespeichert werden.
SEA-DC-02
[CN=SEA-DC-02,OU=Domain Controllers,dc=NA,DC=fabrikam,DC=com]
8/21/2002 1:53:24 PM
SEA-DC-03
[CN=SEA-DC-03,OU=Domain Controllers,dc=NA,DC=fabrikam,DC=com]
8/27/2002 9:53:24 AM
SEA-PM-01
[CN=SEA-PM-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
8/27/2002 11:53:24 AM
...
SEA-SQL-01
[CN=SEA-SQL-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
8/27/2002 4:06:30 PM
SEA-DC-04
[CN=SEA-DC-04,OU=Domain Controllers,DC=fabrikam,DC=com]
9/03/2002 2:00:03 PM
Multiwert-Attribute über eine Suche abfragen
Einige Active Directory-Objekte stellen Multiwert-Attribute zur Verfügung. Auch diese
Attribute können Sie über den Ergebnissatz zurückgeben lassen (zum Beispiel das Attribut
member eines Gruppenobjekts).
Script 5.35 gibt einen solchen Ergebnissatz zurück. Es fragt die Einzelwert-Attribute name
und distinguishedName und das Multiwert-Attribut member aller Gruppen in der Domäne
Script 5.35: Suchen nach dem Namen und DNs aller Objekte der Domäne
Users
[CN=Users,CN=Builtin,DC=na,DC=fabrikam,DC=com]
Group Member(s):
CN=Domain Users,CN=Users,DC=na,DC=fabrikam,DC=com
CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=na,DC=fabrikam,DC=com
CN=S-1-5-4,CN=ForeignSecurityPrincipals,DC=na,DC=fabrikam,DC=com
...
Atl-Users
[CN=Atl-Users,CN=Users,DC=na,DC=fabrikam,DC=com]
Group Member(s):
CN=LewJudy,OU=Sales,DC=na,DC=fabrikam,DC=com
CN=HuffArlene,OU=HR,DC=na,DC=fabrikam,DC=com
CN=MyerKen,OU=HR,DC=na,DC=fabrikam,DC=com
Teile von Multiwert-Attributen über die Eigenschaft Range abfragen
Wenn ein Multiwert-Attribut viele Einträge hat, dann können Sie über die Eigenschaft Range
nur Teile dieser Einträge abfragen. Die Last auf dem abgefragten Domänencontroller wird so
geringer - daher wird auch die Abfrage schneller. Wenn ein Multiwert-Attribut mehr als 1.000
Einträge hat, dann müssen Sie die Abfrage auf Teile der Einträge beschränken. Ansonsten
kann es sein, dass die Abfrage nicht korrekt durchgeführt wird.
Script 5.36 gibt einen Ergebnissatz mit den ersten 1.000 Einträgen des Multiwert-Attributs
member der Gruppe Atl-Users in der Domäne na.fabrikam.com zurück.
Anmerkung: Wenn es weniger als 1.000 Mitglieder in der Gruppe gibt, schlägt das Script
fehl. Es muss bei jeder Abfrage mehr Einträge geben, als in der Eigenschaft Range definiert
sind (in diesem Fall 999).
Um die Anzahl der Einträge einzugrenzen, geht das Script folgendermaßen vor:
1.Das Schlüsselwort Range wurde mit in den Abfragestring aufgenommen (Zeile 9). Mit dem
Wert 0-999 werden die ersten 1.000 Einträge des Attributs member der Gruppe
zurückgegeben.
2.Es gibt den Text "Die ersten 1000 Mitglieder:" aus (Zeile 13).
3.Es initialisiert eine Variable mit den Namen arrMembers mit den Inhalten des Attributs
member über die Eigenschaft fields des RecordSet-Objekts.
Auch für die Eigenschaft Fields muss der Wert Range angegeben werden - und zwar exakt
so, wie sie im Abfragestring angegeben wurde.
Tabelle 5.4: Optionen zur Verbesserung der Leistung bei großen Ergebnissätzen
Option Beschreibung StandardwertSyntax
Page Size Weist den Domänencontroller an, Deaktiviert
(paging) eine bestimmte Anzahl von objCommand.Properties _
Einträgen zu verarbeiten und diese ("Page Size")= Records
dann vor der weiteren Verarbeitung Records ist die Anzahl der zu
an den Client zurückzugeben. erzeugenden Einträge.
Script 5.38: Verschieben von mehreren Benutzerkonten mit Hilfe des Ergebnissatzes
einer Suche
Script 5.40: Auflisten des Containers Partitions, um das Attribut upnSuffixes zu lesen
und zu schreiben
1 Const ADS_PROPERTY_APPEND = 3
2 Set objPartitions = GetObject _
3 ("LDAP://cn=Partitions,cn=Configuration,dc=fabrikam,dc=com")
4
5 objPartitions.PutEx ADS_PROPERTY_APPEND, upnSuffixes", _
6 Array("sa.fabrikam.com","corp.fabrikam.com")
7 objPartitions.SetInfo
8
9 For Each Suffix in objPartitions.GetEx("upnSuffixes")
10 Wscript.Echo Suffix
11Next
Wenn Sie das Script in der Stammdomäne fabrikam.com ausführen fügt es zum Attribut
upnSuffixes zwei Einträge hinzu und gibt dann die Inhalte des Attributs aus:
corp.fabrikam.com
sa.fabrikam.com
Script 5.40 funktioniert standardmäßig nur dann, wenn Ihr Benutzerkonto Mitglied der
globalen Gruppe Domänen-Admins der Stammdomäne oder der Gruppe Organisations-
Admins ist. Nur diese Gruppen haben das Recht, den Container Partitions zu bearbeiten.
Script 5.41: Einschränken der Auflistung auf Benutzerkonten über die Eigenschaft
Filter
Script 5.43: Erstellen des ADsPfads der Stammdomäne über den rootDSE
Script 5.44: Erstellen des ADsPfads des Containers Configuration mit dem rootDSE
Script 5.45: Erstellen des ADsPfads des Containers Schema mit dem rootDSE
Anmerkung: Eine vollständige Liste der Eigenschaften des rootDSE finden Sie unter dem
Link Active Directory Programmer's Guide unter
http://www.microsoft.com/windows/reskits/webresources.
Script 5.46: Auslesen der verpflichtenden und optionalen Attribute der Klasse computer
Optionale Attribute
volumeCount
siteGUID
rIDSetReferences
...
dNSHostName
defaultLocalPolicyObject
cn
catalogs
Wenn Sie ein Computerobjekt erstellen, müssen Sie einen Wert für das Attribut
sAMAccountName festlegen - es handelt sich hier um ein verpflichtendes Attribut der Klasse
computer. Das vorhergehende Script gibt jedoch an, dass keine verpflichtenden Attribute
vorhanden sind. Das Script hat hier Recht. Die Klasse computer erbt Attribute von den in der
Active Directory-Hierarchie übergeordneten Klassen (dies gilt auch für viele andere Klassen).
Daher verwendet die Klasse computer zwar das verpflichtende Attribut sAMAccountName, es
wird jedoch nicht in der Klasse selbst definiert.
1 arrClassNames = Array _
2 ("cn=top","cn=mail-Recipient", "cn=security-Principal", _
3 "cn=person", "cn=Organizational-Person", _
4 "cn=contact", "cn=user", "cn=computer", "cn=organizational-
5 Unit")
6
7 Set objRootDSE = GetObject("LDAP://rootDSE")
8 For Each ClassName in arrClassNames
9 Set objSchemaClass = GetObject("LDAP://" & ClassName & "," & _
10 objRootDSE.Get("schemaNamingContext"))
11
12 intClassCategory = objSchemaClass.Get("objectClassCategory")
13 WScript.STDOUT.Write ClassName & " is "
14 Select Case intClassCategory
15 Case 0
16 Wscript.Echo "88"
17 Case 1
18 Wscript.Echo "Structural"
19 Case 2
20 Wscript.Echo "Abstract"
21 Case 3
22 Wscript.Echo "Auxiliary"
23 End Select
Next
Wenn Sie das Script ausführen, zeigt es die Klassenkategorien einzelner Klassen an:
cn=top is abstract
1strClassName = "cn=computer"
2
3Set objRootDSE = GetObject("LDAP://rootDSE")
4Set objSchemaClass = GetObject("LDAP://" & strClassName & "," & _
5 objRootDSE.Get("schemaNamingContext"))
6
7strSubClassOf = objSchemaClass.Get("subClassOf")
8Wscript.Echo "Die Klasse " & strClassName & _
9 " ist eine untergeordnete Klasse von " & strSubClassOf
Wenn Sie das Script ausführen, erhalten Sie die folgende Ausgabe:
Die Klasse cn=computer ist eine untergeordnete Klasse von user
Snap-Ins zum Anzeigen und Konfigurieren von Attributen, Klassen und Objekten
Klassen und Attribute des Schemas können Sie auch über ein MMC-Snap-In anzeigen lassen.
Die beiden Snap-Ins hierzu heißen Active Directory Schema und ADSI Edit. Mit dem Snap-In
Active Directory Schema steht Ihnen eine grafische Schnittstelle für den Zugriff auf Klassen
und Attribute zur Verfügung. Mit ADSI Edit können Sie außerdem auch noch auf alle Active
Directory-Objekte zugreifen.
Anmerkung: Sie können natürlich auch eine Verbindung mit einem globalen Katalog-Server
aufbauen und dessen Partitionen anzeigen.
Das Snap-In ADSI Edit installieren Sie folgendermaßen:
1.Installieren Sie die SupportTtools (SupTools.msi) von der Windows 2000 Server-
Installations-CD (die Support Tools befinden sich im Ordner Support\Tools).
2.Starten Sie eine MMC-Konsole Start MMC, indem Sie MMC in der Eingabeaufforderung
oder im Feld Ausführen eingeben.
Partitionen
Es gibt drei vollständig replizierte Partitionen auf jedem Domänencontroller.
•
Die Schemapartition - Diese Partition enthält alle Klassen und Attribute der
Gesamtstruktur.
•
Die Konfigurationspartition - Diese Partition enthält Informationen über die Konfiguration
des Gesamtstruktur (zum Beispiel Domänennamen und Standorte).
•
Die Domänenpartition - Diese Partition enthält alle Objekte der jeweiligen Domäne des
Domänencontrollers. Im Gegensatz zu den anderen beiden Partitionen ist die
Domänenpartition für jede Domäne unterschiedlich. Schema- und Konfigurationspartition
werden von allen Domänen der Gesamtstruktur gemeinsam verwendet.
1 strAttributeName = "cn=given-name"
2
3 Set objRootDSE = GetObject("LDAP://rootDSE")
4 Set objSchemaAttribute = GetObject("LDAP://" & strAttributeName & "," & _
5 objRootDSE.Get("schemaNamingContext"))
6
7 blnInGC = objSchemaAttribute.Get("isMemberOfPartialAttributeSet")
8 If blnInGC Then
9 Wscript.Echo strAttributeName & _
10 " wird an den globalen Katalog-Server repliziert."
11 Else
12 Wscript.Echo "The " & strAttributeName & _
13 " wird nicht an den globalen Katalog-Server repliziert."
14End If
Wenn Sie das Script ausführen, erhalten Sie die folgende Ausgabe:
cn=given-name wird an den globalen Katalog-Server repliziert.
Nachdem Sie festgestellt haben, dass ein Attribut an den globalen Katalog-Server repliziert
wird, können Sie den Provider GC statt LDAP verwenden.
In Script 5.50 ist Ihnen möglicherweise aufgefallen, dass das Script nach einem Attribut
(isMemberOfPartialAttributeSet) eines Attributs sucht. Auch Attribute haben Attribute. Wenn
Sie sich ein Attribut über das Snap-In ADSI Edit anschauen, dann werden Sie sehen, dass die
Attribute und Klassen hier als Objekte angezeigt haben - und wie Sie wissen, haben Active
Directory-Objekte nun einmal Attribute.
Script 5.51: Lesen des Attributs searchFlags, um festzustellen, ob ein Attribut indiziert
wird
1 Const IS_INDEXED = 1
2 strAttributeName = "cn=given-name"
3
4 Set objRootDSE = GetObject("LDAP://rootDSE")
5 Set objSchemaAttribute = GetObject("LDAP://" & strAttributeName & "," & _
6 objRootDSE.Get("schemaNamingContext"))
7
8 intSearchFlags = objSchemaAttribute.Get("searchFlags")
9 If IS_INDEXED AND intSearchFlags Then
10 Wscript.Echo strAttributeName & " is indexed."
11Else
12 Wscript.Echo strAttributeName & " not indexed."
13End If
Wenn Sie das Script ausführen, sehen Sie die folgende Ausgabe:
cn=given-name is indexed.
Attribute, die sowohl zum globalen Katalog-Server repliziert als auch indiziert werden
Im Idealfall sollten Suchoperationen Attribute verwenden, die zum globalen Katalog-Server
repliziert und indiziert werden.
Vorsicht: Sie können die Attribute des Schemas auch von Hand so konfigurieren, dass Sie
zum globalen Katalog-Server repliziert oder indiziert werden - zum Beispiel über das Snap-In
Active Directory Schema. Sie sollten jedoch bei der Änderung des Schemas Vorsicht walten
lassen. Wenn Sie das Schema beschädigen, dann kann es zu schweren Fehlern in Active
Directory kommen.
Script 5.52 zeigt, wie Sie eine Suchoperation durchführen, mit der Sie alle Attribute
zurückerhalten, die sowohl indiziert als auch zum globalen Katalog-Server repliziert werden.
Das Script geht hierzu folgendermaßen vor:
1.Es definiert die Konstante IS_INDEXED mit dem Wert 1, um später feststellen zu können,
ob das Attribut indiziert wird.
2.Es verwendet den rootDSE, um die Variable strADsPath mit dem Wert des Attributs
schemaNamingContext zu initialisieren.
Script 5.52: Attribute auflisten, die indiziert und zum globalen Katalog repliziert
werden
1 Const IS_INDEXED = 1
2
3 Set objConnection = CreateObject("ADODB.Connection")
4 objConnection.Open "Provider=ADsDSOObject;"
5
6 Set objCommand = CreateObject("ADODB.Command")
7 objCommand.ActiveConnection = objConnection
8
9 Set objRootDSE = GetObject("LDAP://rootDSE")
10strADsPath = "<LDAP://" & objRootDSE.Get("schemaNamingContext") & ">"
11objCommand.CommandText = strADsPath & _
12 ";(objectCategory=AttributeSchema);" & _
13
14"lDAPDisplayName,isMemberOfPartialAttributeSet,searchFlags;onelevel"
15
16Set objRecordSet = objCommand.Execute
17Wscript.Echo "Attribute die indiziert und zum GC repliziert werden: "
18While NOT objRecordSet.EOF
19 strAttribute = objRecordSet.Fields("lDAPDisplayName")
20 If objRecordSet.Fields("isMemberOfPartialAttributeSet") AND _
21 (IS_INDEXED AND objRecordSet.Fields("searchFlags")) Then
22 Wscript.Echo strAttribute
23 End If
24 objRecordSet.MoveNext
25Wend
26
objConnection.Close
Wenn Sie das Script ausführen, erhalten Sie eine Ausgabe wie die folgende:
Attribute die indiziert und zum GC repliziert werden:
AltSecurityIdentities
cn
displayName
mail
...
name
sAMAccountName
sAMAccountType
servicePrincipalName
sIDHistory
sn
Die ADSI-Architektur
Wenn Sie saubere ADSI-Scripte schreiben möchten, dann ist es wichtig, dass Sie die
Architektur von Active Directory kennen und verstehen. Auch das ADSI-Objektmodell
sollten Sie kennen - inklusive der ADSI-Dateien, der logischen Komponenten, der
verfügbaren ADSI-Provider und der möglichen Schnittstellen.
Das ADSI-Objektmodell
ADSI ist eine Sammlung von DLLs (Dynamic Link Libraries), die von Clientanwendungen
wie zum Beispiel dem Windows Script Host (WSH) und dem Snap-In Active Directory
Benutzer und Computer zum Zugriff auf Active Directory genutzt werden können.
Wenn Sie eine Bindung in einem ADSI-Script einrichten, verwendet das Script den Moniker
im ADsPfad, um die entsprechende ADSI-Provider-DLL zu laden (wenn Sie zum Beispiel
den Moniker LDAP angegeben, wird die LDAP-DLL geladen - Adsidp.dll). Die ADSI-
Provider-DLL erstellt ein COM-Objekt (Component Object Model). Das COM-Objekt wird
dem Script als Referenz zurückgegeben und diese wird über den Befehl Set einer Variablen
zugewiesen.
Jedes Objekt stellt Schnittstellen zur Verfügung. Eine Schnittstelle ist eine Gruppe von
Methoden. Mit diesen Methoden können Sie bestimmte Aufgaben durchführen. Um Active
Directory zu bearbeiten, haben Sie zum Beispiel die Methoden Create, Put, Get und Delete
verwendet - diese Methoden werden alle über eine Schnittstelle mit dem Namen IADs zur
Verfügung gestellt. In Abbildung 5.7 sehen Sie die Zusammenhänge zwischen einer Bindung,
einem Provider, einem COM-Objekt, seinen Schnittstellen und Active Directory.
Abbildung 5.7: Ein COM-Objekt zum Zugriff auf ein Active Directory-Objekt erstellen
ADSI-Komponenten
Unter Windows NT-basierten Computern finden Sie ADSI im Ordner systemroot\System32.
Es setzt sich aus den Dateien ActiveDS.dll, ActiveDS.tlb und DLLs (alle DLLs, deren Name
mit ads anfängt - zum Beispiel Adsldp.dll). Außerdem werden bei der Installation von ADSI
einige andere DLLs aktualisiert - zum Beispiel Wldap32.dll.
ADSI ist eine Systemkomponente von Windows 2000, Windows XP und Windows Server
2003. Unter diesen Betriebssystem muss also nichts installiert werden. Unter den
Betriebssystemen Windows® 95, Windows® 98, Windows® Millennium Edition (Me) oder
Windows NT 4.0 sieht das anders aus. Informationen zur Installation von ADSI unter diesen
Betriebssystemen finden Sie unter dem Link Active Directory Service Interfaces unter
http://www.microsoft.com/windows/reskits/webresources (englischsprachig).
ADSI-Schichten
Die ADSI-Architektur können Sie sich als fünf Schichten vorstellen:
•
Verzeichnis oder Namespace
•
ADSI-Provider
•
ADSI-Router und Registrierung
•
Eigenschafts-Zwischenspeicher
•
ADSI-Anwendung
Der Provider
ADSI ist kein Teil von Active Directory selbst. Es stellt nur die Schnittstellen zu Active
Directory und dessen Namespace zur Verfügung. Über die folgenden Namespaces können Sie
auf Active Directory zugreifen:
•
LDAP
•
SAM-Datenbank (Security Accounts Manager)
Tabelle 5.5: ADSI-Provider und die Verzeichnisdienste, auf die sie zugreifen
Provider Zugriff auf
LDAP LDAP-Verzeichnisse der Versionen 2 und 3 - inklusive Active Directory.
GC Globaler Katalog der Active Directory-Domäne. Der Provider GC entspricht
dem Provider LDAP - er verwendet jedoch die TCP-Portnummern 3268.
ADSI OLE Active Directory für Suchoperationen.
DB
WinNT Windows NT-Domänen und die lokale Kontendatenbank unter Windows
NT/Windows 2000/Windows XP/Windows Server 2003.
IIS IIS-Metabase
NDS Novell NetWare Directory Services.
NWCOMPAT Novell Netware Bindery.
ADSI-Provider arbeiten als Vermittler zwischen einem Verzeichnis-Namespace und einer
ADSI-Anwendung. Alle Scripte in diesem Kapitel bauen eine Bindung an den LDAP-
Provider oder den GC-Provider auf.
Tipp: Verwenden Sie den rootDSE, damit Sie keine DNs in den ADsPfad eintragen müssen.
Es gibt noch einen besonderen Provider mit dem Namen ADSI-Namespace. Mit diesem
Provider können Sie eine Liste aller anderen Provider zurückgeben. Script 5.54 demonstriert
dies.
Vorsicht: Auch wenn es möglich ist zumindest Teile der Active Directory-Objekte über den
Provider WinNT zu verwalten, ist dies nicht empfehlenswert. Die Verwendung dieses
Providers kann schwerwiegende Auswirkungen auf die Leistung und die Fehleranfälligkeit
des Scripts haben.
Router
Wenn ein Script die Funktion GetObject verwendet, dann erhält der ADSI-Router eine
Anfrage. Er identifiziert den Provider der angefordert wurde, sucht in der Registrierung nach
Informationen über diesen Provider und lädt diesen dann in den Speicher (der Provider wird
anhand der angegeben ProgID identifiziert). Der Provider übergibt das angeforderte Element
später an den Router und dieser erstellt das ADSI-Objekt, das an das Script übergeben wird.
ADSI-Anwendung
Dies ist die oberste Schicht im ADSI-Schichtmodell. Die Scripte aus diesem Kapitel sind
Beispiele für ADSI-Anwendungen - ebenso das Snap-In ADSI-Edit.
ADSI-Schnittstellen
Jede Schnittstelle stellt Methoden zur Verfügung. Die Methoden führen entweder Aktionen
aus oder geben Informationen über ein Objekt zurück. Methoden, die Aktionen ausführen,
werden auch Methoden genannt. Im Gegensatz dazu werden Methoden, die einfach nur
Informationen zurückgeben, Eigenschaften oder Attribute genannt.
Ob eine Schnittstelle zur Verfügung steht oder nicht, hängt vom verwendeten Provider ab.
Der LDAP-Provider implementiert die Schnittstelle IADsADSystemInfo zum Beispiel nicht,
da diese speziell zur Abfrage von Informationen über Clientcomputer dient - der LDAP-
Provider fragt seine Informationen aber von Domänencontrollern ab.
Außerdem verwenden Provider nicht unbedingt alle Methoden einer Schnittstelle. Der LDAP-
Provider implementiert zum Beispiel die Methode CopyHere der Schnittstelle IADsContainer
nicht.
Eine Liste der von den Providern unterstützten Schnittstellen finden Sie unter dem Link
Active Directory Programmer's Guide unter
http://www.microsoft.com/windows/reskits/webresources (englischsprachig). Suchen Sie dort
nach dem Text "Provider Support of ADSI Interfaces."
WMI-Überblick
Ein grundlegendes Verständnis von WMI ist zur Systemadministration mindestens genauso
wichtig wie das Wissen um Active Directory und ADSI. WMI stellt ein konsistentes Modell
einer verwalteten Umgebung zur Verfügung. Für jede verwaltbare Ressource gibt es eine
entsprechende WMI-Klasse. Sie können sich eine WMI-Klasse als kurze Beschreibung der
Eigenschaften einer verwalteten Ressource und der Aktion, die WMI zur Verwaltung der
Ressource durchführen kann, vorstellen.
Anmerkung: Was ist eine 'verwaltete Ressource'? Im Zusammenhang mit diesem Kapitel ist
eine verwaltete Ressource jedes Objekt, das über WMI verwaltet werden kann (Hardware,
Software, Benutzerkonten, usw.).
Überlegen Sie sich, wie Sie Arbeitsstationen und Server bis jetzt verwalten und überwachen.
Sie verwenden eine Vielzahl an administrativen Werkzeugen, um diverse unterschiedliche
Ressourcen zu verwalten (zum Beispiel Festplatten, Ereignisprotokolle, Dateien, Ordner,
Dateisystem, Netzwerkkomponenten, Betriebssystemeinstellungen, Leistungsdaten, Drucker,
Prozesse, Registrierungseinstellung, Dienste, Freigaben, Benutzer und Gruppen).
Wenn Sie das WMI-Modell und dessen Anwendung verstanden haben, dann können Sie diese
Komponenten alle über die WMI-Scripting-Bibliothek verwalten. Die Scripting-Bibliothek
ermöglicht Ihnen die Arbeit mit WMI-Klassen und den entsprechenden verwalteten
Ressourcen. Sie können also die unterschiedlichsten Ressourcen über einen gemeinsamen
Weg verwalten.
WMI entspricht einem Industriestandard der DMTF (Distributed Management Task Force).
Die DMTF ist eine Organisation, die mit Herstellern von Schlüsseltechnologien (inklusive
Microsoft) und Standardisierungsgremien zusammenarbeitet, um übergreifende
Verwaltungslösungen zu entwickeln. Die Architektur von WMI basiert auf den Ideen der
WBEM-Initiative (Web-Based Enterprise Management) der DMTF.
WMI wurde 1998 das erste Mal veröffentlicht und als Komponente über das Service Pack 4
für Microsoft® Windows NT® bereitgestellt. WMI ist inzwischen ein integraler Bestandteil
aller Windows-Betriebssysteme - inklusive Microsoft Windows 2000, Microsoft®
Windows® XP und Windows Server 2003.
Anmerkung: Das Script sieht zugegebenermaßen auf den ersten Blick nicht ganz einfach aus.
Sie werden jedoch feststellen, dass es sich beim größten Teil des Scripts um Bausteine
handelt, die Sie in jedem WMI-Script unverändert wieder verwenden können.
1 strComputer = "."
2
3 Set objSWbemServices = GetObject("winmgmts:\\" & strComputer)
4 Set colSWbemObjectSet = _
5 objSWbemServices.InstancesOf("Win32_LogicalMemoryConfiguration")
6
7 For Each objSWbemObject In colSWbemObjectSet
8 Wscript.Echo "Physikalischer Speicher in KB: " & _
9 objSWbemObject.TotalPhysicalMemory
10Next
Wenn Sie das Script unter CScript ausführen, dann zeigt es den installierten Hauptspeicher in
KB an. Die Ausgabe sieht zum Beispiel so aus:
Total Physical Memory (kb): 261676
Wie arbeitet das Script nun? Wenn Sie auf die fett geschriebenen Teile des Scripts achten,
dann werden Sie feststellen, dass das Script zwei Aufgaben ausführt:
1.Es verbindet sich mit einer WMI-Klasse mit dem Namen
Win32_LogicalMemoryConfiguration.
WMI-Klassen repräsentieren die verwaltbaren Ressourcen eines Computers. Wie der Name
schon andeutet, ermöglicht es Ihnen die Klasse Win32_LogicalMemoryConfiguration
Informationen über den Hauptspeicher abzufragen.
2.Es gibt den Wert einer Eigenschaft mit dem Namen TotalPhysicalMemory aus.
WMI-Klassen haben Eigenschaften. Die Klasse Win32_LogicalMemoryConfiguration hat
zum Beispiel eine Eigenschaft, über die Sie den installierten Hauptspeicher abfragen
1 strComputer = "."
2
3 Set objSWbemServices = GetObject("winmgmts:\\" & strComputer)
4 Set colSWbemObjectSet = _
5 objSWbemServices.InstancesOf("Win32_LogicalMemoryConfiguration")
6
7 For Each objSWbemObject In colSWbemObjectSet
8 Wscript.Echo "Virtueller Speicher in KB: " & _
9 objSWbemObject.TotalVirtualMemory
10Next
WMI kann natürlich für mehr als nur zur Rückgabe von Informationen über den Speicher
eines Computers verwendet werden. Script 6.3 fragt zum Beispiel die Namen, den Status und
den Starttyp aller installierten Dienste ab.
1 strComputer = "."
2
3 Set objSWbemServices = GetObject("winmgmts:\\" & strComputer)
4 Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_Service")
5
6 For Each objSWbemObject In colSWbemObjectSet
7 Wscript.Echo " Name: " & objSWbemObject.DisplayName & vbCrLf & _
8 " Status: " & objSWbemObject.State & vbCrLf & _
9 " Starttyp: " & objSWbemObject.StartMode
10Next
Wenn Sie das Script unter CScript ausgeführt wird, dann erhalten Sie eine Ausgabe wie die
folgende (nur Teile der Ausgabe):
Name: Windows-Zeitgeber
Status: Running
Starttyp: Auto
Name: Webclient
Status: Running
Starttyp: Auto
Name: Windows-Verwaltungsinstrumentation
Status: Running
Starttyp: Auto
Name: Dienst für Seriennummern der tragbaren Medien
Status: Stopped
Starttyp: Manual
Name: Treibererweiterungen für Windows-Verwaltungsinstrumentation
Anmerkung: Bevor Sie Script 6.4 ausführen, sollten Sie sich bewusst sein, dass es
möglicherweise sehr lange zur Ausführung benötigt - abhängig davon, wie viele Einträge im
Ereignisprotokoll vorhanden sind.
1 strComputer = "."
2
3 Set objSWbemServices = GetObject("winmgmts:\\" & strComputer)
Die WMI-Architektur
Die ersten Seiten dieses Kapitels sollten einen wichtigen Punkt herausstellen. WMI-Scripting
muss nicht schwer sein - es kann sogar sehr einfach sein. Wie Sie gesehen haben, können Sie
bereits über eine einzelne Vorlage und geringe Änderungen Hunderte von Scripten zur
Abfrage einer riesigen Menge von Informationen erstellen.
Einige wichtige Probleme wurden jedoch bis jetzt verschwiegen. Sie werden uns zum Beispiel
zustimmen, wenn wir sagen, dass Sie über die Klasse Win32_NTLogEvent Ereignisse aus dem
Ereignisprotokoll abfragen können. Woher wissen Sie aber, dass es eine Klasse mit dem
Namen Win32_NTLogEvent gibt? Oder woher wissen Sie, dass es eine Klasse mit dem
Namen Win32_Service und den Eigenschaften Name, Description und State gibt? Sie können
Hunderte von unterschiedlichen Scripten aus dem ersten Script erstellen - jedoch nur, wenn
Sie wissen, welche Klassen und Eigenschaften Sie verwenden können.
Tatsächlich ist das Schreiben des Scripts der einfache Teil von WMI - der schwere Teil ist es,
herauszufinden, was über WMI verwaltet werden kann und was nicht. Hierbei helfen Ihnen
die aufgabenbasierten Abschnitte dieses Kapitels. Im Abschnitt Dateien und Ordner lesen Sie
zum Beispiel mehr über die entsprechenden WMI-Klassen (und deren Methoden und
Eigenschaften) - was aber, wenn Sie Grafikkarten, Monitore oder Netzwerkkarten verwalten
wollen? Leider gibt es in diesem Buch nicht für alle verwaltbare Ressourcen einen
entsprechenden Abschnitt.
Heißt das, Sie können nur die im Buch beschriebenen Ressourcen verwalten? Natürlich nicht
- wenn Sie wissen wie WMI funktioniert, dann können Sie alle Bereiche von WMI nutzen.
Wenn Ihnen klar ist, wo und wie WMI Informationen speichert, dann können Sie die vorhin
gestellten Fragen ganz einfach beantworten. Welche Klassen stehen mir zur Verfügung? Wie
sind die Namen dieser Klassen? Welche Eigenschaften und Methoden kann ich über die
Klasse verwenden?
Dieser und der folgende Abschnitt beschäftigen sich mit dem Common Information Model
(CIM) und beschreiben die WMI-Architektur. Als erstes sehen wir uns die drei grundlegenden
WMI-Schichten an (Abbildung 6.1):
•
Konsumenten
•
WMI-Infrastuktur
Verwaltete Ressourcen
Die grundlegende Schicht der WMI-Architektur bilden die verwalteten Ressourcen. Eine
verwaltete Ressource ist jede logische oder physikalische Komponente, die über WMI
zugreifbar und verwaltbar ist. Bei diesen Ressourcen handelt es sich unter anderem um:
Computer, Festplatten, Peripheriegeräte, Ereignisprotokolle, Dateien, Ordner, Dateisysteme,
Netzwerkkomponenten, Betriebssystem-Subsysteme, Leistungsindikatoren, Drucker,
Prozesse, Registrierungseinstellungen, Sicherheit, Dienste, Freigaben, SAM-Benutzer und -
Gruppen, Active Directory, Windows-Installer, WDM-Gerätetreiber und SNMP.
Eine WMI-Ressource kommuniziert mit WMI über einen Provider. Für das virtuelle
Gegenstück einer verwalteten Ressource wird oft der Begriff Instanz verwendet.
Entsprechend dem WMI-SDK ist eine Instanz 'ein Repräsentant eines physikalischen Objekts,
das zu einer bestimmten Klasse gehört'.
Sehen Sie sich zum Beispiel Script 6.5 an. Es gibt die Laufwerksbuchstaben für alle logischen
Laufwerke eines Computers zurück.
1strComputer = "."
Anmerkung: Was ist, wenn es keine Instanzen einer Klasse gibt? Nehmen wir an, dass Sie
versuchen Informationen über die Bandlaufwerke eines Computers abzufragen - der
Computer hat jedoch keine Bandlaufwerke. Wird dies zu einem Fehler führen? Nein -
letztendlich ist Win32_TapeDrive eine gültige WMI-Klasse. Es ist völlig unbedeutend, ob es
tatsächlich Bandlaufwerke (oder Instanzen der entsprechenden Klasse) gibt.
Die WMI-Infrastruktur
Die WMI-Infrastruktur ist die Vermittlungsschicht im WMI-Architekturmodell. WMI setzt
sich aus drei primären Komponenten zusammen: dem CIMOM (Common Information Model
Object Manager, auch WMI-Dienste genannt), dem CIM-Repository (Common Information
Model, auch WMI-Repository genannt) und WMI-Providern. Zusammen bilden diese drei
Komponenten die WMI-Infrastruktur.
WMI-Provider
WMI-Provider arbeiten als Vermittler zwischen dem CIMOM und der verwalteten Ressource.
Provider fordern Informationen von den verwalteten Ressourcen an und geben Informationen
an diese weiter. Script 6.1 und Script 6.3 verwenden zum Beispiel den Provider Win32, um
Informationen über den Hauptspeicher und die Dienste abzufragen. Script 6.4 verwendet
hingegen den Provider Event Log.
Provider verbergen die Implementierungsdetails für die einzelnen verwalteten Ressourcen
über ein standardbasiertes und einheitliches Zugriffsmodell. WMI-Provider kommunizieren
mit ihren jeweiligen verwalteten Ressourcen über die nativen APIs (Application
Programming Interfaces) der verwalteten Ressource. Mit CIMOM kommunizieren die WMI-
Provider über die WMI-Programmierschnittstelle. Der Provider Event Log ruft zum Zugriff
auf die Ereignisprotokolle zum Beispiel die Win32-EventLog-APIs auf.
Warum müssen Sie das wissen? Um eine Anwendung zu erstellen, die Windows-Subsysteme
verwaltet, werden normalerweise die Win32-APIs verwendet. Ohne WMI müssten Sie diese
CIMOM
Das CIMOM handhabt die Interaktion zwischen Konsumenten und Providern. Alle WMI-
Anfragen und der gesamte Datenfluss werden über den CIMOM durchgeführt. Wenn Sie ein
WMI-Script starten, dann wird das Script an CIMOM umgeleitet. Der CIMOM verarbeitet die
Anfrage des Scripts jedoch nicht direkt. Nehmen wir zum Beispiel an, das Script fragt eine
Liste der installierten Dienste ab. Der CIMOM ruft die Liste der Dienste in diesem Fall nicht
für Sie ab - er ruft stattdessen den entsprechenden WMI-Provider auf, und dieser ruft dann die
Liste ab. Wenn die Liste abgefragt ist, dann wird Sie an den CIMOM übergeben. Dieser leitet
sie dann an das Script weiter.
Der CIMOM wird unter Windows XP und Windows Server 2003 über den WMI-Dienst
(winmgmt.exe) bereitgestellt. Der WMI-Dienst wird unter dem Prozess svchost.exe
ausgeführt.
Anmerkung: Unter Windows 2000 und Windows NT 4.0 SP4 wird der WMI-Dienst als
separater Prozess ausgeführt. Unter Windows ME, Windows® 98 und Windows® 95 OSR
2.5 wird WMI als Standardprozess ausgeführt.
Der WMI-Dienst entspricht den meisten Betriebssystemdiensten. Er kann zum Beispiel
angehalten und gestartet werden:
net stop winmgmt
net start winmgmt
Wenn der Dienst angehalten ist und ein Script oder eine Anwendung aufgeführt wird, die den
Dienst benötigt, dann wird der Dienst automatisch neu gestartet.
Der CIMOM stellt die folgenden Dienste für die WMI-Infrastruktur zur Verfügung:
•
Registrierung von Providern - Der CIMOM speichert die Informationen zu den Providern
im CIM-Repository.
•
Routing von Anfragen - Der CIMOM verwendet die gespeicherten Provider-Informationen,
um Konsumentenanfragen an den entsprechenden Provider weiterzuleiten.
•
Remotezugriff - Anfragen von Remote-Konsumenten werden vom CIMOM verarbeitet.
•
Sicherheit - Der CIMOM kontrolliert den Zugriff auf die verwalteten Ressourcen, indem er
das Zugrifftoken des Benutzers überprüft.
•
Abfrageverarbeitung - Erlaubt es einem Konsumenten Abfragen gegen verwaltete
Ressourcen über die WMI Query Language (WQL - WMI-Abfragesprache) durchzuführen.
•
Ereignisverarbeitung - Erlaubt es einem Konsumenten auf Ereignisse einer verwalteten
Ressource zu reagieren.
Anmerkung: Auch für die WMI-Sicherheit sind Namespaces wichtig. Dieses Thema wird
weiter unten in diesem Kapitel besprochen.
CIM-Klassen enthalten Eigenschaften und Methoden. Eigenschaften beschreiben die
Konfiguration und den Status einer über WMI verwalteten Ressource. Methoden sind
ausführbare Funktionen, die bestimmte Aktionen für die über WMI verwalteten Ressourcen
ausführen.
Unter Windows 2000 und Windows NT 4.0 SP4 ist das CIM unter
systemroot\System32\Wbem\Respository\cim.rep gespeichert. Unter Windows Me, Windows
98 und Windows 95 OSR 2. ist das CIM unter %windir%\System\Wbem\Repository\cim.rep
gespeichert.
Unter Windows XP und Windows Server 2003 ist das CIM im Ordner
systemroot\System32\Wbem\Repository\FS gespeichert und setzt sich aus den folgenden
Dateien zusammen:
WMI-Konsumenten
Bei den WMI-Konsumenten handelt es sich um die letzte Schicht der WMI-Infrastruktur. Ein
Konsument kann ein Script, eine Anwendung, eine Webanwendung oder ein anderes Tool
sein, das auf WMI zugreift.
Ein solches Script muss nicht kompliziert sein. Das folgende dreizeilige Script ist ein Beispiel
für einen WMI-Konsumenten. Es fragt den verfügbaren Speicherplatz auf Laufwert C ab:
Set objSWbemServices = GetObject("winmgmts:")
Set objDisk = objSWbemServices.Get("Win32_LogicalDisk.DeviceID='C:'")
Wscript.Echo objDisk.FreeSpace
WMI-Sicherheit
WMI ist eine Technologie, die für die Systemadministration extrem nützlich ist. Scripte
können genauso einfach gegen Remotecomputer wie gegen den lokalen Computer ausgeführt
werden. Außerdem benötigen Sie zum Entwickeln von WMI-Scripten nicht mehr als einen
Texteditor. WMI wird zwar so zur perfekten Technologie zur Systemadministration, doch
leider gibt es noch eine weitere Gruppe, die WMI nutzen kann - Hacker. Wie schwer wäre es
zum Beispiel, ein Script zu schreiben, das alle Computer in Ihrer Organisation einen nach
dem anderen herunterfährt?
Wenn wir ganz ehrlich sind, dann wäre es ganz einfach, ein solches Script zu schreiben.
Dieses Script jedoch auszuführen wird deutlich schwerer. Das liegt daran, dass die Sicherheit
ein wichtiger Teil der WMI-Infrastruktur ist. WMI wurde so entworfen, dass solche
Aktivitäten, wie die oben beschriebenen, verhindert werden.
Stellen Sie sich zum Beispiel vor, ein Hacker versucht über WMI einen Ihrer Computer
herunterzufahren. Dieser Versuch wird fehlschlagen. Warum? Weil nur Administratoren ein
Script gegen einen Remotecomputer ausführen können. Solange der Hacker kein
Administrator ist, ist er nicht in der Lage, einen Computer über WMI herunterzufahren (wenn
der Hacker Administrator ist, dann kann er auch ohne ein Script eine Menge Probleme
verursachen).
Was ist, wenn ein Hacker das Script per E-Mail an einen Benutzer schickt und diesen dazu
bringt, das Script auszuführen? Auch das wird nicht funktionieren. Ein WMI-Script, das etwas
tut, benötigt immer administrative Rechte. In den meisten Organisationen verfügen die
Benutzer jedoch nicht über solche Rechte. WMI wird immer unter den Rechten der Person
ausgeführt, die das Script gestartet hat.
WMI-Sicherheit ist eine Erweiterung der anderen Windows-Sicherheits-Subsysteme und setzt
sich aus den folgenden Komponenten zusammen:
WMI-Namespace-Sicherheit
Bevor ein Benutzer sich mit WMI verbinden kann - egal ob auf einem lokalen Computer oder
einem Remotecomputer, - wird das Zugriffstoken des Benutzers auf die entsprechenden
Rechte überprüft. Die benötigten Rechte sind im CIM-Repository gespeichert.
Standardmäßig hat die Gruppe Administratoren einen Vollzugriff auf WMI und das gesamte
CIM-Repository - sowohl auf dem lokalen Computer als auch auf Remotecomputern. Alle
anderen Benutzer haben über die Gruppe Jeder die Rechte Konto aktivieren, Methoden
ausführen und Anbieterschreibzugriff auf dem lokalen Computer. In Tabelle 6.2 sehen Sie die
verfügbaren WMI-Berechtigungen - diese können Sie über die Registerkarte Sicherheit des
Snap-Ins Windows-Verwaltungsinfrastruktur (WMI) (systemroot\System32\Wmimgmt.msc)
konfigurieren.
Anmerkung: Unter Windows NT 4.0 SP4, Windows 98 und Windows 95 OSR 2.5 müssen
Sie die Anwendung Wbemcntl.exe verwenden. Sie finden diese unter Windows NT 4.0 SP4
im Ordner systemroot\System32\Wbem.
DCOM-Sicherheit
DCOM ist die Architektur, über die die WMI-Scripting-Bibliothek mit dem WMI-Dienst
zusammenarbeitet. Sie stellt einen Mechanismus zur Verfügung, der Impersonation genannt
wird (Personifizierung - auch mit dem Begriff 'Ausführen als' bezeichnet - zur Vereinfachung
wird in diesem Text der Begriff Personifizierung verwendet). Die Personifizierung legt fest,
unter welchen Benutzerrechten der WMI-Dienst ein Script ausführt.
Standardmäßig führt der WMI-Dienst Script unter den Anmeldeinformationen des
angemeldeten Benutzers aus - dies ist auch die empfohlene Einstellung. Sie können dem
WMI-Dienst das Recht geben, über Ihre Anmeldeinformationen auf andere DCOM-basierte
Dienste zuzugreifen. Dieser Vorgang wird Delegierung genannt - mit ihm sind jedoch einige
Risiken verbunden.
Was für Risiken sind das? Standardmäßig unterstützt DCOM nur eine 'Einzelschritt-
Personifizierung'. Stellen Sie sich zum Beispiel vor, Sie führen ein Script auf Computer A
aus, das Informationen von Computer B abfragen soll. Das Script kann für den 'einzelnen
Schritt' von Computer A zu Computer B eine Personifizierung durchführen. Was passiert
jedoch, wenn Computer B Informationen von einem dritten Computer abfragen muss?
Standardmäßig kann das Script für diesen 'Doppelschritt' keine Personifizierung mehr
durchführen. Es schlägt daher fehl.
Es ist natürlich möglich, Computer B ebenfalls zu erlauben, Ihre Anmeldeinformationen zu
verwenden - auch den Computer D, E und G können Sie dies erlauben. Hier tritt jedoch das
Sicherheitsrisiko zu tage. Bei zwei Computern können Sicherheitsprobleme auf die beiden
Computer beschränkt werden. Bei vielen Computern sind diese auch alle von
Sicherheitsproblemen betroffen.
Die unterschiedlichen DCOM-Sicherheitsebenen werden weiter unten in diesem Kapitel im
Abschnitt WMI-Scripte erstellen besprochen. Dort erfahren Sie auch mehr zu entsprechenden
Sicherheitsmaßnahmen.
Windows-Betriebssystem-Standardsicherheit
Zusätzlich zu den WMI- und DCOM-spezifischen Sicherheitseinstellung verwendet WMI
auch die Standardsicherheitseinstellung des Betriebssystems. Nehmen wird zum Beispiel
einmal an, jemand wird durch die Sicherheitseinstellungen eines Ordners daran gehindert, in
den Ordner zu schreiben. Wenn diese Person diesen Vorgang über ein WMI-Script
Anmerkung: Was passiert, wenn das Script trotzdem Schreiboperationen in diesem Ordner
durchführen muss? In diesem Fall müssen Sie entweder die NTFS-Berechtigungen des
Ordners ändern, oder das Script unter einem Benutzerkonto ausführen, das die entsprechenden
Rechte besitzt.
1 strComputer = "."
2
3 Set objSWbemServices = GetObject("winmgmts:\\" & strComputer)
4 Set colServices = objSWbemServices.InstancesOf("Win32_Service")
5
6 For Each objService In colServices
7 Wscript.Echo "Name: " & objService.Name & vbCrLf & _
8 "Angez. Name: " & objService.DisplayName & vbCrLf & _
9 "Beschreibung: " & objService.Description & vbCrLf & _
10 "Pfadname: " & objService.PathName & vbCrLf & _
11 "Starttyp: " & objService.StartMode & vbCrLf & _
12 "Status: " & objService.State & vbCrLf
13Next
Script 6.7 ist eine weitere Variante des Scripts. Es verwendet dieses Mal jedoch die Klasse
Win32_OperatingSystem. Wie Sie vielleicht erkennen, gibt es Informationen über das
installierte Betriebssystem zurück.
1 strComputer = "."
2
3 Set objSWbemServices = GetObject("winmgmts:\\" & strComputer)
4 Set colOperatingSystems = _
5 objSWbemServices.InstancesOf("Win32_OperatingSystem")
6
7 For Each objOperatingSystem In colOperatingSystems
8 Wscript.Echo "Name: " & objOperatingSystem.Name & vbCrLf & _
9 "Caption: " & objOperatingSystem.Caption & vbCrLf & _
10 "CurrentTimeZone:" & objOperatingSystem.CurrentTimeZone & vbCrLf & _
11 "LastBootUpTime: " & objOperatingSystem.LastBootUpTime & vbCrLf & _
Blaupausen
WMI vereinheitlicht die Konfiguration und Verwaltung von Ressourcen über das CIM-
Repository - dem Schema von WMI. Stellen Sie sich das Schema als Blaupause oder Modell
vor, das für ein echtes Objekt steht.
In Abbildung 6.2 sehen Sie eine konzeptuelle Ansicht der internen Struktur und Organisation
des CIM-Repository. Wie Sie sehen verwendet CIM für das Datenmodell Klassen. Es enthält
jedoch weit mehr Klassen als im Diagramm zu sehen.
In Abbildung 6.2 werden drei wichtige CIM-Konzepte gezeigt:
1.Das CIM-Repository ist in mehrere Namespaces aufgeteilt.
2.Jeder Namespace kann eine oder mehrere der folgenden Klassengruppen enthalten:
•
Systemklassen
•
Kernklassen oder allgemeine Klassen
Namespaces
CIM-Klassen sind in Namespaces organisiert. Namespaces sind
Partitionierungsmechanismen, mit denen das CIM den Bereich und die Sichtbarkeit von
Klassendefinitionen steuert. Jeder Namespace im CIM enthält eine logische Gruppe mit den
Klassen zu einer bestimmten Technologie oder zu einem bestimmten Bereich der Verwaltung.
Namespaces sind das gleiche wie Ordner in einem Laufwerk. Wie Ordner bieten auch
Namespaces einen Platz, um zusammengehörige Informationen zu speichern. Ein Ordner mit
dem Namen Scripts enthält wahrscheinlich Scripte - ein Namespace mit dem Namen
MicrosoftActiveDirectory enthält wahrscheinlich Informationen über Active Directory. So wie
Sie nur eine Datei mit dem Namen C:\Scripts\WMI_Script.vbs haben können, so können Sie
auch nur eine Klasse mit dem Namen root\cimv2:Win32_Process haben.
Anmerkung: Warum wurde der Wert von strComputer auf "." gesetzt? Bei WMI-Scripting
ist der erste Teil eines Objektpfads immer der Name des Computers. Wenn kein
Computername oder nur ein Punkt angegeben wird, dann wird das Script gegen den lokalen
Computer ausgeführt. Durch die Variable, die auf den Wert "." gesetzt wird, erreichen Sie
Seite 335 von 394
zwei Dinge: Das Script wird gegen den lokalen Computer ausgeführt und Sie haben die
Möglichkeit, einen anderen Computer einzutragen und das Script so ganz einfach gegen einen
Remotecomputer auszuführen.
1 strComputer = "."
2
3 Set objSWbemServices = _
4 GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
5 Set colWMISettings = objSWbemServices.InstancesOf("Win32_WMISetting")
6
7 For Each objWMISetting in colWMISettings
8 Wscript.Echo "Der Standard-Namespace ist: " & _
9 objWMISetting.ASPScriptDefaultNamespace
10Next
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
Der Standard-Namespace ist: root\cimv2
Um den Standard-Namespace zu ändern, können Sie Script 6.8 erneut verwenden - mit einer
wichtigen Änderung: Statt die Eigenschaft zu lesen, gehen Sie folgendermaßen vor:
1.Sie schreiben einen neuen Wert in die Eigenschaft.
2.Sie rufen die Methode SWbemObject.Put_ auf, um die Änderung an die WMI-Ressource zu
übermitteln.
Diese Aufgabe wird in einer For-Each-Schleife durchgeführt. Und zwar darum, weil die
Methode InstancesOf immer eine Collection zurückgibt. Dies passiert auch dann, wenn es
nur eine Instanz der Ressource gibt (so wie bei der Klasse Win32_WMISetting).
1 strComputer = "."
2
3 Set objSWbemServices = _
4 GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
5 Set colWMISettings = objSWbemServices.InstancesOf("Win32_WMISetting")
6
7 For Each objWMISetting in colWMISettings
8 objWMISetting.ASPScriptDefaultNamespace = "root\cimv2"
9 objWMISetting.Put_
10Next
Abrufen von Namespaces
1strComputer = "."
2
3Set objSWbemServices = GetObject("winmgmts:\\" & strComputer & "\root")
4Set colNameSpaces = objSwbemServices.InstancesOf("__NAMESPACE")
5
6For Each objNameSpace In colNameSpaces
7 Wscript.Echo objNameSpace.Name
8Next
Wenn Sie das Script unter Windows 2000 ausführen, erhalten Sie die folgende Ausgabe:
DEFAULT
SECURITY
CIMV2
WMI
directory
Die Liste der Namespaces variiert je nach der verwendeten Windows-Version und der
installierten WMI-Version. Auch WMI-Anwendungen beeinflussen die Liste. Unter Windows
XP mit installiertem Microsoft® Office XP und dem .NET Framework erhalten Sie zum
Beispiel die folgende Liste:
SECURITY
RSOP
Cli
WMI
CIMV2
MSAPPS10
Policy
Microsoft
DEFAULT
directory
subscription
NetFrameworkv1
Script 6.10 gibt nicht alle Namespaces auf dem Computer aus. Es zeigt nur die Namespaces
an, die sich direkt unter dem Namespace root befinden. Um alle Namespaces anzuzeigen,
müssen Sie das Script verändern. Wie Script 6.11 zeigt, ist dies jedoch nicht so schwer, wie
Sie vielleicht denken.
Script 6.10 wird einfach in ein rekursives Script umgewandelt. Hierzu wird der Hauptteil des
Scripts in eine Subroutine verschoben. Das Script geht folgendermaßen vor:
1.Es initialisiert die Variable strComputer mit dem Namen des Zielcomputers.
2.Es ruft die Subroutine EnumNameSpaces auf und übergibt ihr den Start-Namespace root.
Der Inhalte der Subroutine EnumNameSpaces ist mit Script 6.10 identisch - mit einer
1 strComputer = "."
2 Call EnumNameSpaces("root")
3
4 Sub EnumNameSpaces(strNameSpace)
5 Wscript.Echo strNameSpace
6 Set objSWbemServices = _
7 GetObject("winmgmts:\\" & strComputer & "\" & strNameSpace)
8 Set colNameSpaces = objSWbemServices.InstancesOf("__NAMESPACE")
9 For Each objNameSpace In colNameSpaces
10 Call EnumNameSpaces(strNameSpace & "\" & objNameSpace.Name)
11 Next
12End Sub
Unter Windows 2000 Advanced Server erhalten Sie die folgende Ausgabe:
root
root\DEFAULT
root\SECURITY
root\CIMV2
root\CIMV2\Applications
root\CIMV2\Applications\MicrosoftIE
root\CIMV2\ms_409
root\WMI
root\directory
root\directory\LDAP
root\directory\LDAP\ms_409
root\MicrosoftNLB
root\MicrosoftNLB\ms_409
Klassenkategorien
Wie Sie in Abbildung 6.2 gesehen haben, gibt es drei generelle Kategorien von Klassen:
system, Kern und allgemein und erweitert.
Systemklassen
1strComputer = "."
2Set objSWbemServices = _
3 GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
4Set colWin32Providers = objSWbemServices.InstancesOf("__Win32Provider")
5
6For Each objWin32Provider In colWin32Providers
7 Wscript.Echo objWin32Provider.Name
8Next
Wenn Sie das Script unter Windows 2000 ausführen, erhalten Sie die folgende Ausgabe:
CIMWin32
WBEMCORE
MS_Power_Management_Event_Provider
MS_NT_EVENTLOG_PROVIDER
MS_NT_EVENTLOG_EVENT_PROVIDER
SECRCW32
MSIProv
NT5_GenericPerfProvider_V1
Wahrscheinlich werden Sie Systemklassen eher selten verwenden - mit einer Ausnahme:
WMI-Überwachungsscripts abbonieren bestimmte WMI-Ereignisse, um bei deren Auftreten
benachrichtigt zu werden. Dieses Thema wird jedoch später in diesem Kapitel besprochen.
Anmerkung: Die tatsächliche Anzahl der Klassen kann von vielen verschiedenen Faktoren
abhängen - zum Beispiel von der Windows-Version und der installierten WMI-Version.
1strComputer = "."
2
3Set objSWbemServices = _
4 GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
5Set colClasses = objSWbemServices.SubclassesOf()
6
7For Each objClass In colClasses
8 Wscript.Echo objClass.Path_.Path
9Next
Wenn Sie das Script unter Windows 2000 ausführen, erhalten Sie eine Liste mit 636
Einträgen. Ein Teil der Ausgabe sieht so aus:
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_NTEventlogFile
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_NTLogEvent
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_NTLogEventLog
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_NTLogEventUser
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_NTLogEventComputer
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_SID
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_AccountSID
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_SecuritySetting
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_SecuritySettingOfObject
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_SecuritySettingOwner
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_SecuritySettingGroup
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_SecuritySettingAccess
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_SecuritySettingAuditing
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_Trustee
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_ACE
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_SecurityDescriptor
\\ATL-WIN2K-01\ROOT\CIMV2:Win32_LogicalFileSecuritySetting
Sie können Script 6.13 zur Auflistung der Klassen anderer Namespaces anpassen, indem Sie
einfach den Ziel-Namespace im Script ändern. Um nach Klassen zu suchen, können Sie das
Script zusammen mit dem Befehl findstr.exe verwenden. Findstr.exe ist ein
Kommandozeilentool, mit dem Sie in Dateien nach Text suchen können.
Nehmen wir beispielsweise einmal an, Sie möchten wissen, ob Ihre Windows-Version die
neue Windows XP-Klasse Win32_TSSessionSetting unterstützt. Mit dem folgenden Befehl
können Sie feststellen, ob die Klasse im Namespace root\cimv2 vorhanden ist. Das Script
schickt seine Ausgabe an Findstr.exe. Findstr.exe sucht dann in der Ausgabe nach dem Text
"Win32_TSSessionSetting".
cscript GetClasses.vbs |findstr /I "win32_tssessionsetting"
CIM-Klassentypen
Zu diesem Zeitpunkt sollte klar sein, dass es sich bei den grundlegenden Einheiten im CIM-
Repository um die Klassen handelt. Genau wie im Active Directory-Schema werden WMI-
Konfiguratinsinformationen und verwaltete Ressourcen durch eine oder mehrere Klassen
definiert. CIM-Klassen sind hierarchisch organisiert. Untergeordnete Klassen erben
Eigenschaften und Methoden von den übergeordneten Klassen.
Die dynamische Klasse Win32_Service erbt zum Beispiel von der abstrakten Klasse
Win32_BaseService. Diese erbt von der abstrakten Klasse CIM_Service, die von der
abstrakten Klasse CIM_LogicalElement und diese erbt wiederum von der abstrakten Klasse
CIM_ManagedSystemElement. Diese Klassenhierarchie können Sie in Abbildung 6.2
erkennen.
Tabelle 6.3 vergleicht die Eigenschaften dieser Klassen. Wie Sie sehen können, erben
Unterklassen alle Eigenschaften von ihrer übergeordneten Klasse. Außerdem definieren Sie
meist noch weitere, eigene Eigenschaften. Dies ist auch der Grund, aus dem ein Entwickler
eine neue Unterklasse statt einer ganz neuen Klasse definiert. Die übergeordnete Klasse bringt
meist bereits viele der benötigten Eigenschaften mit.
CIM_ManagedSystemElementundCIM_Logical CIM_Service Win32_BaseServ Win32_Servi
Element ice ce
Caption Caption Caption Caption
Description Description Description Description
InstallDate InstallDate InstallDate InstallDate
Name Name Name Name
Status Status Status Status
CreationClas CreationClass CreationClas
s s
Tabelle 6.3: Vergleich der Eigenschaften von über- und untergeordneten Klassen
Heißt das, dass Sie die Klasse Win32_BaseService verwenden können, um Informationen über
Dienste zurückzugeben? Nein - Win32_BaseService ist eine abstrakte Klasse. Das bedeutet,
dass sie nur als Vorlage für andere Klassen dient - nicht zum Abfragen von Daten.
Anmerkung: Wenn eine Eigenschaft nicht mit einem Wert konfiguriert ist, gibt WMI den
Wert NULL zurück.
Die Klassendefinitionen (Blaupausen) setzten sich aus Eigenschaften, Methoden und
Kennzeichnern zusammen. Bevor wir uns diese Komponenten anschauen, sollten Sie wissen,
wo die Klassendefinitionen eigentlich herkommen.
Nehmen wir einmal an, Microsoft entscheidet sich dazu, einen neuen WMI-Provider zu
erstellen, den Administratoren zu Verwaltung und Überwachung von DNS-Servern
verwenden können. Das entsprechende Team bei Microsoft würde in diesem Fall mindestens
zwei Dateien erstellen: Einen Provider und eine MOF-Datei (Managed Object Format).
Der Provider ist die DLL, die als Vermittlungsstelle zwischen der WMI-Infrastruktur und der
verwalteten Ressource arbeitet (in diesem Fall der DNS-Server). Der Provider verarbeitet
WMI-Anfragen, indem er die nativen APIs der Ressource aufruft.
Die MOF-Datei enthält Klassendefinitionen, die die Features des DNS-Providers beschreiben.
DNS-Server verwenden zum Beispiel Zonen und Ressourceneinträge. Daher wird die MOF-
Datei wahrscheinlich Klassen wie MicrosoftDNS_Zone und MicrosoftDNS_ResourceRecord
definieren.
Wenn der DNS-Provider installiert wird, dann wird dessen DLL beim Betriebssystem und bei
WMI registriert. Die MOF-Datei wird kompiliert. Danach ist die DNS-Providerklasse im
CIM-Repository vorhanden und kann nun verwendet werden.
MOF-Dateien sind Textdateien, die auf der MOF-Sprache basieren. Die MOF-Sprache wurde
vom DMTF entwickelt. Wie Sie in Abbildung 6.3 sehen, folgt eine Klassendefinition einer
wohl definierten Struktur und Syntax.
Kennzeichner
Kennzeichner sind zusätzliche Informationen über eine Klasse, eine Eigenschaft oder eine
Methode. Wenn Sie Scripte schreiben, die etwas mehr machen als nur Informationen
abzufragen (zum Beispiel Eigenschaften ändern oder Methoden aufrufen), werden
Kennzeichner schnell sehr wichtig. Dies liegt daran, dass die Charakteristika einer
Eigenschaft oder Methode beschreiben.
Welche Informationen stellen Ihnen Kennzeichner nun zur Verfügung? Erstmal sollten Sie
wissen, dass es drei Arten von Kennzeichnern gibt - somit gibt es auch drei unterschiedliche
Informationstypen.
Klassenkennzeichner
Klassenkennzeichner stellen Ihnen zusätzliche Informationen über eine Klasse zur Verfügung:
•
Die Kennzeichner Abstract (Abstrakt), Dynamic(Dynamisch) und Association (Assoziativ)
zeigen den Klassentyp an.
•
Der Kennzeichner Provider gibt an, welcher Provider für die Klasse zuständig ist.
•
Der Kennzeichner EnumPrivileges gibt die erforderlichen Rechte zu Verwendung der Klasse
an. Der Kennzeichner EnumPrivileges der Klasse Win32_NTLogEvent teilt Ihnen zum
Beispiel mit, dass das Recht SeSecurityPrivilege zur Verwendung der Klasse notwendig ist.
Eigenschaftskennzeichner
Eigenschaftskennzeichner stellen Informationen über eine Eigenschaft zu Verfügung:
•
Der Kennzeichner CIMType gibt den Datentyp der Eigenschaft an. WMI unterstützt einige
unterschiedliche Datentypen (zum Beispiel String, Integer, Date, Array und Boolean).
Ist es wirklich wichtig, welchen Datentyp eine Eigenschaft hat? Für die bisherigen einfachen
Beispiele nicht. Stellen Sie sich jedoch vor, Sie verwenden die Klasse Win32_Printer und
fragen die Eigenschaft Capabilities ab. Diese Eigenschaft gibt ein Array zurück.
Konsequenterweise können Sie die Eigenschaft nicht einfach ausgeben:
Wscript.Echo objPrinter.Capabilities Stattdessen müssen Sie die einzelnen Elemente des
Arrays durchgehen:
For Each intCapability in objPrinter.Capabilities
Wscript.Echo intCapability
Next
•
Der Kennzeichner Read zeigt, ob die Eigenschaft gelesen werden kann.
•
Der Kennzeichner Write zeigt, ob Sie die Eigenschaft verändern können. Die Eigenschaft
ASPScriptDefaultNamespace der Klasse Win32_WMISetting, die in Script 6.9 verändert
wird, ist zum Beispiel schreibbar. Die anderen in den bisherigen Scripten verwendeten
Eigenschaften sind hingegen nur lesbar. Ausnahmen sind Eigenschaften, die Sie über eine
Methode ändern.
Methodenkennzeichner
Methodenkennzeichner stellen Informationen über Methoden zur Verfügung:
•
Der Kennzeichner Implemented zeigt an, dass eine Methode über einen Provider
implementiert ist. Dies ist wichtig, da WMI-Klassen oftmals Methoden enthalten, die noch
nicht funktionieren (da sie noch nicht implementiert wurden).
•
Der Kennzeichner ValueMap definiert die Werte, die als Parameter verwendet werden
können und den Rückgabewert.
•
Der Kennzeichner Privileges definiert die zum Aufrufen der Methode erforderlichen Rechte.
Anmerkung: Es gibt noch deutlich mehr Kennzeichner. Eine komplette Liste der WMI-
Kennzeichner finden Sie im WMI SDK. Das SDK finden Sie unter dem Link Microsoft
Windows Management Instrumentation (WMI) SDK unter
http://www.microsoft.com/windows/reskits/webresources (englischsprachig).
Anmerkung: Mit WMI können Sie keine Informationen von einem Remotecomputer
abfragen, wenn WMI auf diesem nicht installiert ist. Auch die verwendeten Methoden und
Eigenschaften müssen vorhanden sein. Ein WMI-Script, das lokal auf einem Computer unter
Windows XP korrekt ausgeführt wird, kann daher auf einem Remotecomputer unter Windows
2000 durchaus fehlschlagen.
Wie stellen Sie fest, ob eine Methode oder Eigenschaft auf einem bestimmten Computer zur
Verfügung steht? Sie fragen die Klassendefinition ab.
1 strComputer = "."
2 strNameSpace = "root\cimv2"
3 strClass = "Win32_Service"
4
5 Set objClass = GetObject("winmgmts:\\" & strComputer & _
6 "\" & strNameSpace & ":" & strClass)
7
8 Wscript.Echo strClass & " Eigenschaften "
9 Wscript.Echo " — — — — — — — — — — — — — — — "
10
11For Each objClassProperty In objClass.Properties_
12 Wscript.Echo objClassProperty.Name
13Next
Wenn Sie das Script ausführen, werden die 25 Eigenschaften der Klasse Win32_Service
angezeigt.
Win32_Service Eigenschaften
- - - - - - - - - - - - - - -
AcceptPause
AcceptStop
Caption
CheckPoint
CreationClassName
Description
1 strComputer = "."
2 strNameSpace = "root\cimv2"
3 strClass = "Win32_Service"
4
5 Set objClass = GetObject("winmgmts:\\" & strComputer & _
6 "\" & strNameSpace & ":" & strClass)
7
8 Wscript.Echo strClass & " Methoden"
9 Wscript.Echo " — — — — — — — — — — — — — -"
10
11For Each objClassMethod In objClass.Methods_
12 Wscript.Echo objClassMethod.Name
13Next
Wenn Sie das Script ausführen, zeigt es die 10 Methoden der Klasse Win32_Service an:
Win32_Service Methoden
- - - - - - - - - - - - - -
StartService
StopService
PauseService
ResumeService
InterrogateService
UserControlService
Create
Change
ChangeStartMode
Delete
Script 6.16 entspricht zum größten Teil den Scripten 6.14 und 6.15 - mit drei Ausnahmen:
•
In der For-Each-Schleife werden die Elemente der Collection SWbemQualifierSet
durchlaufen. Die Eigenschaft Name jedes Elementes in der Collection wird ausgegeben.
•
Da die Klassenkennzeichner Teil der Klassendefinition sind und Kennzeichner Werte haben,
1 strComputer = "."
2 strNameSpace = "root\cimv2"
3 strClass = "Win32_Service"
4
5 Set objClass = GetObject("winmgmts:\\" & strComputer & _
6 "\" & strNameSpace & ":" & strClass)
7
8 Wscript.Echo strClass & " Klassenkennzeichner"
9 Wscript.Echo " — — — — — — — — — — — — — — — "
10
11For Each objClassQualifier In objClass.Qualifiers_
12 If VarType(objClassQualifier.Value) = (vbVariant + vbArray) Then
13 strQualifier = objClassQualifier.Name & " = " & _
14 Join(objClassQualifier.Value, ",")
15 Else
16 strQualifier = objClassQualifier.Name & " = " & _
17 objClassQualifier.Value
18 End If
19 Wscript.Echo strQualifier
20 strQualifier = ""
21Next
Wenn Sie das Script ausführen, werden die Namen und Werte der fünf Klassenkennzeichner
der Klasse Win32_Service ausgegeben:
Win32_Service Klassenkennzeichner
- - - - - - - - - - - - - - -
dynamic = True
Locale = 1033
provider = CIMWin32
SupportsUpdate = True
UUID = {8502C4D9-5FBB-11D2-AAC1-006008C78BC7}
Script 6.14 und Script 6.15 zeigen keine Methoden- und Eigenschaftskennzeichner an - die
Scripte bleiben so überschaubar.
1 strComputer = "."
2 strNameSpace = "root\cimv2"
3 strClass = "Win32_Service"
4
5 Const wbemFlagUseAmendedQualifiers = &h20000
6
7 Set objSWbemServices = _
8 GetObject("winmgmts:\\" & strComputer & "\" & strNameSpace)
9 Set objClass = objSWbemServices.Get(strClass,
10wbemFlagUseAmendedQualifiers)
11strMOF = objClass.GetObjectText_
12
Wscript.Echo strMOF
Die Ausgabe des Scripts sieht so aus:
[dynamic: ToInstance, provider("CIMWin32"): ToInstance,
Locale(1033): Amended, UUID("{8502C4D9-5FBB-11D2-AAC1-006008C78BC7}"):
ToInstance, Description("The Win32_Service class represents a
service on a Win32 computer system. A service application conforms
to the interface rules of the Service Control Manager (SCM) and
can be started by a user automatically at system boot through
the Services control panel utility, or by an application that
uses the service functions included in the Win32 API. Services
can execute even when no user is logged on to the system."):
ToSubClass Amended]
class Win32_Service : Win32_BaseService
{
[Description("The Caption property is a short textual
description (one-line string) of the object."): ToSubClass
Amended] string Caption;
Es gibt allerdings einen Vorbehalt gegenüber der Methode GetObjectText_ : Sie gibt keine
Informationen über die geerbten Kennzeichner zurück.
WMI-Tester
Der WMI-Tester (Wbemtest.exe) ist ein grafisches Tool das Sie zu Interaktion mit der WMI-
Infrastruktur verwenden können. Sie können das CIM-Schema anzeigen lassen und
Klassendefinitionen verwalten. Über den WMI-Tester können Sie dieselben Aktionen wie
über ein Script ausführen. Da der WMI-Tester ein Teil der WMI-Standardinstallation ist, steht
er immer zur Verfügung.
CIM-Studio
CIM-Studio ist Teil des WMI-SDKs. Es stellt eine webbasierte Benutzerschnittstelle zur
Interaktion mit der WMI-Infrastruktur zur Verfügung. Mit CIM-Studio haben Sie die gleichen
Möglichkeiten wie mit dem WMI-Tester.
Die WMI-Scripting-Bibliothek
Die WMI-Scripting-Bibliothek stellt einen Satz von Automatisationsobjekten zur Verfügung,
über die Scriptsprachen wie VBScript, JScript und ActiveState ActivePerl auf die WMI-
Infrastruktur zugreifen können. Die WMI-Scripting-Bibliothek ist über eine einzelne
Automatisationskomponente (wbemdisp.dll) implementiert - diese befindet sich im Ordner
systemroot\System32\Wbem.
Anmerkung: Die Linien in Abbildung 6.4 zeigen an, dass das entsprechende Objekt über
eine Methode oder eine Eigenschaft erstellt oder aufgerufen wird. Wenn Sie zum Beispiel die
Methode SWbemLocator.ConnectServer aufrufen, dann gibt diese eine SWbemObjectSet-
Collection zurück.
Das Diagramm gibt Ihnen einen guten Überblick über die Arbeitsweise von WMI-Scripten.
Die bisherigen Scripte führten zum Beispiel aller drei grundlegenden Aufgaben aus:
•
Jedes Script hat sich zuerst mit dem WMI-Dienst auf dem Zielcomputer verbunden. Hierzu
wird die Funktion GetObject mit einem entsprechenden WMI-Verbindungsstring verwendet.
Anmerkung: In den folgenden Abschnitten werden nicht alle Methoden und Eigenschaften
jedes Automatisationsobjekts besprochen. Eine vollständige Übersicht können Sie im WMI-
SDK finden. Weitere Informationen hierzu finden Sie unter dem Link Microsoft Windows
Management Instrumentation (WMI) SDK unter
http://www.microsoft.com/windows/reskits/webresources (englischsprachig).
SWbemLocator
An der Spitze des WMI-Scripting-Bibliothek-Objektmodells steht das Objekt SWbemLocator.
Es wird verwendet, um eine authentifizierte Verbindung mit einem WMI-Namespace
aufzubauen - so ähnlich, wie die VBScript-Funktion GetObject und der WMI-Moniker
"winmgmts:" zum Aufbau einer authentifizierten Verbindung zu WMI dienen.
SWbemLocator wurde für zwei bestimmte Scripting-Szenarien entwickelt, die nicht über
GetObject und den WMI-Moniker durchgeführt werden können. SWbemLocator wird in den
folgenden Fällen benötigt:
•
Wenn Sie sich mit einem anderen Benutzernamen und Passwort mit WMI auf einem
Remotecomputer verbinden möchten. Der WMI-Moniker der Funktion GetObject stellt keine
Mechanismen zur Angabe von Anmeldeinformationen zur Verfügung. Die meisten WMI-
Aktivitäten (inklusive der auf Remotecomputern) erfordern jedoch administrative Rechte.
•
Wenn Sie sich mit WMI verbinden möchten und das WMI-Script in einer Webseite
ausführen[NA?]. Wenn Sie Scripte ausführen, die in eine HTML-Seite eingebettet sind,
können Sie die Funktion GetObject aus Sicherheitsgründen nicht verwenden.
Außerdem können Sie SWbemLocator verwenden, um eine Verbindung mit WMI
aufzubauen, wenn Sie den WMI-Verbindungsstring von GetObject zu kompliziert finden.
Eine Referenz auf SWbemLocator erstellen Sie mit CreateObject statt mit GetObject. Sie
müssen der Funktion CreateObject die ProgID von SWbemLocator übergeben
("WbemScripting.SWbemLocator" - wie in Zeile 2 des folgenden Scripts). Nachdem Sie eine
SWbemServices Betriebsmodi
SWbemServices unterstützt drei Betriebsmodi: synchron, asynchron und semisynchron.
•
Synchron - Im synchronen Modus steht das Script so lange still, bis die Methode
SWbemServices ausgeführt wurde. Auch das Script ist betroffen - wenn das WMI Instanzen
von verwalteten Ressourcen abfragt, wird die gesamte SWbemObjectSet-Collection im
Speicher aufgebaut. Erst dann werden diese Daten an das Script zurückgegeben. Dies kann
Auswirkungen auf die Leistung des Scripts und auf den Computer, auf dem das Script
ausgeführt wird, haben. Die synchrone Abfrage von Tausenden von Ereignissen kann unter
Windows 2000 zum Beispiel sehr lange dauern und eine große Menge an Speicher
verbrauchen. Aus diesen Gründen sollten synchrone Methoden nicht ausgeführt werden -
eine Ausnahme sind die drei Methoden Delete, ExecMethod und Get. Diese geben keinen
großen Datensätze zurück.
•
Asynchron - Im asynchronen Modus wird das Script sofort weiter ausgeführt. Um eine
asynchrone Methode zu verwenden, muss Ihr Script erst ein SWbemSink-Objekt und eine
spezielle Subroutine (den Event-Handler) erstellen. WMI führt die asynchrone Methode aus
und benachrichtigt das Script über die Event-Handler-Subroutine, wenn die Methode beendet
ist.
•
Semisynchron - Der semisynchrone Modus ist ein Kompromiss zwischen synchron und
asynchron. Er bietet oft eine bessere Leistung als der synchrone Modus, und es sind keine
zusätzlichen Schritte notwendig. Daher ist dies der Standardmodus für die meisten WMI-
Abfragen.
Im semisynchronen Modus ruft das Script die Methode auf und wird sofort weiter ausgeführt.
WMI ruft die verwalteten Ressourcen währenddessen im Hintergrund ab. Nachdem die
Ressourcen vollständig abgerufen sind, werden diese über eine SWbemObjectSet-Collection
an das Script zurückgegeben. Sie können auf die Ressourcen zugreifen ohne darauf zu warten,
dass die gesamte Collection zusammengestellt ist.
Wenn Sie mit verwalteten Ressourcen arbeiten, die viele Instanzen haben (viel heißt in
diesem Fall mehr als 1.000), dann gibt es gewisse Vorbehalte gegenüber semisynchronen
Methoden. WMI erstellt und speichert für jede Instanz einer Ressource ein SWbemObject-
Objekt. Bei vielen Instanzen kann die Leistung des Scripts und des Computers zurückgehen.
InstancesOf
Sie haben die Verwendung der Methode InstancesOf bereits mehrmals in diesem Kapitel
gesehen. Weiter oben in diesem Kapitel wurde gesagt, dass es nicht möglich ist, Instanzen
von abstrakten Klassen (zum Beispiel CIM_Service) abzufragen. Dies stimmt zwar - das
Standardverhalten der Methode InstancesOf könnte jedoch dafür sorgen, dass Sie dies nicht
glauben.
Standardmäßig führt InstancesOf eine "Tiefenabfrage" durch. Das bedeutet, dass InstancesOf
alle Instanzen einer verwalteten Ressource abfragt deren Klasse Sie angegeben haben und
zusätzlich auch alle Instanzen der Unterklassen unter der angegebenen Klasse. Das folgende
Script fragt zum Beispiel alle Ressourcen ab, die über die die dynamische Klasse
CIM_Service und alle Klasse unter dieser Klasse repräsentiert werden:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")
Set colSWbemObjectSet = objSWbemServices.InstancesOf("CIM_Service")
For Each objSWbemObject In colSWbemObjectSet
Wscript.Echo "Objektpfad: " & objSWbemObject.Path_.Path
Next
Wenn Sie das Script ausführen, erhalten Sie nicht nur die Dienste des Computers zurück,
sondern auch alle Unterklassen unter CIM_Service - inklusive Win32_SystemDriver und
Win32_ApplicationService.
ExecQuery
Sie die Methode InstancesOf gibt auch ExecQuery immer eine SWbemObjectSet-Collection
zurück[???]. Daher muss Ihr Script die von ExecQuery zurückgegebene Collection
durchgehen, um auf die einzelnen Instanzen zuzugreifen:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")
Set colSWbemObjectSet = objSWbemServices.ExecQuery _
("SELECT * FROM Win32_Service")
For Each objSWbemObject In colSWbemObjectSet
Wscript.Echo "Name: " & objSWbemObject.Name
Next
Get
Im Gegensatz zu ExecQuery und InstancesOf gibt Get immer ein SWbemObject-Objekt
zurück (dieses stellt eine spezifische Instanz einer verwalteten Ressource oder eine einzelne
Klassendefinition dar). Um eine spezifische Instanz über die Get zu erhalten, müssen Sie Get
den Objektpfad der Instanz übergeben:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")
WMI-Sicherheitseinstellungen
Beim zweiten, optionalen Teil des WMI-Monikers handelt es sich um die
Sicherheitseinstellungen. Die Sicherheitseinstellungen haben schon zu viel Verwirrung
geführt. Dies liegt vor allem an der Einstellung Personifizierung (ImpersonationLevel) - diese
verhält sich unter den unterschiedlichen Versionen von WMI verschieden.
Über den Sicherheitsteil können Sie verschiedene Einstellungen angeben:
•
Personifizierungsebene - "winmgmts:{impersonationLevel=Wert}".
•
Authentifizierungsebene - "winmgmts:{authenticationLevel=Wert}".
Personifizierungsebene (ImpersonationLevel)
Die ersten beiden Einstellungen (impersonationLevel und authenticationLevel) sind nicht
WMI-spezifisch - sie werden von DCOM abgeleitet. WMI verwendet DCOM, um auf die
WMI-Infrastruktur von Remotecomputern zuzugreifen. Im Kontext von WMI regelt die
Personifizierung, wie weit der WMI-Dienst eines Remotecomputers Aktionen unter Ihrem
Benutzerkontext ausführen darf. DCOM unterstützt vier Personifizierungsebenen:
Anonymous, Identify, Impersonate und Delegate. Diese vier Ebenen sind in Tabelle 6.6
definiert.
Authentifizierungsebene (AuthenticationLevel)
Diese Einstellung ermöglicht es Ihnen, die DCOM-Authentifizierung und -Sicherheit für eine
bestimmte Verbindung anzugeben. Die Einstellungen reichen von keiner Authentifizierung
bis zu einer verschlüsselten Authentifizierung pro Paket. Die sieben möglichen Einstellungen
(Default, None, Connect, Call, Pkt, PktIntegrity und PktPrivacy) werden in Tabelle 6.7
beschrieben. Die Angabe der Einstellung Authentifizierungsebene sollten Sie mehr als
Anfrage statt als Anweisung betrachten. Es gibt keine Garantie dafür, dass die angeforderte
Authentifizierung auch tatsächlich verwendet wird.
Autorität (Authority)
Diese Einstellung erlaubt es Ihnen, das Sicherheitsverfahren zur Authentifizierung der WMI-
Verbindung anzugeben. Sie können die NTLM- oder die Kerberos-Authentifizierung
verwenden. Für NTLM verwenden Sie die Einstellung
authority=NTLMDomäne:Domänenname, wobei Domänenname ein gültiger NTLM-
Domänenname sein muss. Um Kerberos zu verwenden, geben Sie die Einstellung
authority=kerberos:Domänenname\Servername an.
Berechtigungen
Als letzte Einstellung können Sie Berechtigungen angeben. Diese Einstellung ermöglicht es
Ihnen, Recht zu gewähren oder zu verweigern. Zum Beispiel könnten Sie sich selbst das
Recht Security zuweisen, um unter Windows NT/2000 das Sicherheitsprotokoll abzufragen.
Einige der möglichen Rechte sehen Sie in Tabelle 6.8.
Der folgenden Moniker verbindet sich mit dem WMI-Dienst des Remotecomputers atl-dc-
01:
Set objSWbemServices = GetObject("winmgmts:\\atl-dc-01")
Dieser Moniker verbindet sich mit dem Namespace root\default auf dem Computer atl-dc-
01:
Set objSWbemServices = GetObject("winmgmts:\\atl-dc-01\root\default")
•
Eine WMI-Klasse in einem Namespace - Wenn in einem Moniker eine Klasse angegeben
wird, muss dieser von Computername und Namespace durch einen Doppelpunkt getrennt
werden. Der folgende Moniker verbindet sich zum Beispiel mit der Klasse
Win32_OperatingSystem:
Set objSWbemObject = GetObject _
("winmgmts:\\atl-dc-01\root\cimv2:Win32_OperatingSystem")
•
Eine Spezifische Instanz oder Instanzen einer WMI-Klasse in einem Namespace - Der
folgende Moniker verbindet sich direkt mit der WMI-Instanz von Laufwerk C:
Set objSWbemObject = GetObject _
("winmgmts:\\atl-dc-01\root\cimv2:Win32_LogicalDisk.DeviceID='C:'")
Anmerkung: Sie können die beiden Formen sogar mischen. Dies wird jedoch nicht
empfohlen, da Ihr Scriptcode so schwerer lesbar wird. Trotzdem wäre der folgende
Objektpfad gültig: \\Webserver/root/cimv2.
Wenn im Objektpfad eine WMI-Klasse angegeben wird, dann muss die Klasse vom
Namespace durch einen Doppelpunkt getrennt werden:
\\WebServer\root\cimv2:Win32_Printer
Anmerkung: Was ist, wenn Sie eine Liste der Dienste mit dem Starttyp Automatisch
benötigen? Dies können Sie über die Methode ExecQuery durchführen. Die Methode wird
weiter unten in diesem Kapitel im Abschnitt Abfragen von verwalteten Ressourcen über die
WMI-Abfragesprache besprochen.
Klassen haben normalerweise nur eine Schlüsseleigenschaft - auch wenn es ein paar
Ausnahmen gibt. Die Klasse Win32_NTLogEvent hat zum Beispiel zwei
Schlüsseleigenschaften: Logfile und RecordNumber. Dies liegt daran, dass RecordNumber
einen Eintrag in einem Ereignisprotokoll nicht eindeutig identifiziert. Es kann in den
unterschiedlichen Protokollen Einträge mit den gleichen Nummern geben. Wenn Sie einen
solchen Eintrag aufrufen wollen, müssen Sie daher beide Schlüsseleigenschaften angeben:
\\WebServer\root\cimv2:Win32_NTLogEvent.Logfile='Application',RecordNumber=
555
1 strComputer = "."
2 Set objSWbemServices = _
3 GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
4
5 Set colServices = _
6 objSWbemServices.ExecQuery("SELECT * FROM Win32_Service")
7
8 For Each objService In colServices
9 Wscript.Echo objService.Name
10Next
Anmerkung: Auch wenn es schon schlimm genug ist, dass das Script abstürzt - es kommt
noch schlimmer. Auch wenn das Script abgestürzt ist, führt WMI die Abfrage weiter aus.
Somit kommt das ganze System zum Stillstand. Der einzige Weg, dies zu beenden, wäre ein
Neustart des WMI-Dienstes.
Sie sehen also: In diesem Fall ist der Unterschied tatsächlich dramatisch. Ein Script, das nur
die Instanzen mit dem Ereigniscode 532 zurückgibt, ist in wenigen Sekunden beendet.
Um eine solche Abfrage zu erstellen, benötigen Sie eine WHERE-Bedingung:
"SELECT * FROM Klassename WHERE Eigenschaftsname = Eigenschaftswert"
Anmerkung: Dieser Beschreibung ist nicht vollkommen richtig. Außer dem Gleichzeichen
(=) können Sie auch noch andere Operatoren verwenden - zum Beispiel kleiner (), größer ()
und ungleich ().
Die folgende Abfrage gibt zum Beispiel nur die Einträge zurück, die im Systemprotokoll
aufgezeichnet wurden:
"SELECT * FROM Win32_NTLogEvent WHERE Logfile = 'System'"
Die Abfrage setzt sich folgendermaßen zusammen:
•
Win32_NTLogEvent ist die abzufragende WMI-Klasse.
•
Logfile ist die Eigenschaft.
•
System ist der gesuchte Wert der Eigenschaft Logfile. Nur die Ereignisse, bei denen die
Eigenschaft Logfile den Wert System hat, werden zurückgeben.
Wenn Sie Abfragen mit einer WHERE-Bedingung schreiben, müssen Sie darauf achten, den
Wert richtig zu formatieren. Das verwendete Format hängt von der abgefragten Eigenschaft
ab (String, Zahl, Boolean-Wert, usw.).
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")
strComputer = "."
Set objSWbemServices = _
GetObject("winmgmts:{(Security)}\\" & strComputer & "\root\cimv2")
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")
1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
3 "\root\cimv2")
4 Set objOS = objSWbemServices.ExecQuery("SELECT * FROM
5 Win32_OperatingSystem")
6 For Each strOS in objOS
7 dtmInstallDate = strOS.InstallDate
8 strReturn = WMIDateStringToDate(dtmInstallDate)
9 Wscript.Echo strReturn
10Next
11Function WMIDateStringToDate(dtmInstallDate)
12 WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & _
13 Mid(dtmInstallDate, 7, 2) & "/" & Left(dtmInstallDate, 4) _
14 & " " & Mid (dtmInstallDate, 9, 2) & ":" & _
15 Mid(dtmInstallDate, 11, 2) & ":" & Mid(dtmInstallDate, _
13, 2))
End Function
1strComputer = "."
2Set objSWbemServices = GetObject("winmgmts:" _
3 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
4Set colTimeZone = objSWbemServices.ExecQuery _
5 ("SELECT * FROM Win32_TimeZone")
6For Each objTimeZone in colTimeZone
7 Wscript.Echo "Differenz: "& objTimeZone.Bias
8Next
Wenn Sie das Script unter CScript ausführen, erhalten Sie auf einem deutschen Computer die
folgende Ausgabe:
1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:" _
3 & "{impersonationLevel=impersonate}!\\" & strComputer &
4 "\root\cimv2")
5 Set colTimeZone = objSWbemServices.ExecQuery _
6 ("SELECT * FROM Win32_TimeZone")
7 For Each objTimeZone in colTimeZone
8 strBias = objTimeZone.Bias
9 Next
10
11dtmCurrentDate = Date
12dtmTargetDate = Year(dtmCurrentDate)
13
14dtmMonth = Month(dtmCurrentDate)
15If Len(dtmMonth) = 1 Then
16 dtmMonth = "0" & dtmMonth
17End If
18
19dtmTargetDate = dtmTargetDate & dtmMonth
20
21dtmDay = Day(dtmCurrentDate)
22If Len(dtmDay) = 1 Then
23 dtmDay = "0" & dtmDay
24End If
25
26dtmTargetDate = dtmTargetDate & dtmDay & "000000.000000"
dtmTargetDate = dtmTargetDate & Cstr(strBias)
Script 6.22 demonstriert eine praktische Verwendung der Konvertierung. Es ruft alle Ordner
ab, die nach einem bestimmten Datum erstellt wurden (in diesem Fall der 18.10.2003):
1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:" _
3 & "{impersonationLevel=impersonate}!\\" & strComputer &
4 "\root\cimv2")
5 Set colTimeZone = objSWbemServices.ExecQuery _
Anmerkung: Alle Scriptvorlagen werden gegen den lokalen Computer ausgeführt ("."). Um
das Script gegen einen Remotecomputer auszuführen, ändern Sie einfach den Wert der
Variable strComputer:
strComputer = "atl-dc-01"
1 strComputer = "."
2 strNamespace = "\root\cimv2"
3 strClassName = "Win32_Service"
4
5 Set objSWbemServices = GetObject("winmgmts:" _
6 & "{impersonationLevel=impersonate}!\\" & strComputer & strNamespace)
7
8 Set colInstances = objSWbemServices.ExecQuery _
9 ("SELECT * FROM" & strClassName)
10For Each objInstance in colInstances
11 Wscript.Echo "Caption " & objInstance.Caption
12 Wscript.Echo "Description " & objInstance.Description
13Next
Um die Vorlage mit anderen WMI-Klassen zu verwenden:
•
Setzen Sie die Variable strClassName auf die entsprechende WMI-Klasse.
•
Setzen Sie - wenn nötig - die Variable strNamespace auf den entsprechenden WMI-
Namespace.
•
Ersetzt die Zeilen in der For-Each-Schleife durch die entsprechenden Eigenschaften
Script 6.24: Vorlage zum Abfragen und Anzeigen aller Eigenschaften einer Ressource
1 strComputer = "."
2 strNamespace = "\root\cimv2"
3 strClassName = "Win32_Process"
4
5
6 Set objSWbemServices = _
7 GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_
8 strComputer & strNamespace)
9
10Set colInstances = objSWbemServices.ExecQuery("SELECT * FROM " &_
11 strClassName)
12
13Wscript.Echo "Eigenschaften der Klasse " & strClassName
14Wscript.Echo "================================================="
15
16iCount = 0
17For Each objInstance in colInstances
18 iCount = iCount + 1
19 Set colProperties = objInstance.Properties_
20
21 Wscript.Echo vbCrLf
22 Wscript.Echo "******************"
23 Wscript.Echo "INSTANZ NUMMER: " & iCount
24 Wscript.Echo "******************"
25 Wscript.Echo vbCrLf
26
27 For Each objProperty in colProperties
28 Wscript.Echo objProperty.Name & " : " & objProperty.Value
29 Next
Anmerkung: Diese Vorlage funktioniert nur für Eigenschaften, die schreibbar sind. Bei allen
anderen Eigenschaften führt es zu einem Fehler.
1 strComputer = "."
2 strClassName = "Win32_OSRecoveryConfiguration"
3 strNamespace = "\root\cimv2"
4
5 Set objSWbemServices = GetObject("winmgmts:" _
6 & "{impersonationLevel=impersonate}!\\" & strComputer & strNamespace)
7 Set colInstances = objSWbemServices.ExecQuery _
8 ("SELECT * FROM " & strClassName)
9 For Each objInstance in colInstances
10 objInstance.DebugInfoType = 1
11 objInstance.DebugFilePath = "c:\scripts\memory.dmp"
12 objInstance.OverWriteExistingDebugFile = False
13 objInstance.Put_
14Next
Um die Vorlage mit anderen WMI-Klassen zu verwenden und andere Eigenschaften zu
ändern:
•
Setzen Sie den Wert von strClassName auf die entsprechende WMI-Klasse.
•
Wenn notwendig, ändern Sie den Wert von strNamespace.
•
Ersetzt die Zeilen in der For-Each-Schleife durch die entsprechenden Eigenschaften
1 strComputer = "."
2 strNamespace = "\root\cimv2"
3 strClassName = "Win32_Service"
4 strKeyName = "Name"
5 strKeyValue = "Alerter"
1 strComputer = "."
2 strNamespace = "\root\cimv2"
3 strClassName = "Win32_Share"
4
5 Set objSWbemServices = GetObject("winmgmts:" _
6 & "{impersonationLevel=impersonate}!\\" & strComputer & strNamespace)
7
8 Set objNewShare = objSWbemServices.Get(strClassName)
9 Set objInParams = _
10objNewShare.Methods_("Create").InParameters.SpawnInstance_()
11
12objInParams.Properties_.Item("Description") = "New Share Description"
13objInParams.Properties_.Item("Name") = "New Share Name"
14objInParams.Properties_.Item("Path") = "C:\scripts\shared"
15objInParams.Properties_.Item("Type") = 0
16
objNewShare.ExecMethod_ "Create", objInParams
Um die Vorlage mit anderen WMI-Klassen zu verwenden und andere Eigenschaften zu
ändern:
•
Setzen Sie den Wert von strClassName auf die entsprechende WMI-Klasse.
•
Wenn notwendig, ändern Sie den Wert von strNamespace.
•
Ersetzt die Zeilen in der For-Each-Schleife durch die erforderlichen neuen Zeilen.
1 strComputer = "."
2 strNamespace = "\root\cimv2"
3 strClassName = "Win32_Share"
4 strKeyName = "Name"
5 strKeyValue = "New Share Name"
6
7 Set objSWbemServices = GetObject("winmgmts:" _
8 & "{impersonationLevel=impersonate}!\\" & strComputer & strNamespace)
9
10Set objInstance = objSWbemServices.Get(strClassName & "." &_
11 strKeyName & "='" &_
12 strKeyValue & "'")
13objInstance.Delete
Um die Vorlage mit anderen WMI-Klassen zu verwenden und andere Eigenschaften zu
ändern:
•
Setzen Sie den Wert von strClassName auf die entsprechende WMI-Klasse.
•
Wenn notwendig, ändern Sie den Wert von strNamespace.
•
Ersetzt Sie die Zeilen in der For-Each-Schleife durch die erforderlichen neuen Zeilen.
•
Setzten Sie den Wert von strKeyName auf die Schlüsseleigenschaft der Klasse.
•
Setzen Sie den Wert von strKeyValue auf den entsprechenden Wert für diese Eigenschaft.
1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:" &_
3 "{impersonationLevel=impersonate}!" &_
4 "\\" & strComputer & "\root\cimv2")
1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:" &_
3 "{impersonationLevel=impersonate}!" &_
4 "\\" & strComputer & "\root\cimv2")
5
6 Set objEventSource = objSWbemServices.ExecNotificationQuery( _
7 "SELECT * FROM __InstanceModificationEvent " &_
8 "WITHIN 10 " &_
9 "WHERE TargetInstance " &_
10 "ISA 'Win32_Service' " &_
11 "AND TargetInstance.Name = 'alerter'")
12
13Set objEventObject = objEventSource.NextEvent()
14Wscript.Echo "Status des Dienstes alerter hat sich geändert."
Vergleichen Sie das Script mit Script 6.29. Die Elemente, die sich unterscheiden, sind fett
formatiert. Es gibt vier Unterschiede:
•
Der überwachte Ereignistyp:
__InstanceCreationEvent wurde in __InstanceModificationEvent geändert.
•
Die WMI-Klasse der zu überwachenden Ressource:
Win32_Process wurde in Win32_Service geändert.
•
Der Wert der Eigenschaft Name:
notepad.exe wurde in alerter geändert.
•
Die angezeigte Nachricht.
Erweiterte Überwachung
Die Überwachung über ein WMI-Script unterliegt einigen Einschränkungen:
•
Instanzen können nur über eine einzelne Eigenschaft überwacht werden.
•
Es kann nur ein Ereignis überwacht werden.
•
Es kann nur ein Ereignistyp überwacht werden: Erstellen, Ändern oder Löschen.
•
Es kann nur ein Ressourcentyp überwacht werden.
Die folgenden Beispielscripte zeigen, wie Sie diese Beschränkungen umgehen können.
Script 6.31: Überwachen der ersten CPU auf eine Auslastung von mehr als 90 Prozent
1 Set objSWbemServices = _
Script 6.32: Fortwährende Überwachung der ersten CPU auf eine Auslastung von mehr
als 90 Prozent
1 strComputer = "."
2 Set objSWbemServices = _
3 GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
4
5 strWQL = "SELECT * FROM __InstanceModificationEvent " & _
6 "WITHIN 5 " & _
7 "WHERE TargetInstance ISA 'Win32_Processor' " & _
8 "AND TargetInstance.DeviceID='CPU0' " & _
9 "AND TargetInstance.LoadPercentage > 90"
10
11Set objSWbemEventSource = objSWbemServices.ExecNotificationQuery(strWQL)
12
13While True
14 Set objSWbemObject = objSWbemEventSource.NextEvent()
15 WScript.Echo "Load Percentage on CPU0 exceeded 90%."
16Wend
Mehr als einen Ereignistyp überwachen
Script 6.29 verarbeitet nur die Erstellungs-Ereignisse. Script 6.30 verarbeitet nur Änderungs-
Ereignisse. Nehmen wir jedoch an, Sie möchten benachrichtigt werden wenn Notepad
gestartet wird, wenn die Instanz von Notepad geändert wird und wenn Notepad gelöscht wird.
Bis jetzt müssten Sie hierzu drei Scripte schreiben und starten.
Die Klassen __InstanceCreationEvent, __InstanceModificationEvent und
__InstanceDeletionEvent sind alle von der Klasse __InstanceOperationEvent abgeleitet.
Wenn Sie also in der WQL-Benachrichtigungsabfrage __InstanceOperationEvent verwenden,
dann werden Sie über alle Ereignisse informiert.
1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:" &_
3 "{impersonationLevel=impersonate}!" &_
4 "\\" & strComputer & "\root\cimv2")
5
1 strComputer = "."
2 Set objSWbemServices = _
3 GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
4
5 Set objSWbemEventSource = objSWbemServices.ExecNotificationQuery( _
6 "SELECT * FROM __InstanceModificationEvent " & _
7 "WITHIN 1 " & _
8 "WHERE (TargetInstance " & _
9 "ISA 'Win32_Process' " & _
10 "AND TargetInstance.Name = 'notepad.exe') " & _
11 "OR (TargetInstance " & _
12 "ISA 'Win32_Service' " & _
13 "AND TargetInstance.Name='w3svc')")
14
15Set objSWbemObject = objSWbemEventSource.NextEvent()
16Select Case objSWbemObject.TargetInstance.Path_.Class
17 Case "Win32_Process"
18 WScript.Echo "Instanz von notepad.exe geändert."
19 Case "Win32_Service"
20 WScript.Echo "Status von Dienst W3SVC geändert."
21End Select