Sie sind auf Seite 1von 394

Microsoft Windows 2000 - Scripting-

Handbuch (Teil 1)

Seite 1 von 394


Microsoft Windows 2000 - Scripting-Handbuch (Teil 1).................................................... 1
Scripting-Konzepte und -Technologien zur Systemadministration: Kapitel 1 - Einführung in
die Windows-Scripting-Technologien..................................................................................... 8
Wodurch hat sich Scripting einen so schlechten Ruf erworben?...............................10
Über dieses Buch............................................................................................................12
Woher weiß ich, ob das Buch für mich geeignet ist?...................................................13
Aufbau des Buches ........................................................................................................13
Die in diesem Buch verwendeten Scripte..................................................................14
Wo lassen sich die fehlenden Teile finden?..............................................................14
Ein Hinweis zu VBScript .............................................................................................15
Systemanforderungen....................................................................................................16
Scripting-Konzepte und -Technologien zur Systemadministration:Kapitel 2 - VBScript.........16
Übersicht zu VBScript .......................................................................................................17
Arbeiten mit Objekten .......................................................................................................18
Mit Objekten verbinden..................................................................................................19
Eine Objektreferenz erstellen ........................................................................................20
Methoden aufrufen ........................................................................................................20
Attribute Abfragen .........................................................................................................21
Variablen ..........................................................................................................................22
Konstanten .......................................................................................................................23
Zeichenketten ...................................................................................................................24
Zeichenketten als Variablen ..........................................................................................26
Verketten von Zeichenketten.........................................................................................27
Collections (Sammlungen) ................................................................................................28
For Each .......................................................................................................................29
Collections ohne Elemente............................................................................................30
Schleifen...........................................................................................................................31
For Next ........................................................................................................................31
Entscheidungen treffen .....................................................................................................33
Mehre Aktionen mit If Then Else durchführen................................................................34
Arrays (Felder)..................................................................................................................35
Eingabe ............................................................................................................................36
Fehlerbehandlung.............................................................................................................38
Das Err-Objekt ..............................................................................................................38
Fehler löschen...............................................................................................................41
VBScript-Referenz ............................................................................................................41
Arbeiten mit Variablen.......................................................................................................43
Variablen unter VBScript deklarieren.............................................................................44
Initialisierung von Variablen...........................................................................................44
Verwendung von Konstanten ............................................................................................46
Definieren von Konstanten ............................................................................................47
Vordefinierte Konstanten verwenden.............................................................................47
Datentypen unter VBScript................................................................................................49
Mit Datum- und Zeitinformationen arbeiten .......................................................................52
Abfragen der aktuellen Uhrzeit und des Datums............................................................52
Prüfen, ob ein Wert ein gültiges Datum ist.....................................................................52
Teile eines Datums oder eines Zeitwertes abfragen ......................................................54
Formatierung von Datum- und Zeitwerten .....................................................................60
Arbeiten mit Strings (Zeichenketten) .................................................................................62
Manipulation von Strings und String-Längen .................................................................63
In einem String nach Text suchen .................................................................................67
Groß- und Kleinbuchstaben...........................................................................................68
Arbeiten mit Zahlen...........................................................................................................69
Rechenreihenfolge ........................................................................................................69
Formatierung von Zahlen ..............................................................................................70
Prozentwerte formatieren ..............................................................................................72

Seite 2 von 394


Befehle mehrfach ausführen .............................................................................................73
Do Loop ........................................................................................................................73
Prüfen der Schleifenbedingung .....................................................................................74
Eine Schleife verlassen .................................................................................................75
Entscheidungen treffen .....................................................................................................76
Mehrere Bedingungen prüfen ........................................................................................77
If Then ElseIf .................................................................................................................78
Select Case...................................................................................................................80
Arrays ...............................................................................................................................81
Erstellen von Arrays ......................................................................................................81
Dynamische Arrays erstellen .........................................................................................82
Einen String mit Trennzeichen in ein Array konvertieren ...............................................84
Alternativen zur Verwendung von Arrays.......................................................................85
Fehlerbehandlung.............................................................................................................85
Handhabung von Laufzeitfehlern...................................................................................87
Aktivieren der Fehlerbehandlung...................................................................................89
Fehlerbehandlung in COM-Objekten .............................................................................90
Prozeduren .......................................................................................................................91
Aufrufen einer Prozedur ................................................................................................92
Funktionen ....................................................................................................................94
Parameter an Funktionen übergeben ............................................................................95
Rekursion ......................................................................................................................98
COM-Objekte....................................................................................................................99
Der COM-Prozess .......................................................................................................100
Bindung.......................................................................................................................101
Eine Methode für die Bindung eines Automatisationsobjekts auswählen.....................102
Überprüfen von Objektreferenzen ...............................................................................103
Objekte aus dem Speicher entfernen ..........................................................................103
Scripting-Konzepte und -Technologien zur Systemadministration: Kapitel 3 - Der WSH.....105
WSH-Übersicht ...............................................................................................................106
Standardmäßige Durchführung von Administrationsaufgaben .....................................106
Verwendung von COM-Objekten.................................................................................107
Nutzung von Standard-Features einer WSH-kompatiblen Scriptsprache.....................107
Verwendung von Kommandozeilentools......................................................................108
WSH vs. Cmd.exe .......................................................................................................108
Ein Hinweise zu WSH-Versionen ................................................................................109
Die WSH-Architektur.......................................................................................................109
Komponenten der WSH-Umgebung................................................................................110
Scriptdateien ...............................................................................................................111
Script Hosts.................................................................................................................112
Scripting Language Engines........................................................................................112
COM-Objekte ..............................................................................................................113
Zusammenarbeit der einzelnen Komponenten der WSH-Umgebung ..............................113
Das WSH-Objektmodell ..................................................................................................114
WSH-Script ausführen ....................................................................................................115
Scripte über die Kommandozeile ausführen ................................................................116
Script Host-Optionen ...................................................................................................116
Die Scriptausgaben in eine Textdatei umleiten............................................................118
Ausführung von Scripten planen..................................................................................119
Andere Verfahren zum Starten eines Scripts...............................................................119
WSH-Objekte..................................................................................................................120
Das Objekt WScript.........................................................................................................120
COM-Objekte verwenden ............................................................................................122
Eingaben und Ausgaben .............................................................................................125
Texteingaben und -ausgaben ......................................................................................127
Verwenden von Kommandozeilenargumenten ............................................................132

Seite 3 von 394


Die Scriptausführung steuern ......................................................................................142
WSH-Umgebungsvariablen abfragen ..........................................................................144
Auf Ereignisse reagieren .............................................................................................146
Das Objekt WshShell ......................................................................................................146
Programme ausführen.................................................................................................148
Arbeiten mit Verknüpfungen ........................................................................................154
Arbeiten mit Spezialordnern ........................................................................................157
Umgebungsvariablen ..................................................................................................158
Einträge im Ereignisprotokoll erzeugen .......................................................................162
Schreiben und Lesen in der lokalen Registrierungsdatenbank ....................................163
Tastatureingaben an ein Programm schicken..............................................................165
Das aktuelle Arbeitsverzeichnis eines Scripts abfragen und ändern ............................169
Zeitgesteuerte Nachrichtenfenster anzeigen ...............................................................169
Das Objekt WshNetwork .................................................................................................174
Verwalten von Netzlaufwerken ....................................................................................176
Verwalten von Netzwerkdruckern ................................................................................178
Informationen über den Benutzer und den Computer abfragen ...................................180
Das Objekt WshController...............................................................................................180
Scripte auf einem Remotecomputer ausführen............................................................183
Den Status von Remotescripten überwachen..............................................................183
Die vom Remotescript ausgelösten Fehler genauer untersuchen................................185
Beschränkungen im Zusammenhang mit Remotescripten...........................................186
Absichern von Scripten ...................................................................................................186
Signieren von Scripten....................................................................................................187
Die Verwendung von signierten Scripten erzwingen....................................................187
Scripte über ein mit Hilfe eines Scripts signieren.........................................................188
Eine Signatur mit Hilfe eines Scripts überprüfen..........................................................188
Die Ausführung von Scripten einschränken ....................................................................189
Deaktivieren des Windows Script Host ........................................................................190
Scripting-Konzepte und -Technologien zur Systemadministration - Kapitel 4 - Die Script-
Laufzeitbibliothek................................................................................................................190
Script Laufzeitbibliothek-Übersicht ..................................................................................191
Das Objekt FileSystemObject .........................................................................................192
Verwalten von Laufwerken..............................................................................................192
Eine Collection mit Laufwerken abrufen ......................................................................193
Binden an ein bestimmtes Laufwerk ............................................................................193
Auflisten der Laufwerkseigenschaften .........................................................................194
Prüfen, ob ein Laufwerk bereit ist ................................................................................196
Verwalten von Ordnern ...................................................................................................196
Eine Referenz auf einen Ordner erstellen....................................................................197
Prüfen, ob ein Ordner vorhanden ist............................................................................197
Einen Ordner erstellen.................................................................................................198
Löschen eines Ordners ...............................................................................................198
Ordner und deren Inhalte kopieren..............................................................................199
Verschieben von Ordnern und deren Inhalten .............................................................200
Ordner umbenennen ...................................................................................................201
Verwenden von Ordnereigenschaften.............................................................................201
Auflisten von Ordnereigenschaften..............................................................................202
Verwalten von Ordnerattributen ......................................................................................203
Ändern von Ordnerattributen .......................................................................................206
Auflisten der Dateien in einem Ordner.........................................................................206
Auflisten von Unterordnern..........................................................................................207
Verwalten von Dateien....................................................................................................209
Eine Referenz auf eine Datei erstellen ........................................................................209
Prüfen, ob eine Datei vorhanden ist.............................................................................210
Löschen einer Datei ....................................................................................................211

Seite 4 von 394


Kopieren einer Datei....................................................................................................212
Verschieben einer Datei ..............................................................................................213
Eine Datei umbenennen ..............................................................................................213
Abfragen von Dateieigenschaften ...................................................................................214
Auflisten der Dateiattribute ..........................................................................................215
Konfigurieren von Dateiattributen ................................................................................216
Den Pfad einer Datei verarbeiten ................................................................................217
Abfragen der Dateiversion...........................................................................................218
Textdateien lesen und schreiben ....................................................................................218
Textdateien erstellen ...................................................................................................219
Lesen von Textdateien ................................................................................................223
In Textdateien schreiben .............................................................................................227
Das Dictionary-Objekt .................................................................................................230
Ein Dictionary-Objekt erstellen ....................................................................................231
Einträge zu einem Dictionary-Objekt hinzufügen .........................................................232
Bearbeiten von Schlüsseln und Werten in einem Dictionary-Objekt.............................233
Die Zahl der Einträge in einem Dictionary-Objekt abfragen .........................................233
Die Elemente eines Dictionary-Objekts aufzählen .......................................................233
Die Existenz eines Schlüssels prüfen ..........................................................................234
Ein Element in einem Dictionary-Objekt ändern...........................................................235
Elemente aus einem Dictionary-Objekt entfernen........................................................235
Scripting-Konzepte und -Technologien zur Systemadministration: Kapitel 5 - ADSI-Scripting
...........................................................................................................................................237
ADSI-Überblick ...............................................................................................................237
Ein einführendes Beispiel ............................................................................................238
Verwaltung des Verzeichnisdienstes ...........................................................................238
ADSI-Scripting-Grundlagen.............................................................................................239
Primäre ADSI-Scripting-Kategorien .............................................................................239
Erstellen von Active Directory-Objekten ......................................................................239
Bearbeiten von Active Directory-Objekten ...................................................................241
Attribute eines Active Directory-Objekts lesen .............................................................243
Löschen von Active Directory-Objekten.......................................................................244
Vergleich der primären Aufgaben eines ADSI-Scripts .................................................246
Das Erstellen von ADSI-Scripten.................................................................................247
Schritt 1: Eine Verbindung aufbauen ...........................................................................247
Schritt 2: Eine Aufgabe ausführen ...............................................................................251
Schritt 3: Übermitteln an Active Directory ....................................................................254
Mehrere Aufgaben über ein Script durchführen ...........................................................255
Fortgeschrittene ADSI-Scripting-Techniken ....................................................................257
Administration von Multiwert-Attributen .......................................................................258
Ändern von Multiwert-Attributen ..................................................................................258
Lesen von Multiwert-Attributen ....................................................................................263
Das Cachen von Daten ...............................................................................................264
Die Methode GetInfo explizit aufrufen..........................................................................266
Die Methode GetInfoEx ...............................................................................................266
Kopieren, Verschieben und Umbenennen von Objekten .............................................268
Kopieren von Objekten................................................................................................268
Verschieben und Umbenennen von Objekten .............................................................270
Suchen........................................................................................................................273
Suchen in Active Directory ..........................................................................................273
Optimieren der Suchleistung .......................................................................................287
Administrative Aufgaben über einen Ergebnissatz ausführen......................................289
Auflisten der Active Directory-Objekte in Containern ...................................................291
Auflisten von Containerinhalten ...................................................................................292
Root Directory Service Entry .......................................................................................295
Verwendung des rootDSE ...........................................................................................295

Seite 5 von 394


Die Active Directory-Architektur ......................................................................................296
Die physikalische Architektur.......................................................................................297
Die logische Struktur ...................................................................................................297
Klassen und Attribute ..................................................................................................298
Active Directory-Replikation und -Indizierung ..............................................................305
Attribute, die zum globalen Katalog-Server repliziert werden.......................................305
Operative Attribute ......................................................................................................309
Die ADSI-Architektur.......................................................................................................310
ADSI-Schichten...........................................................................................................311
ADSI-Schnittstellen .....................................................................................................315
Scripting-Konzepte und -Technologien zur Systemadministration - Kapitel 6 - WMI-Scripting
...........................................................................................................................................317
WMI-Überblick ................................................................................................................318
Die WMI-Architektur........................................................................................................322
Verwaltete Ressourcen ...............................................................................................323
Die WMI-Infrastruktur ..................................................................................................324
WMI-Provider ..............................................................................................................324
CIMOM........................................................................................................................326
Das CIM-Repository ....................................................................................................327
WMI-Konsumenten......................................................................................................328
WMI-Sicherheit............................................................................................................328
WMI-Namespace-Sicherheit........................................................................................329
DCOM-Sicherheit ........................................................................................................330
Windows-Betriebssystem-Standardsicherheit..............................................................330
Das Common Information Model (CIM)...........................................................................331
Blaupausen .................................................................................................................333
Namespaces ...............................................................................................................334
Klassenkategorien.......................................................................................................338
CIM-Klassentypen .......................................................................................................342
Komponenten einer Klasse .........................................................................................344
Erkunden des CIM-Repository.....................................................................................352
Die WMI-Scripting-Bibliothek ..........................................................................................353
Das Objektmodell der WMI-Scripting-Bibliothek ..........................................................353
SWbemLocator ...........................................................................................................356
SWbemServices..........................................................................................................358
Schreiben von WMI-Scripten ..........................................................................................363
Eine Verbindung zu WMI über den WMI-Moniker aufbauen ........................................363
Das Prefix 'WinMgmts:'................................................................................................363
WMI-Sicherheitseinstellungen .....................................................................................364
Verwenden von WMI-Objektpfaden.............................................................................369
Abfragen von verwalteten Ressourcen über die WMI-Abfragesprache ........................370
Abfragen aller Eigenschaften aller Instanzen einer Klasse ..........................................372
Abfragen ausgewählter Eigenschaften aller Instanzen einer Klasse ............................372
Abfragen aller Eigenschaften für ausgewählten Instanzen einer Klasse ......................373
Zielgerichtete Abfragen über AND oder OR erstellen ..................................................376
Ausgewählte Eigenschaften für ausgewählte Instanzen einer Klasse zurückgeben.....377
Schnellere Abfragen über Forward-only erzeugen.......................................................377
Arbeiten mit Datum- und Zeitwerten ............................................................................378
WMI-Datumwerte in das Standardformat konvertieren ................................................380
Ein Standarddatum in ein WMI-Datum konvertieren ....................................................381
Scripte auf Basis von WMI-Vorlagen erstellen.............................................................383
Abfragen und Anzeigen der einzelnen Eigenschaften verwalteter Ressourcen ...........383
Abfragen und Anzeigen aller Eigenschaften einer verwalteten Ressource ..................384
Schreiben von Ressourceneigenschaften ...................................................................385
Aufrufen von Methoden ...............................................................................................385
Erstellen von Ressourcen............................................................................................386

Seite 6 von 394


Löschen von Ressourcen ............................................................................................387
Überwachen von Ressourcen über WMI-Ereignisbenachrichtigungen.........................387
Die drei Schritte eines Überwachungsscripts...............................................................389
Wie die Ereignisbenachrichtigung arbeitet...................................................................390
Erweiterte Überwachung .............................................................................................392

Seite 7 von 394


Scripting-Konzepte und -Technologien zur
Systemadministration: Kapitel 1 -
Einführung in die Windows-Scripting-
Technologien
Veröffentlicht: 26. Apr 2004
(Engl. Originaltitel: Introduction to Windows Script Technologies)
Dieses Kapitel des "Microsoft Windows 2000 - Scripting-Handbuchs" bietet eine Einführung
in das Thema Scripting im Allgemeinen und in die Windows-Scripting-Technologien im
Speziellen. Zudem erläutert es Aufbau, Inhalt und Zielsetzung des Handbuchs sowie die
Systemanforderungen, die für die im Buch beschriebenen Muster-Scripte erfüllt sein müssen.
Dies ist ein Buch über das Scripting für Systemadministratoren. Wie die meisten
Systemadministratoren wundern Sie sich möglicherweise, warum sich dieses Buch an Sie
wendet. Im Allgemeinen gehört Scripting nicht zu den Dingen, mit denen sich
Systemadministratoren beschäftigen. Jeder weiß: Scripting ist schwer, Scripting ist
zeitaufwendig und für Scripting müssen Sie alle möglichen Abkürzungen lernen - WSH,
WMI, ADSI, CDO, ADO, COM. Systemadministratoren verfügen weder über die Zeit noch
über den Hintergrund, um Scripte schreiben zu können. Oder doch? Eines der Hauptziele
dieses Buches ist es, Missverständnisse wie diese zu beseitigen. Ist Scripting schwer?
Möglicherweise. Andererseits - werfen Sie doch einmal einen Blick auf das folgende Script.
Es führt eine häufig auftretende administrative Aufgabe durch.
Set objNetwork = CreateObject("WScript.Network")
objNetwork.MapNetworkDrive "X:", "\\atl-fs-01\public"
Auch wenn Sie nichts über Scripting wissen und fassungslos auf die erste Zeile blicken,
werden Sie trotzdem erkennen, dass das Script die Freigabe \\atl-fs-01\public zu Laufwerk X
zuordnet. Wenn Sie sich mit der Systemadministration auskennen - das bedeutet, Sie wissen
was eine Freigabe, ein gemapptes Netzlaufwerk und ein UNC-Pfad (Universal Naming
Convention) ist - dann ist der Schritt vom Mappen eines Laufwerks über die grafische
Benutzeroberfläche oder die Kommandozeile zum Mappen eines Laufwerks über ein Script
nicht mehr sehr groß.

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.

Seite 8 von 394


Zugegebenermaßen sind nicht alle Scripte so einfach und intuitiv, wie das eben gezeigte.
Wenn sie dieses Buch durcharbeiten, werden Sie feststellen, dass die meisten der gezeigten
Scripte nicht mehr als 15 bis 20 Zeilen lang sind - und sie führen alle nützlichen
administrativen Aufgaben aus. Viele der Scripte können Sie untersuchen, und über den
Scriptcode können Sie herausfinden, was das Script macht - hierzu ist es ganz egal, wie groß
Ihre Scripting-Erfahrung ist.
Erfordert Scripting viel Zeit? Kann sein. Wenn Sie ein Script schreiben, dass 500 Zeilen lang
ist (das könnte durchaus passieren), dann wird schon das Eingeben des Scriptes eine Menge
Zeit kosten. Wichtiger ist es aber, die Entwicklungszeit des Scriptes und die Zeiteinsparung
durch die Verwendung des Scriptes zu berücksichtigen. Unten finden Sie beispielsweise ein
Script, das alle Ereignisprotokolle eines Computers sichert und löscht.
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate, (Backup, Security)}!\\" _
& strComputer & "\root\cimv2")
Set colLogFiles = objWMIService.ExecQuery _
("Select * from Win32_NTEventLogFile")
For Each objLogfile in colLogFiles
strBackupLog = objLogFile.BackupEventLog _
("c:\scripts\" & objLogFile.LogFileName & ".evt")
objLogFile.ClearEventLog()
Next
Zugegeben, dieses Script ist nicht so intuitiv wie das erste Script. Außerdem werden Sie zur
Entwicklung eines solchen Scripts etwas mehr über Scripting und über WMI lernen müssen.
Und Sie müssen das Script ja auch noch in Notepad eingeben - die ganzen 11 Zeilen.
Aber überlegen Sie Folgendes: Wie lange würde es dauern, die Ereignisprotokolle eines
Computers manuell zu sichern und zu löschen? (Wenn Sie dies überhaupt manuell
durchführen - da das manuelle Löschen und Sichern so mühsam und zeitaufwändig ist, wird
der Vorgang oft einfach vergessen.) Mit einem Script können Sie diese Aufgabe in wenigen
Minuten durchführen. Und wie wäre es, wenn Sie eine weitere halbe Stunde investieren, um
das Script so zu ändern, das es die Ereignisprotokolle auf allen Computern sichert und löscht?
Möglicherweise müssen Sie etwas Zeit und Energie investieren, aber es wird nicht lange
dauern, bis sich diese Investition auszahlen wird.
Noch nicht überzeugt? Auch wenn Scripting nicht schwer und zeitaufwändig ist, so müssen
Sie doch noch immer den ganzen technischen Krimskrams lernen? Sicherlich - wenn Sie ein
Experte im Scripting werden wollen. Schauen Sie sich doch einmal das folgende Script an. Es
gibt die Namen aller auf einem Computer installierten Dienste zurück.
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & _
"{impersonationLevel=Impersonate}!\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Service")
For Each objItem in colItems
Wscript.Echo objItem.Name
Next
Das ist ein recht kompliziertes Script. Neben anderen Dingen verwendet es:
•Objekt-Methoden und -Attribute
•Sprachelemente von Microsoft® Visual Basic® Scripting Edition (VBScript), wie zum
Beispiel eine For-Each-Loop-Schleife um die Elemente einer Collection aufzulisten

Seite 9 von 394


•Einen COM-Moniker (Component Object Model)
•WMI-Objektpfade, -Namensräume und -Klassen
•Eine WMI-Abfrage

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.

Wodurch hat sich Scripting einen so schlechten Ruf


erworben?
Wenn Scripting so einfach ist, warum hat es dann einen so schlechten Ruf? Und wenn es so
nützlich ist, warum nutzen es nicht mehr Systemadministratoren? Schließlich würden die
meisten Systemadministratoren etwas, dass ihnen das Leben einfacher macht, nicht
wissentlich ignorieren.

Seite 10 von 394


Es gibt wahrscheinlich viele Gründe für diesen schlechten Ruf - die meisten von ihnen gehen
aber auf die ersten Versionen der Microsoft® Windows® Script-Technologie zurück.
VBScript und Microsoft® JScript® (die zwei Scriptsprachen, die mit Microsoft® Windows®
zur Verfügung stehen) wurden für clientseitiges Scripting für Webseiten entwickelt. Für
Internet-Entwickler waren sie sehr nützlich - für Administratoren eher nicht. Daher wurde
Scripting oft eher mit der Entwicklung von Webseiten in Verbindung gebracht (auch heute ist
noch eine Menge des Bespielcodes aus der offiziellen Microsoft VBScript-Dokumentation in
eine Webseite eingebettet).
Später wurde der Windows Script Host (WSH) entwickelt. Der WSH ermöglichte die
Verwendung von Scriptsprachen und -Technologien außerhalb von Internet Explorer;
tatsächlich wurde der WSH sogar für Systemadministratoren entwickelt. Trotzdem konnte
sich Scripting in der Systemadministration nicht umfassenden durchsetzen.
Dies lag möglicherweise anfangs an der fehlenden Dokumentation. Es war schwer,
Informationen zur Verwendung von VBScript oder JScript als Systemadministrationstool zu
finden, und Informationen zu Technologien wie WMI oder Active Directory Service
Interfaces (ADSI) zu finden war so gut wie unmöglich. Auch als diese endlich dokumentiert
waren (typischerweise über Software Development Kits), war diese Dokumentation für
Programmierer gedacht. Codebeispiele waren typischerweise in C++ statt in einer
Scriptsprache geschrieben. Stellen Sie sich vor, Sie sind ein typischer Systemadministrator
(mit guten Kenntnissen zu Windows und minimalen Kenntnissen zur Programmierung).
Stellen Sie sich nun vor, Sie suchen auf der Microsoft-Website nach Informationen über
Script und finden den folgenden Beispielcode:
int main(int argc, char **argv)
{
HRESULT hres;
hres = CoInitializeEx(0, COINIT_MULTITHREADED); // Initialize COM.
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
hres = CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_CONNECT,
RPC_C_IMP_LEVEL_IDENTIFY,
NULL, EOAC_NONE, 0
);
Mit einem solchen Beispiel gibt es wohl kaum sehr viele Systemadministratoren, die glauben,
dass WMI oder ADSI praktische Werkzeuge sind.
Heutzutage besteht natürlich kein Mangel mehr an Literatur zum Thema Scripting. Eine
kürzliche Suche bei einem großen Online-Buchversender nach dem Schlüsselwort 'VBScript'
ergab 339 Treffer. Das sind die guten Nachrichten. Die schlechten Nachrichten sind, dass die
meisten dieser Titel nach einem von zwei möglichen Ansätzen arbeiten: Entweder betrachten
sie Scripting weiterhin als Werkzeug für Webentwickler, oder sie konzentrieren sich fast
ausschließlich auf VBScript und WSH. Natürlich sind VBScript und WSH wichtige
Scripting-Technologien, aber für sich alleine sind dieses beiden Technologien nicht in der
Lage, sehr viele nützliche Administrationsaufgaben zu erledigen. Von den 339 gefunden
Scripting-Büchern behandelten nur eine Handvoll Scripting als Administrationswerkzeug, und
nur einige von diesen deckten die Schlüsseltechnologien - WMI und ADSI - umfassend ab.
Ein Systemadministrator, der sich ein oder zwei zufällige Scripting-Bücher anschaut, wird

Seite 11 von 394


wahrscheinlich nicht erkennen, dass Scripting zur Verwaltung von Windows-basierten
Computern extrem nützlich sein kann.

Über dieses Buch


Ist das Microsoft Windows 2000 - Scripting-Handbuch also nur Buch Nummer 340, oder
unterscheidet es sich irgendwie von seinen Vorgängern? Dieses Buch stellt in vielerlei Art
einen neuen Ansatz zum Scripting für die Systemadministration dar. Tatsächlich gibt es vier
eindeutige Punkte, durch die dieses Buch sich von vielen anderen Büchern auf dem Markt
unterscheidet:
•Es konzentriert sich auf Scripting aus der Sicht eines Systemadministrators. In diesem
Buch finden Sie viele Kapitel, die es auch in anderen Scripting-Büchern gibt; Es gibt zum
Beispiel ein Kapitel über VBScript. Der Unterschied besteht darin, dass sich das Kapitel in
diesem Buch auf die VBScript-Elemente konzentriert, die für Systemadministratoren wichtig
sind. Systemadministratoren müssen viel mit COM arbeiten - daher erfahren Sie eine Menge
über die Verwendung von COM-Objekten in einem Script. Systemadministratoren haben
aber zum Beispiel wenig Verwendung für die Berechnung von Kosinus-Werten. Daher
werden solche Themen gar nicht angesprochen - auch wenn es möglich ist, solche
Berechungen mit VBScript durchzuführen.
•Dieses Buch ist aufgabenorientiert und nicht scriptbezogen. In vielen Fällen wurden die
Scripte in diesem Buch nachträglich erstellt. Manchmal erstellt ein Buchautor eine Menge
Scripte und produziert dann einen Text um diese Scripte herum. Diese Buch verwendet einen
ganz anderen Ansatz: Statt mit Scripten zu beginnen, stellen die Autoren erst einmal fest,
welche Schlüsselaufgaben täglich von einem Systemadministrator erledig werden müssen.
Erst dann stellen wir fest, wie diese Aufgaben über Scripte erledig werden können. Daher ist
dieses Buch nicht unbedingt ein Buch über Scripting, sondern ein Buch über die effiziente
Verwaltung von Windows-Computern.
•In diesem Buch werden Tutorials mit praktischen Elementen kombiniert. Einige Bücher
versuchen, Ihnen Scripting beizubringen - daher konzentrieren sie sich eher auf die Konzepte
hinter Scripting. Oft beschränkt sich der praktische Teil auf reine Lippenbekenntnisse.
Andere Bücher verfolgen einen komplett anderen Ansatz: Sie konzentrieren sich auf den
praktischen Teil. Diese Bücher stellen Ihnen eine Menge nützlicher Scripte zur Verfügung,
helfen Ihnen aber nicht dabei diese Scripte auch zu verstehen. Sie sind also nicht in der Lage,
die Scripte zu verändern. In dem vorliegenden Buch versuchen wir das Beste aus beiden
Ansätzen zu kombinieren. Wenn zum Beispiel ein nützliches Script zur
Systemadministration präsentiert wird, dann wird dieses Script auch Schritt für Schritt
erklärt. Sie erfahren, wie dieses Script arbeitet und wie Sie es an Ihre persönlichen
Bedürfnisse anpassen können.
•Dieses Buch berücksichtigt, dass mit der Größe einer Organisation auch der Bedarf an
der Automatisierung von Prozessen wächst. Die Scripte in diesem Buch können sogar
dann für Sie von Nutzen sein, wenn Sie Systemadministrator in einer Organisation mit nur
einem Computer sind. Um ehrlich zu sein, werden Sie es aber wohl einfacher finden, Ihren
einzelnen Computer über die Benutzeroberfläche zu verwalten. Wenn Sie 100 oder 1000
Computer verwalten, dann wird der Nutzen von Scripten und Scripting jedoch auf einmal
dramatisch ansteigen. Um dies zu berücksichtigen, gibt es in diesem Buch extra ein eigenes
Kapitel - Creating Enterprise Scripts - in dem besprochen wird, wie Sie die Beispiele für
eine Organisation mit vielen Computern anpassen können.

Seite 12 von 394


Woher weiß ich, ob das Buch für mich geeignet ist?
Offiziell wurde dieses Buch für Systemadministratoren in mittleren bis großen Organisationen
geschrieben, die sich mit der Verwaltung von Windows-Computern beschäftigen. Diese
Gruppe wird wahrscheinlich den Großteil der Leser darstellen, ganz einfach, weil sich das
Buch mit der Systemadministration beschäftigt und weil Systemadministratoren in mittleren
und großen Organisationen die Personen sind, die die gezeigten Scripte nutzen.
Das Buch sollte jedoch auch für alle Anderen nützlich sein, die das Entwickeln von Scripten
lernen möchten. Obwohl sich die in diesem Buch besprochenen Techniken auf mittlere bis
große Organisationen konzentrieren, können Sie in den meisten Fällen auch in kleinen
Organisationen effektiv eingesetzt werden. Bei diesen Techniken handelt es sich
typischerweise um administrative Aufgaben, sie können jedoch auch von
Anwendungsprogrammierern und Web-Entwicklern umgesetzt werden. Die Verwaltung von
Microsoft Exchange Server über Scripting wird in diesem Buch nicht besprochen; Microsoft
Exchange Server kann allerdings über WMI verwaltet werden. Daher könnte für Exchange-
Administratoren nicht nur das Kapitel WMI Scripting interessant sein, sondern auch das
Kapitel VBScript - in diesem werden grundlegende Techniken zur Arbeit mit
Automatisationsobjekten besprochen.
Auch Personen, die bereits über unterschiedliche Erfahrungsstufen im Scripting-Bereich
verfügen, werden das Buch nützlich finden. Es wird jedoch keinerlei Erfahrung im Scripting-
Bereich vorausgesetzt. Wenn Sie das Buch von Anfang bis Ende durchlesen, werden Sie mit
den fundamentalen Grundlagen des Scripting beginnen und sich dann zu den komplexeren
Szenarien hocharbeiten. Was ist, wenn Sie sich bereits mit VBScript auskennen, jedoch nicht
viel über ADSI wissen? Springen Sie direkt zum Kapitel ADSI-Scripting. Sie kennen die
grundlegenden Prinzipien von WMI, möchten aber wissen, wie Sie über WMI Prozesse
erstellen und beenden? Springen Sie direkt zum Abschnitt Processes.
In diesem Buch gibt es für jeden interessante Informationen. Es wird kein Wissen
vorausgesetzt. Dies heißt jedoch nicht, dass nicht gelegentlich eine Aufgabe oder eine
Technik besprochen wird, die fortgeschrittene Kenntnisse erfordern.

Aufbau des Buches


Das Microsoft Windows 2000 - Scripting-Handbuch ist in drei Teile aufgeteilt:
•Konzeptuelle Kapitel. Diese Kapitel geben Ihnen einen umfassenden Überblick zu den
primären Microsoft-Scripting-Technologien, inklusive Windows Script Host (WSH),
VBScript, WMI, ADSI und der Script-Laufzeitbibliothek (Runtime library). Die Kapitel
haben Tutorial-Charakter, und sind alle vom Standpunkt eines Systemadministrators aus
geschrieben. Sie gehen alle davon aus, dass der Leser über keine oder nur geringe Erfahrung
mit Scripting verfügt.
•Aufgabenbasierte Kapitel. In diesem Kapitel werden die Kernbereiche der
Systemadministration identifiziert, inklusive solcher Dinge, wie dem Verwalten von
Diensten, Druckern und Ereignisprotokollen. Für jeden Kernbereich werden ca. 25 häufige
Aufgaben identifiziert, zum Beispiel das Starten und Anhalten von Diensten, die Änderung
von Dienstkonten-Passwörtern und das Feststellen der ausgeführten Dienste. Zu jeder
Aufgabe erhalten Sie eine genaue Beschreibung der Aufgabe und warum diese wichtig ist,

Seite 13 von 394


ein Beispielscript, das diese Aufgabe ausführt, und eine Schritt-für-Schritt-Anleitung zur
Arbeitsweise des Scriptes. Außerdem erfahren Sie, wie Sie das Script an Ihre eigenen
Bedürfnisse anpassen können.
•Unternehmens-Kapitel. Diese Kapitel decken einen großen Themenbereich ab, inklusive
der Einrichtung einer Scripting-Infrastruktur und der Scripterstellung in einem
administrativen Team. Außerdem erfahren Sie mehr dazu, wie Sie ein Script in ein
Unternehmens-Script umwandeln können - zum Beispiel ein Script, dass eine bestimmte
Aktion auf allen Domänencontrollern oder für alle Benutzerkonten ausführt, oder ein Script,
das Argumente aus einer Textdatei oder Datenbank entgegennimmt.
Sie müssen nicht auf Seite Eins beginnen und das gesamte Buch bis zu Ende durchlesen. Es
ist so gestaltet, dass Sie die Möglichkeit haben, nur die Teile zu lesen, die Sie interessieren.
Wenn Sie jedoch noch nicht über Erfahrung im Scripting-Bereich verfügen, dann sollten Sie
als Erstes die Kapitel über VBScript und WMI lesen.
Wenn Sie sich mehr für die Verwendung von Scripten als für deren Entwicklung
interessieren, dann können Sie mit den aufgabenbasierten Kapiteln beginnen. Lesen Sie ein
Kapitel, kopieren Sie die Scripte und führen Sie diese aus, um zu sehen, was passiert. Wenn
Sie genauer verstehen möchten, wie diese Scripte arbeiten, dann springen Sie zu den
konzeptionellen Kapiteln zurück.

Die in diesem Buch verwendeten Scripte


Die meisten Personen, die eine Vorab-Kopie dieses Buches gesehen haben, stellten überrascht
- und dankbar - fest, dass die Scripte sehr kurz sind. Viele hatten Scripting-Bücher gelesen, in
denen die Beispielscripte über zwei oder drei Seiten gingen, und waren überrascht, dass
Scripting so einfach sein kann.
Es gab allerdings auch Personen, die darüber schockiert waren, dass die Scripte so einfach
gehalten sind. Nur sehr wenige der Beispielscripte verwenden zum Beispiel eine
Fehlerbehandlung. Warum verwenden wir also keine Beispielscripte, wie sie auch in einer
echten Produktionsumgebung vorkommen würden?
Die Antwort ist einfach: Die Scripte aus diesem Buch sind nicht für eine Verwendung in
einem Produktionssystem vorgesehen. Stattdessen sind sie zu Lernzwecken gedacht. Sie
sollen Ihnen zeigen, wie Sie mit den unterschiedlichen Scripting-Technologien und -
Techniken umgehen. Die meisten der Scripte können zwar durchaus zur Systemadministration
verwendet werden, dabei handelt es sich aber eher um einen glücklichen Zufall; dieses Buch
und die enthaltenen Scripte wurden entwickelt, um Ihnen das Schreiben von Scripten
beizubringen. Sie selbst sind nicht zu Verwaltung gedacht.

Wo lassen sich die fehlenden Teile finden?


Nur weil die Scripte einfach gehalten wurden, heißt das nicht, dass Konzepte, wie zum
Beispiel die Fehlerbehandlung oder die Verarbeitung von Parametern, ignoriert werden.
Solche Techniken werden in den Kapiteln Creating Enterprise Scripts und Scripting
Guidelines dieses Buches besprochen. Auch wenn Sie in diesem Buch keine Fünfhundert-
Zeilen-Scripte finden, die jede nur denkbare Scripting-Technik verwenden, werden doch alle
diese Techniken irgendwo in diesem Buch beschrieben. Indem solche Dinge wie eine
Fehlerbehandlung weggelassen werden, werden die Scripte aus diesem Buch so kurz wie
möglich. Sie konzentrieren sich auf die jeweilige Aufgabe. Nehmen wir zum Beispiel einmal
das erste Script aus diesem Kapitel, das zum Mappen eines Netzlaufwerkes verwendet wird:

Seite 14 von 394


Set objNetwork = CreateObject("WScript.Network")
objNetwork.MapNetworkDrive "X:", "\\atl-fs-01\public"
Dieses Script ist so einfach gehalten, wie nur möglich. Sie brauchen es nicht lange studieren,
bevor Sie sagen können: 'Oh, so werden also Netzlaufwerke über ein Script gemappt". In
einer Produktionsumgebung werden Sie das Script zugegebenermaßen anpassen wollen. Zum
Beispiel so, dass der Benutzer einen Laufwerksbuchstaben und eine Freigabe angeben kann.
Dies ist kein Problem, Sie benötigen jedoch einigen zusätzlichen Script-Code. So würde aus
einem einfachen zweizeiligen Script ein Script mit mindestens 22 Zeilen. Die Grundidee - ein
einfache Script, das das Mappen von Laufwerken demonstriert - wäre so verloren.

Ein Hinweis zu VBScript


Alle Scripte in diesem Buch sind in VBScript geschrieben. Die Einscheidung für VBScript
und gegen andere Scriptsprachen wurde aufgrund von drei Faktoren getroffen:
•Mit Ausnahme von Perl, ist VBScript die populärste Scriptsprache zur Erstellung von
administrativen Scripten. Es macht Sinn, eine Sprache auszuwählen, mit der die Leser bereits
möglichst vertraut sind.
•Im Gegensatz zu Perl wird VBScript auf allen Windows 2000-Computern automatisch
installiert (Jscript übrigens auch). Daher sind mit VBScript keine Anschaffungen oder
Installationen notwendig.
•VBScript ist einfacher zu lernen als Jscript. Als kleiner Bonus ist VBScript Visual Basics
sehr ähnlich. Visual Basic ist eine Programmiersprache, mit der einige
Systemadministratoren möglicherweise bereits erste Erfahrungen gesammelt haben.
In anderen Worten: VBScript ist einfach zu verwenden, erfordert keine zusätzlichen
Investitionen und es muss nichts heruntergeladen oder installiert werden.
Um ehrlich zu sein, ist in vielen Fällen die verwendete Scriptsprache irrelevant. VBScript
selbst bietet relativ wenig Unterstützung zur Systemadministration. Es bietet die meisten
Möglichkeiten, wenn es mit WSH, WMI, ADSI und anderen Scripting-Technologien
eingesetzt wird. Hier unterscheidet sich VBScript nicht von anderen Scriptsprachen. Der
allergrößte Teil der Scripte aus diesem Buch verwendet WMI oder ADSI - die Scriptsprache
ist hier eigentlich irrelevant. Möchten Sie lieber mit JScript oder ActiveState ActivePerl
arbeiten? Kein Problem - alles, was Sie lernen müssen, ist, wie Sie sich mit diesen Sprachen
mit WMI oder ADSI verbinden.
Das nächste Script ist ein WMI-Script. Es fragt den Namen des installierten BIOS ab, und
zeigt diesen an. Das Script ist in VBScript geschrieben.
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\ " _
& strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery _
("Select * from Win32_BIOS")
For Each objItem in colItems
Wscript.Echo objItem.Name
Next
Das nächste Script entspricht dem vorherigen. Es ist nur in JScript geschrieben. Wie Sie sehen
können, sind Syntax und Sprachkonventionen unterschiedlich, aber die Schlüsselelemente
(fett dargestellt) bleiben gleich - Verbinden mit WMI, Abfragen der Informationen über die
Klasse Win32_BIOS, Ausgabe des BIOS-Namens. Sie sehen also, die Auswahl der Sprache
ist mehr eine Frage des persönlichen Geschmacks.

Seite 15 von 394


var strComputer = ".";
var objWMIService = GetObject("winmgmts:\\\\ " +
strComputer + "\\root\\cimv2");
var colItems = objWMIService.ExecQuery
("Select * from Win32_BIOS");
var e = new Enumerator(colItems);
for (;!e.atEnd();e.moveNext()) { var objItem = e.item();
WScript.Echo(objItem.Name);
}
Anmerkung:
•In der Realität gibt es einige kleine Unterschiede zwischen den Scriptsprachen. Diese wirken
sich auf das aus, was Sie mit den Scripten durchführen können oder nicht durchführen
können. Diese Unterschiede sind jedoch nicht wirklich einer Diskussion wert.

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.

Scripting-Konzepte und -Technologien zur


Systemadministration:Kapitel 2 - VBScript
Veröffentlicht: 26. Apr 2004
(Engl. Originaltitel: VBScript Overview)
Microsoft Visual Basic Scripting Edition (VBScript) ist eine einfach zu verwendende
Scriptsprache, die es Systemadministratoren ermöglicht, hervorragende Tools zur Verwaltung
von Windows-Computern zu entwickeln. In der ersten Hälfte dieses Kapitels werden die

Seite 16 von 394


grundlegenden Prinzipien von VBScript beschrieben. Hierbei wird ein Script erstellt, das den
freien Festplattenplatz von Laufwerk C anzeigt. Im Laufe des Kapitels wird das Script zu
einem verfeinerten Tool weiter entwickelt, das den freien Festplattenplatz von beliebigen
Laufwerken anzeigen kann. Der zweite Teil des Kapitels bespricht die grundlegenden
Prinzipien genauer und stellt andere VBScript-Konstrukte dar.
Microsoft® Visual Basic® Scripting Edition (VBScript) ist eine einfach zu verwendende
Scriptsprache, die es Systemadministratoren ermöglicht, hervorragende Tools zur Verwaltung
von Windows-Computern zu entwickeln. In der ersten Hälfte dieses Kapitels werden die
grundlegenden Prinzipien von VBScript beschrieben. Hierbei wird ein Script erstellt, das den
freien Festplattenplatz von Laufwerk C anzeigt. Im Laufe des Kapitels wird das Script zu
einem verfeinerten Tool weiter entwickelt, das den freien Festplattenplatz von beliebigen
Laufwerken anzeigen kann. Der zweite Teil des Kapitels bespricht die grundlegenden
Prinzipien genauer und stellt andere VBScript-Konstrukte dar.

Ü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

1Set objWMIService = GetObject("winmgmts:")


2Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
3Wscript.Echo objLogicalDisk.FreeSpace
Es kann natürlich sein, dass das Script nicht alle Ihre Wünsche erfüllt. Das Script zeigt Ihnen
beispielsweise nur den freien Plattenplatz des lokalen Computers - und hier auch nur für
Laufwerk C.
Das Script kann jedoch einfach angepasst werden, ohne neu anfangen zu müssen. Dies ist ein
weiterer Vorteil von Scriptsprachen und VBScript: Sie können mit einem eher einfachen
Script anfangen und dies dann Ihren Bedürfnissen anpassen. Dieses Kapitel beschreibt einen
solchen Vorgang. Sie fangen mit Script 2.1 an, und in den folgenden Abschnitten werden Sie
dann zu diesem einfachen dreizeiligen Script weitere Funktionalitäten hinzufügen. Nach
diesen Erweiterungen haben Sie dann ein Script, das die folgenden Funktionen zur Verfügung
stellt:

Abfragen des freien Plattenplatzes von jedem Computer in Ihrer Organisation - auch von
Remotecomputern.

Seite 17 von 394



Abfragen des freien Plattenplatzes von mehreren Computern.

Abfragen des freien Plattenplatzes aller Laufwerke eines Computers.

Anzeigen einer Benachrichtigung, wenn nur noch wenig Platz auf einen Laufwerk verfügbar
ist.

Kein Fehler oder Abbruch, wenn der Benutzer einen ungültigen Computernamen angibt, oder
wenn auf einen Computer über das Netzwerk nicht zugegriffen werden kann.
Jedes Mal, wenn neue Features zum Script hinzugefügt werden, werden die verwendeten
VBScript-Konstrukte ausführlich erklärt. Nachdem das Script vollständig ist, finden Sie einen
Referenzabschnitt, der diese Konstrukte (und andere) detaillierter abdeckt.

Arbeiten mit Objekten


Mit VBScript können Sie über Programmiertechniken wie Verzweigungen, Schleifen,
Fehlerbehandlung und Funktionsaufrufen sehr komplexe Scripte erstellen. Was Sie jedoch
nicht finden werden, sind eingebaute Funktionen zu Systemadministration. VBScript verfügt
über Funktionen, mit denen Sie die Wurzel einer beliebigen Zahl ermitteln oder den ASCII-
Wert eines Zeichens anzeigen können - es gibt aber keine Funktionen um diesen anzuhalten,
Einträge aus dem Systemprotokoll abzurufen oder andere Administrationsaufgaben
durchzuführen.
Glücklicherweise gibt es andere Möglichkeiten solche Aufgaben durchzuführen - und zwar
primär über Automatisationsobjekte. Automatisationsobjekte sind eine Untermenge von COM
(Component Object Model). COM ist eine Möglichkeit für Anwendungen (exe-Dateien) oder
Programmbibliotheken (dll-Dateien) ihre Funktionalitäten als Objekte zur Verfügung zu
stellen. Diese Objekte und die von ihnen zu Verfügung gestellten Funktionalitäten können
dann von Programmierern (oder Scriptautoren) in eigenen Anwendungen oder Scripten
verwendet werden. Ein Textverarbeitungsprogramm könnte zum Beispiel seine
Rechtschreibprüfung als Automatisationsobjekt zur Verfügung stellen. Ein Scriptautor kann
dieses Objekt dann zur Rechtschreibprüfung in seinem Script verwenden.
Die Möglichkeit mit Automatisationsobjekten zu arbeiten, und die Methoden (auch
Funktionen genannt) und Attributen (Eigenschaften) dieses Objekte verwenden zu können,
macht VBScript zu einem mächtigen Tool in der Systemadministration. Alleine ist VBScript
nicht in der Lage auf das Ereignisprotokoll zuzugreifen. Mit der Funktionalität von WMI wird
dies jedoch auf einmal möglich. VBScript verfügt über keine eigenen Verfahren, um
Benutzerkonten zu erstellen. Sie können jedoch die Funktionalität von ADSI für diese
Aufgaben verwenden. Statt also eine riesige Menge von eigenen Funktion zur Verfügung zu
stellen, bietet VBScript eher die Rahmenbedingungen, um die Methoden und Attribute von
Automatisationsobjekten zu nutzen.
Script 2.2 zeigt die Bedeutung von Automatisationsobjekten in VBScript. Dieses Script gibt
wiederum den freien Festplattenplatz von Laufwerk C zurück. Es verwendet nur sehr wenig
VBScript-Code. Stattdessen macht es folgendes:
1.Es baut über die VBScript-Methode GetObject eine Verbindung zu WMI auf (WMI ist ein
Automatisationsobjekt).
2.Es verwendet die Methode Get von WMI, um die Informationen über Laufwerk C

Seite 18 von 394


abzurufen.
3.Es verwendet die Methode Echo von WSH (ein weiteres Objekt), um diese Informationen
anzuzeigen.
Wie gesagt, es gibt relativ wenig VBScript-Code in diesem Script. Stattdessen wird VBScript
primär dazu verwendet, die Funktionalitäten von WMI und WSH zu verbinden.

Script 2.2: Objekte mit VBScript verwenden

1Set objWMIService = GetObject("winmgmts:")


2Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
3Wscript.Echo objLogicalDisk.FreeSpace

Mit Objekten verbinden


Bevor Sie die Daten einer Datenbank verwenden können, müssen Sie sich irgendwie mit
dieser Datenbank verbinden. Bei Objekten ist das genauso - bevor Sie die Methoden
(Funktionen) und Attribute (Eigenschaften) eines Automatisationsobjektes verwenden
können, müssen Sie eine Verbindung zu diesem Objekt aufbauen. Dieses Verfahren wird auch
als Einbinden von Objekten in ein Script bezeichnet.
Das Einbinden von Objekten kann ein wenig verwirrend sein, da sowohl die Sprache
VBScript als auch der WSH (Windows Scripting Host) über eine Methode GetObject und
CreateObject für den Zugriff auf Objekte verfügen. Auch wenn die beiden Methoden bei
VBScript und bei WSH fast gleich arbeiten, so gibt es doch kleine Unterschiede - und diese
werden immer wichtiger, je geübter Sie im Schreiben von Scripten werden. Diese
Unterschiede werden später in diesem Kapitel besprochen. Im Moment stellen Sie sich
einfach dumm und kümmern sich nicht darum, ob Sie die beiden Methoden über VBScript
oder den WSH verwenden (in dem meisten Fällen werden Sie die VBScript-Varianten dieser
beiden Methoden verwenden).

WMI oder ADSI über GetObject einbinden. Sowohl WMI als auch ADSI ermöglichen Ihnen
die Verwendung eines Monikers bei der Einbindung eines Scripts. Ein Moniker ist ein
Zwischenobjekt, das die Nutzung von Objekten vereinfacht (das Thema wird weiter unten in
diesem Kapitel genauer besprochen). Auch wenn es möglich (und manchmal erforderlich)
ist, WMI oder ADSI über die Methode CreateObject einzubinden, ist die Verwendung von
GetObject und eines Monikers in dem meisten Fällen schneller und einfacher.

WMI oder ADSI über CreateObject einbinden. Im Allgemeinen benötigen Sie die Methode
CreateObject, um neue Instanzen eines Objektes zu erstellen (zum Beispiel Instanzen der
Objekte FileSystem, Dictionary oder Internet Explorer).

Eine Verbindung zu WSH aufbauen


In Zeile 1 von Script 2.2 wird über den folgenden Ausdruck WMI in das Script eingebunden:
Set objWMIService = GetObject("winmgmts:")
Mit dieser Zeile wird das Script mit dem SWbemServices-Objekt von WMI verbunden.
Um eine Verbindung zu WSH aufzubauen, ist so etwas nicht nötig. Sie sind bereits mit WSH
verbunden, da WSH zur Ausführung eines Scriptes benötigt wird. Das WSH-Objekt steht
somit also in jedem Script ohne Ihr Zutun zur Verfügung.

Seite 19 von 394


Eine Objektreferenz erstellen
In der Automatisation arbeiten Sie nicht direkt mit den Objekten selbst. Stattdessen erstellen
Sie eine Referenz mit Hilfe von GetObject oder CreateObject auf das Objekt, und weisen
diese Referenz dann einer Variable zu. Nachdem Sie eine solche Referenz erstellt haben,
können Sie dann über die Variable statt über das Objekt selbst auf die Methoden und Attribute
des Objektes zugreifen.
In Script 2.2 wird die Methode GetObject verwendet, um der Variable objWMIService einen
Verweis auf das WMI-Objekt SWbemServices zuzuweisen. Nach der Zuweisung können alle
Attribute und Methoden des SWbemServices-Objektesüber die Variable objWMIService
abgefragt und aufgerufen werden. In Zeile Zwei des Scripts wird zum Beispiel die Methode
Get des Objektes zur Abfrage der Eigenschaften von Laufwerk C aufgerufen.
Jedes Mal, wenn Sie einer Variable eine Referenz (einen Verweis) auf ein Objekt zuweisen,
dann müssen Sie das VBScript-Schlüsselwort Set verwenden. Der folgende Code würde zum
Beispiel zu einem Laufzeitfehler (einen Fehler bei der Ausführung des Scripts) führen:
objWMIService = GetObject("winmgmts:")
Stattdessen müssen Sie zur Erstellung einer Objektreferenz das Schlüsselwort Set verwenden:
Set objWMIService = GetObject("winmgmts:")
Das Schlüsselwort Set wird in VBScript nur zur Erstellung einer Objektreferenz verwendet.
Wenn Sie es für andere Zwecke verwenden, zum Beispiel zum Zuweisen eines Wertes zu
einer Variable, dann wird ein Laufzeitfehler auftreten. Der folgende Code wird zum Beispiel
zu einem Fehler führen:
Set x = 5
Warum? Set kann nur zum Zuweisen von Objekten zu Variablen verwendet werden. Da 5
jedoch kein Objekt ist, tritt ein Fehler auf.

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.

Seite 20 von 394


Nachdem Sie eine Referenz auf ein Objekt erstellt haben, können Sie über die Punkt-
Schreibweise (Notation) die Methoden des Objektes aufrufen. Die Punkt-Notation wird so
genannt, da Sie beim Aufruf einer Methode den Namen der Variable schreiben, die den
Verweis (die Referenz) auf das Objekt enthält, und dann einen Punkt und den Namen der
gewünschten Methode des Objektes schreiben (abhängig von der Methode müssen Sie
möglicherweise noch Parameter anhängen). Im Allgemeinen wird bei der Punkt-Notation die
folgende Syntax verwendet:
Objektreferenz.MethodenName
In der folgenden Codezeile sehen Sie ein Beispiel für die Punkt-Notation. Sie ruft die
Methode Get des Objektes SWbemServices auf.
Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
Die einzelnen Teile des Aufrufes der Methode Get des Objektes SWbemServices sind in
Tabelle 2.1 genauer beschrieben.

Tabelle 2.1: Die einzelnen Teile des Methodenaufrufes


Teil Beschreibung
ObjWMIService Die Objektreferenz
. Der Punkt trennt die Objektreferenz vom Namen der
aufgerufenen Methode des Objektes.
Get Der Name der Methode
('Win32_LogicalDisk.DeviceID='c:'')Parameter der Methode. Im Fall unserer Methode Get
bedeutet dieser Parameter so viel wie "gib mir eine
Referenz auf die Klasse Win32_LogicalDisk, bei der die
DeviceID C: ist'.

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

Seite 21 von 394


Bei WMI verweist das Objekt objLogicalDisk in diesem Fall nicht auf irgendein formloses
Programmkonstrukt, sondern auf die tatsächliche Festplatte des Computers. Beim Attribut
FreeSpace handelt es daher auch nicht einfach um eine Eigenschaft des
Automatisationsobjektes, sondern um eine Eigenschaft von Laufwerk C. In gewissem Sinn
erstellt WMI ein virtuelles Abbild eines physikalischen Objektes. Wenn Sie die Attribute
dieses Abbilds abfragen, dann fragen Sie tatsächlich die Attribute des physikalischen
Objektes ab.

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.

Abbildung 2.1: Freier Festplattenplatz in Byte


Auch wenn mit einem Blick zu sehen ist, dass auf Laufwerk C noch genügend Patz zur
Verfügung steht, so ist es doch schwer festzustellen, wie viel Platz noch verfügbar ist. Die
meisten Systemadministratoren würden es wohl einfacher finden, wenn das Script den
Speicherplatz in MB oder GB statt in Byte ausgibt.
VBScript stellt eine große Menge mathematischer Funktionen zur Verfügung, über die Sie
solche Aufgaben wie die Konvertierung von Byte in MB durchführen können. Außerdem
steht Ihnen mit VBScript ein Konstrukt zur Verfügung, in dem Sie das Ergebnis einer solchen
mathematischen Funktion speichern können: die Variable. In Variablen können Sie während
der Laufzeit des Scripts jede Form von Daten speichern.
Variablen sind Speichereinheiten, die dem Script während seiner Laufzeit zur Verfügung
stehen. Sie können sich den Hauptspeicher des Computers in diesem Zusammenhang als eine
Ansammlung von vielen kleinen Fächern vorstellen, die alle mit einem Etikett versehen sind.
Eine Variable ist eines von diesen Fächern. Das Etikett dient zur Identifizierung dieses
Fachs/der Variable. Sie können beliebige Daten in diesem Fach ablegen, und VBScript kann
diese dann bei Bedarf wieder aus dem Fach abholen. Wenn Sie auf die Variable zugreifen
(also auf die in ihr enthaltenen Daten), dann sucht VBScript einfach nach der entsprechen
Speicheradresse und gibt die unter dieser Adresse gespeicherten Daten an Sie zurück.
In Zeile 3 von Script 2.3 wird die Variable mit dem Namen FreeMegabytes zur Speicherung
des Ergebnisses einer Division des Attributes FreeSpace durch 10484576 verwendet (ein MB
enthält 10484576 Byte). Nach Zeile 3 enthält die Variable FreeMegabytes also das Ergebnis
dieser Division. Wenn Sie nun die freien Megabyte irgendwo anders in Ihrem Script
benötigen, dann können Sie auf die Variable zugreifen - Sie müssen die Berechnung nicht neu
durchführen. Dies sehen Sie in Zeile 4, hier wird der Inhalt der Variable auf dem Monitor
ausgegeben.
Seite 22 von 394
Script 2.3: Verwendung von Variablen

1Set objWMIService = GetObject("winmgmts:")


2Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
3FreeMegaBytes = objLogicalDisk.FreeSpace / 1048576
4Wscript.Echo FreeMegaBytes
Die Ausgabe von Script 2.3 sehen Sie in Abbildung 2.2.

Abbildung 2.2: Freier Plattenplatz in MB konvertiert


Anmerkung: Beachten Sie, dass der Wert als 2954 statt als 2.954 ausgegeben wird (also ohne
Tausender-Trennzeichen). Auch wenn es möglich ist, dieses in der Script-Ausgabe
hinzuzufügen, so können Sie dieses intern in VBScript nicht verwenden.

Formatierung der Script-Ausgabe


Der Wert 2954,1328125 (er bedeutet, es gibt ca. 2954 MB freien Plattenplatz) ist für einen
Systemadministrator wahrscheinlich viel Aussagekräftiger als der Wert 3098144768 aus
unserem vorherigen Script. Die Nachkommastellen verwirren jedoch wahrscheinlich mehr, als
das Sie nützen. Glücklicherweise bietet VBScript mehrere verschiedene Wege, um die
Ausgabe eines Scripts anzupassen. Die Funktion Int zwingt VBScript zum Beispiel dazu, die
Zahl als Integer (Ganzzahl ohne Nachkommastellen) anzuzeigen. Bitte beachten Sie, dass die
Nachkommastellen der Varabile FreeMegaBytes in dem folgenden Beispiel nicht verworfen
werden - sie werden nur nicht mit angezeigt.

Script 2.4: Formatierung der Ausgabe

1Set objWMIService = GetObject("winmgmts:")


2Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
3FreeMegaBytes = objLogicalDisk.FreeSpace / 1048576
4Wscript.Echo Int(FreeMegaBytes)
In Abbildung 2.3 sehen Sie die Ausgabe von Script 2.4. Die Funktion Int schneidet die
Nachkommastellen des Originalwertes ab. Weitere Formatierungsmöglichkeiten, mit denen
Sie zum Beispiel ein Tausender-Trennzeichen zur Ausgabe hinzufügen können, lernen Sie
später in diesem Kapitel kennen.

Abbildung 2.3: die Ausgabe mit der Funktion Int formatieren

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.

Script 2.5: Verwendung von Konstanten

1Const CONVERSION_FACTOR = 1048576


2Set objWMIService = GetObject("winmgmts:")
3Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
4FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
5Wscript.Echo Int(FreeMegaBytes)
Ein weiterer Vorteil von Konstanten ist deren Wiederverwendbarkeit. Sie werden einmal
erstellt, und können dann im gesamten Script so oft wie nötig verwendet werden. In einer
erweiterten Version von Script 2.5 könnte es zum Beispiel notwendig sein, mehrmals eine
Konvertierung von Byte zu MB durchzuführen. Hierzu können Sie dann jedes Mal die
Konstante verwenden. Wenn Sie sich später entscheiden in GB statt in MB zu konvertieren,
dann müssen Sie nur noch die Konstante statt jedes einzelnen Literalwertes verändern.

Zeichenketten

Seite 24 von 394


Wenn Sie anspruchsvollere Scripte schreiben, dann werden Sie feststellen, dass es
unterschiedliche Datentypen gibt (wir werden dies später in diesem Kapitel genauer
besprechen). In Zeile 1 von Script 2.5 wird der Konstante CONVERSION_FACTOR zum
Beispiel der numerische Wert 1048576 zugewiesen:
Const CONVERSION_FACTOR = 1048576
Diese Zuweisung funktioniert deshalb, weil es sich um einen numerischen Wert handelt.
Wenn Sie einen solchen Wert zuweisen möchten, dann reicht es, ein Gleichheitszeichen,
gefolgt vom Wert, zu verwenden.
Wenn Sie allerdings versuchen, auf diese Art einen alphanumerischen Wert (eine
Zeichenkette, auch String genannt) zuzuweisen, dann kann es zu unvorhergesehenen
Problemen kommen. Die folgende Zeile versucht zum Beispiel der Variable Computer die
Zeichenkette atl-dc-01 zuzuweisen und den Inhalt der Variable dann auszugeben:
Computer = atl-dc-01
Wscript.Echo Computer
Die Ausgabe des Scripts sehen Sie in Abbildung 2.4.

Abbildung 2.4: Falsche Zuweisung einer Zeichenkette zu einer Variable


Wieso wurde der Variable Computer der Wert -1 zugewiesen? Wenn VBScript eine
alphanumerische Zeichenkette ohne Anführungszeichen findet, geht es davon aus, dass dieses
Zeichenkette einen Variablennamen darstellt. Wenn irgendwo in der Zeichenkette in
Bindestrich vorkommt, dann interpretiert VBScript dieses als Minuszeichen. Als Ergebnis
interpretiert VBSCript die Zeile Computer = atl-dc-01 als 'Der Variable Computer sollt das
Ergebnis der Berechnung Variable atl minus der Variable dc minus 01 zugewiesen werden'.
Da atl und dc als neue und nicht initialisierte Variablen (ohne zugewiesenen Wert) angesehen
werden, enthalten Sie den Wert 0. VBScript interpretiert die Codezeile also so:
Computer = 0 - 0 - 1
Als Ergebnis steht natürlich in der Variable Computer der falsche Wert-1.
Wenn Sie eine Zeichenkette zu einer Variable oder Konstante zuweisen, dann müssen Sie die
Zeichenkette in Anführungszeichen einschließen. So können Sie sicherstellen, dass VBScript
die Zeichenkette auch als Zeichenkette und nicht als Zahl oder Variable interpretiert. Die
folgende Beispielzeile weist der Variable Computer zum Beispiel korrekt die Zeichenkette
atl-dc-01 zu und gibt den Inhalt der Variable dann aus:
Computer = "atl-dc-01"
Wscript.Echo Computer
Die Ausgabe des Scripts sehen Sie in Abbildung 2.5.

Seite 25 von 394


Abbildung 2.5: Korrekte Zuweisung einer Zeichenkette zu einer Variable

Zeichenketten als Variablen


Zeichenketten werden oft zur Zuweisung von Werten zu Variablen verwendet. Das
Beispielscript in diesem Kapitel verwendet zum Beispiel die folgende Zeile zur Bindung an
WMI:
Set objWMIService = GetObject("winmgmts:")
Mit dieser Zeile verbinden Sie sich mit dem lokalen Computer. Wenn Sie jedoch für viele
Computer zuständig sind, dann möchten Sie wahrscheinlich auch Informationen von den
Remotecomputern abfragen.
Wenn Sie WMI verwenden, dann können Sie sich mit einem Remotecomputer verbinden,
indem Sie einfach den Computernamen in den an GetObject übergebenen Moniker mit
aufnehmen. Die folgende Codezeile bindet den WMI-Dienst zum Beispiel an den
Remotecomputer atl-dc-01:
Set objWMIService = GetObject("winmgmts://atl-dc-01")
Diese Codezeile können Sie zwar für ein Script verwenden, das einen Remotecomputer
abfragt, in einer Unternehmensumgebung benötigen Sie jedoch möglicherweise eine
flexiblere Lösung.
Ein Weg für eine Abfrage mehrerer Computer wäre das Script vor jeder Ausführung zu
ändern. Sie ersetzen den hardcodierten Computernamen durch einen anderen. Ein weit
besserer Ansatz ist jedoch das Script so zu ändern, dass es bei seinem Start einen
Computernamen entgegennimmt - zum Beispiel durch einen Kommandozeilenparameter.
Methoden zur Benutzereingabe werden später in diesem Kapitel besprochen. Vorher sollten
Sie jedoch wissen, wie Sie Zeichenketten (zum Beispiel Computernamen) zu Variablen
zuweisen und diese dann im Scriptcode verwenden.
In Zeile 2 von Script 2.6 wird zum Beispiel die Zeichenkette 'atl-dc-01' zur Variable
Computer zugewiesen. In Zeile 3 wird dieses Variable dann zur Bindung des WMI-Dienstes
an Computer atl-dc-01 verwendet. Dies wird hier jedoch nicht über die Hardcodierung der
Zeichenkette atl-dc-01 erreicht, sondern indem der Wert in der Variable Computer verwendet
wird.

Script 2.6: Verwendung von Zeichenketten

1Const CONVERSION_FACTOR = 1048576


2Computer = "atl-dc-01"
3Set objWMIService = GetObject("winmgmts://" & Computer)
4Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
5FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
6Wscript.Echo Int(FreeMegaBytes)
In einem kleinen Beispielscript wie diesem erfordert das Zuweisen einer Zeichenkette zu
einer Variable mehr Aufwand als eine Hardcodierung dieser Zeichenkette. Das Script zeigt
trotzdem ein wichtiges Konzept: Sie können einen Wert zu einer Variable zuweisen und
dieses Variable dann an Stelle einer Hardcodierung dieses Wertes verwenden.
Warum ist das wichtig? Stellen Sie sich vor, dass Script wurde zur Abfrage des freien
Festplattenplatzes von 100 statt von einem Computer entwickelt. Statt separate Zeichenketten
zur WMI-Bindung für jeden Computer fest einzutragen, verwenden Sie jedoch nur eine

Seite 26 von 394


Zeichenkette mit der Variable Computer. Ihr Script könnte dann die gleiche Codezeile 100
Mal ausführen - und jedes Mal würde die Variable Computer einfach einen unterschiedlichen
Computernamen enthalten.
Im Moment müssen Sie sich allerdings nur auf Zeile 3 von Script 2.6 konzentrieren:
Set objWMIService = GetObject("winmgmts://" & Computer)
So interpretiert VBScript diese Codezeile:
1.Es liest alle bis zum zweiten Anführungszeichen. Mit anderen Worten:
Set objWMIService = GetObject("winmgmts://"
2.Es erkennt das kaufmännische Und (&) - dieses bedeutet "Hänge alles Folgende an die
Zeichenkette an". Dem & folgt in diesem Fall die Variable Computer, der der Wert atl-dc-
01 zugewiesen wurde. Für VBScript sieht die Codezeile damit also so aus:
Set objWMIService = GetObject("winmgmts://atl-dc-01"
3.Es liest die schließende Klammer. In VBScript muss es genauso viele schließende
Klammern wie geöffnete Klammern geben. Wenn die schließende Klammer fehlt, gibt
VBScript eine Fehlermeldung aus. Die von VBScript gelesene Codezeile sieht nun so aus:
Set objWMIService = GetObject("winmgmts://atl-dc-01")
4.Da nun das Ende der Codezeile erreicht ist, wird die Anweisung ausgeführt. Das Script
verbindet sich mit dem WMI-Dienst von Computer atl-dc-01. Um sich mit dem WMI-
Dienst eines anderen Computers zu verbinden, reicht es, den Wert in der Variable Computer
zu ändern.

Verketten von Zeichenketten


Verketten heißt zwei oder mehr Zeichenketten zu einer einzelnen Zeichenkette zu verbinden
(Sie können auch Zeichenketten mit numerischen Werten und Datumswerten verketten). Mit
einer Verkettung erreichen Sie oft eine besser lesbare oder deutlichere Ausgabe. Script 2.4
gibt zum Beispiel den Wert 2953 zurück. Wenn Sie wissen, dass das Script den freien
Speicherplatz von Laufwerk C in MB zurückgibt, ist dies eine sehr nützliche Information.
Wenn Sie jedoch nicht wissen, was das Script macht, dann ist die Ausgabe völlig sinnfrei.
Neben anderen Dingen kann Ihnen eine Verkettung bei einer besseren Script-Ausgabe helfen.
Statt zum Beispiel nur den Wert 2953 zurückzugeben, könnten Sie eine Nachricht wie "Es
stehen 2953 MB freier Festplattenplatz zur Verfügung" zurückgeben. Hierzu müssen Sie die
folgenden drei Teile kombinieren:

'Es stehen ' - eine einfache Zeichenkette mit dem Anfang der Ausgabe.

FreeMegabytes - die Variable, die den freien Speicherplatz in MB enthält.

' MB freier Festplattenplatz zur Verfügung" - eine zweite Zeichenkette mit dem Ende der
Ausgabe.
Wie Sie den Zeilen 6 und 7 von Script 2.7 sehen, können Sie in VBScript mehrere
Zeichenketten mit dem kaufmännischen Und (&) verketten.

Script 2.7: Verketten von Zeichenketten

1Const CONVERSION_FACTOR = 1048576


2Computer = "atl-dc-01"
3Set objWMIService = GetObject("winmgmts://" & Computer)

Seite 27 von 394


4Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
5FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
6Wscript.Echo "Es stehen " & Int(FreeMegaBytes) & _
7 " MB freier Festplattenplatz zur Verfügung."
Anmerkung:

Der Unterstrich (_) am Ende von Zeile 6 wird zum Fortsetzen einer Zeile in der nächsten
Zeile verwendet. Das bedeutet für VBScript, dass es die Zeile 6 und 7 wie eine einzige Zeile
behandeln soll. Die beiden Zeilen passten nur einfach nicht in eine einzige Zeile.
Alternativ können Sie den Wert "Es stehen" einer Variable mit dem Namen MessageStart und
den Wert "MB freier Festplattenplatz zur Verfügung" einer Variable mit dem Namen
MessageEnd zuweisen. Sie können die drei Variablen dann so verketten:
Wscript.Echo MessageStart & Int(FreeMegabytes) & MessageEnd
Wenn Sie sich die Zeilen 6 und 7 genau anschauen, dann werden Sie feststellen, dass die
Zeichenketten Leerzeichen enthalten. Dies ist notwendig, da vom kaufmännischen Und keine
Leerzeichen beim Verketten eingefügt werden. Nehmen wir einmal an, Sie würden die
Leerzeichen weglassen:
Wscript.Echo "Es stehen" & Int(FreeMegaBytes) & "MB freier Festplattenplatz
zur Verfügung."
In diesem Fall würde die Ausgabe so aussehen:

Abbildung 2.6: Falsch verkettete Zeichenketten


Bei einfacheren Verkettungen können Sie dieses Problem umgehen, indem Sie statt des
kaufmännischen Und ein Komma zur Verkettung verwenden:
Wscript.Echo "Es stehen", Int(FreeMegaBytes), "MB freier Festplattenplatz
zur Verfügung."
Wenn die Zeichenketten durch ein Komma verkettet werden, dann wird jeweils ein
Leerzeichen eingefügt. Das Ergebnis sollte dann so wie in Abbildung 2.7 aussehen:

Abbildung 2.7: Korrekt verkettete 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.

Script 2.8: Verwendung von Collections

1Const CONVERSION_FACTOR = 1048576


2Computer = "atl-dc-01"
3Set objWMIService = GetObject("winmgmts://" & Computer)
4Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
5For Each objLogicalDisk In colLogicalDisk
6 FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
7 Wscript.Echo objLogicalDisk.DeviceID & " " & Int(FreeMegaBytes)
8Next
Wenn Informationen als Collections zurückgegeben werden, dann bedeutet das für Sie, dass
Sie nicht raten müssen, wie viele Laufwerke auf einem Computer installiert sind. Stattdessen
rufen Sie einfach die Collection ab (alle auf einem Computer installierten Laufwerke).
Danach können Sie eine For- Each-Schleife verwenden, um auf jedes einzelne Objekt in der
Collection zuzugreifen.

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.

Tabelle 2.2: Teile von For Each


Teil Beschreibung

Seite 29 von 394


Teil Beschreibung
objLogicalDisk Diese Variable repräsentiert die einzelnen in der Collection
enthaltenen Laufwerke
colLogicalDisk Diese Variable enthält die Collection
For Each objLogicalDisk in Startet die Schleife. Bedeutet so viel wie 'mache etwas mit
colLogicalDisk jedem Element der Collection'.
Wscript.Echo Befehle die in der Schleife für jedes Element der
objLogicalDisk.DeviceID Collection ausgeführt werden (in diesem Fall nur einer).
Next Das Ende der Schleife
Bei der Arbeit mit Collections gehen Sie normalerweise die gesamte Collection durch, statt
nur auf ein einzelnes Element der Collection zuzugreifen. Wenn wir zum Beispiel annehmen,
dass die Collection aus den Laufwerken C, D, E, F und G besteht, und Sie möchten nur den
verfügbaren Platz von Laufwerk G ausgeben, dann gehen Sie trotzdem die gesamte Collection
durch. Bei jedem Durchlauf fragen Sie ab, ob das Element den Laufwerkbuchstaben G
verwendet, und wenn dies der Fall ist, dann geben Sie den verfügbaren Plattenplatz für dieses
Element aus.

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.

Collections ohne Elemente


Es ist möglich, dass eine Collection keine Elemente enthält. Das folgende Bespielscript fragt
zum Beispiel alle auf einem Computer installierten Bandlaufwerke ab:
Set objWMIService = GetObject("winmgmts:")
Set colTapeDrives = objWMIService.InstancesOf("Win32_TapeDrive")
For Each objTapeDrive In colTapeDrives
Wscript.Echo objTapeDrive.Name
Next
Wenn das Script auf einem Computer ohne Bandlaufwerke ausgeführt wird, dann scheint es,
als ob nichts passiert. In Wahrheit wird das Script sehr wohl ausgeführt. Da der Computer
jedoch über kein Bandlaufwerk verfügt, enthält auch die Collection keine Elemente.
Wenn das Script auf einem Computer ohne Bandlaufwerke ausgeführt wird, passiert
folgendes:
1.Verbindung mit dem WMI-Dienst
2.Abfrage der Collection mit den installierten Bandlaufwerken
3.Einrichtung einer For Each-Schleife um die gesamte Collection durchzugehen. Für jedes
Element wird der Name ausgegeben.

Seite 30 von 394


Da es jedoch keine Elemente in der Collection gibt, wird die For Each-Schleife kein einziges
Mal ausgeführt. Stattdessen macht das Script gleich mit der Zeile nach Next weiter. In
unserem Beispielscript gibt es allerdings nach Next keine Zeile mehr. Damit ist das Script zu
Ende.
Es gibt keinen einfachen Weg um festzustellen, ob ein Script ausgeführt wurde. Ein Weg zur
Verbesserung des Scripts wäre die Verwendung des Attributes Count. Mit diesem können Sie
feststellen, wie viele Elemente eine Collection enthält. Das folgende Beispielscript verwendet
das Attribut Count, um die Zahl der Bandlaufwerke des Computers zurückzugeben:
Set objWMIService = GetObject("winmgmts:")
Set colTapeDrives = objWMIService.InstancesOf("Win32_TapeDrive")
Wscript.Echo colTapeDrives.Count
Wenn Sie die Zahl der Elemente einer Collection über das Attribut Count abgefragt haben,
dann können Sie die beiden folgenden Dinge durchführen:

Sie können die Eigenschaften der Elemente der Collection ausgeben (wenn es ein oder
mehrere Elemente gibt).

Wenn es keine Elemente in der Collection gibt, dann können Sie eine Nachricht wie "Es gibt
keine Bandlaufwerke" ausgeben.
Ein solches Script könnte wie folgt aussehen (der Ausdruck If-Then-Else wird später in
diesem Kapitel besprochen):
Set objWMIService = GetObject("winmgmts:")
Set colTapeDrives = objWMIService.InstancesOf("Win32_TapeDrive")
If colTapeDrives.Count = 0 Then
Wscript.Echo "Es gibt keine Bandlaufwerke."
Else
For Each objTapeDrive In colTapeDrives
Wscript.Echo objTapeDrive.Name
Next
End If

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.

Seite 31 von 394


Script 2.9 prüft zum Beispiel jede Stunde den freien Plattenplatz eines Computers - und zwar
12 Stunden lang. Hierzu wird das For-Statement aus Zeile 5 verwendet. Es besagt, dass der in
der For Next-Schleife eingeschlossene Codeblock 12 Mal ausgeführt werden soll. Die Zeilen
6 bis 10 enthalten den Code, der zum Abfragen des Plattenplatzes notwendig ist, und in Zeile
11 wird das Script für eine Stunde angehalten (über eine Konstante, die das Script für
3.600.000 Millisekunden anhält). Zeile 12 markiert mit dem Next-Statement schließlich das
Ende der Schleife.
Wenn das Script ausgeführt wird, dann wird als erstes eine Verbindung zum Remotecomputer
atl-dc-01 aufgebaut. Das Script fragt den freien Festplattenplatz ab und hält dann für eine
Stunde an. Nach der Stunde springt das Script wieder zum ersten Statement innerhalb der For
Next-Schleife und arbeitet den Codeblock in der Schleife ein weiteres Mal ab. Dies geht so
weiter, bis die Schleife 12 Mal durchlaufen wurde. Nach der Schleife gibt es keinen weiteren
Code mehr, so dass das Script dann beendet ist.

Script 2.9: Befehle mehrfach ausführen

1 Const CONVERSION_FACTOR = 1048576


2 Const ONE_HOUR = 3600000
3 Computer = "atl-dc-01"
4 Set objWMIService = GetObject("winmgmts://" & Computer)
5 For i = 1 to 12
6 Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
7 For Each objLogicalDisk In colLogicalDisk
8 FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
9 Wscript.Echo objLogicalDisk.DeviceID & " " & Int(FreeMegaBytes)
10 Next
11 Wscript.Sleep ONE_HOUR
12Next
Mit dem For-Next-Statement ist es also möglich, einen bestimmen Codeblock mehrmals
ausführen zu lassen. Sie sollten dies nicht mit dem For-Each-Statement verwechseln. For
Each wird verwendet, um alle Elemente einer Collection zu durchlaufen. For Next wird
verwendet, um einen bestimmten Codeblock mehrmals auszuführen.
Um ein For-Next-Statement zu verwenden, müssen Sie sowohl den Startpunkt als auch den
Endpunkt der Schleife festlegen. Da For-Next-Schleifen typischerweise X Mal ausgeführt
werden, fangen sie normalerweise mit 1 an und enden mit X. Um eine Schleife 10 Mal
auszuführen, fangen Sie daher mit 1 an und enden mit 10.

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

Seite 32 von 394


Wscript.Echo "For Next-Schleife vollständig."
Was passiert, wenn i gleich 6 ist? Das Script springt zurück zum Anfang der Schleife und
prüft, ob 6 noch innerhalb der gewünschten Schleifenzahl liegt. Da dies nicht der Fall ist, wird
die Schleife beendet. Das Script wird mit der ersten Zeile hinter der Schleife (die Zeile unter
Next) weitergeführt. In unserem Bespielscript wird nun die Nachricht "For-Next-Schleife
vollständig" ausgegeben.
Die Ausgabe des Scripts sollte folgendermaßen aussehen:
1
2
3
4
5
For Next-Schleife vollständig.
Anmerkung:

Es gibt Fälle, in denen Sie den gleichen Befehlsblock immer wieder ausführen möchten -
ohne dass Sie vorher wissen, wie oft der Block genau ausgeführt werden soll. Stellen Sie sich
zum Beispiel vor, Sie möchten den freien Festplattenplatz so lange prüfen, bis dieser unter
einen bestimmen Wert fällt. In solchen Situationen sollten Sie eine Do-Loop-Schleife
verwenden, die später in diesem Kapitel besprochen wird.

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.

Seite 33 von 394


Script 2.10:Entscheidungen treffen

1 Const CONVERSION_FACTOR = 1048576


2 Const WARNING_THRESHOLD = 100
3 Computer = "atl-dc-01"
4 Set objWMIService = GetObject("winmgmts://" & Computer)
5 Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
6 For Each objLogicalDisk In colLogicalDisk
7 FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
8 If FreeMegaBytes &#60; WARNING_THRESHOLD Then
9 Wscript.Echo objLogicalDisk.DeviceID & " hat wenig freien
10Speicherplatz."
11 End If
Next

Mehre Aktionen mit If Then Else durchführen


Script 2.10 zeigt eine Warnmeldung an, wenn der freie Festplattenplatz gering ist. Wenn dies
nicht der Fall ist, dann wird auch keine Nachricht angezeigt. Für ein einfaches
Überwachungsscript reicht dies sicher aus. Andererseits weiß der Benutzer bei der
Scriptausführung nicht, ob er keine Meldung bekommen hat, weil der Plattenplatz ausreichen
ist, oder weil das Script aus irgendeinem Grund fehlgeschlagen ist.
Besser wäre es also, im Fall von wenig verfügbarem Speicherplatz eine Warnmeldung, und in
allen anderen Fällen eine "Alles Ok"-Nachricht auszugeben. Einen solchen Ansatz können Sie
über das If-Then-Else-Statement umsetzen.
If-Then-Else-Statements arbeiten folgendermaßen: Wenn (If) eine Bedingung wahr ist, dann
(then) führe folgende Aktion durch - Andernfalls (else) führe folgende Aktion durch.
Wenn der Plattenplatz gering ist, dann gib eine Warnmeldung aus - andernfalls gib eine
"Alles Ok"-Nachricht aus.
Script 2.11 zeigt Ihnen ein Beispiel hierzu. In Zeile 8 wird der freie Plattenplatz mit einem
Grenzwert (warning_threshold) verglichen. Wenn die Bedingung wahr ist (also wenn der freie
Platz unter dem Grenzwert liegt), dann wird Zeile 9 ausgeführt.
Was passiert, wenn die Bedingung falsch ist? In diesem Fall wird Zeile 11 hinter dem Else-
Statement ausgeführt.

Script 2.11: Verwendung des If-Then-Else-Statements

1 Const CONVERSION_FACTOR = 1048576


2 Const WARNING_THRESHOLD = 100
3 Computer = "atl-dc-01"
4 Set objWMIService = GetObject("winmgmts://" & Computer)
5 Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
6 For Each objLogicalDisk In colLogicalDisk
7 FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
8 If FreeMegaBytes &#60; WARNING_THRESHOLD Then
9 Wscript.Echo objLogicalDisk.DeviceID & " is low on disk space."
10 Else
11 Wscript.Echo objLogicalDisk.DeviceID & " has adequate disk space."
12 End If
13Next
Es ist durchaus möglich, raffiniertere Szenarien zu konstruieren, zum Beispiel welche, in
denen es mehr als zwei mögliche Aktionen gibt. Später in diesem Kapitel werden Sie noch
zwei unterschiedliche Wege hierzu kennen lernen.
Seite 34 von 394
Arrays (Felder)
Collections sind eine hervorragende Möglichkeit Informationen zusammenzufassen, da sie es
ermöglichen mit einer unbegrenzten Zahl von Elementen zu arbeiten - und zwar auch dann,
wenn Sie keine Details dieser Elemente kennen. Script 2.8 ermöglicht es Ihnen zum Beispiel
den freien Plattenplatz für alle installierten Festplatten eines Computers abzufragen. Sie
müssen vorher nicht wissen, wie viele Festplatten installiert sind. Um die einzelnen Elemente
einer solchen Collection durchzugehen, verwenden Sie eine einfache For-Each-Schleife.
Diese Collections werden von Automatisationsobjekten für Sie erstellt. Es könnte jedoch sein,
dass Sie andere Informationen verarbeiten möchten (Informationen, die nicht von einem
Automatisationsobjekt zur Verfügung gestellt werden), und dass Sie für diese Informationen
ebenfalls eine einfache Möglichkeit zum Durchgehen von Elementen benötigen. Stellen Sie
sich zum Beispiel vor, dass Sie den verfügbaren Plattenplatz auf drei Computern statt auf nur
einem prüfen möchten. Sie könnten hierzu natürlich einen Scriptcode schreiben, der dies auf
dem ersten Computer durchführt, den Scriptcode dann kopieren und wieder einfügen, den
kopierten Code so anpassen, dass er den Plattenplatz auf dem zweiten Computer prüft, usw.
Natürlich würde ein solcher Ansatz funktionieren. Er könnte jedoch schnell sehr mühsam
werden. Stellen Sie sich vor, Sie müssten statt drei Computern nun 100 Computer prüfen.
Oder stellen Sie sich vor, Sie müssten Änderungen am Code vornehmen - zum Beispiel um
nicht nur den freien Plattenplatz, sondern auch die Gesamtgröße des Laufwerks abzufragen.
In diesem Fall müssten Sie bei 100 Computern auch 100 Änderungen am Code vornehmen.
Das wäre nicht nur sehr mühsam, sondern es gäbe ich eine gute Chance, dass Sie irgendwo
einen Fehler machen.
Ein besserer Ansatz wäre hier eine For-Each-Schleife, die einfach eine Collection mit
Computern durchgeht und für jeden den freien Plattenplatz abfragt. Dies können Sie
erreichen, indem Sie die Computernamen in einem Array speichern. Ein Array ist eine
Datenstruktur, die Sie ganz ähnlich wie eine Collection verwenden können.
Script 2.12 schreibt die Namen von drei Computern (atl-dc-01, atl-dc-02 und atl-dc-03) in ein
Array. Dann verwendet es eine For-Each-Schleife, um eine Verbindung mit jedem Computer
aufzubauen und den freien Plattenplatz abzufragen. Das Array wird in Zeile 3 mit Hilfe der
Funktion Array erstellt. Ihr werden als Parameter die drei Computernamen angehängt (da die
Namen Zeichenketten sind, werden sie jeweils in Anführungszeichen eingeschlossen). In
Zeile 4 werden die einzelnen Elemente des Arrays Computers mit Hilfe einer For-Each-
Schleife durchlaufen.

Script 2.12: Mit einem Array arbeiten

1 Const CONVERSION_FACTOR = 1048576


2 Const WARNING_THRESHOLD = 100
3 Computers = Array("atl-dc-01", "atl-dc-02", "atl-dc-03")
4 For Each Computer In Computers
5 Set objWMIService = GetObject("winmgmts://" & Computer)
6 Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
7 For Each objLogicalDisk In colLogicalDisk
8 FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
9 If FreeMegaBytes &#60; WARNING_THRESHOLD Then
10 Wscript.Echo Computer & " " & objLogicalDisk.DeviceID & _
11 " is low on disk space."
12 End If

Seite 35 von 394


13 Next
14Next
Auch wenn Arrays einer Collection sehr ähnlich sind, so gibt es doch einen grundlegenden
Unterschied. Als Scriptentwickler haben Sie über Collections sehr wenig Kontrolle. Wenn Sie
eine Liste der installierten Laufwerke über WMI abrufen, dann erhalten Sie die Liste in der
Reihenfolge zurück, die WMI festgelegt hat. Sie sind außerdem nicht in der Lage auf ein
einzelnes Laufwerk zuzugreifen, ohne die gesamte Collection durchzugehen.
Im Gegensatz dazu können Sie die Reihenfolge der Elemente eines Arrays bestimmten - denn
Sie sind normalerweise derjenige, der den Array mit Elementen füllt. Außerdem haben Sie die
Möglichkeit auf einzelne Elemente eines Arrays zuzugreifen, ohne das gesamte Array
durchlaufen zu müssen. Das liegt daran, dass jedem Element eines Arrays eine Indexnummer
zugewiesen wird. Unter VBScript hat das erste Element eines Arrays immer die Indexnummer
0 - die nachfolgenden Elemente erhalten fortlaufende Indexnummern (1, 2, 3 usw.). Der Array
aus Script 2.12 enthält nach diesen Regeln also die in Tabelle 2.3 gezeigten Elemente und
Indexnummern. Sie sollten sich merken, dass die höchste Indexnummer eines Arrays immer
der Gesamtzahl von Elementen minus eins entspricht.

Tabelle 2.3: Indexnummern in einem Array


IndexnummerElement
0 atl-dc-01
1 atl-dc-02
2 atl-dc-03
Sie können die Indexnummern verwenden, um auf die einzelnen Elemente eines Arrays
zuzugreifen. Die folgende Codezeile gibt zum Beispiel den Text atl-dc-02 aus - der Wert von
Element 1 (genauer: das Element mit der Indexnummer 1) im Array:
Wscript.Echo Computers(1)
Um den Wert eines anderen Elementes auszugeben, ersetzten Sie den Wert 1 einfach durch
die entsprechende Indexnummer.
Später in diesem Kapitel werden noch weitere Verfahren zum Erstellen von Arrays und dem
Zugriff auf einzelne Array-Elemente besprochen.

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

Seite 36 von 394


müssen Sie das Script verändern.

Regelmäßige Änderungen - Script 2.12 wurde entwickelt, um eine bestimmte Gruppe von
Computern abzufragen (zum Beispiel alle Domänencontroller an einem bestimmten
Standort). Jedes Mal, wenn ein neuer Domänencontroller hinzugefügt wird, muss das Script
geändert werden. Wenn in Ihrer Organisation nur dieses eine Script verwendet wird, ist das
sicher kein allzu großes Problem. Wenn Sie jedoch Dutzende von Scripten verwenden, dann
verbringen Sie möglicherweise mehr Zeit mit der Pflege von Scripten, als Sie durch die
Scripte einsparen.
Es gibt einige Arten, auf die Sie Informationen (zum Beispiel Computernamen) an ein Script
übergeben können (weitere Informationen hierzu finden Sie im Kapitel Creating Enterprise
Scripts in Teil 3 dieses Buchs). Der wahrscheinlich einfachste Weg ist es, den Benutzer beim
Aufruf des Scripts Parameter (auch Argumente genannt) angeben zu lassen.
Ein Argument ist eine Information, die zusammen mit dem Befehl, über den das Script
gestartet wird, angegeben wird. Nehmen wir einmal an, Sie starten ein Script normalerweise,
indem Sie folgenden Befehl in der Eingabeaufforderung eingeben:

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:

cscript FreeDiskSpace.vbs atl-dc-01 atl-dc-02 atl-dc-03


Sie müssen Ihrem Script natürlich auch Code hinzufügen, der diese Argumente verarbeitet.
Im Kapitel Der WSH wird dies sehr detailliert besprochen - in Script 2.13 sehen Sie daher nur
ein einfaches Beispiel. In Zeile 9 dieses Scripts wird eine For-Each-Schleife verwendet, um
die vom Benutzer beim Start des Scripts angegebenen Argumente durchzugehen. Die
einzelnen Argumente werden jeweils der Variable Computer zugewiesen. Mit Hilfe dieser
Variable wird dann in Zeile 10 eine Verbindung zum WMI-Dienst dieses Computers
aufgebaut.

Script 2.13: Eingaben des Benutzers verarbeiten

1 Const CONVERSION_FACTOR = 1048576


2 Const WARNING_THRESHOLD = 100
3
4 If WScript.Arguments.Count = 0 Then
5 Wscript.Echo "Usage: FirstScript.vbs server1 [server2] [server3] ..."
6 WScript.Quit
7 End If
8
9 For Each Computer In WScript.Arguments
10 Set objWMIService = GetObject("winmgmts://" & Computer)
11 Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
12 For Each objLogicalDisk In colLogicalDisk
13 FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
14 If FreeMegaBytes &#60; WARNING_THRESHOLD Then
15 Wscript.Echo Computer & " " & objLogicalDisk.DeviceID & _
16 " is low on disk space."
17 End If
18 Next
19Next

Seite 37 von 394


Ein Vorteil von Befehlszeilenargumenten ist, dass sie automatisch über eine Collection
bereitgestellt werden (Wscript.Arguments). So ist es einfach, die Argumente über eine For-
Each-Schleife durchzugehen - denn dieser Vorgang unterscheidet sich nicht von der
Auflistung aller Laufwerke eines Computers.
Dank der Collection ist es auch ganz einfach festzustellen, wie viele Argumente angegeben
wurden - wenn überhaupt welche angegeben wurden. Hierzu wird in Zeile 4 des Scripts das
Attribut Wscript.Arguments.Count verwendet. In ihm steht die Zahl der bei Scriptstart
übergebenen Argumente. Wenn Wscript.Arguments.Count den Wert 0 hat, dann wurden keine
Argumente übergeben. In diesem Fall wird in 2.13 einfach ein Text ausgegeben, der die
möglichen Argumente des Scripts anzeigt. Danach wird das Script mit dem Befehl
WScript.Quit beendet.).

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:

Seite 38 von 394


1.Eine Verbindung zu einem Remotecomputer herstellen.
2.Dateien vom lokalen Computer auf den Remotecomputer kopieren.
3.Die Originaldateien vom lokalen Computer löschen.
Stellen Sie sich nun vor, Sie starten das Script, und der Remotecomputer ist nicht erreichbar.
Folgendes würde passieren:
1.Das Script versucht eine Verbindung zum Remotecomputer herzustellen. Dies schlägt fehl.
On Error Resume Next stellt jedoch sicher, dass das Script weiter ausgeführt wird.
2.Das Script versucht, Dateien auf den Remotecomputer zu kopieren. Dies schlägt natürlich
ebenfalls fehl. Auch hier stellt On Error Resume Next sicher, dass das Script weiter
ausgeführt wird.
3.Das Script löschte die Dateien vom lokalen Computer. Unglücklicherweise wird das sauber
ausgeführt. Der lokale Computer steht ja zur Verfügung. Als Ergebnis sind die Dateien vom
lokalen Computer gelöscht und nicht auf den Remotecomputer kopiert.
Glücklicherweise können Sie das VBScript-Objekt Err verwenden, um festzustellen, ob ein
Fehler aufgetreten ist. Danach können Sie die erforderlichen Maßnahmen ergreifen.
Das Err-Objekt wird automatisch erstellt, sobald Sie das Script starten (solche immer
verfügbaren Objekte werden auch Intrinsic-Objekte genannt). Es stellt mehrere Attribute zur
Verfügung. Drei von ihnen sehen Sie in Tabelle 2.4. Wenn ein Laufzeitfehler auftritt, werden
diese Attribute automatisch mit Werten gefüllt. Diese Werte zeigen Ihnen, was für ein Fehler
aufgetreten ist.

Tabelle 2.4: Attribute des Err-Objektes


Attribut Beschreibung
DescriptionEine Beschreibung des Fehlers. Sie kann dazu verwendet werden, den Benutzer
über den Fehler zu informieren. Geben Sie das Attribut einfach auf dem
Bildschirm aus:

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.

Script 2.14: Fehler abfangen

1 On Error Resume Next


2 Const CONVERSION_FACTOR = 1048576
3 Const WARNING_THRESHOLD = 100
4
5 If WScript.Arguments.Count = 0 Then
6 Wscript.Echo "Usage: FirstScript.vbs server1 [server2] [server3] ..."
7 WScript.Quit
8 End If
9
10For Each Computer In WScript.Arguments
11 Set objWMIService = GetObject("winmgmts://" & Computer)
12 If Err.Number &#60;&#62; 0 Then
13 Wscript.Echo Computer & " " & Err.Description
14 Err.Clear
15 Else
16 Set colLogicalDisk = _
17 objWMIService.InstancesOf("Win32_LogicalDisk")
18 For Each objLogicalDisk In colLogicalDisk
19 FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
20 If FreeMegaBytes &#60; WARNING_THRESHOLD Then
21 Wscript.Echo Computer & " " & objLogicalDisk.DeviceID & _
22 " is low on disk space."
23 End If
24 Next
25 End If
26Next
Wenn Sie Script 2.14 ausführen, und einer der Server nicht erreichbar ist, dann enthalten die
Attribute des Err-Objektes die in Tabelle 2.5 zu sehenden Werte.

Tabelle 2.5: Werte der Attribute des Err-Objektes


Attribut Wert
Err.DescriptionDer Remoteservercomputer existiert nicht oder ist nicht verfügbar: ,GetObjekt'

Seite 40 von 394


Attribut Wert
Err.Number 462
Err.Source Laufzeitfehler in Microsoft VBScript

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

Seite 41 von 394


objWMI
=
(GetObject("winmgmts:")
.
InstancesOf("Win32_process"))
Das liegt daran, dass VBScript das Zeilenende (und damit normalerweise auch das Ende eines
Befehls) am Zeilenumbruch statt an einem bestimmten Zeichen erkennt.
Im Allgemeinen ist dies ein Vorteil von VBScript. Es kann zum Beispiel nicht passieren, dass
Sie vergessen das Zeilenendezeichen (das Semikolon) einzugeben. Ein Problem gibt es aber
trotzdem: Um die Lesbarkeit Ihrer Scripte zu verbessern, sollten Sie keine Zeilen verwenden,
die länger als max. 80 Zeichen sind (in einigen Texteditoren können Sie möglicherweise gar
nicht mehr als 80 Zeichen in einer Zeile eingeben). Was machen wir also, wenn eine Zeile
100 Zeichen enthalten muss?
Auch wenn es nahe liegend erscheint: Sie können die Zeile nicht einfach durch einen
Zielenumbruch in zwei Zeilen aufteilen. Das folgende Codestück würde unter VBScript zum
Bespiel zu einem Fehler führen, da die erste Befehlszeile durch einen Zeilenumbruch in zwei
einzelne Zeile aufgeteilt wurde (Zeile 1 und 2):
strMessageToDisplay = strUserFirstName, strUserMiddleInitial,
strUserLastName,
strCurrentStatus
Wscript.Echo strMessageToDisplay
In diesem Fall würde nun jede der beiden Zeilen als einzelner Befehl interpretiert. Die erste
Zeile mag ja auch noch immer einen gültigen Befehl enthalten (eine Zuweisung zu einer
Variable). Die zweite Zeile jedoch ist kein gültiger Befehl mehr.
Um einen Befehl über mehrere Zeile fortzusetzen, müssen Sie statt des Zeilenumbruchs den
Unterstrich verwenden (_).
strMessageToDisplay = strUserFirstName, strUserMiddleInitial,
strUserLastName, _
strCurrentStatus
Wscript.Echo strMessageToDisplay
Das Leerzeichen und der Unterstrich am Ende von Zeile 1 bedeuten für VBScript, dass der
Befehl in der nächsten Zeile fortgesetzt wird. Um dies auch für den Leser zu verdeutlichen,
wurde Zeile zwei um vier Zeichen eingerückt.
Wenn Sie versuchen eine Befehlszeile mit Zeichenketten (die in Anführungsstriche eingefasst
sind) zu trennen, dann wird dies noch etwas komplexer. Stellen Sie sich zum Beispiel vor, sie
teilen eine WMI-Abfrage folgendermaßen durch einen Unterstrich in zwei Zeilen auf:
Set colServiceList = GetObject("winmgmts:").ExecQuery("SELECT * FROM _
Win32_Service WHERE State = 'Stopped' AND StartMode = 'Auto' ")
Wenn sie das Script so ausführen, dann erhalten Sie wieder einen Laufzeitfehler. Das liegt
daran, dass Sie die Befehlszeile innerhalb einer Zeichenkette getrennt haben, die in
Anführungsstrichen eingeschlossen war (und der trennende Unterstrich daher nur als Teil der
Zeichenkette statt als Trennzeichen behandelt wird). Um eine solche Befehlszeile zu trennen
gehen Sie folgendermaßen vor:
1.Beenden Sie die erste Zeile mit einem Anführungszeichen. Hängen Sie dann das
Leerzeichen und den Unterstrich dahinter.
2.Beginnen Sie die zweite Zeile mit einem kaufmännischen "Und" (&). Dies zeigt VBScript,
dass hier die unterbrochene Zeichenkette aus Zeile 1 fortgesetzt wird.

Seite 42 von 394


3.Beginnen sie die fortgesetzte Befehlszeile mit einem weiteren Anführungszeichen.
Das "&" und die Anführungsstriche zeigen VBScript, dass die in Zeile 1 begonnene
Zeichenkette mit der folgenden Zeichenkette fortgesetzt werden soll.
Die korrekte Befehlszeile muss also so aussehen:
Set colServiceList = GetObject("winmgmts:").ExecQuery("SELECT * FROM " _
& "Win32_Service WHERE State = 'Stopped' AND StartMode = 'Auto' ")
Wenn Sie Befehlszeilen auf diese Art teilen, dann sollten Sie aufpassen, wo Sie die
Leerzeichen setzen. Im gezeigten Beispiel wurde zum Beispiel ein Leerzeichen hinter dem
Wort 'FROM' und vor dem schließenden Anführungszeichen eingefügt. Wenn dieses
Leerzeichen nicht vorhanden wäre, dann würde die Zeichenkette so aussehen:
" SELECT * FROMWin32_Service WHERE State = 'Stopped' AND StartMode = 'Auto'
"
Natürlich würde dies zu einem Fehler führen, "FROMWIn32"kann nicht richtig sein.

Arbeiten mit Variablen


Variablen sind benannte Speicherstellen im Speicher des Computers. Die meisten
Scriptsprachen erlauben eine implizite Deklaration von Variablen. Sie können Variablen also
verwenden, ohne deren vorgesehene Nutzung zu deklarieren. Sie können das folgende Script
zum Beispiel ausführen, ohne dass es zu einem Fehler kommt, und das, obwohl in der ersten
Zeile des Scripts der Wert 11 zur Variable sngDegreesCelsius zugewiesen wird und die
Variable vorher nicht deklariert wurde (VBScript weiß also vorher nichts von deren Existenz).
sngDegreesCelsius = 11
sngDegreesFahrenheit = ConvertToFahrenheit(sngDegreesCelsius)
Wscript.Echo sngDegreesFahrenheit
Function ConvertToFahrenheit(ByVal sngDegreesCelsius)
ConvertToFahrenheit = (sngDegreesCelsius * (9/5)) + 32
End Function
Durch eine implizite Variablendeklaration kann das Entwickeln von Scripten schneller und
einfacher werden. Sie kann jedoch auch zu sehr subtilen Fehlern führen, die schwer zu finden
und zu beheben sind.
Das folgende Script illustriert solche Probleme. Das vorherige Script konvertierte 11° Celsius
in Fahrenheit (51.8°). Das folgende Script macht genau das gleiche. Leider gibt es 32 statt
51.8 zurück.
sngDegreesCelsius = 11
sngDegreesFahrenheit = ConvertToFahrenheit(sngDegreesCelsius)
Wscript.Echo sngDegreesFahrenheit
Function ConvertToFahrenheit(ByVal sngDegreesCelsius)
ConvertToFahrenheit = (sngDegresCelsius * (9/5)) + 32
End Function
Warum gibt das Script einen falschen Wert zurück? Das Problem liegt in einem einfachen
Tippfehler. In Zeile 6 sollte die Variable sngDegreesCelsius verwendet werden. Stattdessen
hat der Entwickler jedoch sngDegresCelsius (ein e fehlt im Wort Degrees). Das führt dazu,
dass die Berechnung den Wert in der Variable sngDegresCelsius statt jenem in
sngDegreesCelsius verwendet. Da der Variablen sngDegresCelsius nie ein Wert zugewiesen
wurde, enthält sie den Standardwert 0. Als Konsequenz wird der Wert 0 mit 9/5 multipliziert -
das Ergebnis ist 0. Das Script addiert dann 32 zu diesem Wert und gibt das falsche
Endergebnis 32 zurück.

Seite 43 von 394


Solche Fehler können wirklich schwer zu finden sein. Der Syntax ist korrekt, daher wird
keine Fehlermeldung generiert. Sie erwarten einen numerischen Wert, und Sie erhalten auch
einen. In einem größeren Script könnte die Suche nach einem Tippfehler sehr lange dauern.

Variablen unter VBScript deklarieren


Um Probleme wie das oben demonstrierte zu vermeiden, können Sie alle Variablen explizit
deklarieren. In diesem Fall führen alle nicht deklarierten Variablen zu einem Laufzeitfehler.
In dem folgenden Script wird zum Beispiel über den Befehl Option Explicit eine explizite
Variablendeklaration erzwungen und jede Variable wird über den Befehl Dim deklariert:
Option Explicit
Dim sngDegreesCelsius
Dim sngDegreesFahrenehit
sngDegreesCelsius = 11
sngDegreesFahrenheit = ConvertToFahrenheit(sngDegreesCelsius)
Wscript.Echo sngDegreesFahrenheit
Function ConvertToFahrenheit(ByVal sngDegreesCelsius)
ConvertToFahrenheit = (sngDegresCelsius * (9/5)) + 32
End Function
Wenn das Script ausgeführt wird, findet der Scripting-Host eine undeklarierte Variable. Daher
wird die Ausführung des Scripts angehalten, und es wird ein Fehlermeldung wie die folgende
angezeigt:
C:\Scripts\TempConvert.vbs(10, 5) Laufzeitfehler in Microsoft VBScript:
Variable ist nicht
definiert: 'sngDegresCelsius'
Um in VBScript Variablen zu deklarieren, gehen Sie folgendermaßen vor:
1.Verwenden Sie den Befehl Option Explicit, um die Deklaration von Variablen zu
erzwingen. Der Befehl muss in der ersten Zeile Ihres Scripts stehen.
2.Verwenden Sie den Befehl Dimzur Deklaration von Variablen. Auch wenn Sie mit einem
Dim-Befehl mehrere Variablen deklarieren können, sollten Sie sich doch auf eine Variable
pro Dim-Befehl beschränken. Dies ermöglicht es Ihnen, einen Kommentar hinter der
Deklaration einzufügen, indem Sie die Verwendung der Variable beschreiben können. Das
Ergebnis könnte so aussehen:

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

Initialisierung von Variablen


Initialisieren von Variablen bedeutet ganz einfach, dass Sie den Variablen schon zu Beginn
einen Wert zuweisen. Die folgenden beiden Codezeilen initialisieren zum Beispiel zwei
Variablen. X wird der Wert 100 zugewiesen und Y der Wert abcde:
X = 100
Y = 'abcde'
Wenn Sie Variablen deklarieren, diese aber nicht initialisieren (ihnen also keinen Wert
zuweisen), dann hat die Variable einen von zwei Standardwerten:

Wenn die Variable als Zeichenkette (String) verwendet wird, dann hat sie den Wert Leer

Seite 44 von 394


(Empty).

Wenn die Variable als Zahl verwendet wird, dann hat Sie den Wert 0.
Das folgende Script deklariert zum Beispiel zwei Variablen (X und Y), weist diesen jedoch
keinen Wert zu:
Dim X
Dim Y
Wscript.Echo X & Y
Wscript.Echo X + Y
In Zeile 3 werden die beiden Variablen als Zeichenketten verwendet (der Operator "&"
verbindet zwei Zeichenketten zu einer). Das Ergebnis dieser Zeile sehen Sie in Abbildung 2.8.
Da beide Variablen leer sind, ist auch die Kombination aus beiden leer. Das Fenster zeigt also
eine leere Zeichenkette an.

Abbildung 2.8: Verbinden zweier nicht initialisierter Variablen


In Zeile 4 werden die beiden Variablen als Zahlen verwendet. Numerische Variablen, die
nicht initialisiert wurden, haben automatisch den Wert 0. Daher gibt diese Zeile des Scripts
auch die Summe aus 0 + 0 zurück.

Abbildung 2.9: Addition zweier nicht initialisierter Variablen


Verwendung des Gleichheitszeichens in VBScript
In VBScript hat das Gleichheitszeichen (=) unterschiedliche Bedeutungen. Normalerweise
wird der Ausdruck X = 2 + 2 so gelesen:
'X gleich 2 plus 2.'
In VBScript wird er allerdings so gelesen:
'X wird der Wert von 2 plus 2 zugewiesen.'
Anscheinend gibt es keinen großen Unterschied. In beiden Fällen wird X der Wert 4
zugewiesen. Sehen Sie sich jedoch einmal folgendes Script an. Es zählt in einer Schleife von
1 bis 10:
For i = 1 to 10
X = X + 1
Next
Die zweite Zeile des Scripts scheint mathematisch unmöglich. Wie kann X gleich X plus 1
sein? Unter VBScript ist dies jedoch ein gültiger Ausdruck. Es handelt sich nicht um eine

Seite 45 von 394


mathematische Berechnung. Stattdessen wird einfach nur der Variable X ein neuer Wert
zugewiesen. Der Ausdruck liest sich also so:
'X wird der momentane Wert von X plus 1 zugewiesen.'
In anderen Worten, wenn X im Moment 3 ist, denn wird X mit diesem Ausdruck der neue
Wert 4 zugewiesen - 3 (der momentane Wert von X) plus 1.
Das Gleichheitszeichen ist also tatsächlich ein Zuweisungszeichen. Sie können es auch zum
Erstellen von Zeichenketten verwenden. Das folgende Script konstruiert zum Beispiel eine
Meldung aus mehreren Zeichenketten:
Message = "Dies "
Message = Message & "ist eine "
Message = Message & "Testmeldung."
Wscript.Echo Message
Die Ausgabe des Scripts sehen Sie in Abbildung 2.10.

Abbildung 2.10: Zusammengefasste Meldung

Verwendung von Konstanten


Konstanten sind Werte, die während der Laufzeit eines Scripts nicht geändert werden können.
Nehmen Sie zum Beispiel an, dass eines Ihrer Scripte US-Dollar in Euro konvertiert. Wenn
wir davon ausgehen, dass der Wechselkurs für einen Dollar 0,84 Euro beträgt, dann können
Sie diesen Wert fest in Ihr Script implementieren (hardcodieren):
curConvertedPrice = curPriceInEuro * 0.84
Auch wenn dieser Ansatz funktioniert gibt es doch einige potentielle Probleme:

Ein anderer Script-Entwickler weiß möglicherweise nicht, wofür der Wert 0.84 steht.

Wechselkurse ändern sich regelmäßig. Wenn Sie den Wert direkt in Ihr Script eintragen,
dann müssen Sie bei einer Änderung das ganze Script durchsuchen und an jeder Stelle den
Wert ändern. Wenn Sie auch nur eine Stelle übersehen, an der der Wert verwendet wird,
dann kann dies zu falschen Berechnungen führen.

Jedes Mal, wenn Sie den Wert per Hand im Script eingeben oder ändern, dann besteht die
Gefahr von Tippfehlern. Wenn Sie zum Beispiel versehentlich 0.084 eingehen, dann wird das
drastische Auswirkungen auf die Berechnung haben.
Um solche Probleme zu vermeiden, sollten Sie statt hardcodierter Werte Konstanten
verwenden. Diese bieten Ihnen einige Vorteile:

Sie können einer Konstante einen eindeutigen Namen geben. Statt der Zahl 0.84 können Sie
so zum Beispiel den Namen US_DOLLAR_IN_EURO_WECHSELKURS verwenden.

Sie sind einfach zu ändern. Wenn sich der Wechselkurs ändert, dann ändern Sie nur die

Seite 46 von 394


Stelle, an der die Konstante definiert wird.

Da Sie den Wert nur einmal eingeben müssen, sind sie weniger anfällig für Tippfehler.

Sie können nicht versehentlich geändert werden. Nachdem eine Konstante definiert wurde,
führt jeder Versuch im Script den Wert der Konstante zu ändern, zu einem Fehler.

Sie können für Zeichenketten und für Zahlenwerte verwendet werden.

Definieren von Konstanten


Unter VBScript werden Konstanten mit dem Schlüsselwort Const gefolgt von dem Namen
und dem Wert der Konstante, definiert. Sie müssen der Konstante bei deren Definition einen
Wert zuweisen; es ist nicht möglich, der Konstante über eine Variable, eine andere Konstante
oder über eine Funktion einen Wert zuzuweisen. Das folgende Beispiel versucht, eine
Konstante mit der Variable NumberOfDepartments zu definieren und verursacht den Fehler
"Literalkonstante erwartet":
NumberOfDepartments = 20
Const NUMBER_OF_DEPARTMENTS = NumberOfDepartments
Der Konstante muss stattdessen der Wert 20 zugewiesen werden:
Const NUMBER_OF_DEPARTMENTS = 20

Vordefinierte Konstanten verwenden


VBScript umfasst bereits einige vordefinierte Konstanten. Diese können Sie zum Beispiel für
Nachrichtenfenster, Ausgaben oder andere Aktivitäten verwenden. Das folgende Script zeigt
zum Beispiel ein Nachrichtenfenster an. Die im Nachrichtenfenster angezeigten Schalter
werden hierbei durch einen numerischen Wert festgelegt. Auch wenn das Script problemlos
funktioniert, ist es doch schwer festzustellen, was genau das Script macht. Sie müssen wissen,
dass die Zahl 260 bedeutet, dass ein Nachrichtenfenster mit den Schaltern Ja und Nein erstellt
werden soll, bei dem der Schalter Nein standardmäßig den Focus hat. Die Zahl 7 bedeutet,
dass der Benutzer auf den Schalter Nein geklickt hat.
ConfirmDelete = MsgBox ("Möchten Sie die Dateien löschen? ", _
260, "Alle Dateien löschen")
If ConfirmDelete = 7 then
Wscript.Quit
End If
Die folgende Variante des Scripts verwendet statt Zahlen die vordefinierten Konstanten von
VBScript (VbYesNo, VBDefaultButton2 und VbNo). Das Script wird so besser lesbar und
verständlicher.
ConfirmDelete = MsgBox ("Möchten Sie die Dateien löschen? ", _
VbYesNo OR VBDefaultButton2, "Alle Dateien löschen")
If ConfirmDelete = VbNo then
Wscript.Quit
End If
Mit Konstanten wird es außerdem einfacher das Script in einer anderen Programmiersprache
umzusetzen. VBScript verwendet für die Konstante True zum Beispiel den Wert -1; in Visual
Basic hat True aber den Wert 1. Wenn Sie eine Konstante statt des Wertes verwendet haben,
dann müssen Sie sich über dieses Problem keine Sorgen machen, wenn Sie das Script
übertragen sollten.
Die zwei am häufigsten verwendeten vordefinierten Konstanten sind wahrscheinlich:

Seite 47 von 394



VbCrLf - Diese Konstante steht für einen Zeilenumbruch. Sie wird meist zur Formatierung
von Ausgaben verwendet. Das folgende Script produziert zum Beispiel einen mehrzeiligen
Nachrichtentext:

Wscript.Echo 'Erste Textzeile.' & VbCrLF & VbCrLF & _


'Zweite Textzeile.'

Wenn Sie das Script mit Wscript ausführen, dann sehen Sie ein Nachrichtenfenster, das wie
in Abbildung 2.11 aussieht.

Abbildung 2.11: Mit VbCrLf getrennter Text



VbTab - Diese Konstante entspricht einem Tabulatorzeichen. Das folgende Script produziert
zum Beispiel drei durch Tabulatoren getrennte Textspalten:

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

Seite 48 von 394


Wscript.Echo objDiskDrive.DriveLetter
End if
Next
Das Script arbeitet fehlerhaft, da VBScript nicht weiß, dass die Konstante Fixed den Wert 2
hat. Stattdessen behandelt VBScript Fixed als einfache Variable, der kein Wert zugewiesen
wurde. Damit ist die Variable leer, und es wird nach Laufwerken gesucht, bei denen das
Attribut DriveType den Wert 0 statt 2 hat. Da VBScript kein Laufwerk mit diesem Wert
finden kann, wird auch nichts ausgegeben.
Damit das Script funktioniert, müssen Sie eine eigene Konstante mit dem Namen Fixed und
dem Wert 2 definieren:
Const Fixed = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set colDiskDrives = objFSO.Drives
For Each objDiskDrive in colDiskDrives
If objDiskDrive.DriveType = Fixed then
Wscript.Echo objDiskDrive.DriveLetter
End if
Next

Datentypen unter VBScript


VBScript ist eine typenlose Sprache. Das bedeutet, dass Variablen nicht auf einen einzelnen
Datentyp beschränkt werden können. Stattdessen verwendet VBScript nur einen einzigen
Variablentyp: Variant. Dieser kann sämtliche Datentypen speichern.
Im Gegensatz dazu müssen Sie in einer Programmiersprache wie C++ den Typ der in einer
Variablen zu speichernden Daten genau definieren. Wenn Sie versuchen Daten in einer
Variable zu speichern, die für einen anderen Datentyp vorgesehen ist, dann kommt es zu
einem Fehler.
Variant-Variablen können das Entwickeln von Scripten sehr vereinfachen. Sie können
Variablen deklarieren und verwenden, und müssen sich keine Gedanke über die in ihnen
gespeicherten Daten machen. Wenn Sie sich jedoch nicht mit der Typumwandlung
auskennen, dann kann das gleiche Prinzip aber auch zu Problemen führen.

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:")

Seite 49 von 394


intTotal = intFirstNumber + intSecondNumber
Wscript.Echo intTotal
Wenn Sie das Script ausführen und als erste Zahl 4 und als zweite Zahl 2 eingeben, dann gibt
das Script als Ergebnis der Berechnung 4 + 2 die Zahl 42. Wir hatten aber mit der Zahl 6
gerechnet.
Das liegt daran, dass der Operator sowohl für Zahlen als auch für Zeichenketten verwendet
werden kann. VBScript hat in diesem Fall nur zwei Werte (4 und 2). Es gibt keine Angaben
dazu, was das für Werte sind. Ohne weitere Informationen führt VBScript eine
Typumwandlung der beiden Variablen in einen String (Zeichenkette) durch. Wenn die beiden
Zeichenketten nun verkettet werden, dann ist das Ergebnis logischerweise die neue
Zeichenkette "42".
Im Gegensatz dazu gibt das folgende Script den korrekten Wert (2) zurück (zumindest dann,
wenn Sie die Zahlen 4 und 2 eingeben). Das liegt daran, dass der Divisionsoperator (/) nur mit
Zahlen arbeiten kann. In diesem Fall führt VBScript eine Typumwandlung in Ganzzahlen
(Integer) durch.
intFirstNumber = InputBox("Please enter the first number:")
intSecondNumber = InputBox("Please enter the second number:")
intTotal = intFirstNumber / intSecondNumber
Wscript.Echo intTotal
Um solche Probleme zu vermeiden, können Sie die von VBScript zu verwendenden
Datentypen direkt in Ihrem Script angeben. Dies wird auch Casting oder auch explizite
Typumwandlung genannt. Das folgende Script verwendet die Funktion CInt, um die
Eingabevariablen vor der Berechnung in Ganzahlen (Integer) zu konvertieren:
intFirstNumber = CInt(InputBox("Please enter the first number:"))
intSecondNumber = CInt(InputBox("Please enter the second number:"))
intTotal = intFirstNumber + intSecondNumber
Wscript.Echo intTotal
In Tabelle 2.6 sehen Sie alle unter VBScript verfügbaren Funktionen zur expliziten
Typumwandlung.

Tabelle 2.6: VBScript-Funktionen zur expliziten Typumwandlung


FunktionBeschreibung
CBool Konvertiert einen Wert größer Null in Wahr (True) und den Wert 0 zu Falsch
(False).
CByte Konvertiert einen Wert in den Datentyp Byte.
CCur Konvertiert einen Wert in den Datentyp Currency (Währung).
CDate Konvertiert einen Wert in den Datentyp Date (Datum).
CDbl Konvertiert einen Wert in den Datentyp Double (Fliesskommazahl).
CInt Konvertiert einen Wert in den Datentyp Integer (Ganzzahl). Wenn der
Nachkommawert einer Fliesskommazahl 5 oder größer ist, dann rundet die Funktion
das Ergebnis auf. Die Fliesskommazahl 3.5 wird zum Beispiel zu 4 aufgerundet.
CLng Konvertiert einen Wert in den Datentyp Long.
CSng Konvertiert einen Wert in den Datentyp Single.

Seite 50 von 394


FunktionBeschreibung
CStr Konvertiert einen Wert in den Datentyp String (Zeichenkette).

Mit leeren Variablen und Null-Variablen arbeiten


Für die erfolgreiche Ausführung eines Scripts kann es wichtig sein, dass Sie den Unterschied
zwischen einer leeren Variable (Empty) und einer Null-Variable (Null) verstehen. Eine leere
Variable ist eine Variable, die nicht initialisiert wurde. Nach dem Ausdruck Dim curBonus ist
diese Variable so lange "leer", bis Sie ihr einen Wert zugewiesen haben. Eine leere Variable
hat den Wert 0, wenn Sie als Zahl verwendet wird. Wenn Sie als Zeichenkette (String)
verwendet wird, hat sie hingegen den Wert '' (eine Zeichenkette der Länge null).
Eine Null-Variable ist hingegen eine Variable, der kein gültiger Wert zugewiesen ist.
Typischerweise entstehen Null-Variablen im Zusammenhang mit Datenbankoperationen.
Stellen Sie sich zum Beispiel vor, Sie führen eine Datenbankabfrage durch und erhalten so
das Feld "Bonus" eines bestimmten Mitarbeiters. Diesen Wert weisen Sie dann der Variable
curBonus zu. Wenn dieser Mitarbeiter keinen Bonus erhält, dann ist die Variable in diesem
Fall Null.
Der Unterschied zwischen einer leeren Variable und einer Null-Variable tritt bei
mathematischen Operationen auf. Im folgenden Script wird der Wert von curBonus auf Empty
(leer) gesetzt. Danach wird die Variable curBonus zur Variable curBaseSalary (50.000)
addiert. Das Ergebnis ist: 50,000 + 0 = 50,000.
curBonus = Empty
curBaseSalary = 50000
curTotalCompensation = curBaseSalary + curBonus
Wscript.Echo TotalCompensation
Im nächsten Script wird genau das gleiche durchgeführt. Die Variable curBonus wird jedoch
auf den Wert Null gesetzt. Bei der Berechnung erhalten Sie jedoch nicht 50.000 als Ergebnis.
Stattdessen lautet das Ergebnis Null. Wenn in einer mathematischen Operation eine Null-
Variable verwendet wird, dann ist das Endergebnis immer Null. Das liegt daran, dass der Wert
einer Null-Variable nicht bekannt ist - sie hat ja keinen Wert (stellen Sie sich das Ergebnis
Null vor als "ich weiß es nicht").
curBonus = Null
curBaseSalary = 50000
curTotalCompensation = curBaseSalary + curBonus
Wscript.Echo TotalCompensation
Null-Werte könnten bei der Arbeit mit Datenbanken und beim Abfragen von Active
Directory-Informationen über ADSI zu Problemen führen. Glücklicherweise können Sie über
die Methode IsNull feststellen, ob eine Variable den Wert Null hat. Das folgende Script prüft
zum Beispiel den Wert der Variable curBonus. Wenn sie den Wert Null hat, wird ihr explizit
der Wert 0 zugewiesen (denken Sie daran: Null heißt "kein Wert" und 0 heißt "der Wert 0").
Somit kann die Variable dann für eine Berechnung verwendet werden. Alternativ könnten Sie
sich dazu entscheiden die Berechnung nicht durchzuführen und eine Meldung wie "Dem
Mitarbeiter wurden keine Bonus-Informationen zugewiesen" anzuzeigen.
curBonus = Null
curBaseSalary = 50000
If IsNull(curBonus) Then
CurBonus = 0
End If
curTotalCompensation = curBaseSalary + curBonus
Wscript.Echo curTotalCompensation

Seite 51 von 394


Mit Datum- und Zeitinformationen arbeiten
Daten und Uhrzeiten spielen in der Systemadministration eine wichtige Rolle. Wenn Sie zum
Beispiel mit Ereignisprotokollen arbeiten, dann möchten Sie möglicherweise alle Einträge für
einen bestimmten Zeitraum anzeigen. Um die Verfügbarkeit von Diensten zu prüfen, müssen
Sie möglicherweise feststellen, wann ein Dienst gestartet und beendet wurde - und aus diesen
beiden Werten die tatsächliche Laufzeit des Dienstes berechnen. Um sicherzustellen, dass
Scripte wie geplant ausgeführt werden, müssen Sie Datum und Uhrzeit der Scriptausführung
festhalten. Sie sehen also, es gibt eine Menge Anwendungen für Datum- und
Zeitinformationen.
VBScript bietet Ihnen mehrere unterschiedliche Wege, um Datum- und Zeitwerte zu erhalten.
Außerdem stehen Ihnen mehrere Methoden zur Verfügung, um mit diesen Werten zu rechnen
(zum Beispiel um die Tage zwischen zwei Daten zu berechnen).

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.

Abfragen der aktuellen Uhrzeit und des Datums


Oft benötigen Sie zur Systemadministration die aktuelle Uhrzeit oder das aktuelle Datum.
VBScript bietet Ihnen hierzu drei Funktionen an:

Now - gib das aktuelle Datum und die Uhrzeit zurück.

Date - gibt nur das aktuelle Datum zurück.

Time - gibt nur die aktuelle Uhrzeit zurück.
Das folgende Script verwendet die drei Funktionen und zeigt die Ergebnisse in einem
Nachrichtenfenster an:
DateInfo = DateInfo & Now & VbCrLf
DateInfo = DateInfo & Date & VbCrLf
DateInfo = DateInfo & Time & VbCrLf
Wscript.Echo DateInfo
Die Ausgabe des Scripts sehen Sie in Abbildung 2.12.

Abbildung 2.12: Rückgabewerte der Funktionen Now, Date und Time

Prüfen, ob ein Wert ein gültiges Datum ist


Bei der Arbeit mit Daten müssen Sie manchmal feststellen, ob ein Wert ein Datum ist oder
nicht. Dies kann zum Beispiel bei WMI-Abfragen oder bei der Arbeit mit Datenbanken
wichtig werden.
Seite 52 von 394
Die Funktion IsDate zeigt Ihnen, ob ein Wert ein gültiges Datum ist. Sie gibt den Wert 0
(False - Falsch) zurück, wenn es sich bei dem Wert nicht um ein Datum handelt - andernfalls
erhalten sie den Wert -1 (True - Wahr) zurück. Sie können der Funktion den zu prüfenden
Wert auf zwei Arten übergeben:

Als VBScript-Datumswert - Das Datum wird durch zwei Doppelkreuze (#) eingeschlossen.
Dies ist die empfohlene Vorgehensweise. Sie verhindert, dass VBScript den Wert falsch
interpretiert. Ein Datumswert sieht folgendermaßen aus:

#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.

Seite 53 von 394


Teile eines Datums oder eines Zeitwertes abfragen
Oft benötigen Sie nur einen bestimmten Teil eines Datums oder eines Zeitwertes. Zum
Beispiel, wenn Sie Ihr Sicherungsscript nur an Sonntagen oder nur am 15. eines Monats
ausführen möchten.
Unter VBScript haben Sie zwei Möglichkeiten Teile eines Datums oder eines Zeitwertes
abzufragen. Mit der Funktion DatePart können Sie jeden beliebigen Teil eines Datums oder
eines Zeitwertes abfragen. Außerdem stellt VBScript mehrere Funktionen zur Verfügung, um
bestimmte Teile abzufragen (zum Beispiel die Funktionen Day, Month und Year).
Die Funktion DatePart benötigt zwei Parameter: Das Datum und den Teil des Datums, den
Sie herausfinden möchten. Der Teil muss in einem bestimmen Format angegeben werden.
Dieses Format wird in der folgenden Tabelle beschrieben.

Tabelle 2.7: Parameter der Funktion DatePart


ParameterBeschreibung
yyyy Jahr - gibt die Jahreszahl des Datum-/Zeitwerts zurück.
q Quartal - gibt das Quartal - 1, 2, 3 oder 4 - des Datum-/Zeitwerts zurück.
m Monat - gibt den Monat des Datum-/Zeitwerts zurück. Hierbei gelten folgend
Werte:

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

Seite 54 von 394


ParameterBeschreibung
den Wert 17 erhalten.
w Wochentag - gibt den Wochentag zurück. Hierbei gelten die folgenden Werte:

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)

Seite 55 von 394


Anmerkung: Auch wenn Sie ein Datum zu einer Variablen zuweisen, müssen Sie das Datum
in Doppelkreuze (#) einschließen. So stellen Sie sicher, dass VBScript den Wert auch als
Datum und nicht als Zahl oder Zeichenkette interpretiert. Alternativ können Sie auch die
Funktion CDate verwenden.
Script 2.15 interpretiert das aktuelle Datum und die Uhrzeit und gibt die einzelnen
Komponenten für den Benutzer aus.

Script 2.15: Verwendung der Funktion DatePart

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.

Seite 56 von 394


Konstante WertBeschreibung
vbFirstJan1 1 Setzt die erste Woche auf die Woche mit dem 1. Januar.
vbFirstFourDays 2 Setzt die erste Woche auf die erste Woche mit mindestens 4 Tagen.
VbFirstFullWeek3 Setzt die erste Woche auf die erste Woche, die mit einem Montag
beginnt.
Hängen Sie den Wert als dritten Parameter hinter das Datum an. Das folgende Script zeigt die
Verwendung des Parameters "Erste Woche":
TestDate = "6/1/2003"
Wscript.Echo TestDate
Wscript.Echo "Woche: " & DatePart("ww" , TestDate)
Wscript.Echo "Woche: " & DatePart("ww" , TestDate, vbFirstJan1)
Wscript.Echo "Woche: " & DatePart("ww" , TestDate, vbFirstFourDays)
Wscript.Echo "Woche: " & DatePart("ww" , TestDate, vbFirstFullWeek)
Wenn Sie das Script mit CScript ausführen, dann erhalten Sie folgendes Ergebnis:
6/1/2003
Woche: 2
Woche: 2
Woche: 2
Woche: 1
Wie Sie in Abbildung 2.13 sehen, fällt der 6. Januar 2003 nicht in dieselbe Woche wie der 1.
Januar. Außerdem liegt er nicht in der ersten Woche, die mindestens vier Tage hat. Er liegt
jedoch in der ersten Woche, die mit einem Montag beginnt.

Abbildung 2.13: 6. Januar 2003


Weitere Funktionen, um Teile eines Datums zu extrahieren
Zusätzlich zur Funktion DatePart können Sie die Funktionen aus Tabelle 2.9 verwenden.
DatePart bietet allerdings einige Möglichkeiten, die Ihnen mit den zusätzlichen Funktionen
nicht zur Verfügung stehen (zum Beispiel den Tag des Jahres). Möglicherweise fällt es Ihnen
jedoch schwer, sich die Parameter von DatePart zu merken. In diesem Fall sind die
zusätzlichen Funktionen deutlich einfacher zu verwenden - sie erfordern keine Parameter. Die
folgenden beiden Codezeilen geben beispielsweise die Minute der aktuellen Uhrzeit zurück.
Für die Funktion Minute benötigen Sie jedoch keine Parameter:
Wscript.Echo DatePart("n", Now)
Wscript.Echo Minute(Now)
Tabelle 2.9: Funktionen, um Teile eines Datums oder eines Zeitwertes zu extrahieren
Funktion Beschreibung

Seite 57 von 394


Funktion Beschreibung
Day Gibt den Tag zurück
Hour Gibt die Stunde zurück
Minute Gibt die Minute zurück
Month Gibt den Monat zurück
Second Gibt die Sekunde zurück
WeekdayGibt den Wochentag zurück. Hierbei gelten folgende Wert:

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.

Seite 58 von 394


Zum Berechnen von Zeiträumen stellt VBScript zwei Funktionen zur Verfügung. DateDiff
und DateAdd.

Berechnen des Zeitraumes zwischen zwei Daten oder Uhrzeiten


Hierzu wird die Funktion DateDiff verwendet. Sie benötigt drei Parameter:

Den Datums- oder Zeitintervall (zum Beispiel die Zahl der Tage zwischen zwei Daten oder
die Zahl der Stunden zwischen zwei Uhrzeiten). Dieser Parameter verwendet dieselben
Werte wie die Funktion DatePart - diese finden Sie in Tabelle 2.7).

Das Startdatum.

Das Enddatum.
Script 2.16 berechnet zum Beispiel die Tage zwischen dem aktuellen Datum und dem 1. Juli
2007. Hierzu wird der Parameter "d" verwendet. Wenn Sie zum Beispiel die Wochen
zwischen den beiden Daten berechnen möchten, dann würden Sie den Parameter durch "w"
ersetzen.

Script 2.16: Berechnen von Zeiträumen

1Wscript.Echo "Date: " & Date


2Wscript.Echo "Tage bis 1. Juli 2007: " & DateDiff("d", Date, "7/1/2002")
Wenn Sie das Script über Cscript ausführen, erhalten Sie folgendes Ergebnis:
Date: 14.03.2004
Tage seit 1. Juli 2002: 1029

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

Seite 59 von 394


Next
Wscript.Echo DateDiff("s", Start, Now)
Daten berechnen
Mit DateDiff können Sie feststellen, wie groß der Zeitraum zwischen zwei Daten ist. Es wird
jedoch ganz sicher auch Fälle geben, in denen Sie den Zeitraum kennen und mit diesem ein
Datum berechnen müssen. Wenn Sie zum Beispiel alle Protokolleinträge der letzten 45 Tage
abrufen möchten, dann kennen Sie das Enddatum (heute) und den Zeitraum (45 Tage) - nun
fehlt ihnen noch das Startdatum.
Ein solches Datum können Sie mit der Funktion DateAdd berechnen. Die Funktion erwartet
drei Parameter:

Den Intervall (auch hier verwenden Sie bitte wieder die Werte von DatePart aus Tabelle 2.7).
Wenn Sie zum Beispiel das Datum in 180 Tagen von heute an berechnen möchten, dann
verwenden Sie den Parameter "d".

Den Zeitraum (zum Beispiel 180 für 180 Tage). Um von einem Datum aus rückwärts zu
rechnen, verwenden Sie einfach eine negative Zahl.

Das Startdatum.
Script 2.17 berechnet das Datum, das 180 Tag nach dem heutigen Datum liegt.

Script 2.17: Berechnen eines Datums

1Wscript.Echo "Datum: " & Date


2Wscript.Echo "180 von heute an: " & DateAdd("d", 180, Date)
Wenn das Script am 14. März 2004 ausgeführt wird, dann erhalten Sie folgende Ausgabe:
Datum: 14.03.2004
180 von heute an: 10.09.2004

Formatierung von Datum- und Zeitwerten


Standardmäßig zeigt VBScript die Ausgaben der Funktionen Now, Date und Time so an, dass
sie den Betriebssystemeinstellungen entsprechen. Auf Computer mit der deutschen Version
von Windows sieht diese Ausgabe normalerweise so aus, wie in Tabelle 2.10 dargestellt.

Tabelle 2.10: Standardausgabe von Datum und Uhrzeit


FunktionBeispielausgabe
Now 14.03.2004 22:08:10
Date 14.03.2004
Time 22:08:10
Sie müssen sich jedoch nicht auf diese Standardformate beschränken. Stattdessen stellt
VBScript mehrere Konstanten zur Verfügung, über die Sie mit der Funktion FormatDateTime
Datum- und Zeitwerte neu formatieren können.

Tabelle 2.11: Parameter der Funktion FormatDateTime


Konstante Wert
vbGeneralDate0

Seite 60 von 394


Konstante Wert
vbLongDate 1
vbShortDate 2
vbLongTime 3
vbShortTime 4
Das folgende Script zeigt das aktuelle Datum und die Uhrzeit an, und gibt diese in
unterschiedlichen Formaten aus:
CurrentDate = Now
Wscript.Echo "GeneralDate: " & FormatDateTime(CurrentDate, vbGeneralDate)
Wscript.Echo "LongDate: " & FormatDateTime(CurrentDate, vbLongDate)
Wscript.Echo "ShortDate: " & FormatDateTime(CurrentDate, vbShortDate)
Wscript.Echo "LongTime: " & FormatDateTime(CurrentDate, vbLongTime)
Wscript.Echo "ShortTime: " & FormatDateTime(CurrentDate, vbShortTime)
Wenn Sie das Script über CScript ausführen, erhalten Sie das folgende Ergebnis:
GeneralDate: 14.03.2004 22:12:53
LongDate: Sonntag, 14. März 2004
ShortDate: 14.03.2004
LongTime: 22:12:53
ShortTime: 22:12
Dies sind die einzigen vordefinierten Formate unter VBScript. Sie können Sich jedoch auch
eigene Formate zusammenbauen. Die folgende Codezeile zeigt das Datum zum Beispiel im
Format "Monat/Jahr" an:
Wscript.Echo Month(Now) & "/" & Year(Now)
Formatierung von Wochentag und Monat des Jahres
Die Funktionen WeekdayDay und Month liefern Ihnen den Wochentag oder den Monat eines
Datums. Bei dem Rückgabewert handelt es sich allerdings um einen Integer-Wert (Ganzahl).
Die Bedeutung der Werte sehen Sie in Tabelle 2.12

Tabelle 2.12: Werte für Wochentag und Monat


WertWochentagMonat
1 Sonntag Januar
2 Montag Februar
3 Dienstag März
4 Mittwoch April
5 Donnerstag Mai
6 Freitag Juni
7 Samstag Juli
8 - August
9 - September
10 - Oktober

Seite 61 von 394


WertWochentagMonat
11 - November
12 - Dezember
Um die Funktionen WeekdayName und MonthName verwenden zu können, müssen Sie erst
den Tag oder den Monat aus dem Datum extrahieren. Sie können nicht direkt mit einem
Datum verwendet werden. Die folgende Codezeile funktioniert zum Beispiel nicht:
Wscript.Echo MonthName("19/9/2002")
Um MonthName verwenden zu können, müssen Sie zuerst die Funktion Month verwenden:
MonthValue = Month("19/9/2002")
Wscript.Echo MonthName(MonthValue)
Alternativ können Sie die beiden Funktionen in einer Codezeile verschachteln:
Wscript.Echo MonthName(Month("19/9/2002"))
Eine genauere Beschreibung der Funktionen WeekdayName und MonthName finden Sie in
Tabelle 2.13.

Tabelle 2.13: WeekdayName und MonthName


Funktion Beschreibung
WeekdayNameGibt statt der Nummer des Tages dessen Namen zurück. Als Parameter muss
nur der Tag angegeben werden. Daher müssen Sie die Funktionen
WeekdayName und Day folgendermaßen verschachteln:

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 WeekDayName(Day('9/1/2002'), True)


MonthName Gibt statt der Nummer des Monats dessen Namen zurück. Als Parameter muss
nur der Monat angegeben werden. Daher müssen Sie die Funktionen
MonthName und Month folgendermaßen verschachteln:

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:

Wscript.Echo MonthName(Month('9/1/2002') , True)

Arbeiten mit Strings (Zeichenketten)


Viele Scripte zur Systemadministration geben Informationen über verwaltete Elemente zurück
- zum Beispiel Dienste, Hardware oder Ereignisse. Viele dieser Informationen werden als

Seite 62 von 394


Zeichenketten zurückgegeben. Wenn Sie zum Beispiel die Beschreibung eines Ereignisses aus
dem Ereignisprotokoll abrufen, dann erhalten Sie einen String wie den folgenden:
Dienst "Universeller Plug & Play-Gerätehost" befindet sich jetzt im Status
"Ausgeführt".
Auch wenn Zeichenketten eigentlich ganz einfach sind, kann die Arbeit mit Ihnen kniffelig
sein. Ganz besonders, wenn die Daten von einem COM-Objekt zurückgegeben werden oder
wenn Sie die Daten in einer Datenbank speichern oder auf dem Bildschirm anzeigen müssen.
Das liegt daran, dass Sie keine Kontrolle darüber haben, wie die zurückgegebenen Daten
aussehen. Es kann sein, dass sie falsch formatiert sind (zum Beispiel nur Großbuchstaben)
oder das eine Zeichenkette zu lang oder zu kurz für den vorgesehenen Platz ist (wenn das Feld
in der Datenbank zum Beispiel nur 20 Zeichen lang und die Zeichenkette 30 Zeichen lang ist).
Daher sollten Sie in der Lage sein mit Strings umzugehen - zum Beispiel einen String zu
verkürzen oder zu verlängern, einen String neu zu formatieren oder in einem String nach
einem Text zu suchen. Hierzu stellt Ihnen VBScript einige Funktionen zur Verfügung.

Manipulation von Strings und String-Längen


Oft benötigen Sie nur einen Teil eines Strings. Der Windows Script Host (WSH) stellt zum
Beispiel ein Attribut mit dem Namen FullName zur Verfügung. Dieses zeigt Ihnen, ob ein
Script unter CScript oder WScript ausgeführt wird. Diese Information kann sehr nützlich sein,
wenn Sie Scripte verwenden, die entweder nur unter CScript oder nur unter WScript
ausgeführt werden können. Das Attribut gibt aber leider nicht nur den Namen des Scripting
Hosts zurück, sondern den gesamten Pfad der ausführbaren Datei des Scripting Hosts. Dieser
sieht normalerweise so aus:
C:\Windows\Cscript.exe
C:\Windows\Wscript.exe.
Meistens benötigen Sie jedoch nicht den gesamten Pfad, sondern nur den Namen des
Scripting Hosts - außerdem hängt der Pfad auch vom Speicherort der ausführbaren Datei des
Scripting Hosts ab. Daher benötigen Sie eine Methode, um nur die letzten acht Zeichen
(cscript.exe oder wscript.exe) aus dem Pfad zu extrahieren.
In anderen Fällen ist die Länge eines Strings sehr wichtig. Ganz besonders dann, wenn es um
formatierte Bildschirmausgaben oder Ausgaben in eine Textdatei geht. Das folgende Script
ruft zum Beispiel eine Collection ab, die die im Ordner C:\Windows gespeicherten Dateien
enthält und gibt Dateiname, Dateigröße und das Datum des letzten Zugriffs für jede Datei aus:
Set FSO = CreateObject("Scripting.FileSystemObject")
Set Folder = FSO.GetFolder("C:\Windows")
Set FileList = Folder.Files
For Each File in FileList
Wscript.Echo File.Name & VbTab & File.Size & File.DateLastModified
Next
Wenn Sie das Script ausführen, dann wird die Ausgabe so ähnlich wie unten aussehen. Wie
Sie feststellen werden, ist es nicht so einfach, diese Ausgabe zu lesen.
regedit.exe 14131229.08.2002 04:43:40
regopt.log 134816.01.2004 22:15:13
Rhododendron.bmp 1736218.08.2001 14:00:00
Santa Fe-Stuck.bmp 6583218.08.2001 14:00:00
SchedLgU.Txt 542414.03.2004 18:36:49
Seifenblase.bmp 6597818.08.2001 14:00:00
sessmgr.setup.log 106016.01.2004 22:27:34
SET3.tmp 108618229.08.2002 09:54:40
SETA.tmp 1389818.08.2001 14:00:00

Seite 63 von 394


Mit ein paar Tabulatoren und in Spalten angeordnet ist die Ausgabe viel einfacher zu lesen
und zu überblicken:
regedit.exe 141312 29.08.2002 04:43:40
regopt.log 1348 16.01.2004 22:15:13
Rhododendron.bmp 17362 18.08.2001 14:00:00
Santa Fe-Stuck.bmp 65832 18.08.2001 14:00:00
SchedLgU.Txt 5424 14.03.2004 18:36:49
Seifenblase.bmp 65978 18.08.2001 14:00:00
sessmgr.setup.log 1060 16.01.2004 22:27:34
SET3.tmp 1086182 29.08.2002 09:54:40
SETA.tmp 13898 18.08.2001 14:00:00
Um eine solche Ausgabe zu erreichen, müssen Sie Strings verändern. In der letzten Ausgabe
beginnt der Dateiname zum Beispiel an Zeichenposition 1, und die Dateigröße beginnt immer
an Zeichenposition 30:
123456789012345678901234567890123456789012345678901234567890123456789
SETA.tmp 13898 18.08.2001 14:00:00
Um eine solche Ausgabe zu erstellen, müssen Sie Folgendes durchführen:
1.Sie müssen die Länge der Dateinamen berechnen (der Dateiname SETA.tmp ist zum
Beispiel 8 Zeichen lang).
2.Sie müssen die Länge des Dateinamens (8 Zeichen) vom Gesamtplatz für den Dateinamen
(30 Zeichen) abziehen.
3.Sie müssen entsprechend viele Leerzeichen einfügen (30 minus 8 = 22 Leerzeichen).
Glücklicherweise stellt VBScript eine Menge Funktionen zur Manipulation von Strings zur
Verfügung. Einige dieser Funktionen sehen Sie in Tabelle 2.14.

Tabelle 2.14: Funktionen zur String-Bearbeitung


FunktionBeschreibung
Len Gibt die Zahl der Zeichen in einem String zurück. Diese Funktion ist besonders bei
der Bildschirmausgabe von Strings nützlich. Stellen Sie sich vor, Sie möchten in
einer bestimmten Spalte nicht mehr als 20 Zeichen ausgeben. Um dies zu
garantieren, müssen Sie feststellen können, wie viele Zeichen ein String enthält.

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.

Seite 64 von 394


FunktionBeschreibung

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.

Seite 65 von 394


Die Variable DisplayName enthält dann folgenden String (die Trennstriche stehen für
Leerzeichen):
Warndienst----------
5.Das Script gib die Variable DisplayName und den Status des Dienstes aus.
6.Es wiederholt den Prozess für den nächsten Dienstnamen.

Script 2.18: Tabellarische Ausgaben

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.

Abbildung 2.14: Buchstaben in einer nichtproportionalen Schrift


Im Gegensatz dazu wird in einem Nachrichtenfenster normalerweise eine proportionale
Schrift verwendet. Das bedeutet, dass die Breite der Buchstaben unterschiedlich ist. Wie Sie
in Abbildung 2,15 sehen, sind die Zeichen i, j und l hier viel schmaler als die Zeichen m, v
und w.

Seite 66 von 394


Abbildung 2.15: Zeichenbreite bei einer proportionalen Schrift
Aufgrund dieser unterschiedlichen Zeichenbreiten können Sie nicht einfach davon ausgehen,
dass eine Spalte zum Beispiel an Position 20 beginnt und dass die Spalte damit bündig
ausgerichtet ist.

In einem String nach Text suchen


Sie haben also nicht immer eine vollständige Kontrolle über den ausgegebenen Text. Stellen
wir uns einmal vor, Sie möchten eine Protokolldatei öffnen und feststellen, welche Aktionen
fehlgeschlagen und welche erfolgreich waren. In den meisten Fällen enthalten
Protokolleinträge sehr viel mehr Text als ein einfaches Erfolgreich oder Fehlgeschlagen.
Stattdessen können Einträge zum Beispiel so aussehen:
MSI: False - MSP: True - CMW: False
MSISW: REINSTALL=all REINSTALLMODE=vomus /QB /L*V+
C:\WINNT\DEBUG\officexp_sp1.log
MSPSW: REBOOT=ReallySuppress /QB- /L*V+
C:\WINDOWS\DEBUG\officexp_sp1.log
InstallFile Result: [0] and Success: True
Client Maint Wiz: PROPLUS detected
Um hier Erfolg oder Fehlschlag festzustellen, muss Ihr Script den gesamten Text lesen und
dann nach den gewünschten Informationen suchen (in diesem Beispiel nach dem Text
'Success: True').
Die Funktion InStr gibt Ihnen die Möglichkeit, nach einem String in einem anderen String zu
suchen. Stellen Sie sich zum Beispiel vor, Sie haben eine Protokolldatei mit Hunderten
solcher Einträge:
6/1/2002 File a.doc successfully copied
6/1/2002 File b.doc successfully copied
6/1/2002 Error: File c.doc could not be copied
6/1/2002 File d.doc successfully copied
Statt diese nun per Hand zu prüfen, können Sie ein Script schreiben, dass die Protokolldatei
Zeilenweise einliest und nur die Zeilen ausgibt, die das Wort "Error" enthalten.

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).

Seite 67 von 394


InStr gibt die Zeichenposition zurück, an der der Suchstring gefunden wurde. Nehmen wir an,
Sie suchen nach dem Text ment im Wort developmental. In diesem Fall gibt InStr den Wert 8
zurück, da der Text ment an Zeichenposition Acht anfängt.

Abbildung 2.16: Zeichenpositionen im Wort Developmental


Wenn Sie jedoch nach dem Text mant suchen, dann gibt InStr den Wert 0 zurück. Dieser
Rückgabewert bedeutet, dass der Suchstring nicht gefunden wurde.
InStr benötigt zwei Parameter: den String, in dem gesucht werden soll und den String, nach
dem gesucht werden soll (der Suchstring). Die folgende Codezeile sucht im Wort
developmental zum Beispiel nach dem Text ment:
Wscript.Echo InStr("ment", "developmental")
Sie können die verwendeten Strings auch zu Variablen zuweisen und diese dann in der
Funktion verwenden. Das folgende Script sucht im Satz In diesem Text-String wird nach zwei
unterschiedlichen Wörtern gesucht nach den Wörtern Strang und Test.
TestString = "In diesem Text-String wird nach zwei unterschiedlichen
Wörtern gesucht"
PresentString = "Test"
AbsentString = "Strang"
Wscript.Echo InStr(PresentString, TestString)
Wscript.Echo InStr(AbsentString, TestString)
Wenn Sie das Script ausführen, werden die Werte 11 und 0 zurückgegeben. Der Wert 11
zeigt, dass das Wort Test an Zeichenposition Elf gefunden wurde, und der Wert 0 zeigt, dass
das Wort Strang gar nicht gefunden wird.

Groß- und Kleinbuchstaben


Die Kontrolle über die Schrifteigenschaften ist nicht gerade die starke Seite von VBScript.
Egal, ob Sie etwas in einer Eingabeaufforderung oder in einem Nachrichtenfenster ausgeben -
über Eigenschaften wie Schriftart, -größe und -farbe haben Sie keine Kontrolle. Das Einzige,
was Sie verändern können, ist die Groß- und Kleinschreibung.
Mit Großbuchstaben können Sie wichtige Informationen betonen. Die folgende hypothetische
Ausgabe ist zum Beispiel besser zu lesen, wenn der fehlerhafte Server schnell zu erkennen ist:
Server Status
atl-dc-01 Healthy
atl-dc-02 Healthy
ATL-DC-03 ERROR
atl-dc-04 Healthy
Auch für Eingaben kann die Kontrolle über die Groß- und Kleinschreibung ganz nützlich
sein. Wenn Sie zum Beispiel sicherstellen möchten, dass der Benutzer ein Landeskürzel (DE,
GB, USA) in Großbuchstaben eingibt, dann können Sie die den eingegebenen String einfach
in Großbuchstaben umwandeln - so spielt es keine Rolle, was der Benutzer eingegeben hat.

Tabelle 2.15: Funktionen zur Umwandlung in Groß- oder Kleinbuchstaben


FunktionBeschreibung

Seite 68 von 394


FunktionBeschreibung
LCase Konvertiert alle alphabetischen Zeichen in Kleinbuchstaben.

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)

Arbeiten mit Zahlen


Vieles im Bereich der Systemadministration hat mit Zahlen zu tun: Über wie viel Speicher
verfügt ein Computer? Wie viele fehlgeschlagene Anmeldeversuche gab es? Wie viel
Prozessorzeit wird auf einem Domänencontroller verbraucht?
Solche Informationen können über Scripte sehr einfach ermittelt werden. Die Fragen oben
können Sie zum Beispiel alle über WMI beantworten. Leider werden Informationen nicht
immer im gewünschten Format zurückgegeben. Der freue Plattenplatz wird zum Beispiel in
Byte zurückgeliefert - bei einer Festplatte mit ca. 10 GB freiem Speicherplatz erhalten Sie so
den Wert 10,842,824,704 Byte zurück. Die Prozessorauslastung wird in 100 Nanosekunden-
Schritten angegeben. Die Maximalhöhe und -breite des von einem Drucker unterstützten
Papiers wird in Zehntelmillimeter zurückgegeben.
Glücklicherweise bietet VBScript Ihnen einige Funktionen zur Verarbeitung von Zahlen.

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

Formatierung von Zahlen


Sich selbst überlassen formatiert VBScript Zahlen immer gleich. Erinnern wir uns an eines
der ersten Scripte dieses Kapitels: es gab den freien Plattenplatz für ein Laufwerk zurück. Der
zurückgegebene Wert war 10842824704. Er war ziemlich schwer zu lesen - besser wäre eine
Ausgabe wie 10.842.824.704 gewesen.
Eine Berechnung weiter oben in diesem Kapitel gab zum Beispiel den Wert
10340,4458007813 zurück. Wenn überhaupt, dann werden Sie eine so genaue Kommazahl
nur ganz selten benötigen. Es wäre besser, wenn der Wert als 10.340 oder 10.340,45
zurückgegeben würde. Diese Ausgaben sind nicht nur besser zu lesen, sie benötigen auch
weniger Anzeigeplatz. Das könnte zum Beispiel wichtig werden, wenn Sie Ausgaben in
Tabellenform durchführen möchten.
Mit der Funktion FormatNumber können Sie definieren, wie Zahlen ausgegeben werden. Sie
erwartet als Parameter die zu formatierende Zahl und eine oder alle Parameter aus Tabelle
2.16. Die folgende Codezeile gibt die Zahl 37,874 zum Beispiel ohne Nachkommastellen aus
- es wird als nur 37 angezeigt:
Wscript.Echo FormatNumber(37.874, 0)
Tabelle 2.16: Paramter von FormatNumber

Seite 70 von 394


Parameter Beschreibung
Zahl der Die Funktion FormatNumber löscht nicht angezeigte Nachkommastellen
Nachkomma- nicht einfach. Stattdessen werden sie auf- oder abgerundet. Wenn Sie die
stellen. Zahl 11,6 zum Beispiel ohne Nachkommastellen anzeigen lassen, dann wird
die Zahl 12 angezeigt. Im Gegensatz dazu ergäbe 19,2 die Zahl 19.

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:

-1 - True. Mit führender 0.

0 - False. Ohne führende 0

-2 - Einstellungen aus Regional- und Spracheinstellungen verwenden.


Negative Zahlen Mögliche Werte:
in Klammern.
-1 - True. Negative Zahlen in Klammern.

0 - False. Keine Klammern.

-2 - Einstellungen aus Regional- und Spracheinstellungen verwenden.


Tausender- Mögliche Werte:
Trennzeichen.
-1 - True. Mit Tausender-Trennzeichen.

0 - False. Ohne Tausender-Trennzeichen

-2 - Einstellungen aus Regional- und Spracheinstellungen verwenden.


Damit Ihr Script einfacher zu lesen und zu pflegen sein wird, können Sie statt der in der
Tabelle gezeigten Werte auch Konstanten verwenden. In der folgenden Scriptzeile ist zum
Beispiel nicht unbedingt sofort klar, wofür die 0 steht:
Wscript.Echo FormatNumber(37.874, 0)
Mit einer Konstante ist das Script viel einfacher zu lesen:
Const NoDecimalPlaces = 0
Wscript.Echo FormatNumber(37.874, NoDecimalPlaces)
Alle Formatierungsparameter sind optional. Sie können durchaus alle Parameter ignorieren
und nur das Tausender-Trennzeichen verwenden. Dieser Parameter muss allerdings immer der
fünfte Parameter sein (nach den Nachkommastellen und den drei anderen optionalen
Parametern). Wenn Sie nur einzelne Parameter verwenden möchten, dann haben Sie die
folgenden Möglichkeiten:

Verwenden Sie "leere" Parameter (schreiben Sie für die Parameter, die Sie nicht verwenden
möchten, also nur ein Komma ohne Wert).

Verwenden Sie für die nicht verwendeten Parameter den Standardwert. Setzen Sie diese

Seite 71 von 394


hierzu einfach auf False (Falsch).
Im folgenden Script werden zum Beispiel Konstanten mit den entsprechenden Werten
verwendet:
Const Decimals = 3
Const LeadingZero = True
Const UseParentheses = True
Const Default = False
NumberToFormat = 1 / -7
Wscript.Echo NumberToFormat
Wscript.Echo FormatNumber(NumberToFormat, Decimals)
Wscript.Echo FormatNumber(NumberToFormat, Default, LeadingZero)
Wscript.Echo FormatNumber(NumberToFormat, Default, Default, UseParentheses)
Wenn Sie das Script unter CScript ausführen, erhalten Sie folgende Ausgabe:
-0,142857142857143
-0,143
-0,14
(0,14)
Einen alternativen Weg sehen Sie im folgenden Script. Es formatiert das Ergebnis der
Multiplikation von 33 mit 454:
Const GroupDigits = True
Const Default = False
Const NoDecimals = 0
NumberToFormat = 33 * 454
Wscript.Echo NumberToFormat
Wscript.Echo FormatNumber(NumberToFormat, Default, Default, Default,
GroupDigits)
Wscript.Echo FormatNumber _
(NumberToFormat, NoDecimals , Default, Default, GroupDigits)
Wenn Sie dieses Script unter CScript ausführen, dann erhalten Sie folgende Ausgabe:
14982
14,982.00
14,982

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

Seite 72 von 394



Negative Werte in Klammern

Tausender-Trennzeichen (6.500.000% statt 6500000%)
Die Syntax der Funktion FormatPercent ist identisch mit der Funktion FormatNumber:
Das folgende Script dividiert 1 durch 7 und gibt das Ergebnis aus. Es verwendet
FormatPercent, um die Ausgabe als Prozentwert ohne Nachkommastellen zu formatieren.
Const NoDecimals = 0
NumberToFormat = 1 / 7
Wscript.Echo NumberToFormat
Wscript.Echo FormatPercent(NumberToFormat, NoDecimals)
Wenn Sie das Script unter CScript ausführen, dann erhalten
Sie folgende Ausgabe:
0,142857142857143
14%

Befehle mehrfach ausführen


Ein Grund dafür, dass die Systemadministration so schwierig und zeitaufwändig ist, liegt
darin, dass IT-Umgebungen dynamisch sind. Das bedeutet, dass Systemadministratoren
dieselben Aufgaben wieder und wieder ausführen müssen. Wenn ein Computer heute über
ausreichend freien Festplattenplatz verfügt, dann muss das morgen oder nächsten Monat nicht
ebenfalls so sein.
Zum Glück wird Scripten nie langweilig. Sie werden auch nie müde oder machen Fehler,
wenn sie eine Aufgabe ständig wiederholen müssen. Ein Script wird so zum perfekten
Instrument, um sich ständig wiederholende Aufgaben auszuführen. Hierzu steht Ihnen unter
VBScript die Do-Loop-Schleife zur Verfügung.

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

Seite 73 von 394


Wscript.Echo strNextLine
Loop
Wenn das Script ausgeführt wird, wird die Schleifenbedingung bei jedem Durchlauf geprüft.
Wenn die Bedingung wahr (True) ist - wenn also das Dateiende erreicht ist - dann wird die
Schleife nicht mehr weiter ausgeführt.
Im Gegensatz dazu wird eine Do-While-Schleife so lange ausgeführt, wie die Bedingung
nicht zutrifft (also falsch ist - False). Das folgende Script verwendet hierzu die Syntax:
Do While Not objTextFile.AtEndOfStream
Diese Scriptzeile könnte übersetzt lauten "Führe die Schleife so lange aus, wie das Ende der
Textdatei nicht erreicht ist".
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
("c:\test.txt", ForReading)
Do While Not objTextFile.AtEndOfStream
strNextLine = objTextFile.Readline
Wscript.Echo strNextLine
Loop
Endlosschleifen
Vielleicht haben Sie es sich schon gedacht: Es ist möglich Endlosschleifen zu erstellen - diese
werden nie beendet (wenn die Bedingung niemals zutrifft, dann wird die Schleife unendlich
ausgeführt). Meist handelt es sich bei solchen Schleifen um einen Fehler des Scripterstellers.
Es könnte jedoch auch sein, dass Sie zum Beispiel ein Script benötigen, das Sie bei jedem
Fehler im Ereignisprotokoll benachrichtigt. Sie möchten nicht, dass das Script nach dem
ersten Fehler beendet wird; stattdessen möchten Sie, dass es in einer Endlosschleife auf
weitere Fehler wartet.
Um ein Script mit einer solchen Schleife zu erstellen, verwenden Sie einfach eine Bedingung,
die niemals zutreffen kann. Das folgende Script macht dies, indem es die Schleife so lange
ausführt, bis die Variable LoopVariable den Wert 0 hat. Da das Script jedoch nie etwas an
dem Wert von LoopVariable ändert, wird diese Bedingung niemals zutreffen.
LoopVariable = 1
Do Until LoopVariable = 0
FreeMegaBytes = objLogicalDisk.FreeSpace / CONVERSION_FACTOR
If FreeMegaBytes &#60; WARNING_THRESHOLD Then
Wscript.Echo Computer & " " & objLogicalDisk.DeviceID & _
" is low on disk space."
End If
Loop
Dieses Script müssen Sie bei Bedarf dann natürlich auch manuell beenden.

Prüfen der Schleifenbedingung


Die Schleifenbedingung können Sie unter VBScript an zwei Stellen der Schleife prüfen:
Entweder bevor die Schleife ausgeführt wird, oder nachdem die Schleife ausgeführt wurde.
Dies kann durchaus ein Unterschied sein. Wenn Sie möchten, dass die Schleife nur dann
ausgeführt wird, wenn die Bedingung zutrifft, dann prüfen Sie die Bedingung vor der
Schleifenausführung. Wenn Sie sicherstellen möchten, dass die Schleife mindestens einmal
ausgeführt wird (egal, ob die Bedingung zutrifft oder nicht), dann prüfen Sie die Bedingung
am Ende der Schleife.

Seite 74 von 394


Das folgende Script verdeutlicht den Unterschied zwischen den beiden Varianten. Nachdem
Die Variable LoopVariable auf den Wert 1 gesetzt wurde, verwendet das Script zwei
Schleifen. In der ersten Schleife wird die Bedingung vor dem Schleifendurchlauf geprüft. Die
Syntax hierzu lautet:
Do Until LoopVariable = 1
Die zweite Schleife prüft die Bedingung erst nach dem Schleifendurchlauf. Die entsprechende
Syntax lautet:
Loop Until LoopVariable = 1
Das Script selbst sieht so aus:
LoopVariable = 1
Do Until LoopVariable = 1
Wscript.Echo "Script ist in Schleife 1."
Loop
Do
Wscript.Echo "Script ist in Schleife 2."
Loop Until LoopVariable = 1
Wenn Sie das Script ausführen, dann erhalten Sie folgende Ausgabe:
Script ist in Schleife 2
Wie Sie sehen können, wird Schleife 2 einmal ausgeführt. Schleife 1 wird gar nicht
ausgeführt.
Woher kommt dieser Unterschied? In der ersten Schleife ist die Bedingung (wenn die
Variable LoopVariable gleich 1 ist) vor der Ausführung der Schleife getestet. Da
LoopVariable den Wert 1 hat, wird die Do-Loop-Schleife sofort beendet. Sie wird also nicht
einmal ausgeführt.
In der zweiten Schleife wird die Bedingung erst dann getestet, wenn die Schleife ausgeführt
wurde. Der genaue Ablauf sieht also so aus:
1.Die Schleife beginnt mit dem Befehl Do Loop
2.In der Schleife wird der Text 'Script ist in Schleife2' ausgegeben
3.Am Ende der Schleife wird die Bedingung geprüft (ist die Variable LoopVariable gleich
1?). Das ist wahr. Daher wird die Schleife beendet, nachdem sie einmal ausgeführt wurde.
Mit dem Befehl Loop Until wird jede Schleife als mindestens einmal ausgeführt. Wenn Sie
dies nicht möchten, dann verwenden Sie den Befehl Do Until.

Eine Schleife verlassen


VBScript arbeitet standardmäßig jede Zeile Code innerhalb einer Do-Loop-Schleife
nacheinander ab. In den meisten Fällen ist das auch genau das, was Sie möchten. Es mag
jedoch auch Ausnahmen geben, in denen Sie eine Schleife sofort verlassen möchten - und
zwar ohne den restlichen Code in der Schleife abzuarbeiten. Dies können Sie mit dem Befehl
Exit Do erreichen. Er sorgt dafür, dass diese Schleife sofort beendet wird.
Das folgende Script erzeugt einen Fehler (5 geteilt durch 0). Die Schleifenbedingung sagt:
"Führe die Schleife aus, bis ein Fehler auftritt" (Err 0). Sie könnten also annehmen, dass die
Schleife bei dem Versuch 5 durch 0 zu teilen beendet wird (das wäre ja ein Fehler).
On Error Resume Next
Do Until Err &#60;&#62; 0

Seite 75 von 394


X = 5/0
Wscript.Echo " Das Ergebnis ist " & X & "."
Loop
Wenn Sie das Script ausführen, dann erhalten Sie jedoch die folgende Ausgabe:

Abbildung 2.17: Fehlerhaftes Nachrichtenfenster


Warum ist das so? Wenn das Script den Fehler durch die Division durch 0 feststellt, dann
wird die Schleife nicht verlassen - obwohl dies in der Bedingung so angegeben ist. Stattdessen
werden die verbleibenden Befehle der Schleife weiter abgearbeitet. Das liegt daran, dass die
Schleifenbedingung nur einmal pro Durchlauf geprüft wird (am Anfang). So wird nach dem
Fehler noch die Ausgabe durchgeführt (X enthält den Wert Null). Erst dann wird vor dem
nächsten Vorlauf die Schleifenbedingung erneut geprüft und die Schleife beendet.
Wenn Sie eine Schleife vor der Beendigung eines Durchlaufes verlassen müssen, dann
verwenden Sie den Befehl Exit Do. Im folgenden Script wird die Fehlerbedingung innerhalb
der Schleife getestet. Wenn ein Fehler aufgetreten ist, dann wird eine Fehlermeldung
ausgegeben, und die Schleife wird über den Befehl Exit Do sofort beendet.
On Error Resume Next
Do Until Err &#60;&#62; 0
X = 5/0
If Err &#60;&#62; 0 Then
Wscript.Echo "Es ist ein Fehler aufgetreten."
Exit Do
End If
Wscript.Echo " Das Ergebnis ist " & X & "."
Loop
Wenn Sie dieses Script ausführen, dann erhalten Sie die folgende Anzeige:

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

Seite 76 von 394


und dann beendet wird. Das Ausführen jeder Zeile des Scripts kann jedoch aus zu
Komplikationen führen. Was passiert, wenn es Zeilen gibt, die Sie nicht ausführen wollen?
Nehmen wir einmal ein, Sie haben ein Script geschrieben, dass eine bestimmte Gruppe von
Dateien auf einen Remotecomputer sichert und die Originaldateien dann löscht. Solange keine
Probleme auftauchen, möchten Sie auch, dass jede Zeile des Scripts ganz normal ausgeführt
wird. Was ist aber, wenn der Remotecomputer nicht erreichbar ist? In diesem Fall versucht
das Script die Dateien auf den Remotecomputer zu sichern. Dies schlägt dann natürlich fehl.
Dann löscht das Script die Originaldateien. Problem erkannt?
In einem Fall wie diesem wünschen Sie sich sicherlich ein Script, das eine bestimmte
Bedingung überprüfen kann ("Ist der Remotecomputer erreichbar?") und nur weiterarbeitet,
wenn diese Bedingung wahr ist. Eine solche Entscheidung können Sie über die Befehle If
Then oder Select Case implementieren.

Mehrere Bedingungen prüfen


Die Scripte, die in der ersten Hälfte dieses Kapitels verwendet wurde, trafen ihre
Entscheidungen auf Basis einer einzelnen Bedingung. Wenn zum Beispiel die Menge an
freiem Speicherplatz unter einen bestimmten Wert gefallen ist, dann wird ein Alarm
ausgelöst:
If FreeMegaBytes &#60; WARNING_THRESHOLD Then
Wscript.Echo objLogicalDisk.DeviceID & " is low on disk space."
End If
Es könnte jedoch vorkommen, dass Sie eine bestimmte Aktion nur dann durchführen
möchten, wenn zwei oder mehr Bedingungen zutreffen. Eine sofortige Alarmmeldung
benötigen Sie zum Beispiel nur für die Mailserver. Bei allen anderen Servern möchten Sie
nicht sofort benachrichtigt werden. Stattdessen soll zum Beispiel nur ein Protokolleintrag
erzeugt werden.
Der Alarm soll also nur dann angezeigt werden, wenn zwei Bedingungen wahr sind: der freie
Plattenplatz liegt unter einer bestimmten Grenze und der Server ist ein Mailserver. Eine
solche Entscheidung können Sie über den logischen Operator And (Und) implementieren.
Im folgenden Script wird die Alarmmeldung nur in diesem Fall angezeigt. Wenn eine der
beiden Bedingungen nicht wahr ist, dann wird kein Alarm angezeigt.
If FreeMegaBytes &#60; WARNING_THRESHOLD And ServerType = "Email" Then
Wscript.Echo objLogicalDisk.DeviceID & " is low on disk space."
End If
In anderen Fällen kann es zum Beispiel wichtig sein, eine Aktion durchzuführen, wenn eine
oder einige der Bedingungen wahr sind. Zum Beispiel, wenn Sie eine Meldung anzeigen
möchten, wenn der freie Speicherplatz unter einer bestimmten Grenze liegt, oder wenn der
verfügbare Arbeitsspeicher unter eine bestimmten Grenze liegt. In Tabelle 2.17 sehen Sie alle
möglichen Zustände und Entscheidungen für ein solches Script

Tabelle 2.17: Entscheidungsmatrix


Ausreichend SpeicherplatzAusreichen ArbeitsspeicherAlarmmeldung
Ja Ja Nein
Ja Nein Ja

Nein Ja Ja

Seite 77 von 394


Ausreichend SpeicherplatzAusreichen ArbeitsspeicherAlarmmeldung
Nein Nein Ja
Solche Entscheidungen können Sie mit dem logischen Operator Or (Oder) implementieren:
If FreeMegaBytes &#60; WARNING_THRESHOLD Or AvailableMemory &#60;
MEMORY_THRESHOLD Then
Wscript.Echo "Computer is low on disk space or memory."
End If
Der logische Operator Or (Oder) gibt Wahr zurück, wenn irgendeine der Bedingungen wahr
ist (oder wenn alle wahr sind).

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 &#60;= 100 Then
Wscript.Echo Computer.Name & " benötigt sofortige Aufmerksamkeit."
ElseIf FreeMegabytes &#60; 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."

Seite 78 von 394


End If
Wenn Sie mehrere Bedingungen implementieren, dann prüft If-Then-Else alle Bedingungen,
bis eine Bedingung gefunden wird, die wahr ist. In diesem Fall werden die Befehle hinter
dieser Bedingung ausgeführt und keine weiteren Bedingungen mehr geprüft. Das bedeutet
natürlich, dass Sie die Bedingungen sehr gewissenhaft anordnen müssen.
Sehen wir uns zum Beispiel einmal das folgende Script an:
x = 5
If x &#60; 20 Then
Wscript.Echo "X ist zwischen 11 und 20."
ElseIf x &#60; 11 Then
Wscript.Echo " X ist zwischen 0 und 10."
Else
Wscript.Echo "X ist gleich 0."
End If
Die Ausgabe des Scripts sehen Sie in Abbildung 2.19

Abbildung 2.19: Falsche Anordnung von Bedingungen


Woher kommt dieses falsche Ergebnis? Die erste Bedingung prüft, ob X kleiner als 20 ist. Da
dies immer wahr ist, wird natürlich auch immer die Nachricht 'X ist zwischen 11 und 20"
ausgegeben. Nachdem die erste Bedingung wahr ist, werden keine weiteren Bedingungen
geprüft.
Damit das Script korrekt arbeitet, müssen Sie die Bedingungen neu anordnen:
x = 5
If x = 0 Then
Wscript.Echo "X ist gleich 0."
ElseIf x &#60; 11 Then
Wscript.Echo " X ist zwischen 0 und 10."
Else
Wscript.Echo " X ist zwischen 11 und 20."
End If
Einen Else-Befehl im Ende zu verwenden ist immer eine gute Idee. So können Sie auch die
Fälle abfangen, in denen keine der ElseIf-Bedingungen zutrifft. Sehen Sie sich zum Beispiel
das folgende Script an:
If JobID = 1 Then
Wscript.Echo "Dieser Benutzer ist ein Manager."
ElseIf JobID = 2 Then
Wscript.Echo " Dieser Benutzer ist kein Manager."
End If
Es funktioniert sehr gut, solange jedem Benutzer eine JobID von 1 oder 2 zugewiesen wurde.
Was passiert aber, wenn die JobID eines Benutzers 3 ist (oder wenn der Benutzer keine JobID
hat)? Diesen Fall können Sie über einen abschließenden Else-Befehl abfangen:
If JobID = 1 Then
Wscript.Echo "Dieser Benutzer ist ein Manager."
ElseIf JobID = 2 Then
Wscript.Echo " Dieser Benutzer ist kein Manager."

Seite 79 von 394


End If
Wscript.Echo "Diesem Benutzer wurde keine gültige Job-ID zugewiesen."
End If

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

Seite 80 von 394


Case 2

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.

Anmerkung: Eine vollständige Besprechung zu Arrays - insbesondere die Verwendung von


mehrdimensionalen Arrays - liegt außerhalb des Themenbereichs dieses Kapitels. Das Kapitel
konzentriert sich auf die Verwendung von Arrays in administrativen Scripten.

Erstellen von Arrays


Der einfachste Weg ein Array zu erstellen, ist die Funktion Array. Auch wenn das wirklich
ganz einfach ist, sollten Sie zwei Dinge bei der Verwendung der Array-Funktion bedenken.
Erstens können mit der Array-Funktion nur eindimensionale Arrays erstellt werden. Und
zweitens müssen Sie bei dieser Funktion alle Elemente des Arrays bereits im Voraus kennen.
Bei administrativen Aufgaben ist das normalerweise nicht der Fall - meist schreiben Sie ein
Script, um genau diese Elemente (zum Beispiel die Dienste oder die Computer in einer OU)
abzurufen.
Wenn Sie die Elemente des Arrays bereits kennen, dann ist die Funktion Array natürlich
trotzdem sehr nützlich. Ein Script in der ersten Hälfte dieses Kapitels sollte zum Beispiel auf
drei Computern ausgeführt werden. Mit der Funktion Array können Sie die Namen dieser drei
Computer in ein Array schreiben:
Computers = Array("atl-dc-01", "atl-dc-02", "atl-dc-03")
Ein Array deklarieren und füllen
Normalerweise kennen Sie die zu speichernden Elemente vorher nicht. Das Script könnte die
Computernamen zu Beispiel aus einer Textdatei einlesen oder die in einem Ordner
enthaltenen Dateinamen in einem Array speichern. In einem solchen Fall kennen Sie die
Elemente und deren Anzahl erst dann, wenn das Script ausgeführt wird.
Unter VBScript haben Sie die Möglichkeit, eine Variable als Array zu definieren. Diese
Variable müssen Sie nicht sofort mit Elementen füllen. Hierzu legen Sie mit dem Befehl Dim
die Variable und die maximale Anzahl der in ihr gespeicherten Elemente fest.
Das erste Element eines Arrays wird immer durch die Indexnummer 0 bezeichnet - nicht
durch 1. Die Indexnummer des letzten Elementes eines Arrays entspricht der Maximalzahl an
Elementen minus 1. Wenn Ihr Array also 9 Elemente aufnehmen soll, dann müssen Sie es
über den Dim-Befehl mit der Größe 8 definieren (9 - 1).

Seite 81 von 394


Das folgende Beispiel erstellt einen Array mit dem Namen arrTestArray und der Größe 4 (4 -
1 = 3):
Dim arrTestArray(3)
Nachdem Sie einen Array deklariert haben, können Sie ihn mit den gewünschten Werten
auffüllen. Die nächste Codezeile weist Element 0 des Arrays (das erste Element) zum Beispiel
den Wert "A" zu:
arrTestArray(0) = "A"
Dieses einfache Script erstellt einen Array mit dem Namen arrTestArray und weist den vier
Elementen des Arrays Werte zu:
Dim arrTestArray(3)
arrTestArray(0) = "A"
arrTestArray(1) = "B"
arrTestArray(2) = "C"
arrTestArray(3) = "D"
So weit so gut. Was passiert aber, wenn Sie den Array ursprünglich zu klein deklariert haben?
Was, wenn arrTestArray fünf Werte aufnehmen soll? Wenn Sie einfach versuchen dem
fünften Elemente einen Wert zuzuweisen, dann werden Sie einen Fehler produzieren. Das
folgende Beispielscript versucht einem Array mit vier Elementen einen fünften Wert
zuzuweisen:
Dim arrTestArray(3)
arrTestArray(0) = "A"
arrTestArray(1) = "B"
arrTestArray(2) = "C"
arrTestArray(3) = "D"
arrTestArray(4) = "E"
Wie Sie sehen, erzeugt das Script den Fehler "Index außerhalb des gültigen Bereichs:
,(number: 4)' wenn Sie versuchen es auszuführen.
In einer solchen Situation haben Sie zwei Möglichkeiten:

Sie können den Array schon im Voraus größer machen. Sie deklarieren arrTestArray einfach
mit 1.000 Elementen statt mit 4 Elementen. Das wäre allerdings in vielen Fällen eine
sinnlose Speicherverschwendung, da Sie viele der Elemente ja gar nicht verwenden.

Sie erstellen einen dynamischen Array.

Dynamische Arrays erstellen


Ein dynamisches Array bietet Ihnen zwei Vorteile:

Sie müssen die Maximalgröße des Arrays nicht im Voraus festlegen.

Die Größe des Arrays kann während der Ausführung des Scripts verändert werden.
Wenn Sie zum Beispiel die Computernamen aus einer Textdatei einlesen, und das Array ist zu
klein, dann können Sie das Array für jeden weiteren Computernamen einfach vergrößern -
und zwar so lange, bis alle Computernamen gelesen und gespeichert wurden. Um ein
dynamisches Array zu erstellen, müssen Sie zwei Dinge tun: Erstens dürfen Sie bei der
Deklaration des Arrays keine Größe angeben. Stattdessen schreiben Sie einfach zwei
Klammern:
Dim arrTestArray()

Seite 82 von 394


Und zweitens müssen Sie den Befehl ReDim Preserve verwenden, um das Array zu
vergrößern. Dieser Befehl erfüllt zwei Aufgaben:

Der Teil ReDim sorgt für die Vergrößerung des Arrays.

Der Teil Preserve stellt sicher, dass die vorhandenen Inhalte des Arrays bei diesem Vorgang
nicht gelöscht werden. Wenn Sie nur den Befehl ReDim verwenden, dann werden alle Array-
Inhalte bei der Vergrößerung gelöscht.
Das folgende Script erstellt ein dynamisches Array mit dem Namen arrTestArray. Danach
wird eine Variable mit dem Namen intSize erstellt. Dieser wird der Wert 0 zugewiesen. Mit
der Variable wird dann das Array so neudimensioniert, dass es ein Element aufnehmen kann
(1 - 1 = 0).
Nachdem dem ersten Element (Index 0) ein Wert zugewiesen wurde, wird der Befehl ReDim
Preserve verwendet, um das Array so zu vergrößern, dass es zwei Elemente aufnehmen kann
(intSize + 1). Dem zweiten Element wird dann ebenfalls ein Wert zugewiesen:
Dim arrTestArray()
intSize = 0
ReDim Preserve arrTestArray(intSize)
arrTestArray(intSize) = "A"
ReDim Preserve arrTestArray(intSize + 1)
arrTestArray(intSize + 1) = "B"
Um zu zeigen, wie der Befehl ReDim Preserve in einem echten Script zur
Systemadministration verwendet werden kann, fragt das folgende Scripte eine Liste aller auf
dem Computer installierten Dienste ab. Es speichert die Dienstnamen in einem dynamischen
Array. Hierzu geht es folgendermaßen vor:
1.Es erstellt ein dynamisches Array mit dem Namen arrTestArray.
2.Es erstellt eine Variable mit dem Namen intSize und weist dieser den Wert 0 zu.
3.Es verbindet sich mit dem WMI-Dienst und fragt eine Liste der installierten Dienste ab.
4.Für jeden Dienst in der erhaltenen Collection führt es folgendes aus:
1.Es verwendet den Befehl ReDim Preserve, um die Größe von arrTestArray auf den Wert in
der Variable intSize anzupassen. Beim ersten Dienst der Collection hat intSize den Wert 0.
Das Array hat daher auch die Größe 0 - was bedeutet, dass ein Element in ihm gespeichert
werden kann.
2.Es weist dem gerade erstellen Array-Element den Dienstnamen zu
(objService.DisplayName).
3.Es erhöht den Wert von intSize um eins. Nach dem ersten Element hat intSize zum Beispiel
den Wert 1 (den bisherigen Wert plus 1).
4.Es wiederholt diese Schritte für die verbleibenden Dienste aus der Collection.
Dim arrTestArray()
intSize = 0

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colRunningServices = objWMIService.ExecQuery _
("SELECT * FROM Win32_Service")

Seite 83 von 394


For Each objService in colRunningServices
ReDim Preserve arrTestArray(intSize)
arrTestArray(intSize) = objService.DisplayName
intSize = intSize + 1
Next

Einen String mit Trennzeichen in ein Array konvertieren


Um administrative Daten für eine Vielzahl von Anwendungen (inklusive Scripte) lesbar zu
machen, werden diese Daten oft durch bestimmte Zeichen getrennt in Textdateien
gespeichert. Das Trennzeichen ist in diesem Fall einfach das Zeichen, dass die einzelnen in
der Textdatei gespeicherten Informationen voneinander trennt - typischer Weise ist dieses
Zeichen ein Komma. Solche Dateien werden auch oft als CSV-Dateien (Comma Separated
Values) bezeichnet.
Eine Protokolldatei, in der die Namen von Servern, die Namen der Ereignisprotokolle auf
diesen Servern und in diesen Protokollen aufgetretenen Fehlernummern gespeichert werden,
könnte zum Beispiel so aussehen:
atl-dc-01,DNS Server,13
atl-dc-01,System,14
atl-dc-02,Security,3
alt-dc-02,Application,22
Ein Vorteil von solchen Dateien ist, dass sie in viele andere Anwendungen importiert werden
können. Microsoft Excel und Microsoft Access würden das Beispiel oben so interpretieren:

Tabelle 2.18: Importierte Beispieldaten


Feld 1 Feld 2 Feld 3
atl-dc-01DNS Server13
atl-dc-01System 4
atl-dc-02Security 3
atl-dc-02Application 22
Einen durch Trennzeichen aufgeteilten String können Sie mit der Funktion Split in ein Array
umwandeln. Hierzu müssen Sie der Funktion zwei Parameter übergeben:

Den String mit den Werten und den Trennzeichen

Das Trennzeichen
Im folgenden Script ist der zu trennende Text in der Variable TestString gespeichert. Als
Trennzeichen wird das Komma verwendet:
TestString = " atl-dc-01,DNS Server,13"
TestArray = Split(TestString , ",")
For i = LBound(TestArray) to UBound(TestArray)
Wscript.Echo TestArray(i)
Next
Wenn Sie das Script unter CScript ausführen, dann erhalten Sie die folgende Ausgabe:
atl-dc-01
DNS Server
13

Seite 84 von 394


Alternativen zur Verwendung von Arrays
Arrays sind ein schneller und einfacher Weg, um eindimensionale Daten zu speichern. Wenn
Sie es jedoch mit multidimensionalen Daten zu tun haben, dann kann es schnell kompliziert
werden. Bevor Sie also multidimensionale Arrays verwenden, sollten Sie über die folgenden
Alternativen nachdenken:

Dictionary-Objekt: Das Dictionary-Objekt ist Teil der Script-Laufzeitbibliothek und bietet
Ihnen eine einfache Möglichkeit arrayähnliche Daten zu speichern, abzufragen und zu
verändern. Weitere Informationen zum Dictionary-Objekt finden Sie im Kapitel Script-
Laufzeitbibliothek in diesem Buch

Disconnected Recordset: Ein "Disconnected Recordset" ist eine temporäre Datenbank, die
nicht mit einer tatsächlichen physikalischen Datenbank verbunden ist. Stattdessen wird sie
im Speicher erstellt und nach Beendigung des Scripts gelöscht. Wie beim Dictionary-Objekt
auch, können Sie beim Recordset mit einem Namen oder einer Indexnummer auf die
Elemente zugreifen. Außerdem haben Sie die gleichen Möglichkeiten, wie mit einem
normalen Recordset (inklusive Sortieren). Das folgende Codebeispiel sortiert zum Beispiel
ein eindimensionales Array:

For i = LBound(SampleArray) to UBound(SampleArray)


For j = LBound(SampleArray) to UBound(SampleArray)
If j = UBound(SampleArray) Then
Else
If SampleArray(j) &#62; SampleArray(j + 1) Then
TempValue = SampleArray(j + 1)
SampleArray(j + 1) = SampleArray(j)
SampleArray(j) = TempValue
End If
End If
Next
Next

Eein Recordset kann im Gegensatz dazu mit der folgenden einzelnen Codezeile sortiert
werden:

DisconnectedRecordset.Sort = 'FileSize'

Weitere Informationen zu solchen Recordsets finden Sie im Kapitel Creating Enterprise


Scripts in diesem Buch.

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:

Seite 85 von 394


Wscript.Echo "Line 1."
Wscript.Echo "Line 2."
W script.Echo "Line 3."
Das Nachrichtenfenster aus Abbildung 2.20 wird angezeigt.

Abbildung 2.20: Kompilierungsfehler


Im Gegensatz dazu zeigt das folgende Script erst zwei Nachrichtenfenster an, bevor es zu dem
Fehler kommt (der falsch geschriebene Befehl Wscript.Echo). Das liegt daran, dass Zeile 3 für
den Compiler korrekt aussieht. Er kann nicht feststellen, dass Eho keine gültige Methode des
Objektes Wscript ist. Daher zeigt er diese Zeile auch nicht als fehlerhaft an, und die
Scriptausführung wird gestartet:
Wscript.Echo "Line 1."
Wscript.Echo "Line 2."
Wscript.Eho "Line 3."
Wenn dann Zeile 3 des Scripts ausgeführt wird, wird die Fehlermeldung aus Abbildung 2.21
angezeigt. Achten Sie darauf, dass es sich hier um einen Laufzeitfehler statt um einen
Kompilierungsfehler handelt.

Abbildung 2.21: Laufzeitfehler


Laufzeitfehler kommen nicht nur durch falsch geschriebene Befehle zustande. Die nächste
Codezeile ist zum Beispiel syntaktisch und typografisch korrekt. Sie erzeugt einen
Laufzeitfehler, weil nicht auf den Remotecomputer zugegriffen werden kann:
Set Computer = GetObject("winmgmts:\\InaccessibleComputer")
Das bedeutet, dass wir über das Auftreten von Laufzeitfehlern nur wenig Kontrolle haben (das
Netzwerk kann fehlerhaft sein, ein Computer kann heruntergefahren worden sein usw.). Sie
haben unter VBScript drei Möglichkeiten, solche Fehler zu handhaben. Die Vor- und
Nachteile dieser drei Optionen sehen Sie in Tabelle 2.19.

Tabelle 2.19: Vorteile und Nachteile der Optionen zur Fehlerbehandlung


Option Vorteile Nachteile

Seite 86 von 394


Option Vorteile Nachteile
Fehlschlag Kein Aufwand für den Scriptersteller Wenn das Script an irgendeinem
des Scripts in erforderlich. Scripte schlagen fehl, wenn Punkt fehlschlägt, könnte dies dazu
Kauf nehmen ein Laufzeitfehler auftritt. führen, dass der Computer in einem
instabilen Zustand verbleibt.
In vielen Fällen ist es besser, dass ein
Script fehlschlägt, wenn es nicht korrekt Fehler müssen nicht fatal sein. Stellen
ausgeführt werden kann. Wenn Sie zum Sie sich zum Beispiel ein
Beispiel einem Script eine Sicherung von Überwachungsscript vor, das
bestimmten Dateien vornehmen lassen Informationen über 100 Computer
und das Script die Originaldateien danach abruft. Wenn Computer 1 nicht
löschen soll, dann ist es besser, dass das erreicht werden kann, ist es trotzdem
Script fehlschlägt, wenn die Dateien nicht sinnvoll, die Informationen der
gesichert wenn können. So werden restlichen 99 Computer abzufragen.
wenigstens nicht die Originaldateien
gelöscht.
Alle Fehler Scripte werden ohne Unterbrechung Probleme sind schwer zu finden, da
im Script weiter ausgeführt. Sie keine Fehlermeldung erhalten.
ignorieren
Scripte führen den Großteil ihrer Der Computer kann in einen
Aufgaben durch - auch wenn ein Problem unbekannten Zustand versetzt
auftritt. Ein Script könnte zum Beispiel 99 werden, da möglicherweise einige
von 100 Dateien erfolgreich kopieren. Aktionen ausgeführt werden und
andere nicht.
Endbenutzer erhalten keine
Fehlermeldungen, auf die sie reagieren
müssen.
Auf Fehler Sie haben die Möglichkeit, Erfordert zusätzliche Arbeit bei der
im Script mit aussagekräftige Fehlermeldungen Scripterstellung. Der Scriptautor
eigenem anzeigen zu lassen. muss wissen, welche Fehler auftreten
Code können. Dann muss er diese über
reagieren Sie können versuchen, das Problem über entsprechenden Scriptcode abfangen
den Scriptcode zu beheben. Wenn ein und handhaben.
Script zum Beispiel nicht in der Lage ist
eine Verbindung zu einem
Remotecomputer aufzubauen, dann kann
es beispielsweise nach einiger Zeit einen
neuen Verbindungsversuch starten.

Handhabung von Laufzeitfehlern


In den meisten Fällen bedeutet die Handhabung von Laufzeitfehlern einfach folgendes:
"Wenn ein Fehler auftritt, brich das Script nicht ab, sondern mache irgendetwas Anderes".
Typischerweise ist "irgendetwas Anderes" in eines der folgenden Dinge:

Sie können den Fehler ignorieren und einfach mit der nächsten Zeile des Scripts weiter
machen.

Sie können den Fehler abfangen und mit Scriptcode auf den Fehler reagieren (zum Beispiel
könnten Sie eine Fehlermeldung anzeigen).

Seite 87 von 394


Beide Methoden werden über den Befehl On Error Resume Next implementiert. Mit diesem
Befehl wird ein Script beim Auftreten eines Fehlers nicht einfach beendet. Stattdessen
ignoriert das Script die fehlerhafte Codezeile einfach und versucht die nächste Codezeile
auszuführen.

Alle Fehler ignorieren


Die bei weitem einfachste Form der Fehlerbehandlung ist das Ignorieren alle Fehler. Hierzu
schreiben Sie in die erste Zeile des Scripts einfach den Befehl On Error Resume Next. Das
folgende Beispielscript versucht die nicht existente WSH-Methode Wscript.X zu verwenden
und verursacht so einen Laufzeitfehler. Das Script wird trotzdem ohne Fehlermeldung
ausgeführt:
On Error Resume Next
Wscript.X "Testing 1-2-3."
Wscript.X "Testing 4-5-6"
Wscript.X "Testing 7-8-9"
Bedenken Sie, dass die Fehlerbehandlung erst mit dem Befehl On Error Resume Next beginnt.
Das folgende Script führt zu einem Laufzeitfehler, da der Befehl erst nach der ersten
fehlerhaften Scriptzeile verwendet wird:
Wscript.Echo "Line 1."
Wscript.Echo "Line 2."
Wscript.Eho "Line 3."
On Error Resume Next
Wscript.Echo "Line 4."
Um sicherzustellen, dass die Fehlerbehandlung korrekt funktioniert, sollten Sie den Befehl On
Error Resume Next direkt am Anfang des Scripts verwenden:
On Error Resume Next
Wscript.Echo "Line 1."
Wscript.Echo "Line 2."
Wscript.Eho "Line 3."
Wscript.Echo "Line 4."
Wenn Sie das vorhergehende Script unter CScript ausführen, dann erhalten Sie die folgende
Ausgabe:
Line 1.
Line 2.
Line 4.
Wenn der Laufzeitfehler in der Zeile mit dem Befehl "Wscript.Eho ." auftritt, dann wird
einfach die nächste Zeile des Scripts ausgeführt.

Auf Fehler reagieren


Statt Fehler in Ihrem Script zu ignorieren, könnten Sie Scriptcode schreiben, der auf diese
Fehler reagiert. Ein solcher Code kann zum Beispiel
1.prüfen, ob der Wert des Err-Objektes einen anderen Wert als 0 hat (solange kein
Laufzeitfehler auftritt, bleibt der Wert bei 0).
2.auf Fehler reagieren (zum Beispiel Err.Number und Err.Description anzeigen).
3.den Wert des Err-Objektes auf 0 zurücksetzen. Dies ist sehr wichtig, da es sonst nicht
möglich ist, einen weiteren Fehler zu erkennen.
Das folgende Script versucht als Erstes eine Verbindung mit dem WMI-Dienst herzustellen.
Wenn dieser Verbindungsversuch fehlschlägt (wenn also Err einen anderen Wert als 0 hat),
Seite 88 von 394
dann wird ein Nachrichtenfenster mit der Fehlernummer und der Fehlerbeschreibung
angezeigt. Danach wird das Err-Objektauf 0 zurückgesetzt.
Im nächsten Schritt versucht das Script eine Liste aller auf dem Computer installierten
Dienste abzurufen. Dies schlägt fehl, da die Methode ExecQuery falsch geschrieben ist
(ExcQuery). Das Script fragt erneut das Err-Objekt ab - wiederum wird ein
Nachrichtenfenster angezeigt, wenn sein Wert ungleich 0 ist. Danach wird das Err-Objekt auf
den Wert 0 zurückgesetzt.
On Error Resume Next
Set Computer = GetObject("winmgmts:")
If Err &#60;&#62; 0 Then
Wscript.Echo Err.Number & " -- " & Err.Description
Err.Clear
End If
Set ServiceList = Computer.ExcQuery("SELECT * FROM Win32_Service")
If Err &#60;&#62; 0 Then
Wscript.Echo Err.Number & " -- " & Err.Description
Err.Clear
End If
Wenn Sie das Script unter WScript ausführen, erhalten Sie die in Abbildung 2.22 zu sehende
Ausgabe.

Abbildung 2.22: WMI-Fehlermeldung

Aktivieren der Fehlerbehandlung


Manchmal möchten Sie sicher in einem Teil eines Scripts eine Fehlerbehandlung
implementieren und in einem anderen Teil nicht. Hierzu können Sie die Fehlerbehandlung an-
und abschalten:

Mit dem Befehl On Error Resume Next schalten Sie die Fehlerbehandlung an.

Mit dem Befehl On Error GoTo 0 schalten Sie die Fehlerbehandlung aus.
Das folgende Script implementiert die Fehlerbehandlung zum Beispiel gleich in der ersten
Zeile. In der zweiten Zeile tritt ein Fehler auf, da Wscript.Echo falsch geschrieben wurde -
aufgrund der Fehlerbehandlung wird das Script jedoch weiter ausgeführt. In Zeile 3 wird die
Fehlerbehandlung aus- und in Zeile 5 wieder angeschaltet. Da es jedoch dazwischen nicht zu
Fehlern kommt, wird das Script ohne Fehler ausgeführt:
On Error Resume Next
Wscript.Eco "A"
On Error GoTo 0
Wscript.Echo "B"
On Error Resume Next
Wscript.Eco "C"
Wscript.Echo "D"
Wenn Sie das Script unter Cscript ausführen, erhalten Sie die folgende Ausgabe:
B

Seite 89 von 394


D
Beim folgenden Script handelt es sich um eine leicht abgewandelte Version des vorherigen
Scripts. Es schlägt jedoch fehl, da während der abgeschalteten Fehlerbehandlung ein Fehler
auftritt:
On Error Resume Next
Wscript.Eco "A"
On Error GoTo 0
Wscript.Eco "B"
On Error Resume Next
Wscript.Eco "C"
Wscript.Echo "D"
Wenn Sie das Script unter Cscript ausführen, wird die folgende Fehlermeldung ausgegeben:
Microsoft (R) Windows Script Host, Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Alle Rechte vorbehalten.

C:\test.vbs(4, 1) Laufzeitfehler in Microsoft VBScript: Das Objekt


unterstützt diese Eigenschaft
oder Methode nicht.: 'Wscript.Eco'

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.

Abbildung 2.23: Fehlernummer und Fehlerbeschreibung eines COM-Objektes


Das Problem liegt darin, dass dieser Fehler innerhalb von WMI aufgetreten ist. VBScript
erfährt nur, dass ein Fehler aufgetreten ist. In einigen Scripten mag dies auch ausreichen - in
anderen Scripten oder bei der Entwicklung von Scripten wäre es jedoch deutlich praktischer
mehr Informationen über den Fehler zu erhalten.
Viele COM-Objekte stellen eigene Mechanismen zu Fehlerbehandlung bereit. WMI erlaubt es
Ihnen zum Beispiel das Fehlerobjekt SWbemLastError zu erstellen - über dieses erhalten Sie
die folgenden Informationen:

Seite 90 von 394



Die aufgerufene Methode.

Der Parameter, der für den Fehler verantwortlich ist.

Der Name des WMI-Providers, in dem der Fehler aufgetreten ist.
Das folgende Script verwendet das Objekt SWbemLastError, und zeigt die über das Objekt
abgefragten Informationen in einem Nachrichtenfenster an:
On Error Resume Next
Set Test = GetObject _
("Winmgmts:root\cimv2:Win32_Printer.Name='TestPrinter'")
Set WMI_Error = CreateObject("WbemScripting.SwbemLastError")
Wscript.Echo WMI_Error.Operation & VbTab & _
WMI_Error.ParameterInfo & VbTab & WMI_Error.ProviderName
Die Ausgabe des Scripts sehen Sie in Abbildung 2.24.

Abbildung 2.24: Informationen aus dem Objekt SWbemLastError


Wenn Sie SWbemLastError verwenden, dann dürfen Sie das Objekt erst nach der Codezeile
erstellen, von der Sie glauben, dass sie fehlerhaft ist. Das folgende Script gibt zum Beispiel
keine Fehlerinformationen zurück, da SWbemLastError vor dem Auftreten des Fehlers erstellt
wird:
On Error Resume Next
Set WMI_Error = CreateObject("WbemScripting.SwbemLastError")
Set Test = GetObject _
("Winmgmts:root\cimv2:Win32_Printer.Name='TestPrinter'")
Wscript.Echo WMI_Error.Operation & VbTab & _
WMI_Error.ParameterInfo & VbTab & WMI_Error.ProviderName

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.

Seite 91 von 394



Wenn Sie den Parameter /start angeben, dann startet das Script bestimmte Dienste.

Wenn Sie den Parameter /stop angeben, dann beendet das Script bestimmte Dienste.
Wenn Ihr Script umfangreicher wird, werden Sie es wahrscheinlich praktisch finden, einzelne
Scriptteile in Prozeduren zu verlagern. Prozeduren sind Scriptteile, die eine bestimmte
Aufgabe ausführen. Das Script zur Verwaltung von Diensten könnte zum Beispiel drei
Prozeduren verwenden: eine zum Abfragen der ausgeführten Dienste, eine, um die Dienste zu
beenden und eine, um die Dienst zu starten. Wenn Sie den jeweiligen Scriptcode für die drei
Aufgaben in drei Prozeduren platzieren, wird die Bearbeitung des Scripts viel einfacher -
außerdem verbessern Sei die Lesbarkeit Ihres Scripts, und es wird einfach, bestimmte
Scriptteile in andere Scripte zu übernehmen.
Auch wenn Scripte die gleichen Aufgaben immer wieder ausführen, sind Prozeduren sinnvoll.
Zum Beispiel, wenn Sie bei jedem Fehler im Script eine bestimmte Nachricht anzeigen lassen
möchten. Hierzu können Sie natürlich den entsprechen Scriptcode an all den Stellen Ihres
Scripts einfügen, an denen ein Fehler auftreten kann. Dieses Verfahren erfordert jedoch einen
recht hohen Aufwand - Sie müssen nicht nur den entsprechenden Code an möglicherweise
sehr vielen Stellen einfügen, sondern bei einer Änderung der Fehlerausgabe müssen alle
Stellen, an denen der Code verwendet wird, von Hand bearbeitet werden.
Ein besserer Ansatz wäre eine Prozedur zu erstellen, die eine Fehlernachricht anzeigt und
diese Prozedur dann bei einem Fehler aufzurufen. Bei diesem Verfahren müssen Sie bei einer
Änderung der Fehlernachricht den entsprechenden Code nur noch an einer Stelle ändern.
Unter VBScript können Sie zwei Arten von Prozeduren erstellen:

Subroutinen - Diese Prozeduren geben normalerweise keinen Wert zurück (zum Beispiel
eine Prozedur zur Anzeige einer Fehlernachricht).

Funktionen - Diese Prozeduren geben einen Wert zurück. Funktionenwerden zum Beispiel
für mathematische Berechnungen verwendet - beispielsweise, wenn Sie eine Funktion
erstellen, die den freien Festplattenplatz von Byte zu GB konvertiert und den GB-Wert dann
zurückgibt.

Aufrufen einer Prozedur


Normalerweise führt VBScript die einzelnen Zeilen eines Scripte der Reihe nach aus.
Prozeduren bilden jedoch eine Ausnahme von dieser Regel. Subroutinen und Funktionen
werden erst dann ausgeführt, wenn diese irgendwo im Script explizit aufgerufen werden.
Wenn eine Subroutine nicht aufgerufen wird, dann wird sie auch nicht ausgeführt - egal, an
welcher Stelle im Script sie sich befindet.
Das folgende Script enthält zum Beispiel eine Subroutine, die sich in der Mitte des Scripts
befindet - diese wird jedoch niemals ausgeführt:
Wscript.Echo "A"
Sub EchoLine2
Wscript.Echo "B"
End Sub
Wscript.Echo "C"
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
A
C

Seite 92 von 394


Da die Subroutine nicht aufgerufen wird, wird auch der in ihr enthaltene Code nicht
ausgeführt. Das Script läuft also folgendermaßen ab:
1.Zeile 1 wird ausgeführt - der Text 'A' wird angezeigt.
2.Zeile 2 wird als Anfang einer Subroutine erkannt - da die Subroutine hier jedoch nur
definiert und nicht aufgerufen wird, werden die Zeilen 2, 3 und 4 nicht ausgeführt.
3.Das Script fährt mit Zeile 5 fort - der ersten Zeile nach der Subroutine. Danach ist das Script
beendet.
Um die Subroutine auch auszuführen, müssen Sie sie explizit aufrufen. Als Befehl verwenden
Sie hierzu den Namen der Subroutine. Das folgende Script gibt zum Beispiel erst den Text 'A'
aus und ruft dann die Subroutine mit dem Namen EchoLineB aus - danach wird der Text 'C'
ausgegeben:
Wscript.Echo "A"
EchoLine2
Wscript.Echo "C"
Wscript.Quit
Sub EchoLineB
Wscript.Echo "B"
End Sub
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
A
B
C
Das Script wird in diesem Fall folgendermaßen ausgeführt:
1.Zeile 1 wird ausgeführt, und der Text 'A' wird ausgegeben.
2.In Zeile 2 wird die Subroutine mit dem Namen EchoLineB aufgerufen.
3.Das Script springt zu Zeile 5 - in der die Subroutine beginnt.
4.Zeile 6 (die erste Zeile in der Subroutine) wird ausgeführt - der Text 'B' wird angezeigt.
5.In Zeile 7 ist die Subroutine beendet. Daher springt das Script zu der Zeile nach dem
Scriptaufruf (Zeile 3 - die Subroutine wurde ja in Zeile 2 aufgerufen).
6.Zeile 3 wird ausgeführt - der Text 'C' wird ausgegeben
7.Zeile 4 wird ausgeführt, und das Script ist damit beendet.
Prozeduren können an jeder beliebigen Position im Script platziert werden - auf die
Funktionsweise oder die Leistung des Scripts hat dies keinen Einfluss. Die Platzierung der
Prozeduren kann jedoch Auswirkungen auf die Lesbarkeit Ihrer Scripte haben. Weitere
Informationen zur Platzierung von Prozeduren finden Sie im Kapitel Scripting Guidelines in
Teil 3 dieses Buches.
Das folgende Script verwendet zur Anzeige von möglichen WMI-Fehlern eine Prozedur:
On Error Resume Next
Set objWMIService = GetObject("Winmgmts:root\cimv2")
If Err &#60;&#62; 0 Then
ErrorHandler
End If
Set colPrinters = objWMIService.ExecQuery _

Seite 93 von 394


("SELECT * FROM Win32_Printer WHERE Name='TestPrinter'")
If Err &#60;&#62; 0 Then
ErrorHandler
End If
For Each objPrinter in colPrinters
Wscript.Echo objPrinter.Name
Next
Sub ErrorHandler
Select Case Hex(Err.Number)
Case "80041001"
Wscript.Echo "The call failed."
Case "80041002"
Wscript.Echo "The object could not be found."
Case "80041010"
Wscript.Echo "The specified class is not valid."
Case "8004103A"
Wscript.Echo "The specified object path was invalid."
Case "80041048"
Wscript.Echo "The specified class is not supported."
Case Else
Wscript.Echo "An unknown error occurred."
End Select
Err.Clear
End Sub

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

Seite 94 von 394


ThisDate = Date
End Sub

Parameter an Funktionen übergeben


Funktionen werden oft für mathematische Berechnungen verwendet. Das Ergebnis der
Berechnung ist dann der Rückgabewert der Funktion. Ein Beispiel hierfür wäre eine Funktion,
die Byte in MB oder Pfund in Kilogramm konvertiert.
Hierzu müssen Sie der Funktion die entsprechenden Werte übergeben. Wenn Sie zum
Beispiel die Zahlen 1 und 2 addieren möchten, dann benötigt die Funktion diese beiden
Werte. Sie werden ihr als Parameter (auch Argumente genannt) übergeben.
Um Parameter an eine Funktion zu übergeben, nehmen Sie diese einfach mit in den
Funktionsaufruf auf. Die folgende Codezeile ruft zum Beispiel die Funktion AddTwoNumbers
auf und übergibt Ihr die Wert 1 und 2 als Parameter:
AddTwoNumbers(1 , 2)
Damit Sie einer Funktion Parameter übergeben können, müssen diese in der Funktion
definiert werden. Hierzu fügen Sie der Funktion einfach die entsprechende Anzahl an
Variablen hinzu. Die folgende Codezeile definiert eine Funktion, die drei Parameter
akzeptiert:
Function AddThreeNumbers(x, y, z)
Wenn die Zahl der von der Funktion erwarteten Parameter nicht mit der Zahl der Parameter
im Funktionsaufruf übereinstimmt, kommt es zu einem Fehler. Das folgende Script erzeugt
einen solchen Fehler. Es werden zwei Parameter an die Funktion übergeben - diese erwartet
jedoch überhaupt keine Parameter:
x = 5
y = 10
Wscript.Echo AddTwoNumbers(x, y)
Function AddTwoNumbers
AddTwoNumbers = a + b
End Function
Um dieses Problem zu beheben, müssen Sie die Funktionsdefinition ändern und ihr die zwei
Parameter hinzufügen:
x = 5
y = 10
Wscript.Echo AddTwoNumbers(x, y)
Function AddTwoNumbers(a, b)
AddTwoNumbers = a + b
End Function
Sicher ist Ihnen aufgefallen, dass die Parameter im Funktionsaufruf andere Namen haben (x
und y) als die Parameter in der Funktionsdefinition (a und b). Es ist nicht notwendig, dass die
Parameter identische Namen verwenden. Wichtig ist nur, dass die Reihenfolge der Parameter
übereinstimmt. Da x der erste Parameter im Funktionsaufruf ist, wird der Wert von x der
Variable a zugewiesen. y ist der zweite Parameter - daher wird der entsprechende Wert
natürlich b zugewiesen.
Das folgende Beispiel soll zeigen, wie eine Funktion in einem echten Administrationsscript
verwendet wird. Es fragt den freien Speicherplatz von Laufwerk C ab und ruft dann eine
Funktion mit dem Namen FreeMegabytes auf. Diese Funktion konvertiert den freien
Speicherplatz von Byte in MB und gibt diesen Wert zurück. Der neue Wert wird dann vom
Script ausgegeben:

Seite 95 von 394


Set objWMIService = GetObject("winmgmts:")
Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
Wscript.Echo FreeMegaBytes(objLogicalDisk.FreeSpace)
Function FreeMegabytes(FreeBytes)
FreeMegabytes = FreeBytes / 1048576
FreeMegabytes = Int(FreeMegabytes)
End Function
Bedenken Sie, dass VBScript jedes Mal versucht die Funktion aufzurufen, wenn deren Name
im Script auftaucht. Auch wenn es immer eine Variable mit dem Namen der Funktion gibt,
können Sie deren Wert nicht einfach abfragen. Stattdessen wird immer die Funktion
aufgerufen, und Sie erhalten den Rückgabewert der Funktion. Das folgende Script ruft zum
Beispiel die Funktion FreeMegaBytes auf und versucht im nächsten Schritt auf die Variable
FreeMegabytes zuzugreifen. Da auch hier die Funktion aufgerufen wird, kommt es zu einem
Fehler - denn die Funktion erwartet ja einen Parameter:
Set objWMIService = GetObject("winmgmts:")
Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
Wscript.Echo FreeMegaBytes(objLogicalDisk.FreeSpace)
Wscript.Echo "Free space: " & FreeMegaBytes
Function FreeMegabytes(FreeBytes)
FreeMegabytes = FreeBytes / 1048576
FreeMegabytes = Int(FreeMegabytes)
End Function
Wenn Sie das Script ausführen, erhalten Sie die folgende Fehlermeldung:

Abbildung 2.25: Fehlermeldung durch einen fehlerhaften Funktionsaufruf


Wenn Sie später auf den Rückgabewert der Funktion zugreifen möchten ohne die Funktion
erneut aufzurufen, dann müssen Sie diesen in einer separaten Variablen speichern. Das
folgende Script speichert den Rückgabewert der Funktion FreeMegabytes in der Variable
AvailableSpace. Mit dieser Variable können Sie dann jederzeit auf den Wert zugreifen, ohne
die Funktion erneut aufrufen zu müssen:
Set objWMIService = GetObject("winmgmts:")
Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")
AvailableSpace = FreeMegaBytes(objLogicalDisk.FreeSpace)
Wscript.Echo "Free space: " & AvailableSpace
Function FreeMegabytes(FreeBytes)
FreeMegabytes = FreeBytes / 1048576
FreeMegabytes = Int(FreeMegabytes)
End Function
Parameterübergabe by Value oder by Reference
In den seltensten Fällen werden die Parameter in einem Script fest eingetragen.
Normalerweise werden sie über Variablen an eine Funktion übergeben. In den folgenden
beiden Codezeilen wird der Wert der Variable x auf 100 gesetzt und dieser Variable wird als
Parameter an die Funktion ModifyValue übergeben:

Seite 96 von 394


x = 100
Wscript.Echo ModifyValue(x)
Im Moment des Funktionsaufrufes hat x den Wert 100. Der Wert von x nach der Ausführung
der Funktion hängt von zwei Dingen ab: Erstens, ob die Funktion den Wert ändert, und
zweitens, ob der Wert by value(als Wert) oder by reference (als Referenz) übergeben wurde.
Um den Unterschied beider Übergabearten zu erkennen sehen Sie sich das folgende Script an.
Es setzt den Wert von x auf 100. In der Funktion wird der Wert von x dann auf 99 geändert:
x = 100
Wscript.Echo ModifyValue(x) & VbTab & x
Function ModifyValue(x)
ModifyValue = x / 25
x = 99
End Function
Die Ausgabe des Scripts sehen Sie in Abbildung 2.26. Wie Sie sehen können, wurde x einmal
durch 25 geteilt, und dann wurde x der neue Wert 99 zugewiesen.

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.

Seite 97 von 394


Abbildung 2.27: Parameter by value übergeben
Sie können für jeden Parameter einzeln festlegen ob er ByVal oder ByRef übergeben wird.
Beide Varianten können in einer Funktionsdefinition beliebig gemischt werden:
Function TestFunction(ByVal x, ByRef y)

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.

Abbildung 2.28: Beispiel-Ordnerstruktur


Das folgende Script führt eine solche Rekursion durch. Hierzu verwendet es die Funktion
ShowSubFolders. Diese wird so lange aufgerufen, bis alle Ordner durchlaufen wurden.
Set FSO = CreateObject("Scripting.FileSystemObject")
ShowSubfolders FSO.GetFolder("C:\Scripts")
Sub ShowSubFolders(Folder)
For Each Subfolder in Folder.SubFolders
Wscript.Echo Subfolder.Path
ShowSubFolders Subfolder
Next
End Sub
Die Funktion ShowSubFolders funktioniert folgendermaßen:

Seite 98 von 394


1.Sie ruft eine Collection mit den Unterordnern des Startordners ab (c:\scripte). In dieser
Collection gibt es zwei Elemente (Unterordner 1 und Unterordner 2).
2.Dann gibt sie den Ordnerpfad für das erste Element (Unterordner 1) aus und ruft sich selbst
mit dem Ordner als Parameter auf.
3.Sie ruft eine Collection mit allen Unterordnern von Unterordner 1 ab. Diese Collection hat
zwei Elemente: Unterordner 1A und Unterordner 1B.
4.Sie nimmt das erste Element der Collection (Unterordner 1A) und gibt den Ordnerpfad aus.
Dann ruft sie sich selbst mit dem Namen dieses Ordners als Parameter auf.
5.Da Unterordner 1A keine weiteren Unterordner mehr besitzt, geht es mit dem nächsten
Element der Collection weiter (Unterordner 1B). Die Funktion ruft sich nun selbst mit dem
Namen dieses Ordners als Parameter auf.
6.Da Unterordner 1B keine weiteren Unterordner mehr hat, ist die Rekursion von
Unterordner 1 beendet. Die Funktion macht mit dem zweiten Element (Unterordern 2) der
ersten Collection (Unterordner von c:\scripte) weiter und wiederholt den gesamten Vorgang.
Wenn Sie das Script ausführen, erhalten Sie die folgende Ausgabe:
C:\scripte\Unterordner 1
C:\scripte\Unterordner 1\Unterordner 1A
C:\scripte\Unterordner 1\Unterordner 1B
C:\scripte\Unterordner 2
C:\scripte\Unterordner 2\Unterordner 2A
C:\scripte\Unterordner 2\Unterordner 2B
C:\scripte\Unterordner 2\Unterordner 2C
Bei der Rekursion handelt es sich um eine extrem mächtige Technik, um Daten in
Baumstrukturen (zum Beispiel in Active Directory oder im Dateisystem) zu durchsuchen und
anzuzeigen.

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,

Seite 99 von 394


dann ist WMI der COM-Server und Ihr Script ist der COM-Client. COM-Server können auf
zwei Arten implementiert werden:

Out-Of-Process-Server - Out-Of-Process-Server werden normalerweise über ausführbare
Dateien implementiert und werden in einem anderen Prozess als das Script ausgeführt. Wenn
Sie zum Beispiel ein Script starten, dann wird eine Instanz von Wscript.exe gestartet. Wenn
Sie in dem Script dann eine Instanz des Microsoft Word-Objektes erstellen, dann wird diese
in einem weiteren Prozess gestartet.

In-Process-Server - Bibliotheken (.dll-Dateien) sind normalerweise In-Process-Server - sie
werden unter demselben Prozess ausgeführt wie die Anwendung oder das Script, dass sie
aufgerufen hat. Wenn Sie zum Beispiel in einem Script eine neue Instanz des Objektes
FileSystemObject erstellen, dann wird kein neuer Prozess für dieses Objekt gestartet. Dies
liegt daran, dass es sich beim Objekt FileSystemObject (das in der DLL Scrrun.dll definiert
ist) um einen In-Process-Server handelt - dieser wird im selben Prozess ausgeführt, wie das
Script, das Ihn aufgerufen hat. In-Process-Server werden normalerweise schneller ausgeführt
als Out-Of-Process-Server, da das Betriebssystem nicht über Prozessgrenzen hinweg arbeiten
muss, um auf Methoden und Eigenschaften zuzugreifen.
Wie wir schon weiter oben in diesem Kapitel besprochen haben, arbeitet VBScript mit
Objekten, die sich Automatisationsobjekte nennen. Alle COM-Objekte müssen eine oder
mehrere Schnittstellen zur Verfügung stellen. Über diese Schnittstellen können die COM-
Clients auf die COM-Server zugreifen. Alle Objekte, die die Schnittstelle IDispatch zur
Verfügung stellen, werden Automatisationsobjekte genannt. Da nicht alle COM-Objekte diese
Schnittstelle anbieten, kann VBScript auch auf alle COM-Objekte des Computers zugreifen.

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.

Ein neues Objekt erstellen

Seite 100 von 394


Wenn die Methode CreateObject ausgeführt wird, dann liest die Script Engine die ProgID aus
und übergibt sie der COM-API. Diese API erstellt die Objektreferenz. Mit der folgenden
Codezeile wird ein neues Objekt mit der ProgIDScripting.FileSystemObject erstellt:
Set TestObject = CreateObject("Scripting.FileSystemObject")
Die COM-API sucht im Pfad HKEY_CLASSES_ROOT der Registrierung nach einem
Unterschlüssel mit dem Namen der ProgID. Wenn ein solcher Schlüssel gefunden wird, dann
liest die API einen Unterschlüssel mit dem Namen CLSID unter dem ProgID-Schlüssel aus.
Der Unterschlüssel CLSID enthält die GUID (Globally Unique Identifier) des zu erstellenden
Automatisationsobjekts. Eine GUID sieht zum Beispiel so aus:
{172BDDF8-CEEA-11D1-8B05-00600806D9B6}
Mit der GUID findet und verwendet das Betriebssystem COM-Objekte tatsächlich - die
ProgID ist nur ein Alias, damit der Scriptautor leichter auf die Komponente zugreifen kann.
Nachdem die GUID gefunden wird, wird im Schlüssel
HKEY_LOCAL_MACHINE\Software\Classes\CLSID nach einem Unterschlüssel mit
demselben Namen wie die GUID gesucht. Wenn das Betriebssystem diesen Schlüssel findet,
sucht es hier nach dem Speicherort der ausführbaren Datei oder der Bibliotheksdatei der
Komponente (im Fall des Objekts FileSystemObject ist das C:\Windows\System32\Scrrun.dll).
Dann lädt die COM-API die Anwendung oder die Bibliothek, erstellt das Objekt und gibt eine
Objektreferenz an das Script zurück.

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

Seite 101 von 394


Objekt vor dem Ausführen der Anwendung überprüft wird. Außerdem ermöglicht die frühe
Bindung einen Zugriff auf die Typenbibliothek des Objekts - diese enthält Informationen über
die Methoden und Eigenschaften des Objektes.
Da es sich bei VBScript nicht um eine Compilersprache handelt, wird die frühe Bindung nicht
unterstützt. Stattdessen müssen Sie die späte Bindung verwenden - sie wird erst dann
durchgeführt, wenn das Script ausgeführt wird. Bei der späten Bindung muss das Script
Informationen über Objekt, Methoden und Eigenschaften aus der Registrierung entnehmen.
Da VBScript keinen Zugriff auf die Objektbibliothek des Objektes hat, muss der
Registrierungszugriff bei jeder Verwendung des Objekts durchgeführt werden. Außerdem
können fehlerhafte Zugriffe erst dann festgestellt werden, wenn das Script ausgeführt wird.

Eine Methode für die Bindung eines Automatisationsobjekts auswählen


Die Bindung an ein Automatisationsobjekt ist sehr einfach - der schwierigste Teil ist die
Auswahl der geeigneten Methode (GetObject oder CreateObject?). In dem meisten Fällen
hängt dies vom Objekt ab - einige generelle Richtlinien finden Sie jedoch in Tabelle 2.20.

Tabelle 2.20: Methoden zur Bindung von Automatisationsobjekten


Auszuführende Aufgabe Methode
Binden an WMI oder ADSI. GetObject mit dem entsprechenden Moniker.

Ein Moniker ist ein Zwischenobjekt, das es ermöglicht, eine


Referenz auf ein Automatisationsobjekt zu finden, zu
aktivieren und zu erstellen. Sowohl auf WMI als auch auf
ADSI wird über Moniker zugegriffen. Ihre Scripte können
so auf WMI- und ADSI-Objekte zugreifen, ohne dass Ihnen
die physikalische Position dieser Objekte bekannt ist.
Typischerweise werden Moniker für den Zugriff auf Objekte
verwendet, die nicht im Dateisystem gespeichert sind.
Set TestObject = GetObject("winmgmts:")
Binden an eine neue Instanz CreateObject mit der entsprechenden ProgID.
eines Automatisationsobjekts. Set TestObject = CreateObject("Word.Application")
Binden an eine bestehende GetObject mit der entsprechenden ProgID.
Instanz eines Set TestObject = GetObject("Word.Application")
Automatisationsobjekts.
Binden an ein GetObject mit der entsprechenden ProgID.
Automatisationsobjekt über eine Set TestObject = GetObject("c:\scripts\test.xls")
bestehende Datei.
Binden an eine neue Instanz CreateObject mit der entsprechenden ProgID und einer
eines Automatisationsobjekts mit Variable für die Ereigniszuordnung.
der Möglichkeit auf Ereignisse Set TestObject = Wscript.CreateObject _
des Objektes zu reagieren. ("Word.Application", "Word")
Binden an eine bestehende GetObject mit der entsprechenden ProgID und einer
Instanz eines Variable für die Ereigniszuordnung.
Automatisationsobjekts mit der Set TestObject = Wscript.GetObject _ ("Word.Application",
Möglichkeit auf Ereignisse des "Word")

Seite 102 von 394


Auszuführende Aufgabe Methode
Objektes zu reagieren.
Binden an eine neue Instanz CreateObject mit der entsprechenden ProgID und dem
eines Automatisationsobjekts auf Namen des Remotecomputers.
einem Remotecomputer. Set TestObject = CreateObject _ ("Word.Application", "atl-
dc-01")

Überprüfen von Objektreferenzen


Die Funktion IsObject ermöglicht es Ihnen zu überprüfen, ob eine Referenzierung funktioniert
hat. Wenn der Aufruf von GetObject oder CreateObject funktioniert, dann gibt IsObject den
Wert True (-1) zurück - andernfalls erhalten Sie den Rückgabewert False (0). Das folgende
Codestück verwendet die Methode CreateObject, um eine Objektreferenz auf ein
nichtexistentes Objekt zu erstellen (diese wird der Variable TestObject zugewiesen). Da dies
fehlschlägt, gibt eine Prüfung der Referenz über die Methode IsObject den Wert 0 zurück.
On Error Resume Next
Set TestObject = CreateObject("Fake.Object")
Wscript.Echo IsObject(TestObject)
Unglücklicherweise geht VBScript davon aus, dass eine einmal erstelle Objektreferenz für die
gesamte Lebensdauer des Scripts gültig ist. Dies ist normalerweise kein Problem - speziell bei
Objekten wie ADSI und WMI, die wohl kaum während der Scriptausführung verschwinden
werden. Leider lässt sich dasselbe nicht über Automatisationsobjekte sagen. Sehen Sie sich
zum Beispiel das folgende Script an. Es erstellt eine Instanz von Microsoft Word, beendet die
Instanz und prüft dann über IsObject, ob die Objektreferenz noch gültig ist:
Set TestObject = CreateObject("Word.Application")
TestObject.Quit
Wscript.Echo IsObject(TestObject)
Wenn Sie das Script ausführen, behauptet IsObject, dass TestObject noch immer ein aktives
Objekt ist - und zwar darum, weil TestObject ja tatsächlich noch eine Objektreferenz ist. Sie
verweist nur nicht mehr auf eine Instanz von Microsoft Word, die ausgeführt wird.
Es gibt zwei Wege, um solche Probleme zu vermeiden. Ein Ansatz ist es, über WMI zu
prüfen, ob der Prozess (in diesem Fall word.exe) noch ausgeführt wird. Diese Methode
funktioniert zwar, Sie müssen jedoch permanent eine Abfrage der laufenden Prozesse
durchführen - Ihr Script wird so langsamer. Außerdem treten weitere Schwierigkeiten auf,
wenn mehrere Instanzen von word.exe ausgeführt werden.
Ein besserer Ansatz ist es auf Ereignisse des Objektes zu reagieren. Wenn Word geschlossen
wird, dann wird ein Ereignis an Ihr Script gesendet - dieses kann dann entsprechend
reagieren.
Weitere Informationen über die Verarbeitung von Ereignissen finden Sie im Abschnitt
Creating Enterprise Scripts in Teil 3 in diesem Buch.

Objekte aus dem Speicher entfernen


In-Process-Server (Automatisationsobjekte, die über .dll-Dateien zur Verfügung stehen)
werden beim Beenden des Scripts automatisch aus dem Speicher entfernt. Das liegt daran,
dass diese Objekte im selben Prozess wie das Script ausgeführt werden. Das folgende Script
erstellt eine Instanz des Objekts FileSystemObject und zeigt ein Nachrichtenfenster an. Sobald

Seite 103 von 394


Sie das Nachrichtenfenster schließen, werden sowohl das Script als auch das Objekt aus dem
Speicher entfernt.
Set TestObject = CreateObject("Scripting.FileSystemObject")
Wscript.Echo "Script beenden."
Für Out-Of-Process-Server gilt dies nicht - diese werden in einem anderen Prozess als das
Script ausgeführt. Das folgende Script erstellt eine Instanz von Microsoft Word und zeigt
dann ebenfalls ein Nachrichtenfenster an. Wenn Sie das Nachrichtenfenster schließen, dann
wird zwar das Script beendet, der Microsoft Word-Prozess (word.exe) jedoch nicht:
Set TestObject = CreateObject("Word.Application")
Wscript.Echo "Script beenden."
Das liegt daran, dass es keine direkte Verbindung zwischen dem Script-Prozess und dem
Word-Prozess gibt. Die Aktionen, die Sie mit dem Script-Prozess durchführen, betreffen den
Word-Prozess nicht - andersrum gilt das gleiche. Über den Taskmanager können Sie
überprüfen, ob der Prozess noch ausgeführt wird.

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

Seite 104 von 394


Mit dem Schlüsselwort Nothing können Sie eine Objektreferenz und ein Objekt entfernen.
Nachdem eine Objektvariable auf Nothing (Nichts) gesetzt wurde, enthält sie keine
Objektreferenz mehr und kann nicht mehr zum Zugriff auf das Objekt verwendet werden. Das
folgende Script erstellt eine Instanz von Microsoft Word und weist diese der Objektvariablen
TestObject zu. Dann setzt es die Variable auf Nothing und versucht dann über Quit Word aus
dem Speicher zu entfernen:
Set TestObject = CreateObject("Word.Application")
Set TestObject = Nothing
TestObject.Quit
Da Sie versuchen auf ein Objekt zuzugreifen, dessen Referenz vorher bereits mit Nothing
entfernt wurde, erhalten Sie die Fehlermeldung aus Abbildung 2.30, wenn Sie das Script
ausführen.

Abbildung 2.30: Arbeiten mit ungültigen Objektreferenzen


Wenn Sie eine Objektvariable auf Nothing setzen, geben Sie zwar etwas Speicher frei, das
Objekt selbst wird jedoch nicht aus dem Speicher entfernt - daher gibt es normalerweise
keinen Grund Nothing zu verwenden. Der gleiche Vorgang wird auf jeden Fall beim Beenden
des Scripts durchgeführt. Zeile 2 im folgenden Script ist also unnötig:
Set TestObject = CreateObject("Scripting.FileSystemObject")
Set TestObject = Nothing

Scripting-Konzepte und -Technologien zur


Systemadministration: Kapitel 3 - Der WSH
Veröffentlicht: 26. Apr 2004
(Engl. Originaltitel: WSH Primer)
Der Windows Script Host (WSH), ein Feature der Microsoft Windows 2000-Familie, ist eine
mächtige Scripting-Umgebung, die ideal zur Automatisierung von Administrationsaufgaben
eingesetzt werden kann. Scripte, die in der WSH-Umgebung ausgeführt werden, können die
umfangreichen Möglichkeiten der WSH-Objekte und anderer COM-basierter
Automatisationsobjekte nutzen - zum Beispiel WMI (Windows Management Instrumentation)
und ADSI (Active Directory Service Interfaces) zur Verwaltung der Windows-Subsysteme
und zur Zentralisierung von Administrationsaufgaben.

Windows® 2000-Familie, ist eine mächtige Scripting-Umgebung, die ideal zur


Automatisierung von Administrationsaufgaben eingesetzt werden kann. Scripte, die in der
WSH-Umgebung ausgeführt werden, können die umfangreichen Möglichkeiten der WSH-
Objekte und anderer COM-basierter Automatisationsobjekte nutzen - zum Beispiel WMI
Seite 105 von 394
(Windows Management Instrumentation) und ADSI (Active Directory Service Interfaces) zur
Verwaltung der Windows-Subsysteme und zur Zentralisierung von Administrationsaufgaben.

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.

Standardmäßige Durchführung von Administrationsaufgaben


Der WSH ist primär eine Laufzeitumgebung für Scripte. Er stellt eine Umgebung zur
Verfügung, in der Scripte ausgeführt werden können - ganz ähnlich wie ein Befehlsinterpreter
(zum Beispiel cmd.exe oder command.com), über den Batchdateien ausgeführt werden
können.
Auch wenn der WSH primär als 'Container' zur Verwendung anderer Scriptsprachen oder -
technologien dient, ist es doch möglich, "reine" WSH-Scripte zu nutzen. Mit dem WSH
können Sie zum Beispiel Netzlaufwerke und Drucker verbinden. Das folgende zweizeilige
Script ordnet zum Beispiel den Laufwerksbuchstaben X zur Freigabe \\atl-fs-01\public zu:
Set objNetwork = Wscript.CreateObject("WScript.Network")
objNetwork.MapNetworkDrive "X:", "\\atl-fs-01\public"

Seite 106 von 394


Verwendung von COM-Objekten
Wie Sie nun wissen, können Sie den WSH zum Zuordnen von Netzlaufwerken verwenden.
Leider gibt es außer dieser Möglichkeit wenig, was Sie noch über den WSH alleine
durchführen können. Sie können über den WSH nicht die Hardware eines Computers
abfragen oder feststellen, welche Software installiert ist.
Auch wenn der WSH selbst keine dieser Möglichkeiten zur Verfügung stellt, können Sie sie
trotzdem in einem WSH-Script nutzen. Mit dem WSH können Sie nämlich COM-Objekte
(Component Object Model) in Ihren Scripten verwenden.
Ein COM-Objekt ist eine Möglichkeit für Anwendungen (.exe) oder Programmbibliotheken
(.dll) Ihre Funktionen zur Verfügung zu stellen. Der WSH kann diese Funktionen dann
verwenden, indem er diese Objekte in das Script einbindet.
Der WSH stellt zum Beispiel keine Methoden zur Verwaltung von Diensten zur Verfügung.
WMI bietet jedoch solche Möglichkeiten (WMI ist eigentlich eine Sammlung von COM-
Objekten). Mit WMI können Sie die Eigenschaften von Diensten abfragen, Dienste anhalten
und starten und die Diensteinstellungen konfigurieren. Statt also eigene Methoden zur
Verwaltung von Diensten zur Verfügung zu stellen, verwendet der WSH einfach die von
WMI.
Der WSH kann jedes COM-Objekt nutzen, das eine Automatisation unterstützt
(Automatisation ist ein Standardverfahren, um auf COM-Objekte zuzugreifen). Auf den
meisten Computern steht eine riesige Menge an Automatisationsobjekten zur Verfügung. Der
WSH kann so nahezu jede beliebige Aufgabe ausführen - vom Festlegen von
Datenträgerkontingenten bis zur Active Directory-Verwaltung.
Das folgende WSH-Script verwendet zum Beispiel ADSI, um ein Benutzerkonto in Active
Directory zu erstellen:
Set objOU = Wscript.GetObject("LDAP://OU=management,dc=fabrikam,dc=com")
Set objUser = objOU.Create("User", "cn=MyerKen")
objUser.Put "sAMAccountName", "myerken"
objUser.SetInfo

Nutzung von Standard-Features einer WSH-kompatiblen Scriptsprache


Der Verwendungszweck von Anwendungen und wie diese Anwendungen verwendet werden
ist oft sehr unterschiedlich. Der Windows-Taschenrechner hat zum Beispiel nur wenig
Ähnlichkeit mit Ipconfig.exe - beide haben wiederum wenig mit Microsoft® Word
gemeinsam. Abgesehen von diesen Unterschieden gibt es jedoch einige grundlegende
Eigenschaften, die sich diese Anwendungen teilen. Viele Anwendungen geben etwas aus und
nehmen Benutzereingaben entgegen. Viele Anwendungen können Lese- und
Schreiboperationen in der Registrierung durchführen. Viele Anwendungen können mit
Kommandozeilenparametern gestartet werden - sogar viele grafische Anwendungen. Wenn
Microsoft Word zum Beispiel mit dem Schalter /n gestartet wird, dann wird gleich ein leeres
Dokument geöffnet:
winword.exe /n
Diese Standardfunktionalitäten werden auch für administrative Scripte benötigt. Was würde
Ihnen zum Beispiel ein Script nützen, das keine Informationen anzeigen kann? Viele dieser
Funktionalitäten stellt Ihnen der WSH zur Verfügung. Er kann Informationen ausgeben und
Eingaben entgegennehmen, Lese- und Schreiboperationen in der Registrierung durchführen
und Kommandozeilenparameter entgegennehmen.

Seite 107 von 394


Stellen wir uns vor, Sie benötigen ein Script, das einen Ordner löscht. Wenn Sie das Script
starten, können Sie den Ordnernamen als Parameter angeben:
deletefolder.vbs c:\scripts
Das Löschen des Ordners können Sie über das Objekt FileSystemObject durchführen. Das
Script selbst schreiben Sie mit VBScript. Aber wie verarbeiten Sie die
Kommandozeilenparameter? Werder das FileSystemObject noch VBScript können diese
Parameter verarbeiten.
Glücklicherweise ist der WSH dazu in der Lage. Das folgende Script verwende drei
unterschiedliche Technologien:

In Zeile 1 wird VBScript verwendet, um eine neue Instanz des Objektes FileSystemObject zu
erstellen.

In Zeile 2 wird der WSH verwendet, um die Kommandozeilenparameter einzulesen und
diese einer Variable zuzuweisen.

In Zeile 3 wird das Objekt FileSystemObject zum Löschen des angegebenen Ordners
verwendet.
Set objFSO = Wscript.CreateObject("Scripting.FileSystemObject")
strFolder = Wscript.Arguments.Item(0)
objFSO.DeleteFolder(strFolder)
Das gleiche Script können Sie über Jscript, PythonScript oder eine andere WSH-kompatible
Scriptsprache implementieren. Es ist völlig egal, ob die gewählte Sprache die Verarbeitung
von Kommandozeilenparametern unterstützt, da der WSH ja diese Funktionalität zur
Verfügung stellt.

Verwendung von Kommandozeilentools


Sie brauchen den WSH nicht wirklich, um Kommandozeilentools auszuführen. Sie können
ganz einfach in einer Eingabeaufforderung oder über eine Batchdatei gestartet werden. Der
WSH ist jedoch dann ziemlich nützlich, wenn Sie die Tools oder Batchdateien mit etwas
"Intelligenz" ausstatten möchten. Stellen Sie sich zum Beispiel vor, Sie möchten eine
Netzwerkfreigabe nur dann zuordnen, wenn der Benutzer sich in einer bestimmten Domäne
(zum Beispiel "fabricam") anmeldet - andernfalls soll nichts passieren.
Ist das über eine Batchdatei möglich? Ja, ist es - es ist jedoch ziemlich kompliziert. In einem
Script können Sie diese Aufgabe im Gegensatz dazu über die folgenden sechs Zeilen
erledigen:
Set objNetwork = Wscript.CreateObject("Wscript.Network")
Set objShell = WScript.CreateObject("WScript.Shell")
strDomain = objNetwork.DomainName
If strDomain = "fabrikam" Then
objShell.Run "net use x: \\atl-fs-01"
End If

WSH vs. Cmd.exe


An dieser Stelle könnte es ganz nützlich sein, den WSH und Cmd.exe (der
Kommandozeileninterpreter von Windows) zu vergleichen. Beide sind Scripting-
Umgebungen: Der WSH ermöglicht das Ausführen von WSH-Scripten und Cmd.exe
ermöglicht das Ausführen von Batchdateien (manchmal auch Shellscripte genannt). Sowohl
WSH als auch Cmd.exe benötigen eine Scriptsprache und entsprechende Werkzeuge. Es ist

Seite 108 von 394


schwierig, Scripte nur mit dem WSH zu schreiben und es ist genauso schwierig, Batchdateien
nur mit der Shellsprache zu schreiben.
Hier treten nun die Unterschiede beider Umgebung zu tage. Während der WSH Ihnen den
Zugriff auf eine große Zahl an ausgereiften Scriptsprachen ermöglicht, sind Sie mit Cmd.exe
auf die einfache Shellsprache eingeschränkt. Die einzigen Tools, die Sie mit Cmd.exe
verwenden können, sind Kommandozeilentools. Der WSH bietet Ihnen nicht nur einen
Zugriff auf dieselben Tools, sondern Sie sind zusätzlich in der Lage, Automatisationsobjekte
zu verwenden.
Soll das heißen, Sie sollen alle Kommandozeilentools und Batchdateien wegwerfen und alles
nur noch über WSH-Script durchführen? Natürlich nicht - wenn Sie bereits über eine
funktionierende Lösung verfügen, dann gibt es keinen Grund, diese nicht weiter zu
verwenden. Der WSH ist jedoch eine hervorragende Lösung für die Probleme, die Sie mit
Batchdateien und Kommandozeilentools nicht lösen können.

Ein Hinweise zu WSH-Versionen


Die Beispielscripte in diesem Kapitel wurden mit der WSH-Version 5.6 entwickelt und
getestet. Einige der beschriebenen Funktionalitäten stehen auch nur unter Version 5.6 oder
höher zu Verfügung. Daher sollten Sie prüfen, welche WSH-Version bei Ihnen installiert ist
und diese im Zweifelsfall auf Version 5.6 aktualisieren.

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&#62;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.

Komponenten der WSH-Umgebung


Die Architektur des WSH ist modular aufgebaut. Sie setzt sich aus Einzelteilen zusammen,
die jeweils für bestimmte Funktionalitäten verantwortlich sind. Diese Modularität führt zu
zwei Vorteilen: Der WSH unterstützt verschiedene Scriptsprachen und kann COM-Objekte
verwenden.
In Abbildung 3.1 sehen Sie die Hauptkomponenten der WSH-Umgebung und wie diese
miteinander in Verbindung stehen (Scriptdateien, Script Host, Scripting Language Engines
und COM-Objekte). Die Komponenten im dunklen Kasten werden mit der Installation von
WSH 5.6 eingerichtet. Im Rest dieses Kapitels werden die einzelnen Komponenten genauer
besprochen.

Abbildung 3.1: Hauptkomponenten der WSH-Umgebung

Seite 110 von 394


Scriptdateien
WSH-Scriptdateien (meist einfach als Script bezeichnet) sind einfache Textdateien mit
Scriptbefehlen ("Textdatei" bedeutet in diesem Fall, dass keine Zeichen mit speziellen
Formatierungen verwendet werden). Das folgende Script wird zum Beispiel fehlschlagen, da
es typografische Anführungszeichen enthält (das Anführungszeichen ist unten statt oben):
Wscript.Echo "This line is correct."
Wscript.Echo „This line is incorrect."
Da viele Textverarbeitungsprogramme standardmäßig solche Zeichen verwenden, stellen sie
nicht unbedingt die beste Script-Entwicklungsumgebung dar. Texteditoren werden hingegen
für die Arbeit mit normalen Textdateien entwickelt (zum Beispiel Notepad.exe) - daher
sollten Sie Ihre Scripte mit einem Texteditor schreiben.

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.

Tabelle 3.1: Dateierweiterungen von Scripten


DateierweiterungBeispiel-DateinameScriptsprache
.VBS EnumPrinters.vbs VBScript
.JS EnumProcesses.js JScript
.PLS EnumDisks.pls PerlScript
Wenn Sie ein Script mit VBScript schreiben, dann sollten Sie das Script also mit der
Dateierweiterung .vbs speichern.

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.

Seite 111 von 394


Script Hosts
Der Script Host initiiert und koordiniert die Ausführung Ihres Scripts. Er liest die Scriptdatei
ein und interagiert mit den Komponenten der WSH-Umgebung und den COM-Objekten.
Außerdem stellt er fest, welche Scriptsprache er bei der Ausführung des Scripts verwenden
muss. Wenn das Script zum Beispiel die Dateierweiterung .vbs verwendet, dann lädt der
Script Host die VBScript Language Engine, und arbeitet dann mit dieser den Scriptcode ab.
Die WSH-Umgebung stellt zwei Script Hosts zur Verfügung: das konsolenbasierte CScript
und das GUI-basierte WScript. Diese bieten beide eine nahezu identische Funktionalität. In
den meisten Fällen ist es vollkommen egal welcher Script Hosts Ihr Script ausführt.
Die zwei einzigen Unterschiede zwischen den Script Hosts betreffen die Interaktion mit dem
Script - also den Weg, wie Sie Informationen an das Script übergeben (Eingaben) oder von
diesem erhalten (Ausgaben). Die Ein- und Ausgaben von CScript erfolgen über die
Eingabeaufforderung. Im Gegensatz dazu werden bei WScript die Ein- und Ausgaben über
Nachrichtenfenster durchgeführt.
Ansonsten sind die beiden Script Hosts identisch. Wenn Sie ein Script schreiben, dass keine
Interaktion mit dem Benutzer erfordert, dann können Sie es sowohl mit CScript als auch mit
WScript ausführen. Das folgende Script ordnet zum Beispiel eine Netzwerkfreigabe einem
Laufwerksbuchstaben zu. Es wird unter beiden Script Hosts exakt gleich ausgeführt:
Set objNetwork = Wscript.CreateObject("WScript.Network")
objNetwork.MapNetworkDrive "g:", "\\atl-fs-01\Sales"
Ein Script, das Informationen ausgibt, wird hingegen unter CScript ganz anders ausgeführt
(die Ausgaben werden zeilenweise in der Eingabeaufforderung vorgenommen), als unter
WScript (die Ausgaben werden als Nachrichtenfenster angezeigt). Weitere Informationen zum
Ausführen von Scripts mit CScript und WScript finden Sie weiter unten im Abschnitt WSH-
Scripte ausführen in diesem Kapitel.

Scripting Language Engines


Obwohl der Script Host für die Initiierung und Koordinierung der Scriptausführung
verantwortlich ist, kann er trotzdem keine Scriptsprache interpretieren. Diese Aufgabe wurde
in der WSH-Umgebung in eine andere Komponente ausgelagert.
Durch diese Teilung ist der WSH in der Lage mit mehreren Scriptsprachen zu arbeiten. Er
beherrscht selbst keine einzige Scriptsprache, sondern gibt die Interpretation des Scripts an
die entsprechende Language Engine weiter. Sie können VBScript nur darum verwenden, weil
die VBScript Language Engine bereits installiert ist.
Wenn eine neue Scriptsprache installiert wird, dann wird in der Registrierung mindestens eine
neue Zuordnung eingerichtet. Diese verbindet eine Dateierweiterung mit der DLL (Dynamic
Link Library), über die die Scriptsprache implementiert wird. Der Scripthost erkennt die in
einem Script verwendete Scriptsprache normalerweise an der Dateierweiterung des Scripts.
Dann prüft er in der Registrierung, welche Scripting Language Engine (als DLL) dieser
Erweiterung zugeordnet ist, und verwendet die Engine.

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.

Seite 112 von 394


COM-Objekte
Der WSH stellt das Objekt WScript und drei COM-basierte Objekte zur Verfügung: WshShell,
WshNetwork und WshController. Auch wenn diese standardmäßig bereits in der WSH-
Umgebung vorhanden sind, handelt es sich doch um COM-Objekte. Sie werden also auch
genauso wie COM-Objekte verwendet.
Die WSH-COM-Objekte bieten natürlich nicht die gleichen administrativen Möglichkeiten
wie WMI oder ADSI. Trotzdem sind sie in einigen Situationen sehr nützlich:

Wenn Sie Aufgaben ausführen müssen, die nicht über ein anderes Automatisationsobjekt
durchgeführt werden können. Das Objekt WshNetwork erlaubt es Ihnen beispielsweise
Netzlaufwerke zu Laufwerksbuchstaben zuzuordnen - dies ist mit WMI oder ADSI nicht
möglich.

Wenn Sie mit Clients arbeiten müssen, die WMI oder ADSI nicht zur Verfügung stellen. Mit
ADSI können Sie zum Beispiel den Namen des lokalen Computers abfragen - es sei denn, es
handelt sich um einen Computer unter Windows 98. In diesem Fall müssen Sie das Objekt
WshNetwork verwenden.

Wenn sie ein Script auf einem Remotecomputer ausführen müssen. Weder WMI noch ADSI
sind hierzu in der Lage. Mit dem Objekt WshController können Sie jedoch auch diese
Aufgabe bewältigen.

Zusammenarbeit der einzelnen Komponenten der WSH-


Umgebung
Die Komponenten der WSH-Umgebung müssen mit den anderen Komponenten
zusammenarbeiten. Diese Zusammenarbeit sieht folgendermaßen aus:
Script Host und Scriptdatei: Wenn Script Host für die Ausführung eines Scripts aufgerufen
wird, prüft er die Dateierweiterung der Scriptdatei. Dann sucht der Script Host in der
Registrierung nach der Scripting Language Engine, die der Erweiterung zugeordnet ist. Dies
passiert alles, bevor eine einzige Zeile Scriptcode ausgeführt wird.
Script Host und Scripting Language Engine: Nachdem die Scriptsprache festgestellt
wurde, arbeitet der Script Host mit der entsprechenden Scripting Language Engine
zusammen, um die Befehle im Script zu interpretieren. Der Script Host kommuniziert mit der
Scripting Language Engine über die Windows-Script-Schnittstellen. Bevor die erste
Scriptzeile ausgeführt wird, wird das gesamte Script eingelesen und auf syntaktische Fehler
geprüft. Das folgende Script hat zum Beispiel eine fehlerhafte Anweisung in Zeile 3. Der If-
Then-Befehl ist falsch:
Wscript.Echo "Line 1."
Wscript.Echo "Line 2."
If x = 1
Wscript.Echo "X is equal to 1."
End If
Vielleicht erwarten Sie, dass Zeile 1 und 2 ausgeführt werden, bevor der Fehler in Zeile 3
auftritt. Dies ist jedoch nicht so. Der Fehler wird bereits bei der Syntaxprüfung vor der
Ausführung festgestellt. Daher wird mit der Scriptausführung gar nicht begonnen.

Seite 113 von 394


WScript-Bibliothek und COM-Objekte: Wenn im Script ein COM-Objekt verwendet wird,
dann führt die WScript-Bibliothek die Interaktion mit diesem COM-Objekt durch.

Anmerkung: Viele Scriptsprachen bieten die Möglichkeit direkt mit COM-Objekten zu


interagieren. In diesem Fall ist WScript nicht an der Zusammenarbeit beteiligt. Da es in
diesem Kapitel jedoch um den WSH geht, werden die Methoden CreateObject und GetObject
von WScript verwendet. VBScript bietet Ihnen jedoch eine wesentlich einfachere Möglichkeit
mit COM-Objekten zu arbeiten. Daher werden in fast allen anderen Scripten dieses Buches
die VBScript-Funktionen verwendet. Eine genauere Betrachtung der beiden Möglichkeiten
finden Sie im Kapitel VBScript Primer dieses Buches.

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.

Seite 114 von 394


Abbildung 3.2: Diagram des WSH-Objektmodells

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

Seite 115 von 394


einem Nachrichtenfenster ausgegeben. Dies ist besonders bei Scripten wichtig, die Hunderte
von Informationen ausgeben. In den nächsten Abschnitten dieses Kapitels wird das Ausführen
von Scripten detaillierter besprochen.

Scripte über die Kommandozeile ausführen


Auch wenn wir uns im Zeitalter der grafischen Benutzerschnittstellen befinden, arbeiten viele
Administratoren oft mit einer Eingabeaufforderung statt mit der grafischen
Benutzerschnittstelle. Mit dem WSH können Sie Script sowohl in der Eingabeaufforderung
als auch über die GUI starten. In der Kommandozeile stehen Ihnen die gleichen
Möglichkeiten wie über die GUI zur Verfügung - zusätzlich bietet Ihnen CScript jedoch zwei
Vorteile:

Es ist einfach, Argumente an das Script zu übergeben. Diese Argumente können im Script
selbst verwendet werden (Sie können zum Beispiel den Ordner angeben, der vom Script
gelöscht werden soll), oder der Script Host kann sie zur Ausführung des Scripts verwenden.

Mit CScript ist es einfach die Scriptausführung abzubrechen - Sie schließen einfach das
Kommandozeilenfenster oder drücken STRG+C. Wenn ein Script unter WScript ausgeführt
wird, dann können Sie nur den Prozess Wscript.exe über den Taskmanager beenden.
Es gibt zwei Arten, über die Sie in einer Kommandozeile ein Script starten können:

Sie geben den Namen des Scripts inklusive der Dateierweiterung an:
HardwareAudit.vbs

Sie geben den Namen eines der beiden Script Hosts gefolgt vom Namen des Scripts an:
cscript HardwareAudit.vbs
wscript HardwareAudit.vbs
Bei der ersten Methode entscheidet der Kommandozeileninterpreter, welcher Script Host
verwendet wird. In diesem Fall wird das Script unter dem auf dem Computer konfigurierten
Standard-Script Host ausgeführt. Bei der zweiten Methode entscheiden Sie selbst, unter
welchem Script Host das Script ausgeführt wird.

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.

Tabelle 3.2: Script Host-Parameter


Parameter Beschreibung

Seite 116 von 394


Parameter Beschreibung
//B Batch-Modus; unterdrückt alle Benutzereingaben und Scriptfehler.
Wenn ein Script zum Beispiel eine Ausgabe über Wscript.Echo durchführt,
dann wird diese im Batch-Modus nicht angezeigt. Auch VBScript-Funktionen
wie Msgbox werden unterdrückt. Der Standardmodus ist der interaktive Modus.
//D Aktiviert den Microsoft Script Debugger, wenn dieser installiert ist. Der Script
Debugger wird zusammen mit Windows 2000 zur Verfügung gestellt - er
wird standardmäßig jedoch nicht installiert. Windows XP stellt keinen Script
Debugger zur Verfügung.

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

Die Fehlermeldung sieht so aus:

Eingabefehler: Für die Dateierweiterung '.admin'


gibt es kein Skriptmodul.

Wenn Sie das Script jedoch mit dem Parameter //E starten, wird es
korrekt ausgeführt:

cscript //E:vbscript test.admin

Wenn Sie nicht die standardmäßigen Dateierweiterungen verwenden,


dann schützen Sie sich dagegen, ein Script versehentlich durch einen
Doppelklick zu starten. Sie müssen jedoch in diesem Fall bei jeder
Ausführung des Scripts den Schalter //E verwenden.
//H:CScript Konfiguriert Cscript.exe oder Wscript.exe als Standard-Script Host.
oder
//H:WScript
//I Interaktiver Modus; alle Ausgaben werden wie im Script vorgesehen
angezeigt. Dies ist der Standardmodus - die Alternative wäre der
Batch-Modus.
//logo Zeigt ein Logo an, wenn das Script unter CScript ausgeführt wird
(das Standardverhalten des WSH). Dieses Logo wird vor der
Ausführung des Scripts angezeigt und sieht folgendermaßen aus:

Microsoft (R) Windows Script Host, Version 5.6

Seite 117 von 394


Parameter Beschreibung

Copyright (C) Microsoft Corporation 1996-2001. Alle Rechte


vorbehalten.
//nologo Verhindert die Anzeige des Logos.

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:

cscript //nologo //S

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.

Die Scriptausgaben in eine Textdatei umleiten


Stellen Sie sich vor, Sie möchten ein Script ausführen, und die von diesem Script erhaltenen
Informationen erst später analysieren. Zum Beispiel, wenn Sie ein Script verwenden, das alle
auf einem Domänencontroller installierten Programm ausgibt, und Sie diese Liste erst
benötigen, wenn Sie den Domänencontroller wiederherstellen müssen.
In einem solchen Fall wäre es sehr praktisch, wenn Sie die Scriptausgaben in einer Datenbank
oder einer Textdatei speichern könnten - beides ist möglich. Wenn Ihr Script die Ausgaben
immer irgendwo speichern soll, dann werden Sie wahrscheinlich eine entsprechende
Funktionalität in dieses Script einbauen. Was aber, wenn die Scriptausgaben nur einmalig
gespeichert werden sollen? Wenn Ihr Script die Ausgaben über WScript.Echo durchführt,
dann können Sie ein einem solchen Fall die Scriptausgaben in eine Textdatei umleiten. Die
Ausgaben werden bei diesem Verfahren einfach in der Textdatei gespeichert und nicht auf
dem Bildschirm angezeigt.
Der Kommandozeileninterpreter bietet Ihnen hierzu zwei Wege an. Mit dem Zeichen gefolgt
von einem Dateinamen werden die Ausgaben in einer Textdatei gespeichert. Alles, was sich
in dieser Datei bereits befindet, wird überschrieben. Der folgende Kommandozeilenbefehl
speichert zum Beispiel die Ausgaben des Scripts in der Textdatei c:\scripts\services.txt:
cscript service_info.vbs &#62; c:\scripts\services.txt

Seite 118 von 394


Mit dem Zeichen können Sie die Daten an die entsprechende Textdatei anhängen. In diesem
Fall werden die vorhandenen Inhalte der Textdatei nicht überschrieben:
cscript service_info.vbs &#62;&#62; c:\scripts\services.txt
Außerdem sollten Sie den Parameter //nologo verwenden, um zu verhindern dass das Logo in
der Textdatei gespeichert wird:
cscript //nologo service_info.vbs &#62; c:\scripts\services.txt
Wenn Sie die Ausgaben eines Scripts in eine Textdatei umleiten, werden keine Informationen
auf dem Bildschirm angezeigt. Stattdessen gehen alle Ausgaben (auch Fehlermeldung) in die
Textdatei.

Ausführung von Scripten planen


Mit dem Windows 2000 Taskplaner oder dem Kommandozeilentool At.exe können Sie die
Ausführung von Scripten vorausplanen. Die Scripte werden dann ohne Ihr Zutun ausgeführt.
Nehmen wir zum Beispiel einmal an, Sie verwenden ein Script, dass einmal in der Woche
ausgeführt wird und die Ereignisprotokolle auf allen Domänencontrollern sichert und leert.
Wenn sie dieses Script als Task planen, müssen Sie nicht mehr selbst daran denken das Script
regelmäßig auszuführen.
Geplante Tasks können Sie auch über WMI erstellen, löschen und verwalten (weitere
Informationen hierzu finden Sie im Kapitel Creating Enterprise Scripts dieses Buches). Das
folgende Script erstellt zum Beispiel einen Task, der das Script monitor.vbs jeden Montag,
Mittwoch und Freitag um 12:30 Uhr ausführt:
Set Service = GetObject("winmgmts:")
Set objNewJob = Service.Get("Win32_ScheduledJob")
errJobCreated = objNewJob.Create _
("cscript c:\scripts\monitor.vbs", "********123000.000000-420", _
True , 1 OR 4 OR 16, , , JobID)
Wscript.Echo errJobCreated

Andere Verfahren zum Starten eines Scripts


In den meisten Fällen wird ein Systemadministrator ein Script wohl über die Kommandozeile
oder über einen geplanten Task starten. Es gibt jedoch noch einige weitere Möglichkeiten:

Scripte auf Remotecomputern starten: Das Objekt WshController ermöglicht es Ihnen
WSH-basierte Scripte auf Remotecomputern auszuführen. Weitere Informationen hierzu
finden Sie im Abschnitt WSHController Object weiter unten in diesem Kapitel.

Scripte über den Windows Explorer starten: Natürlich können Sie ein WSH-Script auch
über einen Doppelklick im Windows Explorer starten. Es wird dann mit dem Standardhost
ausgeführt. Wenn es sich beim Standardhost um CScript handelt, dann wird ein
Kommandozeilenfenster geöffnet. Dieses wird wieder geschlossen, sobald das Script beendet
ist.

Scripte über das Kontextmenü starten: Sie können ein WSH-Script starten, indem Sie mit
der rechten Maustaste auf die Scriptdatei klicken, und die entsprechende Option auswählen.

Scripte über Drag and Drop starten: Sie können ein Script starten, indem Sie es auf eine
oder mehrere Dateien oder Ordner ziehen. Hierbei wird dem Script Host automatisch der
vollständige Pfad der Datei oder des Ordners übergeben, auf den Sie das Script gezogen
haben.

Seite 119 von 394


Das folgende Script zeigt zum Beispiel den Pfadnamen jedes Ordners oder jeder Datei an, auf
den es gezogen wird:
For Each strArgument in Wscript.Arguments
Wscript.Echo strArgument
Next
Diese Verfahren können Sie sehr gut verwenden, wenn Sie mit Scripten arbeiten, die Datei-
oder Ordnernamen als Parameter erwarten. Stellen Sie sich zum Beispiel vor, Sie ziehen
mehrere Dateien auf ein Script, und das Script kopiert diese automatisch auf einen
Remoteserver.
Die Länge aller Parameter eines Scripts ist jedoch durch den Kommandozeileninterpreter auf
2048 Zeichen begrenzt.

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.

Das Objekt WScript


Das Objekt WScript bietet Ihnen eine große Menge von Funktionalitäten. Egal welche
Scriptsprache Sie verwenden, einige Schlüsselaufgaben (zum Beispiel das Einbinden von

Seite 120 von 394


COM-Objekten und das Entgegennehmen von Kommandozeilenargumenten) können Sie so
immer ausführen.
Abhängig von der verwendeten Scriptsprache kann es sein, dass Sie das WScript-Objekt nicht
benötigen. VBScript stellt zum Beispiel ebenfalls eine Funktion GetObject zur Verfügung,
über die Sie COM-Objekte einbinden können. Da die Syntax dieser Funktion viel einfacher
als ihr WScript-Equivalent ist, werden Sie diese wahrscheinlich viel häufiger verwenden.
Andererseits gibt es in VBScript keine Funktionen zur Verarbeitung von
Kommandozeilenargumenten. Es hindert Sie jedoch nichts daran, die entsprechenden
WScript-Funktionen unter VBScript zu verwenden. Die Möglichkeit, die Methoden und
Funktionen der Scriptsprache und von WScript gemischt zu verwenden, ist einer der
Hauptvorteile der WSH-Umgebung.
In Abbildung 3.3 sehen Sie die Eigenschaften und Methoden des WScript-Objekts und der
Collections WshArguments, WshUnnamed und WshNamed.

Abbildung 3.3: Das Objektmodell von WScript


Auf das Objekt WScript zugreifen
Das Objekt WScript steht in allen WSH-Scripten zur Verfügung, ohne dass Sie es einbinden
müssen. Die folgende Codezeile können Sie überall in Ihrem Script verwenden, ohne die
Methode CreateObject aufrufen zu müssen:

Seite 121 von 394


Wscript.Echo "Keine Bindung erforderlich."
Das Objekt steht deshalb immer zur Verfügung, weil die Methoden CreateObject und
GetObject über dieses Objekt zur Verfügung gestellt werden. Wenn es nicht ständig zur
Verfügung stände, dann könnten Sie ohne die beiden Methoden keine weiteren COM-Objekte
einbinden.

Funktionen von WScript


Das WScript-Objekt soll Ihnen hauptsächlich einige grundlegende Funktionalitäten zur
Verfügung stellen - diese Funktionalitäten sehen Sie in Tabelle 3.3. Die einzelnen Methoden
und Eigenschaften werden in den folgenden Abschnitten dieses Kapitels genauer beschrieben.

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.

Eine neue Instanz eines COM-Objektes erstellen


Um eine neue Instanz eines COM-Objektes zu erstellen, können Sie die Methode
CreateObject des Objektes WScript verwenden. Diese Methode erwartet als Parameter den
Programmatic Identifier (ProgID) des COM-Objektes. Die genaue Syntax sieht so aus:
WScript.CreateObject("ProgID")
Um die Analogie mit der Bibliothek wieder aufzugreifen: Die ProgID ist das Equivalent zur
Ablagenummer des Buches. Wenn Sie in die Bibliothek gehen, geben Sie dem Bibliothekar
diese Ablagenummer, und er oder sie sucht das Buch für Sie heraus. Wenn Sie dem Scripting

Seite 122 von 394


Host die ProgID geben, dann kann der Host in der Registrierung nach dem COM-Objekt
suchen, das Sie erstellen möchten.
Woher wissen Sie nun die richtige ProgID eines COM-Objektes? Unglücklicherweise gibt es
keine einfache Antwort auf diese Frage. Der einfachste Weg ist es, wenn Sie in die
Dokumentation dieses Objektes schauen. Alle ProgIDs werden unter
HKEY_CLASSES_ROOT in der Registrierung gespeichert. Ein Beispiel sehen Sie in
Abbildung 3.4. Diese ProgID-Liste ist jedoch leider nur von eingeschränktem Nutzen, da
nicht alle ProgIDs in Scripten verwendet werden können.

Abbildung 3.4: ProgIDs in der Regisrierung


Um ein neu erstelltes Objekt verwenden zu können, muss Ihr Script eine Referenz auf das
Objekt in einer Variablen speichern:
SetobjVariable= WScript.CreateObject (" ProgID" )
Nachdem die Referenz in einer Variablen gespeichert wurde, kann das Script über die Punkt-
Notation auf die Methoden und Eigenschaften des Objekts zugreifen (die Punkt-Notation wird
im Kapitel VBScript Primer dieses Buches besprochen).
Eine Methode können Sie über die folgende Syntax aufrufen:
objVariable.Methodenname
Der Zugriff auf Eigenschaften verwendet die gleiche Syntax:
objVariable.Eigenschaftsname
Script 3.1 erstellt eine neue Instanz des ADSI-Objektes ADSystemInfo und speichert die
Referenz auf das Objekt in der Variablen objSysInfo. Dann zeigt es den DNS-Namen der
Domäne des angemeldeten Benutzers an.

Script 3.1: Ein COM-Objekt verwenden

1Set objSysInfo = Wscript.CreateObject("ADSystemInfo")


2Wscript.Echo "Domain DNS name: " & objSysInfo.DomainDNSName

Seite 123 von 394


Wie Sie in Abbildung 3.5 sehen, müssen Sie nur zwei Teile des Befehls ändern, wenn Sie ein
anderes COM-Objekt verwenden möchten - die ProgID und den Namen der Referenzvariable
(die Variable brauchen Sie nur zu ändern, wenn Ihr Script mehrere Objekte verwenden soll).

Abbildung 3.5: Elemente des Befehls, der ein COM-Objekt erstellt


Das folgende Script bindet zum Beispiel mehrere COM-Objekte ein:
Set objReference = Wscript.CreateObject("Word.Application")
Set objReference = Wscript.CreateObject("InternetExplorer.Application")
Set objReference = Wscript.CreateObject("Scripting.Dictionary")
Set objReference = Wscript.CreateObject("Wscript.Network")
Eine Verbindung zu einer bestehenden Instanz eines COM-Objektes aufbauen
Wenn das COM-Objekt, das Sie verwenden möchten, bereits ausgeführt wird, können Sie
auch dieses verwenden - Sie müssen in diesem Fall keine neue Instanz erstellen. Hierzu
verwenden Sie die Methode GetObject des WScript-Objektes. Diese gibt Ihnen eine Referenz
auf das bestehende Objekt zurück.
Wenn Sie Scripte schreiben, die WMI oder ADSI verwenden, dann werden Sie normalerweise
immer die Methode GetObject verwenden. Das liegt daran, dass WMI und ADSI
standardmäßig bereits zur Verfügung stehen (den WMI-Dienst können Sie zwar auch
anhalten, aber wenn Sie ein Script ausführen, das WMI verwendet, dann wird der Dienst
automatisch neu gestartet). Auch wenn es Ausnahmen gibt, wird das typische WMI-Script
wohl meist mit einer Zeile wie der folgenden anfangen:
Set objWMIService = Wscript.GetObject("winmgmts:")
Vergleich der VBScript Funktionen CreateObject und GetObject mit den entsprechenden
WSH-Funktionen
Auch VBScript stellt die Funktionen CreateObject und GetObject zur Verfügung. Wenn sie
mit der ProgID des COM-Objektes als Parameter aufgerufen werden, erstellt sowohl die
VBScript-Funktion CreateObject als auch Ihr WScript-Equivalent eine Instanz des COM-
Objektes. Die folgenden zwei Codezeilen machen genau das Gleiche - die erste verwendet die
VBScript-Version von CreateObject und die zweite die WSH-Version:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFSO = Wscript.CreateObject("Scripting.FileSystemObject")
Beide Versionen von CreateObject akzeptieren auch einen zweiten Parameter - er wird jedoch
bei beiden Methoden komplett anders interpretiert. Sehen Sie sich die folgenden zwei
Codezeilen an. Wiederum wird in der ersten Zeile die VBScript-Version und in der zweiten
Zeile die WSH-Version verwendet:
Set objExcel = CreateObject("Excel.Application", "Parameter2")
Set objExcel = Wscript.CreateObject("Excel.Application", "Parameter2")
Die CreateObject-Funktion von VBScript interpretiert den zweiten Parameter als Name eines
Remotecomputers - in dem oben gezeigten Beispiel versucht die Methode eine Instanz von
Microsoft Excel auf dem Remotecomputer mit dem Namen Parameter2 zu erstellen. Die
WScript-Version von CreateObject interpretiert den zweiten Parameter hingegen als Prefix
einer Subroutine, die verwendet werden soll, wenn Ereignisse für das Objekt auftreten.

Seite 124 von 394


Um einfach nur ein COM-Objekt zu erstellen, können Sie beide Funktionen verwenden. Es
gibt in diesem Fall keinen Unterschied. Wenn Sie jedoch ein Remoteobjekt erstellen möchten
oder auf Ereignisse des Objektes reagieren müssen, dann sollten Sie die passende Version der
Methode auswählen. Weitere Informationen zu den Funktionen CreateObject und GetObject
von VBScript finden Sie im Kapitel VBScript Primer dieses Buches.

Eingaben und Ausgaben


Scripte müssen mit Benutzern interagieren. Ein Script, das das Ereignisprotokoll nach
bestimmten Ereignissen durchsucht, sollte auch mitteilen können, wenn passende Ereignisse
gefunden wurden. Oder stellen Sie sich vor, Sie schreiben ein Script dass die Verbindung
zwischen zwei Computern testet. Sie benötigen für dieses Script eine einfache Möglichkeit,
die beiden Computernamen als Eingabe entgegenzunehmen.
WSH stellt Mittel zur Interaktion mit dem Benutzer und - möglicherweise viel wichtiger -
Mittel für eine Eingabe und Ausgabe in der Kommandozeile zur Verfügung. Neben vielen
anderen Dingen haben Sie so die Möglichkeit Scripte zu erstellen, die Sie wie
Kommandozeilenwerkzeuge verwenden können.
Ein einfacher Weg eine Ausgabe zu erzeugen, ist die Methode WScript.Echo. Sie erwartet
einen Parameter (einen String, eine Zahl oder ein Datum) und gibt diesen Parameter auf dem
Bildschirm aus. Script 32. verwendet die Methode WScript.Echo, um die auf dem Computer
installierte WSH-Version auszugeben.

Script 3.2: Anzeige der installierten WSH-Version

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.

Seite 125 von 394


Abbildung 3.6: Methoden und Eigenschaften der TextStream-Objekte
Nachrichten ausgeben
Ein primärer Zweck von administrativen Scripten ist das Abfragen von Informationen. Wie
viel freier Festplattenplatz steht noch zur Verfügung? Unter welchem Konto werden die
Internetinformationsdienste ausgeführt? Welche Prozesse verbrauchen den gesamten freien
Speicher auf dem Mailserver?
Ein Script, das solche Fragen beantwortet, muss eine Möglichkeit haben, mit dem Benutzer zu
kommunizieren. Auch wenn es die Informationen auch in einer Textdatei oder einer
Datenbank speichern könnte, ist es doch einfacher, wenn sie direkt auf dem Bildschirm
ausgegeben werden. Der WSH kann solche Bildschirmausgaben über die Methode Echo
durchführen.
Wenn ein Script unter CScript ausgeführt wird, dann gibt die Methode WScript.Echo die
Informationen in der Eingabeaufforderung aus. Unter WScript werden die Informationen
hingegen in einem Nachrichtenfenster angezeigt. Die folgende Codezeile gibt zum Beispiel
das Ergebnis einer Berechnung aus:
Wscript.Echo 2 + 2
Die Echo-Methode ist einfach zu implementieren. Sie geben ihr einfach die Informationen als
Parameter mit, die auf dem Bildschirm angezeigt werden sollen - zum Beispiel über eine
Variable:

Seite 126 von 394


Wscript.Echo strMyVariable
Auch die Inhalte von VBScript, wie zum Beispiel Now und Time, können Sie ausgeben:
Wscript.Echo Now
Um einen String auszugeben, schließen Sie diesen in Anführungsstriche ein:
Wscript.Echo "This is my string."
Das einzig wirklich Wichtige, das Sie bei der Arbeit mit WScript.Echo berücksichtigen
müssen, ist das unterschiedliche Verhalten unter WScript und CScript. Script 3.3 gibt zum
Beispiel drei Nachrichten über WScript.Echo aus:

Script 3.3: Ausgabe von drei Nachrichten über die Methode Echo

1Wscript.Echo "Prüfung der Systemlaufwerke "


2Wscript.Echo "Abfragen des freien Speicherplatzes "
3Wscript.Echo "Zuordnen von Netzlaufwerken "
Wenn Sie das Script unter CScript ausführen, sehen Sie im Kommandozeilenfenster die
folgende Ausgabe:
Prüfung der Systemlaufwerke
Abfragen des freien Speicherplatzes
Zuordnen von Netzlaufwerken
Wenn Sie das Script unter WScript ausführen, produziert es die drei einzelnen
Nachrichtenfenster, die Sie in Abbildung 2.7 sehen. Der Benutzer muss in jedem dieser
Nachrichtenfenster auf OK klicken, damit das Script weiter ausgeführt wird.

Abbildung 3.7: Echo-Methode unter WScript


Unter WScript führt jeder Aufruf von WScript.Echo zu einem neuen Nachrichtenfenster.
Abhängig vom Script kann das sehr mühsam werden. Bei einem kleinen Script, das den freien
Speicherplatz auf Laufwerk C abfragt, ist es normalerweise egal, ob die Ausgabe in der
Kommandozeile oder in einem Nachrichtenfenster angezeigt wird. Wenn des Script jedoch
den Status aller Dienste zurückgibt, dann müssen Sie im Zweifelsfall in vielen Dutzend
Nachrichtenfenstern auf OK klicken.
Unter CScript würden alle Informationen ohne Aktion des Benutzers im
Kommandozeilenfenster ausgegeben.

Texteingaben und -ausgaben


Kommandozeilenwerkzeuge arbeiten typischerweise mit drei standardmäßigen Eingabe- und
Ausgabemöglichkeiten - diese werden auch als Standard In (StdIn), Standard Out (StdOut)
und Standard Error (StdErr) bezeichnet. Wenn sie es nicht anders festgelegt haben, geht der
Kommandozeilenprozessor davon aus, dass die Eingaben über die Tastatur (StdIn), die
Ausgaben (StdOut) und Fehlernachrichten (StdErr) in der Kommandozeile ausgegeben
werden sollen.

Seite 127 von 394


StdIn, StdOut und StdErr stehen nur zur Verfügung, wenn das Script unter CScript ausgeführt
wird. Über diese drei Objekte können Sie die drei unterschiedlichen Ein- und
Ausgabemöglichkeiten in Ihren Scripten nutzen:

Sie können Ausgaben im Kommandozeilenfenster durchführen.

Sie können im Kommandozeilenfenster Eingaben durch den Benutzer einlesen.

Sie können Fehlerinformationen in Ihrem Script entgegennehmen, die von anderen Scripten,
Batchdateien oder Kommandozeilentools ausgegeben werden.
Ausgaben über StdOut durchführen
Über StdOut können sie Ausgaben im Kommandozeilenfenster durchführen. Die einzelnen
Methoden von StdOut sehen Sie in Tabelle 3.4.

Tabelle 3.4: Methode von StdOut


Methode Beschreibung
Write Gibt den übergebenen Parameter auf dem Bildschirm aus.
Hängt jedoch keinen Zeilenumbruch an. Das folgende Script führt zum
Beispiel vier Ausgaben durch:

Wscript.StdOut.Write "ABCD"
Wscript.StdOut.Write "EFGHIJKLMN"
Wscript.StdOut.Write "OPQRSTUV"
Wscript.StdOut.Write "WXYZ"

Die Ausgabe des Scripts sieht so aus:

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"

Die Ausgabe des Scripts sieht dieses Mal jedoch so aus:

ABCD EFGHIJKLMN OPQRSTUV WXYZ


WriteBlankLinesGibt Leerzeilen aus. Als Parameter benötigt WriteBlankLines die
Anzahl der auszugebenden Leerzeilen:

Seite 128 von 394


Methode Beschreibung
Wscript.StdOut.WriteLine "ABCD"
Wscript.StdOut.WriteBlankLines 1
Wscript.StdOut.WriteLine "EFGHIJKLMN"
Wscript.StdOut.WriteLine "OPQRSTUV"
Wscript.StdOut.WriteBlankLines 2
Wscript.StdOut.WriteLine "WXYZ"

Das Script produziert die folgende Ausgabe:

ABCD

EFGHIJKLMN
OPQRSTUV

WXYZ
Script 3.4 zeigt eine Nachricht über die Methoden Write und WriteLine des Objektes
StdOut.TextStream an.

Script 3.4: Verwendung der Methoden Write und WriteLine im


Kommandozeilenfenster

1 Set objNetwork = Wscript.CreateObject("Wscript.Network")


2 Set objStdOut = WScript.StdOut
3 objStdOut.Write "Benutzer: "
4 objStdOut.Write objNetwork.UserDomain
5 objStdOut.Write "\"
6 objStdOut.Write objNetwork.UserName
7 objStdOut.WriteBlankLines(1)
8 objStdOut.WriteLine objNetwork.ComputerName
9 objStdOut.Write "Informationen abgefragt."
10objStdOut.Close
Die Ausgabe von Script 3.4 sieht so aus:
Benutzer: FABRIKAM\kenmyer

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

Seite 129 von 394


Ein Weg, um in einem Script Eingaben entgegenzunehmen, sind Argumente (diese werden
weiter unten in diesem Kapitel besprochen). Der folgende Befehl führt ein Script mit dem
Namen DeleteUser.vbs aus und übergibt als Argument den zu löschenden Benutzernamen:
cscript DeleteUser.vbs kenmyer
Die Verwendung von Argumenten ist schnell und einfach umzusetzen. Andererseits muss der
Benutzer bei der Verwendung des Scripts wissen, welche Argumente es gibt und wie er diese
benutzen kann. Es gibt jedoch eine Alternative - fordern Sie den Benutzer zu Eingabe der
benötigten Informationen auf, nachdem das Script gestartet wurde:
C:\Scripts\cscript DeleteUser.vbs
Bitte geben Sie den Namen des zu löschenden Benutzerkontos an: _
Mit StdIn können Sie Eingaben in der Kommandozeile entgegennehmen. Die Methoden und
Eigenschaften von StdIn sehen Sie in Tabelle 3.5.

Tabelle 3.5: Methoden und Eigenschaften von StdIn


Methode/EigenschaftBeschreibung
Read Liest die angegebene Anzahl an Zeichen ein. Der folgende Befehl liest
zum Beispiel jeweils drei Zeichen über StdIn ein und gibt diese
wieder aus, bis ein Zeilenumbruch (ENTER) eingegeben wurde:

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

Seite 130 von 394


Methode/EigenschaftBeschreibung
und liest die verbleibenden Zeichen auf einmal ein:

Wscript.StdIn.Skip(23)
Do Until Wscript.StdIn.AtEndOfLine
strInput = Wscript.StdIn.Read(1)
Wscript.Echo strInput

Bei der Eingabe 'abcdefghijklmnopqrstuvwxyz' sieht die Ausgabe


des Scripts so aus:
x
y
z
SkipLine Überspringt eine Zeile.
AtEndOfLine Ein Boolean-Wert (ein Wert, der nur zwei Zustände haben
kann - typischerweise True und False), der anzeigt, ob das
Ende einer Zeile erreicht wurde. Über diese Eigenschaft kann
das Script erkennen, ob die gesamte Zeile eingelesen wurde -
in diesem Fall hat sie den Wert True.

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

Seite 131 von 394


dezimale Zahl eingeben lassen. Script 3.5 verwendet hierzu die Methode ReadLine des
WScript-Objekts StdIn. Der eingelesene Wert wird dann in der Variablen strDecimal
gespeichert. Die Funktion Hex von VBScript konvertiert den gespeicherten dezimalen Wert
dann in einen hexadezimalen Wert - dieser wird dann über die Methode WriteLine des
WScript-Objekts StdOut ausgegeben.

Script 3.5: Konvertierung eines dezimalen Wertes in einen hexadezimalen Wert

1Wscript.StdOut.Write "Geben Sie eine Dezimalzahl ein: "


2strDecimal = Wscript.StdIn.ReadLine
3
4Wscript.StdOut.WriteLine strDecimal & " entspricht dem Wert " & _
5 Hex(strDecimal) & " in hexadezimaler Schreibweise."
Wenn Sie das Script unter CScript ausführen, sieht die Ausgabe so aus:
C:\&#62;cscript test.vbs
Microsoft (R) Windows Script Host, Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Alle Rechte vorbehalten.

Geben Sie eine Dezimalzahl ein: 254


254 entspricht dem Wert FE in hexadezimaler Schreibweise.

Verwenden von Kommandozeilenargumenten


Argumente sind Werte, die Sie beim Start des Scripts in der Kommandozeile angeben können.
Wenn Sie bereits mit Kommandozeilentools gearbeitet haben, dann kennen Sie das Konzept
wahrscheinlich. Wenn Sie zum Beispiel ping.exe ausführen, dann müssen Sie mindestens
einen Hostnamen oder eine IP-Adresse als Argument (auch Parameter genannt) angeben:
ping 192.168.1.1
Das Aufrufen eines Scripts mit einem Argument ist in den Fällen sehr praktisch, in denen Sie
bei jedem Aufruf des Scripts einen anderen Wert übergeben möchten. Wenn Sie den
entsprechenden Wert fest in das Script eintragen würden, dann müssten Sie das Script vor
jedem Aufruf bearbeiten. In diesen Fällen sparen Sie sich also mit
Kommandozeilenargumenten eine Menge Zeit.
Die Arbeit mit Script-Argumenten unterscheidet sich nicht von der Arbeit mit
Kommandozeilentools. Sie können Script-Argumente genauso verwenden, wie Sie zum
Beispiel Argumente (Parameter) bei ping.exe angeben (IP-Adresse, -t, usw.).
Argumente werden in einer Collection mit dem Namen WshArguments gespeichert. Über die
Eigenschaft Arguments des Objekts WScript können Sie auf diese Collection zugreifen - dies
sehen Sie in Abbildung 3.8. Außerdem werden die Argumente automatisch nach deren
Format gefiltert und zusätzlich in die beiden Collections WshNamed und WshUnnamed
einsortiert.

Seite 132 von 394


Abbildung 3.8: Collections mit Kommandozeilenargumenten
Ablage und Filterung der Argumente
Wenn Sie ein Script mit Argumenten starten, dann speichert der WSH diese Argumente in der
Collection WshArguments - und zwar in der Reihenfolge, in der Sie beim Start des Scripts
angegeben wurden. WScript.Arguments.Item(0) enthält das erste Argument,
WScript.Arguments.Item(1) enthält das zweite usw.
Die Argumente werden jedoch zusätzlich in zwei weiteren Collections gespeichert:
WshNamed und WshUnnamed. Argumente, die im Format /name:wert angegeben wurden,
werden in WshNamed gespeichert, und alle Argumente, die nicht dieses Format verwenden,
werden in WshUnnamed gespeichert. Der Sinn dieser zusätzlichen gefilterten Speicherung
wird weiter unten in diesem Abschnitt genauer besprochen.
Wenn Sie zum Beispiel den folgenden Befehl ausführen, dann starten Sie das Script
ServerStats.vbs mit den drei Argumenten /s:atl-dc-01, /u:admin und perf.
cscript serverstats.vbs /s:atl-dc-01 /u:admin perf
Die Argumente werden nach dem Scriptnamen angegeben und müssen durch ein oder
mehrere Leerzeichen getrennt werden. Argumente, die selbst Leerzeichen enthalten, müssen
in Anführungszeichen eingeschlossen werden. Ein Beispiel hierfür ist das dritte Argument
("perf monitor")im folgenden Befehl:

Seite 133 von 394


cscript serverstats.vbs /s:atl-dc-01 /u:admin "perf monitor"
Ohne die Anführungsstriche würden perf und monitor als zwei einzelne Argumente behandelt
werden.
In Abbildung 3.9 sehen Sie die Inhalte der drei Argument-Collections, nachdem Sie ein Script
mit dem Namen status.vbs und den drei Argumenten /s:atl-dc-01, /u:admin und perf gestartet
haben.

Abbildung 3.9: Inhalte der Argument-Collections


In der Collection WshArguments werden alle Argumente genauso gespeichert, wie Sie in der
Kommandozeile angegeben wurden. Die Methode Count und die Eigenschaft Length geben
die Gesamtzahl der übergebenen Argumente zurück.
In der Collection WshNamed sind die zwei Argumente gespeichert, die zusätzlich 'Werte'
angeben. Solche Argumente bestehen immer aus zwei Teilen: dem Argument selbst (zum
Beispiel /u) und dem Wert für dieses Argument (zum Beispiel admin). Argument und Wert
werden hierbei durch einen Doppelpunkt getrennt (zum Beispiel /u:admin). Das Argument
muss in diesem Fall immer mit einem Slash (/) angegeben werden. Es ist nicht möglich,
alternativ ein Minuszeichen (-) zu verwenden. Der folgende Befehl führt zum Beispiel nicht
dazu, dass das Argument in der Collection WshNamed gespeichert wird. Stattdessen wird das
Argument in der Collection WSHUnnamed gespeichert:
cscript serverstats.vbs -Server:atl-dc-01
Wenn Sie sich Abbildung 3.9 genau ansehen, dann werden Sie feststellen, dass die
Argumente in der Collection WshNamed vor deren Speicherung verändert werden. Der
'Argument-Teil' des Arguments (also zum Beispiel der Teil /s) wird zum Index und kann über
die Eigenschaft Item der Collection WshNamed verwendet werden, um den 'Wert-Teil' (zum

Seite 134 von 394


Beispiel at1-dc-01) des Arguments abzufragen. Auch für die Methode Exists der Collection
WshNamed können Sie den 'Argument-Teil' verwenden. Diese Methode prüft, ob das
entsprechende Argument beim Scriptstart angegeben wurde. Wie Sie in Abbildung 3.9 sehen,
werden Slash und Doppelpunkt verworfen, und nur der tatsächliche Parametername (s) und
der Wert des Parameters (at-dc-01) werden in der Collection gespeichert. Wie in der
Collection WshArguments auch, können Sie in der Collection WshNamed über die Methoden
Count und die Eigenschaft Length die Anzahl der Argumente in der Collection abrufen.
Es gibt also drei Wege, um auf die Kommandozeilenargumente zuzugreifen:

Sie können über die Collection WshArguments auf alle Argumente zugreifen.

Über die Collection WshNamed können Sie nur auf die Argumente zugreifen, bei denen ein
zusätzlicher Wert angegeben wurde (zum Beispiel /s:at-dc-01).

Über die Collection WshUnnamed können Sie auf die Argumente zugreifen, bei denen keine
zusätzlichen Werte angegeben wurden (zum Beispiel /u).
Verwenden der standardmäßigen Argument-Collection WshArguments
Auf die Collection WshArguments greifen Sie über Eigenschaft Arguments des Objekts
WScript zu. Die Collection WshArguments stellt zwei Methoden und vier Eigenschaften für
die Arbeit mit Argumenten zur Verfügung.
Methoden

Count - Gibt die Gesamtzahl der Argumente in der Collection WshArguments zurück.

ShowUsage - Gibt Informationen zur Verwendung des Scripts aus. Diese Informationen
werden dem Abschnitt runtime einer WSF-Datei (Windows Script File - .wsf) entnommen.
WSF-Dateien werden in diesem Buch nicht besprochen.
Eigenschaften

Named - Stellt einen Zugriff auf die Collection WshNamed zur Verfügung. WshNamed ist
eine gefilterte Collection, in der alle Argumente im Format /name:wert gespeichert sind.
Solche Argumente werden im WSH auch 'Named Arguments' (benannte Argumente)
genannt.

Unnamed - Stellt einen Zugriff auf die Collection WshUnnamed zur Verfügung.
WshUnnamed ist eine gefilterte Collection mit den Argumenten, die nicht im Format
/name:wert angegeben wurden. Solche Argumente werden im WSH auch 'Unnamed
Arguments' (unbenannte Argumente) genannt.

Length - Gibt die Gesamtzahl der Argumente in der Collection WshArguments an.

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.

Seite 135 von 394


Mit dem folgenden Befehl wird ein Script mit dem Namen GetEvents.vbs und drei
Argumenten ausgeführt:
cscript getevents.vbs atl-dc-01 "Directory Service" 1130
WSH speichert die drei Argumente in der Reihenfolge in der Collection WshArguments, in
der sie angegeben wurden. Um die drei Argumente auszulesen, verwenden Sie die
Eigenschaft Arguments des Objekts WScript in Kombination der Eigenschaft
WshArguments.Item:
ServerName = WScript.Arguments.Item(0)
EventLog = WScript.Arguments.Item(1)
EventID = WScript.Arguments.Item(2)
Da alle Collections bei 0 beginnen, erhalten Sie mit WScript.Arguments.Item(0) das erste
Argument zurück. WScript.Arguments.Item(1) liefert Ihnen das zweite Argument (dieses
Argument wurde in Anführungszeichen eingeschlossen, da es Leerzeichen enthält).
WScript.Arguments.Item(2) liefert Ihnen das dritte Argument zurück.
Die Inhalte der Collection sehen Sie in Tabelle 3.6.

Tabelle 3.6: Beispielinhalte der Collection WSHArguments


ItemWert
0 atl-dc-01
1 Directory Service
2 1130
Wenn das Script mit weiteren Argumenten aufgerufen worden wäre, dann würde
WScript.Arguments.Item(3) das vierte Argument zurückliefern usw.
Es gibt keine Beschränkung für die Anzahl der Argumente, die in der Collection
WshArguments gespeichert werden können. Die gesamte Befehlszeile darf jedoch die
maximale Länge der Kommandozeile nicht überschreiten.
Sie können sich viel Arbeit sparen, wenn Sie die Collection WshArguments einer Variablen
zuweisen. So brauchen Sie nicht jedes Mal WScript.Arguments schreiben, wenn Sie auf ein
Argument zugreifen möchten, sondern können den Namen der Variable nutzen. Verwenden
Sie hierzu das VBScript-Schlüsselwort Set, gefolgt von dem Variablennamen. Das
Schlüsselwort Set ist erforderlich, da es sich bei Collections um normale COM-Objekte
handelt. Das folgende Beispiel macht genau das Gleiche, wie das vorhergehende Beispiel. Es
verwendet jedoch zum Zugriff auf die Collection eine Variable:
Set args = WScript.Arguments
ServerName = args.Item(0)
EventLog = args.Item(1)
EventID = args.Item(2)
Die letzten drei Beispiele gehen alle davon aus, dass mit GetEvents.vbs immer drei
Argumente übergeben werden. Bei einem eben schnell geschriebenen Ad-Hoc-Script können
Sie möglicherweise darauf verzichten, die Anzahl der übergebenen Argumente zu überprüfen,
bei anderen Scripten kann dies jedoch schnell zu Fehlern führen - ganz besonders dann, wenn
auch andere Benutzer das Script verwenden sollen.
Die folgende Zeile startet das Script GetEvents.vbs ohne Argumente:

Seite 136 von 394


cscript getevents.vbs
In diesem Beispiel würden alle drei oben verwendeten Beispielscripte zu folgendem
Laufzeitfehler führen:
C:\test.vbs(2, 1) Laufzeitfehler in Microsoft VBScript: Index außerhalb des
gültigen Bereichs
Wenn Sie versuchen auf ein Item zuzugreifen, das nicht existiert, kommt es zu diesem
Laufzeitfehler. In Script 3.6 sehen Sie, wie Sie über die Methode WshArguments.Count
sicherstellen können, dass beim Scriptstart die richtige Anzahl von Argumenten verwendet
wurde.

Script 3.6: Anzahl der übergebenen Argumente über Count prüfen

1If WScript.Arguments.Count = 3 Then


2 ServerName = WScript.Arguments.Item(0)
3 EventLog = WScript.Arguments.Item(1)
4 EventID = WScript.Arguments.Item(2)
5Else
6 Wscript.Echo "Verwendung: GetEvents.vbs ServerName EventLog EventID"
7 Wscript.Quit
8End If
In Zeile 1 des Scripts wird die Methode WshArguments.Count verwendet, um die Anzahl der
übergebenen Argumente abzufragen. Wenn es sich um drei Argumente handelt, dann weist
das Script diese den Variablen ServerName, EventLog und EventID zu. Andernfalls gibt das
Script eine Information zur Verwendung des Scripts aus.

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.

Script 3.7: Abfragen der Kommandozeilenargumente über die Collection Arguments

1strServer = WScript.Arguments.Item(0)
2strPacketSize = WScript.Arguments.Item(1)
3strTimeout = WScript.Arguments.Item(2)
4

Seite 137 von 394


5Wscript.Echo "Anzupingender Server: " & strServer
6Wscript.Echo "Paketgröße: " & strPacketSize
7Wscript.Echo "Timeout: " & strTimeout
Die folgende Befehlszeile führt das Script mit Argumenten aus - und zwar in der Reihenfolge,
in der das Script die Argumente erwartet:
EchoUnnamedArgs.vbs DCServer01 100 5000
Das Script erzeugt die folgende Ausgabe:
Anzupingender Server: DCServer01
Paketgröße: 100
Timeout: 5000
Die folgende Befehlszeile führt das gleiche Script aus. Die Argumente werden jedoch in einer
falschen Reihenfolge angegeben:
EchoUnnamedArgs.vbs 100 DCServer01 5000
Das Script produziert die folgende Ausgabe:
Anzupingender Server: 100
Paketgröße: DCServer01
Timeout: 5000
Die Ausgabe im ersten Versuch ist korrekt - die Ausgabe im zweiten Versuch ist hingegen
falsch. Da das Script mit unbenannten Argumenten arbeitet, und diese nicht über Ihren
Namen, sondern nur in der Eingabereihenfolge ausgelesen werden können, ist das Script
darauf angewiesen, dass die Argumente in der korrekten Reihenfolge angegeben werden.
Wenn das Script im zweiten Versuch ping.exe mit den Argumenten ausgeführt hätte, dann
hätte dies zu einem Fehler geführt - es gibt keinen Server mit dem Namen 100 oder eine
Paketgröße von DCServer01.

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:

Seite 138 von 394


ServerTest.vbs /Timeout:3000 /Server:HRServer01
Die benannten Argumente eines Scripts werden in der Collection WshNamed gespeichert.
Script 3.8 verwendet diese Collection, um die Argumente anzuzeigen.

Script 3.8: Abfragen von Argumenten über die Collection WshNamed

1Set colNamedArguments = WScript.Arguments.Named


2
3strServer = colNamedArguments.Item("Server")
4strPacketSize = colNamedArguments.Item("PacketSize")
5strTimeout = colNamedArguments.Item("Timeout")
6Wscript.Echo "Servername: " & strServer
7Wscript.Echo "Paketgröße: " & strPacketSize
8Wscript.Echo "Timeout (ms): " & strTimeout
Über die folgende Befehlszeile wird das Script zusammen mit drei benannten Argumenten
ausgeführt:
EchoNamedArgs.vbs /Server:HRServer01 /PacketSize:300 /Timeout:8000
Das Script erzeugt die folgende Ausgabe
Servername: HRServer01
Paketgröße: 300
Timeout (ms): 8000
Die nächste Befehlszeile führt dasselbe Script aus. Die Argumente werden jedoch in einer
anderen Reihenfolge angegeben:
EchoNamedArgs.vbs /Timeout:8000 /PacketSize:300 /Server:HRServer01
Trotzdem erzeugt auch dieses Script die folgende Ausgabe
Servername: HRServer01
Paketgröße: 300
Timeout (ms): 8000
Die Ausgabe ist bei beiden Befehlszeilen gleich. Sie können die Argumente in jeder
beliebigen Reihenfolge angeben.
Auch wenn Sie optionale Parameter verwenden wollen, sind benannte Argumente sinnvoll.
Script 3.9 entspricht Script 3.8. Das Argument PacketSize ist jedoch optional. Wenn der
Benutzer keine Paketgröße angibt, verwendet das Script eine Standardpaketgröße.
Das Script verwendet die Methode Exists um zu prüfen, ob das Argument PacketSize
angegeben wurde. Wenn das Ergebnis der Prüfung Wahr (True) ist, dann fährt das Script mit
Zeile 7 fort. Wenn das Ergebnis der Prüfung Falsch (False) ist, dann geht es mit Zeile 9
weiter. In Zeile 9 wird die Variable PacketSize über die Konstante
DEFAULT_PACKET_SIZE auf den Wert 100 gesetzt.

Script 3.9: Kommandozeilenargumente und Standardwerte

1 Const DEFAULT_PACKET_SIZE = 100


2
3 Set colNamedArguments = WScript.Arguments.Named
4
5 strServer = colNamedArguments.Item("Server")
6 If colNamedArguments.Exists("PacketSize") Then

Seite 139 von 394


7 strPacketSize = colNamedArguments.Item("PacketSize")
8 Else
9 strPacketSize = DEFAULT_PACKET_SIZE
10End If
11strTimeout = colNamedArguments.Item("Timeout")
12
13Wscript.Echo "Server Name: " & strServer
14If colNamedArguments.Exists("PacketSize") Then
15 Wscript.Echo "Packet Size :" & strPacketSize
16Else
17 Wscript.Echo "Packet Size [default]: " & strPacketSize
18End If
19Wscript.Echo "Timeout (ms): " & strTimeout
Unbenannte und benannte Argumente verwenden
Normalerweise sollten Sie benannte und unbenannte Argumente nicht zusammen in einem
Script verwenden. Der Scriptaufruf wird so nur unnötig kompliziert. Wenn Sie zwei oder ein
Argument verwenden, sollten Sie unbenannte Argumente nutzen. Bei mehr als zwei
Argumenten ist es besser benannte Argumente zu verwenden.
Wenn Sie jedoch beide Argumenttypen zusammen verwenden, dann müssen die unbenannten
Argumente beim Scriptaufruf zuerst angegeben werde:
CheckServer.vbs HRServer01 /timeout:200 /logfile:serverlog.txt /verbose:true

Überprüfen von Kommandozeilenargumenten


Viele Scripte benötigen eine bestimmte Anzahl von Argumenten. Um sicherzustellen, dass die
Argumente angegeben wurden, haben Sie zwei Möglichkeiten:

Sie prüfen, ob die Zahl der angegeben Argumente der erforderlichen Argumentzahl
entspricht.

Sie prüfen, ob die erforderlichen Argumente angegeben wurden.

Die Anzahl der angegebenen Argumente prüfen


Stellen Sie sich vor, Sie schreiben ein Script, das Dateien von einem Computer zum anderen
kopiert. Ein solches Script erfordert wahrscheinlich genau zwei Argumente: den Namen des
Quellcomputers und den Namen des Zielcomputers.
In einem solchen Fall sollten Sie in Ihrem Script als Erstes prüfen, ob die erforderliche
Argumentzahl angegeben wurde. Dies können Sie am einfachsten über die Eigenschaft Count
der entsprechenden Collection durchführen. Wenn Wscript.Arguments.Count den Wert 2 hat,
dann gibt es zwei Argumente.
Script 3.10 prüft die Anzahl der übergebenen Argumente. Das Script akzeptiert bis zu vier
Argumente - zwei von diesen sind optional. Daher muss der Benutzer mindestens zwei und
höchstens vier Argumente angeben.

Script 3.10: Überprüfen der angegebenen Argumente

1iNumberOfArguments = WScript.Arguments.Count
2If iNumberOfArguments &#62;= 2 And iNumberOfArguments &#60;= 4 Then
3 Wscript.Echo iNumberOfArguments & " arguments entered. " & _
4 "Gültige Argumentzahl."

Seite 140 von 394


5Else
6 Wscript.Echo "Fehler: Falsche Argumentzahl angegeben. " & _
7 "Bitte geben Sie 2, 3 oder 4 Argumente an."
8 Wscript.Quit
9End If
In Zeile 1 des Scripts wird über die Eigenschaft WScript.Arguments.Count festgestellt, wie
viele Argumente angegeben wurden. Das Script speichert diese Zahl in der Variable
iNumberOfArguments.
In Zeile 2 verwendet das Script die Bedingung iNumberOfArguments =2 And
iNumberOfArguments =4 um zu prüfen, ob der Benutzer 2, 3 oder 4 Argumente angegeben
hat:

Wenn die Bedingung Wahr (True) ist, dann fährt das Script mit Zeile 3 fort und gibt einen
Text aus, der anzeigt, dass die Argumentzahl gültig war.

Wenn die Bedingung Falsch (False) ist, dann fährt das Script mit Zeile 6 fort und gibt einen
Text aus, der anzeigt, dass die Argumentzahl ungültig war.
Die folgende Befehlszeile führt das Script mit mehr als vier Argumenten aus:
CheckNumArgs.vbs HRServer01 RASServer01 SQLServer01 1000 300
Das Script produziert die folgende Ausgabe:
Fehler: Falsche Argumentzahl angegeben. Bitte geben Sie 2, 3 oder 4
Argumente an.'
Diese Befehlszeile führt das Script mit drei Argumenten aus:
CheckNumArgs.vbs HRServer01 1000 300
Das Script produziert die folgende Ausgabe:
Gültige Argumentzahl.
Überprüfen, ob alle erforderlichen Argumente angegeben wurden
Wenn Sie Argumente in Ihrem Script verwenden, dann sollte das Script überprüfen, ob alle
erforderlichen Argumente angegeben wurden. Unglücklicherweise gibt es keine Möglichkeit
WSH mitzuteilen, dass ein bestimmtes Argument zwingend erforderlich ist. Sie müssen sich
also selbst darum kümmern, dass die erforderlichen Argumente angegeben werden.
Wenn bestimmte Argumente für Ihr Script erforderlich sind, dann sollten Sie benannte
Argumente verwenden. Ein Vorteil von benannten Argumenten ist, dass Sie mit der Methode
Exists prüfen können, ob das Argument angegeben wurde. Die folgende Codezeile prüft, ob
das Argument mit dem Namen FolderName angegeben wurde. Wenn es vorhanden ist, dann
wird der Wert-1 (True) ausgeben - andernfalls lautet die Ausgabe 0 (False):
Wscript.Echo colNamedArguments.Exists("FolderName")
Script 3.11 baut auf Script 3.10 auf. In Zeile 4 verwendet das Script die Bedingung Not
colNamedArgument.Exists("Server") um zu testen, ob der Benutzer das benannte Argument
Server angegeben hat.

Wenn der Test feststellt, dass das Argument nicht angegeben wurde, fährt das Script mit
Zeile 5 fort. Dort wird eine Nachricht ausgegeben, die dem Benutzer mitteilt, dass das
Argument Server fehlt. In Zeile 6 wird der Befehl Wscript.Quit verwendet, um das Script

Seite 141 von 394


anzuhalten.

Wenn der Test feststellt, dass das Argument angegeben wurde, fährt das Script mit Zeile 7
fort. In den Zeilen 9 und 10 wird der Befehl colNamedArguments.Item("Server") verwendet,
um den Wert des Argumentes Server abzufragen. Dann zeigt das Script eine Nachricht an.

Script 3.11: Überprüfen, ob alle erforderlichen Argumente angegeben wurden

1 iNumberOfArguments = WScript.Arguments.Count
2 Set colNamedArguments = WScript.Arguments.Named
3
4 If Not colNamedArguments.Exists("Server") Then
5 Wscript.Echo "Verwendung: /Server:&#60;servername&#62; ist
6 erforderlich."
7 Wscript.Quit
8 ElseIf iNumberOfArguments &#62;= 2 Or iNumberOfArguments &#60;= 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:&#60;servername&#62; 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

Die Scriptausführung steuern


Wenn Sie ein Script ausführen, werden die Befehle im Script normalerweise von oben nach
unten ausgeführt. Es gibt keine Pausen, und das Script ist erst beendet, wenn die letzte
Befehlszeile abgearbeitet wurde.
Das Objekt WScript stellt zwei Eigenschaften (Timeout und Interactive) und zwei Methoden
(Sleep und Quit) zur Verfügung, über die Sie die Scriptausführung kontrollieren können. Sie
haben folgende Möglichkeiten:

Das Script für einen bestimmen Zeitraum anhalten.

Die Scriptausführung sofort beenden.

Die Scriptausführung nach einer bestimmen Zeitspanne beenden.

Ein Script anhalten

Seite 142 von 394


Normalerweise führt WSH ein Script so schnell wie möglich aus. Meist ist dies auch das
gewünschte Verhalten - je schneller das Script beendet ist, desto besser.
Es gibt jedoch auch Fälle, in denen Sie nicht möchten, dass das Script so schnell wie möglich
ausgeführt wird. Zum Beispiel dann, wenn Sie zum Beispiel alle 10 Sekunden die
Prozessorauslastung abfragen möchten - und zwar so lange, bis 100 Messungen
vorgenommen wurden.
Sie können die Ausführung eines Scripts mit der Methode Sleep des Objekts WScript für
einen bestimmen Zeitraum anhalten. Die Methode erwartet als Parameter den Zeitraum in
Millisekunden, für den das Script angehalten werden soll (eine Sekunde hat 1.000
Millisekunden und eine Minute hat 60.000 Millisekunden).
In folgenden Situationen können Sie die Methode Sleep verwenden:

Wenn Sie auf ein bestimmtes Ereignis warten müssen.

Wenn Sei möchten, dass Ihr Script einen bestimmten Status in regelmäßigen Zeitabständen
prüft (zum Beispiel alle 10 Sekunden die Prozessorauslastung).

Wenn Sie die Interaktion mit dem Benutzer auf ein vernünftiges Maß herunterbremsen
möchten. Wenn Sie zum Beispiel die Einträge des Ereignisprotokolls anzeigen lassen,
möchten Sie möglicherweise, dass eine kurze Pause zwischen den einzelnen Ausgaben liegt.
Script 3.12 prüft den freien Festplattenplatz aller Laufwerke des Computers. Dann wartet das
Script 5 Minuten (300.000 Millisekunden) und prüft wiederum den freien Festplattenplatz.

Script 3.12: Das Script mit der Methode Sleep anhalten

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).

Ein Script beenden


Im Allgemeinen wird ein Script erst dann beendet, wenn die letzte Zeile ausgeführt wurde. Es
mag jedoch Situationen geben, in denen Sie das Script abbrechen möchten, bevor die letzte
Scriptezeile ausgeführt wurde. Zum Beispiel, wenn Sie ein Script schreiben, das zwei
Argumente benötigt. Wenn der Benutzer nur ein Argument angibt, soll das Script
abgebrochen werden.

Seite 143 von 394


Sie können ein Script über die Methode WScript.Quit beenden. Mit der Quit-Methode wird
das Script sofort beendet. Das folgende Beispielscript gibt zum Beispiel drei Nachrichten aus
und wird dann beendet. Die letzten drei Befehle werden niemals ausgeführt:
Wscript.Echo "1"
Wscript.Echo "2"
Wscript.Echo "3"
Wscript.Quit
Wscript.Echo "4"
Wscript.Echo "5"
Wscript.Echo "6"
Einen Time-Out-Wert für ein Script verwenden
Auch wenn eigentlich jedes Script einen Time-Out-Wert verwenden sollte, ist dies ganz
besonders für Scripte wichtig, die möglicherweise unendlich ausgeführt werden können.
Stellen Sie sich zum Beispiel vor, ein Script muss sich als Erstes mit einem Remotecomputer
verbinden. Was passiert, wenn diese Verbindung nicht aufgebaut werden kann? Das Script
könnte zum Beispiel 60 Sekunden warten und einen neuen Verbindungsversuch starten. Dies
könnte das Script so lange fortführen, bis die Verbindung zustande kommt.
Was aber, wenn der Zielcomputer permanent aus dem Netzwerk entfernt wurde? In diesem
Fall wird das Script theoretisch für immer ausgeführt. Hier könnte es also praktisch sein,
einen Time-Out-Wert zu definieren. Wenn eine bestimmte Aufgabe im definierten Zeitraum
nicht ausgeführt werden kann, dann soll das Script beendet werden.
Die Eigenschaft WScript.Timeout definiert einen solchen Zeitraum in Sekunden
(standardmäßig wird das Script unendlich ausgeführt). Script 3.13 setzt den Time-Out auf 5
Sekunden. Wenn das Script also nach fünf Sekunden nicht von selbst beendet wurde, wird es
automatisch beendet. Da im Script in Zeile 2 eine Pause von 60 Sekunden definiert ist, wird
es immer durch den Time-Out abgebrochen. Zeile 3 wird also niemals ausgeführt.

Script 3.13: Verwendung des Time-Out in einem Script

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.

Tabelle 3.7: WSH-Umgebungsinformationen


Eigenschaft Beschreibung
ScriptFullNameVollständiger Pfad des aktiven Scripts
(zum Beispiel C:\Scripts\Monitor.vbs).
ScriptName Dateiname des aktiven Scripts (zum Beispiel Monitor.vbs).
Version Die WSH-Version (zum Beispiel 5.6).
Build Die WSH-Buildnummer. Die vollständige Versionsnummer
des Windows Script Hosts setzt sich aus der Versionsnummer

Seite 144 von 394


Eigenschaft Beschreibung
und der Build-Versionsnummer zusammen. Wenn die Windows
Script-Host-Versionsnummer zum Beispiel 5.6 und die
Buildversion 6626 ist, dann ist die vollständige Versionsnummer 5.6.6626.
Name Gibt immer den String Windows Script Host zurück.
FullName Pfad und Name des Script Hosts (entweder Wscript.exe
oder CScript.exe).
Path Der vollständige Pfad des Ordners, in dem sich der
Script Host befindet - ohne Dateiname.
Diese Metadaten können sehr nützlich sein. Über die Versionsnummer können Sie zum
Beispiel feststellen, ob die korrekte WSH-Version installiert ist. Wenn Ihr Script
beispielsweise die WSH 5.6 voraussetzt, können Sie dies über den folgenden Scriptcode
testen:
If Wscript.Version &#60;&#62; "5.6" Then
Wscript.Echo "Dieses Script muss unter WSH 5.6. ausgeführt werden."
Wscript.Quit
End If
Oder stellen Sie sich vor, Ihr Script führt eine große Menge an Ausgaben über Wscript.Echo
durch. In diesem Fall möchten Sie möglicherweise nicht, dass das Script unter WScript
ausgeführt wird - dies könnte zu hunderten von Nachrichtenfenstern führen, die alle per Hand
geschlossen werden müssten.
Sie können die verwendete Script Host-Version über die Eigenschaft FullName abfragen. Es
reicht allerdings aus, die letzten 11 Zeichen des Wertes zu überprüfen (um sicherzustellen,
dass die Überprüfung funktioniert, sollten Sie die Zeichen mit der Funktion UCase in
Großbuchstaben umwandeln). Wenn die letzten 11 Zeichen 'WSCRIPT.EXE' sind, wird das
Script unter WScript ausgeführt - bei 'CSCRIPT.EXE' handelt es sich beim Script Host um
CScript.

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.

Script 3.14: Anzeigen der verfügbaren WSH-Umgebungsinformationen

1Wscript.Echo "Script Full Name: " & Wscript.ScriptFullName


2Wscript.Echo "Script Name: " & Wscript.ScriptName
3Wscript.Echo "Version: " & WScript.Version
4Wscript.Echo "Build: " & Wscript.BuildVersion
5Wscript.Echo "Name: " & Wscript.Name

Seite 145 von 394


6Wscript.Echo "Full Name: " & Wscript.FullName
7Wscript.Echo "Path: " & Wscript.Path
Die Ausgabe des Scripts sieht so oder ähnlich aus:
Script Full Name: C:\test.vbs
Script Name: test.vbs
Version: 5.6
Build: 8515
Name: Windows Script Host
Full Name: C:\WINDOWS\system32\cscript.exe
Path: C:\WINDOWS\system32

Auf Ereignisse reagieren


Windows ist ein ereignisbasiertes Betriebssystem. Die Ereignisse, die unter Windows
generiert werden, sind oftmals das Ergebnis einer Benutzeraktion - zum Beispiel das Klicken
auf einen OK-Schalter oder eine Bewegung der Maus. Die meisten Windows-Programme
reagieren auf diese Ereignisse. Wenn Sie zum Beispiel eine Anwendung wie Microsoft Word
starten, dann wird die Anwendung geladen und wartet darauf, dass Sie etwas tun (zum
Beispiel etwas eingeben). Wenn Sie kein Ereignis auslösen, auf das reagiert werden kann,
dann wartet Word unendlich.
Außerdem ermöglicht dieser Ereignismechanismus verschiedenen Softwarekomponenten
miteinander zu kommunizieren. Wenn ein Ereignis in einer Komponente auftritt (auslösende
Komponente), dann wird eine andere Komponente (reagierende Komponente) davon
benachrichtigt. Die reagierende Komponente kann dann die notwendige Aktion ausführen.
Die Ereignismechanismen des WSH werden in gewöhnlichen administrativen Scripten
normalerweise nicht verwendet. Diese Scripte sind meist prozedurgesteuert. Das bedeutet,
wenn Sie einmal gestartet wurden, laufen sie einfach weiter - und zwar ohne auf äußere
Ereignisse zu reagieren.

Anmerkung: Die Möglichkeit Ressourcen zu überwachen und auf deren Ereignisse zu


reagieren ist sehr wichtig. Eine solche Ereignisüberwachung führen Sie jedoch am besten über
WMI durch. Außerdem kann die Ereignisüberwachung für die Automatisation von GUI-
Anwendungen wichtig sein. Scripte können zum Beispiel den Internet Explorer als
Benutzerschnittstelle verwenden. In diesem Fall sollte das Script auch auf Ereignisse des
Internet Explorers reagieren können. Weitere Informationen zu diesem Thema finden Sie im
Kapitel Creating Enterprise Scripts dieses Buches.

Das Objekt WshShell


Die Shell ist die Windows-Komponente, die die Benutzerschnittstelle zur Verfügung stellt.
Sie ist für Elemente wie den Desktop, den Windows Explorer, das Startmenü, Verknüpfungen
und Desktop-Schemata zuständig.
Das Objekt WshShell gibt Ihnen die Möglichkeit mit der Windows-Shell zu arbeiten. Ihre
Scripte können über das Objekt eine Vielzahl von administrativen Aufgaben durchführen -
inklusive Programme ausführen, Informationen in der Registrierung lesen und schreiben und
Erstellen von Verknüpfungen. Die Methoden und Eigenschaften des WshShell-Objekts sehen
Sie in Abbildung 3.10.

Seite 146 von 394


Abbildung 3.10: Das WshShell-Objektmodell
Auf das WshShell-Object zugreifen
Das WshShell-Object ist ein COM-Objekt. Mit der folgenden Codezeile können Sie eine
Instanz des Objekts erstellen:
Set objShell = WScript.CreateObject("WScript.Shell")
Funktionalitäten von WshShell
Das WshShell-Objekt ermöglicht Ihrem Script die Automatisierung von Windows-Shell-
bezogenen Aufgaben. In Tabelle 3.8 sehen Sie die Methoden und Eigenschaften des Objekts.

Tabelle 3.8: Methoden und Eigenschaften des WshShell-Objekts

Seite 147 von 394


Kategorie Methode oder Eigenschaft
Programme ausführen Run, Exec
Arbeiten mit Spezialordnern SpecialFolders
Arbeiten mit Verknüpfungen CreateShortcut
Arbeiten mit Umgebungsvariablen Environment,
ExpandEnvironmentStrings
Arbeiten mit dem Ereignisprotokoll LogEvent
Arbeiten mit der Registrierung RegRead, RegWrite, RegDelete
Tastendrücke an Anwendungen sendenAppActivate, SendKeys
Abfragen des aktuellen CurrentDirectory
Verzeichnisses des Scripts
Zeitgesteuerte Dialogfenster erstellen Popup

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.

Seite 148 von 394


Die beiden Methoden sind nicht auf Batchdateien oder Kommandozeilentools eingeschränkt.
Sie können auf diese Art jede beliebige ausführbare Datei aus Ihrem Script heraus starten.

Unterschiede zwischen Run und Exec


Es gibt zwei Wege, Programme aus Ihrem Script heraus zu starten - welchen sollen Sie
verwenden? Die Antwort zu dieser Frage hängt von Ihrem Script und von dem, was Sie mit
dem Script erreichen wollen, ab.
Sie verwenden die Methoden Run und Exec fast genauso wie Sie ein Programm über das
Dialogfenster Ausführen im Startmenü ausführen. Egal welche Methode Sie verwenden: Das
Programm wird in einem neuen Prozess gestartet. Wenn Sie die Methode Run verwenden, hat
Ihr Script jedoch keinen Zugriff auf die Standard-Eingabe-, -Ausgabe- und -Fehlerkanäle des
gestarteten Programms.
Stellen Sie sich zum Beispiel vor, Sie möchten ping.exe starten und seine Ausgaben in Ihrem
Script weiter verarbeiten. Über Run ist dies nicht möglich. Sie müssten stattdessen ping.exe
starten, dessen Ausgaben in einer Datei speichern und dieses Datei mit Ihrem Script einlesen.
Das folgende Script verwendet die Methode Run, um ping.exe zu starten. Die Ausgaben von
ping.exe werden in eine temporäre Datei umgeleitet. Das Script öffnet dann diese Textdatei,
prüft, ob der Ping-Befehl erfolgreich ausgeführt wurde (ob Zeilen der Ausgabe mit dem Wort
'Antwort' beginnen) und löscht die Datei dann:
Set objFSO = Wscript.CreateObject("Scripting.FileSystemObject")
Set objShell = Wscript.CreateObject("Wscript.Shell")
objName = objFSO.GetTempName
objTempFile = objName
objShell.Run "cmd /c ping -n 3 -w 1000 157.59.0.1 &#62;" & objTempFile, 0,
True
Set objTextFile = objFSO.OpenTextFile(objTempFile, 1)
Do While objTextFile.AtEndOfStream &#60;&#62; True
strText = objTextFile.ReadLine
If Instr(strText, "Antwort") &#62; 0 Then
Wscript.Echo "Antwort erhalten."
Exit Do
End If
Loop
objTextFile.Close
objFSO.DeleteFile(objTempFile)
Auch wenn dieser Ansatz durchaus funktioniert, ist er doch etwas kompliziert. Wenn Sie auf
die Ausgaben eines Programms zugreifen müssen, dann sollten Sie die Methode Exec
verwenden. Auch das folgende Script interpretiert die Ausgaben von ping.exe. Es verwendet
hierzu jedoch die Methode Exec. So kann es die Ausgaben direkt einlesen - es muss keine
temporäre Datei erstellen, öffnen, lesen und löschen. Das Script ist so nur noch 9 Zeilen statt
15 Zeilen lang:
Set objShell = WScript.CreateObject("WScript.Shell")
Set objExecObject = objShell.Exec("cmd /c ping -n 3 -w 1000 157.59.0.1")
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadLine()
If Instr(strText, "Antwort") &#62; 0 Then
Wscript.Echo "Antwort erhalten."
Exit Do
End If
Loop
In vielen Fällen ist die Methode Exec die bessere Wahl. Aber auch die Run-Methode ist in
einigen Situationen ganz nützlich:
Seite 149 von 394

Wenn Sie eine Anwendung in einem bestimmten Fenstertyp, zum Beispiel einem
minimierten Fenster, öffnen möchten, dann stellt Ihnen Run die in Tabelle 3.9 zu sehenden
Optionen zur Verfügung.

Wenn Sie ein Script auf einem Computer ausführen müssen, auf dem der WSH 5.6 nicht
installiert ist. Exec wird erst ab WSH 5.6 unterstützt.

Wenn Sie vor der weiteren Scriptausführung warten möchten, bis die gestartete Anwendung
wieder beendet wurde. Dies ist zwar auch über Exec möglich, mit Run ist es jedoch
einfacher.

Ausführen von Programmen


Die Methode Run verwendet drei Parameter. Nur der erste Parameter ist jedoch zwingend
erforderlich - er definiert den Namen des Programms, das Sie ausführen möchten. Wenn sich
das Programm im gleichen Ordner wie das Script befindet, reicht der Name der
Programmdatei aus (zum Beispiel calc.exe). Andernfalls müssen Sie den vollständigen Pfad
angeben (zum Beispiel C:\Admin\Monitoring\DiskSpace.exe).
Beim zweiten Parameter handelt es sich um einen Integer-Wert. Dieser legt den Fensterstil
fest, mit dem das Programm gestartet wird (wenn das Programm in einem Fenster ausgeführt
wird). Die möglichen Werte dieses Parameters sehen Sie in Tabelle 3.9.

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

Seite 150 von 394


WertBeschreibung
Anzeigezustands des Programms, das die Anwendung gestartet hat.
Script 3.15 startet Notepad. In Zeile 1 definiert das Script die Konstante
MAXIMIZE_WINDOW mit dem Wert 3 (aktiviert und maximiert). In Zeile 3 verwendet das
Script die Methode Run des Objekts WshShell, um Notepad zu starten. Hierbei übergibt es
den Wert der Konstante MAXIMIZE_WINDOW als zweiten Parameter.

Script 3.15: Ein Programm über die Methode Run starten

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.

Ausführen von Kommandozeilentools


Das Ausführen von Kommandozeilentools ist sowohl über Run als auch über Exec möglich -
in diesem Fall müssen Sie jedoch eine leicht andere Syntax als bei GUI-Programmen
verwenden. Sie müssen den Kommandozeilentools einen der folgenden Werte voranstellen:

%comspec% /k

%comspec% /c
Bei %comspec% handelt es sich um eine Umgebungsvariable, die den
Kommandozeilenprozessor zurückgibt. Mit ihr können Sie Scripte erstellen, die sowohl unter
Windows 98 (hier ist der Kommandozeilenprozessor command.exe) und unter Windows 2000
(hier ist der Kommandozeilenprozessor cmd.exe) ausgeführt werden können.
Sie müssen die Variable %comspec% nicht verwenden - sie bietet jedoch den Vorteil, dass
das Kommandozeilenfenster nach der Ausführung des Tools geöffnet bleibt (ohne dass Sie
den Kommandozeilenprozessor mit angeben wird das Fenster geöffnet, das Tool wird

Seite 151 von 394


ausgeführt, und das Fenster wird wieder geschlossen - Sie haben also nicht viel Zeit, die
Ausgaben zu lesen).
Außerdem ist die Variable %comspec% der einzige Weg, Kommandozeilenbefehle wie zum
Beispiel dir zu verwenden (dies liegt daran, dass dir kein Standardtool ist - es gibt kein
Programm mit dem Namen dir.exe). Das folgende Script produziert daher nur einen Fehler:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("dir"), 1, True
Dieses Script startet als Erstes den Kommandointerpreter und führt den dir-Befehl dann im
Kommandointerpreter aus:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("%comspec% /K dir"), 1, True
Über die Paramter /k und /c können Sie angeben, dass das Kommandozeilenfenster nach der
Scriptausführung geöffnet bleibt (/k) oder geschlossen wird (/c).
Das folgende Script startet zum Beispiel das Tool Cacls.exe. Dies zeigt in diesem Fall die
Berechtigung des Ordners C:\Scripts an. Das Script sorgt dafür, dass das Fenster geöffnet
bleibt, so dass Sie die Ausgaben lesen können:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("%comspec% /c sc.exe stop alerter"), 1, True
Das folgende Script startet das Tool Sc.exe und hält den Warndienst an. Sobald das Script
ausgeführt wurde, wird auch das Fenster wieder geschlossen:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("%comspec% /k sc.exe getkeyname "Upload Manager""), 1, True
Leerzeichen in Kommandozeilenparametern
Wenn die an ein Kommandozeilentool übergebenen Parameter Leerzeichen enthalten, dann
müssen diese Parameter in Anführungszeichen eingeschlossen werden. Wenn Sie zum
Beispiel das Tool Sc.exe zum Beenden des Dienstes Upload Manager verwenden möchten,
dann müssen Sie die folgende Syntax verwenden:
sc.exe getkeyname "Upload Manager"
Um denselben Befehl in einem Script auszuführen, müssen Sie ebenfalls den Parameter in
Anführungszeichen einschließen. Dies ist jedoch nicht ganz so einfach. Wenn Sie zum
Beispiel versuchen die folgende Codezeile zu verwenden, dann erhalten Sie einen Fehler:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("%comspec% /k sc.exe getkeyname "Upload Manager"), 1, True
Die Fehlermeldung sieht so aus:

Abbildung 3.11: Falsche Angabe der Parameter

Seite 152 von 394


Diese Fehlermeldung scheint erst einmal unsinnig - sie sagt, es würde die schließende
Klammer fehlen. Im Scriptcode ist jedoch eine schließende Klammer vorhanden. Wie sich
herausstellt, liegt das wahre Problem nicht in der Klammer, sondern in den
Anführungszeichen. Der WSH sieht das erste Anführungszeichen (das sich direkt vor
%comspec% befindet) als Beginn des Kommandostrings der der Methode Run übergeben
werden soll. Das zweite Anführungszeichen markiert für den WSH logischerweise das Ende
des Kommandostrings. Alles dazwischen ist für den WSH der Befehl, den Sie ausführen
möchten. Die Zeile sieht für den WSH also so aus:
objShell.Run("%comspec% /k sc.exe getkeyname "
Da diese Syntax natürlich nicht korrekt ist (die rechte Klammer fehlt ja tatsächlich) kommt es
zur Fehlermeldung.
Wenn Sie Anführungszeichen in einem String verwenden möchten, müssen Sie jedes Mal
zwei Anführungszeichen schreiben:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("%comspec% /k sc.exe getkeyname ""Upload Manager"""), 1, True
Ein Programm ausführen und auf dessen Ausgaben zugreifen
Um ein Programm auszuführen und auf dessen Ausgaben zuzugreifen, verwenden Sie die
Exec-Methode von WshShell. Sie gibt ein Objekt zurück, das Ihnen einen Zugriff auf die
Standard-Eingabe-, -Ausgabe- und -Fehlerkanäle des Programms ermöglicht.
Script 3.16 führt das Kommandozeilentoll ipconfig.exe aus. Dieses Tool fragt Informationen
über die Netzwerkkonfiguration des Computers ab - inklusive der aktuellen IP-Adresse des
Computers. Das Script fragt dann die Ausgaben des Tools über dessen Ausgabekanal ab und
geht diese Ausgabe zeilenweise durch. Wenn es in einer Zeile das Wort 'Adresse' findet, gibt
es die Zeile aus.

Script 3.16: Ausführen einer Anwendung und Zugriff auf deren Ausgabe

1 Set objShell = WScript.CreateObject("WScript.Shell")


2 Set objExecObject = objShell.Exec("%comspec% /c ipconfig.exe")
3
4 Do Until objExecObject.StdOut.AtEndOfStream
5 strLine = objExecObject.StdOut.ReadLine()
6 strIP = Instr(strLine,"Adresse")
7 If strIP &#60;&#62; 0 Then
8 Wscript.Echo strLine
9 End If
10Loop
In Zeile 2 verwendet das Script die Methode Exec, um das Kommandozeilentool ipconfig.exe
auszuführen. In der Variable objExecObject wird eine Referenz auf das Tool gespeichert.
In Zeile 4 nimmt das Script in einer Schleife die einzelnen Zeilen der Ausgabe des Tools
entgegen - und zwar so lange, bis das Ende der Ausgabe erreicht ist.
In Zeile 6 verwendet das Script die Funktion Instr von VBScript, um zu prüfen ob in der
aktuellen Zeile das Wort 'Adresse' enthalten ist. Wenn das Wort gefunden wurde, dann wird
die Zeile über die Methode Echo ausgegeben.
Wenn Sie ipconfig.exe in einer Kommandozeile alleine ausführen, erhalten Sie eine Ausgabe
wie diese:
Windows-IP-Konfiguration

Seite 153 von 394


Ethernetadapter VMware Network Adapter VMnet8:
Verbindungsspezifisches DNS-Suffix:
IP-Adresse. . . . . . . . . . . . : 192.168.184.1
Subnetzmaske. . . . . . . . . . . : 255.255.255.0
Standardgateway . . . . . . . . . : 192.168.184.100
Wenn Sie das Script ausführen sieht die Ausgabe so aus:
IP-Adresse. . . . . . . . . . . . : 192.168.184.1

Arbeiten mit Verknüpfungen


Verknüpfungen sind Links zu Programmen, Dateien, Ordnern, Computern oder
Internetadressen. Eine Verknüpfung ist eine Datei mit der Endung .lnk oder .url. Diese beiden
Dateierweiterungen werden für Standardverknüpfungen (lnk) und URLs (Uniform Resource
Locator) verwendet.
Verknüpfungen werden an vielen Stellen verwendet (Shell, Menüs, Werkzeugleisten, usw.).
Das Startmenü besteht zum Beispiel aus Verknüpfungen - und die Verknüpfungen aus der
Schnellstartleiste werden im folgenden Ordner gespeichert:
C:\Dokumente und Einstellungen\{Name des
Benutzerprofils}\Anwendungsdaten\Microsoft\Internet Explorer\Quick Launch
Ihre Scripte können den Desktop und die Menüs eines Benutzers über Verknüpfungen
anpassen. Sie können zum Beispiel ein Script erstellen, das unterschiedlichen
Benutzergruppen unterschiedliche Menüoptionen zur Verfügung stellt.
In Tabelle 3.10 sehen Sie die Eigenschaften des Objekts WshShortcut.

Tabelle 3.10: Eigenschaften des Objekts WshShortcut


Eigenschaft Beschreibung
Arguments Zusätzliche Kommandozeilenargumente, die Sie beim
Start der Anwendung verwenden können.
Description Beschreibung der Verknüpfung.
FullName Nur-Lese-Eigenschaft, die den vollständigen Pfad
zur Zielanwendung angibt.
HotKey Tastenkombination: Eine Tastenkombination, über die
die Anwendung gestartet werden kann. Tastenkombinationen
setzen sich normalerweise aus einer der folgenden Tasten
plus einem Buchstaben (a-z), einer Zahl (0-9) oder einer
Funktionstaste (F1-F12) zusammensetzen:

ALT

STRG

HOCHSTELLTASTE

Wenn Sie die Eigenschaft angeben, müssen Sie für


die Taste STRG den Wert CTRL und für die Hochstelltaste
den Wert SHIFT angeben. Für die Tastenkombination STRG
und 9 verwenden Sie beispielsweise den folgenden Wert:
Seite 154 von 394
Eigenschaft Beschreibung

Ctrl + 9

Wenn die Tastenkombination bereits verwendet wird, dann


wird sie überschrieben und der neuen Verknüpfung zugewiesen.
IconLocation Ermöglicht Ihnen die Angabe einen Symbols und eines
Symbolindexes für die Verknüpfung. Wenn nichts angegeben
wird, dann wird das Standardsymbol der Anwendung verwendet.
TargetPath Vollständiger Pfad zur Zielanwendung. Sie müssen einen
vollständigen Pfad (inklusive des Laufwerkbuchstabens)
oder einen UNC-Pfad angeben.

Der angegeben Wert wird nicht überprüft.


WindowStyle Fenstertyp der gestarteten Anwendung. Die möglichen
Werte entsprechen den Werten der Methode Run in Tabelle 3.9.
WorkingDirectoryArbeitsverzeichnis der Anwendung.

Erstellen von Standardverknüpfungen


Zum Erstellen von Standardverknüpfungen sind drei Schritte erforderlich:
1.Eine Instanz des Objekts WshShortcut über die Methode CreateShortcut() erstellen. Der
Methode muss der Pfad für die neue Verknüpfungsdatei übergeben werden. Auch wenn
Verknüpfungen überall im Dateisystem angelegt werden können, werden sie normalerweise
jedoch in Spezialordnern wie AllUsersDesktop und StartMenu angelegt. Spezialordner
werden weiter unten in diesem Kapitel besprochen.
2.Festlegen der Eigenschaften des neuen WshShortcut-Objekts.
3.Aufrufen der Methode WshShortcut.Save. Wenn Sie die Save-Methode nicht aufrufen, dann
wird die Verknüpfung nicht erstellt.
Script 3.17 erstellt eine Verknüpfung zur IIS-Verwaltung (Internetinformationsdienste -
Internet Information Services) auf dem Desktop. Die Verknüpfung wird für alle Benutzer
angezeigt und kann entweder über einen Doppelklick oder über die Tastenkombination
STRG-HOCHSTELLTASTE+I geöffnet werden.

Script 3.17: Erstellen einer Verknüpfung auf dem Desktop

1Set objShell = WScript.CreateObject("WScript.Shell")


2strDesktopFolder = objShell.SpecialFolders("AllUsersDesktop")
3Set objShortCut = objShell.CreateShortcut(strDesktopFolder & _
4 "\IIS Manager.lnk")
5objShortCut.TargetPath = "%SystemRoot%\System32\Inetsrv\iis.msc"
6objShortCut.Description = "IIS-Verwaltung starten."
7objShortCut.HotKey = "Ctrl+Shift+I"
8objShortCut.Save
In Zeile 2 wird der Pfad zum Spezialordner Desktop über die Eigenschaft
WshShell.SpecialFolders abgefragt und in der Variable strDesktopFolder gespeichert.

Seite 155 von 394


In den Zeilen 3 und 4 wird über die Methode CreateShortcut eine neue Verknüpfungsdatei
mit dem Namen IISManager.lnk im Desktopordner erstellt.
In den Zeilen 5-7 füllt das Script die Eigenschaften TargetPath, Description und HotKey des
WshShortcut-Objekts mit Werten.
In Zeile 8 erstellt das Script die Verknüpfung dann über die Methode WshShortcut.Save.

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.

Script 3.18: Erstellen eine URL-Verknüpfung auf dem Desktop

1Set objShell = WScript.CreateObject("WScript.Shell")


2strDesktopFld = objShell.SpecialFolders("Desktop")
3Set objURLShortcut = objShell.CreateShortcut(strDesktopFld & "\MSDN.url")
4objURLShortcut.TargetPath = "http://msdn.microsoft.com"
5objURLShortcut.Save
Ein Element zur Schnellstartleiste hinzufügen
Script 3.19 verwendet eine URL-Verknüpfung, um ein Element zur Schnellstartleiste
hinzuzufügen, über das die Microsoft® TechNet-Website geöffnet wird. Da die neue
Verknüpfung im Schnellstartordner des angemeldeten Benutzers erstellt wird, ist das neue
Element nur für die Benutzer sichtbar, die das Script ausgeführt haben.

Script 3.19: Ein neues Element in der Schnellstartleiste erstellen

1Set objShell = WScript.CreateObject("WScript.Shell")


2Set colEnvironmentVariables = objShell.Environment("Volatile")
3
4strQLFolder = colEnvironmentVariables.Item("APPDATA") & _
5 "\Microsoft\Internet Explorer\Quick Launch"
6
7Set objURLShortcut = objShell.CreateShortcut(strQLFolder & "\TechNet.url")
8objURLShortcut.TargetPath = "http://www.microsoft.com/germany/technet"
9objURLShortcut.Save

Seite 156 von 394


Löschen von Verknüpfungen
Verknüpfungsdateien können genauso gelöscht werden wie alle anderen Dateien. Das
folgende Script löscht zum Beispiel die mit Script 3.19 erstellte Verknüpfung:
Set objShell = WScript.CreateObject("WScript.Shell")
Set colEnvironmentVariables = objShell.Environment("Volatile")
Set objFSO = CreateObject("Scripting.FileSystemObject")

strQLFolder = colEnvironmentVariables.Item("APPDATA") & _


"\Microsoft\Internet Explorer\Quick Launch\TechNet.URL"
objFSO.DeleteFile(strQLFolder)
Weitere Informationen zur Arbeit mit Dateien in WSH-Scripten finden Sie im Kapitel Script
Runtime Primer dieses Buches.

Arbeiten mit Spezialordnern


Spezialordner sind Ordner, die es unter allen Windows-Computern gibt (oder zumindest
geben könnte) - zum Beispiel Eigene Dateien, Fonts und Startmenü. Es gibt zwei Arten von
Spezialordnern: Spezialordner mit Standardordnern und welche ohne. Der Ordner Favoriten
befindet sich zum Beispiel in einem Standardordner - der Ordner Arbeitsplatz nicht.
In der Collection WScript.SpecialFolders finden Sie die vollständigen Pfade zu allen
Spezialordnern, die einen Standardpfad verwenden. In Tabelle 3.11 sehen Sie die Namen und
die Inhalte dieser Ordner:

Tabelle 3.11: Spezialordner


Name Inhalt
AllUsersDesktop Desktopinhalte, die allen Benutzern angezeigt werden.
AllUsersStartMenuStartmenüeinträge, die allen Benutzern angezeigt werden.
AllUsersPrograms Einträge im Menü Programme, die allen Benutzern angezeigt werden.
AllUsersStartup Programme, die für alle Benutzer beim Systemstart ausgeführt werden.
Desktop Desktopinhalte, die nur dem aktuellen Benutzer angezeigt werden.
Favorites Einträge in den Favoriten des aktuellen Benutzers.
Fonts Installierte Schriften
MyDocuments Ordner Meine Dokumente des aktuellen Benutzers.
NetHood Objekte, die im Ordner Netzwerkumgebung angezeigt werden.
PrintHood Drucker
Recent Objekte, die unter dem Menüpunkt Dokumente im Startmenü
angezeigt werden (für den aktuellen Benutzer).
SendTo Optionen im Menü Senden an im Kontextmenü nach einem
Rechtsklick im Windows Explorer.
StartMenu Startmenü des aktuellen Benutzers.

Seite 157 von 394


Name Inhalt
Startup Programme, die für den aktuellen Benutzer beim Systemstart
ausgeführt werden.
Templates Anwendungsvorlagen des aktuellen Benutzers.

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.

Den Speicherort von Spezialordner abfragen


Script 3.20 fragt den Speicherort des Spezialordners Fonts ab. Dann gibt das Script diesen
Speicherort aus.

Script 3.20: Abfragen des Speicherortes des Spezialordners Fonts

1Set objShell = WScript.CreateObject("WScript.Shell")


2strFontDirectoryPath = objShell.SpecialFolders.Item("Fonts")
3Wscript.Echo "Pfad zum Ordner Font: " & strFontDirectoryPath
Eine Verknüpfung in einem Spezialordner erstellen
Wenn Sie eine Anwendung installieren, dann weist sich diese oft einer Dateierweiterung zu.
Wenn Sie zum Beispiel Microsoft® FrontPage® erstellen, weist sich Frontpage der
Dateierweiterung .htm zu. Wenn Sie mit der rechten Maustaste auf eine .htm-Datei klicken
und Bearbeiten auswählen, dann wird die Datei mit Frontpage geöffnet.
Manchmal möchten Sie die .htm-Datei aber vielleicht nur einfach in Notepad anzeigen.
Hierzu gibt es unter Windows einen Spezialordner mit dem Namen SendTo (Senden an). In
diesem Ordner finden Sie alle Anwendungen, über die Sie über das Kontextmenü im
Windows Explorer eine Datei öffnen können. Über den Spezialordner SendTo können Sie
diesem Ordner Verknüpfungen hinzufügen. Wenn Sie das nächste Mal eine .htm-Datei mit
Notepad öffnen möchten, dann klicken Sie einfach mit der rechten Maustaste auf die Datei
und wählen im Kontextmenü Senden an und Notepad aus.
Script 3.21 erstellt eine Verknüpfung zur Anwendung Notepad im Spezialordner SendTo.

Script 3.21: Notepad zum Menü Senden an hinzufügen.

1Set objShell = WScript.CreateObject("WScript.Shell")


2strSendToFolder = objShell.SpecialFolders("SendTo")
3strPathToNotepad = objShell.ExpandEnvironmentStrings _
4 ("%SystemRoot%/system32/notepad.exe")
5
6Set objShortcut = objShell.CreateShortcut(strSendToFolder & _
7 "\notepad.lnk")
8objShortcut.TargetPath = strPathToNotepad
9objShortcut.Save

Umgebungsvariablen
Der Windows-Shellprozess verwendet einige Umgebungsvariablen, deren Inhalte Ihnen in
Ihrem Script nützen können:

Seite 158 von 394



Ordner, in denen nach Programmen gesucht wird, wenn Sie in der Eingabeaufforderung nur
den Programmnamen angeben.

Anzahl der CPUs, CPU-Hersteller und CPU-Architektur.

Speicherort des Benutzerprofils.

Speicherorte der temporären Ordner.
Wenn Sich ein Benutzer unter Windows anmeldet, dann lädt die Shell die
computerspezifischen Umgebungsvariablen aus dem Pfad HKEY_LOCAL_MACHINE und
die benutzerspezifischen Umgebungsvariablen aus dem Pfad HKEY_CURRENT_USER der
Registrierung.
Zusätzlich zu diesen Umgebungsvariablen werden bei jeder Anmeldung noch Prozess-
Umgebungsvariablen generiert.

Tabelle 3.12: Umgebungsvariablen und deren Speicherorte


Typ Beschreibung Speicherort in der Registrierung
User Spezifisch für den angemeldeten HKCU\Environment
Benutzer.
Werden zwischen Ab- und Anmeldung
des Benutzers gespeichert.
System Gelten für alle Benutzer des Computers HKLM\System\CurrentControlSet\
und werden zwischen An- und Control\Session Manager\Environment
Abmeldung gespeichert.
VolatileGelten nur für die aktuelle Sitzung. HKCU\VolatileEnvironment
Werden nicht gespeichert.
Process Gelten nur für den aktuellen Prozess. Werden nicht in der Registrierung
gespeichert.
Die Eigenschaft Environment des Objekts WshShell gibt die Collection WshEnvironment
zurück, über die Ihr Script Umgebungsvariablen abfragen, einrichten und verändern kann.

Abfragen von Umgebungsvariablen


Um eine Collection mit den Umgebungsvariablen eines bestimmten Typs zu erhalten,
verwenden Sie die Eigenschaft WshShell.Environment. Ihr übergeben Sie eine String, der den
gewünschten Variablentyp enthält: system, user, process oder volatile. Danach kann das
Script über die Collection WshEnvironment über den Namen der Umgebungsvariablen auf
diese zugreifen.

Tabelle 3.13: Umgebungsvariablen


Name SystemUserProcessProcess (nur Windows 98/Me)
NUMBER_OF_PROCESSORS
PROCESSOR_ARCHITECTURE
PROCESSOR_IDENTIFIER
PROCESSOR_LEVEL

Seite 159 von 394


Name SystemUserProcessProcess (nur Windows 98/Me)
PROCESSOR_REVISION
OS
COMSPEC
HOMEDRIVE
HOMEPATH
PATH
PATHEXT
PROMPT
SYSTEMDRIVE
SYSTEMROOT
WINDIR
TEMP
TMP
Die Umgebungsvariablen in der Tabelle gibt es unter allen Windows-Computern. Es kann
jedoch zusätzliche benutzerspezifische Variablen geben. Wenn Sie die Namen dieser
zusätzlichen Variablen nicht kennen, dann können Sie in der Eingabeaufforderung eine
komplette Liste über den Befehl Set abrufen.
Script 3.22 ruft die benutzerspezifische und die computerspezifische Umgebungsvariable
PATH ab.

Script 3.22: Anzeigen der Umgebungsvariable PATH

1Set objShell = WScript.CreateObject("WScript.Shell")


2Set colSystemEnvVars = objShell.Environment("System")
3Set colUserEnvVars = objShell.Environment("User")
4Wscript.Echo "Computer-specific PATH Environment Variable"
5Wscript.Echo colSystemEnvVars("PATH")
6Wscript.Echo "User-specific PATH Environment Variable"
7Wscript.Echo colUserEnvVars("PATH")
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
Computer-specific PATH Environment Variable
C:\Programme\PTP2002;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System
32\Wbem
User-specific PATH Environment Variable
C:\Programme\PTP2002;;
Umgebungsvariablen erstellen
Um Umgebungsvariablen zu erstellen, gehen Sie anfangs genauso vor wie beim Abfragen
einer Umgebungsvariable: Sie benötigen eine Referenz auf die Collection mit den
Umgebungsvariablen. Erst dann könnten Sie eine neue Umgebungsvariable erstellen.

Seite 160 von 394


Die folgende Codezeile erstellt zum Beispiel eine Umgebungsvariable mit dem Namen
MeineVariable mit den Anfangswert 0.
colUsrEnvVars("MeineVariable") = 0
Sie können über Ihre Scripts Variablen vom Typ process oder volatile erzeugen - diese sind
jedoch nicht sonderlich nützlich, da beide Variablentypen bei der Abmeldung des Benutzers
nicht gespeichert werden. Daher finden Sie Variablen vom Typ user und system
wahrscheinlich deutlich praktischer - diese werden bei der Abmeldung des Benutzers
gespeichert.
Script 3.23 erstellt eine Umgebungsvariable vom Typ user mit dem Namen APP_VARIABLE
und setzt deren Wert auf Installiert. Danach fragt das Script den Wert der neu erstellen
Variable ab, um sicherzustellen, dass diese auch erstellt wurde.

Script 3.23: Erstellen einer Umgebungsvariable vom Typ user

1Set objShell = WScript.CreateObject("WScript.Shell")


2Set colUsrEnvVars = objShell.Environment("USER")
3colUsrEnvVars("APP_VARIABLE") = "Installiert"
4Wscript.Echo colUsrEnvVars("APP_VARIABLE")
Ändern von Umgebungsvariablen
Auch bei der Änderung von Umgebungsvariablen beginnen Sie, indem Sie sich eine Referenz
auf die Collection mit den Umgebungsvariablen erstellen. Script 3.24 ändert den Wert der
Umgebungsvariable von Typ user mit dem Namen APP_VARIABLE auf den Wert
Aktualisiert.

Script 3.24: Änderung einer Umgebungsvariable von Typ user

1Set objShell = WScript.CreateObject("WScript.Shell")


2Set colUsrEnvVars = objShell.Environment("USER")
3strCurrentValue = colUsrEnvVars("APP_VARIABLE")
4colUsrEnvVars("APP_VARIABLE") = "Aktualisiert"
5Wscript.Echo colUsrEnvVars("APP_VARIABLE")
Auswerten von Umgebungsvariablen
Über Umgebungsvariablen können Sie Systeminformationen abrufen. Wenn Sie zum Beispiel
auf den temporären Ordner des Benutzers zugreifen möchten, dann brauchen Sie die
Pfadangabe für diesen Ordner (beispielsweise C:\Temp).
Um den Wert einer Umgebungsvariable abzufragen, verwenden Sie die Methode
WshShell.ExpandEnvironmentStrings. Diese Methode erwartet als Parameter den in
Prozentzeichen (%) eingeschlossenen Namen der Umgebungsvariable als String und gibt
deren Wert zurück.
Script 3.25 gibt erst den Wert einer Umgebungsvariable und dann die ausgewertete
Umgebungsvariable aus.

Script 3.25: Erstellen und Anzeigen einer Umgebungsvariable

1Set objShell = WScript.CreateObject("WScript.Shell")


2Set colEnvVars = objShell.Environment("User")
3Wscript.Echo "temporärer Ordner:"
4Wscript.Echo colEnvVars("TEMP") & vbCrLf
5Wscript.Echo "temporärer Ordner (ausgewertet) "

Seite 161 von 394


6Wscript.Echo objShell.ExpandEnvironmentStrings("%TEMP%")
Wenn Sie das Script unter Cscript ausführen, erzeugt es eine Ausgabe wie die folgende.
temporärer Ordner:
%USERPROFILE%\Lokale Einstellungen\Temp

temporärer Ordner (ausgewertet)


C:\DOKUME~1\ADMINI~1\LOKALE~1\Temp

Einträge im Ereignisprotokoll erzeugen


Die Fehlersuche in Anwendungen und bei Diensten wird dadurch vereinfacht, dass diese
wichtige Ereignisse in das Ereignisprotokoll eintragen. Ihre Scripte können das ebenfalls so
machen. Das WshShell-Objekt stellt Ihnen hierzu die Methode LogEvent zur Verfügung - sie
erzeugt einen Eintrag im Anwendungsprotokoll.

Anmerkung: Wenn Sie Ereignisprotkolleinträge lesen oder verarbeiten möchten, dann


müssen Sie WMI verwenden. Weitere Informationen hierzu finden Sie im Kapitel Logs.
LogEvent erwartet zwei Parameter. Der erste Parameter ist ein Integerwert, der das Ereignis
definiert, dass Sie in das Ereignisprotokoll eintragen möchten. Die möglichen Werte sehen
Sie in Tabelle 3.14.

Tabelle 3.14: Ereignistypen


WertEreignistyp
0 Erfolgreich
1 Fehler
2 Warnung
4 Information
8 Erfolgsüberwachung
16 Fehlerüberwachung
Der zweite Parameter gibt den Text für den Protokolleintrag an. Als dritten Parameter können
Sie optional den Computernamen angeben - zum Beispiel, wenn das Ereignis nicht auf dem
Computer eingetragen wird, auf dem das Script ausgeführt wird, sondern auf einem zentralen
Computer (dieser Parameter wird unter Windows 95 und Windows 98 ignoriert).
Script 3.26 erzeugt jeweils ein Ereignis der in Tabelle 3.14 angegebenen Ereignistypen mit
einer entsprechenden Beschreibung.

Script 3.26: Ereignisse im Ereignisprotokoll erzeugen

1Set objShell = WScript.CreateObject("Wscript.Shell")


2objShell.LogEvent 0,"Test Erfolgreich"
3objShell.LogEvent 1,"Test Fehler"
4objShell.LogEvent 2,"Test Warnung "
5objShell.LogEvent 4, "Test Information "
6objShell.LogEvent 8, "Test Erfolgsüberwachung "
7objShell.LogEvent 16, "Test Fehlerüberwachung "

Seite 162 von 394


Mit der LogEvent-Methode können Sie Ereignisse nur im Anwendungsprotokoll erzeugen. Sie
können keine bestimmte Ereignis-ID oder Quelle angeben. Die Quelle für alle Ereignisse ist
automatisch der WSH - als Ereignis-ID werden die Werte aus Tabelle 3.14 verwendet.

Schreiben und Lesen in der lokalen Registrierungsdatenbank


Im Allgemeinen ist es besser die Registrierung über die entsprechenden Tools (zum Beispiel
Regedit.exe) zu verwalten. Diese sind zwar auch nicht idiotensicher, verfügen jedoch über
eingebaute Sicherheitsoptionen, um potentielle Beschädigungen der Registrierung zu
verhindern. Andererseits ist es über solche Tools oft schwer die Registrierung auf mehreren
Computern zu bearbeiten. In einem solchen Fall bietet Ihnen das WshShell-Objekt die
Möglichkeit, Einträge in der Registrierung zu lesen, zu schreiben und diese zu verändern.

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.

Tabelle 3.15: Registrierungsdatentypen und die entsprechenden VBScript-Datentypen


Name Datentyp VBScript-Datentyp
REG_SZ String String
REG_DWORD Number Integer
REG_BINARY Binary Value Integer-Array

Seite 163 von 394


Name Datentyp VBScript-Datentyp
REG_EXPAND_SZExpandable StringString
REG_MULTI_SZ Array of Strings String-Array
Bei den Datentypen in der Tabelle handelt es sich nur um die gebräuchlichsten. Wenn Sie
versuchen mit RegRead nicht unterstützte Datentypen auszulesen, führt dies zu einem Fehler.

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.

Script 3.27: Auslesen eines Multistring-Wertes aus der Registrierung

1Set objShell = WScript.CreateObject("WScript.Shell")


2arrValues = objShell.RegRead _
3 ("HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Security\Sources")
4For Each strValue In arrValues
5 Wscript.Echo strValue
6Next
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
Spooler
Security Account Manager
SC Manager
NetDDE Object
LSA
DS
Security
Registrierungseinträge erstellen oder ändern
Über die Methode RegWrite können Sie neue Registrierungseinträge erstellen oder
bestehende Einträge ändern. Die Methode nimmt hierzu drei Parameter entgegen: Den
Registrierungseintrag, den Sie erstellen oder ändern möchten, den Wert, den Sie dem Eintrag
zuweisen möchten und (optional) den Datentyp des Eintrages.
Script 3.28 verwendet die Methode RegWrite, um einen DWORD-Eintrag zu erstellen und
dessen Wert auf 56 zu setzen.

Script 3.28: Einen DWORD-Eintrag in der Registrierung erstellen

1Set objShell = WScript.CreateObject("WScript.Shell")


2objShell.RegWrite "HKCU\TestKey\Version", 56, "REG_DWORD"

Anmerkung: Der Datentyp REG_MULTI_SZ wird von der Methode RegWrite nicht
unterstützt.

Registrierungseinträge löschen

Seite 164 von 394


Mit der Methode RegDelete können Sie Schlüssel oder Einträge in der Registrierung löschen.
Sie akzeptiert einen Parameter - dieser gibt den zu löschenden Schlüssel oder Eintrag an.
Wenn Sie einen Schlüssel löschen, dann werden auch alle Einträge unter diesem Schlüssel
gelöscht.
Script 3.29 verwendet die Methode RegDelete, um einen DWORD-Eintrag aus der
Registrierung zu löschen.

Script 3.29: Löschen eines DWORD-Eintrags aus der Registrierung

1Set objShell = WScript.CreateObject("WScript.Shell")


2objShell.RegDelete "HKCU\TestKey\Version"

Tastatureingaben an ein Programm schicken


Der WSH ermöglicht Ihnen eine Automatisierung von COM-fähigen Anwendungen, indem er
Ihnen einen Zugriff auf die jeweiligen COM-Objekte zur Verfügung stellt.
Unglücklicherweise sind einige Anwendungen nicht COM-fähig - dies betriff spezielle ältere
Anwendungen. Um auch die Arbeit mit solchen Anwendungen automatisieren zu können,
haben Sie die Möglichkeit, Tastatureingaben an die Anwendungen zu schicken.
Mit der Methode WshShell.SendKeys imitiert Ihr Script die Tastatureingaben durch einen
Benutzer. Um ein einzelnes Zeichen zu simulieren, übergeben Sie der Methode SendKeys das
Zeichen einfach als Parameter.
Sondertasten (zum Beispiel STRG oder ALT) können Sie über bestimmte
Zeichenkombinationen angeben. In Tabelle 3.16 sehen Sie alle oft verwendeten Sondertasten
und die entsprechenden Zeichenkombinationen.

Tabelle 3.16: Zeichenkombinationen für Sondertasten mit SendKeys


Taste Wert für SendKeys
Rückschritt {BACKSPACE}, {BS}, oder {BKSP}
Pause {BREAK}
Feststelltaste {CAPSLOCK}
Entf. oder Entfernen{DELETE} oder {DEL}
Pfeil runter {DOWN}
Ende {END}
Eingabe {ENTER} oder ~
ESC {ESC}
Hilfe {HELP}
Pos1 {HOME}
Einf. oder Einfügen {INSERT} oder {INS}
Pfeil Links {LEFT}

Seite 165 von 394


Taste Wert für SendKeys
NUM {NUMLOCK}
Bild runter {PGDN}
Bild hoch {PGUP}
Druck {PRTSC}
Pfeil links {RIGHT}
Rollen {SCROLLLOCK}
Tabulator {TAB}
Pfeil hoch {UP}
Hochstelltaste +
Steuerung (Strg) ^
Alt %
Alle Funktionstasten werden über den Tastennamen in geschweiften Klammern angegeben -
zum Beispiel {F1} für die Taste F1 usw.
Das folgende Script startet zum Beispiel Notepad und schreibt den Satz 'Dies ist ein Test.':
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run("Notepad.exe")
objShell.AppActivate "Editor"
objShell.SendKeys "Dies ist ein Test."
Wenn Sie das Script ausführen, wird Notepad geöffnet. Dann wird der Beispielsatz in
Notepad geschrieben.

Abbildung 3.12: Notepad über SendKeys steuern

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.

Seite 166 von 394



Das Script ist schwer mit der Anwendung zu synchronisieren.
Das Timing-Problem ist ganz besonders schwer zu lösen - ganz einfach darum, weil die
meisten Scripte sehr viel schneller ausgeführt werden, als die meisten GUI-basierten
Anwendungen. Das folgende Script startet zum Beispiel den Windows-Taschenrechner und
schickt dann die Ziffer 2 an diese Anwendung. Wahrscheinlich wird es zwar korrekt
ausgeführt, die Zahl 2 ist im Taschenrechner jedoch nicht zu sehen:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
objShell.AppActivate "Rechner"
objShell.SendKeys "2"
Das unerwartete Ergebnis liegt nicht an einem Fehler im Script, sondern an einem Timing-
Problem. Das Script führt die folgenden Befehle so schnell wie möglich aus:
1.Windows-Taschenrechner starten.
2.Focus auf den Taschenrechner verschieben (über die Methode AppActivate).
3.Die Zahl 2 an den Taschenrechner schicken.
Das Script wird jedoch viel schneller ausgeführt, als der Windows-Taschenrechner geladen
werden kann. Das führt dazu, dass die Zahl 2 schon gesendet wird, wenn der Taschenrechner
noch nicht einmal vollständig geladen wurde - natürlich kann er in diesem Zustand noch keine
Tastatureingaben entgegennehmen oder gar verarbeiten.
Zur Lösung dieses Problems gibt es zwei Wege. Bei der ersten Möglichkeit stellen Sie fest,
wie lange die Anwendung zum Laden braucht, und halten dann das Script für diesen Zeitraum
an. Das folgende Script verwendet zum Beispiel die Methode Run, und wartet dann 5
Sekunden auf das Laden des Taschenrechners:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
Wscript.Sleep 5000
objShell.AppActivate "Rechner"
objShell.SendKeys "2"
In einigen Fällen kann es natürlich schwer einzuschätzen sein, wie lange eine Anwendung
zum Laden benötigt. In einem solchen Fall können Sie das zweite Verfahren nutzen: Sie
verwenden die Methode AppActivate, um den Rückgabewert der Anwendung zu überprüfen.

Verwendung von AppActivate


Bevor Sie Tastatureingaben an eine Anwendung schicken, müssen Sie sicherstellen, dass die
Anwendung ausgeführt wird und über den Focus verfügt (das Anwendungsfenster muss also
das aktive Fenster sein) - hierzu können Sie die Methode AppActivate verwenden.
AppActivate erwartet einen Parameter, bei dem es sich entweder um einen String mit dem
Titel der Anwendung (wird ganz oben in der Titelleiste der Anwendung angezeigt) oder um
die Prozess-ID der Anwendung handeln kann. Die Methode gibt einen Boolean-Wert zurück,
der anzeigt, ob die Methode erfolgreich ausgeführt wurde oder nicht. Der Rückgabewert
False bedeutet, dass AppActivate nicht in der Lage war, den Focus auf die Anwendung zu
verschieben (zum Beispiel, wenn die Anwendung noch nicht vollständig geladen ist).
Sie können eine Schleife verwenden, in der AppActivate so lange aufgerufen wird, bis ihr
Rückgabewert True ist. Dann wissen Sie, dass die Anwendung vollständig geladen wurde und
bereit für Tastatureingaben ist.

Seite 167 von 394


Das folgende Script prüft den Rückgabewert von AppActivate. Wenn dieser Wert False ist,
wartet das Script für eine Sekunde ab und prüft den Wert dann noch einmal. Dieser Vorgang
wird so lange wiederholt, bis der Rückgabewert True ist. Erst dann fährt das Script mit den
Tastatureingaben fort:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "Calc.exe"
Do Until Success = True
Success = objShell.AppActivate("Rechner")
Wscript.Sleep 1000
Loop
objShell.SendKeys "2"
Mit AppActivate wird der übergebene String mit allen Fenstertiteln verglichen. Wenn keine
Übereinstimmung gefunden wird, setzt AppActivate den Focus auf das Fenster, dessen Titel
mit dem übergebenen String beginnt. Wenn auch hier keine Übereinstimmung gefunden
werden kann, wird der Focus auf das Fenster gesetzt, dessen Titel mit dem String endet. So
wird sichergestellt, dass AppActivate auch mit Anwendungen funktioniert, in denen
Dokumente geöffnet werden können (wenn Sie zum Beispiel Notepad starten und ein neue
Dokument öffnen, dann lautet der Fenstertitel von Notepad Unbenannt -Editor und nicht
Editor.
Das bedeutet, dass Sie die folgenden Codezeilen verwenden können, um den Focus auf den
Taschenrechner zu verschieben:
objShell.AppActivate "Rechner"
objShell.AppActivate "Rech"
objShell.AppActivate "R"
Die 'Kurzmethode' kann natürlich auch zu Problemen führen. Stellen Sie sich vor, Sie
verwenden die folgende Codezeile:
objShell.AppActivate "Rech"
Wenn Sie in diesem Fall ein Word-Dokument mit dem Namen Rechnungen.doc geöffnet
haben, könnten die Tasteneingaben versehentlich an dieses Fenster geschickt werden.
Script 3.30 zeigt eine mehr praktische Anwendung der Methode SendKeys. Es startet die
Microsoft Management Console (MMC) und verschiebt den Focus auf die Anwendung. Dann
schickt es die Tastatureingaben an die Anwendung, die erforderlich sind, um den Dialog
Snap-In hinzufügen/entfernen und das Dialogfenster Eigenständiges Snap-In hinzufügen
anzuzeigen.

Script 3.30: Tastatureingaben an eine GUI-Anwendung schicken

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}"

Seite 168 von 394


16Wscript.Sleep 100
17objShell.SendKeys "{ENTER}"

Das aktuelle Arbeitsverzeichnis eines Scripts abfragen und ändern


Das Arbeitsverzeichnis eines Scripts ist standardmäßig das Verzeichnis, in dem das Script
gestartet wurde. Dies ist nicht notwendigerweise das Verzeichnis, in dem das Script
gespeichert ist. Wenn Sie sich in Verzeichnis C:\Temp befindenund das Script
c:\scripts\report.vbs starten, dann ist das Arbeitsverzeichnis des Scripts c:\temp.
Das Objekt WshShell verfügt über eine Eigenschaft mit dem Namen CurrentDirectory. Über
diese Eigenschaft können Sie das Arbeitsverzeichnis abfragen und verändern. Hierfür kann es
mehrere Gründe geben:

Sie möchten, dass das Script eine Protokolldatei in dem Ordner erstellt, in dem das Script
gespeichert ist.

Sie möchten feststellen, ob das Script lokal oder über das Netzwerk gestartet wurde - wenn
es über das Netzwerk gestartet wurde, beginnt das Arbeitsverzeichnis mit zwei Backslashes
(\\).
Um das Arbeitsverzeichnis abzufragen, erstellen Sie eine Instanz von WshShell und greifen
dann auf die Eigenschaft CurrentDirectory zu. Um das Arbeitsverzeichnis zu ändern, weisen
Sie der Eigenschaft einfach einen neuen Wert zu.

Script 3.31: Konfigurieren und Abfragen des aktuellen Arbeitsverzeichnisses

1Set objShell = WScript.CreateObject("WScript.Shell")


2
3Wscript.Echo "Aktuelles Arbeitsverzeichnis:"
4Wscript.Echo objShell.CurrentDirectory
5
6objShell.CurrentDirectory = "C:\"
7
8Wscript.Echo "Arbeitsverzeichnis nach Änderung:"
9Wscript.Echo objShell.CurrentDirectory
Wenn Sie das Script aus dem Ordner c:\temp unter CScript starten, erhalten Sie die folgende
Ausgabe:
Aktuelles Arbeitsverzeichnis:
C:\Temp
Arbeitsverzeichnis nach Änderung:
C:\

Zeitgesteuerte Nachrichtenfenster anzeigen


In einer perfekten Welt trifft Ihr Script bei jeder Ausführung auf perfekte Bedingungen - es
führt seine vorgesehene Aufgabe schnell und zuverlässig aus. In der echten Welt
funktionieren einige Dinge jedoch nicht immer so zuverlässig. Manchmal starten Sie ein
Script, und es werden Entscheidungen erforderlich; zum Beispiel, wenn Sie eine Verbindung
mit einem Remotecomputer aufbauen wollen und dieser nicht erreichbar ist. Soll das Script
einen neuen Versuch unternehmen, den Computer zu erreichen oder das Problem ignorieren?
Oder soll das Script möglicherweise einfach aufgeben?

Seite 169 von 394


In solchen Fällen können Sie die Methode WshShell.Popup verwenden. Sie zeigt ein
Nachrichtenfenster an, und liefert als Rückgabewerte den Schalter, auf den der Benutzer
geklickt hat. Sie können zum Beispiel ein Nachrichtenfenster mit einen Ja- und einem Nein-
Schalter anzeigen lassen, und Ihr Script kann dann auf die Auswahl des Benutzers reagieren.
'Soll ein weiterer Verbindungsversuch unternommen werden? Ja/Nein'.
Ein weiterer Vorteil der Methode Popup ist, dass Sie einen Timeout-Wert definieren können
und Symbol und Titel des Nachrichtenfensters festlegen können. Nachrichtenfenster, die über
die Methode Wscript.Echo erzeugt werden, bieten Ihnen diese Möglichkeiten nicht - sie haben
immer den Titel Windows Script Host.
In Abbildung 3.13 sehen Sie ein Beispiel für ein Nachrichtenfenster, das über die Methode
Popup erzeugt wurde.

Abbildung 3.13: Popup-Nachrichtenfenster


Vergleich der Methoden Echo und Popup
Wenn Sie ein Script unter WScript ausführen, können Sie ein Nachrichtenfenster statt mit der
Methode WshShell.Popup auch über die Methode Wscript.Echo anzeigen. Mit Wscript.Echo
haben die Benutzer jedoch nur die Möglichkeit auf OK zu klicken.
Außerdem hält das Script an, wenn eine Nachricht über Wscript.Echo angezeigt wird. Erst
nachdem der Benutzer auf OK geklickt hat, wird es weiter ausgeführt.

Abbildung 3.14: Mit Wscript.Echo unter WScript erzeugtes Nachrichtenfenster

Anmerkung: Im Gegensatz zu Wscript.Echo zeigt die Methode Popup immer ein


Nachrichtenfenster an - egal, ob das Script unter CScript oder WScript ausgeführt wird.

Ein Nachrichtenfenster mit Time-Out erstellen


Script 3.32 verwendet die Methode Popup, um drei Nachrichtenfenster zu erstellen. Jedes
Fenster verfügt über einen OK-Schalter und wird für maximal 5 Sekunden angezeigt. Wenn
der Benutzer nicht auf OK klickt, dann wird das Nachrichtenfenster automatisch nach 5
Sekunden geschlossen.

Script 3.32: Nachrichtenfenster mit Time-Out

1Const TIMEOUT = 5

Seite 170 von 394


2Set objShell = WScript.CreateObject("WScript.Shell")
3
4objShell.Popup "Festplattenprüfung durchgeführt", TIMEOUT
5objShell.Popup "Speicherprüfung durchgeführt", TIMEOUT
6objShell.Popup "CPU-Prüfung durchgeführt", TIMEOUT
Solche Nachrichtenfenster mit Time-Out sind in zwei Situationen sehr praktisch. Erstens,
wenn Sie Informationen ausgeben wollen, ohne das Script zu unterbrechen - zum Beispiel
könnte Script 3.32 ja tatsächlich die drei Prüfungen durchführen. Nachdem eine Prüfung
durchgeführt wurde, würde das Script den Benutzer über die Popup-Methode
benachrichtigen, jedoch bereits während der Anzeige mit der nächsten Prüfung fortfahren.
Zweitens können Sie dem Benutzer die Möglichkeit geben eine Entscheidung zu treffen oder
das Script einfach weiter laufen zu lassen. Stellen Sie sich vor, Sie schreiben ein Script, das
einige Aufgaben durchführt und dann Dateien auf einen Computer im Netzwerk kopiert. Da
das Kopieren möglicherweise sehr lange dauert, können Sie den Benutzer vorher fragen, ob er
die Aktion durchführen möchte. Wenn dieser nicht reagiert, könnten Sie automatisch mit dem
Kopieren anfangen.

Symbole und Schalter in Nachrichtenfenstern


Sie haben die Möglichkeit, unterschiedliche Schalter und Symbole im Nachrichtenfenster
anzeigen zu lassen (zum Beispiel die Schalter Ja und Nein oder die Schalter Abbrechen,
Wiederholen, Ignorieren).
Die Angezeigten Schalter und Symbole definieren Sie mit dem vierten Parameter der
Methode Popup. Er setzt sich auch einer Kombination von vordefinierten Konstanten
zusammen - die beiden Werte werden einfach addiert. Die verfügbaren Symbole und die
entsprechenden Werte sehen Sie in Tabelle 3.17.

Tabelle 3.17: Konstanten für Symbole


Symbol Konstante Wert
Stop vbCritical 16
Fragezeichen vbQuestion 32
AusrufungszeichenvbExclamation48
Information vbInformation 64
In Tabelle 3.18 sehen Sie die zur Verfügung stehenden Schalter und die entsprechenden
Konstanten.
Tabelle 3.18: Konstanten für Schalter
Schalter Konstante Wert
OK vbOKOnly 0
OK und Abbrechen vbOKCancel 1
Abbrechen, Wiederholen und IgnorierenvbAbortRetryIgnore2
Ja, Nein und Abbrechen vbYesNoCancel 3
Ja und Nein vbYesNo 4

Seite 171 von 394


Schalter Konstante Wert
Wiederholen und Abbrechen vbRetryCancel 5
Auch wenn Sie in Ihrem Script sowohl die Konstanten als auch die Werte verwenden können,
sollten Sie bei den Konstanten bleiben. Ihre Scripte werden so leichter nachvollziehbar und
lesbar.
Script 3.33 zeigt einige Nachrichtenfenster an, die jeweils unterschiedliche Symbole und
Schalter verwenden. Wenn Sie auf einen Schalter im Nachrichtenfenster klicken, wird das
nächste Nachrichtenfenster angezeigt - dies geschieht auch, wenn Sie einfach 5 Sekunden
abwarten.

Script 3.33: Kombinationen von Symbolen und Schaltern anzeigen

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.

Einen Standardschalter auswählen


Mit der Methode WshShell.Popup haben Sie die Möglichkeit, einen Standardschalter
anzugeben. Der Standardschalter ist der Schalter, der den Focus besitzt und ausgewählt wird,
wenn der Benutzer einfach nur die Eingabetaste drückt.
Es ist für einen Benutzer nicht unüblich, dass er einfach die Eingabetaste drückt, wenn eine
Fehlermeldung angezeigt wird. Daher sollten Sie bei der Auswahl des Standardschalters
vorsichtig sein. Sie können zum Beispiel den Schalter verwenden, der fast immer ausgewählt
wird. Oder Sie verwenden den 'sichersten' Schalter. Ihr Nachrichtenfenster könnte zum
Beispiel lauten: 'Sind Sie sicher, dass Sie alle Dateien auf der Festplatte löschen möchten?'. In
einem solchen Fall sollten Sie als Standardschalter den Schalter Nein festlegen - so werden
keine Dateien gelöscht, wenn der Benutzer versehentlich die Eingabetaste drückt.
Den Standardschalter legen Sie fest, indem Sie eine weitere Konstante zum vierten Parameter
addieren - Tabelle 3.19 zeigt Ihnen die möglichen Werte. Wenn Sie einen Schalter auswählen,
der nicht angezeigt wird (zum Beispiel den mittleren Schalter, wenn nur ein Schalter
angezeigt wird), dann ist der erste Schalter der Standardschalter.

Tabelle 3.19: Konstanten für den Standardschalter

Seite 172 von 394


Standardschalter Konstante Wert
Linker Schalter vbDefaultButton10
Mittlerer SchaltervbDefaultButton2256
Rechter Schalter vbDefaultButton3512
Script 3.34 zeigt zwei Nachrichtenfenster an. Beide Fenster verwenden die Schalter
Abbrechen, Wiederholen und Ignorieren. Beim ersten Fenster wird kein Standardschalter
angegeben - daher hat der erste Schalter den Focus. Beim zweiten Fenster wird der
Standardschalter mit der Konstante vbDefaultButton2 festgelegt - daher hat der Schalter
Wiederholen den Focus.

Script 3.34: Schalter Wiederholen als Standardschalter definieren

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

Seite 173 von 394


den das Script ausgeführt wird. Dann fragt es den Benutzer, ob dieser mehr Informationen
über die Datei erhalten möchte.

Script 3.35: Benutzereingaben über ein Nachrichtenfenster entgegennehmen

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

Das Objekt WshNetwork


Das Objekt WshNetwork ermöglicht es Ihren Scripten mit Netzwerklaufwerken und -druckern
zu arbeiten. Außerdem können Sie den Namen des Computers, dessen Domäne und den
Namen des angemeldeten Benutzers abfragen.
Das WshNetwork-Objekt kann für einige Aufgaben verwendet werden, die Sie auch über das
Kommandozeiletool net.exe ausführen können. Der Befehl net name gibt zum Beispiel den
Namen des Benutzers und den Namen des Computers zurück. Mit dem Befehl net use können
Sie ein Netzlaufwerk erstellen. Diese Aufgaben können Sie auch über das Objekt
WshNetwork ausführen, das somit zu einem idealen Werkzeug für Anmeldescripte wird.
In Tabelle 3.21 sehen Sie die Funktionalitäten von WshNetwork und dessen Methoden und
Eigenschaften.

Tabelle 3.21: Methoden und Eigenschaften des Objekts WshNetwork


Funktionalität Methode und Eigenschaft
Arbeiten mit Netzlaufwerken MapNetworkDrive

EnumNetworkDrives

Seite 174 von 394


Funktionalität Methode und Eigenschaft

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.

Abbildung 3.15: Das Objektmodell von WshNetwork


Auf das Objekt WshNetwork zugreifen
Bei WshNetwork handelt es sich um ein COM-Objekt. Mit dem folgenden Ausdruck können
Sie eine Instanz des Objekts erstellen:

Seite 175 von 394


Set objNetwork = WScript.CreateObject("WScript.Network")

Verwalten von Netzlaufwerken


Netzlaufwerke sind ein wichtiger Teil einer Netzwerkumgebung. Benutzer ziehen es
normalerweise vor, mit Netzlaufwerken statt mit UNC-Pfaden (Universal Naming
Convention) zu arbeiten - es ist einfach, sich daran zu erinnern, dass die Finanzdaten unter
Laufwerk X gespeichert sind, als sich an die Netzwerkfreigabe \\atl-fs-
01\departments\accounting\admin\financial_records\2002_archive zu erinnern.
Das Erstellen, Ändern und Löschen von Netzwerkfreigaben zu Laufwerksbuchstaben ist eine
der wenigen Aufgaben, die Sie nicht über WMI durchführen können - das Auflisten von
Netzwerklaufwerken ist hingegen sowohl mit dem WSH-Objekt WshNetwork alsauch über
WMI (über die Klasse Win32_MappedLogicalDisk) möglich.
Zur Arbeit mit Netzlaufwerken stellt Ihnen WshNetwork drei Methoden zur Verfügung:
MapNetworkDrive, RemoveNetworkDrive und EnumNetworkDrives.

Zuordnen von Netzwerklaufwerken


Über die Methode MapNetworkDrive ordnen Sie einen Laufwerksbuchstaben zu einer
Netzwerkfreigabe zu. Die Methode hat zwei zwingende und drei optionale Argumente - diese
sehen Sie in Tabelle 3.22.

Tabelle 3.22: Parameter von MapNetworkDrive


Parameter Type ErforderlichStandardwertBeschreibung
LocalName String Keiner Der Laufwerksbuchstabe gefolgt von
einem Doppelpunkt, der für das
Netzlaufwerk verwendet werden soll
(zum Beispiel H:)
RemoteName String Keiner Der UNC-Pfad der Netzwerkfreigabe - zum
Beispiel \\ServerName\ShareName oder
\\ServerName\ShareName\FolderName.
UpdateProfileBoolean False Ein Boolean-Wert, der angibt, ob das neue
Laufwerk im aktuellen Benutzerprofil
gespeichert werden soll. Mit dem Wert True
wird das neue Laufwerk gespeichert.
UserName String Keiner Verbindet das Netzlaufwerk unter
Verwendung eines alternativen
Benutzernamens.
Password String Keiner Das Passwort zum alternativen
Benutzernamen.
Das folgende Script zeigt, wie Sie mit MapNetworkDrive zwei neue Netzlaufwerke erstellen:
Set objNetwork = Wscript.CreateObject("WScript.Network")
objNetwork.MapNetworkDrive "G:", "\\atl-fs-01\Sales"
objNetwork.MapNetworkDrive "H:", "\\atl-fs-01\Users$\lewjudy"
Standardmäßig verwendet MapNetworkDrive die Anmeldeinformationen des aktuellen
Benutzers. Da Sie jedoch ein Netzlaufwerk nur dann zuordnen können, wenn Sie über die
erforderlichen Berechtigungen verfügen, haben Sie die Möglichkeit, über die Parameter

Seite 176 von 394


UserName und Password alternative Anmeldeinformationen anzugeben - zum Beispiel für
administrative Scripte.
Es gibt zwei Gründe, aus denen die Methode MapNetworkDrive fehlschlagen kann:

Der Benutzer, der das Script ausführt verfügt nicht über ausrechende Berechtigungen um ein
Netzwerklaufwerk zu erstellen.

Der lokale Laufwerksbuchstabe wird bereits verwendet.
Um Fehler durch fehlende Berechtigungen zu vermeiden, sollten Sie eine Fehlerbehandlung
über den Befehl On Error Resume Next implementieren. Einen Fehler durch einen bereits
verwendeten Laufwerksbuchstaben können Sie zum Beispiel umgehen, indem Sie das
Laufwerk trennen, das im Moment den Laufwerksbuchstaben verwendet.

Ein Netzlaufwerk trennen


Über die Methode RemoveNetworkDrive können Sie ein Netzlaufwerk trennen. Sie benötigt
als einzigen Parameter den lokalen Laufwerksbuchstaben von dem Netzlaufwerk, das Sie
trennen möchten.

Script 3.36: Trennen eines Netzlaufwerkes

1Set objNetwork = WScript.CreateObject("Wscript.Network")


2objNetwork.RemoveNetworkDrive "G:"
Die Methode akzeptiert zwei weitere optionale Parameter:

Einen Boolean-Wert - Wenn dieser auf True gesetzt ist, dann wird das Netzlaufwerk auch
dann getrennt, wenn es gerade verwendet wird.

Einen weiteren Boolean-Wert - Wenn dieser auf True gesetzt ist, dann wird das
Netzlaufwerk auch aus dem Benutzerprofil entfernt.

Auflisten der aktuellen Netzlaufwerke


Mit der Methode EnumNetworkDrives können Sie die aktuell zugeordneten Netzlaufwerke
auflisten. Sie gibt eine Collection zurück, in der jeweils in Paaren die lokalen
Laufwerksbuchstaben und die entsprechenden UNC-Pfade gespeichert sind. Der Index der
Collection beginnt bei 0 - die Elemente mit einer geraden Indexnummer enthalten jeweils die
lokalen Laufwerksbuchstaben, und die ungeraden Elemente enthalten die UNC-Pfade.
In Tabelle 3.23 sehen Sie ein Beispiel für die Collection.

Tabelle 3.23: Beispiel für die Collection mit den Netzwerklaufwerken


IndexWert
0 D:
1 \\atl-fs-01\users\kmyer
2 E:
3 \\atl-fs-02\accounting
4 F:

Seite 177 von 394


IndexWert
5 \\atl-fs-03\public
Wenn Sie die einzelnen Netzlaufwerke aus der Collection abfragen möchten, dann sollten Sie
in jedem Schleifendurchlauf jeweils zwei Elemente (den Laufwerksbuchstaben und den UNC-
Pfad) abfragen. Ein Beispiel hierfür sehen Sie in Script 3.37.

Listing 3.37: Abfragen der aktuellen Netzlaufwerke

1Set objNetwork = WScript.CreateObject("WScript.Network")


2Set colDrives = objNetwork.EnumNetworkDrives
3For i = 0 to colDrives.Count-1 Step 2
4 Wscript.Echo colDrives.Item(i) & vbTab & colDrives.Item (i + 1)
5Next

Verwalten von Netzwerkdruckern


Mit dem WshNetwork-Objekt haben Sie die Möglichkeit Netzwerkdrucker hinzuzufügen oder
zu entfernen, den Standarddrucker zu definieren und die Netzwerkdrucker aufzulisten.

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.

Windows-basierte Netzwerkdrucker hinzufügen


Mit der Methode AddWindowsPrinterConnection können Sie Drucker unter Windows 2000,
Windows Server 2003, Windows XP oder Windows NT hinzufügen. Als einzigen Parameter
müssen Sie hier den UNC-Pfad des Druckers angeben.

Script 3.38: Hinzufügen einer Windows-basierten Druckerverbindung

1Set objNetwork = Wscript.CreateObject("WScript.Network")


2objNetwork.AddWindowsPrinterConnection "\\HRServer01\Printer1"
Wenn Sie die Methode unter Windows 95, Windows 98 oder Windows Me verwenden, dann
müssen sie zwei Parameter angeben: den UNC-Pfad des Druckers und den Namen des
Druckertreibers (dieser muss bereits installiert sein). Außerdem akzeptiert die Methode unter
diesen Betriebssystemen einen dritten optionalen Parameter - den lokalen Port für den
Drucker.

Hinzufügen von MS-DOS-basierten Druckerverbindungen


Mit der Methode AddPrinterConnection können Sie MS-DOS-basierte Druckerverbindungen
hinzufügen. Sie benötigt zwei Parameter: den lokalen Port für den Druck und den UNC-Pfad
des Netzwerkdruckers.
Außerdem haben Sie die Möglichkeit, die neue Druckerverbindung zum Profil des Benutzers
hinzuzufügen. Hierzu verwenden Sie einen optionalen dritten Parameter. Wenn dieser auf
True gesetzt ist, dann wird die neue Druckerverbindung im Profil gespeichert.

Seite 178 von 394


Entfernen einer Druckerverbindung
Um eine Druckerverbindung zu entfernen, verwenden Sie die Methode
RemovePrinterConnection.
WshNetwork.RemovePrinterConnection(printerName, [forced], [updateProfile])
Der erste Parameter definiert den freigegebenen Drucker. Die beiden anderen Parameter sind
optional:

Soll die Verbindung auch dann getrennt werden, wenn der Drucker gerade verwendet wird?

Soll die Verbindung auch aus dem Benutzerprofil gelöscht werden?
Die Methode entfernt sowohl Windows- als auch MS-DOS-basierte Druckerverbindungen.
Wenn der Drucker über die Methode AddPrinterConnection eingerichtet wurde, dann muss
als Druckername der lokale Port angegeben werden. Wenn der Drucker mit der Methode
AddWindowsPrinterConnection angelegt wurde, dann muss als Druckername der UNC-Pfad
des Druckers angegeben werden.
Der folgende Befehl entfernt zum Beispiel den Drucker \\atl-ps-01\colorprinter.
Set objNetwork = WScript.CreateObject("WScript.Network")
objNetwork.RemovePrinterConnection "\\atl-ps-01\colorprinter"
Auflisten der verfügbaren Drucker
Die Abfrage der verfügbaren Netzwerkdrucker funktioniert genauso wie die Abfrage der
zugeordneten Netzwerklaufwerke. Mit der Methode EnumPrinterConnections erhalten Sie
eine Collection mit den Netzwerkdruckern. In ihr sind paarweise die lokalen Druckernamen
bzw. die Ports und die UNC-Pfade gespeichert.

Script 3.39: Auflisten der verfügbaren Drucker

1Set objNetwork = WScript.CreateObject("WScript.Network")


2Set colPrinters = objNetwork.EnumPrinterConnections
3For i = 0 to colPrinters.Count -1 Step 2
4 Wscript.Echo colPrinters.Item(i) & vbTab & colPrinters.Item (i + 1)
5Next
Wenn Sie das Script unter CScript ausführen, könnte die Ausgabe so aussehen:
LPT1: Drucker Marketing-Abteilung
XRX00034716DD75 \\atl-prn-xrx\plotter
XRX0000AA622E89 \\atl-prn-xrx\farbdrucker
Definieren des Standarddruckers
Viele Benutzer drucken Dokumente einfach über das Drucken-Symbol der Anwendung aus.
In den meisten Fällen bedeutet das, dass das Dokument über den Standarddrucker ausgedruckt
wird. Wenn Sie den verschiedenen Benutzern unterschiedliche Standarddrucker zuweisen,
können Sie die Last auf verschiedene Drucker verteilen. Dies können Sie über die Methode
SetDefaultPrinter durchführen. Die Methode verwendet die folgende Syntax:
WshNetwork.SetDefaultPrinter(printerName)
Beim Parameter printerName handelt es sich um den UNC-Pfad des Druckers (wenn es sich
um einen lokalen Drucker handelt, können Sie den Port des Druckers verwenden - zum
Beispiel LPT1). Das folgende Script richtet den Drucker \\atl-ps-01\colorprinter als
Standarddrucker ein:
Set objNetwork = WScript.CreateObject("WScript.Network")

Seite 179 von 394


objNetwork.SetDefaultPrinter("\\atl-ps-01\colorprinter")
Den aktuellen Standarddrucker können Sie über SetDefaultPrinter leider nicht abfragen.

Informationen über den Benutzer und den Computer abfragen


Das Objekt WshNetwork stellt drei Eigenschaften zur Verfügung: ComputerName,
UserDomain und UserName - Sie können diesen Eigenschaften allerdings keinen Wert
zuweisen (Nur-Lese-Eigenschaften).
Abhängig von Ihren Anforderungen können Sie die gleichen Informationen auch über ADSI
abrufen. Mit dem WSH können Sie außerdem nur den SAM-Kontonamen abrufen - mit ADSI
haben Sie auch Zugriff auf Informationen wie dem eindeutigen Namen (Distinguished Name -
DN) des Objekts (zum Beispiel cn=Ulf Dornheck Busscher,ou=Human
Resources,dc=fabrikam,dc=com). Mit dem DN können Sie dann direkt auf Active Directory
zugreifen und Informationen wie zum Beispiel die Gruppenzugehörigkeit des Benutzers
abrufen.
Wenn Sie jedoch nur den Benutzernamen, den Domänennamen oder den Computernamen
benötigen, dann reicht das Objekt WshNetwork vollkommen aus. Außerdem steht das WSH-
Objekt unter Windows 98 und Windows NT 4.0 standardmäßig zur Verfügung - dies ist bei
ADSI nicht der Fall.
Das WshNetwork-Objekt wird oft in Anmeldescripten verwendet - hier werden die
Informationen zum Beispiel zum Zuordnen von Netzwerklaufwerken benötigt. Script 3.40
führt eine solche Zuordnung durch (N zu \\fileserver01\accounting ). Jedoch nur, wenn der
Benutzer der Domäne ACT angehört. Wenn der Benutzer der Domäne DEV angehört, dann
wird Laufwerk N zu \\fileserver01\development zugeordnet.

Script 3.40: Zuordnen von Netzwerklaufwerken abhängig von der Domäne des
Benutzers

1 Set objNetwork = WScript.CreateObject("WScript.Network")


2 strUserDomain = objNetwork.UserDomain
3
4 If strUserDomain = "ACCOUNTING" Then
5 objNetwork.MapNetworkDrive "N:", "\\fileserver01\accounting", True
6 ElseIf strUserDomain = "DEVELOPMENT" Then
7 objNetwork.MapNetworkDrive "N:", "\\fileserver01\development", True
8 Else
9 Wscript.Echo "User " & objNetwork.UserName & _
10 "not in ACCOUNTING or DEVELOPMENT. N: not mapped."
11End If

Das Objekt WshController


Eine Einschränkung des WSH war es immer, dass Scripte nur lokal ausgeführt werden
können. Es war nicht möglich ein Script gegen einen Remotecomputer auszuführen. Stellen
Sie sich zum Beispiel vor, Sie möchten über ein Script auf einigen Remotecomputern eine
Druckerverbindung hinzufügen. Sie müssten dieses Script auf allen Remotecomputern
ausführen. In der Vergangenheit waren Sie nicht in der Lage ein Script auf Computer A
auszuführen und in diesem Script auf Computer B eine Druckerverbindung hinzuzufügen.
Daher wurde der WSH auch primär nur in Anmeldescripten verwendet.

Seite 180 von 394


Natürlich wäre es viel praktischer, wenn ein Script Änderungen auf einem oder mehreren
Remotecomputern durchführen könnte. Hierzu stellt Ihnen ab WSH 5.6 das Objekt
WshController zur Verfügung.
Das Objekt WshController ermöglicht es Ihnen, ein Controller Script (Steuerungsscript)zu
erstellen, das Worker Scripts (Arbeitsscripte) gegen andere Computer ausführen kann. Das
Controller Script initiiert, überwacht und beendet das Worker Script. Das Worker Script ist
hingegen einfach ein Script, das administrative Aufgaben ausführt - zum Beispiel das
Hinzufügen einer Druckerverbindung oder eines Netzwerklaufwerkes.
Das Worker Script muss sich nicht auf dem selben Computer befinden wie das Controller
Script - sein Speicherort muss jedoch relativ zu dem Computer angegeben werden, auf dem
das Controller Script ausgeführt wird. Sie können zum Beispiel ein Controller Script
erstellen, das auf ein Worker Script in einer Netzwerkfreigabe auf einem anderen Computer
zugreift und dieses Worker Script auf einem dritten Computer ausführt.
Das Script, das auf dem Remotecomputer ausgeführt wird, wird hierbei niemals auf dem
Remotecomputer gespeichert. Stattdessen wird es im WSH-Prozess des Remotecomputers
gestartet.
In Abbildung 3.16 sehen Sie eine Liste aller Objekte, Methoden, Eigenschaften und
Ereignisse des WshController-Objektes.

Abbildung 3.16: Das Objektmodell von WshController


Auf das Objekt WshController zugreifen
Bei WshController handelt es sich um ein COM-Objekt. Über die folgende Codezeile können
Sie eine Instanz des Objekts erstellen:
Set objController = WScript.CreateObject("WshController")

Seite 181 von 394


Anmerkung: Die ProgID des Objekts WshController folgt nicht denselben
Namenskonventionen wie den Objekten WshNetwork (WScript.Network) und WshShell
(WScript.Shell). Sie verwendet keinen Punkt und beginnt nicht mit WScript.

Vorbereiten der Remoteausführung von Scripten


Bevor Sie das Objekt WshController verwenden können, müssen Sie Ihre Umgebung
folgendermaßen konfigurieren:

Sowohl auf dem lokalen Computer als auch auf dem Remotecomputer muss der WSH in der
Version 5.6 installiert sein.

Sie müssen dem Registrierunsschlüssel HKEY_LOCAL_
MACHINE\SOFTWARE\Microsoft\Windows Script Host\Settings auf allen Zielcomputern
einen String-Eintrag (REG_SZ) mit dem Namen Remotehinzufügen und dessen Wert auf 1
setzen. Auf dem lokalen Computer, von dem aus Sie das Script starten, ist dieser Eintrag
nicht erforderlich.

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.

Script 3.41: Hinzufügen eines Registrierungseintrags, um Scripte remote ausführen zu


können

1Const HKEY_LOCAL_MACHINE = &H80000002


2strComputer = "RemoteComputerName"
3
4Set objRegProv = GetObject("winmgmts:{impersonationLevel=Impersonate}" & _
5 "!\\" & strComputer & "\root\default:StdRegProv")
6
7strKeyPath = "SOFTWARE\Microsoft\Windows Script Host\Settings"
8objRegProv.SetStringValue HKEY_LOCAL_MACHINE,strKeyPath,"Remote","1"
Der Benutzer, der das Script ausführt, muss ein Mitglied der Gruppe Administratoren des
Zielcomputers sein.

Funktionalitäten von WshController


Das Objekt WshController ermöglicht es Ihnen, Scripte aus Remotecomputern auszuführen,
deren Status zu überwachen und die von diesen Scripten generierten Fehler abzufragen. In
Tabelle 3.24 sehen Sie die Methoden, Eigenschaften und Ereignisse der Objekte
WshController, WshRemote und WshRemoteError, die Sie hierzu verwenden können.

Seite 182 von 394


Tabelle 3.24: Methoden, Eigenschaften und Ereignisse der Objekte WshController,
WshRemote und WshRemoteError
Aufgabe Methode, Eigenschaft oder Ereignis
Scripte auf Remotecomputern ausführen CreateScript, Execute, Terminate
Den Status von Remotescripten überwachenStatus, Start, End, Error (Ereignisse)
Fehler eines Remotescripts abfragen Error (Ereignis), Error (Eigenschaft), Character,
Description, Line, Number, Source, SourceText

Scripte auf einem Remotecomputer ausführen


Zum Starten eine Scripts auf einem Remotecomputer stellt Ihnen WshController die Methode
CreateScript zur Verfügung - diese gibt ein WshRemote-Objekt zurück.
Das WshRemote-Objekt kann dann zum Ausführen des Worker Scripts verwendet werden.
Das Worker Script wird also nicht über die Methode CreateScript selbst gestartet. Stattdessen
wird die Methode Execute des neuen WshRemote-Objekts zum Start des Scripts auf dem
Remotecomputer verwendet.
Script 3.42 startet das hypothetische Worker Script MapNetworkDrive.vbs auf dem
Remotecomputer RASServer01. Die Position des Worker Scripts kann als lokaler Pfad oder
als UNC-Pfad angegeben werden. In Script 3.42 wird allerdings gar kein Pfad angegeben - in
diesem Fall muss sich das Worker Script im gleichen Ordner befinden wie dass Controller
Script.

Script 3.42: Ein lokales Script auf einem Remotecomputer ausführen

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.

Den Status von Remotescripten überwachen


Wenn Sie ein Remotescript starten, dann möchten Sie wahrscheinlich auch wissen, ob das
Script erfolgreich ausgeführt wurde. Das Objekt WshRemote verfügt hierzu über eine
Eigenschaft mit dem Namen Status. Sie kann drei verschiedene Werte annehmen:

0 - das Remotescript wurde noch nicht gestartet.

1 - das Remotescript wird gerade ausgeführt.

Seite 183 von 394



2 - die Ausführung des Remotescripts ist beendet.
Zusätzliche zur Eigenschaft Status stehen Ihnen drei Ereignisse zur Überwachung des
Remotescripts zu Verfügung:

Start - dieses Ereignis wird ausgelöst, wenn die Ausführung des Remotescripts beginnt.

End - dieses Ereignis wird bei Beendigung des Remotescripts ausgelöst.

Error - dieses Ereignis wird ausgelöst, wenn im Remotescript ein Fehler auftritt. In einem
solchen Fall können Sie über das Objekt WshRemoteError von WshRemote weitere
Informationen über den Fehler abfragen.
Script 3.43 verwendet drei Subroutinen (Remote_Start, Remote_End und Remote_Error), die
auf die Ereignisse Start, Error und End reagieren. Diese Subroutinen werden aufgerufen,
wenn eins der Ereignisse ausgelöst wird, und sie zeigen eine einfache Nachricht an.
Durch den Aufruf von ConnectObject in Zeile 7 zwingt das Script dazu auf die Ereignisse zu
reagieren. Beachten Sie, dass der String 'Remote_', der als zweiter Parameter übergeben wird,
der erste Teil des Namens der Subroutine ist, die das entsprechende Ereignis verarbeitet. Der
zweite Teil des jeweiligen Namens ergibt sich aus dem jeweiligen Ereignis.

Script 3.43: Überwachen eines remote ausgeführten Scripts

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.

Seite 184 von 394


Die vom Remotescript ausgelösten Fehler genauer untersuchen
Wenn ein Fehler aufgetreten ist, dann müssen Sie feststellen, wie dieser Fehler zustande
gekommen ist. Hierzu können Sie bei einem Remotescript das Objekt WshRemoteError
verwenden (dieses Objekt ist eine Eigenschaft von WshRemote). Es enthält einige
Eigenschaften, die den aufgetretenen Fehler genauer definieren. Diese Eigenschaften sehen
Sie in Tabelle 3.25.

Tabelle 3.25: Eigenschaften des Objekts WshRemoteError


EigenschaftBeschreibung
Character Gibt die Zeichenposition in der aktuellen Scriptzeile wieder, an der
der Fehler aufgetreten ist. Beim Semikolon in der folgenden Zeile
handelt es sich zum Beispiel um ein falsches Zeichen - es befindet
sich an Position 14 der Zeile. Die Eigenschaft Character würde also
den Wert 14 zurückgeben: Wscript.Echo ;
Description Eine Beschreibung des Fehlers
Line Die Zeilennummer des Scripts, in der der Fehler aufgetreten ist.
Number Der Fehlercode des Fehlers.
Source Das COM-Objekt, das den Fehler ausgelöst hat.
SourceText Die Scriptzeile, die den Fehler ausgelöst hat. Diese Eigenschaft enthält
jedoch nicht in allen Fällen einen Wert.
Script 3.44 reagiert mit einer Subroutine auf das Error-Ereignis. Im Gegensatz zu Script 3.43,
dass nur eine einfach Fehlermeldung angezeigt hat, verwendet die Subroutine die Eigenschaft
Error von WshRemote, um eine Instanz des Objekts WshRemoteError zu erhalten. Dann zeigt
das Script alle verfügbaren Eigenschaften des Objekts an.

Script 3.44: Abfragen von Fehlerinformationen bei Remotescripten

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

Seite 185 von 394


24 objRemoteScript.Terminate
25 Wscript.Quit
26End Sub

Beschränkungen im Zusammenhang mit Remotescripten


Es gibt zwei wichtige Einschränkungen im Zusammenhang mit Remotescripten. Erstens gibt
es keinen einfachen Weg, um an die Ausgaben des Remotescripts zu gelangen, und zweitens
können Remotescripte nicht mit den Kontoinformationen des Benutzers arbeiten, der das
Controller Script ausgeführt hat.
Um das erste Problem zu umgehen, können Sie eine Textdatei erstellen, in der das Worker
Script dann seine Ausgaben speichert - diese Textdatei kann dann zum Beispiel in einer
Netzwerkfreigabe gespeichert sein. Weitere Informationen zur Erstellung von Textdateien
erhalten Sie im Kapitel Script Runtime Primer in diesem Buch.
Es gibt leider keinen Weg, um das zweite Problem zu vermeiden - jedenfalls nicht ohne
potentielle Sicherheitsprobleme.

Absichern von Scripten


Sicherheit ist in der Systemadministration immer ein wichtiges Thema - dies gilt auch für
Scripte. Der ILOVEYOU-Virus war nicht so erfolgreich, weil er Sicherheitslücken im
Windows Script Host ausgenutzt hat, sondern durch menschliches Fehlverhalten: Menschen
sind von natur aus neugierig. Wenn Sie mit der Frage konfrontiert werden 'Wollen Sie dieses
Script ausführen', und keine weiteren Informationen zur Verfügung stehen, dann entscheiden
sich viele Menschen dafür mit 'Ja' zu antworten.
Der WSH 5.6 hilft den Benutzern intelligentere Entscheidungen zu treffen. Sie können den
WSH zum Beispiel so konfigurieren, dass er eine Nachricht wie 'Der Autor dieses Scripts ist
unbekannt. Sind Sie sicher, dass Sie fortfahren wollen?' anzeigt, wenn ein Benutzer versucht
ein Script auszuführen. Alternativ kann der Administrator den Benutzern diese Entscheidung
auch abnehmen - der WSH kann so konfiguriert werden, dass er nur Scripte ausführt, die
digital signiert und freigegeben wurden.
In diesem Abschnitt werden mehrere Techniken untersucht, mit der Sie die Sicherheit Ihrer
Scripte verbessern können:

Signieren von Scripten.

Den Benutzer in der Scriptausführung einschränken.

Den Windows Script Host deaktivieren.

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.

Seite 186 von 394


Signieren von Scripten
Digitale Signaturen (eingeführt mit WSH 5.6) bieten Ihnen einen Weg, den Autoren eines
Scripts zu überprüfen und zu garantieren, dass das Script seit seiner Erstellung und Signierung
nicht verändert wurde. Das bedeutet nicht zwingend, dass das Script 'sicher' ist - auch
Virenautoren können Signaturen verwenden. Die Signatur bietet Ihnen jedoch zwei Vorteile:

Sie können definieren, welchen Scriptautoren vertraut wird und welchen nicht. Zum Beispiel
könnten Sie festlegen, dass nur die Scripte ausgeführt werden, die mit einem
vertrauenswürdigen Zertifikat signiert wurden.

Sie können sicherstellen, dass ein Script seit seiner Signierung nicht verändert wurde. Wenn
Sie wissen, dass das Script ThirdPartyScript.vbs sicher ist, dann können Sie das Script in
dem sicheren Wissen verwenden, dass es von niemandem manipuliert wurde. Wenn ein
Script signiert wird, dann wird ein 'Hash' für dieses Script ermittelt. Mit diesem Hash kann
die Signatur des Scripts überprüft werden. Wenn das Script verändert wurde, dann ist der
Hash nicht mehr gültig.
Wenn ein Script signiert wird, dann wird am Ende des Scripts eine digitale Signatur als
Kommentar angehängt. Eine solche Signatur kann zum Beispiel so aussehen:
'' SIG '' Begin signature block
'' SIG '' MIIC8AYJKoZIhvcNAQcCoIIC4TCCAt0CAQExDjAMBggq
'' SIG '' hkiG9w0CBQUAMGYGCisGAQQBgjcCAQSgWDBWMDIGCisG
'' SIG '' AQQBgjcCAR4wJAIBAQQQTvApFpkntU2P5azhDxfrqwIB
'' SIG '' AAIBAAIBAAIBAAIBADAgMAwGCCqGSIb3DQIFBQAEEPC2
'' SIG '' QdSn0Xnjl7nT/Xwadl2gggF6MIIBdjCCASCgAwIBAgIQ
'' SIG '' NeMgQmXo1o1F8M6hs6TX1jANBgkqhkiG9w0BAQQFADAW
'' SIG '' MRQwEgYDVQQDEwtSb290IEFnZW5jeTAeFw0wMDEyMjEy
'' SIG '' MzUxMTJaFw0zOTEyMzEyMzU5NTlaMBUxEzARBgNVBAMT
'' SIG '' Ck15IENvbXBhbnkwXDANBgkqhkiG9w0BAQEFAANLADBI
'' SIG '' AkEAx/bBOOqOzdHk2EfxXloUaGo9PtI/HSJ9LQSXkhF7
'' SIG '' neEf4Qy+oyA7NImnOacI+1HDCOAPeKgGJIvaFcZs0BuM
'' SIG '' iQIDAQABo0swSTBHBgNVHQEEQDA+gBAS5AktBh0dTwCN
'' SIG '' YSHcFmRjoRgwFjEUMBIGA1UEAxMLUm9vdCBBZ2VuY3mC
'' SIG '' EAY3bACqAGSKEc+41KpcNfQwDQYJKoZIhvcNAQEEBQAD
'' SIG '' QQA6/fIIDKycSp2DdBT/A3iUSxoiu2BqmEEpVoGKE5yY
'' SIG '' CA3MDWuI29RRvgNJ2oQasb8rZiD5dEexGK3rWEQGV6r+
'' SIG '' MYHhMIHeAgEBMCowFjEUMBIGA1UEAxMLUm9vdCBBZ2Vu
'' SIG '' Y3kCEDXjIEJl6NaNRfDOobOk19YwDAYIKoZIhvcNAgUF
'' SIG '' AKBOMBAGCisGAQQBgjcCAQwxAjAAMBkGCSqGSIb3DQEJ
'' SIG '' AzEMBgorBgEEAYI3AgEEMB8GCSqGSIb3DQEJBDESBBCV
'' SIG '' t6owbn7YLnkAnCqiDdINMA0GCSqGSIb3DQEBAQUABECe
'' SIG '' xmfNlmrIls2kFkyhXOWKicnpOk5iW4twTRNAc4LAkO8M
'' SIG '' uk0ZBCBgR5XC8F7slEMfWCG9R7129EUF4vFhZToK
'' SIG '' End signature block

Die Verwendung von signierten Scripten erzwingen


Um die Sicherheitseinstellung für signierte und unsignierte Scripte zu konfigurieren, müssen
Sie den Registrierungsschlüssel HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
Script Host\Settings\TrustPolicy bearbeiten. Die folgenden Werte können Sie verwenden:

0 - alle Scripte werden ohne Warnung ausgeführt (die Standardeinstellung).

1 - bevor ein Script ausgeführt wird, wird eine Sicherheitswarnung mit dem Sicherheitsstatus
des Scripts angezeigt (signiert und überprüft, signiert und nicht überprüft und unsigniert).
Der Benutzer hat jedoch unabhängig vom Status des Scripts die Möglichkeit das Script

Seite 187 von 394


auszuführen. Außerdem kann er sich weitere Informationen zur Signierung des verwendeten
Zertifikats anzeigen lassen.

2 - bevor ein Script ausgeführt wird, wird dessen Signatur überprüft. Es wird geprüft, ob das
Script aus einer vertrauenswürdigen Quelle stammt. Wenn dies der Fall ist, dann wird das
Script automatisch ausgeführt. Wenn das Script unsigniert ist oder nicht aus einer
vertrauenswürdigen Quelle stammt, dann wird das Script nicht ausgeführt. Der Benutzer hat
in so einem Fall keine Möglichkeit die Ausführung des Scripts zu erzwingen. Er erhält
stattdessen die folgende Nachricht:

Ausführung des Windows Script Host fehlgeschlagen. (Keine Signatur vorhanden.)

Scripte über ein mit Hilfe eines Scripts signieren


Der WSH 5.6 stellt ein Objekt mit dem Namen Scripting.Signer zur Verfügung, über das Sie
ein Script mit Hilfe eines Scripts signieren können. Hierzu gehen Sie folgendermaßen vor:

Erstellen Sie eine Instanz des Objekts Scripting.Signer.

Verwenden Sie die Methode SignFile. Diese erwartet als Parameter den Dateinamen des zu
signierenden Scripts und den Namen des Zertifikats, mit dem das Script signiert werden soll.
Das folgende Script verwendet zum Beispiel das Zertifikat mit dem Namen IT Department
und das Script C:\Scripts\CreateUsers.vbs zu signieren:
set objSigner = WScript.CreateObject("Scripting.Signer")
objSigner.SignFile "C:\Scripts\CreateUsers.vbs", "IT Department"
Sie können auch mehrere Scripte auf einmal signieren. Das folgende Script verwendet eine
Schleife, um alle Scripts im Ordner C:\Scripts zu signieren (es geht allerdings davon aus, dass
in diesem Ordner nur Scripte gespeichert sind):
set objSigner = WScript.CreateObject("Scripting.Signer")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("c:\scripts")
Set colListOfFiles = objFolder.Files
For each objFile in colListOfFiles
objSigner.SignFile objFile.Name, "IT Department"
Next

Eine Signatur mit Hilfe eines Scripts überprüfen


Das Objekt Scripting.Signer kann auch zur Überprüfung einer Signatur verwendet werden.
Hierzu verwenden Sie die Methode VerifyFile mit den folgenden Parametern:

Dem Dateinamen des Scripts, dessen Signatur Sie überprüfen möchten.

Einen Boolean-Wert, der angibt ob, Sie eine Sicherheitsmeldung anzeigen möchten, wenn
die Signatur nicht überprüft werden kann. Wenn der Wert auf False gesetzt ist, dann wird
keine Meldung angezeigt.
Das folgende Script überprüft die Signatur von Script C:\Scripts\CreateUsers.vbs und
unterdrückt die Sicherheitswarnung. Es gibt einen von zwei möglichen Werten zurück: True
bedeutet, dass die Signatur überprüft wurde, und False bedeutet, dass das Script nicht signiert
ist oder die Signatur nicht überprüft werden konnte:
set objSigner = WScript.CreateObject("Scripting.Signer")
blnShowGUI = False

Seite 188 von 394


blnIsSigned = objSigner.VerifyFile("C:\Scripts\CreateUsers.vbs",
blnShowGUI)
If blnIsSigned then
WScript.Echo objFile.Name & " wurde signiert."
Else
WScript.Echo objFile.Name & " wurde nicht signiert."
End If
End If
Natürlich können Sie auch mit der Methode VerifyFile mehrere Signaturen auf einmal prüfen.
Das folgende Script überprüft die Signaturen aller Scripte im Ordner C:\Scripts (es geht auch
diesmal wieder davon aus, dass im Ordner nur Scripte gespeichert sind):
set objSigner = WScript.CreateObject("Scripting.Signer")
blnShowGUI = False

Set objFSO = CreateObject("Scripting.FileSystemObject")


Set objFolder = objFSO.GetFolder("C:\Scripts")
Set colListOfFiles = objFolder.Files
For each objFile in colListOfFiles
blnIsSigned = objSigner.VerifyFile(objFile.Name, blnShowGUI)
If blnIsSigned then
WScript.Echo objFile.Name & " wurde signiert."
Else
WScript.Echo objFile.Name & " wurde nicht signiert."
End If
Next

Die Ausführung von Scripten einschränken


Standardmäßig wird ein Script mit einem Doppelklick auf eine .vbs-Datei sofort ausgeführt.
Über die Registrierung können Sie dieses Verhalten jedoch ändern. Der Benutzer wird
hierdurch jedoch nicht daran gehindert, dass Script auszuführen. Er kann zum Beispiel
einfach die Option Öffnen mit im Kontextmenü auswählen und das Script dann über
Wscript.exe oder Cscript.exe ausführen. Außerdem kann er über die folgenden Befehle das
Script in der Kommandozeile starten:

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:

Seite 189 von 394


1.Sie verwendet Reg.exe (zum Beispiel aus den Windows 2000 Support Tools), um den
Registrierungspfad HKEY_CLASSES_ROOT\VBSFile\Shell nach
HKEY_CLASSES_ROOT\VBSFile\bkupShell zu kopieren (der gesamte Pfad wird gesichert,
damit die Originaleinstellungen bei Bedarf wiederhergestellt werden können).
2.Sei löscht HKEY_CLASSES_ROOT\VBSFile\Shell.
3.Sie erstellt einen neuen Eintrag (NoOpen) in HKEY_CLASSES_ROOT\VBSFile und
konfiguriert die gewünschte Warnmeldung als Wert für diesen Eintrag - in dieser Beispiel-
Batchdatei lautet diese Warnmeldung 'Führen Sie dieses Script nicht aus, wenn es nicht von
der IT-Abteilung freigegeben wurde.' (die Länge der Warnmeldung ist auf 140 Zeichen
begrenzt).
Eine Beschränkung für andere Scriptdateien (zum Beispiel .VBE, .JS, .JSE und .WSF)
können Sie auf ähnliche Weise konfigurieren.

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.

Deaktivieren des Windows Script Host


Wenn erforderlich, können Sie den Windows Script Host auch deaktivieren - so können Sie
sicherstellen, dass keine Scripte mehr ausgeführt werden, die vom WSH abhängig sind
(inklusive VBScript und JScript).
Um den Windows Script Host zu deaktivieren, erstellen Sie einen der beiden folgenden
Registrierungseinträge (REG_DWORD) und setzen seinen Wert auf 0. Um den WSH für
einen bestimmten Benutzer zu deaktivieren, verwenden Sie den folgenden Eintrag:
HKEY_CURRENT_USER\Software\Microsoft\Windows Script Host\Settings\Enabled
Um den WSH für alle Benutzer des Computers zu deaktivieren, verwenden Sie diesen
Eintrag:
HKEY_CURRENT_USER\Software\Microsoft\Windows Script Host\Settings\Enabled
Wenn der WSH deaktiviert ist, sehen Sie die folgende Fehlermeldung, wenn Sie versuchen
ein WSH-Script zu starten:
Der Zugriff auf Windows Script Host wurde auf diesem Computer deaktiviert.
Für weitere Informationen wenden Sie sich an Ihren Administrator.
Die Meldung wird auch dann angezeigt, wenn der Benutzer versucht, ein Script über die
Kommandozeile zu starten (zum Beispiel über den Befehl cscript.exe c:\scripts\myscript.vbs).

Scripting-Konzepte und -Technologien zur


Systemadministration - Kapitel 4 - Die
Script-Laufzeitbibliothek
Veröffentlicht: 26. Apr 2004

Seite 190 von 394


Die Verwaltung des Dateisystems ist ein wichtiger Teil der Systemadministration - und leider
bieten in diesem Bereich weder der Windows Script Host (WSH) noch Microsoft Visual
Basic Scripting Edition (VBScript) sehr viele Möglichkeiten. Glücklicherweise können Sie
zur Verwaltung von Laufwerken, Ordnern und Dateien die Script-Laufzeitbibliothek (Script
Runtime Library) verwenden. Sie stellt Methoden zum Lesen und Schreiben in und aus
Textdateien, zum Erstellen von "Verzeichnissen" und zum Codieren von Scripten zur
Verfügung.
(Engl. Originaltitel: Script Runtime Primer)

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).

Anmerkung: In diesem Kapitel werden die Objekte FileSystemObject und Dictionary


besprochen. Das Script Encoder-Objekt wird jedoch nicht behandelt.
Die Script Runtime Library ist Teil von Windows 2000. Sie wird auch zusammen mit
bestimmten Microsoft-Anwendungen installiert. Hierzu zählen unter anderem:

Windows Script Host

VBScript

Seite 191 von 394



Internet Explorer

Microsoft Office

Das Objekt FileSystemObject


Wie der Name (FileSystemObject - Dateisystemobjekt) schon andeutet, hilft Ihnen das Objekt
FileSystemObject (FSO) bei der Arbeit mit dem Dateisystem. Es ermöglicht Ihnen,
grundlegende Informationen über Dateisystemelemente wie Laufwerke, Ordner und Dateien
abzurufen, und stellt außerdem Methoden zur Durchführung von administrativen Aufgaben
zur Verfügung - zum Beispiel dem Kopieren, Löschen und Verschieben von Dateien und
Ordnern.
Der Name FileSystemObject ist nicht ganz passend - denn das Objekt setzt sich eigentlich aus
mehreren Objekten zusammen. Die einzelnen Objekte von FileSystemObject sehen Sie in
Tabelle 4.1.

Tabelle 4.1: Die einzelnen Objekte des Objekts FileSystemObject


Objekt Beschreibung
Drive Stellt den Zugriff auf ein Laufwerk oder eine Collection von Laufwerken zur
Verfügung.
File Stellt den Zugriff auf eine Datei oder eine Collection von Dateien zur Verfügung.
Folder Stellt den Zugriff auf einen Ordner Laufwerk oder eine Collection von Ordnern
zur Verfügung.
TextStreamStellt eine Quelle zur Verfügung, aus der Text gelesen werden kann, in die Text
geschrieben werden kann, oder an die Text angehängt werden kann.
Die einzelnen Objekte werden in diesem Kapitel genauer besprochen.

Verwalten von Laufwerken


Als Systemadministrator müssen Sie wissen, welche Laufwerke auf einem Computer
installiert sind, und Sie müssen deren Eigenschaften abfragen können - zum Beispiel
Laufwerkstyp (Diskettenlaufwerk, Festplatte, CD-ROM), Laufwerksgröße und den freien
Speicherplatz des Laufwerks.
Als Scriptautor haben Sie zwei primäre Optionen bei der Verwaltung von Laufwerken: das
Objekt FileSystemObject und WMI (Windows Management Instrumentation). Im
Allgemeinen ist es besser, die Laufwerksverwaltung über WMI durchzuführen - und zwar aus
den folgenden Gründen:

WMI kann einige Eigenschaften zur Verfügung stellen, die Ihnen über das FileSystemObject
nicht zur Verfügung stehen - zum Beispiel die physikalischen Eigenschaften eines Laufwerks
(Köpfe, Sektoren und Zylinder).

WMI kann wahlweise nur bestimmte Laufwerkstypen zurückgeben (zum Beispiel nur
Festplatten). Mit dem Objekt FileSystemObject ist dies nicht möglich.

Mit WMI können Sie Laufwerksinformationen von Remotecomputern abfragen. Mit
Seite 192 von 394
FileSystemObject ist dies nur zusammen mit dem Objekt WshController möglich.
Auch wenn WMI also die bessere Technologie für solche Zwecke darstellt, gibt es doch zwei
Gründe dafür, dass Sie sich mit dem Objekt FileSystemObject auskennen sollten. Erstens
kann es auch auf älteren Computern ohne WMI verwendet werden (zum Beispiel Microsoft®
Windows® 98) - auch wenn es für einige ältere Betriebssysteme möglich ist, WMI
nachträglich zu installieren. Und zweitens wird das Objekt FileSystemObject seit langer Zeit
von vielen Scriptautoren verwendet. Es ist daher sehr wahrscheinlich, dass Sie auf das Objekt
stoßen werden, wenn Sie Scripte anderer Autoren lesen und verwenden.

Eine Collection mit Laufwerken abrufen


Bevor Sie die Laufwerke eines Computers verwalten können, müssen Sie wissen, welche
Laufwerke überhaupt zur Verfügung stehen. Das Objekt FileSystemObject stellt Ihnen hierzu
einen Collection mit allen verfügbaren Laufwerken zur Verfügung - uns zwar inklusive aller
Laufwerke mit Wechseldatenträgern und zugeordneten Netzlaufwerke (mit anderen Worten:
jedes Laufwerk mit einem Laufwerksbuchstaben).
Um diese Collection zu erhalten, erstellen Sie erst eine Instanz von FileSystemObject und eine
Referenz auf die Eigenschaft Drives. Dann können Sie diese Referenz (Drives ist die
Collection) für eine Auflistung aller Elemente der Collection nutzen.
Script 4.1 ruft eine Collection mit allen auf dem Computer installierten Laufwerken ab und
gibt für jedes Element der Collection den Laufwerksbuchstaben zurück.

Script 4.1: Auflisten aller auf einem Computer installierten Laufwerke

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.

Binden an ein bestimmtes Laufwerk


Wenn Sie bereits wissen, mit welchem Laufwerk Sie arbeiten möchten (zum Beispiel mit
Laufwerk C oder dem Netzlaufwerk \\accounting\\receivables, dann können Sie die Methode
GetDrive verwenden, um eine Referenz auf dieses Laufwerk zu erhalten. Sie müssen so nicht
die gesamte Collection durchgehen.
Die Methode GetDrive erwartet einen Parameter - den Laufwerksbuchstaben oder den UNC-
Pfad des Netzlaufwerks. Den Laufwerksbuchstaben können Sie in unterschiedlichen
Varianten angeben:

C

C:

C:\

Seite 193 von 394


Script 4.2 erstellt eine Instanz von FileSystemObject, verwendet die Methode GetDrive, um
eine direkte Referenz auf Laufwerk C zu erhalten und gibt dann den freien Speicherplatz
dieses Laufwerks aus.

Script 4.2: Eine Referenz auf ein einzelnes Laufwerk

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objDrive = objFSO.GetDrive("C:")
3Wscript.Echo "Verfügbarer Speicherplatz: " & objDrive.AvailableSpace
Wie Sie sehen, ist keine For-Each-Schleife erforderlich. Das liegt daran, dass GetDrive ein
einzelnes Objekt vom Typ Drive statt ein Objekt (Collection) vom Typ Drives zurückgibt.

Auflisten der Laufwerkseigenschaften


Die Collection Drives wird meist zur Inventarisierung oder Überwachung verwendet - als
Systemadministrator müssen Sie wissen, welche Laufwerke auf bestimmten Computern zur
Verfügung stehen und außerdem über detaillierte Informationen zu diesen Laufwerken
verfügen (zum Beispiel die Seriennummern oder den freien Speicherplatz). Mit einer Drives-
Collection oder einem einzelnen Drive-Objekt können Sie die in Tabelle 4.2 aufgelisteten
Eigenschaften abfragen.

Tabelle 4.2: Eigenschaften des Objekts Drive


Eigenschaft Beschreibung
AvailableSpaceDer freie Speicherplatz auf dem Laufwerk in Byte. Um den freien
Speicherplatz in KB zu erhalten, teilen Sie diesen Wert durch 1.024 (es
handelt sich um den Speicherplatz, der dem aktuellen Benutzer zur Verfügung
steht - wenn Kontingente verwendet werden, kann der Wert kleiner sein als
der gesamte zur Verfügung stehende freie Speicherplatz).
DriveLetter Der dem Laufwerk zugewiesene Laufwerksbuchstabe ohne den angehängten
Doppelpunkt. Für das Diskettenlaufwerk wird also zum Beispiel der
Buchstabe A verwendet.
DriveType Ein Integer-Wert, der den Laufwerkstyp angibt:

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

Seite 194 von 394


Eigenschaft Beschreibung
befindet, hat diese Eigenschaft den Wert False.
Path Pfad zum Laufwerk. Bei lokalen Laufwerken finden Sie unter dieser
Eigenschaft den Laufwerksbuchstaben (zum Beispiel A). Bei Netzlaufwerken
gibt die Eigenschaft den UNC-Pfad des Laufwerkes zurück (zum Beispiel
\\Server1\SharedFolder).
RootFolder Der Pfad zum Stammordner des Laufwerks.
SerialNumber Die Seriennummer des Laufwerks. Bei Diskettenlaufwerken oder
Netzlaufwerken hat diese Eigenschaft normalerweise den Wert 0.
ShareName Freigabename eines Netzwerklaufwerks.
TotalSize Gibt die Gesamtgröße des Laufwerks in Byte zurück (um die Gesamtgröße in
KB zu erhalten, teilen Sie den Wert durch 1.024. Für die Gesamtgröße in MB
teilen Sie den Wert durch 1.048.576 (1.024 x 1.024).
VolumeName Der Volumenname des Laufwerks.
Um die Laufwerke eines Computers aufzulisten erstellen Sie eine Instanz von
FileSystemObject und eine Referenz auf die Eigenschaft Drives und verwenden dann eine
For-Each-Schleife, um alle Elemente der Collection zu durchlaufen. In der Schleife können
Sie für die einzelnen Laufwerke jeweils alle Eigenschaften ausgeben.

Script 4.3: Auflisten der Laufwerkseigenschaften

1 Set objFSO = CreateObject("Scripting.FileSystemObject")


2 Set colDrives = objFSO.Drives
3 For Each objDrive in colDrives
4 Wscript.Echo "Verfügbarer Speicherplatz: " & objDrive.AvailableSpace
5 Wscript.Echo "Laufwerksbuchstabe: " & objDrive.DriveLetter
6 Wscript.Echo "Laufwerkstyp: " & objDrive.DriveType
7 Wscript.Echo "Dateisystem: " & objDrive.FileSystem
8 Wscript.Echo "Bereit: " & objDrive.IsReady
9 Wscript.Echo "Pfad: " & objDrive.Path
10 Wscript.Echo "Stammordner: " & objDrive.RootFolder
11 Wscript.Echo "Seriennummer: " & objDrive.SerialNumber
12 Wscript.Echo "Freigabename: " & objDrive.ShareName
13 Wscript.Echo "Gesamtgröße: " & objDrive.TotalSize
14 Wscript.Echo "Volumenname: " & objDrive.VolumeName
15Next
Wenn Sie Script 4.3 unter CScript ausführen, erhalten Sie eine ähnliche Ausgabe wie die
folgende:
Verfügbarer Speicherplatz: 5422272512
Laufwerksbuchstabe: C
Laufwerkstyp: 2
Dateisystem: NTFS
Bereit: Wahr
Pfad: C:
Stammordner: C:\
Seriennummer: 2018221812
Freigabename:
Gesamtgröße: 15356563456
Volumenname: Festplatte

Seite 195 von 394


Prüfen, ob ein Laufwerk bereit ist
Script 4.3 hat eine potentielle Fehlerquelle. Wenn sich keine Diskette im Diskettenlaufwerk
oder keine CD im CD-ROM befindet, dann schlägt das Script mit der Fehlermeldung
Laufwerk nicht bereit fehl.
Wenn ein Laufwerk nicht bereit ist (normalerweise, weil kein Medium eingelegt ist), dann
können Sie nur die folgenden Eigenschaften ohne Fehler abfragen:

DriveLetter

DriveType

IsReady

ShareName
Glücklicherweise haben Sie über die Eigenschaft IsReady die Möglichkeit festzustellen, ob
ein Laufwerk tatsächlich nicht bereit ist. Wenn ihr Wert True ist, dann können Sie ohne
Gefahr alle anderen Eigenschaften abrufen.
Script 4.4 ruft eine Collection mit den verfügbaren Laufwerken ab. Für jedes Laufwerk prüft
das Script über die Eigenschaft IsReady, ob es die restlichen Eigenschaften ohne Fehler
abfragen kann. Wenn dies möglich ist, gibt das Script den Laufwerksbuchstaben und den
freien Speicherplatz des Laufwerks zurück. Wenn das Laufwerk nicht bereit ist, dann gibt das
Script nur den Laufwerksbuchstaben zurück (eine der vier Eigenschaften, die auch in diesem
Zustand gefahrlos abgefragt werden kann).

Script 4.4: Prüfen, ob ein Laufwerk bereit ist

1 Set objFSO = CreateObject("Scripting.FileSystemObject")


2 Set colDrives = objFSO.Drives
3 For Each objDrive in colDrives
4 If objDrive.IsReady = True Then
5 Wscript.Echo "Drive letter: " & objDrive.DriveLetter
6 Wscript.Echo "Free space: " & objDrive.FreeSpace
7 Else
8 Wscript.Echo "Drive letter: " & objDrive.DriveLetter
9 End If
10Next

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.

Verwalten von Ordnern


Wenn Sie wissen in welchem Laufwerk eine Datei gespeichert ist, dann benötigen Sie im
nächsten Schritt den Ordner, in der die Datei gespeichert ist. Bei vielen anderen Aufgaben der
Systemadministration müssen Sie die Inhalte von Ordnern auflisten, Ordner kopieren, Ordner
anlegen und sie auch wieder löschen.

Seite 196 von 394


Das Objekt FileSystemObject stellt Ihnen nicht nur detaillierte Informationen zu einem
Ordner zur Verfügung, sondern bietet Ihnen auch Möglichkeiten zum Kopieren, Verschieben
und Löschen an. Außerdem können Sie die Dateien und Ordner in einem Ordner auflisten.

Eine Referenz auf einen Ordner erstellen


In der Windows-Shell sind Ordner COM-Objekte. Das bedeutet, dass Sie vor einem Zugriff
auf die Eigenschaften eines Ordners eine Objektreferenz auf diesen Ordner erstellen müssen.
Dies können Sie über die Methode FileSystemObject.GetFolder durchführen.
Für die Methode GetFolder benötigen Sie den Pfad des Ordners. Erkann entweder als lokaler
Pfad oder als UNC-Pfad angegeben werden (zum Beispiel \\accounting\receivables). Sie
dürfen keine Wildcards verwenden. Außerdem können Sie keine Referenz auf mehrere
Ordner erstellen. Die folgende Codezeile führt also zu einem Fehler:
objFSO.GetFolder("C:\FSO", "C:\Scripts")
Wenn Sie mit mehreren Ordnern arbeiten wollen, dann müssen Sie entweder WMI verwenden
oder für jeden Ordner eine separate Referenz erstellen.
Script 4.5 erzeugt zum Beispiel eine Referenz auf den Ordner C:\FSO und weist diese der
Variable objFolder zu.

Script 4.5: Erstellen einer Referenz auf einen Ordner

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFolder = objFSO.GetFolder("C:\FSO")
Mit dem Punkt (.) können Sie eine Referenz auf den aktuellen Ordner erstellen, und mit zwei
Punkten (..) erstellen Sie eine Referenz auf den dem aktuellen Ordner übergeordneten Ordner.
Mit dem Backslash schließlich erstellen Sie eine Referenz auf den Stammordner. Die
folgende Codezeile erstellt zum Beispiel eine Referenz auf den aktuellen Ordner:
Set objFolder = objFSO.GetFolder(".")

Prüfen, ob ein Ordner vorhanden ist


Bei den meisten Ordneroperationen muss der Ordner bereits vorhanden sein - ein Script kann
einen Ordner, der nicht vorhanden ist nicht kopieren, verschieben oder löschen. Ein solcher
Versuch wird zur Fehlermeldung Pfad nicht gefunden führen.
Um solche Probleme zu vermeiden, können Sie mit der Methode FolderExists überprüfen, ob
ein Ordner schon vorhanden ist. Die Methode benötigt einen Parameter: den Pfad des
Ordners. Sie gibt einen Boolean-Wert zurück. Wenn der Rückgabewert True ist, dann ist der
Ordner vorhanden - bei False nicht.
Script 4.6 verwendet die Methode FolderExists, um die Existenz von Ordner C:\FSO zu
überprüfen. Wenn die Methode den Wert True zurückgibt, dann erstellt das Script eine
Referenz auf den Ordner. Andernfalls gibt das Script die Nachricht "Ordner ist nicht
vorhanden zurück".

Script 4.6: Überprüfen, ob ein Ordner vorhanden ist

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2If objFSO.FolderExists("C:\FSO") Then
3 Set objFolder = objFSO.GetFolder("C:\FSO")
4 Wscript.Echo "Referenz erstellt."

Seite 197 von 394


5Else
6 Wscript.Echo "Ordner ist nicht vorhanden zurück?
7End If

Einen Ordner erstellen


Das Objekt FileSystemObject ermöglicht es Ihnen über Ihr Script neue Ordner anzulegen.
Script 4.6 prüft zum Beispiel, ob ein bestimmter Ordner vorhanden ist. Wenn der Ordner
existiert, dann verwendet es die Methode GetFolder, um eine Referenz auf den Ordner zu
erstellen. Wenn der Ordner nicht vorhanden ist, dann gibt das Script eine Benachrichtigung
aus.
Auch wenn das Script so daran gehindert wird einen Fehler zu produzieren, ist dies wohl
kaum die beste Lösung. Statt den Benutzer einfach darüber zu informieren, dass der Ordner
nicht vorhanden ist, wäre es möglicherweise besser, den Ordner anzulegen. Hierzu kann das
Script zum Beispiel die Methode FileSystemObject.CreateFolder verwenden. Sie erwartet als
Parameter den vollständigen Pfad des neuen Ordners. Script 4.7 erstellt zum Beispiel einen
Ordner mit dem Namen C:\FSO.

Script 4.7: Einen neuen Ordner erstellen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFolder = objFSO.CreateFolder("C:\FSO")
Wenn der zu erstellende Ordner schon vorhanden ist, dann wird ein Fehler erzeugt ('Datei ist
bereits vorhanden'). Daher sollten Sie vorher prüfen, ob der neue Ordner bereits vorhanden
ist.

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).

Löschen eines Ordners


Manchmal ist es erforderlich, einen Ordner zu löschen. Zum Beispiel, wenn Sie einen
temporären Ordner entfernen möchten. Hierzu können Sie die Methode DeleteFolder
verwenden. Sie benötigt als Parameter den Pfad des zu löschenden Ordners. Script 4.8 löscht
zum Beispiel den Ordner C:\FSO und seine gesamten Inhalte.

Script 4.8: Löschen eines Ordners

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2objFSO.DeleteFolder("C:\FSO")
Die Methode DeleteFolder löscht den Ordner und alle Inhalte sofort. Es wird keine
Bestätigung angefordert, und die Elemente werden auch nicht im Papierkorb abgelegt.

Ordner über Wildcards löschen

Seite 198 von 394


Ein Hauptvorteil der Verwaltung über Scripte ist, dass sie viele Aufgaben auf einmal
erledigen können. Statt also viele Ordner einen nach dem anderen zu löschen, können Sie
diese Aufgabe einfach in einem Schritt über ein Script durchführen.
Das Objekt FileSystemObject erlaubt es Ihnen, Ordner über Wildcards zu löschen. Stellen Sie
sich zum Beispiel vor, Sie haben es mit der Ordnerstruktur aus Abbildung 4.1 zu tun und
möchten alle Unterordner löschen, die mit einem U anfangen.

Abbildung 4.1: Beispiel-Ordnerstruktur


Eine solche Aufgabe können Sie über die folgende Scriptzeile ausführen:
objFSO.DeleteFolder("C:\FSO\U*")
Sie löscht die Ordner Unterordner 1 und Unterordern 2.
Wildcards können nur im letzten Teil des Pfades verwendet werden. Die folgende Scriptzeile
wird also zum Fehler 'Pfad nicht gefunden' führen:
objFSO.DeleteFolder("C:\*\Unterordern 1")

Ordner und deren Inhalte kopieren


Über die Methode CopyFolder können Sie Ordner und deren Inhalte kopieren. Wenn Sie
keine Wildcards verwenden, funktioniert die Methode wie der Befehl Xcopy /E: sie kopiert
alle Dateien und alle Unterordner, inklusive aller leeren Unterordner. Die Methode benötigt
zwei Parameter:

Quellordner - der zu kopierende Ordner. Dieser Ordner kann entweder als lokaler Pfad
(C:\Scripts) oder als UNC-Pfad (\\helpdesk\scripts) angegeben werden.

Zielordner - der Ordner, in dem die Kopien erstellt werden. Auch er kann entweder als
lokaler Pfad oder als UNC-Pfad angegeben werden. Wenn der Zielordner nicht vorhanden
ist, dann erstellt das Script diesen automatisch.
Die Methode CopyFolder akzeptiert noch einen dritten optionalen Parameter: Überschreiben.
Wenn Sie diesen Parameter auf True setzen (das ist die Standardeinstellung), dann werden
alle bestehenden Ordner im Zielordner überschrieben. Wenn Sie den Parameter auf False
setzen, werden die vorhanden Ordner nicht überschrieben - stattdessen tritt ein Laufzeitfehler
auf.

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

Seite 199 von 394


Dateien und Ordner aus C:\Scripts. Um einen Ordner mit dem Namen C:\FSO\Scripts zu
erstellen, müssen Sie als Zielordner C:\FSO\Scripts angeben.

Script 4.9: Einen Ordner kopieren

1Const OverWriteFiles = True


2Set objFSO = CreateObject("Scripting.FileSystemObject")
3objFSO.CopyFolder "C:\Scripts" , "C:\FSO" , OverWriteFiles

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 mit Hilfe von Wildcards kopieren


Die Methode CopyFolder kopiert alle Dateien und alle Unterordner eines Ordners. Dieses
Verhalten kann jedoch problematisch sein - vielleicht möchten Sie nur die Dateien im Ordner
C:\FSO und nicht die in C:\FSO\Subfolder1, C:\FSO\Subfolder2 und C:\FSO\Subfolder3
gespeicherten Dateien kopieren?
Unglücklicherweise gibt es keine einfache Methode, um nur die Dateien im Ordner ohne die
Unterordner zu kopieren. Sie können jedoch Wildcards verwenden. Die folgende Scriptzeile
kopiert zum Beispiel nur die Ordner, die mit den Buchstaben log beginnen:
objFSO.CopyFolder "C:\Scripts\Log*" , "C:\Archive", True
Wenn die Codezeile ausgeführt wird, dann werden die Ordner C:\Scripts\Logs und
C:\Scripts\Logfiles kopiert - zusammen mit den in ihnen gespeicherten Dateien und
Unterordnern. Die Dateien im Ordner C:\Scripts werden jedoch nicht kopiert (unabhängig
von deren Namen).
Es ist mit CopyFolder nicht möglich, nur die Dateien ohne Ordner zu kopieren. Hierzu
müssen Sie die CopyFile verwenden - sie wird später in diesem Kapitel besprochen.

Verschieben von Ordnern und deren Inhalten


Zum Verschieben von Ordnern verwenden Sie die Methode MoveFolder. Sie akzeptiert zwei
Parameter:

Quellordner - der zu verschiebende Ordner. Dieser Ordner kann entweder als lokaler Pfad
oder als UNC-Pfad angegeben werden.

Zielordner - der Ordner, in den die Quellordner verschoben werden. Auch er kann entweder
als lokaler Pfad oder als UNC-Pfad angegeben werden. Wenn der Zielordner nicht vorhanden
ist, dann erstellt das Script diesen automatisch.
Wenn der Zielordner noch nicht vorhanden ist, dann wird der Quellordner verschoben. Wenn
der Zielordner schon existiert, schlägt die Methode fehl. Sie können mit der Methode keinen
bestehenden Ordner überschreiben.
Script 4.10 verschiebt den lokalen Ordner C:\Scripts in die Freigabe \\helpdesk\management.

Script 4.10: Verschieben eines Ordners

Seite 200 von 394


1Set objFSO = CreateObject("Scripting.FileSystemObject")
2objFSO.MoveFolder "C:\Scripts" , "\\helpdesk\management"
Bedenken Sie, dass Sie bei einem Fehler keine Möglichkeit haben, die Aktionen von
MoveFolder rückgängig zu machen. Wenn zum Beispiel während des Verschiebens in eine
Netzwerkfreigabe die Netzwerkverbindung getrennt wird, bleiben einige Dateien auf
Computer A, einige Dateien wurden auf Computer B verschoben und einige Dateien sind
möglicherweise während des Verschiebens verloren gegangen. Es gibt keine Möglichkeit den
ursprünglichen Zustand wiederherzustellen.
Daher sollten Sie den Verschiebevorgang besser über zwei einzelne Methoden durchführen:
CopyFolder und DeleteFolder. Sie löschen den Quelleordner über die Methode DeleteFolder
erst dann, wenn die Methode CopyFolder erfolgreich ausgeführt wurde.

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.

Script 4.11: Ordner über die Methode MoveFolder umbenennen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2objFSO.MoveFolder "C:\FSO\Samples" , "C:\FSO\Scripts"

Verwenden von Ordnereigenschaften


Da es sich bei Ordnern um COM-Objekte handelt, verfügen diese natürlich auch über
Eigenschaften und sie können aufgelistet werden. Um Informationen über einen bestimmten
Ordner abzurufen, können Sie das Objekt Folder verwenden - dieses finden Sie unter dem
Objekt FileSystemObject. Die Eigenschaften des Folder-Objekts sehen Sie in Tabelle 4.3.
Tabelle 4.3: Eigenschaften des Objekts Folder
Eigenschaft Beschreibung
Attributes Ein Bitfeld mit den Attributen des Ordners. Weitere Informationen finden
Sie im Abschnitt Verwalten von Ordnerattributen in diesem Kapitel.
DateCreated Erstellungsdatum des Ordners.

Seite 201 von 394


Eigenschaft Beschreibung
DateLastAccessedLetztes Zugriffsdatum.
DateLastModified Letztes Bearbeitungsdatum.
Drive Laufwerksbuchstabe mit Doppelpunkt (zum Beispiel C:) des Laufwerks, in
dem der Ordner gespeichert ist.
Files Eine Collection mit Objekten vom Typ File zum Zugriff auf die im Ordner
gespeicherten Dateien.
IsRootFolder Ein Boolean-Wert, der anzeigt, ob es sich um einen Stammordner (wie zum
Beispiel C:\) handelt.
Name Name des Ordners ohne Pfadangaben (zum Beispiel System32).
ParentFolder Name des Ordners, in dem der Ordner gespeichert ist. Für den Ordner
C:\Scripts wäre dies zum Beispiel C:\.
Path Vollständiger Pfad des Ordners (zum Beispiel C:\Windows\System32).
ShortName Ordnername in der MS-DOS-Syntax mit der 8.3-Namenskonvention. Der
Ordner C:\Windows\Programme wird zum Beispiel als Progra~1 angezeigt
ShortPath Pfadname des Ordners in der MS-DOS-Syntax. Der Ordner
C:\Windows\Programme wird zum Beispiel als C:\Windows\Progra~1
angezeigt.
Size Gesamtgröße in Byte aller Inhalte des Ordners. Dies schließt die in dem
Ordner gespeicherten Dateien und alle Dateien in Unterordnern ein.
SubFolders Eine Collection mit den Unterordnern des Ordners. Die Unterordner in den
Unterordnern sind nicht in dieser Collection enthalten.
Type Ein String mit einer Beschreibung des Ordnertyps - meist File Folder.

Auflisten von Ordnereigenschaften


Um die Eigenschaften eines Ordners abzufragen, muss ein Script folgendermaßen vorgehen:
1.Eine Instanz des Objekts FileSystemObject erstellen.
2.Eine Referenz auf den jeweiligen Ordner über die Methode GetFolder erzeugen.
3.Die Eigenschaften aus Tabelle 4.3 ausgeben.
Bei der Arbeit mit den Eigenschaften eines Ordners sollten Sie bedenken, dass die
Eigenschaften Files und Subfolders beide eine Collection zurückgeben. Außerdem handelt es
sich bei der Eigenschaft Attributes um ein Bitfeld. Wie Sie mit diesen Eigenschaften
umgehen, erfahren Sie in den folgenden Abschnitten dieses Kapitels.
Script 4.12 verwendet die Methode GetFolder, um eine Referenz auf den Ordner C:\FSO zu
erstellen und dann die Eigenschaften des Ordners auszugeben.
Script 4.12: Eigenschaften eines Ordners abfragen

Seite 202 von 394


1 Set objFSO = CreateObject("Scripting.FileSystemObject")
2 Set objFolder = objFSO.GetFolder("C:\FSO")
3 Wscript.Echo "DateCreated: " & objFolder.DateCreated
4 Wscript.Echo "DateLastAccessed: " & objFolder.DateLastAccessed
5 Wscript.Echo "DateLastModified: " & objFolder.DateLastModified
6 Wscript.Echo "Drive: " & objFolder.Drive
7 Wscript.Echo "IsRootFolder: " & objFolder.IsRootFolder
8 Wscript.Echo "Name: " & objFolder.Name
9 Wscript.Echo "ParentFolder: " & objFolder.ParentFolder
10Wscript.Echo "Path: " & objFolder.Path
11Wscript.Echo "ShortName: " & objFolder.ShortName
12Wscript.Echo "ShortPath: " & objFolder.ShortPath
13Wscript.Echo "Size: " & objFolder.Size
14Wscript.Echo "Type: " & objFolder.Type
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
DateCreated: 28.03.2004 15:56:33
DateLastAccessed: 28.03.2004 15:56:3
DateLastModified: 28.03.2004 15:56:3
Drive: C:
IsRootFolder: Falsch
Name: fso
ParentFolder: C:\
Path: C:\fso
ShortName: FSO
ShortPath: C:\FSO
Size: 0
Type: Dateiordner

Verwalten von Ordnerattributen


Wenn Sie mit der rechten Maustaste auf einen Ordner klicken und Eigenschaften auswählen,
dann können Sie die Attribute des Ordners festlegen. Wie Sie in Abbildung 4.2 sehen, stehen
Ihnen die folgenden Attribute zur Verfügung:

Schreibgeschützt

Versteckt

Archiviert

Komprimiert

Seite 203 von 394


Abbildung 4.2: Eigenschaften eines Ordners
Die Attribute, die Sie über das Objekt FileSystemObject abfragen können, sehen Sie in
Tabelle 4.4.
Tabelle 4.4: Über FileSystemObject abfragbare Ordnerattribute
Konstante Wert Beschreibung
Hidden 2 Versteckt - Zeigt an, dass der Ordner versteckt ist.
System 4 System - Zeigt an, dass es sich um einen Systemordner handelt.
Directory 16 Ordner - Der Standardwert für alle Ordner.
Archive 32 Archiv - Das Archiv-Attribut wird zum Beispiel von Sicherungsprogrammen
verwendet. Diese stellt über das Attribut fest, welche Dateien und Ordner
gesichert werden müssen.

Seite 204 von 394


Konstante Wert Beschreibung
Compressed2048Komprimiert - Zeigt an, ob der Ordner komprimiert ist.
Es könnte sein, dass Sie bei der Abfrage der Eigenschaft Attributes einige verwirrende
Ergebnisse erhalten - zum Beispiel den Wert 20. Dieser Wert steht nicht in Tabelle 4.4.
Außerdem erhalten Sie immer nur einen einzelnen Wert zurück - auch wenn der Ordner
mehrere der in der Tabelle aufgelisteten Eigenschaften verwendet. Statt zum Beispiel einen
Wert der Tabelle zu erhalten (2, 4, 16, 32, 2048), gibt die Abfrage der Eigenschaft den Wert
2102 zurück. Dieses Verhalten liegt daran, dass es sich bei dem zurückgegebenen Wert immer
um ein Bitfeld handelt.
Ein Bitfeld ist wie eine Reihe Schalter, die entweder an oder aus sein können. Wenn ein
bestimmter Schalter aus ist, dann hat dieser Schalter den Wert 0. Wenn ein bestimmter
Schalter an ist, dann hat er im Fall eines Ordners den Wert aus Tabelle 4.4. Der Wert des
gesamten Bitfeldes setzt sich aus der Gesamtsumme aller Schalter-Werte zusammen.
In Abbildung 4.3 sehen Sie zum Beispiel eine stark vereinfachte Darstellung eines Bitfeldes.
In diesem Beispiel ist nur ein Schalter (Ordner) an - er halt den Wert 16 (siehe Tabelle 4.4).
Da alle anderen Schalter aus sind haben Sie alle den Wert 0. Die Gesamtsumme aller Schalter
ist also 16. Die Eigenschaft Attribute des entsprechenden Ordners hätte also den Wert 16.

Abbildung 4.3: Erstes Beispiel für ein Bitfeld


Im Gegensatz dazu sind in Abbildung 4.4 drei Schalter aktiviert. Versteckt (mit dem Wert 2),
Ordner (mit dem Wert 16) und Komprimiert (mit dem Wert 248). Der Gesamtwert dieses
Bitfeldes wäre also 2 + 16 + 2048 = 2066. Für diesen Ordner hätte die Eigenschaft Attributes
also den Wert 2066.

Abbildung 4.4: Zweites Beispiel für ein Bitfeld


Bitfelder arbeiten so, dass jeder mögliche Wert nur mit einer einzigen Schalterkombination
erreicht werden kann - der Wert 2066 ist nur mit den Schaltern Versteckt, Komprimiert und
Ordner möglicht.
Daher können Sie über den Wert der Eigenschaft Attributes ermitteln, welcher Schalter
gesetzt ist. Glücklicherweise müssen Sie hierzu keine mathematischen Berechnungen
durchführen oder alle möglichen Werte kennen. Stattdessen können Sie den logischen
Operator AND verwenden - mit ihm können Sie feststellen, welche Schalter an bzw. aus sind.
Das folgende Codestück prüft zum Beispiel, ob ein Ordner versteckt ist. Wenn dies der Fall
ist, dann gibt das Script die Nachricht 'Versteckter Ordner' aus:
If objFolder.Attributes AND 2 Then
Wscript.Echo "Versteckter Ordner"
End If
Der If-Befehl mag ein wenig komisch aussehen. Sie können ihn auch so lesen: 'Wenn in der
Eigenschaft Attributes der Schalter mit dem Wert 2 (Hidden - siehe Tabelle 4.4) gesetzt ist,
dann .' Der folgende Befehl bedeutet zum Beispiel: 'Wenn in der Eigenschaft Attributes der
Schalter mit dem Wert 16 (System) gesetzt ist, dann .':

Seite 205 von 394


If objFolder.Attributes AND 16 Then
Script 4.13 erstellt eine Referenz auf den Ordner C:\FSO und zeigt dessen Attribute an.

Script 4.13: Auflisten von Ordnerattributen

1 Set objFSO = CreateObject("Scripting.FileSystemObject")


2 Set objFolder = objFSO.GetFolder("C:\FSO")
3 If objFolder.Attributes AND 2 Then
4 Wscript.Echo "Versteckt"
5 End If
6 If objFolder.Attributes AND 4 Then
7 Wscript.Echo "System"
8 End If
9 If objFolder.Attributes AND 16 Then
10 Wscript.Echo "Ordner"
11End If
12If objFolder.Attributes AND 32 Then
13 Wscript.Echo "Archiv"
14End If
15If objFolder.Attributes AND 2048 Then
16 Wscript.Echo "Komprimiert"
17End If

Ändern von Ordnerattributen


Sie können die im vorherigen Abschnitt kennen gelernten Attribute natürlich auch selbst
aktivieren oder deaktivieren - ganz einfach indem Sie die Schalter anschalten oder abschalten.
Am einfachsten geht das folgendermaßen:
1.Erstellen Sie eine Referenz auf den Ordner über die Methode GetFolder.
2.Prüfen Sie den Attributwert den Sie ändern möchten. Wenn Sie zum Beispiel das Attribut
Versteckt eines Ordners ausschalten möchten, dann prüfen Sie, ob das Attribut im Moment
angeschaltet ist.
3.Wenn der Ordner versteckt ist, dann verwenden Sie den logischen Operator XOR, um den
Schalter auf aus umzustellen. Wenn der Ordner nicht versteckt ist, dann verwenden Sie
XOR nicht - in diesem Fall würden Sie den Schalter sonst anschalten.
Script 4.14 verwendet den Operator AND mit dem Wert 2(Hidden), um festzustellen, ob der
Ordner C:\FSO versteckt ist. Wenn dies der Fall ist, dann verwendet das Script den logischen
Operator XOR, um den entsprechenden Schalter auf aus umzustellen.

Script 4.14: Ändern von Ordnerattributen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFolder = objFSO.GetFolder("C:\FSO")
3If objFolder.Attributes AND 2 Then
4 objFolder.Attributes = objFolder.Attributes XOR 2
5End If

Auflisten der Dateien in einem Ordner


Nur zu wissen, dass ein Ordner vorhanden ist, ist meist eher nutzlos. Normalerweise wollen
Sie wissen, welche Dateien in dem Ordner gespeichert sind. Hierzu stellt Ihnen das Objekt
Folder eine Eigenschaft mit dem Namen Files zur Verfügung. Diese gibt einen Collection mit

Seite 206 von 394


allen Dateien im entsprechenden Ordner zurück. Um diese Collection zu erhalten, gehen Sie
folgendermaßen vor:
1.Erstellen Sie eine Instanz des Objekts FileSystemObject.
2.Verwenden Sie die Methode GetFolder, um eine Referenz auf den entsprechenden Ordner
zu erstellen.
3.Erstellen Sie eine Objektreferenz auf die Eigenschaft Files des Ordnerobjekts.
4.Verwenden Sie eine For-Each-Schleife, um alle Dateien und deren Eigenschaften in der
Collection Files zu durchlaufen (die Eigenschaften des Objekts Files sehen Sie in Tabelle
4.5.).
Script 4.15 ruft die Collection Files des Ordnerobjekts C:\FSO ab und gibt dann die
Eigenschaften Name und Größe (in Byte) jedes File-Objekts in der Collection aus.

Script 4.15: Abfragen der Eigenschaften aller Dateien in einem Ordner

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFolder = objFSO.GetFolder("C:\FSO")
3Set colFiles = objFolder.Files
4For Each objFile in colFiles
5 Wscript.Echo objFile.Name, objFile.Size
6Next
Wie bei den meisten Collections haben Sie keine Kontrolle darüber, in welcher Reihenfolge
die Informationen zurückgegeben werden - Sie können nicht angeben, dass die Dateien nach
Name, Größe oder anderen Kriterien sortiert werden sollen. Wenn Sie die Dateien sortieren
möchten, dann müssen Sie die Collection in ein Array, ein Dictionary-Objekt oder ein nicht
verbundenes Recordset kopieren. Weitere Informationen hierzu finden Sie im Kapitel
Creating Enterprise Scripts in diesem Buch.

Auflisten von Unterordnern


Zusätzlich zu den in einem Ordner gespeicherten Dateien interessieren Sie sich sicher für die
Unterordner eines Ordners. Hierzu stellt Ihnen das Folder-Objekt eine Eigenschaft mit dem
Namen Subfolders zur Verfügung. Über diese Eigenschaft erhalten Sie eine Collection mit
den direkten Unterordnern des Ordners. Die Unterordner der Unterordner sind nicht in der
Collection enthalten. Bei der folgenden Ordnerstruktur enthält die Collection für den Ordner
Scripte also nur die Unterordner Unterordner1 und Unterordner2. Unterordner1A,
Unterordner1B usw. sind nicht in der Collection enthalten.

Abbildung 4.5: Eine Beispiel-Ordnerstruktur


Eine Collection mit den Unterordnern erhalten Sie folgendermaßen:
Seite 207 von 394
1.Sie erstellen eine Instanz des Objekts FileSystemObject.
2.Sie verwenden die Methode GetFolder um eine Referenz auf einen Ordner zu erhalten.
3.Sie erstellen eine Referenz auf die Eigenschaft Subfolders des Ordnerobjekts (dies ist
erforderlich, da es sich bei Collections ja um Objekte handelt).
Nachdem Sie eine Referenz auf die Collection erstellt haben, können Sie die einzelnen
Unterordner in der Collection mit einer For-Each-Schleife durchlaufen. Script 4.16 erstellt
zum Beispiel eine Referenz auf den Ordner C:\FSO und gibt dann den Namen und die Größe
der Unterordner aus. Die restlichen Eigenschaften eines Ordnerobjekts haben Sie in Tabelle
4.3 gesehen.

Script 4.16: Auflisten von Unterordnern

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFolder = objFSO.GetFolder("C:\FSO")
3Set colSubfolders = objFolder.Subfolders
4For Each objSubfolder in colSubfolders
5 Wscript.Echo objSubfolder.Name, objSubfolder.Size
6Next
Unterordner der Unterordner auflisten
Wahrscheinlich reicht es Ihnen nicht aus, die Unterordner eines Ordners zu kennen -
stattdessen möchten Sie alle Unterordner auflisten. Die Collection Subfolders gibt Ihnen zwar
die beiden Unterordner von c:\Scripte zurück, aber wie kommen Sie an deren Unterordner?

Abbildung 4.6: Eine Beispiel-Ordnerstruktur


Um alle Unterordner abzufragen, müssen Sie eine rekursive Funktion verwenden - eine
Funktion, die sich selbst aufruft. Weitere Informationen über Rekursion finden Sie im Kapitel
VBScript Primer in diesem Buch.
Script 4.17 ist ein Beispiel dafür, wie ein Script alle Unterordner eines Ordners (inklusiver der
Unterordner der Unterordner usw.) auflisten kann. Hierzu geht das Script folgendermaßen
vor:
1.Er erstellt eine Instanz des Objekts FileSystemObject.
2.Es verwendet die Methode GetFolder, um eine Referenz auf C:\Scripte zu erstellen. Diese
Referenz wird der Subroutine ShowSubfolders als Parameter übergeben. Die Subroutine
listet alle Unterordner von C:\Scripts auf.
3.Das Script ruft eine Collection mit allen Unterordnern von C:\Scripte ab. Diese Collection
hat zwei Elemente: Unterordner1 und Unterordner2.

Seite 208 von 394


4.Das Script gibt den Ordnerpfad für das erste Element der Collection aus. Dann ruft sich die
Subroutine mit dem Namen des Ordners als Parameter selbst auf (die Subroutine
ShowSubFolders wird also jetzt mit dem Parameter Unterordner1 aufgerufen).
5.Das Script ruft eine Collection mit allen Unterordnern von Unterordner1 ab. Diese
Collection hat zwei Elemente: Unterordner1A und Unterordner1B.
6.Das Script gibt den Ordnerpfad für das erste Element der Collection aus (Unterordner1A).
Dann ruft sich die Subroutine mit dem Namen des Ordners als Parameter selbst auf (die
Subroutine ShowSubFolders wird als mit dem Parameter Unterordner1A aufgerufen).
7.Da Unterordner1A keine Unterordner mehr hat, wird das nächste Elemente der Collection
abgearbeitet. Die Subroutine ruft sich selbst mit dem Parameter Subfolder1B auf.
8.Damit ist die Rekursion durch Unterordner1 abgeschlossen. Das Script macht mit dem
zweiten Element der ersten Collection (aus Schritt 3) weiter und wiederholt den gesamten
Vorgang.

Script 4.17: Rekursive Auflistung von Unterordnern

1Set FSO = CreateObject("Scripting.FileSystemObject")


2ShowSubfolders FSO.GetFolder("C:\Scripts")
3Sub ShowSubFolders(Folder)
4 For Each Subfolder in Folder.SubFolders
5 Wscript.Echo Subfolder.Path
6 ShowSubFolders Subfolder
7 Next
8End Sub
Wenn Sie das Script unter CScript ausführen, sollte die Ausgabe so aussehen:
C:\scripte\Unterodner1
C:\scripte\Unterodner1\Unterodner1A
C:\scripte\Unterodner1\Unterodner1B
C:\scripte\Unterodner2
C:\scripte\Unterodner2\Unterodner2A
C:\scripte\Unterodner2\Unterodner2A\Unterodner 2A-1
C:\scripte\Unterodner2\Unterodner2B
C:\scripte\Unterodner2\Unterodner2C
Um zum Beispiel eine komplette Liste aller Ordner eines Laufwerkes abzufragen, beginnen
Sie einfach mit dem Stammordner des entsprechenden Laufwerks (zum Beispiel C:\).

Verwalten von Dateien


Zur Verwaltung des Dateisystems gehört auch die Verwaltung der einzelnen Dateien - diese
müssen kopiert, verschoben, umbenannt und gelöscht werden. Das Objekt FileSystemObject
bietet auch für diese Aufgaben die richtigen Methoden an.

Eine Referenz auf eine Datei erstellen


Das Objekt FileSystemObject stellt Ihnen einige Methoden zur Verfügung, über die ein Script
mit Dateien arbeiten kann, ohne eine neue Instanz eines File-Objekts zu erstellen - unter
anderem CopyFile und DeleteFile. Für andere Aufgaben ist jedoch ein File-
Objekterforderlich. Um zum Beispiel eine Liste der Dateieigenschaften abzurufen, muss ein
Script erst eine Referenz auf ein File-Objekt erstellen.

Seite 209 von 394


Um eine solche Referenz zu erstellen, verwenden Sie die Methode GetFile. Das von Getfile
zurückgegebene File-Objekt weisen Sie dann mit dem Schlüsselwort Set als Referenz zu einer
Variablen zu. Als Parameter erwartet die Methode GetFile den Dateinamen (entweder ein
lokaler Pfad oder ein UNC-Pfad).
Script 4.18 erstellt zu Beispiel eine Referenz auf die Datei C:\FSO\ScriptLog.txt.

Script 4.18: Eine Referenz auf eine Datei erstellen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2objFSO.GetFile("C:\FSO\ScriptLog.txt")
Im Allgemeinen ist es eine gute Idee, den absoluten Pfad einer Datei als Parameter zu
verwenden. Dies stellt sicher, dass das Script immer auf die Datei zugreifen kann. Wenn sich
die Datei im gleichen Ordner wie das Script befindet, dann reicht es auch, nur den
Dateinamen anzugeben.
Die folgende Scriptzeile erzeugt zum Beispiel eine Referenz auf die Datei ScriptLog.txt, die
sich im gleichen Ordner wie das Script befindet:
objFSO.GetFile("ScriptLog.txt")
Wenn sich die Datei im dem Scriptordner übergeordneten Ordner befindet, dann können Sie
die folgende Syntax verwenden:
objFSO.GetFile(".\ScriptLog.txt")
Bitte denken Sie daran, dass das Objekt FileSystemObject nicht in den Pfaden der
Umgebungsvariable Path nach den Dateien sucht. So können Sie beispielsweise den
Windows-Rechner starten, indem Sie in der Eingabeaufforderung einfach calc.exeeingeben -
egal wo Sie sich befinden. Mit GetFile-Methode funktioniert dies nicht. Hier müssen Sie
immer den korrekten Pfad angeben (für den Windows-Taschenrechner wäre das zum Beispiel
C:\Windows\System32)

Prüfen, ob eine Datei vorhanden ist


Manchmal ist es sehr wichtig zu prüfen, ob eine Datei vorhanden ist oder nicht. Zum Beispiel
wenn Sie die Datei verschieben, kopieren oder löschen möchten. Wenn Sie versuchen eine
solche Aktion mit einer nicht vorhandenen Datei durchzuführen, dann kommt es zu einem
Laufzeitfehler.
Um solche Fehler zu vermeiden, können Sie vorher mit der Methode FileExists prüfen, ob die
Datei vorhanden ist. Die Methode benötigt nur einen einzelnen Parameter (die Datei mit Pfad)
und gibt einen Boolean-Wert zurück. Wenn die Datei vorhanden ist, dann ist der
Rückgabewert True ansonsten False:
Script 4.19 prüft mit der Methode FileExists, ob die Datei C:\FSO\ScriptLog.txt vorhanden
ist. Wenn dies der Fall ist, dann verwendet das Script die Methode GetFile, um eine Referenz
auf die Datei zu erstellen. Wenn die Datei nicht vorhanden ist, dann gibt das Script die
Fehlermeldung 'Datei ist nicht vorhanden' aus.

Script 4.19: Existenz einer Datei überprüfen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2If objFSO.FileExists("C:\FSO\ScriptLog.txt") Then
3 Set objFile = objFSO.GetFile("C:\FSO\ScriptLog.txt")
4Else

Seite 210 von 394


5 Wscript.Echo "Datei ist nicht vorhanden."
6End If
Es ist nicht möglich Wildcards zu verwenden - zum Beispiel um zu prüfen, ob eine bestimmte
Gruppe von Dateien vorhanden ist (beispielsweise *.txt). Die folgende Codezeile führt zwar
nicht zu einem Fehler, gibt jedoch immer den Wert False zurück:
WScript.Echo objFSO.FileExists("C:\FSO\*.*")
Wenn Sie die Existenz einer Datei auf Basis bestimmter Kriterien prüfen müssen, dann haben
Sie zwei Möglichkeiten:

Verwenden Sie die Methode GetFolder, um eine Referenz auf den Ordner zu erstellen, rufen
Sie die Eigenschaft Files ab und gehen Sie die gesamte Collection durch. So können Sie alle
Dateien im Ordner überprüfen und feststellen, ob die gesucht Datei vorhanden ist.

Verwenden Sie WMI. Mit WMI haben Sie die Möglichkeit speziellere Abfragen zu erstellen
- zum Beispiel 'alle Dateien mit der Dateierweiterung .doc'. Danach können Sie mit der
Methode Count ermitteln, wie viele Dateien die Abfrage zurückgegeben hat.

Löschen einer Datei


Zum Löschen von Dateien erstellen Sie als erstes eine Instanz des Objektes FileSystemObject.
Dann rufen Sie die Methode DeleteFile mit dem Dateinamen und deren Pfad als Parameter
auf. Script 4.20 löscht als Beispiel die Datei C:\FSO\ScriptLog.txt.

Script 4.20: Löschen einer Datei

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2objFSO.DeleteFile("C:\FSO\ScriptLog.txt")
Standardmäßig löscht die Methode DeleteFile keine schreibgeschützten Dateien - wenn Sie
dies versuchen, kommt es zu einem Laufzeitfehler. Um solche Fehler zu vermeiden und um
schreibgeschützte Dateien löschen zu können, können Sie den optionalen Parameter Force
verwenden. Wenn Sie den Parameter auf True setzen, werden alle Dateien gelöscht:
objFSO.DeleteFile("C:\FSO\ScriptLog.txt", True)
Eine Gruppe von Dateien löschen
Innerhalb eines Ordners können Sie mehrere Dateien über Wildcards löschen. Wenn die
Dateien über mehrere Ordner verteilt sind, ist dies mit einem einzigen Aufruf von DeleteFile
jedoch nicht möglich. Um mehrere Dateien in unterschiedlichen Ordner mit einem Aufruf zu
löschen (zum Beispiel alle .TMP-Dateien auf einem Computer), müssen Sie WMI verwenden.
Um mehrere Dateien in einem Ordner zu löschen, verwenden Sie die Methode DeleteFile und
geben den Pfad und den Dateinamen einfach mit Wildcards an. Die folgende Codezeile löscht
zum Beispiel alle .doc-Dateien im Ordner C:\FSO:
objFSO.DeleteFile("C:\FSO\*.doc")
Die folgende Codezeile löscht alle Dateien mit den Buchstaben log irgendwo im Dateinamen:
objFSO.DeleteFile("C:\FSO\*log.* ")
Wie bereits erwähnt, löscht DeleteFile standardmäßig keine Dateien, die schreibgeschützt
sind. Bei einem solchen Versuch kommt es zu einem Laufzeitfehler und die Methode bricht
ab - und zwar unabhängig davon, ob im Script der Befehl On Error Resume Next verwendet
wurde oder nicht.

Seite 211 von 394


Script 4.21 löscht alle .txt-Dateien im Ordner C:\FSO. Um sicherzustellen, dass alle Dateien
gelöscht werden (auch die schreibgeschützten), wird der Parameter Force mit dem Wert
DeleteReadOnly verwendet.

Script 4.21:Löschen einer Gruppe von Dateien

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.

Kopieren einer Datei


Die Methode CopyFile dient zum Kopieren von Dateien. Sie müssen zwei Parameter angeben
- ein dritter Parameter ist optional:

Quelle (erforderlich) - die zu kopierende Datei. Entweder ein lokaler Pfad oder ein UNC-
Pfad.

Ziel (erforderlich) - Pfad und Dateiname. Entweder ein lokaler Pfad oder ein UNC-Pfad.
Um die Datei unter dem gleichen Namen in den Zielordner zu kopieren, lassen Sie einfach
den Dateinamen weg:
objFSO.CopyFile "C:\FSO\ScriptLog.txt" , "D:\Archive\"
Um der Datei am Zielort einen neuen Namen zu gegen verwenden Sie folgende Syntax:
objFSO.CopyFile "C:\FSO\ScriptLog.txt" , "D:\Archive\NewFileName.txt"
Wenn der Zielordner nicht vorhanden ist wird er automatisch erstellt.

Überschreiben (optional) - Standardmäßig kopiert die Methode die Datei nicht, wenn im
Zielordner schon eine Datei mit dem gleichen Namen vorhanden ist. Sie können das
Überschreiben erzwingen, indem Sie den Parameter auf den Wert True setzen.
Script 4.22 kopiert die Datei C:\FSO\ScriptLog.txt in den Ordner D:\Archive. Um
sicherzustellen, dass der Vorgang nicht fehlschlägt, wird der dritte Parameter auf True gesetzt.

Script 4.22: Eine Datei kopieren

1Const OverwriteExisting = True


2Set objFSO = CreateObject("Scripting.FileSystemObject")
3objFSO.CopyFile "C:\FSO\ScriptLog.txt" , "D:\Archive\", OverwriteExisting
Wenn Sie den Zielordner angeben, dürfen Sie das letzte Slash-Zeichen nicht vergessen. Wenn
Sie das Zeichen weglassen, dann wird die Datei nicht in den Ordner kopiert. Stattdessen
versucht die Methode eine neue Datei mit dem Ordnernamen anzulegen.
Wenn Sie versuchen eine schreibgeschützte Datei zu überschreiben, wird die Methode
fehlschlagen - auch dann, wenn Sie den Parameter OverWrite auf True gesetzt haben. In
einem solchen Fall müssen Sie die Datei im Zielordner vorher löschen.

Eine Gruppe von Dateien kopieren


Seite 212 von 394
Solange sich die Dateien im gleichen Ordner befinden, können Sie mit Wildcards ganze
Dateigruppen kopieren. Script 4.23 kopiert zum Beispiel alle .txt-Dateien im Ordner C:\FSO
nach D:\Archive.

Script 4.23: Kopieren von mehreren Dateien

1Const OverwriteExisting = True


2Set objFSO = CreateObject("Scripting.FileSystemObject")
3objFSO.CopyFile "C:\FSO\*.txt" , "D:\Archive\" , OverwriteExisting
Mit Wildcards und der Methode CopyFile haben Sie die Möglichkeit alle Dateien in einem
Ordner zu kopieren - ohne die Unterordner. Mit CopyFolder hingegen werden sowohl Dateien
als auch Unterordner kopiert. Die folgende Scriptzeile kopiert alle Dateien im Ordner
C:\FSO:
objFSO.CopyFile "C:\FSO\*.*" , "D:\Archive\"

Verschieben einer Datei


Statt eine Datei zu kopieren, möchten Sie diese möglicherweise verschieben. Hierzu können
Sie die Methode MoveFile nutzen. Sie arbeitet genauso wie die Methode CopyFile: Sie
erstellen eine Instanz des Objekts FileSystemObject und rufen die Methode MoveFile mit
zwei Parametern auf:

Dem kompletten Pfad der zu verschiebenden Datei.

Dem kompletten Pfad des neuen Speicherortes - inklusive des abschließenden Backslash-
Zeichens.
Script 4.24 verschiebt die Datei C:\FSO\ScriptLog.log in den Ordner Archive auf Laufwerk D.

Script 4.24: Verschieben einer Datei

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2objFSO.MoveFile "C:\FSO\ScriptLog.log" , "D:\Archive\"
Mehrere Dateien verschieben
Über Wildcards können Sie mehrere Dateien in einem Vorgang verschieben. Mit dem
folgenden Parameter verschieben Sie zum Beispiel alle Dateien im Ordner FSO, die mit data
anfangen:
C:\FSO\Data*.*
Script 4.25 verschiebt alle Protokolldateien (.log) aus dem Ordner FSO auf Laufwerk C in den
Ordner Archive auf Laufwerk D.

Script 4.25: Verschieben von mehreren Dateien

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2objFSO.MoveFile "C:\FSO\*.log" , "D:\Archive\"

Eine Datei umbenennen


Das Objekt FileSystemObject stellt keine Methode zum Umbenennen von Dateien bereit. Sie
können eine Datei jedoch über den gleichen Vorgang umbenennen, den wir bereits beim
Umbenennen von Ordnern kennen gelernt haben. Verwenden Sie die Methode MoveFile und
belassen Sie die Datei in ihrem aktuellen Ordner.

Seite 213 von 394


Script 4.26 benennt die Datei ScriptLog.txt in BackupLog.txt um. Technisch verschiebt das
Script die Datei C:\FSO\ScriptLog.txt nach C:\FSO\BackupLog.txt. Das Endergebnis ist
jedoch eine umbenannte Datei.

Script 4.26: Umbenennen von Dateien über die Methode MoveFile

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2objFSO.MoveFile "C:\FSO\ScriptLog.txt" , "C:\FSO\BackupLog.txt"

Abfragen von Dateieigenschaften


Auch Dateien haben einige Eigenschaften, die Sie abfragen können. Auch hierzu verwenden
Sie das Objekt FileSystemObject - neben vielen anderen Dingen können Sie mit ihm die
Eigenschaften einer oder mehrere Dateien abfragen. Eine vollständige Liste der Eigenschaften
des Objekts File finden Sie in Tabelle 4.5.
Tabelle 4.5: Eigenschaften des Objekts File
Eigenschaft Beschreibung
Attributes Ein Bitfeld mit den Attributen der Datei.
DateCreated Das Erstellungsdatum der Datei.
DateLastAccessedDas Datum des letzten Dateizugriffs.
DateLastModified Das Datum der letzten Änderung an der Datei.
Drive Laufwerksbuchstabe mit Doppelpunkt des Laufwerks, auf dem die Datei
gespeichert ist.
Name Dateiname ohne Pfadinformationen. Für die Datei
C:\Windows\System32\Scrrun.dll wäre das zum Beispiel Scrrun.dll.
ParentFolder Name des Ordners, in dem die Datei gespeichert ist. Für
C:\Windows\System32\Scrrun.dll wäre das zum Beispiel System32.
Path Der vollständige Pfad der Datei (zum Beispiel
C:\Windows\System32\Scrrun.dll).
ShortName Der MS-DOS-Name der Datei (in 8.3-Schreibweise). Für die Datei
C:\MySpreadsheet.xls ist das zum Beispiel MySpre~1.xls.
ShortPath Der Pfad in MS-DOS-Schreibweise (in 8.3-Schreibweise). Für die Datei
C:\Windows\Program Files\MyScript.vbs wäre das zum Beispiel
C:\Windows\Progra~1\MyScript.vbs.
Size Gesamtgröße der Datei in Byte.
Type Ein String mit der Dateiart (zum Beispiel Microsoft Word Document).
Ein Script kann folgendermaßen auf die Dateieigenschaften zugreifen:

Eine Instanz des Objekts FileSystemObject erstellen.

Mit der Methode GetFile eine Objektreferenz auf eine bestimmte Datei erstellen (die

Seite 214 von 394


Methode GetFile benötigt als Parameter den Pfad der Datei).

Die Dateieigenschaften ausgeben oder ändern.
Script 4.27 verwendet die GetFile-Methode, um eine Referenz auf die Datei
C:\Windows\System32\Scrrun.dll zu erstellen und deren Eigenschaften auszugeben.

Script 4.27: Auflisten von Dateieigenschaften

1 Set objFSO = CreateObject("Scripting.FileSystemObject")


2 Set objFile = objFSO.GetFile("c:\windows\system32\scrrun.dll")
3 Wscript.Echo "DateCreated: " & objFile.DateCreated
4 Wscript.Echo "DateLastAccessed: " & objFile.DateLastAccessed
5 Wscript.Echo "DateLastModified: " & objFile.DateLastModified
6 Wscript.Echo "Drive: " & objFile.Drive
7 Wscript.Echo "Name: " & objFile.Name
8 Wscript.Echo "ParentFolder: " & objFile.ParentFolder
9 Wscript.Echo "Path: " & objFile.Path
10Wscript.Echo "ShortName: " & objFile.ShortName
11Wscript.Echo "ShortPath: " & objFile.ShortPath
12Wscript.Echo "Size: " & objFile.Size
13Wscript.Echo "Type: " & objFile.Type
Wenn Sie das Script unter CScript ausführen erhalten Sie die folgende Ausgabe:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.GetFile("c:\windows\system32\scrrun.dll")
Wscript.Echo "DateCreated: " & objFile.DateCreated
Wscript.Echo "DateLastAccessed: " & objFile.DateLastAccessed
Wscript.Echo "DateLastModified: " & objFile.DateLastModified
Wscript.Echo "Drive: " & objFile.Drive
Wscript.Echo "Name: " & objFile.Name
Wscript.Echo "ParentFolder: " & objFile.ParentFolder
Wscript.Echo "Path: " & objFile.Path
Wscript.Echo "ShortName: " & objFile.ShortName
Wscript.Echo "ShortPath: " & objFile.ShortPath
Wscript.Echo "Size: " & objFile.Size
Wscript.Echo "Type: " & objFile.Type

Auflisten der Dateiattribute


Auch Dateien haben Attribute. Wie bei Ordnern werden diese als Bitfeld zurückgegeben
(weitere Informationen zu Bitfeldern finden Sie im Abschnitt Verwalten von Ordnerattributen
dieses Kapitels). In Tabelle 4.6 sehen Sie die verfügbaren Dateiattribute.

Tabelle 4.6: Dateiattribute


Konstante Wert Beschreibung
Normal 0 Datei ohne Attribute.
Read-only 1 Datei kann nur gelesen werden.
Hidden 2 Versteckte Datei.
System 4 Datei ist Teil des Betriebssystems.
Archive 32 Datei ist zur Sicherung markiert.
Alias 64 Datei ist eine Verknüpfung, die auf eine andere Datei verweist.

Seite 215 von 394


Konstante Wert Beschreibung
Compressed2048Datei ist komprimiert.
Um die Dateiattribute abzufragen, verwenden Sie als erstes die Methode GetFile, um eine
Referenz auf die Datei zu erstellen. Danach verwenden Sie den logischen Operator AND, um
die Dateiattribute zu überprüfen.
Script 4.28 erstellt eine Referenz auf die Datei C:\FSO\ScriptLog.txt und prüft dann alle
Dateiattribute.

Script 4.28: Auflisten von Dateiattributen

1 Set objFSO = CreateObject("Scripting.FileSystemObject")


2 Set objFile = objFSO.GetFile("C:\FSO\ScriptLog.txt")
3 If objFile.Attributes AND 0 Then
4 Wscript.Echo "Keine Attribute vorhanden."
5 End If
6 If objFile.Attributes AND 1 Then
7 Wscript.Echo "Read-only."
8 End If
9 If objFile.Attributes AND 2 Then
10 Wscript.Echo "Hidden."
11End If
12If objFile.Attributes AND 4 Then
13 Wscript.Echo "System."
14End If
15If objFile.Attributes AND 32 Then
16 Wscript.Echo "Archive."
17End If
18If objFile.Attributes AND 64 Then
19 Wscript.Echo "Alias."
20End If
21If objFile.Attributes AND 2048 Then
22 Wscript.Echo "Compressed."
23End If

Konfigurieren von Dateiattributen


Natürlich haben Sie auch die Möglichkeit die Dateiattribute zu verändern. Dies ist jedoch nur
für die folgenden Attribute möglich:
1.ReadOnly
2.Hidden
3.System
4.Archive
Um ein Dateiattribut zu ändern, muss ein Script folgendermaßen vorgehen:
1.Eine Referenz auf die Datei über GetFile erstellen.
2.Die Attribute prüfen, die geändert werden sollen. Wenn Sie zum Beispiel das Attribut read-
only setzen möchten, dann sollten Sie prüfen, ob das Attribut nicht eventuell bereits gesetzt
ist.
3.Wenn das Attribut nicht gesetzt ist, dann verwendet das Script den logischen Operator XOR,

Seite 216 von 394


um das Attribut 'umzuschalten'. Wenn das Attribut bereits gesetzt ist, dann dürfen Sie XOR
nicht verwenden - Sie würden das Attribut so 'ausschalten'.
Script 4.29 verwendet den Operator AND um zu prüfen, ob der Schalter mit dem Wert 1
(read-only) gesetzt ist. Wenn dies nicht der Fall ist, dann wird der Schalter mit dem Operator
XOR gesetzt.

Script 4.29: Konfigurieren von Dateiattributen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFile = objFSO.GetFile("C:\FSO\TestScript.vbs")
3If objFile.Attributes AND 1 Then
4 objFile.Attributes = objFile.Attributes XOR 1
5End If
Über die folgende Codezeile schalten Sie alle Attribute gleichzeitig aus:
objFile.Attributes = objFile.Attributes AND 0

Den Pfad einer Datei verarbeiten


Manchmal benötigen Sie den Pfad einer Datei oder nur einen Teil eines Pfades - in anderen
Fällen vielleicht nur die Dateierweiterung. In all diesen Fällen müssen Sie in der Lage sein,
die gewünschten Informationen abzufragen. Das Objekt FileSystemObject stellt Ihnen hierzu
die in Tabelle 4.7 aufgelisteten Methoden zur Verfügung.

Tabelle 4.7: Methoden zur Abfrage von Dateipfaden


Methode Beschreibung
GetAbsolutePathNameGibt den vollständigen Pfad einer Datei zurück (zum Beispiel
C:\FSO\Scripts\Scriptlog.txt).
GetParentFolderName Gibt den Pfad des Ordners zurück, in dem die Datei gespeichert ist
(zum Beispiel C:\FSO\Scripts).
GetFileName Gibt den Dateinamen ohne Pfadinformationen zurück (zum Beispiel
ScriptLog.txt).
GetBaseName Gibt den Basisnamen der Datei zurück (der Dateiname ohne
Erweiterung - zum Beispiel ScriptLog).
GetExtensionName Gibt die Erweiterung der Datei zurück (zum Beispiel txt).
Script 4.30 fragt die Pfadinformationen der Datei ScriptLog.txt ab. Das Script funktioniert nur
dann, wenn sich die Datei ScriptLog.txt im gleichen Ordner wie das Script befindet.
Andernfalls müssten Sie der Methode GetFile den vollständigen Pfad zur Zieldatei angeben
(zum Beispiel C:\FSO\Scripts\ScriptLog.txt).

Script 4.30: Abfragen von Pfadinformationen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFile = objFSO.GetFile("ScriptLog.txt")
3Wscript.Echo "Absoluter Pfad: " & objFSO.GetAbsolutePathName(objFile)
4Wscript.Echo "Überg. Ordner: " & objFSO.GetParentFolderName(objFile)
5Wscript.Echo "Dateiname: " & objFSO.GetFileName(objFile)
6Wscript.Echo "Basisname: " & objFSO.GetBaseName(objFile)
7Wscript.Echo "Erweiterung: " & objFSO.GetExtensionName(objFile)

Seite 217 von 394


Wenn Sie das Script unter CScript ausführen, erhalten Sie eine Ausgabe wie die folgende:
Absoluter Pfad: C:\scriptlog.txt
Überg. Ordner: C:\
Dateiname: scriptlog.txt
Basisname: scriptlog
Erweiterung: txt

Abfragen der Dateiversion


Manchmal müssen Sie als Administrator feststellen, ob eine Datei veraltet ist. Hierzu
benötigen Sie die Dateiversion, die Sie über die Methode GetFileVersion erhalten. Das Script
muss folgendermaßen vorgehen:
1.Eine Instanz des Objekts FileSystemObject erstellen.
2.Die Methode GetFileVersion aufrufen und ihr als Parameter den Pfad zur Datei übergeben.
Script 4.31 demonstriert diesen Vorgang und fragt die Dateiversion von Scrrun.dll ab.

Script 4.31: Abfragen der Dateiversion

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Wscript.Echo objFSO.GetFileVersion("c:\windows\system32\scrrun.dll")
Wenn Sie das Script auf einem Computer unter Windows 2000 mit WSH 5.6 ausführen,
erhalten Sie die in Abbildung 4.7 zu sehende Ausgabe.

Abbildung 4.7: Versionsnummer der Datei Scrrun.dll


Versionsnummern setzen sich normalerweise aus vier Teilen zusammen. Die
Versionsnummer 5.6.0.6626 enthält zum Beispiel die folgenden Informationen:
1.5 - Die Hauptversionsnummer.
2.6 - Die Unterversionsnummer. Hauptversion und Unterversion zusammen sind die
Information, die normalerweise mit 'Versionsnummer' gemeint ist. In unserem Beispiel
würden Sie zum Beispiel wahrscheinlich eher von Version 5.6 statt von Version 5.6.0.6626
sprechen.
3.0 - DieBuildnummer (normalerweise 0).
4.6626 - Die Dateinummer.
Nicht alle Dateien stellen Versionsnummern zur Verfügung. Bei den meisten ausführbaren
Dateien und DLLs sind jedoch Versionsnummern vorhanden.

Textdateien lesen und schreiben


Eins der praktischsten Werkzeuge eines Systemadministrators ist die Textdatei. Das scheint
im Zeitalter von 3D-Grafik und High-End-Datenbanken erst einmal schwer vorstellbar -
trotzdem hat eine einfache Textdatei viele Vorteile. Sie ist klein und leicht zu pflegen, es wird
keine zusätzliche Software benötigt (Notepad.exe reicht aus) und sie ist extrem portabel.
Mit Textdateien steht Ihnen ein einfacher Weg zur Verfügung, um Informationen in ein Script
und aus einem Script heraus zu übertragen. Textdateien können Argumente enthalten, die Sie

Seite 218 von 394


ansonsten direkt in das Script schreiben müssten. Sie können Scriptausgaben sehr einfach in
einer Textdatei speichern (natürlich könnten Sie die Daten auch direkt in einer Datenbank
schreiben - dies wäre jedoch viel komplizierter).
Das Objekt FileSystemObject bietet Ihnen daher sowohl Methoden zum Lesen als auch zum
Schreiben von Textdateien an.

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.

Script 4.32: Erstellen einer Textdatei

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFile = objFSO.CreateTextFile("C:\FSO\ScriptLog.txt")
Wenn die Datei noch nicht vorhanden ist, dann erstellt die Methode CreateTextFile diese.
Wenn die Datei bereits existiert, wird sie mit einer neuen, leeren Textdatei überschrieben.
Wenn Sie nicht möchten, dass vorhandene Dateien überschrieben werden, dann können Sie
einen zweiten, optionalen Parameter verwenden: Overwrite. Wenn Sie diesen Parameter auf
True setzen, dann werden vorhandene Dateien überschreiben (True ist auch der
Standardwert). Mit False werden die vorhandenen Dateien nicht überschrieben. Die folgende
Scriptzeile überschreibt die vorhandene Datei nicht:
Set objFile = objFSO.CreateTextFile("C:\FSO\ScriptLog.txt", False)
Wenn Sie den Parameter auf False setzen und die Datei bereits vorhanden ist, dann kommt es
zu einem Laufzeitfehler. Daher sollten Sie vor dem Anlegen der Datei prüfen, ob diese schon
vorhanden ist und in diesem Fall einen anderen Dateinamen wählen.

Dateinamen in einem Script erstellen


Ein Weg, um das oben beschriebene Problem mit vorhandenen Dateien zu umgehen, besteht
darin, einen eindeutigen Dateinamen zu generieren. Da diese Dateinamen dann jedoch nicht
sehr aussagekräftig sind, handelt es sich hierbei allerdings nicht um den besten Ansatz.
Trotzdem kann ein eindeutiger Dateiname in einigen Situationen sehr nützlich sein - zum
Beispiel bei temporären Dateien. Einen solchen Dateinamen erzeugen Sie mit der Methode
GetTempFileName.
Das Script muss zuerst eine Instanz von FileSystemObject erstellen und ruft dann die Methode
GetTempName auf (sie benötigt keine Parameter). Script 4.33 erstellt zum Beispiel in einer
Schleife 10 zufällige Dateinamen.

Script 4.33: Generieren von Dateinamen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2For i = 1 to 10
3 strTempFile = objFSO.GetTempName
4 Wscript.Echo strTempFile
5Next

Seite 219 von 394


Wenn Sie das Script unter Cscript ausführen, dann erhalten Sie eine ähnliche Ausgabe wie die
folgende:
rad646E9.tmp
radEC50C.tmp
rad0C40A.tmp
radE866E.tmp
rad77F3D.tmp
rad19970.tmp
rad7A21A.tmp
radB9DDC.tmp
rad84930.tmp
rad92199.tmp

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.

Script 4.34: Erstellen und benennen einer Textdatei

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2strPath = "C:\FSO"
3strFileName = objFSO.GetTempName
4strFullName = objFSO.BuildPath(strPath, strFileName)
5Set objFile = objFSO.CreateTextFile(strFullName)
6objFile.Close
Öffnen von Textdateien
Die Arbeit mit Textdateien ist ein Prozess mit drei Schritten. Bevor Sie etwas anderes
machen, müssen Sie die Datei öffnen (alternativ können Sie auch eine neue Textdatei
erstellen - diese ist dann automatisch geöffnet). Durch das Öffnen erhalten Sei ein Objekt vom
Typ TextStream.

Seite 220 von 394


Nachdem Sie über eine Referenz auf das TextStream-Objekt verfügen, können Sie aus der
Datei lesen oder in die Datei schreiben. Es ist nicht möglich, beide Vorgänge gleichzeitig
durchzuführen. Sie können zum Beispiel eine Datei nicht öffnen, Daten lesen und dann sofort
Daten in die geöffnete Datei schreiben. Stattdessen müssen Sie die Datei nach dem
Lesevorgang schließen, sie neu öffnen und dann in die Datei schreiben. Dies liegt daran, dass
eine Textdatei entweder zum Lesen oder zum Schreiben geöffnet wird. Wenn Sie eine neue
Textdatei erstellen, dann ist diese automatisch zum Schreiben geöffnet (zu lesen gibt es ja
normalerweise auch nichts).
Im letzten Schritt müssen Sie die Datei dann noch schließen. Die ist zwar nicht unbedingt
erforderlich (die Datei wird auch geschlossen, wenn das Script beendet wird), um ein
korrektes Script zu schreiben sollten Sie diesen Schritt aber trotzdem durchführen.
Um eine Textdatei zu öffnen, gehen Sie folgendermaßen vor:
1.Erstellen Sie eine Instanz von FileSystemObject.
2.Verwenden Sie die Methode OpenTextFile, um eine Textdatei zu öffnen. Sie benötigt zwei
Parameter - den Pfadnamen der Datei und einen der folgenden Modi:

ForReading (1) - Die Datei wird im Lesemodus geöffnet. Schreiben in die Datei ist nicht
möglich (hierzu müssten Sie die Datei schließen und denn im Modus ForWriting oder
ForAppending neu öffnen).

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

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")

Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", ForReading)


Set objFile2 = objFSO.OpenTextFile("C:\FSO\ScriptLog2.txt", 1)
Allerdings müssen Sie die Konstante erst definieren - das liegt daran, dass VBScript leider
keinen Zugriff auf die Konstanten von COM-Objekten hat (und ForReading ist eine
Konstante des COM-Objekts FileSystemObject - im Gegensatz zum Beispiel zur Konstante
True, bei der es sich um eine Konstante von VBScript handelt). Das folgende Script bricht mit
der Fehlermeldung 'Ungültiger Prozeduraufruf oder Argument' ab, da die Konstante
ForReading nicht definiert wurde:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", ForReading)
Script 4.35 öffnet die Datei C:\FSO\ScriptLog.txt zum Lesen und definiert hierzu die
Konstante ForReading mit dem Wert 1.

Script 4.35: Eine Textdatei zum Lesen öffnen

Seite 221 von 394


1Const ForReading = 1
2Set objFSO = CreateObject("Scripting.FileSystemObject")
3Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", ForReading)
Schließen von Textdateien
Alle vom Script geöffneten Textdateien werden beim Beenden des Scripts automatisch
geschlossen. Daher müssen Sie dies nicht unbedingt selbst durchführen. Sie sollten sich
jedoch trotzdem selbst darum kümmern. Nicht nur, weil es eine saubere Programmierung so
erfordert, sondern auch um zu vermeiden, dass folgende Probleme mit der geöffneten Datei
auftreten:

Löschen der Datei - Wenn Sie versuchen eine geöffnete Datei zu löschen, tritt der
Laufzeitfehler 'Zugriff verweigert' auf.

Neu-Einlesen der Datei - Es könnte sein, dass Sie im selben Script ein zweites Mal auf die
Textdatei zugreifen möchten. Wenn Sie versuchen eine bereits geöffnete Datei ein zweites
Mal zu öffnen, erhalten Sie keinen Laufzeitfehler. Das Ergebnis wird allerdings auch nicht
Ihren Erwartungen entsprechen. Das folgende Script liest zum Beispiel aus einer Textdatei
und gibt die gelesenen Informationen aus. Dann versucht es den Vorgang zu wiederholen,
ohne die Datei vorher zu schließen:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", 1)
Wscript.Echo "Erstes Lesen der Datei:"
strContents = objFile.ReadAll
Wscript.Echo strContents
Wscript.Echo "Zweites Lesen der Datei:"
Do While objFile.AtEndOfStream = False
strLine = objFile.ReadLine
Wscript.Echo strLine
Loop
Wenn Sie das Script unter Cscript ausführen, erhalten Sie die folgende Ausgabe:
Erstes Lesen der Datei:
Zeile 1.
Zeile 2.
Zeile 3.
Zweites Lesen der Datei:
Beim ersten Lesen werden die erwarteten Dateiinhalte ausgegeben. Beim zweiten Lesen
kommt es jedoch zu keinerlei Ausgabe. Dies liegt daran, dass das Ende der Datei bereits beim
ersten Lesen erreicht wurde. Um die Datei ein zweites Mal zu lesen, müssen Sie sie erst
schließen und dann neu öffnen. Sie können nicht einfach zum Anfang der Datei springen und
dann von vorne beginnen.
Um eine Textdatei zu schließen, wird die Methode Close des Objekts TextStreamObject
verwendet. Script 4.36 demonstriert dies, indem es erst eine Instanz von FileSystemObject
erstellt, dann eine Textdatei öffnet (C:\FSO\ScriptLog.txt) und diese dann wieder schließt.

Script 4.36: Öffnen und Schließen einer Textdatei

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", 1)
3objFile.Close

Seite 222 von 394


Lesen von Textdateien
Lesen aus einer Textdatei ist ein Standardverfahren bei vielen Administrationsaufgaben. Zum
Beispiel:

Lesen von Kommandozeilenargumenten - In der Textdatei könnte zum Beispiel eine Liste
der Computer gespeichert sein, auf die das Script zugreifen soll.

Eine Protokolldatei automatisch nach bestimmten Einträgen durchsuchen - Sie können
zum Beispiel nach Fehlereinträgen suchen.
Mit dem Objekt FileSystemObject können Sie aus Textdateien lesen. Hierbei sollten Sie
jedoch die folgenden Einschränkungen bedenken:

Sie können nur ASCII-Textdateien lesen - Sie können keine Unicode-Dateien oder
Binärdateien (zum Beispiel Microsoft Word oder Microsoft Excel lesen).

Sie können nur vom Anfang zum Ende der Textdatei lesen - Sie können nicht rückwärts
lesen oder zu Zeilen oder Zeichen in der Textdatei zurückspringen.

Sie können eine Datei nicht für gleichzeitiges Lesen und Schreiben öffnen
Die zum Lesen verfügbaren Dateien von FileSystemObject sehen Sie in Tabelle 4.8. Die
Beispiele gehen von einer Textdatei aus, die folgendermaßen aussieht:
Alerter,Share Process,Running,Auto,LocalSystem,
AppMgmt,Share Process,Running,Manual,LocalSystem,
Ati HotKey Poller,Own Process,Stopped,Auto,LocalSystem,
Tabelle 4.8: FileSystemObject-Methoden zum Lesen aus Textdateien
Methode Beschreibung
Read Liest die angegeben Anzahl an Zeichen. Der folgende Befehl liest zum Beispiel die
ersten 12 Zeichen der ersten Zeile ("Alerter'Shar'") und speichert diese in der
Variable strText:
strText = objTextFile.Read(12)
ReadLineLiest eine Zeile auf der Textdatei. Der folgende Befehl liest zum Beispiel die erste
Zeile ("Alerter'Share Process' Running,Auto,LocalSystem") und speichert sie in der
Variable strText:
strText = objTextFile.ReadLine
ReadAll Liest die gesamte Textdatei.
Skip Überspringt die angegebene Anzahl an Zeichen. Der folgende Befehl überspringt
zum Beispiel die ersten 12 Zeichen. Alle weiteren Leseoperationen beginnen also
bei Zeichen 13 ('e Process,Running,Auto,LocalSystem'):
objTextFile.Skip(12)
SkipLine Überspringt eine Zeile. Der folgende Code liest zum Beispiel die erste und die dritte
Zeile:
strText = objTextFile.Readline
objTextFile.SkipLine
strText = objTextFile.Readline

Die Größe einer Datei prüfen

Seite 223 von 394


Manchmal sind die von Windows erstellten Textdateien leer - das bedeutet, dass in der Datei
keine Zeichen enthalten sind und sie eine Größe von 0 Byte hat. Dies kommt zum Beispiel bei
Protokollen vor, die so lange leer sind bis ein Ereignis aufgetreten ist.
Leere Dateien sind ein Problem für Scriptautoren, da VBScript einen Laufzeitfehler erzeugt,
wenn Sie versuchen aus einer leeren Datei zu lesen.
Wenn die Möglichkeit besteht, dass die Datei leer sein könnte, dann vermeiden Sie den
Fehler, indem Sie vor einem Leseversuch die Dateigröße testen.
Script 4.37 erstellt eine Referenz auf die Datei C:\Windows\Netlogon.log. Dann prüft das
Script die Größe der Datei - wenn diese größer 0 ist, wird die Datei geöffnet und gelesen.
Andernfalls wird eine Fehlermeldung ausgegeben.

Script 4.37: Prüfen der Dateigröße

1 Set objFSO = CreateObject("Scripting.FileSystemObject")


2 Set objFile = objFSO.GetFile("C:\Windows\Netlogon.log")
3 If objFile.Size > 0 Then
4 Set objReadFile = objFSO.OpenTextFile("C:\Windows\Netlogon.log", 1)
5 strContents = objReadFile.ReadAll
6 Wscript.Echo strContents
7 objReadFile.Close
8 Else
9 Wscript.Echo "Die Datei ist leer."
10End If
Lesen einer gesamten Textdatei
Das einfachste Verfahren, um eine gesamte Datei einzulesen, ist die Methode ReadAll. Sie
rufen die Methode einfach auf, und speichern ihren Rückgabewert in einer Variablen.
Auch wenn Sie mehrere Textdateien zusammenfassen möchten, ist die Methode ReadAll die
beste Wahl. Stellen Sie sich zum Beispiel vor, Sie haben eine Gruppe von täglichen
Protokolldateien, die Sie in einer wöchentlichen Protokolldatei zusammenfassen möchten. Ein
solches Script würde folgendermaßen vorgehen:
1.Es öffnet die Textdatei für Montag, liest die gesamten Dateien über ReadAll ein und
speichert diese in einer Variablen.
2.Es öffnet die wöchentliche Protokolldatei im Modus Append und schreibt die Daten aus der
Variablen in diese Datei.
3.Es wiederholt die Schritte 1 und 2 für alle verbleibenden täglichen Protokolldateien.
Die Methode ReadAll benötigt keine Parameter. Script 4.38 öffnet die Textdatei
C:\FSO\ScriptLog und liest den gesamten Inhalt der Datei über ReadAll aus.

Script 4.38: Lesen einer Textdatei über die Methode ReadAll

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

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFile = objFSO.OpenTextFile("C:\FSO\ServerList.txt", 1)
3Do Until objFile.AtEndOfStream
4 strLine = objFile.ReadLine
5 Wscript.Echo strLine
6Loop
7objFile.Close
Eine Textdatei von unten nach oben 'lesen'
Wie schon erwähnt, können Sie mit dem Objekt FileSystemObject eine Datei nur von vorne
nach hinten lesen. Sie können nicht hinten beginnen und rückwärts lesen. Manchmal ist das
ein Problem - zum Beispiel bei der Arbeit mit Protokolldateien. Stellen Sie sich vor, Sie
möchten die neusten Einträge einer Protokolldatei (also die letzten) zuerst lesen und sich dann
zu den ältesten vorarbeiten.
Ein Script muss in einem solchen Fall folgendermaßen vorgehen:
1.Es erstellt einen Array, der die einzelnen Zeilen der Textdatei speichert.
2.Es liest die einzelnen Zeilen über die Methode ReadLine ein und speichert diese jeweils im
Array.
3.Es ruft den Inhalt des Array ab, beginnt jedoch mit dem letzten Element des Arrays (also
mit der Zeile, die als letztes gelesen wurde bzw. die als letzte Zeile in der Datei steht).
Script 4.40 demonstriert dieses Verfahren mit der Datei C:\FSO\ScriptLog.txt. Es speichert
die einzelnen Zeilen im Array arrFileLines. Nachdem alle Zeilen der Datei gelesen wurden,
werden die einzelnen Elemente des Arrays in umgekehrter Reihenfolge ausgegeben. Hierzu
wird eine For-Schleife verwendet. Sie beginnt mit dem letzten Element (die Obergrenze des
Arrays - Upper Bound - UBOUND) und arbeitet sich zum ersten Elemente vor (die
Untergrenze des Arrays - Lower Bound - LBOUND).
Script 4.40: Umgekehrtes 'Lesen' aus einer Textdatei

Seite 225 von 394


1 Dim arrFileLines()
2 i = 0
3 Set objFSO = CreateObject("Scripting.FileSystemObject")
4 Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", 1)
5 Do Until objFile.AtEndOfStream
6 Redim Preserve arrFileLines(i)
7 arrFileLines(i) = objFile.ReadLine
8 i = i + 1
9 Loop
10objFile.Close
11For l = Ubound(arrFileLines) to LBound(arrFileLines) Step -1
12 Wscript.Echo arrFileLines(l)
13Next
Nehmen wir an, die Textdatei hat den folgenden Inhalt:
6/19/2002 Success
6/20/2002 Failure
6/21/2002 Failure
6/22/2002 Failure
6/23/2002 Success
Dann würde die Ausgabe des Scripts folgendermaßen aussehen:
6/23/2002 Success
6/22/2002 Failure
6/21/2002 Failure
6/20/2002 Failure
6/19/2002 Success
Eine Textdatei Zeichen für Zeichen einlesen
Eine Textdatei kann auch einzelne Werte enthalten. In einem solchen Fall hat zum Beispiel
jeder Werte eine bestimmte Länge. Wert 1 ist 15 Zeichen lang, Wert 2 ist 10 Zeichen lang,
usw. Eine solche Textdatei könnte zum Beispiel folgendermaßen aussehen:
Server Value Status
atl-dc-01 19345 OK
atl-printserver-02 00042 OK
atl-win2kpro-05 00000 Failed
Wenn Sie nun einzelne Werte aus dieser Datei benötigen, dann müssen Sie die Datei
zeichenweise einlesen (eine Zeile enthält ja schließlich mehrere Werte). Nehmen wir an, Sie
benötigen jeweils den dritten Wert aus der oben gezeigten Textdatei. Dieser Wert beginnt in
jeder Zeile beim 26. Zeichen und ist nicht länger als 5 Zeichen. Sie müssen alle die Zeichen
26, 27, 28, 29 und 30 jeder Zeile lesen.
Mit der Methode Read ist genau dies möglicht. Sie liest die als Parameter übergebene Anzahl
von Zeichen ein. Die folgende Zeile liest zum Beispiel die nächsten 7 Zeichen aus der
Textdatei und speichert diese in der Variable strCharacters:
strCharacters = objFile.Read(7)
Indem Sie die Methoden Skip und SkipLine verwenden, haben Sie die Möglichkeit Zeichen zu
überspringen und so nur bestimmte Zeichen einzulesen. Script 4.41 liest zum Beispiel nur das
sechste Zeichen jeder Zeile ein. Hierzu geht es folgendermaßen vor:
1.Es überspringt die ersten fünf Zeichen mit dem Befehl Skip(5).
2.Es liest sechs Zeichen über den Befehl Read(1) ein.
3.Es springt zur nächsten Zeile.

Seite 226 von 394


Script 4.41: Einlesen von bestimmten Zeichen

1Set objFSO = CreateObject("Scripting.FileSystemObject")


2Set objFile = objFSO.OpenTextFile("C:\FSO\ScriptLog.txt", 1)
3Do Until objFile.AtEndOfStream
4 objFile.Skip(5)
5 strCharacters = objFile.Read(1)
6 Wscript.Echo strCharacters
7 objFile.SkipLine
8Loop
Um zu veranschaulichen wie das Script arbeitet, nehmen wir an, die Textdatei
C:\FSO\ScriptLog.txt hätte den folgenden Inhalt:
XXXXX1XXXXXXXXXXXXXX
XXXXX2XXXXXXXXXXXXXXXXXXX
XXXXX3XXXXXXXXXXXX
XXXXX4XXXXXXXXXXXXXXXXXXXXXXXXX
Die ersten fünf Zeichen jeder Zeile sind ein X, das sechste Zeichen ist eine Zahl und die
restlichen Zeichen der Zeile sind wieder X. Wenn das Script ausgeführt wird, dann geht es
folgendermaßen vor:
1.Es öffnet die Textdatei und beginnt in der ersten Zeile mit dem Lesen.
2.Es überspringt die ersten fünf Zeichen.
3.Es verwendet die Methode Read, um das sechste Zeichen zu lesen.
4.Es gibt das Zeichen aus.
5.Es springt zur nächsten Zeile und wiederholt den Prozess so lange bis alle Zeilen gelesen
wurden.
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
1
2
3
4

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

Seite 227 von 394


3.Es schreibt über die Methode Write, WriteLine oder WriteBlankLines in die Datei.
4.Es schließt die Datei.
Die drei Methoden zum Schreiben in Textdateien sehen Sie in Tabelle 4.9.

Tabelle 4.9: Methoden zum Schreiben in Textdateien


Methode Beschreibung
Write Schreibt Daten in eine Textdatei, ohne einen Zeilenumbruch anzuhängen.
Der folgende Code schreibt zum Beispiel zwei Strings in eine Textdatei:

objFile.Write ("Die ist Zeile 1.")


objFile.Write ("Die ist Zeile 2.")

Die Textdatei sieht dann so aus:


Die ist Zeile 1.Die ist Zeile 2.
WriteLine Schreibt Daten in eine Textdatei und hängt einen Zeilenumbruch an. Der
folgende Code schreibt zum Beispiel zwei Strings in eine Textdatei:

objFile.WriteLine ("Die ist Zeile 1.")


objFile.WriteLine ("Die ist Zeile 2.")

Das Ergebnis sieht so aus:

Die ist Zeile 1.


Die ist Zeile 2.
WriteBlankLinesSchreibt eine leere Zeile in die Textdatei. Der folgende Code schreibt zwei
Strings in die Textdatei und trennt diese durch einen Leerzeile:

objFile.Writeline ("Dies ist Zeile 1.")


objFile.WriteBlankLines(1)
objFile.Writeline ("Dies ist Zeile 2.")

Das Ergebnis sieht so aus:

Dies ist Zeile 1.

Dies ist Zeile 2.


Außerdem können Sie beim Schreiben in eine Textdatei die VBScript-Konstante VbTab
verwenden. Mit dieser Konstante fügen Sie an der entsprechenden Position ein
Tabulatorzeichen ein. Die folgende Codezeile demonstriert dies:
objTextFile.WriteLine(objService.DisplayName & vbTab & objService.State)
Eine Schwachstelle von FileSystemObject ist, dass es nicht möglich ist, bestimmte Zeilen in
einer Textdatei zu verändern. Sie können zum Beispiel kein Script schreiben, das einige
Zeilen überspringt und dann eine Zeile mit einem bestimmten Text überschreibt. Stattdessen
müssen Sie folgendermaßen vorgehen:
1.Sie lesen alle Zeilen der Datei ein (zum Beispiel in ein Array).

Seite 228 von 394


2.Sie ändern die entsprechenden Zeilen im Array.
3.Sie schreiben das Array wieder zurück in die Datei

Überschreiben vorhandener Daten


Stellen Sie sich vor, Sie möchten dass ein Script eine bestimmte nächtliche Aufgabe
protokolliert, damit Sie das Protokoll jeweils am nächsten Tag überprüfen können. In diesem
Fall reicht es Ihnen, wenn Ihnen das Protokoll vom Vortag zur Verfügung steht. Es ist nicht
nötig, dass das Script die aktuellen Daten an die alten Dateien anhängt. Das Script kann die
alten Daten vom Vortag einfach überschreiben.
Wenn Sie eine Datei im Modus ForWriting öffnen, dann werden die in der Datei vorhanden
Daten mit den neu geschriebenen Daten überschrieben. Nehmen wird zum Beispiel an, in
einer einzelnen Textdatei haben Sie die letzte Kopie der gesammelten Werke von
Shakespeare gespeichert. Nun öffnet Ihr Script diese Datei im Modus ForWriting und schreibt
ein einzelnes Zeichen in die Datei. In diesem Fall sind alle Werke von Shakespeares für
immer verloren, und die Datei enthält nur noch das eine neue Zeichen.
Script 4.42 öffnet die Datei C:\FSO\ScriptLog.txt im Modus ForWriting und schreibt das
aktuelle Datum und die Uhrzeit in die Datei. Jedes Mal wenn Sie das Script ausführen, wird
der gesamte Inhalt der Datei überschrieben. Die Datei enthält niemals mehr als ein Datum und
eine Uhrzeit - egal wie oft es auch ausgeführt wird.

Script 4.42: Überschreiben von vorhandenen 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

Seite 229 von 394


5objFile.Close
Da das Script die Methode WriteLine verwendet, werden Datum und Uhrzeit immer in eine
neue Zeile geschrieben. Wäre die Methode Write verwendet worden, dann sähe die Textdatei
so aus:
6/25/2002 8:49:47 AM6/25/2002 8:49:48 AM6/25/2002 8:50:33 AM6/25/2002
8:50:35 AM

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.

Seite 230 von 394


Ein Dictionary-Objekt erstellen
Da ein Dictionary-Objekt ein COM-Objekt ist, müssen Sie wie bei allen anderen COM-
Objekten auch erst eine Instanz des Objekts erstellen. Die folgende Codezeile führt dies
durch:
Set objDictionary = CreateObject("Scripting.Dictionary")
Nachdem Sie das Dictionary-Objekt erstellt haben, können Sie dessen Eigenschaften
konfigurieren und Elemente zum Dictionary-Objekt hinzufügen.
Das Dictionary-Objekt hat nur eine konfigurierbare Eigenschaft: CompareMode. Diese
Eigenschaft beeinflusst, wie Sie die Einträge im Dictionary-Objekt finden können.
Standardmäßig arbeitet das Dictionary-Objekt im Binärmodus. Das bedeutet, dass die
einzelnen Schlüssel als ASCII-Werte gespeichert werden. Bei ASCII-Werten wird zwischen
Großbuchstaben und Kleinbuchstaben unterschieden. Im Binärmodus könnten Sie zum
Beispiel die beiden folgenden Werte als Schlüssel anlegen:
alerter
ALERTER
Mit anderen Worten: Im Binärmodus ist es durchaus möglich versehentlich mehrere Einträge
für dasselbe Element anzulegen. Außerdem ist die Suche in diesem Modus schwieriger. Wenn
Sie zum Beispiel nach dem Schlüssel Alerter suchen, dann erhalten Sie kein Ergebnis. Das
liegt daran, weil keiner der beiden Einträge dieser Buchstabenkombination entspricht (großes
A, Rest klein).
Im zweiten Modus, dem Textmodus, werden Groß- und Kleinbuchstaben gleich behandelt. In
diesem Modus können Sie keinen Schlüssel mit dem Namen ALERTER anlegen, wenn bereits
ein Schlüssel mit dem Namen alerter vorhanden ist. Auch das Suchen ist viel einfacher.
Wenn Sie nach dem Schlüssel alerter such, erhalten Sie die Einträge für Alerter und
ALERTER zurück.
Um den Modus eines Dictionary-Objekts zu konfigurieren, erstellen Sie zuerst eine Instanz
des Objekts. Dann setzen Sie die Eigenschaft CompareMode auf einen der beiden folgenden
Werte:
0 - Setzt den Modus auf Binär. Dies ist auch der Standardwert.
1 - Setzt den Modus auf Text.
Script 4.44 setzt das Dictionary-Objekt beispielsweise auf den Modus Text.

Script 4.44: Dictionary-Objekt konfigurieren

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

Seite 231 von 394


Apple
APPLE
Im Textmodus wären die drei Schlüssel jedoch identisch, da in diesem Modus ja nicht
zwischen Groß- und Kleinschreibung unterschieden wird. Sie müssen also erst alle Elemente
aus dem Objekt löschen, bevor Sie dessen Modus ändern können.

Einträge zu einem Dictionary-Objekt hinzufügen


Mit der Methode Add können Sie neue Einträge zu einem Dictionary-Objekt hinzufügen. Die
Methode benötigt zwei Parameter: den Schlüsselnamen, über den später auf den Eintrag
zugegriffen werden soll und den Wert für diesen Eintrag.
Script 4.45 erstellt ein Dictionary-Objekt und fügt diesem dann die Einträge aus Tabelle 4.10
hinzu.

Tabelle 4.10: Beispieleinträge


SchlüsselWert
Drucker1 Druckt
Drucker2 Offline
Drucker3 Druckt

Script 4.45: Einen Eintrag zum Dictionary-Objekt hinzufügen

1Set objDictionary = CreateObject("Scripting.Dictionary")


2objDictionary.Add "Drucker 1", "Druckt"
3objDictionary.Add "Drucker 2", "Offline"
4objDictionary.Add "Drucker 3", "Druckt"
Die Schlüssel der einzelnen Einträge müssen jeweils eindeutig sein - sie dürfen nicht
mehrmals vorkommen. Der folgenden Scriptcode würde daher zum Beispiel zu einem Fehler
führen:
objDictionary.Add "Drucker 1", "Druckt"
objDictionary.Add "Drucker 1", "Offline"
Versehentlich einen Schlüssel zu einem Dictionary-Objekt hinzufügen
Ein potentielles Problem bei Dictionary-Objekten ist es, wenn Sie versuchen auf ein Element
zuzugreifen, das noch nicht vorhanden ist. Statt den Wert für dieses Objekt zurückzugeben,
wird in diesem Fall nämlich ein neuer Eintrag mit diesem Schlüssel angelegt. Das folgende
Script versucht zum Beispiel auf das nicht vorhandene Element mit dem Schlüssel Printer 4
zuzugreifen:
Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.Add "Drucker 1", "Druckt"
objDictionary.Add "Drucker 2", "Offline"
objDictionary.Add "Drucker 3", "Druckt"
Wscript.Echo objDictionary.Item("Drucker 4")
Wenn das Script versucht auf das nicht vorhandene Element (Drucker 4) zuzugreifen, wird
leider kein Laufzeitfehler ausgelöst. Stattdessen wird ein neues Element mit dem Schlüssel
Drucker 4 zum Dictionary-Objekt hinzugefügt. Der Wert dieses Elements ist Null. Da der
Wert des neuen Eintrags auch gleich angezeigt wird, sieht die Ausgabe des Scripts wie in
Abbildung 4.9 aus.

Seite 232 von 394


Abbildung 4.9: Ausgabe eines versehentlich hinzugefügten Elements zu einem
Dictionary-Objekt
Um dieses Problem zu umgehen, müssen Sie vor einem Zugriff auf ein Element prüfen, ob es
das Element gibt.

Bearbeiten von Schlüsseln und Werten in einem Dictionary-Objekt


Zu den Aufgaben, die Sie mit einem Dictionary-Objekt durchführen können, gehören unter
anderem die folgenden:

Prüfen, wie viele Einträge im Dictionary-Objekt vorhanden sind.

Die Einträge im Dictionary-Objekt auflisten.

Prüfen, ob ein bestimmter Eintrag vorhanden ist oder nicht.

Einen Wert oder einen Schlüssel ändern.

Einträge aus dem Dictionary-Objekt entfernen.

Diese Aktionen werden in den folgenden Abschnitt besprochen.

Die Zahl der Einträge in einem Dictionary-Objekt abfragen


Wie die meisten anderen Collections hat auch das Dictionary-Objekt eine Eigenschaft mit
dem Namen Count. Diese gibt die Zahl der Elemente der Collection zurück. Script 4.46
erstellt eine Instanz des Dictionary-Objekts, fügt diesem drei Einträge hinzu und gibt dann die
Anzahl der Einträge über die Eigenschaft Count zurück.
Script 4.46: Prüfen, wie viele Einträge in einem Dictionary-Objekt vorhanden sind

1Set objDictionary = CreateObject("Scripting.Dictionary")


2objDictionary.Add "Drucker 1", "Printing"
3objDictionary.Add "Drucker 2", "Offline"
4objDictionary.Add "Drucker 3", "Printing"
5Wscript.Echo objDictionary.Count
Wenn Sie das Script ausführen, erhalten Sie den Wert 3 zurück (die Anzahl der Einträge).

Die Elemente eines Dictionary-Objekts aufzählen


Über die Methoden Keys und Items können Sie die Schlüssel oder Werte aller Einträge eines
Dictionary-Objekts in einem Array zurückgeben. Nachdem Sie eine der Methoden aufgerufen
haben, können Sie das Array dann mit einer For-Each-Schleife durchgehen.
Script 4.47 erstellt ein einfaches Dictionary-Objekt mit drei Einträgen. Dann verwendet es die
Methode Keys, um alle Schlüssel des Dictionary-Objekts im Array colKeys zu speichern und
die Elemente des Arrays in einer For-Each-Schleife auszugeben. Danach wird für die Werte
des Dictionary-Objekts derselbe Vorgang über die Methode Items ausgeführt.

Seite 233 von 394


Script 4.47: Auflisten der Schlüssel und Werte eine Dictionary-Objekts

1 Set objDictionary = CreateObject("Scripting.Dictionary")


2 objDictionary.Add "Drucker 1", "Druckt"
3 objDictionary.Add "Drucker 2", "Offline"
4 objDictionary.Add "Drucker 3", "Druckt"
5
6 colKeys = objDictionary.Keys
7 For Each strKey in colKeys
8 Wscript.Echo strKey
9 Next
10
11colItems = objDictionary.Items
12For Each strItem in colItems
13 Wscript.Echo strItem
14Next
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
Drucker 1
Drucker 2
Drucker 3
Druckt
Offline
Druckt
Um den Wert eines bestimmten Eintrags anzuzeigen, verwenden Sie die Methode Item. Die
folgende Zeile zeigt zum Beispiel den Wert des Eintrags mit dem Schlüssel Drucker 3 an:
Wscript.Echo objDictionary.Item("Printer 3")

Die Existenz eines Schlüssels prüfen


Das Dictionary-Objekt bietet Ihnen gegenüber einem Array oder einer Collection einen
großen Vorteil: Sie können sehr einfach feststellen, ob ein bestimmter Schlüssel vorhanden
ist. Nehmen wir zum Beispiel einmal an, dass Sie in einer Liste mit Dateien nach bestimmten
DLLs suchen möchten. Mit einer Collection oder einem Array müssen Sie die gesamte Liste
in einer Schleife durchlaufen und jedes Element einzeln prüfen.
Im Gegensatz dazu können Sie bei einem Dictionary-Objekt die Methode Exists verwenden -
mit dieser stellen Sie fest, ob ein bestimmter Schlüssel vorhanden ist. Die Methode erwartet
einen Parameter (den Namen des Schlüssels). Wenn der Schlüssel existiert, dann gibt sie den
Boolean-Wert True zurück - andernfalls ist der Rückgabewert False.
Script 4.48 erstellt zum Beispiel ein Dictionary-Objekt und fügt diesem drei Elemente hinzu
(Drucker 1, Drucker 2 und Drucker 3). Dann prüft das Script, ob ein Schlüssel mit dem
Namen Drucker 4 vorhanden ist und gibt das Ergebnis dieser Prüfung aus.

Script 4.48: Ein Dictionary-Objekt auf einen bestimmten Schlüssel prüfen

1Set objDictionary = CreateObject("Scripting.Dictionary")


2objDictionary.Add "Drucker 1", "Druckt"
3objDictionary.Add "Drucker 2", "Offline"
4objDictionary.Add "Drucker 3", "Druckt"
5If objDictionary.Exists("Drucker 4") Then
6 Wscript.Echo "Drucker 4 ist vorhanden."
7Else
8 Wscript.Echo "Drucker 4 ist nicht vorhanden."
9End If

Seite 234 von 394


Ein Element in einem Dictionary-Objekt ändern
Die Elemente eines Dictionary-Objekts sind nicht in Stein gemeißelt. Sie haben die
Möglichkeit die Elemente zu ändern. Script 4.49 erstellt ein Dictionary-Objekt mit drei
Schlüsseln: atl-dc-01, atl-dc-02 und atl-dc-03. Der Wert jedes Elements wird auf den Text
'No status.' Gesetzt.
Danach werden die Werte der Elemente über die Methode Item geändert. Die Methode
erwartet als Parameter den Schlüssel des zu ändernden Elements.

Script 4.49: Ändern des Werts eines Elements in einem Dictionary-Objekt

1 Set objDictionary = CreateObject("Scripting.Dictionary")


2 objDictionary.Add "atl-dc-01", "Kein Status"
3 objDictionary.Add "atl-dc-02", "Kein Status"
4 objDictionary.Add "atl-dc-03", "Kein Status"
5
6 colKeys = objDictionary.Keys
7 For Each strKey in colKeys
8 Wscript.Echo strKey, objDictionary.Item(strKey)
9 Next
10
11objDictionary.Item("atl-dc-01") = "Verfügbar"
12objDictionary.Item("atl-dc-02") = "Verfügbar"
13objDictionary.Item("atl-dc-03") = "Nicht verfügbar"
14
15colKeys = objDictionary.Keys
16For Each strKey in colKeys
17 Wscript.Echo strKey, objDictionary.Item(strKey)
18Next
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
atl-dc-01 Kein Status
atl-dc-02 Kein Status
atl-dc-03 Kein Status
atl-dc-01 Verfügbar
atl-dc-02 Verfügbar
atl-dc-03 Nicht verfügbar

Elemente aus einem Dictionary-Objekt entfernen


Es gibt zwei Methoden, um Elemente aus einem Dictionary-Objekt zu entfernen:

RemoveAll - entfernt alle Elemente.

Remove - entfernt ein bestimmtes Element.

Alle Elemente aus einem Dictionary-Objekt entfernen


Um alle Elemente aus einem Dictionary-Objekt zu entfernen, können Sie die Methode
RemoveAll verwenden. Script 4.50 demonstriert dies bei einem Dictionary-Objekt mit drei
Elementen. Nachdem es alle Elemente angezeigt hat, entfernt es die Elemente über den
folgenden Befehl:
objDictionary.RemoveAll
Um zu überprüfen ob alle Elemente entfernt wurden, gibt es noch einmal alle Elemente aus.

Script 4.50: Alle Elemente aus einem Dictionary-Objekt entfernen

Seite 235 von 394


1 Set objDictionary = CreateObject("Scripting.Dictionary")
2 objDictionary.Add "Drucker 1", "Druckt"
3 objDictionary.Add "Drucker 2", "Offline"
4 objDictionary.Add "Drucker 3", "Druckt"
5 colKeys = objDictionary.Keys
6 Wscript.Echo "Erster Durchlauf: "
7 For Each strKey in colKeys
8 Wscript.Echo strKey
9 Next
10objDictionary.RemoveAll
11colKeys = objDictionary.Keys
12Wscript.Echo VbCrLf & "Zweiter Durchlauf: "
13For Each strKey in colKeys
14 Wscript.Echo strKey
15Next
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
Erster Durchlauf:
Drucker 1
Drucker 2
Drucker 3
Zweiter Durchlauf:
Bestimmte Einträge aus einem Dictionary-Objekt entfernen
Stellen Sie sich vor, Sie haben ein Dictionary-Objekt mit den folgenden Schlüsseln:
atl-dc-01
atl-dc-02
atl-dc-03
atl-dc-04
atl-dc-05
Sie verwenden das Dictionary-Objekt, um auf die Computer zuzugreifen. Beim Zugriff auf
zwei Computer (atl-dc-03 und atl-dc-04) stellt das Script fest, dass diese nicht erreichbar sind.
Das Script muss also später erneut versuchen diese Computer zu erreichen. Wie können Sie
diese Aufgabe bewältigen? Ein Weg wäre alle erreichten Computer aus dem Dictionary-
Objekt zu entfernen. Nach dem ersten Durchlauf wären also noch folgende Elemente
vorhanden:
atl-dc-03
atl-dc-04
Bei nächsten Durchlauf werden wieder alle erfolgreich kontaktierten Computer entfernt, usw.
Wenn das Dictionary-Objekt keine Einträge mehr enthält, dann wurden alle Computer
erfolgreich kontaktiert.
Um ein Element zu entfernen, verwenden Sie die Methode Remove. Ihr übergeben Sie als
einzigen Parameter den Schlüssel des zu entfernenden Eintrags:
objDictionary.Remove("atl-dc-02")
Script 4.51 erstellt ein Dictionary-Objekt mit drei Elementen und gibt dann alle Schlüssel aus.
Danach entfernt es den Eintrag mit dem Schlüssel Drucker 2 und gibt die Elemente erneut
aus.

Script 4.51: Einen bestimmten Eintrag entfernen

1 Set objDictionary = CreateObject("Scripting.Dictionary")


2 objDictionary.Add "Drucker 1", "Druckt"
3 objDictionary.Add "Drucker 2", "Offline"

Seite 236 von 394


4 objDictionary.Add "Drucker 3", "Druckt"
5 colKeys = objDictionary.Keys
6 Wscript.Echo "Erster Durchlauf: "
7 For Each strKey in colKeys
8 Wscript.Echo strKey
9 Next
10objDictionary.Remove("Drucker 2")
11colKeys = objDictionary.Keys
12Wscript.Echo VbCrLf & "Zweiter Durchlauf: "
13For Each strKey in colKeys
14 Wscript.Echo strKey
15Next
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
Erster Durchlauf:
Drucker 1
Drucker 2
Drucker 3
Zweiter Durchlauf:
Drucker 1
Drucker 2

Scripting-Konzepte und -Technologien zur


Systemadministration: Kapitel 5 - ADSI-
Scripting
(Engl. Originaltitel: ADSI Scripting Primer)
Die Administration eines Verzeichnisdienstes besteht oft aus vielen sich wiederholenden
Aufgaben, zum Beispiel dem Erstellen, Löschen und Ändern von Benutzern, Gruppen, OUs,
Computern und anderen Verzeichniselementen. Scripte sind geradezu prädestiniert, um solche
Aufgaben durchzuführen.
Bei Active Directory Service Interfaces (ADSI) handelt es sich um eine Technologie, die die
Script-basierte Verwaltung des Verzeichnisdiensts Active Directory ermöglicht. ADSI-fähige
Scripte können eine große Menge an administrativen Aufgaben durchführen.
Die Administration eines Verzeichnisdienstes besteht oft aus vielen sich wiederholenden
Aufgaben, zum Beispiel dem Erstellen, Löschen und Ändern von Benutzern, Gruppen, OUs,
Computern und anderen Verzeichniselementen. Scripte sind geradezu prädestiniert, um solche
Aufgaben durchzuführen.
Bei Active Directory Service Interfaces (ADSI) handelt es sich um eine Technologie, die die
Script-basierte Verwaltung des Verzeichnisdiensts Active Directory ermöglicht. ADSI-fähige
Scripte können eine große Menge an administrativen Aufgaben durchführen.

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.

Seite 237 von 394


Ein einführendes Beispiel
Stellen Sie sich das folgende Szenario vor: Es ist Freitagmorgen und Sie planen gerade Ihr
Wochenende - außerdem haben Sie in der nächsten Woche Urlaub. Sie erhalten eine
dringende E-Mail von Ihrem Chef, der Ihnen mitteilt, dass eine Gruppe Consultants
Montagmorgen einen Anwendungstest durchführen will. Bei diesem Test soll an der
Anwendung jeweils eine Testanmeldung mit 1.000 verschiedenen AD-Benutzerkonten
durchgeführt werden.
Ihre Aufgabe soll es nun sein, eine Active Directory-Domäne mit 1.000 Benutzerkonten
einzurichten. Die Einrichtung der Domäne ist einfach - aber was ist mit den 1.000
Benutzerkonten? Wenn Sie die alle per Hand anlegen, dann haben Sie bis Montagmorgen zu
tun. Eine solche Aufgabe können Sie jedoch hervorragend über ein Script erledigen. Script
5.1 legt 1.000 Benutzerkonten an (mit den Namen UserNo1 - UserNo1000).

Script 5.1: Erstellen von 1.000 Active Directory-Benutzerkonten

1 Set objRootDSE = GetObject("LDAP://rootDSE")


2 Set objContainer = GetObject("LDAP://cn=Users," & _
3 objRootDSE.Get("defaultNamingContext"))
4
5 For i = 1 To 1000
6 Set objLeaf = objContainer.Create("User", "cn=UserNo" & i)
7 objLeaf.Put "sAMAccountName", "UserNo" & i
8 objLeaf.SetInfo
9 Next
10Wscript.Echo "1000 Users created."

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.

Verwaltung des Verzeichnisdienstes


Script 5.1 ist zwar sehr nützlich, erledigt jedoch nur eine einzelne Aufgabe - es erstellt
Benutzerkonten. Die normale Verwaltung von Active Directory umfasste jedoch sehr viel
mehr. Diese Aufgaben lassen sich in vier grundlegende Kategorien unterteilen:
1.Erstellen - Zum Beispiel das Erstellen von Benutzerkonten, Gruppen, OUs,
Computerkonten, Standorten, Subnetzen, veröffentlichten Druckern und Freigaben.
2.Ändern - Zum Beispiel das Konfigurieren einer Telefonnummer für ein Benutzerkonto, die
Delegierung der Kontrolle über eine OU, das Löschen von Gruppenmitgliedern oder die
Deaktivierung von Computerkonten.
3.Lesen - Zum Beispiel das Auslesen von Benutzernamen, Gruppenmitgliedern.
4.Löschen - Zum Beispiel das Löschen von Benutzerkonten, Gruppen und OUs.
Was ADSI wirklich praktisch macht, ist die effiziente Verwaltung von Active Directory über
den konsistenten Ansatz von ADSI - mit diesem Ansatz werden die unterschiedlichsten
Objekte auf die gleiche Art und Weise verwaltet. So funktioniert zum Beispiel die Erstellung
von Benutzern, OUs und Gruppen fast gleich.

Seite 238 von 394


Das gleiche gilt für die Bearbeitung und für das Auslesen von Active Directory-Objekten. Sie
können alle Objekte über die gleichen grundlegenden Schritte auslesen.

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 von Active Directory-Objekten


Script 5.1 hat Ihnen gezeigt, wie Sie 1.000 Benutzerkonten erstellen können. Im folgenden
Abschnitt wird - etwas bescheidener - jeweils eine OU, ein Benutzerkonto und eine Gruppe
erstellt.
Die Erstellung von Active Directory-Objekten umfasste vier grundlegende Schritte:
1.Eine Verbindung mit dem Active Directory-Container aufbauen, der das neue Objekt
aufnehmen soll.
2.Das Objekt erstellen.
3.Die verpflichtenden Attribute des Objektes konfigurieren (wenn erforderlich).
4.Das neue Objekt an Active Directory übermitteln.
Das Ziel der drei Scripte dieses Abschnitts ist es, eine OU mit dem Namen HR und in der OU
ein Benutzerkonto mit dem Namen MyerKen und eine Gruppe mit dem Namen Atl-Users zu
erstellen.

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.

Script 5.2: Erstellen einer OU

1Set objDomain = GetObject("LDAP://dc=NA,dc=fabrikam,dc=com")


2Set objOU = objDomain.Create("organizationalUnit", "ou=HR")
3objOU.SetInfo
Erstellen eines Benutzerkontos

Seite 239 von 394


Script 5.3 erstellt ein neues Benutzerkonto mit dem Namen MyerKen in der OU HR. Die OU
HR befindet sich in der Domäne na.fabrkam.com. Das Script führt die folgenden Schritte
durch:
1.Es baut eine Verbindung mit dem Container der OU HR in der Domäne na.fabrikam.com
auf.
2.Es erstellt ein Benutzerkonto mit den Namen MyerKen.
Es ist nicht notwendig den ersten Buchstaben von Vor- und Nachnamen groß zu schreiben -
da die Groß- und Kleinschreibung jedoch in Active Directory erhalten bleibt, fällt es den
Benutzern so möglicherweise einfacher, den Vor- und Nachnamen zu unterscheiden.
3.Es setzt das verpflichtende Attribut sAMAccountName auf den Wert myerken.
4.Es übermittelt das neue Benutzerkonto an Active Directory.

Script 5.3: Erstellen eines Benutzerkontos

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2Set objUser = objOU.Create("user", "cn=MyerKen")
3objUser.Put "sAMAccountName", "myerken"
4objUser.SetInfo
Erstellen einer Gruppe
Script 5.4 erstellt eine globale Gruppe mit den Namen Atl-Users in der OU HR in der Domäne
na.fabrikam.com. Hierzu geht das Script folgendermaßen vor:
1.Es baut eine Verbindung mit dem Container der OU HR in der Domäne na.fabrikam.com
auf.
2.Es erstellt eine Gruppe mit den Namen Atl-Users (standardmäßig wird eine globale Gruppe
erstellt).
3.Es setzt das einzige verpflichtende Attribut sAMAccountName auf den Wert Atl-Users.
4.Es übermittelt die neue Gruppe an Active Directory.

Script 5.4: Erstellen einer Gruppe

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2Set objGroup = objOU.Create("group", "cn=Atl-Users")
3objGroup.Put "sAMAccountName", "Atl-Users"
4objGroup.SetInfo
Aus den Scripten dieses Abschnitts können wir folgende Erkenntnisse gewinnen:

Sie führen alle die gleichen grundlegenden Schritte durch (verbinden mit einem Active
Directory-Container, Objekt erstellen, verpflichtende Attribute setzen und Objekt an Active
Directory übermitteln).

Sie verwenden alle dieselbe Methode (Create), egal was für ein Objekt erstellt wird.

Die einzigen Teile, die sich bei den Scripten unterscheiden, sind die von den Methoden
verwendeten Parameter. Hierzu gehört zum Beispiel der Klassenname (organizationalUnit,
user und group), der angibt was für ein Objekt erstellt werden soll. Auch die zu setzenden
Attribute unterscheiden sich.

Seite 240 von 394


Die Schritte beim Erstellen einer OU (Script 5.2), eines Benutzerkontos (Script 5.3) und einer
Gruppe (Script 5.4) sind exakt gleich. Dies gilt auch für alle übrigen Objekttypen.
Um ein Objekt zu erstellen, verbindet sich das Script als erstes mit einem Container - dieser
Prozess wird auch Bindung genannt. Script 5.2 verbindet sich mit der Domäne, um eine OU
zu erstellen. Die Domäne können Sie sich hier als normalen Container vorstellen. Script 5.3
und Script 5.4 verbinden sich beide mit der OU.
Nach der Bindung an einen Container erstellt das jeweilige Script ein Objekt. Hierzu müssen
zwei Parameter angegeben werden: der Klassenname des Objekts und der Name des
eigentlichen Objekts. Script 5.2 erstellt eine OU. Es gibt hierzu die Klasse organizationalUnit
und den Objektnamen ou=HR an. Script 5.3 erstellt ein Benutzerkonto: Die Klasse heißt user,
und der Name des neuen Objekts ist cn=MyerKen. Script 5.4 erstellt eine Gruppe. Die Klasse
heißt hier group, und der Objektname lautet cn=Atl-Users. Der Vorgang findet jeweils in
Zeile 3 der Scripte statt. Weitere Informationen dazu wie Sie die Objektklasse eines Objekts
abfragen, finden Sie im Abschnitt ADSI Schnittstellen dieses Kapitels.
Bevor ein Objekt an Active Directory übermittelt wird, müssen Sie die verpflichtenden
Attribute für die Objekte setzen. Für eine OU gibt es keine verpflichtenden Attribute. Daher
wird dieser Schritt in Script 5.2 nicht durchgeführt. In Zeile 4 von Script 5.3 und Script 5.4
werden jedoch verpflichtende Attribute gesetzt (sAMAccountName wird sowohl bei einem
Benutzerkonto als auch bei einer Gruppe verwendet). Weitere Informationen dazu, wie Sie
feststellen, welche verpflichtenden Attribute ein bestimmtes Objekt benötigt, erhalten Sie im
Abschnitt Die Active Directory-Architektur in diesem Kapitel.
Der letzte Schritt in der Erstellung eines Objekts ist die Übertragung (Speicherung) in Active
Directory. Dieser Schritt wird jeweils in der letzten Zeile der Scripte durchgeführt.

Bearbeiten von Active Directory-Objekten


Das Bearbeiten von Attributen von Active Directory-Objekten ist gleichbedeutend mit dem
Ersetzen von Attributen. Beim Bearbeiten wird der vorhandene Attributwert gelöscht und der
neue Attributwert geschrieben.
Die Art einer Änderung hängt normalerweise vom Objekttyp und von dessen Attributen ab -
zum Beispiel, ob ein Attribut einen einzelnen Wert oder mehrere Werte speichert. Die
folgenden Beschreibungen ändern jedoch zur Vereinfachung nur Attribute mit einem
einzelnen Wert.
Die Änderung eines Attributs eines Active Directory-Objekts besteht aus drei grundlegenden
Schritten:
1.Eine Verbindung zu dem Active Directory-Objekt aufbauen, das geändert werden soll.
2.Ein oder mehrere Attribute des Objektes ändern.
3.Die Änderungen an Active Directory übertragen.
Die drei Scripte in diesem Kapitel ändern die Attribute der drei Objekte, die weiter oben in
diesem Kapitel erstellt wurden (die OU HR, der Benutzer MyerKen und die globale Gruppe
Atl-Users). Da alle drei Objekte über ein Attribut description (Beschreibung) verfügen, wird
dieses Attribut verändert.

Ein Attribut einer OU ändern

Seite 241 von 394


Script 5.5 ändert das Attribut description der OU HR in der Domäne na.fabrikam.com. Dem
Attribut wird der Wert Human Resources zugewiesen. Hierbei geht das Script
folgendermaßen vor:
1.Es verbindet sich mit der Objekt der OU HR in der Domäne na.fabrikam.com. Im Gegensatz
zum Erstellen wird die OU hier als Objekt statt als Container bezeichnet - die liegt daran,
dass bei diesem Vorgang ein Attribut eines Objekts geändert wird.
2.Es ändert das Attribut des Objekts, indem es ihm den Wert Human Resources zuweist.
3.Es überträgt die Änderung an der OU an Active Directory.

Script 5.5: Das Attribut description einer OU ändern

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2objOU.Put "description", "Human Resources"
3objOU.SetInfo
Ein Attribut eines Benutzerkontos ändern
Script 5.6 ändert das Attribut description des Benutzerkontos mit dem Namen MyerKen in der
OU HR der Domäne na.fabrikam.com. Dem Attribut wird der Wert HR employee zugewiesen.
Hierzu geht das Script folgendermaßen vor:
1.Es verbindet sich mit dem Benutzerobjekt MyerKen in der OU HR der Domäne
na.fabrikam.com.
2.Es ändert das Attribut des Objekts, indem es ihm den Wert HR employee zuweist.
3.Es überträgt die Änderungen am Benutzerkonto an Active Directory.

Script 5.6: Das Attribut description eines Benutzerkontos ändern

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.

Script 5.7: Das Attribut description einer Gruppe ändern

1Set objOU = GetObject _


2 ("LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com")
3objOU.Put "description", "Atlanta users"
4objOU.SetInfo

Seite 242 von 394


Zusammenfassend kann man über die Scripte in diesem Abschnitt Folgendes sagen:

Sie führen alle die gleichen grundlegenden Schritte aus: Verbinden mit dem Active
Directory-Objekt, Ändern des Attributes und die Änderung an Active Directory übertragen.

Sie verwenden alle die gleiche Methode (Put), egal, welche Objektklasse geändert wird.

Attribute eines Active Directory-Objekts lesen


In den vorhergehenden Abschnitt wird die Erstellung einer OU, eines Benutzerkontos und
einer Gruppe beschrieben. Außerdem wurde das Attribut description der Objekte konfiguriert.
Als Nächstes lernen Sie, wie die Attribute der Objekte ausgelesen werden.
Das Lesen von Attributen von Active Directory-Objekten wird über zwei einfache Schritte
durchgeführt:
1.Eine Verbindung mit dem Active Directory-Objekt aufbauen, das gelesen werden soll.
2.Ein oder mehrere Attribute des Objekts lesen.
Das Ziel der drei Scripte in diesem Abschnitt ist es, das Attribut description der OU HR, des
Benutzerkontos MyerKen und der Gruppe Atl-Users zu lesen und deren Werte anzuzeigen.

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.

Ein Attribut einer OU auslesen


Script 5.8 liest das Attribut description der OU HR in der Domäne na.fabrikam.com und zeigt
dieses an. Hierzu geht das Script folgendermaßen vor:
1.Es verbindet sich mit dem OU-Objekt HR in der Domäne na.fabrikam.com.
2.Es liest das Attribut description des Objekts.

Script 5.8: Lesen des Attributs description einer OU

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2Wscript.Echo objOU.Get("description")
Ein Attribut eines Benutzerkontos auslesen
Script 5.9 liest das Attribut description des Benutzerobjekts MyerKen in der OU HR in der
Domäne na.fabrikam.com und zeigt dieses an. Hierzu geht das Script folgendermaßen vor:
1.Es verbindet sich mit dem Benutzerobjekt MeyerKen in der OU HR in der Domäne
na.fabrikam.com.
2.Es liest das Attribut description des Objekts.

Script 5.9: Lesen des Attributs description eines Benutzerkontos

Seite 243 von 394


1Set objUser = _
2 GetObject("LDAP://cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com")
3Wscript.Echo objUser.Get("description")
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, erhalten Sie die folgende
Ausgabe:
HR employee
Reading an Attribute of a Group
Script 5.10 liest das Attribut description des Gruppenobjekts Atl-Users in der OU HR in der
Domäne na.fabrikam.com und zeigt dieses an. Hierzu geht das Script folgendermaßen vor:
1.Es verbindet sich mit dem Gruppenobjekt Atl-Users in der OU HR in der Domäne
na.fabrikam.com.
2.Es liest das Attribut description des Objekts.

Script 5.10: Lesen des Attributs description einer Gruppe

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.

Löschen von Active Directory-Objekten


Die letzte Aktion im Leben eines Objekts ist normalerweise das Löschen. Alle bisherigen
Scriptbeispiele haben erst die OU erstellt, dann den Benutzer und dann die Gruppe. Die
folgenden Scripte gehen nun anders herum vor. Erst wird die Gruppe gelöscht, dann der
Benutzer und erst dann die OU. Das liegt daran, dass Sie mit der Methode Delete keine OUs
löschen können, ohne erst die Objekte in der OU zu löschen (dies Objekte werden auch als
Endknotenobjekt bezeichnet).
Wenn Sie versuchen eine OU zu löschen, in der sich noch Endknotenobjekte (untergeordnete
Objekte) befinden, erhalten Sie die folgende Fehlermeldung:
C:\DeleteOu.vbs(2, 1) (null): Der Verzeichnisdienst kann den angeforderten
Vorgang
nur an einem Endknotenobjekt durchführen.

Seite 244 von 394


Die Fehlermeldung ist etwas verwirrend. Warum kann der Vorgang nur für ein
Endknotenobjekt durchgeführt werden? Wenn Objekte in er OU vorhanden sind, dann ist die
OU ein Containerobjekt. Sind jedoch keine Objekte mehr in der OU, dann ist die OU aus der
Perspektive des Scripts kein Container mehr, sondern ein Endknotenobjekt (ein Objekt, das
keine weiteren Objekte enthält). Nun ist die Fehlermeldung klarer.
Da in den folgenden Beispielen erst Benutzer und Gruppen entfernt werden, tritt der Fehler
hier nicht auf.
Das Löschen von Active Directory-Objekten wird über zwei Schritte durchgeführt:
1.Eine Verbindung mit dem Active Directory-Container aufbauen, in dem das Objekt
gespeichert ist.
2.Das Objekt löschen.

Eine Gruppe löschen


Script 5.11 löscht die Gruppe Atl-Users aus der OU HR in der Domäne na.fabrikam.com.
1.Es baut eine Verbindung mit dem OU-Container HR in der Domäne na.fabrikam.com auf.
In diesem Fall wird die OU als Container statt als Objekt behandelt - es soll ja ein Objekt in
einem Container gelöscht werden.
2.Es löscht die Gruppe Atl-Users aus der OU.

Script 5.11: Löschen einer Gruppe

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2objOU.Delete "group", "cn=Atl-Users"
Ein Benutzerkonto löschen
Script 5.12 löscht den Benutzer MyerKen aus der OU HR in der Domäne na.fabrikam.com.
1.Es baut eine Verbindung mit dem OU-Container HR in der Domäne na.fabrikam.com auf.
2.Es löscht den Benutzer MyerKen aus der OU.

Script 5.12: Löschen eines Benutzers

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2objOU.Delete "user", "cn=MyerKen"
Löschen einer OU
Script 5.12 löscht die OU HR in der Domäne na.fabrikam.com.
1.Es baut eine Verbindung mit dem OU-Objekt HR in der Domäne na.fabrikam.com auf.
Es löscht die OU.

Script 5.13: Löschen einer OU

1Set objDomain = GetObject("LDAP://dc=NA,dc=fabrikam,dc=com")


2objDomain.Delete "organizationalUnit", "ou=HR"
Die folgenden wichtigen Erkenntnisse können wir aus den Scripten dieses Abschnitts
gewinnen:
Seite 245 von 394

Sie führen alle die gleichen grundlegenden Schritte aus: eine Verbindung mit dem Active
Directory-Container aufbauen und ein Objekt löschen.

Sie verwenden alle die gleiche Methode (Delete) - egal, welche Klasse das zu löschende
Objekt hat.

Vergleich der primären Aufgaben eines ADSI-Scripts


Sie haben inzwischen die vier primären Aufgabenkategorien der Active Directory-
Administration kennen gelernt (Erstellen, Lesen, Ändern und Löschen). Die Beispielscripte
haben Ihnen gezeigt, wie konsistent die Durchführung dieser Aufgaben in ADSI-Scripten ist.
In Abbildung 5.1 sehen Sie noch einmal eine Zusammenfassung der Kategorien und der
erforderlichen Schritte.

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.

Seite 246 von 394



Mit der Methode Create wird ein Active Directory-Objekt erstellt.

Mit der Methode Delete wird ein Active Directory-Objekt gelöscht.

Mit der Methode Put wird ein Attribut eines Active Directory-Objekts geschrieben.

Mit der Methode Get wird ein Attribut eines Active Directory-Objekts gelesen.

Mit der Methode SetInfo wird ein neues oder geändertes Attribut eines Objekts an Active
Directory übertragen.

Die Parameter von Create, Delete, Put und Get sind immer die gleichen.

Das Erstellen von ADSI-Scripten


In den folgenden Abschnitten werden die Grundschritte der vorhergehenden Scriptbeispiele
genauer untersucht. Sie erhalten so ein besseres Verständnis darüber, wie Sie Ihre eigenen
ADSI-Scripte erstellen können.

Schritt 1: Eine Verbindung aufbauen


Der erste Schritt in den vorherigen Scripten war immer das Aufbauen einer Verbindung zu
einem Objekt. Wenn Sie ein Objekt erstellen oder löschen, müssen Sie eine Verbindung zu
dem Container aufbauen in dem sich das Objekt befindet. Wenn Sie ein Objekt
(beziehungsweise seine Attribute) lesen oder ändern möchten, müssen Sie eine Verbindung
direkt zu dem entsprechenden Objekt aufbauen.

Das Active Directory-Objekt für die Bindung auswählen


Wenn Sie eine Bindung aufbauen wollen, dann müssen Sie sich überlegen, welche Aufgabe
Sie durchführen wollen (Erstellen, Löschen, Lesen oder Ändern). Außerdem müssen Sie den
Typ kennen (Objekt oder Container), und wenn das Objekt ein Container ist, dann müssen Sie
gegebenenfalls prüfen, ob der Container leer ist. In Abbildung 5.2 sehen Sie ein
Flussdiagramm, das Ihnen bei diesem Vorgang hilft.

Seite 247 von 394


Abbildung 5.2: Überlegungen beim Aufbau einer Bindung
Die beiden folgenden Aufgaben, die ebenfalls über ein Script durchgeführt werden können,
sind im Flussdiagramm nicht enthalten:

Das Löschen eines Containers, der nicht leer ist.
Mit der Methode DeleteObject können Sie einen Container löschen, der nicht leer ist. Dies ist
jedoch möglicherweise gefährlich - daher sollten Sie hierbei sehr vorsichtig sein.

Verschieben von Objekten aus einem Container, bevor dieser gelöscht wird.
Weitere Informationen zu diesem Vorgang finden Sie im Abschnitt Verschieben und
Umbenennen von Objekten weiter unten in diesem Kapitel.

Eine Bindung durchführen


Um eine Bindung an ein Active Directory-Objekt zu erstellen, können Sie die VBScript-
Funktion GetObject verwenden. Als Parameter geben Sie den Prefix LDAP: gefolgt von zwei
Slash-Zeichen und dem Pfad des Active Directory-Objekts an. Die entsprechenden Zeilen in
unseren vier vorhergehenden Beispielscripten sahen so aus:

Set objDomain = GetObject("LDAP://dc=NA,dc=fabrikam,dc=com")
Baut eine Bindung zur Domäne na.fabrikam.com auf.

Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")
Baut eine Bindung zur OU HR in der Domäne na.fabrikam.com auf.

Set objUser = _

Seite 248 von 394


GetObject("LDAP://cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com")
Baut eine Bindung zum Benutzerobjekt MyerKen in der OU HR in der Domäne
na.fabrikam.com auf.

Set objGroup = _
GetObject("LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com")
Baut eine Bindung zum Gruppenobjekt Atl-Users in der OU HR der Domäne
na.fabrikam.com auf.
Der Parameter ADsPath
In der Terminologie von ADSI nennt sich der Prefix LDAP:, zusammen mit einem Pfad zu
einem Active Directory-Objekt ADsPath (Active Directory Service Path - Active Directory-
Dienst-Pfad - der Pfad zu einem Active Directory-Objekt). Bei diesem ADsPath - einem
Parameter der Funktion GetObject - handelt es sich um einen String. Er muss daher immer in
Anführungszeichen eingeschlossen werden.

Angeben des Providers


Der erste Teil von ADsPath gibt einen ADSI-Provider an. Über diesen Provider weiß das
ADSI-Script aus welcher Quelle die entsprechenden Daten stammen. Um mit Active
Directory oder einem anderen LDAP-Verzeichnis zu kommunizieren, verwenden Sie zum
Beispiel den Provider LDAP (Lightweight Directory Access Protocol) von ADSI (Adsldp.dll).
Um mit der lokalen SAM-Datenbank (Security Accounts Manager) zu kommunizieren (also
mit lokalen Konten, Gruppen, usw. zu arbeiten) verwenden Sie den Provider WinNT
(Adsnt.dll).

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.

Angeben des Verzeichnispfades des Objekts


Der zweite Teil von ADsPath gibt wie gesagt den Pfad zum Objekt wieder. ADSI unterstützt
mehrere Formate für diesen Objektpfad. In den vorhergehenden Beispielen wurde immer der
eindeutige Name (distinguished name - DN) des Objekts verwendet. Dies ist jedoch nur eine
Möglichkeit einen Objektpfad anzugeben. Weitere Möglichkeiten finden Sie im Abschnitt
Root Directory Service Entry weiter unten in diesem Kapitel
Jedes in Active Directory gespeicherte Objekt hat einen eindeutigen Namen (distinguished
name - DN). Stellen Sie sich den DN als LDAP-Version eines vollständigen
Dateisystempfades vor. Jede Datei hat einen vollständigen Pfad - dieser setzt sich aus dem
Gerät, einem oder mehreren Ordnernamen und dem Namen der Datei selbst zusammen.
Genauso ist es bei Active Directory -dieser vollständige Pfad eines Active Directory-Objekts
nennt sich DN.
So wie ein Dateipfad mehrere Ordner enthält, die jeweils durch ein Backslash getrennt sind,
so setzt sich auch der DN eines Active Directory-Objekts aus mehreren Teilen zusammen -

Seite 249 von 394


diese werden jeweils in der Form attribut=wert angegeben. Die einzelnen Teile werden durch
Kommata getrennt. Jeder Teil (attribut=wert) im DN eines Objekts steht für einen Container
in Active Directory.
Beim attribut handelt es sich um den Typ des DN-Teils (diese Typen sind in RFC 2247 und
RFC 2253 definiert). Der Type eines Benutzerkontos ist zum Beispiel CN - der Typ eine
Organisationseinheit ist OU.

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").

Tabelle 5.1: Objektklassen, Attribute und Werte


Objektklasse AttributtypWert
User CN MyerKen
organizationalUnitOU HR
domain DC NA
domain DC fabrikam
domain DC com
Die gesamte Pfadangabe eines DNs gibt die Position des Objekts im Bezug auf den Stamm
des Active Directory-Verzeichnisbaums an. Wenn Sie die einzelnen Teile des Pfades von
links nach rechts durchgehen, dann gelangen Sie vom Objekt selbst bis zum Stamm der
Active Directory-Hierarchie (Abbildung 5.3 verdeutlicht dies).

Abbildung 5.3: Eine Beispielhierarchie für einen DN


Das Benutzerobjekt MyerKen befindet sich in der OU HR in der Unterdomäne NA der
Domäne fabricam.com. Der gesamte Parameter ADsPath sieht daher für dieses
Benutzerobjekt so aus:
"LDAP://cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com"

Seite 250 von 394


Anmerkung: Der in Script 5.1 verwendete ADsPath-Parameter unterscheidet sich von den
restlichen Beispielen dieses Kapitels - er verwendet ein bestimmtes ADSI-Feature mit dem
Namen rootDSE. Weitere Informationen zu diesem Feature finden Sie im Abschnitt Root
Directory Service Entry weiter unten in diesem Kapitel.

Eine Objektreferenz auf ein Active Directory-Objekt erstellen


Befassen wir uns nun mit dem Teil, der in einer Bindungsanweisung links vom
Gleichheitszeichen steht - dem VBScript-Schlüsselwort Setgefolgt von einem
Variablennamen. In den Beispielscripten wurden zum Beispiel die Variablennamen
objDomain, objOU, objUser und objGroup verwendet.
Im Gegensatz zu einer Zuweisung eines Strings oder einer Zahl zu einer Variable müssen Sie
in diesem Fall das Schlüsselwort Set verwenden. Mit diesem Schlüsselwort weisen Sie der
Variablen eine Referenz auf ein Objekt zu (die Funktion GetObject liefert ein Objekt zurück).
Bei ADSI handelt es sich bei dem von GetObject zurückgegebenen Objekt um das in
ADsPath angegebene Objekt. Es wird jedoch nicht das Objekt selbst zurückgegeben, sondern
nur ein 'virtueller Verweis' auf das Objekt.

Schritt 2: Eine Aufgabe ausführen


Das Erstellen und Löschen von Objekten ist wirklich simpel. Nachdem das Script eine
Bindung zum entsprechenden Container aufgebaut hat, können Sie das Objekt in diesem
Container erstellen. Auch das Lesen und Schreiben von Objektattributen ist sehr einfach. Sie
bauen eine Bindung zum entsprechenden Objekt auf und lesen oder schreiben das Attribut.
Wenn Sie die Methoden Create, Put (Ändern) oder Get (Lesen) verwenden, dann bearbeiten
Sie jedoch nicht das Active Directory-Objekt selbst. Stattdessen werden die entsprechenden
Vorgänge lokal in einem bestimmten Speicherbereich (dem so genannten local property
cache - lokaler Eigenschafts-Zwischenspeicher) durchgeführt. Das oder die Attribute eines
Active Directory-Objekts werden in diesem lokalen Zwischenspeicher gespeichert. Alle
Änderungen am Objekt, die Sie vornehmen, werden in diesem lokalen Zwischenspeicher
vorgenommen. Um die Änderungen für das eigentliche Active Directory-Objekt zu
übernehmen, müssen Sie erst den lokalen Zwischenspeicher an Active Directory übermitteln -
die machen Sie mit der Methode SetInfo.
Eine Methode, die nicht auf diese Art arbeitet, ist Delete. Sie führt ihre Aktion (das Löschen)
direkt in Active Directory aus (es gibt noch einige andere Methoden, die ebenfalls direkt in
Active Directory arbeiten).

Scriptcode, um die eigentliche Aufgabe durchzuführen


Wenn Sie sich die Beispielscripte anschauen, dann bemerken Sie, dass für die
durchzuführenden Aufgaben jeweils der bei der Bindung erstelle Variablennamen mit einem
Punkt und dem Namen der Methode verwendet wird:

objVariableName.Create

objVariableName.Get

objVariableName.Put

Seite 251 von 394



objVariableName.Delete
Die Methoden Create und Delete sind leicht zu merken, da ihr Name ihrer Aktion entspricht.
Mit Get können Sie Attribute lesen und mit Put können Sie Attribute schreiben
(beziehungsweise ändern).

Die Parameter der einzelnen Methoden


Parameter von Create
Die Methode Create benötigt zwei Parameter: den Klassennamen und den RDN(relative
distinguished name - relativer eindeutiger Name) des zu erstellenden Objekts. Ein RDN ist
Teil der DN eines Objekts. Der RDN muss im Container des Objekts eindeutig sein - er setzt
sich aus einem Attribut und dem zugewiesenen Wert zusammen.
Sehen wir uns noch einmal die vorherigen Beispielscripte an:

Set objOU = objDomain.Create("organizationalUnit", "ou=HR")
Erstellt eine OU
Der Klassenname ist organizationalUnit,das Attribut ist ou und der Wert ist HR. Daher lautet
der RDN ou=HR.

Set objUser = objOU.Create("user", "cn=MyerKen")
Erstellt ein Benutzerkonto
Der Klassenname ist user, das Attribut ist cn und der Wert ist MyerKen. Daher lautet der
RDN cn=MyerKen.

Set objGroup = objOU.Create("group", "cn=Atl-Users")
Erstellt eine Gruppe
Der Klassenname lautet group, das Attribut ist cn und der Wert ist Atl-Users. Daher lautet
der RDN cn=Atl-Users.
Auch für die Methode Create benötigen Sie das Schlüsselwort Set. Mit diesem weisen Sie die
von Create zurückgegebene Objektreferenz zu einer Variablen zu. Denken Sie daran, dass es
sich nicht um eine Referenz auf das tatsächliche Objekt, sondern um eine Referenz auf das
Objekt im Zwischenspeicher handelt. Nachdem Sie die erforderlichen Aufgaben am Objekt
durchgeführt haben, müssen Sie das Objekt aus dem Zwischenspeicher an Active Directory
übermitteln. Abbildung 5.4 zeigt noch einmal die einzelnen Teile der Aufrufe von Create in
den vorherigen Scripten:

Seite 252 von 394


Abbildung 5.4: Vergleich der unterschiedlichen Aufrufe der Methode Create
Parametern von Put
Die Methode Put benötigt ebenfalls zwei Parameter: den Namen des Attributes und den Wert,
den Sie diesem Attribut zuweisen möchten.
ADSI erwartet einen bestimmten Typ von Attributnamen - den lDAPDisplayName. Der
Zugriff auf Attribute ist über einige unterschiedliche Namen möglich. In ADSI-Scripten
sollten Sie jedoch den lDAPDisplayName verwenden.
Sehen wir uns erneut die vorherigen Beispielscripte an:

objOU.Put "description", "Human Resources"
Schreibt ein Attribut einer OU
Der lDAPDisplayName des zu bearbeitenden Attributs ist description. Dem Attribut wird der
Wert Human Resources zugewiesen.

objUser.Put "description", "HR employee"
Schreibt ein Attribut eines Benutzerkontos
Der lDAPDisplayName des zu bearbeitenden Attributs ist description. Dem Attribut wird der
Wert HR employee zugewiesen.

objOU.Put "description", "Atlanta users"
Schreibt ein Attribut einer Gruppe
Der lDAPDisplayName des zu bearbeitenden Attributs ist description. Dem Attribut wird der
Wert Atlanta users zugewiesen.
Auch beim Erstellen von Objekten werden möglicherweise Attribute geschrieben. Nämlich
dann, wenn das Objekt verpflichtende Attribute verwendet - diesen müssen Sie vor dem
Übertragen des Objekts an Active Directory einen Wert zuweisen.

Seite 253 von 394


Die folgenden Zeilen aus den vorherigen Beispielscripten schreiben verpflichtende Attribute:

objUser.Put "sAMAccountName", "myerken"
Schreibt das verpflichtende Attribut (sAMAccountName) eines Benutzerkontos.

objUser.Put "sAMAccountName", "atl-users"
Schreibt das verpflichtende Attribut (sAMAccountName) einer Gruppe.
Verpflichtende Attribute werden durch Active Directory definiert. Weitere Informationen zu
diesem Thema erhalten Sie im Abschnitt Die Active Directory-Architektur weiter unten in
diesem Kapitel.
Parameter von Get
Die Methode Get benötigt nur einen Parameter: den lDAPDisplayName des Attributes, das
Sie lesen möchten. In Zeile 2 von Script 5.8 und Zeile 3 von Script 5.9 und Script 5.10 wird
das Attribut mit dem Namen description gelesen:

Wscript.Echo objOU.Get("description")
Liest das Attribut description einer OU und zeigt es an.

Wscript.Echo objUser.Get("description")
Liest das Attribut description eines Benutzerkontos und zeigt es an.

Wscript.Echo objGroup.Get("description")
Liest das Attribut description einer Gruppe und zeigt es an.
Parameter von Delete
Wie die Methode Create benötigt auch Delete zwei Parameter: Den Typ des zu löschenden
Objekts und den RDN des Objekts.

objOU.Delete "group", "cn=Atl-Users"
Löscht eine Gruppe
Der Klassenname ist group. Der RDN des Objekts ist cn=Atl-Users.

objOU.Delete "user", "cn=MyerKen"
Löscht ein Benutzerkonto
Der Klassenname ist user. Der RDN des Objekts ist cn=MyerKen.

objDomain.Delete "organizationalUnit", "ou=HR"
Löscht eine OU
Der Klassenname ist organizationalUnit. Der RDN des Objekts ist cn=HR.

Schritt 3: Übermitteln an Active Directory


Nach dem Erstellen oder Ändern eines Objekts müssen Sie die vorgenommenen Änderungen
an Active Directory übermitteln - dies machen Sie über die Methode SetInfo. Wenn Sie das
Übermitteln vergessen, dann wird Ihr ADSI-Script trotzdem korrekt ausgeführt- nur die
Änderungen ihres Scripts werden nie in Active Directory auftauchen. Das Übermitteln an
Active Directory können Sie sich so vorstellen, wie wenn Sie ein Word-Dokument nach dem
Erstellen speichern. Weitere Informationen zum lokalen Zwischenspeicher finden Sie im
Abschnitt Schritt 2: Durchführen von Aufgaben weiter oben in diesem Kapitel.

Seite 254 von 394


Vielleicht ist Ihnen aufgefallen, dass die Methode SetInfo im Abschnitt Lesen der Attribute
von Active Directory-Objekten nicht verwendet wurde. Das liegt daran, dass in diesen
Scripten ja nur Informationen aus Active Directory ausgelesen werden - das Objekt wird nicht
verändert. Daher ist es auch nicht nötig Informationen aus dem lokalen Zwischenspeicher an
Active Directory zu übermitteln.
Auch bei der Verwendung der Methode Delete benötigen Sie SetInfo nicht. Das Löschen von
Objekten wird nicht im Zwischenspeicher, sondern direkt in Active Directory durchgeführt.

Mehrere Aufgaben über ein Script durchführen


In vielen produktiven Scripten gibt es eine Menge Code, der nicht direkt etwas mit ADSI zu
tun hat - dies ist in den Scripten dieses Buches nicht so. So wird es für Sie einfacher die
Scripte nachzuvollziehen. Das Script ListDCs.vbs aus dem Resource Kit ist zum Beispiel 454
Zeilen lang. Von diesen 454 Zeilen haben 400 nichts mit ADSI zu zun. Warum sind sie also
da? Sie sind da, weil ListDCs.vbs als Mehrzweckwerkzeug entwickelt wurde - so ähnlich wie
ein Kommandozeilenbefehl. Das Script enthält zum Beispiel Code zur Verarbeitung von
Argumenten, zur Formatierung von Ausgaben und zur Handhabung von Fehlern. Auch wenn
dieser Code wichtig ist, so hat er doch nichts mit ADSI zu tun. Wir vermeiden es in diesem
Kapitel solchen Code zu verwenden - so können Sie sich auf den Scriptcode konzentrieren,
der für die Arbeit mit ADSI notwendig ist.
Um ein Script zu erstellen, das mehrere Attribute eines Active Directory-Objekts liest und
schreibt, können Sie die vorherigen Beispielscripte kombinieren:
1.Erstellen Sie eine Bindung an ein Objekt - Sie müssen den Pfad des Objekts kennen.
2.Attribute schreiben oder ändern - hierzu müssen Sie die Eigenschaften und Namen der
entsprechenden Attribute kennen. Außerdem müssen Sie die geänderten Attribute danach an
Active Directory übermitteln.
3.Attribute lesen - hierzu benötigen Sie die gleichen Informationen wie zum Schreiben von
Attributen.
Vorbereitende Schritte
1.Starten Sie Notepad.exe und speichern Sie eine Datei mit dem Namen ModifyUser.vbs im
Ordner C:\scripts.
Sie können die Scripte dieses Abschnitts dann jeweils in die Datei einfügen und diese so
ausführen.
2.Prüfen Sie, ob Sie das Benutzerkonto MyerKen schon in Active Directory erstellt haben.
Wenn nicht, dann erstellen Sie es jetzt.

Binden an ein Benutzerobjekt


Über einen der folgenden Schritte können Sie in der ersten Zeile Ihres Testscripts
ModifyUser.vbs eine Bindung an das Benutzerobjekt aufbauen:
1.Wenn sich das Kontoobjekt in der OU HR derDomäne na.fabrikam.com befindet,
verwenden Sie die folgenden Codezeile:
Set objUser = _
GetObject("LDAP://cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com")

Seite 255 von 394


2.Wenn Sie eine OU mit einem anderen Namen verwenden und keine Domäne mit dem
Namen na.fabrikam.com haben, dann ändern Sie den DN auf den Active Directory-
Container, in dem sich das Benutzerkonto befindet. Wenn Ihre Domäne zum Beispiel
contoso.com heißt und der Name der OU Test lautet, dann sollten Sie die Zeile
folgendermaßen umändern:
Set objUser = _
GetObject("LDAP://cn=MyerKen,ou=Test,dc=contoso,dc=com")
3.Wenn Sie das Benutzerkonto im Container User der Domäne erstellt haben, mit der Sie
momentan verbunden sind, dann verwenden Sie den folgenden Code:
Set objRootDSE = GetObject("LDAP://rootDSE")
Set objUser = GetObject("LDAP://cn=MyerKen,cn=Users," & _
objRootDSE.Get("defaultNamingContext"))

Attribute schreiben oder ändern


Als Nächstes benötigen Sie die lDAPDisplayNames der Attribute, die Sie schreiben oder
ändern möchten. In Abbildung 5.5 sehen Sie die allgemeinen Attribute eines Benutzerkontos
und den entsprechenden lDAPDisplayName jedes Attributs.

Abbildung 5.5: Registerkarte Allgemein des Benutzerkontos MyerKen


Wie Sie sehen, stimmt der jeweilige lDAPDisplayName nicht mit den Feldbezeichnungen im
Eigenschaftsfenster überein. Sie können dieses also nicht verwenden, um die Attributnamen
in Erfahrung zu bringen.

Seite 256 von 394


Es gibt noch zwei andere Methoden, über die Sie auf Attribute von Active Directory-Objekten
zugreifen können - der Weg über den lDAPDisplayName ist jedoch der konsistenteste Ansatz.
Er ist auch der einzige Weg, über den Sie Attribute mit der Methode Put schreiben können.
Um den gesamten gezeigten Vorgang so einfach wie möglich zu halten, verändert das Script
keine Attribute, die mehrere Werte enthalten (Multiwert-Attribute). Dies wären zum Beispiel
die Attribute otherTelephone und url. Weitere Informationen zu Multiwert-Attributen erhalten
Sie im Abschnitt Administration von Multiwert-Attributen weiter unten in diesem Kapitel.
Der Scriptcode zum Schreiben oder Ändern der Attribute eines Benutzerobjekts sieht
folgendermaßen aus:
objUser.Put "givenName", "Ken"
objUser.Put "initials", "E."
objUser.Put "sn", "Myer"
objUser.Put "displayName", "Myer, Ken"
objUser.Put "description", "HR employee"
objUser.Put "physicalDeliveryOfficeName", "Room 4358"
objUser.Put "telephoneNumber", "(425) 555-0100"
objUser.Put "mail", "myerken@fabrikam.com"
objUser.Put "wWWHomePage", "http://www.fabrikam.com"
Fügen Sie Ihrem Script diese Zeilen direkt unter der Zeile zum Binden des Objekts hinzu.
Als letztes müssen Sie die Änderungen noch an Active Directory übermitteln. Hierzu fügen
Sie die folgende Zeile hinzu:
objUser.SetInfo
Lesen und Anzeigen der geänderten Attribute
Nachdem Ihr Script das Objekt verändert hat, können Sie die entsprechenden Attribute
anzeigen lassen.
Den entsprechenden Scriptcode sehen Sie unten. Er liest die einzelnen Attribute in Variablen
ein.
strGivenName = objUser.Get("givenName")
strInitials = objUser.Get("initials")
strSn = objUser.Get("sn")
strDisplayName = objUser.Get("displayName")
strPhysicalDeliveryOfficeName = _
objUser.Get("physicalDeliveryOfficeName")
strTelephoneNumber = objUser.Get("telephoneNumber")
strMail = objUser.Get("mail")
strWwwHomePage = objUser.Get("wWWHomePage")
Nun müssen Sie die Werte in den Variablen nur noch anzeigen lassen:
Wscript.Echo "givenName: " & strGivenName
Wscript.Echo "initials: " & strInitials
Wscript.Echo "sn: " & strSn
Wscript.Echo "displayName: " & strDisplayName
Wscript.Echo "physicalDeliveryOfficeName: " & _
strPhysicalDeliveryOfficeName
Wscript.Echo "telephoneNumber: " & strTelephoneNumber
Wscript.Echo "mail: " & strMail

Fortgeschrittene ADSI-Scripting-Techniken

Seite 257 von 394


Neben den grundlegenden Aufgaben (Erstellen, Ändern, Lesen, Löschen) gibt es noch einige
andere Administrationsaufgaben. Einige dieser Aufgaben sind zum Beispiel:

Administration von Multiwert-Attributen

Kopieren, Verschieben und Umbenennen von Objekten

Cachen von Daten

Suchen

Auflisten der Active Directory-Objekte in Containern

Verwenden des Root Directory Service Entry.

Administration von Multiwert-Attributen


Die bisherigen Scripte dieses Kapitels haben alle nur Attribute mit Einzelwerten bearbeitet
oder gelesen. Multiwert-Attribute enthalten mehrere Werte (wer hätte das gedacht!) - zum
Beispiel die Bridgehead-Server der Domäne, die Mitglieder einer Gruppe oder die
alternativen Telefonnummern eines Benutzerkontos.

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.

Ändern von Multiwert-Attributen


Wenn ein Attribut mehrere Werte enthalten kann, dann gibt es mehrere Möglichkeiten
Änderungen vorzunehmen:

Alle Einträge löschen - wennSie alle Einträge aus einem Attribut entfernen, entfernen Sie
damit das ganze Attribut. Ein Attribut ohne Eintrag ist für ein ADSI-Script nicht länger Teil
des Objekts.

Alle Einträge aktualisieren - alle vorhandenen Einträge werden durch neue ersetzt.

Einen Eintrag hinzufügen - die vorhandenen Einträge bleiben bestehen, ein neuer Eintrag
kommt hinzu.

Einen Eintrag löschen
Egal welche dieser Aktionen Sie ausführen möchten - Sie verwenden immer die Methode
PutEx. Der erste Parameter der Methode ist die Art der Aktualisierung, die Sie vornehmen
möchten. Als zweites Argument geben Sie das zu ändernde Attribut an und als drittes
Argument die Werte für das Attribut. In Tabelle 5.2 sehen Sie alle Argumente der Methode
PutEx.

Tabelle 5.2: Argumente der Methode PutEx

Seite 258 von 394


Argument Typ ErforderlichStandardwertBeschreibung
Control Integer Ja Keiner Mit dem Wert 1 werden alle Einträge gelöscht.
Code (long) Mit 2 werden die Einträge aktualisiert, mit 3
werden ein oder mehrere Einträge angehängt und
mit 4 werden ein oder mehrere Einträge gelöscht.
Attribute String Ja Keiner Der lDAPDisplayName des zu ändernden
Attributs.
Value Variant Ja Keiner Jeder Wert muss in Anführungszeichen
(array) eingeschlossen sein. Mehrere Werte müssen
durch Kommata getrennt werden. Um das
Attribut zu löschen, setzen Sie den Wert auf 0.

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).

Seite 259 von 394


Wenn Sie versuchen einen nicht vorhandenen Eintrag über PutEx zu löschen, kommt es zu
keiner Fehlermeldung. Der folgende Aufruf von SetInfo wird dann jedoch einen Fehler
generieren.
Sie müssen eine Änderung an einem Attribut erst mit der Methode SetInfo übertragen, bevor
Sie eine weitere Änderung an demselben Attribut vornehmen. Sehen Sie sich die folgenden
drei Scriptzeilen an:
objUser.PutEx ADS_PROPERTY_DELETE, "otherTelephone", Array("555-1080")
objUser.PutEx ADS_PROPERTY_APPEND, "otherTelephone", Array("555-1010")
objUser.SetInfo
Die Telefonnummer 555-1010 wird zwar zum Attribut otherTelephone hinzugefügt, wenn Sie
SetInfo ausführen, aber die Nummer 555-1080 wird nicht gelöscht. Um beide Aktionen
durchzuführen, müssen Sie den folgenden Scriptcode verwenden:
objUser.PutEx ADS_PROPERTY_DELETE, "otherTelephone", Array("555-1080")
objUser.SetInfo
objUser.PutEx ADS_PROPERTY_APPEND, "otherTelephone", Array("555-1010")
objUser.SetInfo
Ein weiterer wichtiger Punkt bei der Verwendung von PutEx ist, dass die Einträge in einem
Multiwert-Attribut nicht in einer bestimmten Reihenfolge gespeichert werden können. Ihr
Script sollte sich also nicht auf eine bestimmte Reihenfolge der Speicherung verlassen.
Löschen von Multiwert- und Einzelwert-Attributen über die Methode PutEx
Mit PutEx können Sie Multiwert- und Einzelwert-Attribute löschen. Dies ist besonders im
Zusammenhang mit Einzelwert-Attributen wichtig, da die Methode Put ein Attribut nicht
vollständig löschen kann - Sie können es mit ihr nur auf den Wert NULL oder "" setzen.

Aktualisieren eines Multiwert-Attributs einer Gruppe


Script 5.14 ändert das Attribut member der Gruppe Atl-Users so, dass es zwei Mitglieder
enthält. Hierzu führt das Script die folgenden Schritte durch:
1.Es definiert die Konstante ADS_PROPERTY_UPDATE mit dem Wert 2. Diese Konstante
wird in den Zeilen 5-9 für die Methode PutEx verwendet.
Der Wert 2 bedeutet, dass die Einträge eines Multiwert-Attributs aktualisiert werden.
2.Es baut eine Bindung zur Gruppe Atl-Users in der OU HR der Domäne na.fabrikam.com
auf.
3.Es aktualisiert das Attribut member des Gruppeobjekts mit den DNs von MyerKen und
LewJudy. Da PutEx mit Multiwert-Attributen arbeitet, müssen diese beiden DNs als Array
übergeben werden.
Beachten Sie, dass sich das Benutzerkonto MyerKen in der OU HR und das Benutzerkonto
LewJudy in der OU Sales befindet - beide OUs befinden sich in der Domäne
na.fabrikam.com.
4.Es überträgt die Änderungen an der Gruppe an Active Directory.
Da PutEx mit dem Parameter 2 (aktualisieren) aufgerufen wurde, werden die vorhandenen
Gruppenmitglieder der Gruppe Atl-Users durch die neuen Mitglieder ersetzt.

Script 5.14: Aktualisieren des Attributs member einer Gruppe

1Const ADS_PROPERTY_UPDATE = 2
2Set objGroup = GetObject _

Seite 260 von 394


3 ("LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com")
4
5objGroup.PutEx ADS_PROPERTY_UPDATE, _
6 "member", Array("cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com", _
7 "cn=LewJudy,ou=Sales,dc=NA,dc=fabrikam,dc=com")
8
9objGroup.SetInfo
Einen Einträg zu einem Multiwert-Attribut einer Gruppe hinzufügen
Vorausgesetzt, das Script 5.14 ausgeführt wurde, hängt Script 5.15 einen Eintrag an das
Attribut member an, so das die Gruppe nun drei Mitglieder hat. Hierzu führt das Script die
folgenden Schritte aus:
1.Es definiert die Konstante ADS_PROPERTY_APPEND auf den Wert 3 (anhängen).
2.Es baut eine Bindung zur Gruppe Atl-Users in der OU HR der Domäne na.fabrikam.com
auf.
3.Es hängt einen Eintrag an das Attribut member an. Hierzu verwendet es die Konstante
ADS_PROPERTY_APPEND und den DN des Benutzerobjekts YoungRob.
Das Benutzerobjekt YoungRob befindet sich in der OU R&D der Domäne na.fabrikam.com.
4.Es übermittelt die Änderung an Active Directory.
Da der Eintrag nur angehängt wurde, bleiben alle bisherigen Einträge im Attribut members
der Gruppe ebenfalls erhalten.

Script 5.15: Anhängen eines Eintrags im Attribut member einer Gruppe

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

Seite 261 von 394


1Const ADS_PROPERTY_DELETE = 4
2Set objGroup = GetObject _
3 ("LDAP://cn=Atl-Users,OU=HR,dc=NA,dc=fabrikam,dc=com")
4
5objGroup.PutEx ADS_PROPERTY_DELETE, _
6 "member", Array("cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com")
7
8objGroup.SetInfo
Löschen eines Multiwert-Attributs einer Gruppe
Script 5.17 löscht das Attribut member der Gruppe Atl-Users. Hierzu geht das Script
folgendermaßen vor:
1.Es definiert die Konstante ADS_PROPERTY_CLEAR 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 das Attribut. indem es alle Einträge entfernt. Hierzu verwendet es die Konstante
ADS_PROPERTY_CLEAR und den Wert 0.
4.Es übermittelt die Änderung an Active Directory.

Script 5.17: Löschen des Attributs 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

Seite 262 von 394


1 Const ADS_PROPERTY_UPDATE = 2
2 Set objGroup = GetObject _
3 ("LDAP://cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com")
4
5 objGroup.PutEx ADS_PROPERTY_UPDATE, _
6 "url", Array("http://www.microsoft.com", _
7 "http://www.fabrikam.com/na","http://www.contoso.com")
8
9 objGroup.PutEx ADS_PROPERTY_UPDATE, _
10 "otherTelephone", Array("555-0180", "555-0182", "555-0183")
11
12objGroup.SetInfo

Lesen von Multiwert-Attributen


Da ein Multiwert-Attribut mehr als einen Eintrag haben kann, müssen Sie die Methode GetEx
zum Lesen der Einträge verwenden. Die Einträge werden als Array vom Typ Variant
zurückgeben. Der Datentyp Variant kann jede beliebige Art von Daten enthalten.

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.

Lesen eines Multiwert-Attributs einer Gruppe


Script 5.19 liest die Elemente des Multiwert-Attributs member der Gruppe Atl-Users aus und
zeigt diese an. Bevor Sie das Script ausführen, sollten Sie noch einmal Script 5.14 ausführen
(um sicherzustellen, dass die Gruppe auch Mitglieder hat). Das Script geht folgendermaßen
vor:
1.Es baut eine Bindung mit dem Gruppenobjekt Atl-Users in der OU HR der Domäne
na.fabrikam.com auf.
2.Es verwendet eine For-Each-Schleife, um die Elemente des Attributs zu lesen und
auszugeben.

Script 5.19: Auslesen des Attributs member einer Gruppe

1Set objGroup = GetObject _


2 ("LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com")
3
4For Each Member in objGroup.GetEx("member")

Seite 263 von 394


5 Wscript.Echo Member
6Next
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, sollte es die folgenden
Informationen ausgeben:
CN=LewJudy,OU=Sales,dc=NA,DC=fabrikam,DC=com
CN=MyerKen,OU=HR,dc=NA,DC=fabrikam,DC=com
Lesen von Multiwert-Attributen eines Benutzerkontos
Script 5.20 liest die Einträge url und otherTelephone des Benutzerkontos MyerKen.
1.Es baut eine Bindung zum Benutzerkonto MyerKen in der OU HR der Domäne
na.fabrikam.com auf.
2.Es verwendet eine For-Each-Schleife, um alle Elemente des Attributs url auszugeben.
3.Es verwendet eine weitere Schleife, um alle Elemente des Attributs otherTelephone
auszugeben.

Script 5.20: Auslesen der Attribute url und otherTelephone eines Benutzerkontos

1 Set objGroup = GetObject _


2 ("LDAP://cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com")
3
4 For Each url in objGroup.GetEx("url")
5 Wscript.Echo url
6 Next
7
8 For Each otherTelephone in objGroup.GetEx("otherTelephone")
9 Wscript.Echo otherTelephone
10Next
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, erhalten Sie die folgende
Ausgabe:
http://www.contoso.com
http://www.fabrikam.com/na
http://www.microsoft.com
555-0183
555-0182
555-0180
Die folgenden wichtigen Erkenntnisse können wir aus den Scripten dieses Abschnittes
gewinnen:

Sie führen alle die gleichen grundlegenden Schritte aus: Aufbau einer Bindung und
Ausgeben der Elemente über die For-Each-Schleife.

Sie verwenden alle die gleiche Methode (GetEx) - egal um was für ein Objekt es sich
handelt.

Das Cachen von Daten


Bis jetzt haben Sie relativ wenig über den lokalen Zwischenspeicher (Cache) erfahren, in dem
ADSI die Eigenschaften hinterlegt, beziehungsweise ändert. Sie wissen, dass die Methoden
Get und GetEx Attribute lesen. Beide Methoden verwenden in Hintergrund jedoch die
Methode GetInfo um die Attributwerte aus Active Directory in den lokalen Zwischenspeicher

Seite 264 von 394


zu laden. Auch Sie können die Methode GetInfo (beziehungsweise GetInfoEx) verwenden - so
können Sie steuern, welche Werte sich im Zwischenspeicher befinden. Weitere Informationen
über den Zwischenspeicher finden Sie im Abschnitt Schritt 2: Ausführen von Aufgaben dieses
Kapitels. Wenn Sie verstehen, wie der lokale Zwischenspeicher arbeitet, wird dies verhindern,
dass Sie versehentlich falsche Attributwerte auslesen.
Wie die Methode Get Attributwerte abfragt
Get fragt Attribute aus dem lokalen Zwischenspeicher entweder als String oder als Variant-
Array ab - abhängig vom Typ des Attributs und seinen Inhalten:

Einzelwert-Attribute - Get gibt einen String zurück.

Multiwert-Attribut mit einem Eintrag -Get gibt einen String zurück.

Multiwert-Attribut mit mehreren Einträgen -Get gibt einen Variant-Array zurück.

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.

Seite 265 von 394


Die Methode GetInfo explizit aufrufen
Sie können den lokalen Zwischenspeicher über die Methode GetInfo explizit neu laden oder
aktualisieren. Wenn Sie die Methode aufrufen, lädt sie alle Attribute (außer den operativen
Attributen) in den Zwischenspeicher. Sie sollten die Methode selbst aufrufen, wenn Sie sicher
sein wollen, dass im Zwischenspeicher die aktuellsten Werte vorhanden sind.
Die Syntax der Methode GetInfo sieht folgendermaßen aus:
object.GetInfo
Script 5.21 lädt die meisten Attribute des Gruppenobjekts Atl-Users in den lokalen
Zwischenspeicher.
1.Es baut eine Bindung an die Gruppe Atl-Users in der OU HR der Domäne na.fabrikam.com
auf.
2.Es verwendet die Methode GetInfo, um die Attribute des Gruppenobjekts in den lokalen
Zwischenspeicher zu laden.

Script 5.21: Expliziter Aufruf von GetInfo

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.

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2objOU.Put "description", "Human Resources"
3objOU.SetInfo
Sehen Sie sich im Gegensatz dazu das folgende Script an:

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2objOU.Put "description", "Human Resources"
3objOU.GetInfo
4objOU.SetInfo
In Zeile 2 wird weiterhin der Wert Human Resources in das Attribut description geschrieben.
In Zeile 3 wird dann jedoch der lokale Zwischenspeicher explizit neu geladen - daher wird der
Wert des Attributs überschrieben (wenn die Methode GetInfo von Get oder GetEx aufgerufen
wird, ist dies nicht weiter schlimm - hier wird der Wert nur dann geladen, wenn er im
Zwischenspeicher noch nicht vorhanden ist).

Die Methode GetInfoEx


Statt alle Attribute neu in den Zwischenspeicher zu laden, können Sie sich auf die
gewünschten Attribute beschränken - hierzu verwenden Sie die Methode GetInfoEx. Über
diese Methode können Sie übrigens auch die operativen Attribute abfragen. Auch wenn Sie

Seite 266 von 394


die Last auf dem Domänencontroller gering halten möchten, dann ist GetInfoEx hierzu ideal
geeignet.
Die Syntax der Methode sieht folgendermaßen aus:
object.GetInfoEx Attributes, 0
Der Parameter Attributes ist ein Array mit dem lDAPDisplayName der Attribute, die Sie neu
laden möchten. Der zweite Parameter (0) ist reserviert. Er muss bei jedem Aufruf der
Methode GetInfoEx angegeben werden.
Um die Attribute an die Methode GetInfoEx zu übergeben, erstellen Sie einen Array aus den
entsprechenden lDAPDisplayName-Werten dieser Attribute. Script 5.22 lädt auf diese Weise
zwei Attribute neu: description und dnsHostName.
1.Es baut eine Bindung zum Computerobjekt SEA-SQL-01 im Container Computers der
Domäne na.fabrikam.com auf.
2.Es initialisiert eine Variable mit dem Namen arrAttributes mit einem Array mit den
lDAPDisplayName-Werten der beiden Attribute (description und dnsHostName).
3.Es verwendet die Methode GetInfoEx, um explizit die beiden Attribute neu zu laden.

Script 5.22: Attribute über GetInfoEx neu laden

1Set objComputer = GetObject _


2 ("LDAP://cn=SEA-SQL-01,cn=Computers,dc=NA,dc=fabrikam,dc=com")
3arrAttributes = Array("description", "dnsHostName")
4objComputer.GetInfoEx arrAttributes, 0
Wie bei der Methode GetInfo müssen Sie auch bei der Methode GetInfoEx vorsichtig sein,
wenn Sie Attribute ändern. Vergessen Sie nicht die geänderten Attribute über SetInfo an
Active Directory zu übermitteln, bevor Sie sie neu laden. Ansonsten gehen die Änderungen
verloren.
In den Zeilen 3 und 4 des folgenden Scripts werden zum Beispiel die Werte der Attribute
description und dnsHostName im lokalen Zwischenspeicher geändert. Wenn die gleichen
Attribute in Zeile 7 über GetInfoEx neu geladen werden, sind die geänderten Werte verloren.
In Zeile 9 werden so mit SetInfo die alten (neu geladenen) Werte zurück an Active Directory
übermittelt.

1Set objComputer = GetObject _


2 ("LDAP://cn=SEA-SQL-01,cn=Computers,dc=NA,dc=fabrikam,dc=com")
3objComputer.Put "description", "SQL Computer 1"
4objComputer.Put "dnsHostName", "sea-sql-01.na.fabrikam.com"
5
6arrAttributes = Array("description", "dnsHostName")
7objComputer.GetInfoEx arrAttributes, 0
8objComputer.SetInfo
Das Problem umgehen Sie, wenn Sie die Zeile 8 (den Aufruf von SetInfo) in Zeile 5
verschieben.

Seite 267 von 394


Kopieren, Verschieben und Umbenennen von Objekten

Kopieren von Objekten


Um ein Objekt zu kopieren, benötigen Sie zuerst eine Quelle [aus der?] die Sie kopieren
können. Außerdem müssen Sie festlegen, welche Attribute des Objekts Sie kopieren möchten.
Um ein Objekt zu kopieren, kombinieren Sie einfach mehrere Aufgaben, die Sie bereits weiter
oben in diesem Kapitel kennen gelernt haben:
1.Erstellen Sie als erstes das Zielobjekt.
Weitere Informationen hierzu finden Sie im Abschnitt Erstellen von Active Directory-
Objekten weiter oben in diesem Kapitel.
2.Lesen Sie die Attribute des Quellobjekts aus, die auf das Zielobjekt kopiert werden sollen.
Weitere Informationen hierzu finden Sie in den Abschnitten Lesen von Attributen von Active
Directory-Objekten und Lesen von Multiwert-Attributen weiter oben in diesem Kapitel.
3.Schreiben Sie die Attributwerte in das Zielobjekt.
Weitere Informationen finden Sie in den Abschnitten Ändern eines Active Directory-Objekts
und Ändern von Multiwert-Attributen weiter oben in diesem Kapitel.
Die Scripte in diesem Abschnitt zeigen Ihnen, wie Sie ein Objekt kopieren können. Das erste
Beispiel kopiert zum Beispiel ein Computerobjekt.

Kopieren eines Computerobjekts


Script 5.23 kopiert ausgewählte Attribute eines Computerobjekts mit dem Namen SEA-PM-01
in ein neues Computerobjekt mit dem Namen SEA-SQL-01. Das Computerobjekt, dass als
Vorlage verwendet wird (SEA-PM-01) befindet sich im Container Computers der Domäne
na.fabrikam.com. Das neue Computerobjekt wird ebenfalls im Container Computers erstellt.
1.Das Script baut eine Bindung auf den Container Computers der Domäne na.fabrikam.com
auf.
Achten Sie darauf, dass der Container Computers den Typ CN hat (Außer dem Container
Domain Controllers haben alle Container direkt unter der Domäne das Attribut CN).
2.Es erstellt ein Computerobjekt mit den Namen sea-sql-01.
3.Es setzt das verpflichtende Attribut sAMAccountName des neuen Objekts auf den Wert sea-
sql-01.
4.Es überträgt das neue Computerobjekt an Active Directory.
Hiermit ist das neue Computerobjekt fertig.
5.Das Script baut eine Bindung auf das Computerobjekt SEA-PM-01 in dem Container
Computers der Domäne na.fabrikam.com auf.
Dieses Computerobjekt dient als Vorlage des Kopiervorgangs auf das neue Computerobjekt.
6.Es erstellt einen Array mit dem Namen arrAttributes, das die lDAPDisplayNames der
optionalen Attribute enthält, die auf das neue Computerobjekt kopiert werden sollen.
7.Es verwendet eine For-Each-Schleife, um das Array durchzugehen.

Es liest jedes Attribut aus dem Vorlagen-Computerobjekt aus.

Seite 268 von 394



Es schreibt das ausgelesene Attribut in das neue Computerobjekt.
8.Es überträgt die Änderungen am neuen Computerobjekt an Active Directory.

Script 5.23: Kopieren eines Computerobjekts

1 Set objCompt = GetObject("LDAP://cn=Computers,dc=NA,dc=fabrikam,dc=com")


2 Set objComptCopy = objCompt.Create("computer", "cn=SEA-SQL-01")
3 objComptCopy.Put "sAMAccountName", "sea-sql-01"
4 objComptCopy.SetInfo
5
6 Set objComptTemplate = _
7 GetObject("LDAP://cn=SEA-PM-
8 01,cn=Computers,dc=NA,dc=fabrikam,dc=com")
9 arrAttributes = Array("description", "location")
10
11For Each strAttrib in arrAttributes
12 strValue = objComptTemplate.Get(strAttrib)
13 objComptCopy.Put strAttrib, strValue
14Next
15
objComptCopy.SetInfo
Auch wenn in Script 5.23 nur zwei Attribute kopiert werden, können Sie natürlich so viele
Attribute kopieren, wie Sie möchten.

Kopieren eines Benutzerkontos


Script 5.24 kopiert ausgewählte Einzelwert- und Multiwert-Attribute vom Benutzerkonto
HuffArlene auf ein neues Benutzerkonto mit den Namen BarrAdam. Das Benutzerkonto, das
als Vorlage verwendet wird (HuffArlene), befindet sich in der OU HR der Domäne
na.fabrikam.com. Das neue Benutzerkonto (BarrAdam) wird ebenfalls in der OU HR erstellt.
Das Script geht hierbei folgendermaßen vor:
1.Es definiert die Konstante ADS_PROPERTY_UPDATE mit dem Wert 2 (diese wird später
von der Methode PutEx verwendet, um einen Eintrag in einem Multiwert-Attribut zu
ändern (in Zeile 21).
2.Es baut eine Bindung auf die OU HR in der Domäne na.fabrikam.com auf.
3.Es erstellt ein Benutzerkonto mit dem Namen BarrAdam.
4.Es setzt das verpflichtende Attribut sAMAccountName auf den Wert barradam.
5.Es übermittelt das neue Benutzerkonto an Active Directory.
6.Es baut eine Bindung auf das Benutzerkonto HuffArlene in der OU HR der Domäne
na.fabrikam.com auf.
7.Es erstellt ein Array mit dem Namen arrSVAttributes, das die lDAPDisplayNames-Werte
der optionalen Einzelwert-Attribute enthält, die auf das neue Benutzerkonto kopiert
werden sollen.
8.Es erstellt ein weiteres Array mit dem Namen arrMVAttributes, das die
lDAPDisplayNames-Werte der optionalen Multiwert-Attribute enthält, die auf das neue
Benutzerkonto kopiert werden sollen.

Seite 269 von 394


9.Es verwendet eine For-Each-Schleife, um das Array arrSVAttributes durchzugehen.
In der Schleife verwendet es die Methode Get, um die einzelnen Attribute aus dem
Benutzerkonto auszulesen, das als Vorlage dient und die Methode Put, um diese Attribute
in das neue Benutzerkonto zu schreiben.
10.Es verwendet eine weitere For-Each-Schleife, um den Vorgang mit dem Array
arrMVAttributes und den Multiwert-Attributen zu wiederholen.
11.Es übermittelt die Änderungen an dem neuen Benutzerkonto an Active Directory.

Script 5.24: Kopieren eines Benutzerkontos

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.

Verschieben und Umbenennen von Objekten


Zum Umbenennen und zum Verschieben wird dieselbe Methode verwendet: MoveHere. Im
Gegensatz zum Kopieren ist das Verschieben und Umbenennen über ein ADSI-Script relativ
einfach. Mit der Methode sind die folgenden Aktionen möglich:

Verschieben eines Objekts in einen anderen Container in der gleichen Domäne.

Umbenennen eines Objekts im gleichen Container .

Umbenennen und Verschieben eines Objekts in einen anderen Container der gleichen
Domäne.

Seite 270 von 394



Verschieben eines Objekts in eine andere Domäne.

Umbenennen und Verschieben eines Objekts in eine andere Domäne.
Das Verschieben in eine andere Struktur oder Gesamtstruktur ist mit der Methode MoveHere
nicht möglicht.

Bedingungen für das Verschieben über Domänengrenzen hinweg


Es gibt einige objektspezifische Einschränkungen beim Verschieben über Domänengrenzen
hinweg. Die folgenden Bedingungen müssen erfüllt sein, damit dies möglich ist:

Die Zieldomäne muss im nativen Modus ausgeführt werden.

Sowohl Ziel- als auch Quelldomäne müssen die Kerberos-Authentifizierung verwenden.

Die Verschieben-Operation muss von der Quelldomäne aus durchgeführt werden.

Sie benötigen die entsprechenden Berechtigungen, um das Objekt aus der Quelldomäne zu
entfernen und in der Zieldomäne anzulegen.

Das Verschieben von Containern mit Inhalten ist nicht möglich.

Security-Principals wie zum Beispiel Benutzer, Gruppe und Computer können nicht in eine
andere Domäne verschoben werden, wenn sie Mitglieder einer oder mehrerer globaler
Gruppen sind.
Die Methode MoveHere erwartet zwei Argumente. Beim ersten Argument handelt es sich um
den ADsPfad des zu verschiebenden oder umzubenennenden Objekts. Der DN im ADsPfad
legt fest, wo sich das Objekt im Moment befindet. Das zweite Argument ist der RDN des zu
verschiebenden Objekts oder den neuen Namen des umzubenennenden Objekts. Wenn Sie das
Objekt nur verschieben und nicht umbenennen möchten, dann können Sie als zweiten
Parameter die Konstante vbNullString angeben. In Tabelle 5.3 sind die Argumente der
Methode MoveHere noch einmal zusammengefasst.

Tabelle 5.3: Argumente der Methode MoveHere


Argument Type ErforderlichStandardwertBeschreibung
ADsPath StringJa Keiner Name des Providers und der DN
des Quellobjekts, das verschoben
oder umbenannt werden soll.
RelativeDistinguishedNameStringJa Keiner Das Attribut (cn=name) des
Objekts, das verschoben wird oder
der neue Name des
umzubenennenden Objekts. Wenn
das Objekt nicht umbenannt
werden soll, verwenden Sie die
Konstante vbNullString.
Unabhängig ob Sie ein Objekt umbenennen oder verschieben wollen, müssen Sie zwei
grundlegende Schritte durchführen:
1.Eine Bindung an den Active Directory-Container aufbauen, der als Ziel für die Verschiebe-
oder Umbenenn-Operation dienen soll.

Seite 271 von 394


2.Verschieben oder Umbenennen des Objekts.
Wie die Methode Delete, arbeitet auch die Methode MoveHere direkt in Active Directory.
Daher ist es nicht notwendig die Methode SetInfo aufzurufen.
Das Ziel der drei Scripte in diesem Abschnitt ist das Umbenennen eines veröffentlichten
Druckers, das Verschieben einer Gruppe in eine OU der gleichen Domäne und das
Verschieben eine OU in eine andere Domäne.

Umbenennen eines veröffentlichten Druckers


Script 5.25 benennt den Drucker Printer1 in HRPrn1 um. Der Drucker bleibt in der OU HR
der Domäne na.fabrikam.com.
1.Das Script baut eine Bindung zur OU HR in der Domäne na.fabrikam.com auf.
Hierdurch wird die OU HR zum Zielcontainer der Umbenenn-Operation.
2.Es benennt den Drucker Printer1 in HRPrn1 um.
Als erster Parameter der Methode MoveHere wird der ADsPfad des umzubenennenden
Objekts angegeben (der LDAP-Provider und der DN des Druckers Printer1). Der zweite
Parameter ist der neue Name des Druckers.

Script 5.25: Umbenennen eines veröffentlichten Druckers

1Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")


2
3objOU.MoveHere _
4 "LDAP://cn=Printer1,ou=HR,dc=NA,dc=fabrikam,dc=com", "cn=HRPrn1"
Verschieben einer Gruppe von einem Container in einen anderen
Script 5.26 verschiebt die Gruppe Atl-Users aus der OU HR in den Container Users der
Domäne na.fabrikam.com. Beachten Sie, dass die Gruppe nicht verändert wird - sie wird nicht
umbenannt und die Gruppenmitgliedschaften werden nicht verändert.
1.Das Script baut eine Bindung auf den Container Users der Domäne na.fabrikam.com auf.
Der Container Users wird somit zum Ziel der Verschiebeoperation.
2.Es verschiebt die Gruppe Atl-Users aus der OU HR in den Container Users in derselben
Domäne.
Der erste Parameter der Methode MoveHere ist der ADsPfad des zu verschiebenden Objekts
- der LDAP-Provider und der DN der Gruppe Atl-Users group. Da keine Umbenennung
durchgeführt werden soll, ist der zweite Parameter die Konstante vbNullString.

Script 5.26: Verschieben einer Gruppe innerhalb der gleichen Domäne

1Set objOU = GetObject("LDAP://cn=Users,dc=NA,dc=fabrikam,dc=com")


2
3objOU.MoveHere "LDAP://cn=Atl-Users,ou=HR,dc=NA,dc=fabrikam,dc=com", _
4 vbNullString
Verschieben einer OU von einer Domäne in eine andere
Script 5.27 verschiebt die OU Management aus der Domäne fabrikam.com in die Domäne
na.fabrikam.com.

Seite 272 von 394


1.Das Script baut eine Bindung an die Domäne na.fabrikam.com auf.
Diese Bindung dient als Ziel für die Verschiebeoperation.
2.Es verschiebt die OU in die Domäne na.fabrikam.com.

Script 5.27: Verschieben einer OU über eine Domänengrenze hinweg

1Set objDomain = GetObject("LDAP://dc=NA,dc=fabrikam,dc=com")


2
3objDomain.MoveHere "LDAP://ou=Management,dc=fabrikam,dc=com", _
4 vbNullString
Auch wenn Script 5.27 nützlich sein könnte, so ist es in dieser Form unsinnig. Das
Verschieben zwischen Domänen ist nur für leere Containerobjekte möglich. Daher muss die
OU geleert werden, bevor sie verschoben wird.
Wir können die folgenden wichtigen Erkenntnisse aus den Scripten dieses Abschnitts ziehen:

Sie führen alle die gleichen grundlegenden Schritte durch: eine Bindung an den Zielcontainer
aufbauen und die Methode MoveHere ausführen, um das Objekt zu verschieben oder
umzubenennen.

Sie verwenden alle die gleiche Methode (MoveHere) - egal um welchen Objekttyp es sich
handelt.

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.

Suchen in Active Directory


Das Ziel einer Suche ist die Rückgabe eine Ergebnissatzes mit keinem oder mehreren
Einträgen. Auch ein Ergebnissatz ohne Einträge kann nützlich sein - er zeigt Ihnen, dass ein
Objekt nicht vorhanden ist.
Das Suchen nach Active Directory-Objekten umfasst die folgenden Schritte:
1.Erstellen eines ADO-Connection-Objekts und die Verwendung der Methode Open dieses

Seite 273 von 394


Objekts, um über den ADSI-OLE DB-Provider auf Active Directory zuzugreifen.
2.Erstellen eines ADO-Command-Objekts und zuweisen der Eigenschaft ActiveConnection
des Objekts zum Connection-Objekt.
Dieser Schritt ist notwendig, da das Command-Objekt sowohl die Verbindung als auch den
Abfragestring enthält.
3.Zuweisen einer Suchanfrage (Abfragestring) zur Eigenschaft CommandText des Command-
Objekts.
Sie können entweder eine SQL-Syntax oder einen LDAP-Dialekt verwenden. Alle Beispiel
in diesem Kapitel verwenden den LDAP-Dialekt. Weitere Informationen über die SQL-
Syntax finden Sie unter dem Link Active Directory Programmer's Guide unter
http://www.microsoft.com/windows/reskits/webresources (englischsprachig).
4.Ausführen der Methode Execute des Command-Objekts, um die Abfrage auszuführen und
die Ergebnisse in einem RecordSet-Objekt zu speichern.
5.Verwenden der Eigenschaften des RecordSet-Objekts, um Informationen aus dem
Ergebnissatz zu lesen.
6.Verwenden der Methode Close des Connection-Objekts, um die Verbindung wieder zu
schließen.
Dieser letzte Schritt ist optional - Sie sollten ihn allerdings auf jeden Fall durchführen. Bei
größeren Scripten sparen Sie so Ressourcen.
Ziel der Scripte in diesem Abschnitt ist es, Ihnen zu zeigen, wie Active Directory-Suchen
über ADO und den ADSI-OLE DB-Provider durchgeführt werden. Die oben beschrieben
Schritte werden von allen Scripten durchgeführt.

Erstellen eines einfachen Suchscripts


Script 5.28 gibt als Ergebnissatz die Namen aller Objekte in der Domäne na.fabrikam.com
zurück.
Hierzu führt das Script die folgenden Schritte aus:
1.Erstellen eines ADO-Connection-Objekts und die Verwendung der Methode Open dieses
Objekts, um über den ADSI-OLE DB-Provider auf Active Directory zuzugreifen.
2.Erstellen eines ADO-Command-Objekts und zuweisen der Eigenschaft ActiveConnection
des Objekts zum Connection-Objekt.
Dieser Schritt ist notwendig, da das Command-Objekt sowohl die Verbindung als auch den
Abfragestring enthält.
3.Zuweisen einer Suchanfrage (Abfragestring) zur Eigenschaft CommandText des
Command-Objekts.
Sie können entweder eine SQL-Syntax oder einen LDAP-Dialekt verwenden. Alle
Beispiele in diesem Kapitel verwenden den LDAP-Dialekt. Weitere Informationen über die
SQL-Syntax finden Sie unter dem Link Active Directory Programmer's Guide unter
http://www.microsoft.com/windows/reskits/webresources (englischsprachig).
4.Ausführen der Methode Execute des Command-Objekts, um die Abfrage auszuführen und
die Ergebnisse in einem RecordSet-Objekt zu speichern.
5.Verwenden der Eigenschaften des RecordSet-Objekts, um Informationen aus dem

Seite 274 von 394


Ergebnissatz zu lesen.
6.Verwenden der Methode Close des Connection-Objekts, um die Verbindung wieder zu
schließen.
Dieser letzte Schritt ist optional - Sie sollten ihn allerdings auf jeden Fall durchführen. Bei
größeren Scripten sparen Sie so Ressourcen.
7.Erstellen eines ADO-Connection-Objekts und die Verwendung der Methode Open dieses
Objekts, um über den ADSI-OLE DB-Provider auf Active Directory zuzugreifen.
In Zeile 1 wird ein Connection-Objekt erstellt. In Zeile 2 wird das Connection-Objekt über
den ADSI-OLE DB-Provider geöffnet (der Name - beziehungsweise die ProgID - des
ADSI-OLE DB-Providers lautet ADsDSOObject).
8.Erstellen eines ADO-Command-Objekts und Zuweisen der Eigenschaft ActiveConnection
zum Connection-Objekt (Zeilen 4 und 5).
9.Zuweisen des Abfragestrings zur Eigenschaft CommandText des Command-Objekts.
Zeile 7 und 8 definiert die Suchbasis, das zurückzugebende Attribut und den Suchbereich.

Die Suchbasis - in eckigen Klammern ( ) eingeschlossen - definiert den Startpunkt der
Suche. In diesem Fall ist dies der ADsPfad der Domäne na.fabrikam.com.

Das zurückzugebende Attribut - direkt nach dem doppelten Semikolon - definiert den
lDAPDisplayName der Attribute, die die Abfrage zurückgeben soll. In diesem Fall ist nur
ein Attribut (name) angegeben.Wenn Sie mehrere Attribute angeben, trennen Sie diese
mit Kommata.

Der Suchbereich - am Ende des Abfragestrings - definiert, wo die Abfrage durchgeführt

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

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>;;name;subtree"
9 Set objRecordSet = objCommand.Execute
10
11While Not objRecordSet.EOF
12 Wscript.Echo objRecordSet.Fields("name")
13 objRecordSet.MoveNext
14Wend
15

Seite 275 von 394


16objConnection.Close
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, gibt es die Namen aller
Objekte der Domäne aus. Die Ausgabe sollte also ungefähr so aussehen:
na
Builtin
Administrators
Users
...
S-1-5-11
Program Data
Microsoft
Die vom Script zurück gelieferten Informationen sind jedoch aus den folgenden Gründen nur
von eingeschränktem Nutzen.

Es werden die Namen aller Objekte in der Domäne na.fabrikam.com zurückgegeben.

Es wird nicht deutlich, wo in der Domäne sich die einzelnen Objekte befinden.

Es wird nicht deutlich, was für einen Typ die einzelnen Objekte haben.

Der Ergebnissatz ist zu groß oder zu klein - je nach Ihren Anforderungen.
Damit die Ergebnisse brauchbarer werden, können Sie das Script folgendermaßen ändern:

Sie ändern den Abfragestring - Über den Abfragestring können Sie die zurückzugebenden
Attribute und die Suchbasis angeben. Außerdem können Sie Filter definieren und den
Suchbereich festlegen.

Sie geben zusätzliche Suchoptionen über das Command-Objekt an - Über das
Command-Objekt können Sie viele weitere Aspekte der Suche kontrollieren - zum Beispiel
die Sortierung, die Menge der zurückgegebenen Ergebnisse oder die maximale Dauer der
Suche.

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.

Zurückgeben mehrerer Attribute über die Suche


Script 5.28 hat nur einen einzelnen Wert zurückgegeben - das Attribut name. Mit weiteren
Attributen wird das Ergebnis wahrscheinlich aussagekräftiger. Wenn Sie zum Beispiel das
Attribut distinguishedName mit anzeigen, dann können Sie feststellen, wo sich das Objekt in
Active Directory befindet.
Script 5.29 gibt einen Ergebnissatz zurück, in dem die Attribute name und distinguishedName
aller Objekte der Domäne na.fabrikam.com enthalten sind. Das Script arbeitet bis auf die
folgenden zwei Änderungen genauso wie das vorhergehende Script:

Das Attribut distinguishedName wurde in den Abfragestring aufgenommen (Zeile 8).

Der Wert des Attributs distinguishedName wird in der Kommandozeile ausgegeben (Zeilen
14 und 15).

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.

Seite 277 von 394


Da das Attribut objectCategory nur ein Einzelwert-Attribut ist, ist es besser für Suchanfragen
geeignet. Wenn möglich, sollten Sie also dieses Attribut verwenden.

Anmerkung: Informationen zu Active Directory-Klassen finden Sie im Abschnitt Die Active


Directory-Architektur weiter unten in diesem Kapitel.
Script 5.30 demonstriert, wie Sie einen Ergebnissatz auf eine bestimmte Kategorie
(Computer) einschränken können. Das Script gibt die Attribute name und distinguishedName
aller Computerobjekte der Domäne na.fabrikam.com zurück. Das Script arbeitet genau wie
die beiden vorherigen Scripte. Als einzige Änderung wurde der Filter
objectCategory=computer zum Abfragestring hinzugefügt.

Script 5.30: Suchen nach den Namen und den DNs aller Computerobjekt in der Domäne

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>;(objectCategory=computer)" & _
9 ";distinguishedName,name;subtree"
10
11Set objRecordSet = objCommand.Execute
12
13While Not objRecordSet.EOF
14 Wscript.Echo objRecordSet.Fields("Name")
15 Wscript.Echo "[" & _
16 objRecordSet.Fields("distinguishedName") & "]"
17 objRecordSet.MoveNext
18Wend
19
20objConnection.Close
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, gibt es die Namen und die
DNs aller Computerobjekte in der Kommandozeile aus. Diese Ausgabe sieht ungefähr so aus:
SEA-DC-02
[CN=SEA-DC-02,OU=Domain Controllers,dc=NA,DC=fabrikam,DC=com]
SEA-DC-03
[CN=SEA-DC-02,OU=Domain Controllers,dc=NA,DC=fabrikam,DC=com]
...
SEA-PM-01
[CN=SEA-PM-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
SEA-SQL-01
[CN=SEA-SQL-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
Filter können auch kombiniert werden - außerdem werden Wildcards unterstützt. Weitere
Informationen finden Sie unter dem Link Active Directory Programmer's Guide unter
http://www.microsoft.com/windows/reskits/webresources. Suchen Sie hier nach dem Text
"Search Filter Syntax."

Angeben des globalen Katalog-Servers in der Suchbasis


Nehmen wir einmal an, Sie möchten die Namen und die DNs aller Computer der
Gesamtstruktur abfragen. Hierzu können Sie den globalen Katalog-Server der Stammdomäne
abfragen - dieser speichert unter anderem die beiden gesuchten Attribute. Ein globaler

Seite 278 von 394


Katalog-Server speichert Teile der Informationen aus allen Domänen. Um den globalen
Katalog-Server abzufragen, ändern Sie den LDAP-Moniker in der Suchbasis auf GC und
ändern Sie den DN auf den der Stammdomäne. Sie ändern also den ADsPfad von
<LDAP://dc=NA,dc=fabrikam,dc=com>
auf
<GC://dc=fabrikam,dc=com>
Script 5.31 demonstriert diesen Vorgang. Es arbeitet genau wie die vorherigen Scripte - nur
der Suchstring wurde geändert (Zeile 8).

Script 5.31: Suchen nach den Namen und DNs aller Computerobjekte in der
Gesamtstruktur

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 "<GC://dc=fabrikam,dc=com>;(objectCategory=computer)" & _
9 ";distinguishedName,name;subtree"
10
11Set objRecordSet = objCommand.Execute
12
13While Not objRecordSet.EOF
14 Wscript.Echo objRecordSet.Fields("Name")
15 Wscript.Echo "[" & _
16 objRecordSet.Fields("distinguishedName") & "]"
17 objRecordSet.MoveNext
18Wend
19
20objConnection.Close
Wenn Sie das Script in der Stammdomäne fabrikam.com ausführen, gibt es die Namen und
die DNs aller Computerobjekte der Gesamtstruktur aus. Diese Ausgabe sieht ungefähr so aus:
SEA-DC-01
[CN=SEA-DC-01,OU=Domain Controllers,DC=fabrikam,DC=com]
SEA-DC-04
[CN=SEA-DC-04,OU=Domain Controllers,DC=fabrikam,DC=com]
SEA-DC-02
[CN=SEA-DC-02,OU=Domain Controllers,dc=NA,DC=fabrikam,DC=com]
SEA-DC-03
[CN=SEA-DC-03,OU=Domain Controllers,dc=NA,DC=fabrikam,DC=com]
...
SEA-PM-01
[CN=SEA-PM-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
SEA-SQL-01
[CN=SEA-SQL-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
Den Ergebnissatz über die Nachverfolgung erweitern
Wenn ein Domänencontroller einer übergeordneten Domäne (zum Beispiel der
Stammdomäne) einen Ergebnissatz zusammenstellt, dann gibt er eine Liste der
untergeordneten Domänen an den Clientcomputer, der das Script ausführt. Der
Clientcomputer kontaktiert dann jede der untergeordneten Domänen, so dass diese den
Ergebnissatz vervollständigen können. Dieser Prozess heißt Nachverfolgung.

Seite 279 von 394


Die Nachverfolgung erhöht den Netzwerkverkehr und die Last auf den Domänencontrollern.
Und zwar deshalb, weil ja nicht nur der globale Katalog-Server, sondern auch die
Domänencontroller abgefragt werden.
Sie können die Nachverfolgung explizit aktivieren, indem Sie die Eigenschaft Chase
Referrals auf den Wert &h20 setzen - Script 5.32 demonstriert dies. Es arbeitet (abgesehen
von vier kleinen Änderungen) genau so wie die vorhergehenden Scripte dieses Abschnitts.
Bei den Änderungen handelt es sich um die folgenden:

Die Konstante ADS_CHASE_REFERRALS_SUBORDINATE wird mit dem Wert &h20
definiert (Zeile 1).

Die Nachverfolgung wird aktiviert, indem die Eigenschaft Chase Referrals des Command-
Objekts auf den Wert der Konstante ADS_CHASE_REFERRALS_SUBORDINATE gesetzt
wird (Zeilen 8 und 9).

Das Attribut isCriticalSystemObject wird mit in den Abfragestring aufgenommen. Dieses
Attribut wird nicht im globalen Katalog-Server gespeichert und muss daher über die
Nachverfolgung von den untergeordneten Domänen abgefragt werden (Zeile 13).

Der Wert des Attributs isCriticalSystemObject wird zusätzlich ausgegeben (Zeilen 19 und
20).

Script 5.32: Verwenden der Nachverfolgung bei einer Suche

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

Seite 280 von 394


[CN=SEA-DC-01,OU=Domain Controllers,DC=fabrikam,DC=com]
SEA-DC-04
isCriticalSystemObject: True
[CN=SEA-DC-04,OU=Domain Controllers,DC=fabrikam,DC=com]
SEA-DC-02
isCriticalSystemObject: True
[CN=SEA-DC-02,OU=Domain Controllers,dc=NA,DC=fabrikam,DC=com]
SEA-DC-03
isCriticalSystemObject: True
[CN=SEA-DC-03,OU=Domain Controllers,dc=NA,DC=fabrikam,DC=com]
...
SEA-PM-01
isCriticalSystemObject: False
[CN=SEA-PM-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
SEA-SQL-01
isCriticalSystemObject: False
[CN=SEA-SQL-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
Den Suchbereich definieren
Stellen Sie sich vor, Sie möchten nur die Computer im Container Computers einer
bestimmten Domäne abfragen. Nehmen wir außerdem einmal an, der Container enthält noch
weitere Untercontainer. Um eine Suche so einzuschränken, können Sie den DN im ADsPfad
(die Suchbasis) folgendermaßen ändern:
cn=Computers,dc=NA,dc=fabrikam,dc=com
Ein möglicher Abfragestring könnte zum Beispiel so aussehen:
"<GC://cn=Computers,dc=NA,dc=fabrikam,dc=com>" & _
";(objectCategory=computer)" & _
";distinguishedName,name;subtree"
Mit diesem Abfragestring werden die Attribute DN und name aller Computerobjekte im
Container Computers der Domäne na.fabrikam.com abgefragt. Da der Abfragestring mit dem
Wert subtree endet (der Suchbereich), werden auch die untergeordneten Container
durchsucht.
Die möglichen Werte für den letzten Teil des Abfragestrings (den Suchbereich) sind:

Base - Sucht nur an der durch den DN definierten Stelle.

Onelevel - Sucht auch in allen unmittelbaren Untercontainern.

Subtree - Sucht in den unmittelbaren Untercontainern und in allen weiteren Untercontainern.
Wenn Sie den Bereich nicht angeben, wird dieser Wert standardmäßig verwendet.
Script 5.33 demonstriert eine Suche ausschließlich im durch den DN angegebenen Container.
Um die Suche auf die gewünschten Objekte einzuschränken, geht das Script folgendermaßen
vor:
1.Es gibt den Container Computers der Domäne na.fabrikam.com als Suchbasis an.
2.Es gibt als Suchbereich onelevel an.

Script 5.33: Einschränken der Suche durch den Bereich

1 Set objConnection = CreateObject("ADODB.Connection")


2 objConnection.Open "Provider=ADsDSOObject;"
3
4 Set objCommand = CreateObject("ADODB.Command")

Seite 281 von 394


5 objCommand.ActiveConnection = objConnection
6
7 objCommand.CommandText = _
8 "<GC://cn=Computers,dc=NA,dc=fabrikam,dc=com>" & _
9 ";(objectCategory=computer)" & _
10 ";distinguishedName,name;onelevel"
11
12Set objRecordSet = objCommand.Execute
13
14While Not objRecordSet.EOF
15 Wscript.Echo objRecordSet.Fields("Name")
16 Wscript.Echo "[" & _
17 objRecordSet.Fields("distinguishedName") & "]"
18 objRecordSet.MoveNext
19Wend
20
21objConnection.Close
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, gibt es die Attribute DN und
name aller Computerobjekte im Container Computers der Domäne aus. Die Ausgabe könnte
zum Beispiel so aussehen:
SEA-PM-01
[CN=SEA-PM-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
SEA-SQL-01
[CN=SEA-SQL-01,cn=Computers,dc=NA,DC=fabrikam,DC=com]
...
Die Ergebnisse der Suche sortieren
Eine Sortierung können Sie über die Eigenschaft Sort On des Command-Objekts durchführen.
Die Sortierung wird dann bereits auf dem Server ausgeführt - und zwar bevor er die Daten an
den Clientcomputer zurückgibt, der das Script ausführt.
Der Eigenschaft Sort On weisen Sie den lDAPDisplayName eines Attributs zu. Nach diesem
Attribut wird die Sortierung vorgenommen.

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.

Script 5.34: Sortieren der Computerobjekte nach dem Erstellungsdatum

1 Set objConnection = CreateObject("ADODB.Connection")


2 objConnection.Open "Provider=ADsDSOObject;"

Seite 282 von 394


3
4 Set objCommand = CreateObject("ADODB.Command")
5 objCommand.ActiveConnection = objConnection
6
7 objCommand.Properties("Sort On") = "whenCreated"
8
9 objCommand.CommandText = _
10 "<GC://dc=fabrikam,dc=com>;(objectCategory=Computer);" & _
11 "distinguishedName,name,whenCreated;subtree"
12
13Set objRecordSet = objCommand.Execute
14
15While Not objRecordSet.EOF
16 Wscript.Echo objRecordSet.Fields("Name")
17 Wscript.Echo "[" & _
18 objRecordSet.Fields("distinguishedName") & "]"
19 Wscript.Echo objRecordSet.Fields("whenCreated") & VbCrLf
20 objRecordSet.MoveNext
21Wend
22
23objConnection.Close
Wenn das Script in der Domäne na.fabrikam.com ausgeführt wird, dann gibt es die Attribute
name, DN und whenCreated aller Computerobjekte der Domäne aus. Der Ergebnissatz ist
nach dem Attribut whenCreated sortiert (vom ältesten bis zum jüngsten). Die Ausgabe könnte
folgendermaßen aussehen:
SEA-DC-01
[CN=SEA-DC-01,OU=Domain Controllers,DC=fabrikam,DC=com]
8/14/2002 9:59:12 AM

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

Seite 283 von 394


na.fabrikam.com ab. Hierzu wurden die folgenden Änderungen an dem vorherigen Scripten
vorgenommen:
1.Im Abfragestring wird die Ergebnismenge über den Filter objectCategory=Group auf
Gruppenobjekte eingeschränkt. Außerdem wird das Multiwert-Attribut member mit
aufgenommen (Zeile 9).
Da in diesem Script die Domäne na.fabrikam.com und der Moniker GC verwendet wird,
muss sich in der Domäne auch ein globaler Katalog-Server befinden. Wenn es keinen
globalen Katalog-Server gibt, dann müssen Sie den Moniker LDAP verwenden.
2.Es wird eine Variable mit dem Namen arrMembers mit den Inhalten des Attributs member
initialisiert (diese stammen aus der Eigenschaft fields des RecordSet-Objekts (Zeile 19).
3.Mit der VBScript-Funktion IsArray wird geprüft, ob das Attribut member ein Array ist
(Zeile 22).
Wenn das Ergebnis dieser Prüfung False ist, dann ist das Attribut leer.

Wenn der Rückgabewert von IsArray den Wert True hat, dann wird eine For-Each-Schleife
verwendet, um die Mitglieder der Gruppe auszugeben (Zeilen 23-25).

Wenn der Rückgabewert von IsArrayFalse ist, dann wird das Wort Keine ausgegeben (Zeile
27).

Script 5.35: Suchen nach dem Namen und DNs aller Objekte der Domäne

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 "<GC://dc=NA,dc=fabrikam,dc=com>;(objectCategory=Group);" & _
9 "distinguishedName,name,member;subtree"
10
11Set objRecordSet = objCommand.Execute
12
13While Not objRecordSet.EOF
14 Wscript.Echo objRecordSet.Fields("Name")
15 Wscript.Echo "[" & _
16 objRecordSet.Fields("distinguishedName") & "]"
17
18 Wscript.Echo "Group Member(s):"
19 arrMembers = objRecordSet.Fields("member")
20
21 If IsArray(objRecordSet.Fields("member")) Then
22 For Each strMember in arrMembers
23 Wscript.Echo vbTab & strMember
24 Next
25 Else
26 Wscript.Echo vbTab & "Keine"
27 End If
28 Wscript.Echo VbCrLf
29 objRecordSet.MoveNext
30Wend
31
32objConnection.Close

Seite 284 von 394


Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, gibt es den Namen, den DN
und die Mitglieder aller Gruppenobjekte der Domäne aus:
Administrators
[CN=Administrators,CN=Builtin,DC=na,DC=fabrikam,DC=com]
Group Member(s):
CN=Enterprise Admins,CN=Users,DC=fabrikam,DC=com
CN=Domain Admins,CN=Users,DC=na,DC=fabrikam,DC=com
CN=Administrator,CN=Users,DC=na,DC=fabrikam,DC=com

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

...

Pre-Windows 2000 Compatible Access


[CN=Pre-Windows 2000 Compatible Access,CN=Builtin,DC=na,DC=fabrikam,DC=com]
Group Member(s):
None

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.

Seite 285 von 394


Script 5.36: Einschränken der Einträge in Multiwert-Attributen über die Eigenschaft
Range

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://cn=Atl-Users,cn=Users,dc=NA,dc=fabrikam,dc=com>;;" & _
9 "member;Range=0-999;base"
10
11Set objRecordSet = objCommand.Execute
12
13Wscript.Echo "First 1000 Member(s):"
14arrMembers = objRecordSet.Fields("member;Range=0-999")
15
16For Each strMember in arrMembers
17 Wscript.Echo vbTab & strMember
18Next
19
20objConnection.Close
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, gibt es die ersten 1.000
Mitglieder der Gruppe Atl-Users aus:
First 1000 Member(s):
CN=UserNo988,CN=Users,DC=na,DC=fabrikam,DC=com
CN=UserNo987,CN=Users,DC=na,DC=fabrikam,DC=com
CN=UserNo986,CN=Users,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
Aus den Scripten in diesem Abschnitt können wir die folgenden wichtigen Erkenntnisse
gewinnen:

Sie führen alle die gleichen grundlegenden Schritte aus:
1.Erstellen eines ADO-Connection-Objekts unter Verwendung des ADSI-OLE DB-Providers.
2.Erstellen eines ADO-Command-Objekts und Verbinden dieses Objekts mit dem
Connection-Objekt.
3.Verwenden des Command-Objekts, um einen Abfragestring zu erstellen.
4.Erstellen eines RecordSet-Objekts, um die Abfrage auszuführen und den Ergebnissatz zu
speichern.
5.Verwenden des RecordSet-Objekts, um die Elemente des RecordSet auszulesen.
6.Schließen des Connection-Objekts.

Mit Ausnahme von Script 5.36 werden die Einträge des RecordSet-Objekts in einer While-
Wend-Schleife ausgegeben. In Script 5.36 ist dieser Schritt nicht notwendig, da es nur einen
einzelnen Eintrag zurückgibt.

Das Zurückgeben eines Ergebnissatzes ist der grundlegende Zweck der Suche. Andere
Aufgaben, die Sie über eine Suche durchführen können, finden Sie im Abschnitt

Seite 286 von 394


Administrative Aufgaben über einen Ergebnissatz durchführen weiter unten in diesem
Kapitel.

Optimieren der Suchleistung


Um eine Suche optimieren zu können, sind Kenntnisse über Active Directory notwendig.
Auch von der Verwendung der Objekte in Ihrem Script wird die Suchleistung beeinflusst.

Konsolidierung von Abfragestrings


Wenn Sie ein Script schreiben, in dem viele Suchoperationen durchgeführt werden, dann
überlegen Sie, wie Sie die Suchen zusammenfassen können. Schreiben Sie zum Beispiel einen
Abfragestring, der mehrere Attribute zurückgibt, statt zwei oder mehr separate Suchen zu
verwenden.

Einschränken des Ergebnissatzes


Schränken Sie den Bereich Ihrer Suche so weit wie möglich ein. Wenn Sie zum Beispiel
einen Ergebnissatz mit allen Objekten einer OU benötigen, dann geben Sie als Suchbasis
diesen Container an. Wenn Sie die Objekte in dem Untercontainer nicht benötigen, dann
verwenden Sie zusätzlich die Eigenschaft onelevel.
Verwenden Sie Suchfilter. Geben Sie zum Beispiel die Eigenschaft objectCategory=class
type an - class type ist in diesem Fall der Typ des zu suchenden Objekts. Verwenden Sie eher
objectCategory statt objectClass. Bei objectCategory handelt es sich um einen Einzelwert, der
für Suchanfragen besser geeignet ist. Im Gegensatz zu objectClass wird objectCategory auf
den globalen Katalog-Servern gespeichert und indiziert.
Geben Sie Filter an (zum Beispiel cn=SEA*, der den Ergebnissatz auf Objekt beschränkt, die
mit den Buchstaben SEA anfangen). Wenn Sie das Wildcard-Zeichen * verwenden, dann
jedoch nur am Ende - ansonsten erzeugen Sie noch mehr Last auf dem Domänencontroller der
die Anfrage verarbeitet.
Schränken Sie die Suche noch weiter ein, indem Sie Filter kombinieren. Der folgende Filter
schränkt die Suche zum Beispiel auf alle Computerobjekte ein, die mit SEA anfangen:
(&(objectCategory=computer)(cn=SEA*))
Über die Eigenschaft Range können Sie die Zahl der zurückgegebenen Einträge von
Multiwert-Attributen einschränken.

Zusätzliche Eigenschaften des Command-Objekts


Es gibt eine Menge Eigenschaften des Command-Objekst, die die Suchoperation beeinflussen.
Diese Eigenschaften sind besonders im Umgang mit großen Ergebnisätzen sehr nützlich. In
Tabelle 5.4 sehen Sie einige dieser Optionen.

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.

Seite 287 von 394


Option Beschreibung StandardwertSyntax
Size Limit Gibt die Größe des Ergebnissatzes 1.000
an. Wenn der Domänencontroller objCommand.Properties _
diese Grenze erreicht, wird der ("Size Limit")= Records
Ergebnissatz sofort an den Client Records ist die Anzahl der
zurückgegeben und die Suche ist Einträge, bei der der
beendet. Domänencontroller die Suche
beendet.
Time Limit Gibt die maximale Dauer der Keiner
Suche an. Nach diesem Zeitraum objCommand.Properties _
gibt der Domänencontroller einen ("Time Limit")= Time
Ergebnissatz zurück - auch dann, Time ist der maximale
wenn dieser noch nicht alle Zeitraum (in Sekunden), nach
Ergebnisse enthält. dem der Ergebnissatz
zurückgegeben wird.
Timeout Gibt den Zeitraum an, den der Keiner
Client auf einen Ergebnissatz objCommand.Properties _
wartet, bevor er die Suche abbricht. ("Timeout")= Time
Timeout ist der Zeitraum (in
Sekunden) den der Client auf
den Ergebnissatz wartet.
Cache Results Gibt an, ob der Ergebnissatz auf True
(caching) dem Client zwischengespeichert objCommand.Properties _
werden soll. Bei sehr großen ("Cache Results"= Boolean
Ergebnissätzen kann der Wenn der Wert auf False
Speicherverbrauch auf dem Client gesetzt wird, ist das
durch das Deaktivieren des Zwischenspeichern
Zwischenspeicherns verringert deaktiviert.
werden.
Asynchronous Gibt an, ob der Domänencontroller False
die Einträge im Ergebnissatz objCommand.Properties _
einzeln (asynchron) oder komplett ("Asynchronous"= Boolean
nach der Suche (synchron) senden Wenn der Wert auf True
soll. gesetzt wird, dann sendet der
Domänencontroller die
Einträge asynchron.

Verwenden des globalen Katalog-Servers für Suchoperationen


Wenn alle Attribute einer Suchoperation auf dem globalen Katalog-Server gespeichert
werden, dann verwenden Sie das Prefix GC statt LDAP. Dies ist ganz besonders wichtig,
wenn Sie Ergebnisse aus mehr als einer Domäne abfragen. Wenn Sie den globalen Katalog-
Server verwenden, muss nur dieser die Anfrage bearbeiten - andernfalls werden
möglicherweise sehr viele Domänencontroller mit in die Suche einbezogen. Wenn Sie den
globalen Katalog-Server nicht verwenden, dann müssen Sie die Option Nachverfolgen zur
Abfrage von Objekten aus mehreren Domänen verwenden. Sie sollten dies jedoch wenn
möglich vermeiden.

Seite 288 von 394


Wenn Sie einen Ergebnissatz sortieren müssen, dann sortieren Sie nach Attributen, die
indiziert und auf dem globalen Katalog-Server gespeichert sind. Informationen dazu, wie Sie
feststellen, ob ein Attribut indiziert und auf dem globalen Katalog-Server gespeichert ist,
finden Sie im Abschnitt Die Active Directory-Archiektur weiter unten in diesem Kapitel.

Weniger Objekte verwenden


Erstellen Sie nur ein Connection-Objekt und verwenden Sie dies im gesamten Script (dies gilt
auch für alle anderen Objekte).

Administrative Aufgaben über einen Ergebnissatz ausführen


Mit dem ADSI-OLE DB-Provider ist nur ein Lesezugriff auf Active Directory möglich - Sie
können also keine Objekte direkt ändern. Sie können jedoch über den Ergebnissatz und
weitere ADSI-Methoden Änderungen durchführen. Beispiele hierfür sind:

Nach dem Attribut sAMAccountName eines Objekts suchen. Wenn der Ergebnissatz leer ist,
dann können Sie das Objekt gefahrlos über die Methode Create erstellen.

Über das Attribut objectCategory nach allen Computerobjekten suchen und die Objekte dann
über die Methode Put ändern.

Nach den Objekten suchen, bei denen das Attribut description zeigt, dass sie zu einer
bestimmten Abteilung gehören. Diese Objekte können Sie dann zum Beispiel zur
Konsolidierung in einen bestimmten Container verschieben.
Die beiden Scripte in diesem Abschnitt demonstrieren solche Vorgänge.

Ein Attribut bei vielen Objekten ändern


Script 5.37 ändert das Attribut location aller Computer der Domäne, deren Name mit ATL
beginnt, auf den Wert Atlanta, Georgia. Die hierzu erforderlichen Schritte sind:
1.Verwenden einer ADS-Abfrage, die alle Computerobjekte zurückgibt, deren Name mit ATL
anfängt.

In Zeile 9 werden zwei Filter kombiniert: objectCategory=Computer und cn=ATL*. Der
zweite Filter verwendet ein Wildcard-Zeichen (*), um alle Computer zu finden, deren Name
mit ATL beginnt.

In Zeile 10 wird das Attribut ADsPath jedes Computers im Ergebnissatz zurückgegeben.
1.Verwenden einer While-Wend-Schleife und der Methode MoveNext, um die einzelnen
Einträge des RecordSet-Objekts durchzugehen.

Für jeden Eintrag im Ergebnissatz wird eine Bindung an das entsprechende Active Directory-
Objekt aufgebaut. Dann wird das Attribut location geändert und die Änderung wird an
Active Directory übermittelt (Zeilen 15-18).

Die Anzahl der geänderten Einträge wird über die Eigenschaft RecordCount des RecordSet-
Objekts ausgegeben (Zeilen 21 und 22).

Script 5.37: Ändern eines Attributs von mehreren Computerobjekten

1 Set objConnection = CreateObject("ADODB.Connection")

Seite 289 von 394


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>;" & _
9 "(&(objectCategory=Computer)(cn=ATL*));" & _
10 "ADsPfad;subtree"
11
12Set objRecordSet = objCommand.Execute
13
14While Not objRecordSet.EOF
15 strADsPfad = objRecordSet.Fields("ADsPfad")
16 Set objComputer = GetObject(strADsPfad)
17 objComputer.Put "location", "Atlanta, Georgia"
18 objComputer.SetInfo
19 objRecordSet.MoveNext
20Wend
21Wscript.Echo objRecordSet.RecordCount & " computers objects modified."
22
23objConnection.Close
Verschieben von Objekten, abhängig vom Wert eines bestimmten Attributs
Script 5.38 verschiebt die Benutzerobjekte in die OU HR, derenAttribut department den Wert
Human Resources hat. Die hierzu erforderlichen Schritte sind:
1.Verwenden einer ADO-Abfrage für alle Benutzerkonten, deren Attribut department den
Wert Human Resources hat.

In Zeile 9 und 10 werden drei Filter kombiniert: objectCategory=person, objectClass=user
und department=Human Resources. Beachten Sie die hierbei verwendeten Klammern und
die kaufmännischen Und-Zeichen (&). Das Script verwendet die Eigenschaften
objectCategory und objectClass - so werden alle Benutzerkonten zurückgegeben, die
Sicherheitsprinzipale sind. Weitere Informationen über diese Filterkombination finden Sie im
Abschnitt Active Directory-Benutzer in diesem Buch.

In Zeile 10 werden die Attribute ADsPath, distinguishedName und name aller
Benutzerkonten zurückgegeben, die mit den Filterbedingungen übereinstimmen.
1.Es wird eine Bindung zur Ziel-OU für die Verschieben-Operation aufgebaut (Zeile 14).
Diese Bindung könnte auch für jedes zu verschiebende Objekt in der While-Wend-Schleife
neu aufgebaut werden. Es ist jedoch deutlich effizienter, die Bindung nur einmal vor der
Schleife aufzubauen und diese dann in der Schleife mehrmals zu verwenden.
2.Es wird eine While-Wend-Schleife verwendet, um die Einträge im RecordSet-Objekt zu
lesen (Zeile 16).

Die Variable strADsPath wird über die Eigenschaft field mit dem ADsPath initialisiert.

Es werden zwei weitere Variablen initialisiert: strDNRecord und strDNCompare.
strDNRecord speichert den Wert aus dem Attribut distinguishedName, und strDNCompare
speichert den Wert distinguishedName (wird aus dem Attribut DN und dem Pfad zur OU HR
zusammengesetzt). Über die Variable strDNCompare wird festgestellt, ob sich das
Benutzerkonto aus strDNRecord im Moment in der OU HR befindet.

Seite 290 von 394



Wenn das Benutzerkonto noch nicht in der OU ist (wenn also strDNRecord nicht gleich
strDNCompare ist), dann wird die Methode MoveHere verwendet, um das Konto in die OU
zu verschieben.
Als Letztes wird das Attribut distinguishedName des Benutzerkontos ausgegeben.

Script 5.38: Verschieben von mehreren Benutzerkonten mit Hilfe des Ergebnissatzes
einer Suche

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>;" & _
9 "(&(&(objectCategory=person)(objectClass=user)" & _
10 "(department=Human Resources)));" & _
11 "ADsPath,distinguishedName,name;subtree"
12
13Set objRecordSet = objCommand.Execute
14
15Set objOU = GetObject("LDAP://ou=HR,dc=NA,dc=fabrikam,dc=com")
16
17While Not objRecordSet.EOF
18 strADsPath = objRecordSet.Fields("ADsPath")
19
20 strDNRecord=LCase(objRecordSet.Fields("distinguishedName"))
21 strDNCompare=LCase("cn=" & objRecordSet.Fields("name") & _
22 ",ou=HR,dc=NA,dc=fabrikam,dc=com")
23
24 If strDNRecord <> strDNCompare Then
25 objOU.MoveHere strADsPath, vbNullString
26 Wscript.Echo objRecordSet.Fields("distinguishedName") & " Moved."
27 Else
28 Wscript.Echo objRecordSet.Fields("distinguishedName") & " Not
29Moved."
30 End If
31 objRecordSet.MoveNext
32Wend
33
objConnection.Close
Aus den Scripten dieses Abschnitts können wir die folgenden wichtigen Erkenntnisse
gewinnen:

Beide Scripte führen die gleichen grundlegenden Schritte durch: Sie verwenden ADO, um
ein Connection-, Command- und ein RecordSet-Objekt zu erstellen. Dann lesen Sie die
einzelnen Einträge im RecordSet-Objekt aus.

Sie verwenden die Elemente aus dem Ergebnissatz, um administrative Aufgaben
durchzuführen.

Auflisten der Active Directory-Objekte in Containern


Der Weg über ADO und den ADSI-OLE DB-Provider ist nicht der einzige Weg, um
Informationen über einen Container zu erhalten. Sie können die Inhalte eines Containers auch
über ADSI auflisten - dieser Weg ist jedoch nicht so effizient wie die Auflistung über ADO

Seite 291 von 394


(vor allem bei vielen Objekten). Die Auflistung ist jedoch einfacher zu implementieren als die
Suchabfrage über ADO.

Auflisten von Containerinhalten


Um die Inhalte eines Active Directory-Containers aufzulisten, müssen Sie drei grundlegende
Schritte durchführen:
1.Erstellen Sie eine Bindung an den Active Directory-Container, für den Sie die Inhalte
auflisten möchten.
Normalerweise handelt es sich hier um eine OU.
2.Schränken Sie den Ergebnissatz über die Eigenschaft Filter ein.
Dieser Schritt ist optional, bei vielen Objekten kann er jedoch sehr nützlich sein.
3.Erstellen Sie eine Schleife, in der Sie weitere Aktionen mit den Objekten im Container
durchführen.
Script 5.39 listet die Untercontainer des Containers Configuration auf. Der Container
Configuration befindet sich unter dem Stamm der Domäne fabrikam.com. Das Script geht
hierzu in zwei Schritten vor:
1.Es baut eine Bindung an den Container Configuration in der Domäne auf.
2.Es verwendet eine For-Each-Schleife, um die Namen der Untercontainer auszugeben.

Script 5.39: Auflisten der Untercontainernamen eines Containers

1Set objConfiguration = GetObject _


2 ("LDAP://cn=Configuration,dc=fabrikam,dc=com")
3
4For Each objContainer in objConfiguration
5 Wscript.Echo objContainer.Name
6Next
Wenn sie das Script in der Gesamtstruktur fabrikam.com ausführen, gibt es alle
Untercontainer des Containers Configuration aus:
CN=DisplaySpecifiers
CN=Extended-Rights
CN=ForestUpdates
CN=LostAndFoundConfig
CN=Partitions
CN=Physical Locations
CN=Services
CN=Sites
CN=WellKnown Security Principals
Das Script kann aus jeder Domäne der Gesamtstruktur ausgeführt werden.

Administrative Aufgaben mit Hilfe der Auflistung durchführen


Script 5.40 listet den Container Partitions auf, der sich im Container Configuration der
Stammdomäne fabrikam.com befindet. Während der Auflistung werden zwei Einträge im
Multiwert-Attribut upnSuffixes aktualisiert und das Script gibt die Werte in diesem Attribut
aus. Es geht folgendermaßen vor:
1.Es definiert die Konstante ADS_PROPERTY_APPEND mit dem Wert 3. Diese wird später

Seite 292 von 394


für die Methode PutEx verwendet (Ändern von Einträgen).
2.Es baut eine Bindung an den Container Partitions im Container Configuration der
Stammdomäne auf.
3.Es fügt zwei Einträge zum Attribut upnSuffixes hinzu.
4.Es verwendet eine For-Each-Schleife, um die Einträge im Attribut upnSuffixes des
Containers Partitions auszugeben.

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.

Einschränken der aufgelisteten Container auf einen bestimmten Objekttyp


Script 5.41 listet die Inhalte des Containers Users der Domäne na.fabrikam.com auf und
verwendet die Eigenschaft Filter, um die Auflistung auf Objekte vom Typ user
einzuschränken. Das Script gibt dann das Attribut primaryGroupID und alle Einträge im
Attribut memberOf aus. Weitere Informationen über die Eigenschaft Filter finden Sie im
Abschnitt ADSI-Schnittstellen weiter unten in diesem Kapitel. Das Script geht
folgendermaßen vor:
1.Es verwendet den Befehl On Error Resume Next.
Mit dem Befehl werden alle Laufzeitfehler unterdrückt. In diesem Fall sollen die Fehler
unterdrückt werden, die auftreten, wenn ein Attribut nicht im lokalen Zwischenspeicher
gefunden werden kann.
2.Es definiert die Konstante E_ADS_PROPERTY_NOT_FOUND mit dem Wert
&h8000500D. Diese wird später (in Zeile 15) für die Feststellung des ADSI-Fehlercodes
verwendet (der Fehler tritt auf, wenn das Attribut memberOf nicht im lokalen
Zwischenspeicher gefunden werden kann).
3.Es baut eine Bindung an den Container Users der Domäne na.fabrikam.com auf.
4.Es setzt die Eigenschaft Filter, um nur Benutzerobjekte zurückzugeben (Zeile 6).

Seite 293 von 394


5.Es verwendete eine For-Each-Schleife, um Informationen über die einzelnen
Benutzerkonten auszugeben. In der Schleife passiert folgendes:
1.Über die Methode Get wird der Wert des Attributs primaryGroupID abgefragt und
ausgegeben (Zeile 11).
2.Über die Methode GetEx wird das Array arrMemberOf mit den Einträgen des Attributs
memberOf initialisiert (Zeile 13).
Wenn das Attribut memberOf nicht vorhanden ist, dann tritt ein Fehler mit der
Fehlernummer aus E_ADS_PROPERTY_NOT_FOUND auf. In diesem Fall wird eine
Meldung ausgegeben und das Err-Objekt wird zurückgesetzt (Zeilen 19-21).
Wenn das Attribut vorhanden ist, dann werden die einzelnen Elemente des Arrays
arrMemberOf ausgegeben (Zeilen 15-18).

Script 5.41: Einschränken der Auflistung auf Benutzerkonten über die Eigenschaft
Filter

1 On Error Resume Next


2 Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
3 Set objOU = GetObject _
4 ("LDAP://cn=Users,dc=NA,dc=fabrikam,dc=com")
5
6 ObjOU.Filter= Array("user")
7
8 For Each objUser in objOU
9 Wscript.Echo objUser.cn & " ist Mitglied von: "
10 Wscript.Echo vbTab & "Primary Group ID: " & _
11 objUser.Get("primaryGroupID")
12
13 arrMemberOf = objUser.GetEx("memberOf")
14
15 If Err.Number <> E_ADS_PROPERTY_NOT_FOUND Then
16 For Each Group in arrMemberOf
17 Wscript.Echo vbTab & Group
18 Next
19 Else
20 Wscript.Echo vbTab & "Attribut memberOf ist nicht vorhanden"
21 Err.Clear
22 End If
23 Wscript.Echo VbCrLf
24Next
Wenn Sie das Script in der Domäne na.fabrikam.com ausführen, gibt es das Attribut
primaryGroupID und die Einträge des Multiwert-Attributs memberOf aller Benutzerkonten
aus:
Primary Group ID: 513
CN=Richtlinien-Ersteller-Besitzer,CN=Users,DC=TestOrga,DC=com
CN=Domänen-Admins,CN=Users,DC=TestOrga,DC=com
CN=Organisations-Admins,CN=Users,DC=TestOrga,DC=com
CN=Schema-Admins,CN=Users,DC=TestOrga,DC=com
CN=Administratoren,CN=Builtin,DC=TestOrga,DC=com

Gast ist Mitglied von:


Primary Group ID: 514
CN=Gäste,CN=Builtin,DC=TestOrga,DC=com

Remoterouter ist Mitglied von:


Primary Group ID: 513

Seite 294 von 394


Attribut memberOf ist nicht vorhanden

SUPPORT_388945a0 ist Mitglied von:


Primary Group ID: 513
CN=Hilfedienstgruppe,CN=Users,DC=TestOrga,DC=com

Root Directory Service Entry


Ein Element, das zur Erstellung eines ADsPfads eines Objekts verwendet werden kann, ist der
Root Directory Service Entry (rootDSE). Der rootDSE ist der Stamm des Verzeichnisses - er
ist ein nützliches ADSI-Feature, da er es einem Script ermöglicht, wichtige Informationen
über das Stammverzeichnis abzurufen. So sind Sie in der Lage, keine DNs fest in das Script
eintragen zu müssen.
Bis jetzt haben alle Scripte in diesem Kapitel ein ADSI-Feature verwendet, das sich
serverlose Bindung nennt. Serverlose Bindung bedeutet, dass im Script kein Name eines
Domänencontrollers eingetragen werden muss. Stattdessen sucht ADSI einen
Domänencontroller der Standarddomäne, der die Bindungsanfrage verarbeiten kann. Bei der
Standarddomäne handelt es sich normalerweise um die Domäne, an der Sie angemeldet sind.
Bisher musste in allen Scripte in diesem Kapitel aufgrund der serverlosen Bindung der DN in
den ADsPfaden fest eingetragen werden .Die Scripte arbeiten daher nur in der Gesamtstruktur
fabrikam.com. Mit dem rootDSE können Sie die Scripte so ändern, dass sie auch in anderen
Gesamtstrukturen arbeiten.

Verwendung des rootDSE


Zu Verwendung des rootDSE sind drei grundlegende Schritte erforderlich.
1.Eine Bindung zum rootDSE aufbauen.
2.Verwenden der Methode Get, um Attribute des rootDSE zu lesen.
3.Verwenden der Attribute zum Erstellen des ADsPfads, um eine Bindung an einen Container
oder ein Objekt zu erstellen.
Die Schritte 2 und 3 werden oft in einem Schritt kombiniert.
Die vier Scripte in diesem Abschnitt sollen die Verwendung des rootDSE verdeutlichen.

Binden an die aktuelle Domäne


Script 5.42 baut mit Hilfe des Attributs defaultNamingContext des rootDSE eine Bindung an
die aktuelle Domäne auf. Die aktuelle Domäne ist die, an der der Client angemeldet ist. Indem
Sie die Bindung verändern, können Sie auch eine Bindung an einem bestimmten Container
der Methode aufbauen (zum Beispiel Users). Das Script führt die folgenden Schritte durch:
1.Es baut eine Bindung zum rootDSE auf.
2.Es erstellt den ADsPfad der aktuellen Domäne.
3.Es verwendet die Variable strADsPath für die Bindung an das Zielobjekt.

Script 5.42: Erstellen des ADsPfads mit Hilfe des rootDSE

1Set objRootDSE = GetObject("LDAP://rootDSE")


2strADsPath = "LDAP://" & objRootDSE.Get("defaultNamingContext")

Seite 295 von 394


3Set objDomain = GetObject(strADsPath)
In der Domäne na.fabrikam.com enthält die Variable strADsPath den Wert:
LDAP://DC=na,DC=fabrikam,DC=com
Binden an die Stammdomäne
Script 5.43 baut eine Bindung an die Stammdomäne auf - hierbei ist es egal, an welcher
Domäne der Client angemeldet ist.

Script 5.43: Erstellen des ADsPfads der Stammdomäne über den rootDSE

1Set objRootDSE = GetObject("LDAP://rootDSE")


2strADsPath = "LDAP://" & objRootDSE.Get("rootDomainNamingContext")
3Set objRootDomain = GetObject(strADsPath)
Wenn Sie das Script in einer Domäne in der Gesamtstruktur fabrikam.com ausführen, enthält
die Variable strADsPath den Wert:
LDAP://DC=fabrikam,DC=com
Binden an den Container Configuration
Script 5.44 baut eine Bindung an den Container configuration der Gesamtstruktur auf.

Script 5.44: Erstellen des ADsPfads des Containers Configuration mit dem rootDSE

1Set objRootDSE = GetObject("LDAP://rootDSE")


2strADsPath = "LDAP://" & objRootDSE.Get("configurationNamingContext")
3Set objConfiguration = GetObject(strADsPath)
Wenn das Script in einer Domäne der Gesamtstruktur fabrikam.com ausgeführt wird, dann
enthält die Variable strADsPath den Wert:
LDAP://CN=Configuration,DC=fabrikam,DC=com
Binden an den Container Schema
Script 5.45 baut eine Bindung an den Container schema der Gesamtstruktur auf.

Script 5.45: Erstellen des ADsPfads des Containers Schema mit dem rootDSE

1Set objRootDSE = GetObject("LDAP://rootDSE")


2strADsPath = "LDAP://" & objRootDSE.Get("schemaNamingContext")
3Set objSchema = GetObject(strADsPath)
Wenn das Script in einer Domäne der Gesamtstruktur fabrikam.com ausgeführt wird, dann
enthält die Variable strADsPath den Wert:
LDAP://CN=Schema,CN=Configuration,DC=fabrikam,DC=com

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.

Die Active Directory-Architektur

Seite 296 von 394


Ein grundlegendes Verständnis der physikalischen und logischen Active Directory-Struktur
hilft Ihnen bei der erfolgreichen Erstellung von ADSI-Scripten. Wenn Sie zum Beispiel
wissen, wie Sie herausfinden, welche Attribute ein Objekt verwendet, dann können Sie auch
über ein Script auf diese Attribute zugreifen. Außerdem sollten Sie wissen, welche Attribute
auf dem globalen Katalog-Server gespeichert und indiziert werden.
Die physikalische Struktur von Active Directory gibt wieder, wo die Elemente gespeichert
werden und über welche Komponenten auf diese Elemente zugegriffen werden kann. Die
logische Struktur definiert, wie Active Directory über ADSI und andere Werkzeuge verwaltet
wird.

Die physikalische Architektur


Active Directory setzt sich aus zwei primären Komponenten zusammen: dem Active
Directory-Speicher und den Komponenten, über auf Active Directory zugegriffen werden
kann (DLLs).
Der Active Directory-Speicher stellt einen sicheren, durchsuchbaren und hierarchischen
Speicher für Objekte (Benutzer, Computer, Drucker, Anwendungen, usw.) zur Verfügung.
Der Active Directory-Speicher befindet sich in einer Datei mit dem Namen Ntds.dit
(Windows NT® Directory Services Directory Information Tree).
Bei den erforderlichen Komponenten zum Zugriff auf Active Directory handelt es sich um:

Die Extensible Storage Engine - Schreibt und liest Daten aus dem Active Directory-
Speicher (Ntds.dit). Die Extensible Storage Engine (ESE) führt Schreiboperationen als
direkte Transaktionen durch. Sie sichert die Ntds.dit über Protokolldateien - über diese
können Transaktionen rückgängig gemacht werden und Wiederherstellungen der Datenbank
durchgeführt werden.

Eine Datenbankschicht - Stellt eine objektsorientierte, hierarchische Ansicht der Daten im
Active Directory-Speicher zur Verfügung.

Den DSA (Directory System Agent) - ADSI-Provide und andere Schnittstellen verwenden
den DAS, um eine Verbindung mit der Datenbankschicht aufzubauen und auf den Active
Directory-Speicher zuzugreifen. Der DSA arbeitet als Vermittler und stellt sicher, dass die
Clientaktionen mit den Regeln für die entsprechenden Active Directory-Objekte
übereinstimmen. Ungültige Aktionen (zum Beispiel das Schreiben eines zu langen Werts in
ein Attribut oder das Erstellen eines Objekts ohne alle verpflichtenden Attribute zu
definieren) lässt der DSA nicht zu. Der DSA ist außerdem ein integraler Bestandteil der
Active Directory-Replikation

Das LDAP-Protokoll (Lightweight Directory Access Protocol) - Eine Protokollschicht,
die zur Kommunikation mit LDAP-fähigen Verzeichnisdiensten wie Active Directory
verwendet werden kann.

Die logische Struktur


Wenn Sie einen Computer unter Windows 2000 Server zu einem Domänencontroller machen,
dann wird der Active Directory-Speicher auf diesem Domänencontroller eingerichtet - vor der
vollständigen Einrichtung müssen Sie die Beziehung des neuen Domänencontrollers zu den
vorhandenen Domänencontrollern angeben. Der Domänencontroller kann für eine neue
Domäne oder für eine vorhandene Domäne konfiguriert werden.

Seite 297 von 394


Um skalierbar zu sein, kann Active Directory Tausende von Domänen unterstützen. Alle
Domänen können in Form einer Hierarchie verbunden werden. Eine einzelne Hierarchie wird
Struktur genannt. Mehrere Strukturen sind eine Gesamtstruktur.

Klassen und Attribute


In jeder Active Directory-Gesamtstruktur gibt es ein Schema. Beim Schema handelt es sich
um eine Bibliothek, in der alle Objekte hinterlegt sind, die in Active Directory erstellt werden
können. Sie können sich das Schema als Sammlung von Vorlagen vorstellen. Das Schema
enthält Klassen und Attribute.Klassen werden von Active Directory zur Erstellung von
Objekten verwendet. Die Klassen setzen sich aus einzelnen Attributen zusammen. Die
Objekte, die aufgrund einer Klasse erstellt werden, verwenden daher alle Attribute der Klasse.
Bei den Objekten handelt es sich um die logischen Gegenstücke zu den tatsächlichen
Objekten im Netzwerk (zum Beispiel Computer, Benutzer oder Drucker). In Abbildung 5.6
sehen Sie die Beziehungen zwischen den Attributen und Klassen im Schema und den aus
diesen erstellten Objekten (Instanzen).

Abbildung 5.6: Attribute, Klassen und Objekte und deren Beziehungen


Wenn ein Objekt auf Grundlage einer Klasse erstellt wird, dann wird dieser Vorgang
Instanzierung genannt. Ein Objekt, das Aufgrund einer Klasse erstellt wurde, wird Instanz
genannt. Jede Klasse definiert einen Objekttyp. Die Attribute in einer Klasse beschreiben
diese Klasse (bzw. den aus ihr zu erstellenden Objekttyp). Die Klasse Computer enthält zum
Beispiel das Attribut cn mit dem Wert Computer und das Attribut lDAPDisplayName mit dem
Wert computer. Jedes der beiden Attribute hat eine Funktion. Sie haben zum Beispiel
gesehen, dass das Attribut lDAPDisplayName vom LDAP-Provider zum Zugriff auf das
Objekt verwendet wird.

Verpflichtende (Mandatory) und optionale Attribute


Zwei weitere Attribute einer Klasse sind systemMustContain und systemMayContain. Diese
Attribute definieren, welche Attribute eines Objekts verpflichtend (systemMustContain) und
welche Attribute optional sind.
Script 5.46 liest alle verpflichtenden und optionalen Attribute der Klasse Computer aus.
Hierzu führ das Script die folgenden Schritte durch:
1.Es verwendet den Befehl On Error Resume Next.
2.Es definiert die Konstante E_ADS_PROPERTY_NOT_FOUND mit dem Wert
&h8000500D. Diese wird später verwendet, um festzustellen, ob die Attribute

Seite 298 von 394


systemMustContain oder systemMayContain vorhanden sind (Zeilen 10 und 21).
3.Es verwendet den rootDSE, um den Wert des Attributs schemaNamingContext abzufragen.
Weitere Informationen über den rootDSE finden Sie im Abschnitt Root Directory Service
Entry weiter oben in diesem Kapitel.
4.Es baut über die Funktion GetObject und den Provider LDAP eine Bindung zur Klasse
computer im Container schema auf.
5.Es initialisiert die Variable arrMandatoryAttributes mit dem Attribut systemMustContain
(Zeile 9).

Wenn hier der Fehlerwert aus der Konstante E_ADS_PROPERTY_NOT_FOUND
zurückgegeben wird, dann gibt das Script eine Nachricht aus ("Keine verpflichtenden
Attribute").

Andernfalls wird eine For-Each-Schleife verwendet, um die Namen aller verpflichtenden
Attribute der Klasse computer zu lesen und auszugeben.
1.Es initialisiert die Variable arrOptionalAttributes mit dem Wert des Attributs
systemMayContain (Zeile 20).

Wenn hier der Fehlerwert aus der Konstante E_ADS_PROPERTY_NOT_FOUND
zurückgegeben wird, dann gibt das Script eine Nachricht aus ("Keine optionalen Attribute").

Andernfalls wird eine For-Each-Schleife verwendet, um die Namen aller optionalen Attribute
der Klasse computer zu lesen und auszugeben.

Script 5.46: Auslesen der verpflichtenden und optionalen Attribute der Klasse computer

1 On Error Resume Next


2 Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
3 strClassName = "cn=Computer"
4
5 Set objRootDSE = GetObject("LDAP://rootDSE")
6 Set objSchemaClass = GetObject("LDAP://" & strClassName & "," & _
7 objRootDSE.Get("schemaNamingContext"))
8
9 arrMandatoryAttributes = objSchemaClass.GetEx("systemMustContain")
10If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then
11 Wscript.Echo "Keine verpflichtenden Attribute"
12 Err.Clear
13Else
14 Wscript.Echo "Verpflichtende Attribute"
15 For Each strAttribute in arrMandatoryAttributes
16 Wscript.Echo strAttribute
17 Next
18End If
19
20arrOptionalAttributes = objSchemaClass.GetEx("systemMayContain")
21If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then
22 Wscript.Echo "Keine optionalen Attribute"
23 Err.Clear
24Else
25 Wscript.Echo VbCrLf & "Optionale Attribute "
26 For Each strAttribute in arrOptionalAttributes
27 Wscript.Echo strAttribute
28 Next
29End If

Seite 299 von 394


Wenn Sie das Script ausführen, gibt es die Nachricht "Keine verpflichtenden Attribute" aus
und dann die optionalen Attribute:
Keine verpflichtenden Attribute

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.

Vererbung und Kategorisierung von Klassen


Nicht nur Active Directory verwendet eine hierarchische Struktur (Domänen sind in
Strukturen und Gesamtstrukturen zusammengefasst), sondern auch die Klassen im Schema.
Einige Attribute werden in dieser Hierarchie von einer Klasse zur anderen vererbt - andere
Attribute werden direkt in den Klassen definiert. Das Objekt, das aus einer Klasse erstellt
wird, enthält dann alle Attribute - die geerbten und die in der Klasse definierten.
Ein Computerobjekt erbt zum Beispiel Attribute von der Klasse user. Wenn wir die
Klassenhierarchie weiter nach oben gehen, werden Attribute von den Klassen
organizationalPerson, person und top geerbt. Die Klasse user enthält auch Attribute, die
direkt über die Klassen mailRecipient und securityPrincipal angewandt werden. Die Klasse
securityPrincipal enthält wiederum das Attribut sAMAccountName - dieses ist für alle
Klassen, die das Attribut erben, verpflichtend. Daher erbt auch die Klasse computer das
verpflichtende Attribut sAMAccountName.
Es gibt noch weitere Informationen, die Sie der Klassenhierarchie entnehmen können. Die
Klasse contact ist zum Beispiel kein Sicherheitsprinzipal- und zwar darum, weil die Klasse
securityPrincipal nicht auf die Klasse contact angewandt wird und diese daher nicht die
Attribute der Klasse securityPrincipal erbt.
Klassen sind in die Kategorien Abstract, Structural, Auxiliary und 88 aufgeteilt. Die
Kategorie wird im Attribut objectClassCategory einer Klasse als Integer-Wert gespeichert.

Abstract - Die Attribute dieser Klassen werden in der Hierarchie vererbt. Es können jedoch
keine Objekte aus diesen Klassen erstellt werden. Der Integer-Wert für diese Klasse ist 2.

Auxiliary - Die Attribute dieser Klasse erweitern eine Klasse vom Typ Structural. Es kann
jedoch keine Klasse von Typ Structural oder ein Objekt aus dieser Klasse erstellt werden.
Der Integer-Wert für diese Klasse ist 3.

Structural - Aus dieser Klasse können neue Instanzen von Objekten erstellt werden. Diese
Klasse kann Attribute enthalten, die nicht von anderen Klassen geerbt werden. Der Integer-

Seite 300 von 394


Wert für diese Klasse ist 1.

88 - Diese Klassen wurden definiert, bevor es Klassenkategorien gab. Sie verhalten sich wie
Klassen der Kategorie Structural - aus ihnen können Instanzen von Objekten erstellt werden.
Der Integer-Wert für diese Klasse ist 0.
Active Directory ist kompatibel mit dem X.500-Standard. Daher müssen auch die 1993 in
diesem Standard definierten Kategorien verwendet werden. Alle Klassen, die vor 1993
definiert wurden, entsprechen dem X.500-Standard von 1988. Dieser enthält keine
Kategorien. Daher enthält die Kategorie 88 alle Klassen, die bis 1993 definiert wurden.
Script 5.47 liest das Attribut objectClassCategory der Klassen Top, Mail-Recepient, Security-
Principal, Person, Organizational-Person, Contact, User, Computer und Organizational-
Unit. Hierzu führt das Script die folgenden Schritte durch:
1.Es initialisiert ein Array mit den allgemeinen Namen (CNs) der Klassen.
Die Funktion GetObject benötigt den CN der Klasse - nicht den lDAPDisplayName.
2.Es verwendet den rootDSE, um den Wert des Attributs schemaNamingContext abzufragen.
3.Es verwendete eine For-Each-Schleife, um über die Funktion GetObject und den Provider
LDAP eine Bindung an die einzelnen Klassen im Container Schema aufzubauen.
4.Es initialisiert die Variable intClassCategory mit dem Integer-Wert des Attributs
objectClassCategory.
5.Es verwendet eine Select-Case-Anweisung, um den Wert der Variable intClassCategory zu
prüfen und den Typ der jeweiligen Klasse anzuzeigen.

Script 5.47: Lesen des Attributs objectClassCategory mehrerer Klassen

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

Seite 301 von 394


cn=mail-Recipient is auxiliary
cn=security-Principal is auxiliary
cn=person is 88
cn=Organizational-Person is 88
cn=contact is structural
cn=user is structural
cn=computer is structural
cn=organizational-Unit is structural
Das Attribut systemAuxiliaryClass jeder Klasse gibt die Klassen vom Typ Auxiliary an, die
direkt auf die Klasse angewandt werden. Script 5.48 liest das Attribut für mehrere Klassen
aus:
1.Es verwendet den Befehl On Error Resume Next und definiert die Konstante
E_ADS_PROPERTY_NOT_FOUND mit dem Wert &h8000500D. Über diese Konstante
wird später geprüft, ob das Attribut systemAuxiliaryClass leer ist.
2.Es initialisiert ein Array mit den CNs der Klassen.
3.Es verwendet den rootDSE, um den Wert des Attributs schemaNamingContext abzufragen.
4.Es verwendet eine For-Each-Schleife, um über die Funktion GetObject und dem Provice
LDAP eine Bindung zu den einzelnen Klassen im Container Schema aufzubauen.
5.Es initialisiert die Variable arrSystemAuxiliaryClass mit dem Attribut systemAuxiliaryClass
(Zeilen 15 und 16).

Wenn hier der Fehlerwert in E_ADS_PROPERTY_NOT_FOUND zurückgegeben wird, dann
wird eine entsprechende Meldung ausgegeben.

Andernfalls wird eine For-Each-Schleife verwendet, um die Liste der zur Klasse
zugewiesenen Klassen vom Typ Auxiliary anzuzeigen.

Script 5.48_ Lesen des Attributs systemAuxiliaryClass mehrerer Klassen

1 On Error Resume Next


2 Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
3 arrClassNames = Array _
4 ("cn=top","cn=mail-Recipient", "cn=security-Principal", _
5 "cn=person", "cn=Organizational-Person", _
6 "cn=contact", "cn=user", "cn=computer", "cn=organizational-
7 Unit")
8
9 Set objRootDSE = GetObject("LDAP://rootDSE")
10For Each ClassName in arrClassNames
11 Set objSchemaClass = GetObject("LDAP://" & ClassName & "," & _
12 objRootDSE.Get("schemaNamingContext"))
13
14 arrSystemAuxiliaryClass = _
15 objSchemaClass.GetEx("systemAuxiliaryClass")
16
17 If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then
18 Wscript.Echo "Keine Klassen vom Typ Auxiliary " & _
19 " assigned to " & ClassName
20 Err.Clear
21 Else
22 Wscript.Echo "Auxiliary-Klassen in " & ClassName & ":"
23 For Each strAuxiliaryClass in arrSystemAuxiliaryClass
24 Wscript.Echo vbTab & strAuxiliaryClass
25 Next

Seite 302 von 394


26 Wscript.Echo
27 End If
Next
Wenn sie das Script ausführen, gibt es eine Meldung aus, die anzeigt, das die Auxiliary-Klasse
mailRecipient auf die Klassen contact und user angewandt wird, und dass die Auxiliary-
KlasesecurityPrincipal auf die Klasse user angewandt wird:
No auxiliary classes assigned to cn=top.
No auxiliary classes assigned to cn=mail-Recipient.
No auxiliary classes assigned to cn=security-Principal.
No auxiliary classes assigned to cn=person.
No auxiliary classes assigned to cn=Organizational-Person.
Auxiliary classes in cn=contact:
mailRecipient

Auxiliary classes in cn=user:


securityPrincipal
mailRecipient

No auxiliary classes assigned to cn=computer.


No auxiliary classes assigned to cn=organizational-Unit.
Wenn Sie die Klassenvererbung verstehen, dann hilft Ihnen das dabei Scripte zu schreiben,
die auch die erwarteten Objekte zurückgeben. Wenn Sie zum Beispiel eine Suche nach allen
Objekten durchführen, deren Attribut objectClass den Wert user enthält, dann sind Sie sicher
überrascht, dass Sie auch Objekte zurückerhalten, die aus der Klasse computer erstellt
wurden.
Die Beziehungen zwischen den Klassen können Sie auch über ein Script anzeigen lassen. Das
Attribut subClassOf gibt die übergeordnete Klasse an, von der die Klasse abgeleitet ist. Script
5.49 zeigt, wie Sie dieses Attribut abfragen. Seine Arbeitsweise entspricht den vorherigen
beiden Scripten.

Script 5.49: Lesen des Attributs subClassOf einer Klasse

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.

Das Snap-In Active Directory Schema

Seite 303 von 394


Auf der linken Seite des Snap-Ins sehen Sie zwei Listen:

Die Klassenliste mit allen Klassen des Active Directory-Schemas

Die Attributliste mit allen Attributen des Schemas
Über die Klassenliste können Sie die von einer bestimmten Klasse verwendeten Attribute und
die hierarchischen Beziehungen zwischen den Klassen sehen. Über die Attributliste können
Sie feststellen, wie ein Attribut definiert ist (zum Beispiel, ob das Attribut auf den globalen
Katalog-Server repliziert werden soll, ob es sich um ein Einzelwert- oder Multiwert-Attribut
handelt, usw.).
Das Snap-In Active Directory Schema müssen Sie vor der ersten Verwendung registrieren:
1.Geben Sie in der Eingabeaufforderung den Befehl regsvr32 schmmgmt ein.
(Dieser Schritt muss nur einmal auf jedem Computer durchgeführt werden.)
2.Starten sie eine MMC-Konsole Start MMC, indem Sie MMC in der Eingabeaufforderung
oder im Feld Ausführen eingeben.
3.Klicken Sie auf Datei, Snap-In hinzufügen/entfernen und klicken Sie auf Hinzufügen.
4.Klicken Sie auf Active Directory Schema und dann auf Hinzufügen.

Das Snap-In ADSI Edit


Das Snap-In ADSI Edit zeigt nicht nur Informationen über das Schema, sondern auch über die
Objekte der Domäne an. Wahrscheinlich finden Sie die Informationen über das Schema
jedoch im Snap-In Active Directory Schema übersichtlicher.
Nachdem Sie das Snap-In ADSI Edit geladen haben, können Sie auswählen, wie Sie sich mit
Active Directory verbinden möchten. Die Standard-Verbindungspunkte sind:

LDAP://domain_controller_name/Domain - Informationen über die Objekte der Domäne.

LDAP://domain_controller_name/Configuration - Informationen über die
Konfigurationspartition der Gesamtstruktur.

LDAP://domain_controller_name/RootDSE - Informationen über die Attribute des
RootDSE-Objekts.

LDAP://domain_controller_name/Schema - Informationen über den Schemacontainer der
Gesamtstruktur.

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.

Seite 304 von 394


3.Klicken Sie auf Datei, Snap-In hinzufügen/entfernen und klicken Sie auf Hinzufügen.
4.Klicken Sie auf ADSI Edit und dann auf Hinzufügen.
5.Klicken Sie auf der linken Seite mit der rechten Maustaste auf ADSI Edit und wählen Sie
Connect to.
6.Übernehmen Sie im Fenster Connection Settings die Standardeinstellungen und klicken Sie
auf OK.

Active Directory-Replikation und -Indizierung


Daten werden in Active Directory repliziert. Das bedeutet, dass die Änderungen auf einem
Domänencontroller an alle anderen Domänencontroller übertragen werden.
Ein kritischer Teil der Verwaltung von Active Directory über ADSI-Scripte ist die
Replikation. Um den Replikationsaufwand zu verringern, ist Active Directory in Partitionen
aufgeteilt. Diese Partitionen werden entweder vollständig oder teilweise repliziert. Partitionen
mit einer vollständigen Replikation werden an alle Domänencontroller in der Domäne oder
der Gesamtstruktur übertragen. Sie können also von jedem Domänencontroller in der Domäne
oder Gesamtstruktur gelesen oder geschrieben werden. Partitionen mit einer teilweisen
Replikation werden nur an bestimmte Domänencontroller übertragen. Sie enthalten nur Teile
von Active Directory und können nur gelesen werden.

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.

Attribute, die zum globalen Katalog-Server repliziert werden


Alle Domänencontroller, die als globaler Katalog-Server konfiguriert sind, speichern eine
teilweise Replik aller Domänenpartitionen der Domänen der Gesamtstruktur. Diese Teilreplik
- der globale Katalog - enthält zwar alle Objekte der jeweiligen Domänenpartitionen, aber nur
einen Teil der Attribute dieser Objekte. Wenn Sie effiziente Scripte schreiben möchten, dann
sollten Sie wissen, um welche Attribute es sich handelt. Wenn Sie ohne einen globalen
Katalog-Server Informationen über mehrere Domäne der Gesamtstruktur abfragen möchten,
dann müssen Sie die Eigenschaft Nachverfolgen (chasing) verwenden. Diese sorgt jedoch für
eine höhere Last auf den beteiligten Domänencontrollern. Sie sollten also versuchen jene
Attribute zu verwenden, die auf den globalen Katalog-Server repliziert werden.
Das Attribut isMemberOfPartialAttributeSet eines Attributs im Schema speichert einen
Boolean-Wert. Dieser zeigt, ob das entsprechende Attribut an den globalen Katalog-Server
repliziert wird. In Script 5.50 sehen Sie, wie Sie dieses Attribut abfragen können.

Seite 305 von 394


1.Es initialisiert eine Variable mit dem Namen strAttributeName mit dem CN eines Attributs.
In diesem Beispiel wird das Attribut given-name verwendet.
2.Es verwendet den rootDSE, um den Wert des Attributs schemaNamingContext abzufragen.
3.Es baut über die Funktion GetObject und den Provider LDAP eine Bindung an das Attribut
im Container schema auf.
4.Es initialisiert die Variable blnInGC mit dem Boolean-Wert des Attributs
isMemberOfPartialAttributeSet.

Wenn blnInGC den Wert True hat, dann wird das Attribut an den globalen Katalog-Server
repliziert. Eine entsprechende Meldung wird ausgegeben.

Andernfalls wird das Attribut nicht repliziert. Auch hier wird eine Meldung ausgegeben.

Script 5.50: Lesen des Attributs isMemberOfPartialAttributeSet eines Attributs

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.

Indizierung von Attributen


Ein weiterer wichtiger Aspekt bei der Leistung von Suchen ist, ob das entsprechende Attribut
indiziert wird. Indizierte Attribute sind bereits sortiert - hierdurch wird die Verarbeitungslast
auf dem Domänencontroller verringert.
Das Attribut searchFlags eines Attributs enthält einen Integer-Wert, der unter anderem
anzeigt, ob das Attribut indiziert wird. Script 5.51 zeigt, wie Sie das Attribut abfragen können.
Das Script entspricht zum größten Teil Script 5.50. Es geht 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.

Seite 306 von 394


2.Es verwendet den rootDSE, um den Wert des Attributs schemaNamingContext abzufragen.
3.Es baut über die Funktion GetObject und den Provider LDAP eine Bindung an das Attribut
im Container schema auf.
4.Es initialisiert die Variable intSearchFlags mit dem Integer-Wert des Attributs searchFlags
(Zeile 8).
5.Es verwendet den logischen Operator AND, um den Attributwert mit der konstante
IS_INDEXED zu vergleichen.

Wenn der Vergleich den Wert True zurückgibt, dann wird das Attribut indiziert. Dies wird
mit einer entsprechenden Ausgabe quittiert.

Andernfalls wird das Attribut nicht indiziert. Auch dies wird mit einer Ausgabe bestätigt.

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.

Seite 307 von 394


3.Es verwendet ADO, um alle AttributeSchema-Objekte abzufragen und für diese die Attribute
lDAPDisplayName, isMemberOfPartialAttributeSet und searchFlags zurückzugeben.
Der Filter objectCategory=AttributeSchema gibt alle Schema-Attribute zurück.
4.Es verwendet eine While-Wend-Schleife, um alle Einträge des Ergebnissatzes zu lesen.
5.Bei jedem Eintrag im Ergebnissatz wird festgestellt, ob das Attribut an die globalen
Katalog-Server repliziert wird und ob es indiziert wird (Zeilen 20 und 21).
Wenn beide Bedingungen den Rückgabewert True haben, dann wird das Attribut
lDAPDisplayName des Attributs ausgegeben (aus der Variable strAttribute).

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

Seite 308 von 394


Operative Attribute
Nicht alle Attributwerte werden im Verzeichnisdienst gespeichert. Einige Attributwerte
werden erst dann berechnet, wenn Sie abgefragt werden. Diese Attribute nennt man operative
Attribute. Sie werden wie alle anderen Attribute auch im Schema definiert.
Sie sollten wissen, welche Attribute operative Attribute sind, da Sie diese Attribute nicht in
den lokalen Zwischenspeicher laden können, bevor Sie nicht explizit die Methoden GetInfo
oder GetInfoEx aufgerufen haben.
Script 5.53 fragt ab, welche Attribute im Schema operativ sind. Hierzu geht es
folgendermaßen vor:
1.Es definiert die Konstante ADS_SYSTEMFLAG_ATTR_IS_CONSTRUCTED mit dem Wert
&h4.
2.Es verwendet den rootDSE, um die Variable strADsPath mit dem Attribut
schemaNamingContext zu initialisieren.
3.Es verwendet ADO, um alle Objekte vom Typ AttributeSchema abzufragen und die
Attribute lDAPDisplayName und systemFlags dieser Attribute zurückzugeben.
4.Es verwendet eine While-Wend-Schleife, um jeden Eintrag im Ergebnissatz durchzugehen.
5.Für jeden Eintrag im Ergebnissatz stellt es fest, ob das Attribut operativ ist (Zeilen 19 und
20).

Wenn das der Fall ist, dann zeigt es dass Attribut lDAPDisplayName des Attributs an (aus
der Variable strAttribute).

Script 5.53: Prüfen, ob ein Attribut operativ ist

1 Const ADS_SYSTEMFLAG_ATTR_IS_CONSTRUCTED = &h4


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 "lDAPDisplayName,systemFlags;onelevel"
14
15Set objRecordSet = objCommand.Execute
16Wscript.Echo "Operative Attribute: "
17While NOT objRecordSet.EOF
18 strAttribute = objRecordSet.Fields("lDAPDisplayName")
19 If ADS_SYSTEMFLAG_ATTR_IS_CONSTRUCTED AND _
20 objRecordSet.Fields("systemFlags") Then
21 Wscript.Echo strAttribute
22 objRecordSet.MoveNext
23 End If
24Wend
25
26objConnection.Close

Seite 309 von 394


Wenn Sie das Script ausführen, erhalten Sie eine Ausgabe wie die folgende:
Operative Attribute:
allowedAttributes
allowedAttributesEffective
allowedChildClasses
allowedChildClassesEffective
aNR
attributeTypes
canonicalName
createTimeStamp
...

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

Seite 310 von 394


In Abbildung 5.7 sehen Sie, wie der LDAP-Provider eine Instanz eines COM-Objekts erstellt.
Der Provider stellt fest, dass MyerKen in der OU HR der Domäne na.fabrikam.com ein
Benutzerobjekt ist. Daher erstellt er ein COM-Objekt mit den Schnittstellen zur Arbeit mit
Benutzerobjekten. In der Abbildung sind nur drei Schnittstellen zu sehen. IADs und IADsUser
sind zwei Schnittstellen, die ADSI-Scripte bei der Arbeit mit Benutzerobjekten verwenden,
und die Schnittstelle IUnknown wird an jedes COM-Objekt angehängt - sie ist die
Basisschnittstelle für alle anderen Schnittstellen..
Mit dem Befehl Set erhalten Sie in der Variable objUser eine Referenz auf das neue Objekt.

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

Seite 311 von 394


Abbildung 5.8: Die ADSI-Architektur
Die fünf Schichten aus Abbildung 5.8 finden sich auf zwei Seiten wieder. Die unterste
Schicht (Verzeichnis oder Namespace) befindet sich auf den Computern, die Active Directory
zur Verfügung stellen (den Domänencontrollern), und die restlichen Schichten befinden sich
auf den Clients.

Verzeichnis oder Namespace


Der Verzeichnisdienst (Active Directory) speichert Informationen und stellt diese
Informationen Benutzern und Anwendungen zur Verfügung. Beim Verzeichnisdienst handelt
es sich um eine Datenbank.
Ein Namespace ist ein Bereich, in dem Namen aufgelöst werden können. Der DNS-
Namespace (Domain Name System) ist zum Beispiel ein Domänenbaum, der Hostnamen und
IP-Adressen speichert. Die Clientcomputer verwenden den DNS-Namespace, um Hostnamen
in IP-Adressen aufzulösen. Ein Verzeichnis-Namespace ist ein Bereich, in dem die Namen
von Verzeichniselementen in die entsprechenden Objekte aufgelöst werden können. Bei
Active Directory handelt es sich beim Namespace um die Gesamtstruktur. Die Namen der
einzelnen Active Directory-Objekte können über diesen Namespace in Objekte (zum Beispiel
Domänen, Benutzerkonten, OUs und Computer) aufgelöst werden.

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)

Seite 312 von 394



IIS-Metabase (Internet Information Services)

NDS (Novell NetWare Directory Services)

NetWare Bindery
ADSI-Provider greifen auf den Namespace zu und erstellen virtuelle Gegenstücke für die
Objekte, die Sie über die ADSI-Schnittstellen bearbeiten wollen. Unter den ADSI-DLLs gibt
es hierzu einige Provider-DLLs (Tabelle 5.5).

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.

Anmerkung: Bei den Providernamen wird zwischen Groß- und Kleinbuchstaben


unterschieden. Achten daher Sie besonders beim Provider WinNT auf die korrekte
Schreibweise.
Die Bindung an ein Verzeichnis unterscheidet sich bei den unterschiedlichen Providern. Sie
beginnt jedoch immer mit dem Namen des Providers, gefolgt von einem Doppelpunkt und
zwei Slash-Zeichen. Danach muss der Pfad zu dem Verzeichnis angegeben werden, zu dem
Sie die Bindung aufbauen möchten.
Wie bereits weiter oben in diesem Kapitel erklärt, handelt es sich beim ADsPfad (AdsPath)
um den Namen des Providers und den Pfad zum Verzeichnisobjekt. Beispiele für ADsPfade
sind:

LDAP-Provider mit dem Pfad zu einem Domänencontroller der Domäne
na.fabrikam.com:
LDAP://dc=NA,dc=fabrikam,dc=com.
Beachten Sie, dass in diesem Beispiel kein bestimmter Domänencontroller angegeben wird
sondern nur der Name der Domäne selbst. Diese Art der Bindung wird serverlose Bindung
genannt.

GC-Provider mit Pfad zu einem globalen Katalog-Server der Domäne
Seite 313 von 394
na.fabrikam.com:
GC://dc=NA,dc=fabrikam,dc=com.

WinNT-Provider mit Pfad zu einem Domänencontroller der Domäne na.fabrikam.com:
WinNT://NA.

IIS-Provider mit Pfad zum IIS-Server sea-dc-01.na.fabrikam.com:
IIS://sea-dc-01.na.fabrikam.com.

NDS-Provider mit Pfad zum Verzeichnisserver der Domäne na.fabrikam.com:
NDS://server01/o=org01/dc=com/dc=fabrikam/dc=na.

NWCOMPAT-Provider mit Pfad zu einem Bindery-Server:
NWCOMPAT://server01.
Der Provider ADSI OLE DB verwendet dieselbe Syntax für den ADsPfad wie die Provider
LDAP und GC - nur mit einigen weiteren Parametern. Diese Parameter definieren die
zurückzugebenden Suchergebnisse.

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.

Script 5.54: Eine Liste der installierten ADSI-Provider anzeigen

1Set objProvider = GetObject("ADs:")


2For Each Provider In objProvider
3 Wscript.Echo Provider.Name
4Next
Wenn Sie das Script ausführen, erhalten Sie eine Liste der installierten ADSI-Provider. Die
folgende Ausgabe wurde zum Beispiel auf einem Computer unter Windows 2000 Professional
generiert:
WinNT:
NWCOMPAT:
NDS:
LDAP:
IIS:

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.

Seite 314 von 394


Eigenschafts-Zwischenspeicher
Gleich nach dem Aufbau der Bindung wird ein Speicherbereich für das virtuelle Active
Directory-Objekt reserviert. Das Objekt und seine Attribute werden jedoch noch nicht aus
Active Directory heruntergeladen.

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."

Kategorisierung von Schnittstellen


Die Kategorisierung der Schnittstellen vereinfacht die Suche nach der passenden Schnittstelle
für eine bestimmte Aufgabe. In Tabelle 5.6 sehen Sie die Schnittstellenkategorien, eine
allgemeine Beschreibung zu den Kategorien und die Schnittstellen in diesen Kategorien.

Tabelle 5.6: Schnittstellen, die der LDAP-Provider implementiert


Kategorie Verwendung durch den LDAP- Schnittstellen
Provider
Core Allgemeine Schnittstelle für die IADs, IADsContainer, IADsNamespaces,
Interaktion mit fast jedem Objekt IADsOpenDSObject
eines Verzeichnisses.
Schema Zur Verwaltung und Erweiterung IADsClass, IADsProperty, IADsSyntax
des Schemas.
Property Zur Interaktion mit dem lokalen IADsPropertyEntry, IADsPropertyList,
Cache Zwischenspeicher. IADsPropertyValue, IADsPropertyValue2
Persistent Zur Interaktion mit bestimmten IADsGroup, IADsLocality, IADsMembers,
Object Objekttypen. IADsO, IADsOU, IADsPrintQueue,
IADsUser

Seite 315 von 394


Kategorie Verwendung durch den LDAP- Schnittstellen
Provider
Dynamic Zur Interaktion mit den IADsPrintQueueOperations
Object veröffentlichten Druckern.
Security Zur Interaktion mit DACLs von IADsAccessControlEntry,
Objekten. IADsAccessControlList,
IADsSecurityDescriptor
Non- Low-Level-Zugriff auf Objekte. IDirectoryObject, IDirectorySearch
Automation Stehen über Scriptsprachen nicht zur
Verfügung.
Extension Zum Hinzufügen von Methoden zu IADsExtension
bestehenden Objekten.
Utility Hilfsfunktionen. IADsDeleteOps, IADsPathname,
IADsObjectOptions
Data Type Verarbeitung von Attributen, die als IADsLargeInteger
Datentyp Large Integer (64-Bit)
gespeichert sind.

LDAP-Provider-Objekte und deren Schnittstellen


Indem die Schnittstellen nach den von ihnen unterstützen Objekten in Gruppen eingeteilt
werden, ist es einfacher, die Methoden und Eigenschaften eines Objektes festzustellen. Eine
Tabelle der ADSI-Objekttypen des DAP-Providers finden Sie unter dem Link Active
Directory Programmer's Guidehttp://www.microsoft.com/windows/reskits/webresources.
Suchen Sie dort nach dem Text "ADSI Objects of LDAP." Tabellen zu den anderen Providern
finden Sie, indem Sie nach den Texten "ADSI Objects for WinNT", "ADSI Objects for NDS"
und "ADSI Objects of NWCOMPAT" suchen.

Eigenschaften von IAD


Die Schnittstelle IAD stellt sechs schreibgeschützte Eigenschaften zur Verfügung, über die
Sie jedes Objekt im Verzeichnis identifizieren können.

AdsPath - gibt einen String mit dem vollqualifizierten Pfad des Objekts zurück

Class - gibt einen String mit dem Namen der Schemaklasse des Objekts zurück.

GUID - gibt einen String mit der GUID (Globally Unique Identifier) des Objekts zurück.

Name - gibt einen String mit dem RDN eines Objekts zurück.

Parent - gibt einen String mit dem ADsPfad des übergeordneten Objekts zurück.

Schema - gibt einen String mit der Schemaklasse des Objekts zurück.
Script 5.55 zeigt mit Hilfe der IAD-Eigenschaften Informationen über die Domäne
na.fabrikam.com an.

Script 5.55: Abfragen von Informationen über die IAD-Eigenschaften

1Set objDomain = GetObject("LDAP://dc=NA,dc=fabrikam,dc=com")

Seite 316 von 394


2Wscript.Echo "ADsPath:" & objDomain.ADsPath
3Wscript.Echo "Class:" & objDomain.Class
4Wscript.Echo "GUID:" & objDomain.GUID
5Wscript.Echo "Name:" & objDomain.Name
6Wscript.Echo "Parent:" & objDomain.Parent
7Wscript.Echo "Schema:" & objDomain.Schema
Wenn Sie das Script ausführen, erhalten Sie die folgende Ausgabe:
ADsPath:LDAP://dc=NA,dc=fabrikam,dc=com
Class:domainDNS
GUID:618a1da520255a41ab778f5dc1d8da4d
Name:dc=NA
Parent:LDAP://dc=fabrikam,dc=com
Schema:LDAP://schema/domainDNS
Eigenschaften von IADsContainer
IADsContainer stellt nur eine schreibgeschützte Eigenschaft zur Verfügung.

Filter - gibt die Klassen der gefilterten Objekte zurück.
Script 5.56 demonstriert die Verwendung der Eigenschaft Filter. Es listet die Inhalte der OU
HR auf.

Script 5.56: Anzeigen der Eigenschaft Filter

1Set objOU = GetObject("LDAP://OU=HR,dc=NA,dc=fabrikam,dc=com")


2ObjOU.Filter= Array("Computer", "User")
3Wscript.Echo "Filter:"
4For each strObject in objOU.Filter
5 Wscript.Echo vbTab & strObject
6Next
Wenn Sie das Script ausführen, erhalten Sie die folgende Ausgabe:
Filter:
Computer
User
Weitere Informationen über die Methoden von IADsContainer finden Sie in den
entsprechenden Abschnitten dieses Kapitels:

Filter - Auflistender Active Directory-Objekte in einem Container

Create - Erstellen von Active Directory-Objekten

Delete - Löschen von Active Directory-Objekten

MoveHere - Verschieben und Umbenennen von Objekten

Scripting-Konzepte und -Technologien zur


Systemadministration - Kapitel 6 - WMI-
Scripting
Veröffentlicht: 26. Apr 2004

Seite 317 von 394


(Engl. Originaltitel: WMI Scripting Primer)
Bei WMI (Windows Management Instrumentation) handelt es sich um die wichtigste
Verwaltungstechnologie der Microsoft Windows-Betriebssysteme. Mit WMI ist eine
konsistente und einheitliche Verwaltung, Steuerung und Überwachung der einzelnen Systeme
im gesamten Unternehmen möglich. WMI basiert auf Industriestandards und ermöglicht es
Systemadministratoren, die Konfiguration von Arbeitsstationen, Servern, Anwendungen,
Netzwerken und anderen Komponenten abzufragen, zu ändern und zu überwachen. Scripte
können die WMI-Script-Bibliothek verwenden.

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.

Die Möglichkeiten von WMI


Mit dem WSH und VBScript können Sie WMI-Scripte für die folgenden Bereiche schreiben:

Verwaltung von Computern unter Windows Server 2003, Windows XP Professional
und Windows 2000
Mit WMI-Scripten können Sie Ereignisprotokolle, Dateisystem, Drucker, Prozesse,

Seite 318 von 394


Registrierungseinstellung, geplante Tasks, Sicherheitseinstellung, Dienste, Freigaben und
eine Vielzahl anderer Komponenten verwalten.

Netzwerke
Sie können zum Beispiel Dienste wie DNS, clientseitige Einstellungen (zum Beispiel die
TCP/IP-Einstellungen) und SNMP-Geräte verwalten.

Echtzeitüberwachung
Sie können zum Beispiel das Auftreten von Ereignissen, die Leistungsanzeige, das
Dateisystem oder die Registrierung überwachen.

Serveranwendungen
Sie können zum Beispiel MOM-, SMS-, Exchange- und SQL-Server überwachen.
In einigen Fällen stellt WMI ihnen die gleichen Funktionalitäten wie ein
Kommandozeilenwerkzeug oder eine GUI-Anwendung zur Verfügung. In anderen Fällen
kann WMI Aufgaben ausführen, die über keinen anderen Weg durchführbar sind. Vor WMI
war es zum Beispiel nicht möglich, über ein Script die Menge des installierten RAMs
abzufragen - zumindest nicht ohne ein Drittanbieter-Tool. Mit WMI haben Sie die
Möglichkeit, das installierte RAM von jedem Computer abzufragen, auf dem Sie über die
nötigen administrativen Rechte verfügen. Script 6.1 demonstriert dies.

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.

Script 6.1: Abfragen und Anzeigen des installierten Hauptspeichers

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

Seite 319 von 394


können. Die Eigenschaften der Klassen entsprechen normalerweise den Eigenschaften der
Ressourcen, die durch die Klasse repräsentiert werden. Festplatten haben zum Beispiel
Eigenschaften wie Leseköpfe (Heads), Sectoren (Sectors) und Zylinder (Cylinders). Daher
verfügt auch die Klasse Win32_DiskDrive über Eigenschaften wie TotalHeads, TotalSectors
und TotalCylinders.
Zusätzlich zum physikalischen Speicher gibt es unter Windows-basierten Computern den
virtuellen Speicher. Es ist daher nicht wirklich überraschend, dass die Klasse
Win32_LogicalMemoryConfiguration eine Eigenschaft mit dem Namen TotalVirtualMemory
zur Verfügung stellt. Wie Sie die Größe des virtuellen Speichers abfragen können, sehen Sie
in Script 6.2. Der einzige wirkliche Unterschied zu Script 6.1 ist das fett geschriebene
Element.

Script 6.2: Abfragen und Anzeigen des virtuellen Speichers

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.

Script 6.3: Abfragen und Anzeigen von Informationen über Dienste

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

Seite 320 von 394


Status: Stopped
Starttyp: Manual
Name: WMI-Leistungsadapter
Status: Stopped
Starttyp: Manual
Name: Automatische Updates
Status: Running
Starttyp: Auto
Name: Konfigurationsfreie drahtlose Verbindung
Status: Running
Starttyp: Auto
Wenn Sie sich Script 6.3 genauer ansehen, dann werden Sie zwei Dinge bemerken:

Statt der Klasse Win32_LogicalMemoryConfiguration verwendet das Script eine Klasse mit
dem Namen Win32_Service. Warum? Weil das Script Informationen über Dienste
zurückgeben soll und nicht über den Hauptspeicher. Wenn das Script zum Beispiel
Informationen über einen Monitor zurückgeben würde, dann würde es die Klasse
Win32_DesktopMonitor verwenden. Mit der verwalteten Ressource ändert sich also auch die
verwendete Klasse.

Die abgefragten Eigenschaften unterscheiden sich von den Eigenschaften in den vorherigen
Scripten. Warum? Die Klasse Win32_Service stellt natürlich andere Eigenschaften als die
Klasse Win32_LogicalMemoryConfiguration zur Verfügung. Eine Klasse stellt immer die
Eigenschaften zur Verfügung, die auch die verwaltete Ressource hat, die durch die Klasse
repräsentiert wird.
Wenn Sie nun ein Muster erkennen, dann haben Sie bereits einen großen Schritt beim
Erlernen von WMI-Scripting hinter sich. WMI-Scripte fragen die Informationen über die
verwalteten Ressourcen fast alle gleich ab. Es ändern sich nur die Namen der Klassen und
deren Eigenschaften.
Wie Sie in diesem Kapitel sehen werden, arbeiten WMI-Scripts normalerweise in drei
Schritten:
1.Sie verbinden Sich mit dem WMI-Dienst.
2.Sie fragen Informationen über WMI-Klassen ab.
3.Sie verarbeiten die Informationen auf irgendeine Weise weiter (zum Beispiel werden diese
ausgegeben).
Alle WMI-Scripte folgen diesem Muster. Stellen Sie sich zum Beispiel vor, Sie möchten ein
Script schreiben, das die Einträge aus dem Ereignisprotokoll abfragt und anzeigt. Mit dem
Scriptcode aus Script 6.1 können Sie ein solches Script ganz schnell erstellen - Script 6.4
demonstriert dies.

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.

Script 6.4: Abfragen und Anzeigen von Ereignissen

1 strComputer = "."
2
3 Set objSWbemServices = GetObject("winmgmts:\\" & strComputer)

Seite 321 von 394


4 Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_NTLogEvent")
5 For Each objSWbemObject In colSWbemObjectSet
6 Wscript.Echo _
7 "Protokolldatei: " & objSWbemObject.LogFile & vbCrLf & _
8 "Nummer: " & objSWbemObject.RecordNumber & vbCrLf & _
9 "Typ: " & objSWbemObject.Type & vbCrLf & _
10 "Uhrzeit: " & objSWbemObject.TimeGenerated & vbCrLf & _
11 "Quelle: " & objSWbemObject.SourceName & vbCrLf & _
12 "Kategorie: " & objSWbemObject.Category & vbCrLf & _
13 "Kateogrie-Name: " & objSWbemObject.CategoryString & vbCrLf & _
14 "Ereignis: " & objSWbemObject.EventCode & vbCrLf & _
15 "Benutzer: " & objSWbemObject.User & vbCrLf & _
16 "Computer: " & objSWbemObject.ComputerName & vbCrLf & _
17 "Nachricht: " & objSWbemObject.Message & vbCrLf
18Next

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

Seite 322 von 394



Verwaltete Ressourcen
Dieser Abschnitt schließt mit einer Einführung in die WMI-Sicherheit. Hierbei handelt es sich
zwar nicht um eine WMI-Schicht, es ist jedoch trotzdem wichtig zu wissen, wie Sicherheit
unter WMI funktioniert - und zwar bevor Sie anfangen, Scripte zu schreiben.

Abbildung 6.1: Die WMI-Architektur

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.

Script 6.5: Abfragen und Anzeigen der logischen Laufwerke

1strComputer = "."

Seite 323 von 394


2
3Set objSWbemServices = GetObject("winmgmts:\\" & strComputer)
4Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_LogicalDisk")
5
6For Each objSWbemObject In colSWbemObjectSet
7 Wscript.Echo objSWbemObject.DeviceID
8Next
Abhängig von den logischen Laufwerken des Computers sieht die Ausgabe des Scripts
ungefähr so aus:
A:
C:
D:
E:
Jeder dieser Laufwerksbuchstaben stellt zwei Dinge dar: Erstens ein tatsächliches logisches
Laufwerk und zweitens eine Instanz der Klasse Win32_LogicalDiskDrive.

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.

Anmerkung: Eine weitere Komponente - die WMI-Scriptbibliothek - wird weiter unten in


diesem Kapitel besprochen.

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

Seite 324 von 394


APIs selbst aufrufen. Hierbei gäbe es zwei Probleme: Erstens können Win32-APIs nicht über
ein Script aufgerufen werden - daher müssen Sie eine Programmiersprache wie C++ oder
Visual Basic verwenden. So gehen Ihnen jedoch alle Vorteile von Scripten verloren (schnelle
Entwicklung, keine Entwicklungsumgebung notwendig).
Und zweitens funktionieren nicht alle Win32-APIs auf die gleich Art und Weise. Wenn Sie
die EventLog-APIs beherrschen, dann heißt das noch lange nicht, dass Sie die Service-APIs
genauso verwenden können. Dies ist eine der grundlegenden Schwierigkeiten bei der
Programmierung mit Windows-APIs.
WMI-Provider lösen diese Probleme. Sie müssen sich nicht um den Aufruf der Win32-APIs
kümmern - dies erledigt WMI für Sie - und Sie müssen auch nicht die Unterschiede zwischen
den einzelnen APIs kennen. Stattdessen verwenden Sie die konsistenten WMI-Befehle, und
WMI übersetzt diese für Sie in API-Aufrufe.
WMI wendet sich natürlich nicht nur an Systemadministratoren. Auch Softwareentwickler
können die WMI-Architektur verwenden. Ein Beispiel hierfür ist der Exchange Server 2000-
Provider. Er überwacht den Status des Exchange-Connectors. Auch viele andere
Serverprodukte stellen WMI-Provider zur Verfügung (zum Beispiel MOM-, SMS-, IIS- und
SQL-Server).
Providers werden generell als DLLs (Dynamic-Link Libraries) implementiert. Diese DLLs
befinden sich im Verzeichnis systemroot\System32\Wbem. WMI stellt unter Windows 2000,
Windows XP und Windows Server 2003 bereits eine Menge Provider zur Verfügung - diese
Provider werden auch Standardprovider genannt. Einige dieser Standardprovider sehen Sie in
Tabelle 6.1.

Tabelle 6.1: Einige WMI-Standardprovider


Provider DLL Namespace Beschreibung
Active dsprov.dll root\directory\ldapStellt Active Directory-Objekte über WMI zur
Directory Verfügung
Event Log ntevt.dll root\cimv2 Verwaltet das Windows-Ereignisprotokoll
Performance wbemperf.dllroot\cimv2 Stellt einen Zugriff auf Leistungsdaten zur
Counter Verfügung
Registry stdprov.dll root\default Liest, schreibt, überwacht und erstellt
Registrierungseinträge
SNMP snmpincl.dll root\snmp Stellt einen Zugriff auf SNMP-MIB-Daten und
Trap-Meldungen zur Verfügung
WDM wmiprov.dll root\wmi Stellt einen Zugriff auf WDM-Treiber zur
Verfügung
Win32 cimwin32.dll root\cimv2 Stellt Informationen über Computer,
Festplatten, Peripheriegeräte, Dateien, Ordner,
Dateisysteme, Netzwerkkomponenten,
Betriebssystem, Drucker, Prozesse, Sicherheit,
Dienste, Freigaben, SAM-Benutzer und -
Gruppen und vieles weitere zur Verfügung
Windows msiprov.dll root\cimv2 Stellt einen Zugriff auf Informationen über

Seite 325 von 394


Provider DLL Namespace Beschreibung
Installer installierte Software zur Verfügung
Windows Server 2003 und Windows XP bieten noch viele weitere Standardprovider. Eine
vollständige Liste finden Sie im WMI Software Developers Kit (SDK). Informationen zum
WMI-SDK finden Sie unter dem Link Microsoft Windows Management Instrumentation
(WMI) SDK unter http://www.microsoft.com/windows/reskits/webresources
(englischsprachig).

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.

Seite 326 von 394


Das CIM-Repository
Die Grundidee von WMI ist, dass die Konfiguration und die Verwaltung von
unterschiedlichen Ressourcen über ein einheitliches Schema erfolgt. Das CIM-Repository
speichert dieses Schema - es wird auch Objekt-Repository oder Klassenspeicher genannt. Das
Schema definiert alle über WMI zur Verfügung stehenden Daten und basiert auf dem
Common-Information-Model-Standard der DMTF.
Genau wie das Active Directory-Schema ist das CIM auf Klassen aufgebaut. Eine Klasse ist
eine Blaupause einer über WMI verwaltbaren Ressource. Im Gegensatz zu Active Directory-
Klassen, die statische Objekte vorgeben, stellen CIM-Klassen normalerweise dynamische
Ressourcen dar. Die Instanzen der Ressourcen werden nicht im CIM-Repository gespeichert,
sondern auf Anfrage eines Konsumenten dynamisch abgefragt. Das bedeutet, dass der Begriff
Repository (Speicher) im Bezug auf das CIM nicht ganz richtig ist. Auch wenn das CIM ein
Repository ist und auch statische Daten speichert, so ist sein primärer Zweck doch die
Speicherung von Blaupausen für die verwalteten Ressourcen.
Der Grund hierfür ist einfach: Der Status der meisten über WMI verwalteten Ressourcen
ändert sich regelmäßig. WMI-Klassen können zum Beispiel dazu verwendet werden,
Ereignisse des Ereignisprotokolls abzufragen.
Genau wie Active Directory-Klassen sind auch CIM-Klassen hierarchisch organisiert.
Untergeordnete Klassen erben Eigenschaften der übergeordneten Klassen. Der DMTF pflegt
eine Gruppe von allgemeinen Basisklassen, von denen System- und Anwendungsentwickler
(zum Beispiel Microsoft) system- oder anwendungsspezifische Klassen ableiten können. Die
Klasse Win32_Process ist zum Beispiel von der Klasse CIM_Process abgeleitet (diese ist
wiederum von den Klassen CIM_LogicalElement und CIM_ManagedSystemElement
abgeleitet).
Klassen sind in Namespaces gruppiert - logische Gruppen für bestimmte Bereiche. Der
Namespace root\cimv2 enthält zum Beispiel Klassen, die allgemeine Ressourcen eines
Computers oder eines Betriebssystems repräsentieren. Die Klassen, die in den bisherigen
Scripten verwendet wurden (Win32_LogicalMemoryConfiguration, Win32_Service und
Win32_NTLogEvent) befinden sich im Namespace root\cimv2 - sie sind jedoch nur drei von
Hunderten von Klassen in den unterschiedlichen CIM-Namespaces.

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:

Seite 327 von 394



Index.btr - Binary-tree (btree) Index

Index.map - Transaktionskontrolldatei

Objects.data - CIM-Repository

Objects.map - Transaktionskontrolldatei
Auch wenn das CIM auf objektorientierten Prinzipien basiert, müssen Sie trotzdem kein
Experte im Schema-Design werden. Es ist jedoch wichtig, dass Sie die grundlegenden
Strukturen und die Organisation des CIM-Repository verstanden haben.

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:

Seite 328 von 394



WMI-Namespace-Sicherheit

DCOM-Sicherheit (Distributed COM)

Standard Windows-Betriebssystem-Sicherheit

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.

Tabelle 6.2: WMI-Namespace-Berechtigungen


Berechtigung Beschreibung AdministratorenJeder
Methoden Ermöglicht das Ausführen x x
ausführen von Methoden, die von den
WMI-Klassen oder -Instanzen
exportiert wurden.
Vollständiger Ermöglicht umfassenden x
Schreibzugriff Lese-/Schreib-/Löschzugriff
auf alle WMI-Objekte,
-Klassen und -Instanzen.
EingeschränkterErmöglicht den Schreib- x
Schreibzugriff zugriff auf statische
WMI-Objekte.
Anbieter- Ermöglicht den Schreib- x x
schreibzugriff zugriff auf von Anbietern
bereitgestellte Objekte.
Konto Ermöglicht den Lesezugriff x x
aktivieren auf WMI-Objekte.
Remote- Ermöglicht den Remote- x
aktivierung zugriff auf den Namespace.
Sicherheit Ermöglicht den schreib- x
lesen geschützten Zugriff auf WMI-Sicherheitsinformationen.

Seite 329 von 394


Berechtigung Beschreibung AdministratorenJeder
Sicherheit Ermöglicht den Lese- und x
bearbeiten Schreibzugriff auf WMI-
Sicherheitsinformationen
WMI-Berechtigungen werden auf Namespace-Ebene auf alle Klassen im entsprechenden
Namespace zugewiesen - sie gelten damit auch für alle untergeordneten Namespaces die
Einstellungen von dem entsprechenden Namespace erben. Standardmäßig werden
Berechtigungen nur dem Namespace root zugewiesen und an alle untergeordneten
Namespaces vererbt.
Eine Sicherheitsprüfung wird dann durchgeführt, wenn sich ein Benutzer mit dem CIMOM
verbindet. Daher werden Berechtigungsänderungen nur dann aktiv, wenn der Benutzer eine
neue Verbindung aufbaut.

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

Seite 330 von 394


auszuführen versucht, dann gelten die Sicherheitseinstellungen des Ordners auch für das
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.

Das Common Information Model (CIM)


Wenn Sie ein Haus bauen möchten, dann benötigen Sie jemanden, der die Baupläne lesen und
interpretieren kann. Wenn Sie ein elektronisches Gerät bauen möchten, dann benötigen Sie
jemanden, der sich mit Schaltplänen auskennt. Wenn Sie WMI-Scripte schreiben möchten,
dann müssen Sie wissen, wie Sie mit dem WMI-Blaupausen arbeiten: dem CIM-Repository.
Das CIM-Repository ist das WMI-Schema - in ihm sind alle Klassendefinitionen für alle
Ressourcen gespeichert, die über WMI verwaltet werden können.
Um die Wichtigkeit von CIM und den CIM-Klasse zu unterstreichen, sehen Sie sich Script
6.6 und Script 6.7 an. Script 6.6 ist eine erweiterte Version von Script 6.3 - es gibt
Informationen über die installierten Dienste zurück.

Script 6.6: Abfragen von Informationen über die installierten Dienste

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.

Script 6.7: Abfragen von Informationen über das installierte Betriebssystem

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 & _

Seite 331 von 394


12 "LocalDateTime: " & objOperatingSystem.LocalDateTime & vbCrLf & _
13 "Locale: " & objOperatingSystem.Locale & vbCrLf & _
14 "Manufacturer: " & objOperatingSystem.Manufacturer & vbCrLf & _
15 "OSType: " & objOperatingSystem. OSType & vbCrLf & _
16 "Version: " & objOperatingSystem.Version & vbCrLf & _
17 "ServicePack: " & objOperatingSystem.ServicePackMajorVersion & _
18 "." & objOperatingSystem.ServicePackMinorVersion & vbCrLf & _
19 "Windows Dir: " & objOperatingSystem.WindowsDirectory
20Next
Es gibt zwischen diesen beiden Scripten zwei Unterschiede: der verwendete Klassenname und
die Eigenschaften der Klassen. Das erste Script verwendet zum Beispiel die Eigenschaften
DisplayName, StartMode und State - das zweite Script fragt die Eigenschaften
LastBootUpTime, Version und ServicePackMajorVersion ab.
Dass Sie das gleiche Script verwenden können, um so unterschiedliche Informationen
abzufragen, verdeutlicht die wichtige Rolle von CIM-Klassen. Wenn Sie ein Script erstellt
haben, können Sie über dieses Scripte viele verschiedene Informationen abfragen.
Zu wissen, wie die Klassen und deren Eigenschaften heißen, ist jedoch nur ein Teil der
Arbeit. Bevor Sie WMI voll ausnutzen können, müssen Sie etwas mehr über die Struktur des
CIM-Repository und der WMI-Klassen wissen. Und zwar aus zwei Gründen.

Wenn Sie das CIM-Repository kennen, wird es Ihnen leichter fallen, die Ressourcen eines
Computers oder einer Software zu identifizieren.

Wenn Sie die Klassen kenn, werden Sie leichter feststellen können, welche Aufgaben Sie
über WMI ausführen können.
Beide Gründe sind unabhängig vom verwendeten WMI-Werkzeug. Egal ob Sie ein WMI-
Script oder eine andere Anwendung nutzen - Sie müssen wissen wie das CIM-Repository
aufgebaut ist und wie die WMI-Klassen anzuwenden sind.
Ein genauso wichtiger Grund ist, dass das CIM-Repository eine hervorragende
Dokumentation der verfügbaren verwalteten Ressourcen ist. Wenn Sie Informationen über
eine WMI-Klasse benötigen, können Sie natürlich das WMI-SDK verwenden. Was machen
Sie aber, wenn Sie zum Beispiel wissen möchten, ob eine bestimmte Klasse, Methode oder
Eigenschaft unter einer bestimmten Windows-Version unterstützt wird? In einem solchen Fall
können Sie das CIM-Repository abfragen.
Nehmen wird einmal an, Sie haben sich das folgende Script aus dem Script Center im
Microsoft TechNet besorgt:
Const JOIN_DOMAIN = 1
Const ACCT_CREATE = 2
Set objNetwork = CreateObject("Wscript.Network")
strComputer = objNetwork.ComputerName
Set objComputerSystem = GetObject _
("winmgmts:{impersonationLevel=Impersonate}!\\" & strComputer & _
"\root\cimv2:Win32_ComputerSystem.Name='" & strComputer & "'")
ReturnValue = objComputerSystem.JoinDomainOrWorkGroup _
("FABRIKAM", "password", "FABRIKAM\shenalan", NULL,
JOIN_DOMAIN+ACCT_CREATE)
Sie möchten wissen, ob das Script unter Windows 2000 ausgeführt werden kann. Wie sich
herausstellt kann es nicht ausgeführt werden - und zwar, da die Klasse
Win32_ComputerSystem unter Windows 2000 keine Methode JoinDomainOrWorkGroup zur
Verfügung stellt. Die Methode wurde erst unter Windows XP hinzugefügt.
Seite 332 von 394
Aber wie finden Sie das heraus - außer über das Ausprobieren des Scripts? Ein Weg wäre die
Verwendung der WMI-Tools, die weiter unten in diesem Kapitel im Abschnitt Das CIM-
Repository erkunden beschrieben werden. Ein deutlich flexiblerer Ansatz ist jedoch die
Verwendung der WMI-Scripting-Bibliothek. Eine nützliche Eigenschaft von WMI ist die
Tatsache, dass Sie mit der Scripting-Bibliothek Informationen über WMI selbst abfragen
können. Sie können zum Beispiel WMI-Scripte schreiben, die alle Namespaces und Klassen
im CIM-Repository ausgeben. Sie können auch ein Script schreiben, das alle installierten
Provider ausgibt.

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

3.Es gibt vier primäre Klassentypen: abstrakt, statisch und dynamisch.



Eine abstrakte Klasse ist eine Vorlage von der neue abstrakte oder nicht-abstrakte Klassen
abgeleitet werden. Sie kann nicht zur Erstellung von Instanzen verwalteter Objekte
verwendet werden.

Eine statische Klasse definiert im CIM-Repository gespeicherte Daten. Normalerweise
handelt es sich hierbei um die WMI-Konfiguration und operative Daten.

Eine dynamische Klasse ist eine Klasse, die zur Erstellung neuer Instanzen verwalteter
Ressourcen verwendet wird.

Eine assoziative Klasse ist eine abstrakte, statische oder dynamische Klasse, die eine

Seite 333 von 394


Abbildung 6.2: Strukturelle Ansicht des CIM-Repository (WMI-Schema)

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.

Seite 334 von 394


Anmerkung: Ein Unterschied zwischen Ordner und den WMI-Namespaces ist, dass Ordner
oft tief verschachtelt sind. Namespaces sind hingegen sind selten mehr als drei Ebenen tief.
Die meisten Klassen zur Systemadministration befinden sich zum Beispiel unter root\cimv2 -
also schon in der zweiten Ebene.
Alle Klassen in einem Namespace müssen einen eindeutigen Klassennamen haben. Klassen in
einem Namespace können nicht von Klassen in einem anderen Namespace abgeleitet werden.
Daher finden Sie in unterschiedlichen Namespaces identische Systemklassen, Kernklassen
und allgemeine Klassen.
Die meisten Klassen zur Verwaltung von Ressourcen befinden sich im Namespace
root\cimv2. root\cimv2 ist jedoch nicht der einzige Namespace, auf den Sie achten müssen.
Der Provider Registry speichert seine Klassendefinitionen zum Beispiel im Namespace
root\default.

Einen Namespace angeben


Jedes WMI-Script verbindet sich im ersten Schritt mit einem Namespace. Die folgende
Codezeile verbindet das Script zum Beispiel mit dem Namespace root\cimv2 auf dem lokalen
Computer (die Verbindung wird deshalb mit dem lokalen Computer aufgebaut, weil kein
Computername angegeben ist):
Set objSWbemServices = GetObject("winmgmts:root\cimv2")
Eine Verbindung wird auch dann hergestellt, wenn kein Namespace im Verbindungs-String
angegeben wird:
Set objSWbemServices = GetObject("winmgmts:")
Wenn keine Namespace definiert wurde, dann verbindet sich das Script mit dem Standard-
Namespace. Dieser Standard-Namespace wird im folgenden Registrierungschlüssel definiert:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\Scripting\Default Namespace
Wenn Sie bei der Abfrage von verwalteten Ressourcen keinen Namespace angeben, sucht
WMI die Klassendefinition nur im Standard-Namespace. Wenn dieser dort nicht zu finden ist,
kommt es zum Fehler WBEM_E_INVALID_CLASS (0x80041010).

Anmerkung: Verwechseln Sie nicht den Standard-Namespace mit dem Namespace


root\DEFAULT. Solange Sie den Standard-Namespace nicht auf root\DEFAULT setzen,
haben die beiden nichts mit einander zu tun.
Normalerweise ist der Namespace root\cimv2 der Standard-Namespace. Er kann jedoch auch
ganz einfach geändert werden. Um sicherzustellen, dass Ihr Script korrekt ausgeführt wird,
sollten Sie daher immer einen Namespace angeben. Das folgende Codestück zeigt, wie Sie
einen Namespace angeben. Es verwendet außerdem die Variable strComputer, um den
Computernamen anzugeben, gegen den das Script ausgeführt wird:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")

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.

Konfigurieren des Standard-Namespace


Sie können die WMI-Scripting-Bibliothek zusammen mit der Klasse Win32_WMISetting
verwenden, um den Standard-Namespace auszulesen und zu ändern. Script 6.8 und Script 6.9
demonstrieren dies. Bei Win32_WMISetting handelt es sich um eine dynamische Klasse mit
operativen Parametern des WMI-Dienstes. Über die Eigenschaft ASPScriptDefaultNamespace
können Sie auf den Standard-Namespace zugreifen.
Script 6.8 verwendet die bereits bekannten drei Schritte: verbinden, abfragen und anzeigen.
Wie oben empfohlen, wird beim Verbinden ein Namespace für die Klasse Win32_WMISetting
angegeben.

Script 6.8: Abfragen des Standard-Namespace

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).

Script 6.9: Konfigurieren des Standard-Namespace

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

Seite 336 von 394


Über WMI-Scripting können Sie nicht nur Informationen über Ressourcen abrufen, sondern
auch Informationen über das CIM. Die einzige Änderung zu den vorherigen Scripten ist in
diesem Fall der verwendete Klassenname.
Namespace-Informationen werden im CIM als statische Instanzen der Klasse
__NAMESPACE gespeichert. Im Gegensatz zu verwalteten Ressourcen, bei denen die
Informationen über einen Provider abgerufen werden, werden die Informationen von
Instanzen statischer Klassen direkt im CIM gespeichert und von dort auch ohne einen WMI-
Provider abgerufen. Script 6.10 verwendet die Klasse __NAMESPACE, um alle Namespaces
direkt unter dem Namespace root abzurufen.

Script 6.10: Abrufen der Namespaces direkt unter root

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

Seite 337 von 394


wichtigen Ausnahme:
1.Die Subroutine gibt als erstes das Argument aus, mit dem sie aufgerufen wurde:
strNameSpace.
Die Variable strNameSpace definiert den Namespace, der bei jedem Aufruf der
Subroutine im Verbindungs-String verwendet wird. Beim ersten Aufruf der Subroutine
enthält strNameSpace den Wert "root".
2.Sie verwendet die VBScript-Funktion GetObject, um eine Verbindung mit dem
Namespace aufzubauen, der in der Variable strNameSpace angegeben ist.
3.Nach dem Verbindungsaufbau fragt die Subroutine alle Namespaces direkt unter dem
Namespace ab, mit dem die Verbindung aufgebaut wurde.
4.Die Subroutine verwendet eine For-Each-Schleife, um die Liste der direkten Unter-
Namespaces aufzulisten. Statt die Namen der Namespaces jedoch auszugeben, ruft sich
die Subroutine selbst mit dem jeweiligen Namen des Unter-Namespaces auf.
3.Die Schritte a bis d werden so lange durchgeführt, bis alle Namespaces aufgelistet sind.

Script 6.11: Abfragen aller CIM-Namespaces

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

Seite 338 von 394


Systemklassen sind Klassen, die die interne WMI-Konfigurationen zur Verfügung stellen -
zum Beispiel die Namespace-Konfiguration, die Namespace-Sicherheit, die Registrierung von
Providern und die Ereignisbenachrichtigung. Wenn Sie sich das CIM anschauen, dann können
Sie die Systemklassen leicht an den beiden Unterstrichen erkennen.
Systemklassen sind entweder von Typ abstrakt oder statisch. Abstrakte Systemklassen sind
Vorlagen zum Ableiten (oder Definieren) anderer abstrakter oder statischer Systemklassen.
Statische Systemklassen definieren die WMI-Konfiguration im CIM -Repository. Die
Systemklasse __Win32Provider stellt zum Beispiel Informationen zur Providerregistrierung
zur Verfügung.
Wie bereits mit der Systemklasse __NAMESPACE demonstriert, können Sie WMI nutzen, um
die statischen Instanzen der Systemklassen abzufragen. Script 6.12 fragt zum Beispiel alle
Instanzen der Klasse __Win32Provider im Namespace root\cimv2 ab.

Script 6.12: Abfragen der im Namespace root\comv2 registrierten Win32-Provider

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.

Kernklassen und allgemeine Klassen


Diese Klassen haben zwei Aufgaben. Erstens sind sie die abstrakten Klassen, von denen
System- und Softwareentwickler technologiespezifische Erweiterungsklassen ableiten
können. Zweitens definieren Sie Ressourcen im Bezug auf bestimmte Bereiche der
Verwaltung, die nicht von einer bestimmen Technologie oder Implementierung abhängen.
Theoretisch sind dies Ressourcen, die jedes Betriebssystem unterstützt. Die DMTF definiert
einen Satz an Kernklassen und allgemeinen Klassen. Diesen können Sie über den Prefix
CIM_ prefix erkennen.
Von den 275 Kernklassen und allgemeinen Klassen im Namespace root\cimv2 sind fast alle
abstrakte Klassen. Da Sie keine Instanzen von abstrakten Klassen erstellen können, werden
Sie diese eher selten verwenden. Sie werden normalerweise nur von System- und
Softwareentwicklern genutzt.
Vier der 275 Klassen sind dynamische Klassen. Diese vier Klassen sind CIM_DataFile,
CIM_DirectoryContainsFile, CIM_ProcessExecutable und CIM_VideoControllerResolution.
Seite 339 von 394
Sie können zum Abrufen von Informationen über Ressourcen verwendet werden. Das
folgende Script gibt zum Beispiel Informationen über alle möglichen Auflösungen der
Grafikkarte zurück:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")
Set colVideoControllers = _
objSWbemServices.InstancesOf("CIM_VideoControllerResolution")
For Each objVideoController In colVideoControllers
Wscript.Echo objVideoController.HorizontalResolution
Wscript.Echo objVideoController.VerticalResolution
Wscript.Echo objVideoController.NumberOfColors
Wscript.Echo objVideoController.RefreshRate
Next
Erweiterungsklassen
Erweiterungsklassen sind technologiespezifische Klassen, die von System- und
Softwareentwicklern verwendet werden. Erweiterungsklassen von Microsoft sind zum
Beispiel Win32_BaseService, Win32_Service, Win32_SystemServices und
Win32_ComputerSystem. Die Erweiterungsklassen von Microsoft im Namespace root\cimv2
erkennen Sie am Prefix Win32_.
Gehen Sie jedoch nicht davon aus, dass alle Microsoft-Erweiterungsklassen mit Win32_
beginnen - dies ist nicht der Fall. Die Klasse StdRegProv in root\DEFAULT hält sich zum
Beispiel nicht an diese Regel.
In der aktuellsten Version von WMI gibt es im Namespace root\cimv2 463
Erweiterungsklassen. Von den 463 Win32-Klassensind 68 abstrakte Klassen und 395
dynamische. Die meisten Klassen, die Sie in Ihren Scripten verwenden werden, sind
Erweiterungsklassen.

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.

Auflisten der Klassen in einem Namespace


Sie können ein Script schreiben, dass alle Klassen in einem bestimmen Namespace auflistet.
Script 6.13 demonstriert dies, indem es alle Klassen im Namespace root\cimv2 auflistet. Im
Gegensatz zu den vorherigen Scripten, die die Methode SWbemServices.InstancesOf
verwendet haben, verwendet das Script jedoch die Methode SubclassesOf.
Wie der Name schon sagt, gibt die Methode SubclassesOf alle untergeordneten Klassen einer
bestimmten Klasse oder eines bestimmten Namespaces zurück. Wie InstancesOf gibt auch
SubclassesOf die Unterklassen als Collection zurück. Jedes Element in der Collection ist eine
Klasse.
Ein neues Element in Script 6.13 ist die Eigenschaft objClass.Path_.Path. Sie wird in der For-
Each-Schleife verwendet. Wie in den anderen Scripten dieses Kapitels, geht die Schleife alle
Elemente der von der Methode SubclassesOf zurückgegebenen Collection durch.
Im Gegensatz zu den vorherigen Scripten ist Path_ jedoch eine Eigenschaft von
SWbemObject. Um dies zu verstehen, müssen Sie sich überlegen, in welchem Kontext das
Script SWbemObject verwendet. In diesem Fall greift es nicht auf eine Instanz einer

Seite 340 von 394


verwalteten Ressource zu (zum Beispiel ein Dienst, ein Prozess, etc.), sondern auf die
Klassendefinition der verwalteten Ressource.
Wenn Sie mit SWbemObject auf eine Instanz einer verwalten Ressourcen zugreifen, dann
greifen Sie auf die Eigenschaften und Methoden zu, die über die Klassendefinition für die
verwaltete Ressource definiert werden. Wenn Sie SWbemObject jedoch verwenden, um
Informationen über die Klasse selbst abzurufen, dann verwenden Sie die Eigenschaften und
Methoden von SWbemObject selbst - Path_ ist eine solche Eigenschaft.
Path_ ist eine Referenz auf eine andere WMI-Scripting-Bibliothek mit dem Namen
SWbemObjectPath. Diese stellt die Eigenschaft Path zur Verfügung. Die Eigenschaft
SWbemObjectPath.Path enthält den vollqualifizierten Pfad zur Klasse, die von SWbemObject
referenziert wird (objClass in Script 6.13).

Script 6.13: Abrufen aller Klassen im Namespace root\cimv2

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"

Seite 341 von 394


Wenn Sie den Befehl unter Windows XP ausführen, erhalten Sie die folgende Ausgabe:
\\ATL-WINXP-01\ROOT\cimv2:Win32_TSSessionSettingError
\\ATL-WINXP-01\ROOT\cimv2:Win32_TSSessionSetting
Wenn sie den Befehl unter Windows 2000 ausführen, erhalten Sie keine Ausgabe. Das
bedeutet, dass die Klasse Win32_TSSessionSetting unter Windows 2000 nicht unterstützt
wird.
Einige weitere Befehle, die Sie probieren können, sind:
1.Eine Liste aller Systemklassen im Namespace root\cimv2:
cscript GetClasses.vbs |findstr /I "__"
2.Eine Liste aller Kernklassen und allgemeinen Klassen im Namespace root\cimv2:
cscript GetClasses.vbs |findstr /I "CIM_"
3.Eine Liste aller Win32-Erweiterungsklassen im Namespace root\cimv2:
cscript GetClasses.vbs |findstr /I "Win32_"
4.Eine Liste alle Klassen im Namespace root\cimv2, die den Text "process" enthalten:
cscript GetClasses.vbs |findstr /I "process"

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

Seite 342 von 394


CIM_ManagedSystemElementundCIM_Logical CIM_Service Win32_BaseServ Win32_Servi
Element ice ce
Name Name Name
Description Description Description
Name Name Name
Started Started Started
StartMode StartMode StartMode
Status Status Status
SystemCreati SystemCreation SystemCreati
on ClassName on
ClassName ClassName
SystemName SystemName SystemName
AcceptPause AcceptPause
AcceptStop AcceptStop
DesktopInteract DesktopInter
act
DisplayName DisplayName
ErrorControl ErrorControl
ExitCode ExitCode
PathName PathName
ServiceSpecific ServiceSpecif
ExitCode ic
ExitCode
ServiceType ServiceType
StartName StartName
State State
TagID TagID
Checkpoint
ProcessID
WaitHint

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.

Seite 343 von 394


Komponenten einer Klasse
Jede Hard- und Softwareressource, die über WMI verwaltet werden kann, wird über eine
Klasse definiert. Eine Klasse ist eine Blaupause (oder Vorlage) für eine über WMI verwaltete
Ressource. Alle Instanzen einer Ressource verwenden die Blaupause (oder Klassendefinition).
Das bedeutet, dass alle Dienste (die auch Instanzen der Klasse Win32_Service sind) die
gleichen Eigenschaften haben. Es bedeutet nicht, dass die Eigenschaften alle die gleichen
Werte haben.

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.

Seite 344 von 394


Abbildung 6.3: Struktur einer Klassendefinition
Eigenschaften
Eigenschaften beschreiben die verwaltete Ressource. Klassen verwenden Eigenschaften, um
Dinge wie Konfigurationen, Status und Namen von verwalteten Ressourcen zu beschreiben.
Dienste haben zum Beispiel die Eigenschaften Name, angezeigter Name, Beschreibung,
Starttyp und Status. Daher hat die Klasse Win32_Service die gleichen Eigenschaften.
Jede Eigenschaft hat einen Namen, einen Typ und optional einen Kennzeichner. Über den
Namen greifen Sie auf die Eigenschaft zu:
Wscript.Echo objService.Name
Wscript.Echo objService.Description
In der MOF-Datei sieht die Eigenschaftsdefinition so aus (Name, Datentyp und Kennzeichner
sind fett formatiert):
[read : ToSubclass,MappingStrings{"Win32API|Service
Structures|SERVICE_STATUS|dwControlsAccepted|
SERVICE_ACCEPT_PAUSE_CONTINUE"} : ToSubclass] boolean AcceptPause;
Methoden
Methoden führen Aktionen mit einer verwalteten Ressource aus. Mit den Methoden der
Klasse Win32_Service können Sie zum Beispiel einen Dienst anhalten und starten.
Jede Methode hat einen Namen, einen Rückgabewert, optionale Parameter und optionale
Methoden-Kennzeichner. Das folgende Scriptstück hält zum Beispiel einen Dienst an. Wenn
der Rückgabewert der Methode ungleich 0 ist, dann ist der Vorgang fehlgeschlagen
(normalerweise bedeutet der Rückgabewert 0 immer, dass eine Methode erfolgreich
ausgeführt wurde):
errReturn = obService.StopService()

Seite 345 von 394


Wscript.Echo errReturn
Nicht alle Klassen stellen Methoden zur Verfügung. Unter Windows 2000 stellen zum
Beispiel die Klassen Win32_Service, Win32_NTEventLogFile und Win32_Process Methoden
zur Verfügung. Unter Windows XP gibt es noch bei einigen weiteren Klassen Methoden (zum
Beispiel Win32_DiskQuota und Win32_Printer).

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.

Seite 346 von 394



Der Kennzeichner Key zeigt an, ob die Eigenschaft ein Klassenschlüssel ist und zur
eindeutigen Identifizierung einer Instanz einer verwalteten Ressource verwendet wird.
DeviceID ist zum Beispiel eine Schlüsseleigenschaft von Win32_LogicalDisk.

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).

Vergleich zwischen Klassen und verwalteten Ressourcen


Klassen legen fest, was Sie mit WMI machen können und was nicht. Wenn Sie eine Klasse
für Dienste haben, können Sie diese verwalten - wenn nicht, dann nicht. Konsequenterweise
ist es also wichtig zu wissen, welche Klassen auf einem Computer vorhanden sind.
Der Umfang von WMI unterscheidet sich unter verschiedenen Betriebssystemen. Die Klasse
Win32_ComputerSystem stellt unter Windows XP viele neue Eigenschaften und Methoden
zur Verfügung, die unter Windows 2000 nicht vorhanden sind. Damit Ihr Script funktioniert,
müssen Sie wissen, welche Eigenschaften und Methoden vorhanden sind.

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.

Abfragen von Klassendefinitionen


Sie können die WMI-Scripting-Bibliothek verwenden, um die Klassendefinitionen von
verwalteten Ressourcen abzufragen. Hierzu gibt es zwei Wege:

Sie verwenden die Eigenschaften SWbemObject.Qualifiers_, SWbemObject.Properties_ und
SWbemObject.Methods_.

Sie verwenden die Methode SWbemObject.GetObjectText_, um eine Klassendefinition in
der MOF-Syntax zu erhalten.

Seite 347 von 394


Verwenden der Eigenschaften Properties_, Methods_ and Qualifiers_
Script 6.14, Script 6.15 und Script 6.16 zeigen, wie Sie die Eigenschaften Properties_,
Methods_ und Qualifiers_ zur Abfrage von Informationen über die Klasse Win32_Service
verwenden können. Alle drei Scripte gehen nach dem gleichen Ansatz vor - es gibt allerdings
auch einige Unterschiede.
Script 6.14 beginnt mit der Initialisierung von drei Variablen: strComputer, strNameSpace
und strClass. strComputer werden als Wert der Namen des Zielcomputers zugewiesen.
strNameSpace wird der Name des Namespace zugewiesen, mit dem eine Verbindung
aufgebaut werden soll, und strClass erhält als Wert den Namen der Klasse, dessen
Eigenschaften abgefragt und angezeigt werden soll.
Wenn diese drei Werte in einzelnen Variablen gespeichert werden, wird es einfach, das Script
für andere Computer, Namespaces und Klassen zu verwenden. Mit der Collection WSH
Arguments können Sie das Script sogar ganz einfach in einem Kommandozeilentool
verwenden. Weitere Informationen hierzu finden Sie im Kapitel Der WSH in diesem Buch.
Als Nächstes verwendet das Script die VBScript-Funktion GetObject, um eine Verbindung
mit dem WMI-Dienst auf dem Zielcomputer zu erstellen. Vielleicht ist Ihnen etwas bei dem
Verbindungsstring aufgefallen, der an GetObject übergeben wird. Zusätzlich zum Namespace
wird auch noch der Klassenname angegeben. Dies hat weit reichende Auswirkungen auf das,
was die Methode GetObject zurückgibt. Statt eine Referenz auf ein SWbemServices-Objekt
zurückzugeben (wie in den bisherigen Scripten), gibt GetObject nun eine Referenz auf ein
SWbemObject zurück, das die Zielklasse darstellt. Wie das? Die Antwort liegt im Objektpfad.
Auch wenn Objektpfade später in diesem Kapitel noch genauer besprochen werden, wollen
wir hier eine kurze Einführung geben. Sie wird Ihnen beim Verständnis des Scripts helfen.
Jede WMI-Klasse und jede Instanz einer verwalteten Ressource hat einen Objektpfad. Ein
Objektpfad ist so ähnlich wie ein Dateipfad. Eine Datei hat einen voll qualifizierten Pfad -
dieser setzt sich aus einem Gerätenamen, einem oder mehreren Ordnernamen und dem
Dateinamen zusammen. Klassen und verwaltete Ressourcen haben ebenfalls solche Pfade -
sie setzen sich aus dem Computernamen, dem Namespace, dem Klassenamen, der
Schlüsseleigenschaft der Klasse und dem Wert der Schlüsseleigenschaft zusammen. Ein
solcher Objektpfad sieht zum Beispiel so aus (die eckigen Klammern trennen nur die
einzelnen Teile des Objektpfads - sie werden normalerweise weggelassen):
[\\ComputerName][\Namespace][:Klassenname][.Schlüsseleigenschaft='Wert']
Wenn Sie den gesamten Objektpfad oder einen Teil des Objektpfads im Verbindungsstring
von GetObject verwenden, dann legt dieser den zurückgegebenen Referenztyp fest. Wenn Sie
zum Beispiel nur den Computernamen-Teil des Objektpfads angeben, dann erhalten Sie eine
SWbemServices-Objektreferenz zurück, die mit dem Standard-Namespace verbunden ist.
Wenn Sie den Computernamen oder den Namenspace oder beides angeben, erhalten Sie
ebenfalls eine Referenz auf ein SWbemServices-Objekt. Wenn Sie den Computernamen, den
Namespace und den Klassennamen angeben erhalten, Sie eine Referenz auf ein
SWbemObject zurück, das eine Klasse darstellt. Wenn Sie alle vier Teile des Objektpfads
angeben, erhalten Sie ein SWbemObject zurück, das eine Instanz eines verwalteten Objekts
darstellt - und zwar die Instanz, die durch den Wert der Schlüsseleigenschaft definiert wird.
Die Elemente des Objektpfads und die zurückgegebenen Objekte sind in Tabelle 6.4
zusammengefasst.

Tabelle 6.4: Elemente des Objektpfads und die zurückgegebenen Objekte

Seite 348 von 394


Teile des Objektpfads Zurückgegebenes Objekt
Computername: SWbemServices
Set objSWbemServices = _ (verbunden mit dem
GetObject("winmgmts:\\WebServer") Standard-Namespace)
Computername und/ SWbemServices
oder Namespace: (verbunden mit den
Set objSWbemServices = _ angegebenen Namespace -
GetObject in diesem Fall root\cimv2)
("winmgmts:\\WebServer\root\cimv2")
Computername, Namespace, SWbemObject (stellt die
Klassenname: Klasse Win32_Service dar)
Set objSWbemObject = GetObject _
("winmgmts:\\WebServer\root\
cimv2:Win32_Service")
Computername, Namespace, SWbemObject (stellt die
Klassenname, Schlüsseleigenschaft: Instanz des Dienstes
Set objSWbemObject = GetObject _ mit dem Namen Alerter dar)
"winmgmts:\\WebServer\root\cimv2:" & _
Win32_Service.Name='Alerter'")
Der Rest des Scripts ist ganz einfach. Es verwendet die SWbemObject-Referenz (objClass),
um auf die Eigenschaften (objClass.Properties_) zuzugreifen. Properties_.property
referenziert eine Collection mit den Eigenschaften der Klasse (SWbemPropertySet). Jede
Eigenschaft in der Collection ist ein SWbemProperty-Objekt (objClassProperty) dessen
Eigenschaftsname gelesen und ausgegeben wird.

Script 6.14: Abfragen der Eigenschaften von Win32_Service über


SWbemObject.Properties_

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

Seite 349 von 394


DesktopInteract
DisplayName
ErrorControl
ExitCode
InstallDate
Name
PathName
ProcessId
ServiceSpecificExitCode
ServiceType
Started
StartMode
StartName
State
Status
SystemCreationClassName
SystemName
TagId
WaitHint
Script 6.15 ist mit Script 6.14 bis auf eine Ausnahme identisch: Eine For-Each-Schleife geht
die Collection SWbemMethodSet durch und zeigt die Eigenschaft Name jeder Methode
(objClassMethod) in der Collection SWbemMethodSet an.

Script 6.15: Verwenden von SWbemObject.Methods_, um die Methoden von


Win32_Service abzufragen

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,

Seite 350 von 394


fragt Script 6.16 auch diese ab.

Da Kennzeichner mehrere Werte in einem Array bereitstellen können, muss dies im Script
berücksichtigt werden. Über die VBScript-Funktion VarType wird daher der Typ der
Variable überprüft.

Script 6.16: Abfragen der Klassenkennzeichner von Win32_Service über


SWbemObject.Qualifiers_

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.

Verwenden der Methode SWbemObject.GetObjectText_


Es wurde bereits darauf hingewiesen, dass Sie die Klassendefinitionen von verwalten
Ressourcen über eine MOF-Datei abfragen können. Wenn Sie zum Beispiel die Klasse
Win32_Service abfragen möchten, schlagen Sie in der Datei
systemroot\System32\Wbem\Cimwin32.mof nach. Die direkte Verwendung von MOF-Dateien
hat jedoch ihren Preis - Sie müssen jede Klasse in der Klassenhierarchie überprüfen, um die
komplette Klassendefinition zu erhalten.
Wenn Sie zum Beispiel die Klasse Win32_Service abfragen, dann müssen Sie auch alle fünf
Klassen überprüfen, die sich in der Hierarchie über der Klasse Win32_Service befinden. Dies
ist sehr mühsam - ein einfacherer Ansatz ist es, die Methode SWbemObject.GetObjectText_
zu verwenden. Script 6.17 demonstriert dies.

Seite 351 von 394


Im Gegensatz zu Script 6.14 und Script 6.16 verwendet Script 6.17 die Methode
SWbemServices.Get statt die Klasse über GetObject abzufragen. Die Methode Get muss
verwendet werden, damit das Flag (der Schalter) wbemFlagUseAmendedQuailifiers aktiviert
werden kann. Mit diesem Flag teilen Sie WMI mit, dass es die gesamte Klassendefinition der
verwalteten Ressource zurückgeben soll und nicht nur deren lokale Definition. Mit anderen
Worte: Die zurückgegebenen Informationen umfassen nicht nur drei Eigenschaften, die direkt
in der Klasse definiert werden, sondern auch alle von übergeordneten Klassen gerbten
Eigenschaften.
Die Methode Get gibt eine Referenz auf ein SWbemObject-Objekt (objClass) zurück, dass die
Zielklasse darstellt, mit der die Methode GetObjectText_ aufgerufen wird. Die Methode
GetObjectText_ gibt die MOF-Beschreibung der Klasse zurück. Wenn Sie GetObjectText_
verwenden, ohne das Flag wbemFlagUseAmendedQuailifiers zu aktivieren, erhalten Sie nur
die Methoden, Eigenschaften und Kennzeichner, die direkt in der Klasse Win32_Service
definiert werden. Die geerbten Eigenschaften und Methoden werden nicht ermittelt.

Script 6.17: Abfragen der MOF-Beschreibung der Klasse Win32_Service über


SWbemObject.GetObjectText_

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.

Erkunden des CIM-Repository


Die Erkundung des CIM-Repository ist wahrscheinlich der beste Weg, um mehr über die
verfügbaren Klassen und deren Methoden und Eigenschaften zu lernen. Sie haben bereits ein

Seite 352 von 394


Script kennen gelernt, mit dem Sie das CIM-Repository anzeigen lassen können. Sie sind
jedoch nicht auf dieses Script beschränkt. Es gibt einige unterschiedliche Tools, mit denen Sie
WMI-Klassen anzeigen lassen können.

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.

Scripte aus dem Resource Kit


Das Microsoft Windows 2000 Server Resource Kit enthält Dutzende von Scripten zur
Verwendung von WMI. Mit drei dieser Scripts (EnumClasses.vbs, EnumInstances.vbs und
EnumNamespaces.vbs) können Sie ebenfalls das CIM-Schema anzeigen.

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.

Das Objektmodell der WMI-Scripting-Bibliothek


Die WMI-Scripting-Bibliothek setzt sich aus 19 Automatisationsobjekten zusammen. 16 von
diesen Objekten sehen Sie in Abbildung 6.4. Die WMI-Scripting-Bibliothek stellt ein
konsistentes und einheitliches Scriptmodell für verwaltete Ressourcen zur Verfügung.
Es ist wichtig, dass Sie die Beziehungen zwischen den Automatisationsobjekten der WMI-
Scripting-Bibliothek und den Klassendefintionen der verwalteten Ressourcen im CIM-
Repository verstehen.
Über die WMI-Scripting-Bibliothek können Scripte eine Authentifizierung durchführen und
eine Verbindung mit WMI aufbauen. So erhalten die Scripte einen Zugriff auf die Instanzen
der verwalteten Ressourcen. Das Script kann dann auf die Methoden und Eigenschaften der
Ressource zugreifen.

Seite 353 von 394


Abbildung 6.4: Das Objektmodell der WMI-Scripting-Bibliothek

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.

Seite 354 von 394


Dieser besteht aus dem WMI-Moniker ("winmgmts:") und einem WMI-Objektpfad zum
Zielcomputer und den entsprechenden Namespace:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer & _
"\root\cimv2")
Auf diese Art erhält das Script das in Abbildung 6.4 gezeigt SWbemServices-Objekt zurück.
Es kann dann die Methoden des Objekts aufrufen.

Jedes Script ruft über die Methode InstancesOf Instanzen von verwalteten Ressourcen ab.
Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_Service")
InstancesOf gibt immer eine SWbemObjectSet-Collection zurück. Wie Sie an der Linie
zwischen den Objekten SWbemServices und SWbemObjectSet sehen, handelt es sich um eine
der drei Objektarten, die SWbemServices zurückgeben kann (die anderen beiden sind
SWbemObject und SWbemEventSource).

Jedes Script greift auf die Eigenschaften der verwalteten Ressourcen zu, indem es die
Instanzen im Objekt SWbemObjectSet durchgeht.
For Each objSWbemObject In colSWbemObjectSet
Wscript.Echo "Name: " & objSWbemObject.Name
Next
Wie Sie in Abbildung 6.4 sehen, wird jede Instanz einer verwalteten Ressource in einer
SWbemObjectSet-Collection durch ein SWbemObject-Objekt repräsentiert. Wenn das
SWbemObjectSet-Objekt zum Beispiel aus einer Collection mit allen installierten Diensten
besteht, bedeutet das:

Jedes Element der Collection ist ein SWbemObject-Objekt (dies gilt für jedes
SWbemObjectSet-Objekt).

Jedes Objekt in der Collection ist eine Instanz eines installierten Dienstes.

Interpretieren des WMI-Scripting-Bibliothek-Objektmodells


Was können Sie noch vom WMI-Scripting-Bibliothek-Objektmodell lernen? Sie sehen, dass
die Objekte SWbemLocator, SWbemSink, SWbemObjectPath, SWbemNamedValueSet und
SWbemLastError über die Funktion CreateObject erstellt werden. Andererseits können
SWbemServices und SWbemObject über die Funktion GetObject zusammen mit einem WMI-
Moniker und einem WMI-Objektpfad erstellt werden.
Das Objektmodell zeigt Ihnen außerdem über den Kreis mit dem S, dass sieben Objekte der
WMI-Scripting-Bibliothek ein SWbemSecurity-Objekt zur Verfügung stellen.
Von den 19 Automatisationsobjekten der WMI-Scripting-Bibliothek sind die beiden
wichtigsten Objekte SWbemServices und SWbemObject. SWbemServices repräsentiert die
authentifizierte Verbindung zu einem WMI-Namespace auf einem Computer und spielt eine
wichtige Rolle bei Abfragen und der Verarbeitung von Ereignissen.
Über SWbemObject rufen Sie die Methoden und Eigenschaften der verwalteten Ressource
auf.
Die folgende Diskussion betrachtet die Rolle die die primären WMI-Scripting-Bibliothek-
Automatisationsobjekte beim WMI-Scripting spielen. Wenn Sie Informationen über die
einzelnen Objekte erhalten, nehmen Sie sich einen Moment Zeit und betrachten Sie die
Beziehungen des Objekts zu den anderen Objekten im Objektmodell-Diagramm.

Seite 355 von 394


Namenskonventionen für Variablen
Die Variablen in den folgenden Beispielscripten, die eine Referenz auf WMI-
Automatisationsobjekte speichern, folgen einer Namenskonvention. Die Variable wird nach
dem Automatisationsobjekt benannt, auf das sie eine Referenz speichert - außerdem wird ihr
der Prefix "obj" vorangestellt (zum zu zeigen, dass es sich um eine Objektreferenz handelt).
Eine Variable, die eine Referenz auf ein SWbemServices-Objekt speichert, wird zum Beispiel
objSWbemServices genannt. Eine Variable, die eine Referenz auf ein SWbemObject-Objekt
speichert, wird objSWbemObject genannt. Eine Variable, die eine Referenz auf eine
SWbemObjectSet-Collection speichert, wird colSWbemObjectSet genannt.
Mit dieser Namenskonvention fällt es Ihnen leichter, mit WMI-Objekten zu arbeiten. Ihr
Scriptcode wird leichter lesbar und einfacher zu pflegen. Natürlich können Sie auch beliebige
Variablennamen verwenden - wenn Ihre Variablen x und y heißen, dann ist das auch in
Ordnung. Die beiden folgenden Codestücke arbeiten zum Beispiel vollkommen gleich - sie
verwenden nur unterschiedliche Variablennamen:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")
strComputer = "."
Set x = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

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

Seite 356 von 394


Referenz auf das SWbemLocator-Objekt erhalten haben, rufen Sie die Methode
ConnectServer auf um sich mit WMI zu verbinden und eine Referenz auf ein SWbemServices-
Objekt zu erhalten (Zeile 3 im folgenden Beispielscript):
strComputer = "."
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objSWbemServices = objSWbemLocator.ConnectServer(strComputer,
"root\cimv2")
Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_Service")
For Each objSWbemObject In colSWbemObjectSet
Wscript.Echo "Name: " & objSWbemObject.Name
Next
Die Zeilen 2 und 3 sind identisch mit allen Beispielen zu GetObject, die Sie bereits gesehen
haben. ConnectServer ist die einzige Methode, die von SWbemLocator zur Verfügung gestellt
wird.
Um ein Script mit alternativen Anmeldeinformationen auszuführen, übergeben Sie
ConnectServer den Namen und das Passwort als optionale Parameter. Das folgende Script
wird zum Beispiel unter den Anmeldeinformationen des Benutzers kenmyer ausgeführt - sein
Passwort ist homerjs.
strComputer = "atl-dc-01"
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objSWbemServices = objSWbemLocator.ConnectServer _
(strComputer, "root\cimv2", "kenmyer", "homerjs")
Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_Service")
For Each objSWbemObject In colSWbemObjectSet
Wscript.Echo "Name: " & objSWbemObject.Name
Next
Sie können für den Benutzernamen alternativ auch das Format Domäne\Benutzer verwenden:
" fabrikam\kenmyer"
WMI-Scripte, die sich mit dem WMI-Dienst auf dem lokalen Computer verbinden,
verwenden immer den Sicherheitskontext des angemeldeten Benutzers. Für diese Scripte
können Sie über die Methode SWbemLocator.ConnectServer keinen abweichenden
Benutzernamen und ein Passwort angeben.
Sie sollten es vermeiden, Passwörter direkt in ein Script einzutragen. Stattdessen können Sie
zum Beispiel die Methoden WScript.StdOut und .StdIn verwenden, um den Scriptbenutzer zur
Eingabe des Passworts aufzufordern. Wenn das Script unter Windows XP Professional
ausgeführt wird, können Sie die Scripteingabe sogar über das Objekt ScriptPW unkenntlich
machen.
Das folgende Script demonstriert die Eingabe eines Passworts. Es verwendet die Methode
.StdIn, um das Passwort einzulesen und weist dieses dann der Variable strPassword zu. Da
das Script die Methoden StdIn und StdOut verwendet, muss es unter CScript ausgeführt
werden:
strComputer = "atl-dc-01"
Wscript.StdOut.Write "Geben Sie das Administrator-Passwort ein: "
strPassword = Wscript.StdIn.ReadLine
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objSWbemServices = objSWbemLocator.ConnectServer _
(strComputer, "root\cimv2", "administrator", strPassword)
Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_Service")
For Each objSWbemObject In colSWbemObjectSet
Wscript.Echo "Name: " & objSWbemObject.Name
Next

Seite 357 von 394


SWbemServices
SWbemServices hat zwei primäre Aufgaben. Erstens stellt das Objekt eine authentifizierte
Verbindung zu einem WMI-Namespace auf dem Zielcomputer dar, und zweitens verwenden
Sie SWbemServices zur Abfrage von verwalteten Ressourcen. Eine Referenz auf ein
SWbemServices-Objekt erhalten Sie über zwei Wege:

Wie Sie in den meisten bis jetzt gezeigten Scripten gesehen haben, können Sie die VBScript-
Funktion GetObject zusammen mit dem WMI-Moniker "winmgmts:" verwenden. Das
folgende Beispiel zeigt die einfachste Form einer WMI-Verbindung. Es verbindet sich mit
dem Standard-Namespace (normalerweise root\cimv2) des lokalen Computers:
Set objSWbemServices = GetObject("winmgmts:")

Sie können die Methode ConnectServer eines SWbemLocator-Objekts verwenden. Weitere
Informationen hierzu haben Sie im vorhergehenden Abschnitt SWbemLocator erhalten.
Nachdem Sie eine Referenz auf ein SWbemServices-Objekt haben, können Sie einer der 18
Methoden von SWbemServices aufrufen. SWbemServices kann drei unterschiedliche Objekte
zurückgeben (SWbemObjectSet, SWbemObject und SWbemEventSource). Sie sollten wissen,
welche Methode welches Objekt zurückgibt. Wenn sie zum Beispiel ein Objekt vom Typ
SWbemObjectSet zurückerhalten, müssen Sie eine Collection durchgehen, um an die
einzelnen SWbemObject-Objekte zu gelangen. Wenn Sie direkt ein SWbemObject-Objekt
zurück erhalten, können Sie sofort auf die Methoden und Eigenschaften des Objekts
zugreifen.
Die Methoden und die Rückgaben von SWbemServices sehen Sie in Tabelle 6.5.
Tabelle 6.5: Methoden von SWbemServices
Name der Methode Standardmodus Rückgabewert Beschreibung
AssociatorsOf Semisynchron SWbemObjectSet Ruft die Instanzen von den
verwalteten Ressourcen
einer
bestimmten Klasse ab. Sie
geben einen Objektpfad an,
und die Methode gibt eine
verwaltete Ressource
zurück.
Delete Synchron (kann keiner Löscht eine Instanz einer
nicht geändert verwalteten Ressource
werden) (oder eine Klassendefinition
im CIM-Repository).
ExecMethod Synchron (kann SWbemObject Bietet einen alternativen
nicht geändert Weg,
werden) um eine Methode
auszuführen,
die über die
Klassendefinition
einer verwalteten Ressource
definiert ist. Wird primär in
Situationen verwendet, in
denen eine Scriptsprache

Seite 358 von 394


Name der Methode Standardmodus Rückgabewert Beschreibung
keinen Parameter unterstützt
(zum Beispiel JScript).
ExecNotificationQuerySemisynchron SWbemEventSourceFührt eine
Ereignisabonnement-
abfrage durch, um
Ereignisse
entgegenzunehmen. Eine
Ereignisabonnementabfrage
ist eine Abfrage, die das
Ereignis definiert, das Sie
überwachen möchten.
Wenn das Ereignis auftritt,
übergibt die WMI-
Infrastruktur
ein entsprechendes Ereignis
an das Script.
ExecQuery Semisynchron SWbemObjectSet Führt eine Abfrage aus,
die eine Collection mit den
Instanzen einer verwalteten
Ressource zurückgibt
(oder mit
Klassendefinitionen).
Kann verwendet werden, um
eine gefilterte Collection mit
Instanzen zu erhalten.
Get Synchron (kann SWbemObject Ruft eine einzelne Instanz
nicht geändert einer verwalteten Ressource
werden) (oder Klassendefinition)
über einen Objektpfad ab.
InstancesOf Semisynchron SWbemObjectSet Ruft alle Instanzen einer
verwalteten Ressource auf
Basis eines Klassennamens
ab. Standardmäßig führt
InstancesOf eine
"Tiefenabfrage"
durch - das bedeutet, dass
alle Instanzen der
übergebenen
Klasse und alle Instanzen
der Unterklassen der
übergebenen Klasse
zurückgeliefert werden.
ReferencesTo Semisynchron SWbemObjectSet Gibt alle Zuordnungen
zurück, die eine bestimmte
Ressource referenzieren.
Im Gegensatz zu
AssociatorsOf (die

Seite 359 von 394


Name der Methode Standardmodus Rückgabewert Beschreibung
dynamische Ressourcen
zurückgibt), gibt
ReferencesTo
die entsprechende
Zuordnung
zurück.
SubclassesOf Semisynchron SWbemObjectSet Fragt alle Unterklassen
einer bestimmten Klasse
im CIM-Repository ab.
In Tabelle 6.5 finden Sie nur 9 der 18 Methoden von SWbemServices. Bei den restlichen 9
Methoden handelt es sich um die asynchronen Gegenstücke zu den gezeigten Methoden. Die
Namen der Methoden entsprechen den in der Tabelle gezeigten Namen mit einem
angehängten Suffix Async. Die asynchrone Version von ExecNotificationQuery heißt also
zum Beispiel ExecNotificationQueryAsync.

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.

Seite 360 von 394


Um dieses Problem zu umgehen, können Sie die Aufrufe von semisynchronen Methoden
optimieren, indem Sie das Flag wbemFlagForwardOnly verwenden. Mit dem
wbemFlagForwardOnly-Flag in Kombination mit dem Flag wbemFlagReturnImmediately
teilen Sie WMI mit, dass es eine forward-onlySWbemObjectSet-Collection zurückgeben soll.
Dieser Weg hat jedoch seinen Preis. Eine forward-onlySWbemObjectSet-Collection kann nur
einmal abgefragt werden. Nachdem auf ein Element der Collection zugegriffen wurde, wird
dieses aus dem Speicher entfernt.
Mit Ausnahme der Methoden Delete, ExecMethod, Get und den neun asynchronen Methoden
sollten Sie standardmäßig die semisychronen Methoden verwenden.
Verwenden der Methoden von SWbemServices
Zu den häufig verwendeten Methoden zählen InstancesOf, ExecQuery, Get und
ExecNotificationQuery. Auch wenn Sie oft verwendet wird, ist InstancesOf nicht der
empfohlene Weg, um Informationen abzurufen (auch wenn es wohl der einfachste Weg ist).
Warum dies so ist, wird im nächsten Abschnitt besprochen.

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

Seite 361 von 394


Die anderen Methoden von SWbemServices, die eine SWbemObjectSet-Collection
zurückgeben, sind AssociatorsOf, ReferencesTo und SubclassesOf.

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")

Set objSWbemObject = objSWbemServices.Get("Win32_Service.Name='Messenger'")

Wscript.Echo "Name: " & objSWbemObject.Name & vbCrLf & _


"Angezeigter Name: " & objSWbemObject.DisplayName & vbCrLf & _
"Starttyp: " & objSWbemObject.StartMode & vbCrLf & _
"Status: " & objSWbemObject.State
SWbemObjectSet
Ein SWbemObjectSet-Objekt ist eine Collection mit SWbemObject-Objekten. Jedes
SWbemObject-Objekt in der SWbemObjectSet-Collection kann eine der beiden folgenden
Instanzen sein:

Eine Instanz einer verwalteten Ressource.

Eine Instanz einer Klassendefinition.
Meistens ist das Einzige, was Sie mit einer SWbemObjectSet-Collection machen, das
Auflisten der einzelnen Elemente der Collection. SWbemObjectSet jedoch stellt auch eine sehr
nützliche Eigenschaft zur Verfügung (Count). Wie der Name schon sagt, gibt Count die
Anzahl der Elemente der Collection zurück. Das folgende Script ruft zum Beispiel eine
Collection mit allen installierten Diensten ab und gibt dann die Anzahl der gefundenen
Dienste aus:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")
Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_Service")
Wscript.Echo "Anzahl der installierten Dienste: " & colSWbemObjectSet.Count
Count ist deshalb so nützlich, weil Sie mit dieser Eigenschaft feststellen können, ob eine
bestimmte Instanz auf einem Computer vorhanden ist. Das folgende Script ruft zum Beispiel
eine Collection mit allen Diensten eines Computers auf, die den Namen W3SVC haben. Wenn
Count den Wert 0 zurückgibt, dann heißt das, dass der Dienst auf diesem Computer nicht
installiert ist.
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")
Set colSWbemObjectSet = objSWbemServices.ExecQuery _
("SELECT * FROM Win32_Service WHERE Name='w3svc'")
If colSWbemObjectSet.Count = 0 Then
Wscript.Echo "Der Dienst W3SVC ist nicht installiert."
Else
For Each objSWbemObject In colSWbemObjectSet
' Das Script die gewünschten Aktionen durchführen
' lassen

Seite 362 von 394


Next
End If
Eine Sache, die Sie bei der Verwendung von Count berücksichtigen sollen, ist das WMI keine
'Strichliste' über die Anzahl der Elemente einer Collection führt. Wenn Sie die Methode
Count ausführen, kann WMI nicht sofort mit einer Zahl antworten. Stattdessen muss WMI die
Elemente der Collection erst zählen. Bei einer Collection mit eine paar Elementen ist dies
Verhalten sicher irrelevant - bei einer Collection mit 1.000 Elementen kann die Zählung
jedoch eine ganz Weile dauern.

Schreiben von WMI-Scripten


Ein Punkt, der bereits mehrmals erwähnt wurde ist, dass die meisten WMI-Scripte nach einem
einfachen Muster mit drei Schritten vorgehen:
1.Sie verbinden sich mit dem WMI-Dienst.
2.Sie rufen ein WMI-Objekt oder eine Collection von WMI-Objekten ab.
3.Sie verarbeiten diese Objekte auf irgendeine Art und Weise. Bis jetzt wurden meist
Eigenschaften der Objekte ausgegeben. Sie können jedoch auch Eigenschaften ändern,
Methoden ausführen und Instanzen erstellen oder löschen.
Damit Sie gute WMI-Scripte schreiben können, müssen Sie die Einzelheiten der drei Schritte
verstehen. Der vorherige Abschnitt dieses Kapitels war sehr theoretisch - Sie haben
Hintergrundinformationen dazu erhalten, was WMI ist und was man damit machen kann. In
diesem Teil des Kapitels wollen wir uns einem mehr praktischen Ansatz zuwenden. Sie
erhalten eine detaillierte Übersicht über die drei Schritte.
1.Die Verwendung des WMI-Monikers wird erklärt - eine vielseitige Methode, um eine
Verbindung zum WMI-Dienst aufzubauen.
2.Die Verwendung von ExecQuery, einer Methode von SWbemServices, die eine Alternative
Methode zur Abfrage von WMI-Daten zur Verfügung stellt, wird erklärt.
3.Sie erhalten Vorlagen, die Sie als Basis für eigene Scripte verwenden können.
Außerdem werden zwei weitere wichtige Elemente von WMI-Scripten besprochen: Die
Arbeit mit Daten- und Zeitwerten unter WMI und die Überwachung von Ereignissen.

Eine Verbindung zu WMI über den WMI-Moniker aufbauen


Die WMI-Scripting-Bibliothek stellt zwei Mechanismen zur Verfügung, über die Sie eine
Verbindung mit WMI aufbauen können: Das Objekt SWbemLocator und den WMI-Moniker
'winmgmts:'. Diese beiden Mechanismen unterscheiden sich außer durch ihre Syntax dadurch,
dass Sie bei SWbemLocator einen Benutzernamen und ein Passwort angeben können und
beim WMI-Moniker nicht. Das Objekt SWbemLocator wird im Abschnitt WMI Scripting
Library dieses Kapitels genauer besprochen.

Das Prefix 'WinMgmts:'


WMI-Moniker können aus drei Teilen bestehen: Einem verpflichtenden und zwei optionalen
Teilen. Die verpflichtende Komponente ist das Prefix 'winmgmts:', mit dem alle WMI-
Moniker anfangen müssen:

Seite 363 von 394


Set objSWbemServices = GetObject("winmgmts:")
Beim WMI-Moniker wird im Gegensatz zum ADSI-Provider übrigens nicht zwischen Groß-
und Kleinschreibung unterschieden.
Ein Moniker, der nur aus dem Prefix 'winmgmts:' besteht, ist die einfachste Form, die Sie
verwenden können. Als Ergebnis erhalten Sie eine Referenz auf ein SWbemServices-Objekt,
das eine Verbindung zum WMI-Dienst des lokalen Computers darstellt:
1.Es wird die WMI CLSID aus dem Registrierungsschlüssel HKCR\WINMGMTS\CLSID
abgefragt. Die CLSID ({172BDDF8-CEEA-11D1-8B05-00600806D9B6}) ist eine ID, die
vom Betriebssystem verwendet wird, um WMI dem entsprechenden COM-Objekt
zuzuordnen.
2.Es wird ein zweiter Wert aus dem Registrierungsschlüssel HKCR\CLSID\{172BDDF8-
CEEA-11D1-8B05-00600806D9B6}\InProcServer32 abgefragt. Dieser Wert
(normalerweise C:\Windows\System32\wbem\wbemdisp.dll) zeigt den Pfad zu dem COM-
Objekt an, dass das Objekt SWbemServices zur Verfügung stellt.
3.Die DLL Wbemdisp.dll wird geladen. Sie enthält die WMI-Scripting-Bibliothek und stellt
das Objekt SWbemServices endgültig zur Verfügung.
Nachdem eine Referenz auf ein SWbemServices-Objekt zur Verfügung steht, können Sie
[folgende?]Methoden ausführen:
Set objSWbemServices = GetObject("winmgmts:")
Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_LogicalDisk")
In diesem Beispiel wird eine Referenz-Variable mit dem Namen objSWbemServices mit dem
Moniker 'winmgmts:' initialisiert. Diese Variable wird dann zum Aufrufen der Methode
InstancesOf des SWbemServices-Objekts verwendet.
Auch wenn das Beispiel nicht sehr lang ist, kann es durchaus noch kürzer werden. Sie können
die gleiche Funktionalität zum Beispiel auch über eine Scriptzeile implementieren:
Set colSWbemObjectSet =
GetObject("winmgmts:").InstancesOf("Win32_LogicalDisk")
In diesem Beispiel wird keine Variable verwendet (objSWbemServices im vorherigen
Beispiel), um die Referenz aufzunehmen. Stattdessen wird die vom Moniker erstellte
Referenz auf das SWbemServices-Objekt sofort zum Aufrufen der Methode InstancesOf
verwendet.
Beide Beispiele produzieren das gleiche Ergebnis - eine SWbemObjectSet-Collection mit allen
Instanzen der Klasse Win32_LogicalDisk des lokalen Computers.

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}".

Seite 364 von 394



Authentifizierungsautorität - "winmgmts:{authority=NTLMDomäne:Domänenname}" oder
"winmgmts:{authority=kerberos:Domänenname\Servername}".

Gewährte oder verweigerte Rechte - zum Beispiel "winmgmts:{(Security,
!RemoteShutdown)}".

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.

Tabelle 6.6: DCOM-Personifizierungsebenen


Wert Beschreibung
Anonymous Verbirgt die Anmeldeinformationen des Aufrufers.
Diese Ebene wird von WMI im Moment nicht
unterstützt. Wenn ein Script die Einstellung
impersonationLevel=Anonymous verwendet,
setzt WMI die Einstellung ohne Hinweis auf Identify.
Identify Ermöglicht Objekten die Anmeldeinformationen
des Aufrufers abzufragen. Scripte, die diese
Personifizierungsebene verwenden, werden
wahrscheinlich fehlschlagen. Mit der Einstellung
Identify können Sie normalerweise nicht mehr
machen, als ACLs (Zugriffskontrolllisten - Access
Control Lists) zu überprüfen. Sie sind mit Identify
nicht in der Lage, ein Script gegen einen
Remotecomputer auszuführen.
ImpersonateErmöglicht es Objekten die Anmeldeinformationen
des Aufrufers auszulesen. In WMI-Scripten
sollten Sie diese Personifizierungsebene
verwenden. Mit ihr kann das Script Ihre
Anmeldeinformationen verwenden.
Delegate Ermöglicht es Objekten, anderen Objekten das
Auslesen der Anmeldeinformationen des
Aufrufers zu gestatten. Mit der Einstellung Delegate
kann ein Script Ihre Anmeldeinformationen auf
einem Remotecomputer verwenden, und der
Remotecomputer kann Ihre Anmeldeinformationen
auf einem weiteren Remotecomputer verwenden.
Diese Einstellung kann ein potentielles
Sicherheitsrisiko darstellen. Wenn die in den Vorgang einbezogenen
Benutzer- und Computerkonten in Active
Directory nicht mit der Einstellung Für
Delegierungszwecke vertrauen konfiguriert sind,

Seite 365 von 394


Wert Beschreibung
können Sie die Konten nicht verwenden.
Der Vorgang wird in diesem Fall fehlschlagen.
Die Einstellung Anonymous verhindert, wie gesagt, dass Ihre Anmeldeinformationen an ein
Remoteobjekt weitergegeben werden. Die Einstellung Identify erlaubt es Remoteobjekten, die
Anmeldeinformationen abzufragen. Das Remoteobjekt ist jedoch trotzdem nicht in der Lage,
diese Informationen zu verwenden. Scripte, die eine dieser beiden Einstellungen verwenden,
schlagen prinzipiell fehl - dies gilt sogar für die meisten Scripte, die auf einem lokalen
Computer ausgeführt werden.
Die Einstellung Delegate erlaubt es einem Remote-WMI-Dienst Ihre Anmeldeinformationen
an Objekte weiterzugeben - dies ist ein generelles Sicherheitsrisiko.
Das Standardverhalten der Einstellung Personifizierungsebene unterscheidet sich leider
zwischen den unterschiedlichen WMI-Versionen. Die Versionen vor 1.5 verwenden als
Standardeinstellung Identify. Seit Version 1.5 (mit Windows 2000 veröffentlicht) wurde die
Standardeinstellung auf Impersonate geändert. Die Standardeinstellung wird über den
folgenden Registrierungsschlüssel definiert:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\Scripting\Default Impersonation
Level
Wenn Ihre WMI-Scripte nur mit Computern mit WMI-Version 1.5 oder höher arbeiten,
brauchen Sie sich um die Einstellung ImpersonationLevel nicht kümmern. Um auch ältere
Versionen zu unterstützen und um Fehler zu vermeiden, sollten Sie jedoch trotzdem in jedem
Script die Einstellung impersonationLevel explizit angeben.

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.

Tabelle 6.7: DCOM-Authentifizierungsebene


Wert Beschreibung
None Keine Authentifizierung.
Default Verwendet eine Standardsicherheitsaushandlung,
um die Authentifizierungsebene festzulegen.
Dies ist die empfohlene Einstellung.
Connect Führt eine Authentifizierung nur dann durch,
wenn der Client versucht sich mit einem
Server zu verbinden. Nachdem die Verbindung
aufgebaut wurde, wird keine weitere Authentifizierung
mehr durchgeführt.
Call Authentifiziert den Client nur bei Beginn eines
jeden Aufrufs. Die Paketheader werden signiert.
Die Datenpakete sind jedoch weder signiert

Seite 366 von 394


Wert Beschreibung
noch verschlüsselt.
Pkt Authentifiziert alle Datenpakete. Wie bei Call
werden alle Header signiert, jedoch nicht verschlüsselt.
Die Pakete selbst werden weder signiert noch
verschlüsselt.
PktIntegrityAuthentifiziert alle Datenpakete.
Jedes Datenpaket ist signiert.
Kein Paket wird verschlüsselt.
PktPrivacy Führt alle Authentifizierungen der anderen
Stufen durch und verschlüsselt alle Datenpakete.

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.

Tabelle 6.8: Berechtigungen


Recht Beschreibung
MachineAccount Erforderlich, um ein Computerkonto zu erstellen.
Security Erforderlich, um einige sicherheitsbezogene
Funktionen auszuführen (zum Beispiel das
Anzeigen von Überwachungsnachrichten).
TakeOwnership Erforderlich, um den Besitz an einem
Objekt zu übernehmen.
LoadDriver Erforderlich, um Gerätetreiber zu laden
und zu entladen.
SystemProfile Erforderlich, um das Systemprofil
abzufragen.
SystemTime Erforderlich, um die Systemzeit zu ändern.
ProfileSingleProcessErforderlich, um Informationen über
einen Prozess abzufragen.
IncreaseBasePriorityErforderlich, um die Basispriorität

Seite 367 von 394


Recht Beschreibung
eines Prozesses zu erhöhen.
CreatePagefile Erforderlich, um eine Auslagerungsdatei
zu erstellen.
Backup Erforderlich, um Sicherungsoperationen
durchzuführen.
Restore Erforderlich, um Wiederherstellungen
durchzuführen.
Shutdown Erforderlich, um den lokalen
Computer herunterzufahren.
Audit Erforderlich, um Einträge im
Überwachungsprotokoll zu generieren.
RemoteShutdown Erforderlich, um einen Computer
über das Netzwerk herunterzufahren.
Undock Erforderlich, um aus der
Dockingstation zu entfernen.
SyncAgent Erforderlich, zur Synchronisierung
von Verzeichnisdienstdaten.
Wenn Sie ein Recht verweigern möchten, können Sie dies tun, indem Sie dem Recht ein
Ausrufezeichen (!) voranstellen.
Der folgende Moniker gewährt zum Beispiel das Recht LockMemory und verweigert das
Recht IncreaseQuota:
Set objSWbemServices = GetObject _
("winmgmts:{impersonationLevel=impersonate,(LockMemory, !IncreaseQuota)}")
Wenn Sie in einem Script Rechte gewähren, werden diese nicht auf den Benutzer übertragen.
Nehmen wir zum Beispiel an, Sie führen ein Script aus, das das Recht Shutdown gewährt.
Wenn Sie nicht bereits über das Recht verfügen, können Sie auch über ein Script dieses Recht
nicht wahrnehmen. Um ein Recht wahrnehmen zu können, müssen zwei Bedingungen erfüllt
sein:

Das Script muss das Recht im Verbindungsstring gewähren.

Sie müssen bereits über das Recht verfügen.

Moniker mit Sicherheitseinstellungen


Das Format für Moniker mit Sicherheitseinstellungen sieht folgendermaßen aus:
Set objSWbemServices = GetObject("winmgmts:" & _
"{SecuritySetting1=Wert," & _
"SecuritySetting2=Wert," & _
"(Recht1,!Recht2)}")

Seite 368 von 394


Verwenden von WMI-Objektpfaden
Bei der dritten Komponente des WMI-Monikers handelt es sich um den WMI-Objektpfad.
Für die Sicherheitseinstellungen ist diese Komponente optional. Mit WMI-Objektpfaden
können Sie eine oder mehrere der folgenden Zielressourcen eindeutig identifizieren:

Remotecomputer - Wenn der Computer im Objektpfad nicht angegeben wird, dann wird das
Script gegen den lokalen Computer ausgeführt:
Set objSWbemServices = GetObject("winmgmts:")

Der folgenden Moniker verbindet sich mit dem WMI-Dienst des Remotecomputers atl-dc-
01:
Set objSWbemServices = GetObject("winmgmts:\\atl-dc-01")

Computernamen werden normalerweise über den NetBIOS-Namen des Computers


angegeben. DNS-Namen und IP-Adressen sind jedoch ebenfalls möglich (zum Beispiel atl-
dc-01.fabrikam.com oder 192.168.1.1).

WMI-Namespace - Wenn der Namespace nicht angegeben wird, dann wird der Standard-
Namespace verwendet. Der folgende Moniker verbindet sich mit dem Standard-Namespace
auf dem Remotecomputer 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:'")

Format von Objektpfaden


In einem Objektpfad werden Computername und WMI-Namespace durch die Zeichen Slash
oder Backslash getrennt. Gültige Objektpfade sind zum Beispiel:
\\WebServer\root\cimv2
//WebServer/root/cimv2

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

Seite 369 von 394


Um eine direkte Instanz einer Klasse (zum Beispiel einen bestimmten Dienst) anzugeben,
müssen Sie den Klassennamen und durch einen Punkt (.) getrennt die Schlüsseleigenschaft
angeben. Dann folgt der Wert dieser Eigenschaft der gesuchten Instanz:
\\WebServer\root\cimv2:Win32_Service.Name="Alerter"
Schlüsseleigenschaften
Die Schlüsseleigenschaft ist eine Eigenschaft, die zur eindeutigen Identifizierung einer
Instanz verwendet werden kann. Die Schlüsseleigenschaft der Klasse Win32_Service ist zum
Beispiel die Eigenschaft Name - und zwar darum, weil jeder Dienst einen eindeutigen Namen
hat. Die Eigenschaft StartMode ist hingegen keine Schlüsseleigenschaft - der Starttyp kann
bei vielen Diensten gleich sein. Der folgende Verbindungsstring schlägt daher fehl:
Set colServices = GetObject _
("winmgmts:\\.\root\cimv2\Win32_Service.StartMode='Auto'")
Wenn Sie versuchen dieses Script auszuführen, erhalten Sie die Fehlermeldung 'Ungültiger
Syntax':

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

Abfragen von verwalteten Ressourcen über die WMI-Abfragesprache


Über WMI-Abfragen können Sie Daten oder Ereignisse nach vordefinierten Kriterien abrufen.
Eine WMI-Abfrage kann zum Beispiel alle Dienste mit dem Starttyp Automatisch, die im
Moment angehalten sind, zurückgeben. Eine WMI-Ereignisabfrage können Sie verwenden,
um zum Beispiel beim Anhalten und Starten von Diensten benachrichtigt zu werden. Da der
WMI-Abfrageprozessor ein Teil des WMI-Dienstes ist, können Sie WMI auf alle Daten des
CIM abfragen.
WMI-Abfragen sind ein effizienterer Mechanismus zum Abfragen von Objektinstanzen als
die Methode InstancesOf. WMI-Abfragen geben nur die Instanzen und Daten zurück, die der
Abfrage entsprechen. InstancesOf gibt hingegen alle Objektinstanzen einer Klasse zurück.
Abfragen werden außerdem auf dem Zielcomputer im Objektpfad ausgeführt statt auf dem
Computer, auf dem das Script gestartet wurde. Daher verringern WMI-Abfragen den
Netzwerkverkehr.
Um WMI-Abfragen durchzuführen, erstellt der Administrator einen Abfragestring mit der
WMI-Abfragesprache (WMI Query Language - WQL). Der Abfragestring definiert die
Kriterien der zurückzugebenden Instanzen und Daten. Der Abfragestring wird dann über eine
von mehreren Methoden des SWbemServices-Objekts an WMI übergeben. Das Script erhält
die Ergebnisse der Abfrage über eine SWbemObjectSet-Collection zurück.

Seite 370 von 394


WQL ist eine Untermenge von ANSI-SQL (Structured Query Language). SQL wird
normalerweise in Datenbanken verwendet. Der Hauptzweck von WQL ist das Abfragen von
Informationen. SQL-Funktionen wie UPDATE und DELETE werden von WQL nicht
unterstützt. Außerdem können Sie mit WQL keine Sortierreihenfolge angeben.
Mit WQL und der Methode ExecQuery können Sie viel flexiblere Scripte als mit InstancesOf
schreiben. Sie erhalten nur die Elemente, die für Sie interessant sind. Sie können zum Beispiel
eine grundlegende WQL-Abfrage verwenden, um allen Eigenschaften aller Instanzen einer
bestimmten Klasse abzufragen - diese Informationen würden Sie jedoch auch über die
Methode InstancesOf erhalten. Mit WQL können Sie jedoch deutlich mehr machen. Zum
Beispiel:

Abfragen von ausgewählten Eigenschaften für alle Instanzen einer Klasse.

Abfragen von allen Eigenschaften für ausgewählte Instanzen einer Klasse.

Abfragen von ausgewählten Eigenschaften für ausgewählte Instanzen einer Klasse.
Solche zielgerichteten Abfragen beschleunigen die Geschwindigkeit von Abfragen in einigen
Situationen deutlich - auch die Arbeit mit den zurückgegebenen Daten wird einfacher.
Zielgerichtete Anfragen können außerdem die zurückgegebenen Daten deutlich einschränken.
Bei Scripten, die über das Netzwerk ausgeführt werden, ist dies unter umständen sehr wichtig.
In Tabelle 6.9 sehen Sie einige Werte für unterschiedliche Abfragetypen. Wie Sie sehen, ist
die zurückgegebene Datenmenge teilweise sehr unterschiedlich.

Tabelle 6.9: Vergleich von WMI-Abfragen


Abfrage Bytes zurückgegeben
objSWbemServices.Instances 157.398
Of("Win32_Service")
objSWbemServices.ExecQuery 156.222
("SELECT * FROM Win32_Service")
objSWbemServices.ExecQuery 86.294
("SELECT Name FROM Win32_Service")
objSWbemServices.ExecQuery 88.116
("SELECT StartMode FROM Win32_Service")
objSWbemServices.ExecQuery _ 52.546
("SELECT StartMode FROM Win32_
Service WHERE State='Running'")
objSWbemServices.ExecQuery _ 56.314
("SELECT StartMode, State FROM Win32_
Service WHERE State='Running'")
objSWbemServices.ExecQuery _ 27.852
("SELECT * FROM Win32_Service
WHERE Name='WinMgmt'")
objSWbemServices.Get("Win32_ 14.860
Service.Name='WinMgmt'")

Seite 371 von 394


Anmerkung: Das bedeutet nicht notwendigerweise, dass die Abfragen mit den wenigsten
Daten die beste Lösung darstellen. Sie geben einfach nicht alle Eigenschaften zurück. Wenn
Sie alle Eigenschaften benötigen, bleibt Ihnen nichts anderes übrig, als eine andere Abfrage
zu verwenden.

Abfragen aller Eigenschaften aller Instanzen einer Klasse


Die einfachste WQL-Abfrage ist die, die alle Eigenschaften einer Instanz einer Klasse abfragt.
Hierzu gehen Sie folgendermaßen vor:

Sie verwenden einen Stern (*), um anzuzeigen, dass Sie alle Eigenschaften abfragen wollen.

Sie geben den Namen der Klasse an.
Diese Abfrage gibt zum Beispiel alle Eigenschaften aller installierten Dienste zurück:
"SELECT * FROM Win32_Service"
Der Vorteil einer SELECT * Abfrage ist, dass dieses Verfahren schnell und einfach ist. Der
Nachteil ist, dass Sie möglicherweise viel mehr Informationen zurückerhalten, als Sie
benötigen. Eine Abfrage, die zum Beispiel alle Eigenschaften aller installierten Laufwerke
zurückgibt, produziert ca. 808 Byte an Daten. Eine Abfrage, die nur die Eigenschaft Name
zurückgibt, produziert nur 145 Byte an Daten. Die Abfrage SELECT * wird in weniger als
zwei Sekunden ausgeführt. Die Abfrage SELECT Name benötigt jedoch nur weniger als eine
Sekunde. Möglicherweise finden Sie den Unterschied zwischen den beiden Scripten
unbedeutend.
In anderen Fällen kann der Unterschied jedoch dramatisch sein. Ein Script, das alle
Eigenschaften aller auf einem Computer ausgeführten Threads anzeigt, benötigt hierzu ca. 7
Sekunden und gibt 105 KB Daten zurück. Ein Script, das nur das Thread-Handle zurückgibt,
benötigt nur eine Sekunde und gibt nur 6 KB Daten zurück.
Script 6.18 verwendet eine Standard-WQL-Abfrage, die alle Eigenschaften aller installierten
Dienste zurückgibt.

Script 6.18: Abfragen aller Eigenschaften aller Instanzen einer Klasse

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

Abfragen ausgewählter Eigenschaften aller Instanzen einer Klasse


Wie Sie bereits wissen, wird ein Script schneller ausgeführt und gibt weniger überflüssige
Daten zurück, wenn Sie nur bestimmte Eigenschaften einer Klasse abfragen. Hierzu ersetzen
Sie in der Abfrage den Stern durch die Namen der zurückgegebenen Eigenschaften. Die
folgende Abfrage gibt nur die Eigenschaft Name aller Instanzen der Klasse Win32_Service
zurück:

Seite 372 von 394


"SELECT Name FROM Win32_Service"
Wenn Sie mehrere Eigenschaften zurückgeben möchten, dann trennen Sie die
Eigenschaftsnamen durch Kommata. Die folgende Abfrage gibt zum Beispiel die
Eigenschaften Name und State der Klasse Win32_Service zurück:
"SELECT Name, State FROM Win32_Service"
Was bedeutete es, nur ausgewählte Eigenschaften zurückzugeben? Sehen Sie sich das
folgende Script an. Es ruft nur die Eigenschaft Name der Klasse Win32_Service ab, versucht
jedoch auch die State auszugeben:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")

Set colServices = objSWbemServices.ExecQuery _


("SELECT Name FROM Win32_Service")

For Each objService In colServices


Wscript.Echo objService.Name, objService.State
Next
Wenn Sie das Script unter CScript ausführen, erhalten sie die folgende Fehlermeldung:
Laufzeitfehler in Microsoft VBScript: Das Objekt unterstützt diese
Eigenschaft oder Methode nicht:
'objService.State'
Warum diese Fehlermeldung? State ist zwar eine gültige Eigenschaft der Klasse
Win32_Service, Sie haben Sie jedoch nicht abgefragt. Daher ist die Eigenschaft State in der
Collection nicht vorhanden. Da das Script die zurückgegebene Collection und nicht die Klasse
selbst abfragt, kommt es zu dem Fehler.
Es gibt eine Ausnahme: Die Schlüsseleigenschaft wird immer zurückgegeben - auch dann,
wenn Sie in der WQL-Abfrage nicht angegeben wurde. Name ist zum Beispiel die
Schlüsseleigenschaft der Klasse Win32_Service. Das folgende Script fragt nur die Eigenschaft
State ab. Bei der Ausgabe kann es jedoch auch die Eigenschaft Name verwenden:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")

Set colServices = objSWbemServices.ExecQuery _


("SELECT State FROM Win32_Service")

For Each objService In colServices


Wscript.Echo objService.Name, objService.State
Next
Wenn Sie das Script unter Cscript ausführen, schlägt es nicht fehl. Stattdessen erhalten Sie die
folgende Ausgabe:
Alerter Stopped
ALG Stopped
AppMgmt Stopped
Ati HotKey Poller Stopped
AudioSrv Running
BITS Running

Abfragen aller Eigenschaften für ausgewählten Instanzen einer Klasse


Die beiden bisherigen WQL-Abfragen haben Informationen für jede Instanz einer bestimmten
Klasse zurückgegeben. Oft benötigen Sie jedoch nur eine Untermenge der Instanzen - zum

Seite 373 von 394


Beispiel, wenn Sie nur Informationen über die Dienste erhalten möchten, die angehalten
wurden oder nur über Festplatten (nicht über Diskettenlaufwerke oder CD-Rom-Laufwerke).
In solchen Situationen ist eine Rückgabeliste mit allen Instanzen kontraproduktiv. Sie müssen
die Liste erst nach den gewünschten Instanzen durchsuchen.
In anderen Fällen kann die Beschränkung auf einzelne Instanzen einer Klasse einen
deutlichen Zeitunterschied ausmachen. Stellen Sie sich vor, Sie möchten ein Ereignisprotokoll
mit ca. 48.000 Einträgen abfragen. Ein Script, das nur 4.000 Einträge abfragt, würde schon ca.
18 Sekunden benötigen. Und wie lange braucht das Script für die gesamten 48.000 Einträge?
Das weiß leider keiner - nach 41.592 Einträgen ist das Script wegen Speichermangel
abgestürzt.

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.).

Verwenden von Strings in WHERE-Bedingungen


Vielleicht ist Ihnen aufgefallen, dass der Wert (System) in der vorhergehenden Abfrage in
Hochkommata eingeschlossen war. Dies ist immer dann erforderlich, wenn der Wert für die
WHERE-Bedingung ein String ist. Das folgende Script gibt zum Beispiel die Namen aller
Dienste zurück, die angehalten sind:

Win32_Service ist die WMI-Klasse, die abgefragt wird.

Seite 374 von 394



State ist die Eigenschaft.

Stopped ist der gesuchte Wert der Eigenschaft. Da es sich um einen String handelt muss
dieser in Hochkommata eingeschlossen werden:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")

Set colServices = objSWbemServices.ExecQuery _


("SELECT * FROM Win32_Service WHERE State = 'Stopped'")

For Each objService In colServices


Wscript.Echo objService.Name
Next
Verwenden von Zahlen- und Boolean-Werten in WHERE-Bedingungen
Wenn Sie Zahlen oder Boolean-Werte (True oder False) verwenden, dann müssen diese nicht
in Hochkommata eingeschlossen werden. Das folgende Script fragt zum Beispiel alle Dienste
ab, die angehalten werden können:

Win32_Service ist die abgefragte WMI-Klasse.

AcceptPause ist die Eigenschaft.

True ist der gesuchte Wert der Eigenschaft.
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")

Set colServices = objSWbemServices.ExecQuery _


("SELECT * FROM Win32_Service WHERE AcceptPause = True")

For Each objService In colServices


Wscript.Echo objService.Name
Next
Verwenden von Variablen in einer WHERE-Bedingung
Statt ein Script zu schreiben, das immer die gleichen Informationen abfragt, können Sie das
Script so verändern, dass Sie die gesuchten Informationen über Kommandozeilenargumente
angeben können.
Hierzu müssen Sie den gesuchten Wert in einer Variablen speichern und diese dann in der
WQL-Abfrage verwenden. Nehmen wir einmal an, die gewünschte Abfrage soll so aussehen:
SELECT * FROM Win32_Service WHERE State = 'Stopped'"
Diese Abfrage können wir nun verändern. Statt den String direkt in die Abfrage einzutragen,
können Sie diesen auch in einer Variablen speichern.
strState = "Stopped"
Diese variable können Sie nun in der Abfrage verwenden:
"SELECT * FROM Win32_Service WHERE State ='" & strState & "'"
Wie Sie wissen, können Sie Strings mit dem kaufmännischen Und verketten. Die gilt
natürlich auch für eine Mischung aus Strings und Variablen, die Strings enthalten.
Wenn Sie das nächste Script unter dem Namen ServiceState.vbs speichern, können Sie es mit
der folgenden Befehlszeile aufrufen:
Seite 375 von 394
cscript servicestate.vbs running
strState = Wscript.Arguments.Item(0)

strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")

Set colServices = objSWbemServices.ExecQuery _


("SELECT * FROM Win32_Service WHERE State = '" & strState & "'")

For Each objService In colServices


Wscript.Echo objService.Name
Next
Im Script wird die Zeile mit der WQL-Abfrage dann zu folgender Abfrage aufgelöst:
("SELECT * FROM Win32_Service WHERE State = 'running'")
Das Script liefert so alle im Moment ausgeführten Dienste zurück.

Zielgerichtete Abfragen über AND oder OR erstellen


Mit den Schlüsselwörtern AND und OR können Sie komplexere Abfragen erstellen.
Mit dem Schlüsselwort AND können Sie den Bereich einer Abfrage einschränken. Nehmen
wir zum Beispiel einmal an, Sie möchten eine Liste der Dienste mit dem Starttyp
Automatisch, die angehalten sind, abfragen. Hierzu sind in der WHERE-Bedingung zwei
Parameter notwendig - die Eigenschaft State, die den Wert Stopped haben muss und die
Eigenschaft StartMode, die den Wert Auto haben muss. Die beiden Parameter müssen Sie mit
dem Schlüsselwort AND verknüpfen:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")

Set colServices = objSWbemServices.ExecQuery _


("SELECT * FROM Win32_Service WHERE State = 'Stopped' AND StartMode =
'Auto'")

For Each objService In colServices


Wscript.Echo objService.Name
Next
Mit dem Schlüsselwort OR können Sie hingegen den Abfragebereich erweitern. Nehmen wir
an, Sie benötigen alle Dienste, die den Status stopped oder paused haben. In diesem Fall
verwenden Sie das Schlüsselwort OR.
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & strComputer &
"\root\cimv2")

Set colServices = objSWbemServices.ExecQuery _


("SELECT * FROM Win32_Service WHERE State = 'Stopped' OR State =
'Paused'")

For Each objService In colServices


Wscript.Echo objService.Name
Next

Seite 376 von 394


Ausgewählte Eigenschaften für ausgewählte Instanzen einer Klasse
zurückgeben
Sie haben die Möglichkeit, nur ausgewählte Eigenschaften für ausgewählte Klassen
zurückzugeben. Hierzu gehen Sie folgendermaßen vor:

Geben Sie die zurückzugebenden Eigenschaften an.

Schränken Sie die zurückgegebenen Instanzen über eine WHERE-Bedingung ein.
Eine solche Abfrage ist sozusagen eine Kombination aus zwei Abfragen. Das folgende Script
gibt nur die Eigenschaften Name und State der Dienste zurück, die angehalten werden
können:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")

Set colServices = objSWbemServices.ExecQuery _


("SELECT Name, State FROM Win32_Service WHERE AcceptPause = True")

For Each objService In colServices


Wscript.Echo objService.Name, objService.State
Next

Schnellere Abfragen über Forward-only erzeugen


In einigen Fällen können Sie eine Abfrage über die Option Forward-Only beschleunigen.
Unter Windows 2000 benötigt ein Script zur Abfrage von 10.000 Ereignissen zum Beispiel 47
Sekunden. Mit der Option Forward-Only sind es nur noch 28 Sekunden. Die Differenz von 19
Sekunden scheint nicht sehr groß zu sein, aber wenn Sie das Script auf allen 50
Domänencontrollern ausführen, sieht die Sache ganz anders aus.
Für die Forward-Only-Auflistung von Elementen müssen Sie der Methode ExecQuery drei
Parameter angeben. Der erste Parameter ist die WQL-Abfrage. Der zweite Parameter gibt die
Abfragesprache an - sie sollten Ihn entweder nicht definieren oder hier 'WQL' angeben. Der
dritte Parameter ist der Wert 48. Er steht für zwei Flags (Schalter):

wbemFlagReturnImmediately (Dezimalwert 16) - Dieser Schalter sorgt dafür, dass
ExecQuery semisynchron ausgeführt wird.

wbemFlagForwardOnly (Dezimalwert 32) - Dieser Schalter sorgt dafür, dass eine Forward-
Only-Collection zurückgeben wird.
Eine Forward-Only-Auflistung wird normalerweise schneller als eine normale Abfrage
ausgeführt - außerdem benötigt sie weniger Speicher. Wie Sie wissen, wird jedoch jedes
Element einer solchen Collection nach der ersten Abfrage aus dem Speicher entfernt. Sie
können also nicht zweimal auf ein Element zugreifen.
Das folgende Script verwendet das Forward-Only-Flag und gibt Ereignisse aus dem
Ereignisprotokoll zurück:
Const wbemFlagReturnImmediately = 16
Const wbemFlagForwardOnly = 32

strComputer = "."
Set objSWbemServices = _
GetObject("winmgmts:{(Security)}\\" & strComputer & "\root\cimv2")

Seite 377 von 394


Set colNTLogEvents = objSWbemServices.ExecQuery _
("SELECT * FROM Win32_NTLogEvent", , _
wbemFlagReturnImmediately + wbemFlagForwardOnly)

For Each objNTLogEvent In colNTLogEvents


Wscript.Echo "LogFile: " & objNTLogEvent.LogFile & _
vbCrLf & _
"RecordNumber: " & objNTLogEvent.RecordNumber & _
vbCrLf & _
"Type: " & objNTLogEvent.Type & _
vbCrLf & _
"TimeGenerated: " & objNTLogEvent.TimeGenerated & _
vbCrLf & _
"Source: " & objNTLogEvent.SourceName & _
vbCrLf & _
"Category: " & objNTLogEvent.Category & _
vbCrLf & _
"CategoryString: " & objNTLogEvent.CategoryString & _
vbCrLf & _
"Event: " & objNTLogEvent.EventCode & _
vbCrLf & _
"User: " & objNTLogEvent.User & _
vbCrLf & _
"Computer: " & objNTLogEvent.ComputerName & _
vbCrLf & _
"Message: " & objNTLogEvent.Message & _
vbCrLf
Next
Wenn Sie das Forward-Only-Flag verwenden, können Sie die Methode
SWbemObjectSet.Count nicht mehr verwenden. Die Methode Count zählt die Elemente einer
Collection, indem es sie einzeln durchgeht. Hierbei werden die Elemente einer Forward-Only-
Collection natürlich alle aus dem Speicher entfernt.

Arbeiten mit Datum- und Zeitwerten


Die Handhabung von Daten und Zeiten durch WMI ist etwas verwirrend. Das folgende
einfache Script gibt zum Beispiel das Installationsdatum des Betriebssystems zurück:
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")
Set colOS = objSWbemServices.ExecQuery _
("SELECT * FROM Win32_OperatingSystem")
For Each objOS in colOS
Wscript.Echo objOS.InstallDate
Next
Wenn Sie das Script unter CScript ausführen, erhalten Sie die folgende Ausgabe:
20011224113047.000000+60
Das ist kein Fehler - die Ausgabe des Scripts ist tatsächlich 20011224113047.000000+60.
Dieser Wert besagt, dass das Betriebssystem am 24. Dezember 2001 installiert wurde. Das
Datum ist korrekt - das Problem ist, dass das Datum im UTC-Format angezeigt wird
(Universal Time Coordinate).
Im UTC-Format werden Daten so angezeigt: yyyymmddHHMMSS.xxxxxx±UUU. Die
einzelnen Buchstaben bedeuten:

yyyy das Jahr.

Seite 378 von 394



mm der Monat.

dd der Tag.

HH die Stunde (im 24-Stunden Format).

MM die Minuten.

SS die Sekunden.

xxxxxx die Millisekunden.

±UUU die Differenz der lokalen Zeitzone und Greenwich Mean Time (GMT) in Sekunden.
Der Wert 20011224113047.000000+60 kann also so übersetzt werden:

2001 Jahr.

12 Monat (Dezember).

24 Tag.

11 Stunden.

30 Minuten.

47 Sekunden.

000000 Millisekunden.

-480 Differenz der lokalen Zeitzone zu GMT.
Bei einem solchen Format ist es natürlich nicht ganz einfach, Daten und Uhrzeiten
abzufragen. Stellen Sie sich vor, Sie möchten eine Liste mit allen Ordnern abfragen, die nach
dem 3.12.2002 erstellt wurden. Klingt einfach - die Klasse Win32_Directory stellt schließlich
eine Eigenschaft mit dem Namen CreationDate zur Verfügung.
Unglücklicherweise können Sie als Datum nicht einfach 3/9/2002 angeben. Das folgende
Script versucht dies und gibt keine Daten zurück:
dtmTargetDate = #3/9/2002#

strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")

Set colDirectories = objSWbemServices.ExecQuery _


("SELECT * FROM Win32_Directory WHERE CreationDate > '" & _
dtmTargetDate & "'")

For Each objDirectory In colDirectories


Wscript.Echo objDirectory.Name
Next
Stattdessen müssen Sie das Datum im UTC-Format angeben:
dtmTargetDate = "20020903000000.000000+60"

strComputer = "."
Set objSWbemServices = GetObject("winmgmts:\\" & _
strComputer & "\root\cimv2")

Seite 379 von 394


Set colDirectories = objSWBemServices.ExecQuery _
("SELECT * FROM Win32_Directory WHERE CreationDate > '" & _
dtmTargetDate & "'")

For Each objDirectory In colDirectories


Wscript.Echo objDirectory.Name
Next
Aufgrund dieser Probleme müssen Sie zwei Aufgaben ausführen können:

Konvertieren von WMI-Datumwerten in das Standardformat.

Konvertieren von Standard-Datumwerten in das WMI-Format.

WMI-Datumwerte in das Standardformat konvertieren


Auch wenn UTC-Datumwerte zuerst ein wenig verwirrend aussehen, sind sie doch relativ
einfach zu konvertieren. Das liegt erstens daran, dass die Datumswerte in Form von Strings
vorliegen und damit auch mit Stringfunktionen bearbeitet werden können - und zweitens
daran, dass UTC ein Format mit festen Größen verwendet. Das Jahr ist zum Beispiel immer
vier Ziffern lang. In Tabelle 6.10. sehen Sie diese festen Größen.

Tabelle 6.10: Zeichenpositionen im UTC-Format


ZeichenpositionBeschreibung Beispielwert
1-4 Jahr - vier Zeichen. 2002
5-6 Monat - zwei Zeichen. 10
7-8 Tag - zwei Zeichen. 18
9-14 Stunden, Minuten und Sekunden - 000000
sechs Zeichen.
15 Ein Punkt .
16-21 Millisekunden - sechs Zeichen. 000000
22-25 Unterschied zu GMT - drei Zeichen.-480
Um ein Datum zu konvertieren wählen Sie einfach die entsprechenden Teile aus. Das UTC-
Datum 20020710113047.000000+60 können Sie zum Beispiel so konvertieren:
1.Tag extrahieren (10).
2.Monat extrahieren (07).
3.Jahr extrahieren (2002).
4.Die extrahierten Werte zum Standardformat zusammensetzen: 10/07/2002.
Sie können die einzelnen Komponenten über die VBScript-Funktionen Left und Mid
extrahieren (diese Funktionen werden im Kapitel VBScript besprochen). Um zum Beispiel
den Tag zu extrahieren (die Zeichen an Position 7 und 8) verwenden Sie die folgende
Codezeile (dtmInstallDate ist die Variable, die den zu konvertierenden Wert enthält):
Mid(dtmInstallDate, 7 ,2)

Seite 380 von 394


Die folgende Funktion konvertiert ein komplettes UTC-Datum in ein Standarddatum. Es führt
die folgenden Schritte durch:
WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & _
Mid(dtmInstallDate, 7, 2) & "/" & Left(dtmInstallDate, 4) _
& " " & Mid (dtmInstallDate, 9, 2) & ":" & _
Mid(dtmInstallDate, 11, 2) & ":" & Mid(dtmInstallDate, _
13, 2))
Für den UTC-Wert 20020219145216.000000-480 wirddas folgende Datum zurückgegeben:
2/19/02 2:52:16 PM
Script 6.19 fragt das Datum ab, an dem das Betriebsystem installiert wurde. Das Datum wird
über die Funktion WMIDateStringToDate in ein Standarddatum konvertiert.

Script 6.19: Konvertieren eine UTC-Werts in ein Standarddatum

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

Ein Standarddatum in ein WMI-Datum konvertieren


Um ein WMI-Datum zu erstellen, sind zwei Schritte erforderlich. Erstens müssen Sie die
Differenz in Minuten zu GMT feststellen, und zweitens müssen Sie das Datum zum einem
UTC-Wert konvertieren.

Feststellen der Differenz zu GMT


Glücklicherweise ist es ganz einfach, diese Differenz über WMI abzufragen. Die Klasse
Win32_TimeZone stellt hierzu eine Eigenschaft mit dem Namen Bias zur Verfügung. Script
6.20 zeigt, wie diese Eigenschaft abgefragt werden kann.

Script 6.20: Abfragen der Differenz zu GMT

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:

Seite 381 von 394


Differenz: -480
Ein Datum in einen UTC-Wert konvertieren
Das Zusammenbauen eines UTC-Datums ist eigentlich ganz einfach. Sie verketten einfach die
entsprechenden Zahlen zu einem langen String. Es gibt jedoch eine Schwierigkeit: Monat und
Tag müssen zweistellig sein. Am 10.12 ist dies kein Problem - was machen wir jedoch am
2.6?
Sie fügen dem Wert einfach eine führende Null hinzu - so wird aus 2.6 ganz einfach 02.06.
Hierzu verwenden Sie die VBScript-Funktion Len, um die Länge des Wertes zu prüfen (die
Zahl der Ziffern):
If Len(dtmMonth) = 1 Then
dtmMonth = "0" & dtmMonth
End If
Script 6.21 konvertiert das aktuelle Datum in ein UTC-Datum. Wenn es den Zeitwert zum
Datum hinzufügt, verwendet es die Funktion CStr. Diese stellt sicher, dass der Wert als String
und nicht als Zahl behandelt wird.

Script 6.21: Konvertieren des aktuellen Datums in ein UTC-Datum

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):

Script 6.22 Retrieving Folders Based on Creation Date

1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:" _
3 & "{impersonationLevel=impersonate}!\\" & strComputer &
4 "\root\cimv2")
5 Set colTimeZone = objSWbemServices.ExecQuery _

Seite 382 von 394


6 ("SELECT * FROM Win32_TimeZone")
7 For Each objTimeZone in colTimeZone
8 strBias = objTimeZone.Bias
9 Next
10
11dtmCurrentDate = "18/10/2003"
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"
27dtmTargetDate = dtmTargetDate & Cstr(strBias)
28
29Set colFolders = objSWbemServices.ExecQuery _
30 ("SELECT * FROM Win32_Directory WHERE CreationDate < '" & _
31 dtmtargetDate & "'")
32For Each objFolder in colFolders
33 Wscript.Echo objFolder.Name
Next

Scripte auf Basis von WMI-Vorlagen erstellen


In den folgenden Abschnitten finden Sie grundlegende Scriptvorlagen, mit denen Sie die
folgenden Aktionen durchführen können:

Abfragen und Anzeigen der Eigenschaften von verwalteten Ressourcen.

Ändern der Eigenschaften von verwalteten Ressourcen.

Methoden einer WMI-Klasse aufrufen.

Eine neue Instanz einer verwalteten Ressource erstellen.

Vorhandene Instanzen einer verwalteten Ressource löschen.

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"

Abfragen und Anzeigen der einzelnen Eigenschaften verwalteter


Ressourcen
Script 6.23 gibt Informationen über die installierten Dienste zurück. Es kann jedoch sehr
schnell so angepasst werden, dass es Informationen über jede andere verwaltete Ressource
zurückgibt.

Seite 383 von 394


Script 6.23: Vorlage zum Abfragen und Anzeigen von Ressourceneigenschaften

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

Abfragen und Anzeigen aller Eigenschaften einer verwalteten Ressource


Script 6.24 fragt alle Eigenschaften und die Werte einer Klasse ab.

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

Seite 384 von 394


30 Wscript.Sleep(2000)
31Next
Um diese Vorlage mit anderen WMI-Klassen zu verwenden:

Setzen Sie den Wert von strClassName auf die entsprechende WMI-Klasse.

Wenn notwendig, ändern Sie den Wert von strNamespace.

Schreiben von Ressourceneigenschaften


Script 6.25 fragt alle Instanzen der Klasse Win32_OSRecoveryConfiguration ab. Es ändert die
Werte von einigen Eigenschaften und wendet diese dann über die Methode Put_ an.

Anmerkung: Diese Vorlage funktioniert nur für Eigenschaften, die schreibbar sind. Bei allen
anderen Eigenschaften führt es zu einem Fehler.

Script 6.25: Vorlage zum Schreiben von Ressourceneigenschaften

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

Aufrufen von Methoden


Script 6.26 kann als Vorlage für ein Script verwendet werden, das WMI-Methoden aufruft.
Dieses Script ruft die Methode StopService der Klasse Win32_Service auf, um den Dienst
Alerter anzuhalten.

Script 6.26: Vorlage zum Aufrufen von Methoden

1 strComputer = "."
2 strNamespace = "\root\cimv2"
3 strClassName = "Win32_Service"
4 strKeyName = "Name"
5 strKeyValue = "Alerter"

Seite 385 von 394


6
7 Set objSWbemServices = GetObject("winmgmts:" &_
8 "{impersonationLevel=impersonate}!\\" & strComputer & strNamespace)
9 Set colInstances = objSWbemServices.ExecQuery _
10 ("SELECT * FROM " & strClassName & " WHERE " & strKeyName & " = '" &_
11 strKeyValue & "'")
12For Each objInstance in colInstances
13 objInstance.StopService()
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.

Setzen Sie den Wert von strKeyName auf den Namen der Eigenschaft, die in der WHERE-
Bedingung verwendet wird.

Setzen Sie den Wert von strKeyValue auf den entsprechenden Wert für diese Eigenschaft.

Ersetzt Sie die Zeilen in der For-Each-Schleife durch die entsprechenden Methodenaufrufe

Erstellen von Ressourcen


Script 6.27 verwendet die Methode Create, um einen neuen freigegebenen Ordner zu
erstellen.

Script 6.27: Vorlage zum Erstellen von Ressourcen

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.

Seite 386 von 394


Löschen von Ressourcen
Script 6.28 löscht den freigegebenen Ordner mit dem Namen "New Share Name."

Script 6.28: Vorlage zum Löschen von Ressourcen

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.

Überwachen von Ressourcen über WMI-Ereignisbenachrichtigungen


Über WMI-Ereignisbenachrichtigungen können Sie den Status einer verwalteten Ressource
überwachen und auf ein Problem reagieren.
Statt zum Beispiel zu warten bis der freie Festplattenplatz aufgebraucht ist, können Sie eine
WMI-Ereignisbenachrichtigung einrichten, die Sie per E-Mail benachrichtigt, wenn der freie
Speicherplatz unter einen bestimmten Wert fällt.
Scripte, die verwaltete Ressourcen überwachen, sehen genauso aus wie andere WMI-Scripte.
Script 6.29 überwacht zum Beispiel die Prozesse auf einem Computer und zeigt eine
Nachricht an, wenn ein Prozess mit dem Namen Notepad.exe gestartet wurde.
Wenn Sie das Script unter CScript ausführen, sehen Sie nur, dass das Script gestartet wird und
nicht beendet wird. Das Script wartet einfach auf das entsprechende Ereignis.
Wenn Sie dann Notepad starten, zeigt das Script die folgende Fehlermeldung an:
Notepad.exe wurde soeben gestartet.
Script 6.29: Überwachen des Prozesses Notepad.exe

1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:" &_
3 "{impersonationLevel=impersonate}!" &_
4 "\\" & strComputer & "\root\cimv2")

Seite 387 von 394


5
6 Set objEventSource = objSWbemServices.ExecNotificationQuery( _
7 "SELECT * FROM __InstanceCreationEvent " &_
8 "WITHIN 10 " &_
9 "WHERE TargetInstance " &_
10 "ISA 'Win32_Process' " &_
11 "AND TargetInstance.Name = 'notepad.exe'")
12
13Set objEventObject = objEventSource.NextEvent()
14Wscript.Echo "Notepad.exe wurde soeben gestartet."
In den Zeilen 1 bis 4 baut das Script eine Verbindung zum Namespace root\cimv2 auf.
In den Zeilen 6 bis 11 wird eine Benachrichtigungsabfrage über die Methode
ExecNotificationQuery ausgeführt. Der WQL-Abfragestring wird in den Zeilen 7 bis 11
erstellt. Der Abfragestring enthält die neuen Schlüsselwörter WITHIN und ISA. Diese werden
später besprochen.
In Zeile 13 wird die Methode NextEvent verwendet, um das Script anzuhalten und auf das
nächste durch die Abfrage beschriebene Ereignis zu warten.
In Zeile 14 wir eine Nachricht angezeigt, wenn das Ereignis aufgetreten ist.
Script 6.30 überwachen die Dienste auf einem Computer und zeigt eine Nachricht an, wenn
Sie der Status des Dienstes Alerter ändert. Starten Sie das Script und führen Sie die Befehle
net start alerter oder net stop alerter aus. Sie erhalten die folgende Ausgabe:
Status des Dienstes alerter hat sich geändert.
Script 6.30: Überwachen des Dienstes Alerter

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.

Seite 388 von 394


Die drei Schritte eines Überwachungsscripts
Die Überwachung von Ressourcen erfolgt über drei Schritte:
1.Aufbau einer Verbindung zu einem WMI-Namespace auf einem Computer.
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:" &_
"{impersonationLevel=impersonate}!" &_
"\\" & strComputer & "\root\cimv2")
2.Ausführen einer Benachrichtigungsabfrage.
Hierzu wird eine WQL-Abfrage mit den neuen Schlüsselwörtern WITHIN und ISA
verwendet.
Set objEventSource = objSWbemServices.ExecNotificationQuery( _
"SELECT * FROM __InstanceModificationEvent " &_
"WITHIN 10 " &_
"WHERE TargetInstance " &_
"ISA 'Win32_Service' " &_
"AND TargetInstance.Name = 'alerter'")
3.Empfangen des Ereignisses und Durchführung der erforderlichen Aktionen.
Im dritten Schritt wird die Methode NextEvent aufgerufen. Das Script hält an und wartet auf
das Auftreten des Ereignisses. Dann verarbeitet des die weiteren Zeilen:
Set objEventObject = objEventSource.NextEvent()
Wscript.Echo "Status des Dienst Alerter hat sich geändert."
Es gibt einige wichtige Unterschiede zwischen Standard-WMI-Abfragen und
Ereignisbenachrichtigungsabfragen.

Ereignisbenachrichtigungsabfragen verwenden Ereignisklassen.


Statt Instanzen von verwalteten Ressourcen abzufragen, verwenden
Ereignisbenachrichtigungsabfragen Instanzen einer Ereignisklasse. Die Klasse
__InstanceModificationEvent stellt zum Beispiel das Ereignis dar, das auftritt, wenn eine
Instanz verändert wird - __InstanceDeletionEvent und __InstanceModificationEvent treten bei
Löschen und Ändern von Instanzen auf. Jede dieser drei Klassen ist von der mehr allgemeinen
Klasse __InstanceOperationEvent abgeleitet.
Ereignisbenachrichtigungsabfragen verwenden das Schlüsselwort WITHIN
Da die Klasse Win32_Service nicht über einen WMI-Eventprovider verfügt, muss das
Schlüsselwort WITHIN verwendet werden, damit der WMI-Abfragemechanismus alle 10
Sekunden ausgeführt wird. Theoretisch kann es passieren, dass Ereignisse verpasst werden -
zum Beispiel dann, wenn die Abfrage nur alle 30 Sekunden verwendet wird.
Ereignisbenachrichtigungsabfragen verwenden das Objekt TargetInstance
Es ist ziemlich unwahrscheinlich, dass Sie sich bei jeder erstellten Instanz einer WMI-Klasse
benachrichtigen lassen möchten. Stattdessen sind Sie wahrscheinlich an einer bestimmten
Klasse interessiert. Mit TargetInstance sind Sie in der Lage, diese Instanz anzugeben.
TargetInstance ist ein Objekt, das als Reaktion auf ein Ereignis erstellt wird. Es hat dieselben
Eigenschaften und Werte wie das Objekt, dass das Ereignis ausgelöst hat. Außerdem gibt es
ein WMI-Objekt mit dem Namen PreviousInstance. Dieses Objekt enthält die Eigenschaften

Seite 389 von 394


und Werte, die vor dem Ereignis vorhanden waren. Über diese beiden Objekte können Sie
feststellen, was durch das Ereignis geändert wurde.
Ereignisbenachrichtigungsabfragen verwenden das Schlüsselwort ISA
Über dieses Schlüsselwort können Sie prüfen, ob eine bestimmte Instanz zu einer bestimmten
Klasse gehört. Es entspricht im Groben dem Gleichheitszeichen.

Wie die Ereignisbenachrichtigung arbeitet


Wie für jede verwaltete Ressource gibt es auch für jedes Ereignis eine Klasse. Wenn ein
Ereignis auftritt, wird eine Instanz der entsprechenden Klasse verwendet.
Es gibt drei Haupttypen von WMI-Ereignisklassen, die alle von der Klasse __Event abgeleitet
sind: Intrinsic, Extrinsic und Timer Events. Die Intrinsic-Klasse wird wiederum durch drei
Klassen repräsentiert __NamespaceOperationEvent, __InstanceOperationEvent und
__ClassOperationEvent.
Die von __Event abgeleiteten Klassen müssen in jedem Namespace vorhanden sein, der
Ressourcen enthält, die überwacht werden können. In Abbildung 6.5 sehen Sie die von
__Event abgeleiteten Klassen im Namespace \root\default.

Seite 390 von 394


Abbildung 6.5: Hierarchie der Ereignisklassen
Intrinsic-Ereignisse
Mit Intrinsic-Ereignissen werden Ressourcen überwacht, die durch eine Klasse im CIM-
Repository repräsentiert werden. Sie können außerdem zu Überwachung von Änderungen an
einem Namespace oder einer Klasse verwendet werden.
Ein Intrinsic-Ereignis wird durch eine Instanz einer Klasse repräsentiert, die von den Klassen
__InstanceOperationEvent, __NamespaceOperationEvent oder __ClassOperationEvent
abgeleitet ist. Alle Änderungen an Instanzen werden durch die Klasse
__InstanceOperationEvent und den von dieser Klasse abgeleiteten Klassen
__InstanceCreationEvent, __InstanceModificationEvent und __InstanceDeletionEvent
repräsentiert.
Eine Überwachung dieser Instanzen führen Sie über eine WQL-Benachrichtigungsabfrage
durch. Die entsprechende WQL-Syntax sieht so aus:
Seite 391 von 394
SELECT * FROM __InstanceOperationEventOrDerivedClass WITHIN PollingInterval
WHERE TargetInstance ISA WMIClassName
AND TargetInstance.WMIClassPropertyName = Value
Die von __InstanceOperationEvent abgeleitete Klasse, die Sie zur Überwachung registrieren,
ist von dem zu überwachenden Ereignis abhängig.

Erstellung einer Ressource: __InstanceCreationEvent


Die Benachrichtigungsabfrage für die Erstellung einer Ressource sieht folgendermaßen aus:
SELECT * FROM __InstanceCreationEvent WITHIN PollingInterval WHERE
TargetInstance ISA 'Win32_Process' and TargetInstance.Name = 'notepad.exe'
Änderung einer Ressource: __InstanceModificationEvent
Die Benachrichtigungsabfrage für die Änderung einer Ressource sieht folgendermaßen aus:
SELECT * FROM __InstanceModificationEvent WITHIN PollingInterval WHERE
TargetInstance ISA 'Win32_Service' and TargetInstance.Name = 'alerter'
Löschen einer Ressource: __InstanceDeletionEvent
Die Benachrichtigungsabfrage für das Löschen einer Ressource sieht folgendermaßen aus:
SELECT * FROM __InstanceDeletionEvent WHERE
TargetInstance ISA 'Win32_Process' and TargetInstance.Name = 'notepad.exe'
Extrinsic-Ereignisse
Mit diesen Ereignissen überwachen Sie eine Ressource, die nicht durch eine Klasse im CIM-
Repository repräsentiert ist. Mit Extrinsic-Ereignissen können Sie zum Beispiel überwachen,
ob Änderungen an der Registrierung vorgenommen wurden.
Scripte, die Extrinsic-Ereignisse verwenden, gehen genau wie Scripte mit Intrinsic-
Ereignissen vor. Die entsprechenden Klassen werden jedoch von der Klasse __ExtrinsicEvent
abgeleitet.

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.

Überwachen einer bestimmten Ressource


Sie können die Ressource genauer angeben, wenn Sie die WHERE-Bedingung erweitern.
Script 6.31 definiert, dass die Eigenschaft DeviceID den Wert CPU0 haben muss, und dass
die Eigenschaft LoadPercentage einen Wert größer 90 haben muss.

Script 6.31: Überwachen der ersten CPU auf eine Auslastung von mehr als 90 Prozent

1 Set objSWbemServices = _

Seite 392 von 394


2 GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
3
4 strWQL = "SELECT * FROM __InstanceModificationEvent " &_
5 "WITHIN 5 " &_
6 "WHERE TargetInstance ISA 'Win32_Processor' " &_
7 "AND TargetInstance.DeviceID='CPU0' " &_
8 "AND TargetInstance.LoadPercentage > 90"
9
10Set objEventSource = objSWbemServices.ExecNotificationQuery(strWQL)
11Set objEventObject = objEventSource.NextEvent()
12Wscript.Echo "Load Percentage on CPU0 exceeded 90%."
Mehr als ein Ereignis überwachen
Script 6.29 und Script 6.30 werden nach dem Auftreten des Ereignisses beendet. Wenn die
Scripte nach einem Ereignis auf weitere Ereignisse reagieren soll, sind hierzu nur wenige
Änderungen erforderlich. Fassen Sie den Aufruf der Methode NextEvent und die Ausgabe
einfach in eine Endlosschleife ein.

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.

Script 6.33: Überwachung mehrerer Ereignisse für Notepad.exe

1 strComputer = "."
2 Set objSWbemServices = GetObject("winmgmts:" &_
3 "{impersonationLevel=impersonate}!" &_
4 "\\" & strComputer & "\root\cimv2")
5

Seite 393 von 394


6 Set objEventSource = objSWbemServices.ExecNotificationQuery( _
7 "SELECT * FROM __InstanceOperationEvent " &_
8 "WITHIN 1 " &_
9 "WHERE TargetInstance " &_
10 "ISA 'Win32_Process' " &_
11 "AND TargetInstance.Name = 'notepad.exe'")
12
13Set objEventObject = objEventSource.NextEvent()
14Select Case objEventObject.Path_.Class
15 Case "__InstanceCreationEvent"
16 Wscript.Echo "Instanz von Notepad.exe gestartet."
17 Case "__InstanceDeletionEvent"
18 Wscript.Echo "Instanz von Notepad.exe beendet."
19 Case "__InstanceModificationEvent"
20 Wscript.Echo "Instanz von Notepad.exe geändert."
21End Select
Mehrere Ressourcentypen überwachen
Script 6.29 überwacht einen Prozess und Script 6.30 überwacht einen Dienst. Es scheint also
so, als würde für jede Ressource ein eigenes Script benötigt. Dies ist jedoch nicht richtig - die
beiden Ressourcen können auch in einem Script überwacht werden. Hierzu müssen Sie zwei
Änderungen vornehmen:

Sie müssen die WQL-Abfrage durch logische ORs erweitern, um Benachrichtigungen von
mehreren Ressourcen zu erhalten (Zeilen 12-14).

Um festzustellen, wo ein Ereignis herkommt, müssen Sie die vom Ereignisobjekt
zurückerhaltene Klasse überprüfen (Zeile 17-22).

Script 6.34: Überwachen eines Dienstes und eines Prozesses

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

Seite 394 von 394

Das könnte Ihnen auch gefallen