
Alle auf Deutsch verfügbaren "Tales from the Script"-Kolumnen finden Sie hier.
Hey, wo ist mein Drucker? Die Suche in Active Directory mit Skripten (Teil 1)Haben Sie schon mal Ihren Samstagabend damit verbracht, ziellos im gesamten Haus nach dem Schlüssel oder der Fernbedienung zu suchen? Machen Sie sich nichts draus - Sie sind in guter Gesellschaft. Tatsächlich besteht die Menschheitsgeschichte zu großen Teilen fast ausschließlich aus Leuten, die nach irgendwas gesucht haben (und es nicht fanden): den versunkenen Kontinent Atlantis, den heiligen Gral oder die Zeitung (die einer der Scripting Guys irgendwo auf der kurzen Strecke zwischen seiner Auffahrt und seinem Wohnzimmer verloren hat).
Wenn Sie Systemadministrator sind, dann haben Sie möglicherweise schon selbst einmal vor einigen „Suchproblemen“ gestanden: “Ich muss feststellen, wie viele unserer Computer unter Windows XP ausgeführt werden, und auf wie vielen dieser Computer SP2 installiert ist.” “Gibt es in der Niederlassung in Hamburg nicht schon jede Menge Farbdrucker?” “Wir brauchen eine Liste aller Mitarbeiter, einschließlich der Telefonnummern.” Unglücklicherweise sind solche Aufgabenstellungen für viele von uns ungefähr so aussichtslos wie die Suche nach El Dorado. Alle Forscher, die nach El Dorado gesucht haben, sind normalerweise einfach irgendwo durch den Dschungel von Südamerika gelatscht - in der Hoffnung, irgendwann über den legendären Schatz zu stolpern. Wie wir wissen, war dieser Ansatz bis jetzt alles andere als erfolgreich. Im Gegenteil: Weil er bei der Suche nach El Dorado scheiterte, wurde Sir Walter Raleigh sogar hingerichtet. (Glücklicherweise richten wir bei Microsoft keine Leute hin, weil sie bei etwas erfolglos gewesen sind. Wobei und allerdings gerade einfällt, dass Peter schon seit ein paar Tagen nirgendwo mehr gesehen wurde.) Die Systemadministratoren in der Niederlassung in Hamburg arbeiten nach dem gleichen Prinzip: Sie laufen durch die Büros und hoffen, irgendwann über einen Farbdrucker zu stolpern. Auch wenn dieser Ansatz bezüglich El Dorado eher erfolglos war - irgendwann werden sich so alle Farbdrucker in der Hamburger Niederlassung auffinden. Wahrscheinlich kostet dieses System nur viel Zeit und damit Geld. Außerdem ist es wohl recht fehleranfällig. Es muss doch einen besseren Weg geben, oder? Da gibt es tatsächlich einen: Schreiben Sie sich einfach ein simples kleines Skript, das Active Directory durchsucht. Habe ich da gerade „Active Directory“ gehört?Ja, Active Directory. Jeder weiß, dass in Active Directory Benutzer- und Computerkonten gespeichert werden. Was anscheinend nicht jeder weiß, ist, dass eine große Menge anderer nützlicher Informationen in Active Directory gespeichert werden (oder zumindest dort gespeichert werden können). Hierzu gehört zum Beispiel das auf einem Computer installierte Betriebssystem (und die Version des Service Packs natürlich auch) - diese Information werden automatisch unter dem Computerkonto gespeichert. Wenn Sie Drucker in Active Directory veröffentlichen, werden automatisch weitere Informationen gespeichert: zum Beispiel, ob es sich um einen Farbdrucker handelt, ob er einen Vorlageneinzug hat oder ob er doppelseitig drucken kann. Es gibt allerdings auch Informationen, für die Sie etwas mehr Aufwand betreiben müssen: Wenn Sie einen neuen Benutzer zum Active Directory hinzufügen, werden natürlich nicht automatisch dessen private Telefonnummer, eine Mitarbeiter-ID oder seine Abteilung eingetragen. Was es allerdings gibt, ist die Möglichkeit, solche Informationen einzutragen. Wenn Sie diese Möglichkeit wahrnehmen, dann bekommen Sie eine umfangreiche Datenbank, die Sie zukünftig sehr einfach mit Hilfe von Skripten abfragen können.
Lassen Sie uns also mit einem Skript beginnen, mit dem Sie die besagten Informationen abfragen können. Unser erstes Skript sucht nach allen Benutzern einer Domäne:
On Error Resume Next
Const ADS_SCOPE_SUBTREE = 2
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommandProperties(“Sort On”) = "Name"
objCommand.CommandText = _
"SELECT Name FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectCategory='user'"
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
Wscript.Echo objRecordSet.Fields("Name").Value
objRecordSet.MoveNext
Loop
Wir wissen, was Sie jetzt denken: „Ich kämpfe mich, glaube ich, lieber durch Piranhas und giftige Schlangen und suche nach El Dorado, statt mich mit Dingen wie ADsDSOObject rumzuschlagen.” Bleiben Sie locker: In den meisten Fällen gibt es bei der Erstellung von Active Directory-Suchskripts nur ein paar Elemente, um die Sie sich kümmern müssen. Der Rest kann normalerweise unverändert bleiben - egal, ob Sie nach allen Subnetzen einer Domäne oder nach allen Kontakten in einer Firma suchen. Um Ihnen zu beweisen, dass das auch so ist, teilen wir das Skript in vier Teile auf:
Wenn Sie diese vier Teile überblicken, beherrschen Sie alles, was für die Active Directory-Suche notwendig ist. Aufbau einer Verbindung zu Active Directory mit Hilfe des Active Directory-ADO-ProvidersUm eine Verbindung zu Active Directory aufzubauen, verwenden wir den Active Directory-ADO-Provider (ActiveX Data Objects). Dieser Teil des Skripts ist vollständig wieder verwendbar. Er muss bei weiteren Skripten nicht mehr geändert werden: Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnectionDieser Teil ist auch gleichzeitig der, der die meisten Leute abschreckt. Es gibt aber wirklich keinen Grund dafür - alles was hier gemacht wird, ist das Erstellen von zwei Objekten: des Verbindungs-Objekts (Connection) und des Command-Objekts. Dann wird mit Hilfe der beiden Objekte eine Verbindung zum Active Directory-Dienst aufgebaut. Mit dem Verbindungs-Objekt wird der ADO-Active Directory-Datenbankprovider geladen und die Benutzerinformationen werden überprüft. Nachdem die Verbindung aufgebaut ist, wird das Command-Objekt verwendet, um Befehle und Abfragen auszuführen. Für alles zusammen sind nur diese fünf Zeilen Code notwendig. Und wie gesagt - sie können diese fünf Zeilen in allen weiteren Skripten wieder verwenden. Zusatzinformation: Die Verwendung von anderen Anmeldeinformationen Standardmäßig verbindet sich der Active Directory-Datenbanprovider mit den gleichen Anmeldeinformationen (Benutzername und Kennwort) mit Active Directory, mit denen Sie sich am Betriebssystem angemeldet haben. Was aber, wenn Sie sich mit anderen Benutzerinformationen mit Active Directory verbinden wollen? Nehmen wir zum Beispiel einmal an, Sie haben sich als normaler Benutzer angemeldet. Jetzt möchten Sie eine Active Directory-Verbindung als Administrator aufbauen? Kein Problem: der folgende Code macht genau dies (es geht um die vier Zeilen zwischen den beiden Leerzeilen): Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Properties("User ID") = "Administrator"
objConnection.Properties("Password") = "irte56$#sW"
objConnection.Properties("Encrypt Password") = TRUE
objConnection.Properties("ADSI Flag") = 1
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnectionSie fragen sich, was da alles für Eigenschaften verwendet werden und wozu die gut sind? Glück gehabt - auf der Suche nach der Fernbedienung sind wir zufällig über eine Tabelle gestolpert, die genau das erklärt:
Definition der Parameter des Command-ObjektsNachdem die Verbindung mit Active Directory aufgebaut wurde, führen Sie mit dem Command-Objekt Abfragen aus und definieren Suchparameter. Die Abfragen besprechen wir in einer Minute. Jetzt wollen wir uns jedoch erst mal um drei bestimmte Eigenschaften des Command-Objektes kümmern:
Page SizePage Size ist das vielleicht am häufigsten missverstandene Element in der Geschichte des Skripting (und das, das für den meisten Ärger gesorgt hat). Und zwar aus folgenden Grund: Wenn Sie mit einem Skript in Active Directory suchen, dann bekommen Sie standardmäßig maximal 1.000 Elemente zurück geliefert. Es ist vollkommen egal, ob es in Ihrer Domäne 1.001 oder 100.001 Benutzerkonten gibt - sie erhalten nur 1.000 dieser Konten zurück. Und jetzt der Trick, mit dem Sie diese Grenze beseitigen können: Sie verwenden die Eigenschaft „Page Size“. Nehmen wir an, Sie verwenden eine Codezeile wie diese: objCommand.Properties("Page Size") = 500Mit dieser „Page Size“ würde das Skript die ersten 500 gefundenen Datensätze zurückgeben. Dann würde das Skript kurz warten (wahrscheinlich würden Sie die Pause nicht mal bemerken) und dann die nächsten 500 Datensätze zurückgeben. Dies würde so weiter gehen, bis alle Datensätze zurückgegebenen wären. Hierbei wäre es wieder egal, ob Sie 1.001 oder 100.001 Benutzerkonten haben - sie werden alle zurückgegeben. Auf diese Art können Sie als die 1.000-Datensätze-Grenze umgehen.
SearchscopeWenn Sie zu den Leuten gehören, die ständig Sachen verlieren, werden Sie sich mit Sicherheit Suchstrategien angewöhnt haben. Eine der wichtigsten Strategien in diesem Fall ist es, den besten Punkt für den Beginn der Suche zu finden. Nehmen wir beispielsweise an, Sie haben die Fernbedienung verloren. Wenn Sie nicht in Ostfriesland gewesen sind, macht es wohl keinen Sinn, nach Ostfriesland zu fahren und dort nach der Fernbedienung zu suchen (wenn Sie Ostfriesland durch die Karibik ersetzen, sieht die Sache allerdings vielleicht ganz anders aus). Stattdessen beginnen Sie an dem Punkt, an dem Sie die Fernbedienung am wahrscheinlichsten finden werden. Nehmen wir mal an, Sie haben die Fernbedienung am Morgen noch im Haus verwendet. Solange Sie also das Haus nicht verlassen haben, wäre der beste Startpunkt für eine Suche das Haus. Daher beschränken Sie die Suche auf das Haus. (Es sei denn, Sie haben einen pubertierenden Sohn. In diesem Fall ist es wohl wahrscheinlich, dass er die Fernbedienung hat. Wenn Sie keinen pubertierenden Sohn haben, dann wird die Fernbedienung wohl im Kühlschrank sein). Mit anderen Worten: Ein Suchbereich legt den Startpunkt und den Umfang der Suche fest. Und Sie werden es nicht glauben, aber die Suchstrategien für Fernbedienungen lassen sich ebenso auf Active Directory-Objekte anwenden. Schauen wir uns also die drei verfügbaren Suchbereiche für Active Directory an: Basis-SucheBei dieser Suchart durchsuchen Sie nur das so genannte Basis-Objekt (Base Object). Das Basis-Objekt ist der Container, in dem Sie mit der Suche beginnen - Untercontainer werden nicht durchsucht. Wenn Sie zum Beispiel am Stamm mit der Suche beginnen, wird auch nur der Stamm durchsucht - keine OUs oder andere Container. Die Basis-Suche ist sehr praktisch, wenn Sie Informationen aus einer einzigen OU benötigen (zum Beispiel die Benutzer aus der OU „Buchhaltung“). Verwirrt? Das folgende Diagramm macht das Ganze deutlicher. Die Suche beginnt im Domänenstamm, und der Domänencontainer (gelb) ist somit das einzige Element, das durchsucht wird. ![]() Um eine Basis-Suche durchzuführen, müssen Sie zwei Dinge tun: Erstens müssen Sie eine Konstante mit dem Namen ADS_SCOPE_BASE definieren und deren Wert auf 0 setzen: Const ADS_SCOPE_BASE = 0 Und später müssen Sie der Eigenschaft „Searchscope“ diese Konstante zuweisen: objCommand.Properties("Searchscope") = ADS_SCOPE_BASESuche in einer EbeneDiese Suche ist etwas ungewöhnlich. Sie kann aber von Zeit zu Zeit ganz praktisch sein. Nehmen wir einmal an, Sie haben eine OU mit dem Namen „Buchhaltung“ und zwei Unter-OUs: „Führungskräfte“ und „Mitarbeiter“. Wenn Sie nun eine Suche mit dem Startpunkt „Buchhaltung“ und dem Suchbereich „Eine Ebene“ durchführen, dann werden nur die OUs „Führungskräfte“ und „Mitarbeiter“ durchsucht. Die übergeordnete OU „Buchhaltung“ wird nicht durchsucht. Gehen wir weiter davon aus, dass die OU „Mitarbeiter“ noch zwei Unter-OUs hat: „Intern“ und „Extern“. Auch diese beiden Unter-OUs werden bei einer Suche auf einer Ebene nicht mit durchsucht. Daher also die Bezeichnung „eine Ebene“. Die folgende Grafik zeigt die Container, die bei einer Suche in einer Ebene und dem Startpunkt „Domänenstamm“ durchsucht werden (gelb). ![]() Um eine Basis-Suche durchzuführen, müssen Sie zwei Dinge tun: Erstens müssen Sie eine Konstante mit dem Namen ADS_SCOPE_ONELEVEL definieren und deren Wert auf 1 setzen: Const ADS_SCOPE_ONELEVEL = 1 Und später müssen Sie der Eigenschaft „Searchscope“ diese Konstante zuweisen: objCommand.Properties("Searchscope") = ADS_SCOPE_ONELEVELSubtree-SucheDie Subtree-Suche ist wohl der am häufigsten genutzt Suchbereich. Wenn Sie keinen Suchbereich angeben, dann ist dies auch der Standardwert. Bei einer Subtree-Suche werden alle Container unter dem Startpunkt durchsucht (inkl. dem Startpunkt-Container). Wenn Sie also das gesamte Active Directory durchsuchen möchten, dann beginnen Sie im Active Directory-Stamm und verwenden eine Subtree-Suche. Eine weitere Grafik soll das Ganze noch einmal verdeutlichen. Als Startpunkt wird wiederum der Domänenstamm gewählt. Der Suchbereich ist „Subtree“. ![]() Um eine Basis-Suche durchzuführen, müssen Sie zwei Dinge tun: Erstens müssen Sie eine Konstante mit dem Namen ADS_SCOPE_SUBTREE definieren und deren Wert auf 2 setzen: Const ADS_SCOPE_SUBTREE = 2 Und später müssen Sie der Eigenschaft „Searchscope“ diese Konstante zuweisen: objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREESort OnMit der Eigenschaft „Sort On“ können Sie festlegen, wie die zurückgegebenen Daten sortiert werden. Um die Daten zum Beispiel nach den Nachnamen der Benutzer zu sortieren (SN), verwenden Sie den folgenden Code: objCommand.Properties("Sort On") = "SN"Oder lieber nach Abteilung? Nehmen Sie diese Codezeile: objCommand.Properties("Sort On") = "Department"Beachten Sie, dass Sie nur nach einem Attribut sortieren können. Sie können nicht nach Abteilung und dann nach Nachname sortieren. Erstellen einer AbfrageEs gibt zwei verschiedene Wege, um Active Directory-Abfragen zu erstellen. Sie können die LDAP- oder die SQL-Syntax nutzen. Normalerweise verhalten sich beide gleich. Fast alle Suchen, die Sie mit der LDAP-Syntax durchführen können, sind auch mit der SQL-Syntax möglich - das gleiche gilt auch andersherum. Wir konzentrieren und jedoch auf die SQL-Syntax, da diese einfacher zu nutzen ist, und die meisten typischen Systemadministratoren mit SQL wohl mehr anfangen können als mit LDAP. (Wenn Sie mehr über die LDAP-Syntax lernen möchten, dann werfen Sie einen Blick in den englischsprachigen Scripting Guys-Webcast zum Suchen in Active Directory.) Der Rest von uns schaut sich jetzt mal die Abfrage an, mit der wir alle Benutzerkonten in einer Domäne gesucht hatten: objCommand.CommandText = _
"SELECT Name FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectCategory='user'"
Zum größten Teil sieht die Abfrage wie eine normale SQL-Abfrage aus: „SELECT irgendwas (Name) FROM irgendwo (‘LDAP://dc=fabrikam,dc=com’), bei denen bestimmte Kriterien gegebenen sind (WHERE objectCategory = ‘user’)“. Ziemlich einfach. Es gibt nur zwei Dinge, die Sie beim Schreiben von SQL-Abfragen für Active Directory wissen sollten (wenn Sie sich bereits mit SQL-Abfragen auskennen). Erstens: Sie müssen die Namen aller Attribute angeben, die die Abfrage zurückgeben sollen. Die Auswahl aller Attribute mit * ist nicht möglich. Eine Abfrage wie die folgende funktioniert also nicht: SELECT * FROM ... In diesem Fall erhalten Sie nur das AdsPath-Attribut zurück. Wenn Sie zum Beispiel die Attribute CN (Common Name), Department und Title zurück erhalten möchten, muss Ihre Abfrage so aussehen: objCommand.CommandText = _
"SELECT CN, Department, Title FROM 'LDAP://dc=fabrikam,dc=com' " & _
"WHERE objectCategory='user'"
Zweitens müssen Sie den Startpunkt einer Suche als ADsPath angeben. Normalerweise werden Sie im Domänenstamm mit der Suche beginnen wollen. Hierzu verwenden Sie ganz einfach den ADsPath des Domänenstamms (denken Sie daran den Pfad in einzelne Anführungszeichen einzuschließen): 'LDAP://dc=fabrikam,dc=com' Was aber, wenn Sie nicht im Domänenstamm beginnen möchten? Wenn Sie zum Beispiel in einer OU beginnen wollen, verwenden Sie einfach den ADsPath der OU: 'LDAP://ou=Finance,dc=fabrikam,dc=com' Sie möchten die Gesamtstruktur durchsuchen? In diesem Fall nehmen Sie den ADsPath des globalen Katalogs: 'GC://dc=fabrikam,dc=com'
Und als letztes gibt es da noch die WHERE-Bedingung. Mit dieser geben Sie an, nach was Sie eigentlich suchen. Eine Sache, die sich in fast jeder WHERE-Bedingung findet (oder zumindest finden sollte), ist das Attribut objectCategory. Mit diesem Attribut geben Sie den Typ der zu suchenden Objekte an. Mit der folgenden Abfrage suchen wir zum Beispiel nach Objekten vom Typ „user“: objCommand.CommandText = _
"SELECT CN, Department, Title FROM 'LDAP://dc=fabrikam,dc=com' " & _
"WHERE objectCategory='user'"Das nächste Beispiel sucht nach Objekten vom Typ „user“ oder „computer“: objCommand.CommandText = _
"SELECT CN, Department, Title FROM 'LDAP://dc=fabrikam,dc=com' " & _
"WHERE objectCategory='user' OR objectCategory='computer'"Das Attribut objectClass wird deutlich häufiger verwendet als das Attribut objectCategory. Der Unterschied zwischen objectClass und objectCategory liegt in der Vererbung von Active Directory begründet. Wir wollen ihn hier nicht im Detail besprechen, aber Sie sollten wissen, dass die meisten Active Directory-Klassen von anderen Klassen abgeleitet werden. Die folgende Abbildung zeigt einen Teil der Klassenvererbung in Active Directory (sie ist allerdings ein wenig vereinfacht). Ganz oben im Vererbungsbaum finden Sie die Klasse „top“. Darunter die Klasse „person“. Die Klasse „person“ enthält alle Eigenschaften der Klasse „top“ und ein paar Attribute, die nicht in der Klasse „top“ zu finden sind. Unter „person“ befindet sich die Klasse „organizational person“. Wie Sie sich vielleicht denken können, enthält diese alle Attribute der Klassen „top“ und „person“ und einige zusätzliche neue Attribute. ![]() Warum interessiert uns das alles? Wenn Sie mit dem Attribut objectClass suchen, erhalten Sie alle Objekte zurück, die im entsprechenden Vererbungsbaum zu finden sind (die roten Elemente links). Suchen Sie also nach objectClass='user', dann erhalten Sie Objekte aus „user“, aus den „user“ übergeordneten Klassen („organization persons“, etc.) und aus den „user“ untergeordneten Klassen („computer“, etc.). Wenn Sie jedoch nach objectCategory='user' suchen, erhalten Sie nur Objekte der Klasse „user“ (rot rechts). Genau da liegt der Unterschied. Ausführen der AbfrageWenn Sie Ihre Abfrage fertig gestellt haben, müssen Sie nur noch die Execute-Methode aufrufen, und die Daten werden abgerufen: Set objRecordSet = objCommand.Execute Durchgehen des zurückgegebenen RecordsetsNach dem Ausführen der Abfrage erhalten Sie die Daten in Form eines Recordsets zurück. Am einfachsten ist es nun, alle Datensätze im Recordset zu durchlaufen. Hierzu rufen Sie einmal die Methode MoveFirst auf, um sicherzugehen, dass Sie mit dem ersten Datensatz beginnen. (Um die Wahrheit zu sagen: wir sind uns nicht ganz sicher, ob das wirklich notwendig ist, aber um auf der sicheren Seite zu sein…) Dann verwenden Sie eine Do/Until-Schleife, die so lange läuft, bis das Ende des Recordsets erreicht ist (EOF). Innerhalb der Schleife können Sie dann mit den einzelnen Datensätzen machen, was Sie wollen. Der folgende Code gibt zum Beispiel den Wert des Attributes „Name“ für jedes Element im Recordset aus: objRecordSet.MoveFirst
Do Until objRecordSet.EOF
Wscript.Echo objRecordSet.Fields("Name").Value
objRecordSet.MoveNext
LoopZwei Dinge sollten Sie hier beachten: Erstens: Sie geben hiermit den Wert des Feldes „Name“ aus. Wenn Sie zum Beispiel den Wert des Feldes „Titel“ ausgeben möchten (vorausgesetzt, „Titel“ ist Teil Ihrer Abfrage), verwenden Sie diesen Code: Wscript.Echo objRecordSet.Fields("Title").ValueUnd zweitens diese Zeile: objRecordSet.MoveNext Mit dieser Zeile wechseln Sie innerhalb der Schleife zum nächsten Datensatz im Recordset. Wenn Sie die Zeile vergessen (nicht, dass uns das jemals passiert wäre), dann gibt Ihr Skript immer und immer wieder den entsprechenden Wert für den ersten Datensatz im Recordset aus. Stay Tuned …Das sollte uns für die ersten Schritte beim Suchen in Active Directory reichen. Mit diesen Grundlagen werden wir uns nächsten Monat tiefer gehend mit dem Suchen beschäftigen. Vielleicht möchten Sie sich bis dahin den englischsprachigen Scripting Guys-Webcast zum Thema „Suchen in Active Directory“ oder einige der Beispielskripte im Script Center-Script Repository anschauen. Wir werden solange mal einen spontanen Trip in den Dschungel von Südamerika machen. Warum? Ach, einfach nur so - ehrlich.
| In diesem Beitrag
|