Windows 2003 Shell Scripting

Scripting-Hilfe für ActiveDirectory

27.10.2008 von Armin Hanisch
Mit den passenden Scripten lassen sich wiederkehrende Arbeiten unter Windows deutlich bequemer erledigen. In dieser Ausgabe unserer Serie „Shell Scripting unter Windows 2003“ beschäftigen wir uns mit Scripten rund um ActiveDirectory.

Unter Linux sind Scripts der Alltag, mittlerweile holt auch die Windows-Fraktion auf. Spätestens, seit Microsoft die Power Shell eingeführt hat, sind auch unter Windows komplexe und hilfreiche Scripts möglich. In dieser Artikelreihe zeigen wir Ihnen Scripts zur Lösung für Aufgabenstellungen aus der täglichen Praxis.

Nachdem sich Teil 1 um allgemeine Problemstellungen drehte und Teil 2 sich mit den Scripts zur Datei- und Systemverwaltung beschäftigte, nehmen wir uns nun das ActiveDirectory vor. Denn die Möglichkeiten zur Verwaltung des ActiveDirectory haben sich seit Windows Server 2003 deutlich verbessert. Die neuen ds*-Kommandos lassen nun erstmals das direkte Anlegen, Ändern und Löschen von Informationen im AD über die Shell zu, ohne sich mit komplexen Shell Scripts beschäftigen zu müssen. Das Komplizierteste, was Sie sich jetzt noch merken müssen, ist der LDAP-Pfad zum gewünschten Objekt.

Windows 2003 Shell Scripting: Das Buch zu unserer Serie.

Unsere neue Serie zum Shell Scripting unter Windows 2003 basiert auf Kapitel 16 des Standardwerks „Windows 2003 Shell Scripting - Abläufe automatisieren ohne Programmierkenntnisse“ von Armin Hanisch aus dem Haus Pearson Education. Sie können dieses 320 Seiten starke Buch auch in unserem Partner-Buchshop bestellen.

Artikelserie: Shell Scripting unter Windows 2003

Teil 1: Allgemeine Problemstellungen

Teil 2: System- und Dateiverwaltung

Teil 3: ActiveDirectory

Teil 4: Netzwerk

LDAP-Suchfilter

Ein möglicher Stolperstein für die Arbeit mit den ActiveDirectory-Kommandos ist die Definition von LDAP-Suchfiltern. Diese besitzen eine gewöhnungsbedürftige Syntax, weshalb wir eine kleine Einführung in das Thema auch der Beschreibung der AD-Kommandos voranstellen.

Ein LDAP-Suchfilter besteht aus einem oder mehreren Ausdrücken in der Form ( <attribut> <operator> <wert> ). Die runden Klammern müssen mit angegeben werden. Beispielsweise lautet der Standardsuchfilter für die Kommandos csvde und ldifde auf (objectClass=*), also die Suche nach allen Objekten.

Die Namen der Attribute sind die tatsächlichen Schemanamen, nicht die Beschriftungen aus den Admin-Tools. Aus diesem Grund müssen Sie die Namen der Attribute unter Umständen erst mit einem AD-Werkzeug wie adsiedit.msc aus den Support Tools nachschlagen.

Folgende Operatoren sind in einer LDAP-Abfrage möglich:

Tabelle: Relationale LDAP-Operatoren

=

beide Werte müssen übereinstimmen

~=

ungefähre Übereinstimmung

>=

größer gleich

<=

kleiner gleich

Nicht alle LDAP-Implementierungen stellen die ungefähre Übereinstimmung zur Verfügung (ideal zur Suche nach allen „Meiers“ mit „e“ oder „a“). Ein Ungleich kann nur durch die Kombination aus >= und <= oder durch eine logische Negation eines =-Ausdrucks gebildet werden. Zur Kombination von Ausdrücken können Sie logische Operatoren verwenden:

Tabelle: Logische LDAP-Operatoren

!

logisch nicht (wird für ungleich benötigt)

&

logisch UND

|

logisch ODER

Die Syntax für die Kombination von Ausdrücken ist eine sogenannte Präfix-Notation, das heißt, es wird zuerst der Operator angegeben, danach die Teilausdrücke, jeweils in runden Klammern. Der gesamte Filter wird ebenfalls wieder in runde Klammern eingeschlossen.

Möchten Sie (beispielsweise aus dem users-Container) nur alle Benutzerkonten exportieren, verwenden Sie folgenden Filter:

(&(objectClass=user)(objectCategory=person))

Die Kombination aus beiden Ausdrücken ist notwendig, da auch die Computerkonten einer Domain unter der Objektklasse user laufen ((natürlich reicht eigentlich auch (objectCategory = Person) allein aus, allerdings könnten wir dann nicht den Operator "&"-Operator demonstrieren.))

Möchten Sie nur alle Benutzer, deren Nachname mit einem „T“ beginnt, dann können Sie folgenden Suchfilter verwenden:

(&(objectCategory=Person)(sn=T*))

Schwieriger wird es bei Mehrfachkombinationen. Hier eine Abfrage, die alle Gruppen oder User sucht, die nach dem 01.06.2004 erzeugt wurden. Wie Sie erkennen, muss der ODER-Ausdruck separat geklammert werden.

(&(|(objectClass=group)(objectClass=user))(whenCreated>=20040601000000.0Z))

Achten Sie bei Abfragen mit Datumswerten darauf, diese in der korrekten Schreibweise anzugeben. Das Format lautet JJJJMMTT hhmmss.xZ, wobei x für die Sekundenbruchteile und das Z für „Zulu-Time“ (Weltzeit) steht.

(&(objectClass=group)(whenCreated>=20040601000000.0Z))

Vorsicht: Schreiben Sie das Z immer groß, ansonsten wird die Abfrage fehlschlagen. Ebenso dürfen in der gesamten Abfrage keine Leerzeichen vorkommen.

CSVDE

csvde.exe ist ein Programm, mit dem komplette Objekte aus dem ActiveDirectory exportiert oder importiert werden können. Einzelne Attribute eines bestehenden Objekts lassen sich nicht verändern, dafür wird ldifde oder dsmod benutzt. csvde.exe ist besonders dann sehr nützlich, wenn es um die Erstellung von Reports geht oder viele Benutzerdaten an Programme zur Auswertung übergeben werden müssen.

Hier die allgemeine Syntax von csvde:

CSV Verzeichnis Exchange

General Parameters
==================
-i Turn on Import Mode (The default is
Export)
-f filename Input or Output filename
-s servername The server to bind to (Default to DC of
computer's domain)
-v Turn on Verbose Mode
-c FromDN ToDN Replace occurences of FromDN to ToDN
-j path Log File Location
-t port Port Number (default = 389)
-u Use Unicode format
-? Help

Export Specific
===============
-d RootDN The root of the LDAP search (Default to
Naming Context)
-r Filter LDAP search filter (Default to
"(objectClass=*)")
-p SearchScope Search Scope (Base/OneLevel/Subtree)
-l list List of attributes (comma separated) to
look for in an
LDAP search
-o list List of attributes (comma separated) to
omit from input.
-g Disable Paged Search.
-m Enable the SAM logic on export.
-n Do not export binary values

Import
======
-k The import will go on ignoring
'Constraint Violation' and
'Object Already Exists' errors

Credentials Establishment
=========================
Note that if no credentials is specified, CSVDE will
bind as the currently
logged on user, using SSPI.

-a UserDN [Password | *] Simple
authentication
-b UserName Domain [Password | *] SSPI bind method

Beispiele für CSVDE

Sehen wir uns dazu gleich ein Beispiel an. Sie werden erkennen, dass nicht viele Optionen benötigt werden, um csvde sinnvoll einzusetzen. Zuerst sollen alle Objekte im Container „users“ ausgegeben werden. Für die Authentifizierung wird das Konto des angemeldeten Benutzers verwendet, und die Ausgabe soll in der Datei ausgabe.dat landen:

csvde -f ausgabe.dat -d "cn=users,dc=shellbook,dc=com"

Diese Ausgabe wird allerdings nicht oft Verwendung finden, sie enthält einfach zu viele Daten. Daher noch ein Beispiel aus der Praxis. Hier sollen aus einer OU alle Kontaktdaten in eine CSV-Datei exportiert werden, damit diese in ein E-Mail-Adressbuch übernommen werden können. Aus diesem Grund sollen auch nicht wahllos alle Attribute exportiert werden, sondern nur der angezeigte Name, die E-Mail-Adresse und die Homepage.

Dafür werden zwei weitere Optionen benutzt. Die Option -l definiert eine kommagetrennte Liste aus Attributnamen, und die Option -r legt einen LDAP-Suchfilter fest.

csvde -f ausgabe.dat -d "ou=produktion,dc=shellbook,dc=com" -r "(objectClass=contact)" -l "displayName,wwwhomepage,mail"

Die Ausgabe des Kommandos in der Konsole sieht dann wie folgt aus:

Connecting to "(null)"
Logging in as current user using SSPI
Exporting Verzeichnis to file ausgabe.dat
Searching for entries...
Writing out entries
..
Export Completed. Post-processing in progress...
2 entries exported

The command has completed successfully

Da wir keinen Server angegeben haben, erfolgt die Anmeldung am DC. Ohne die Optionen -a oder -b werden die Daten des angemeldeten Benutzers für die Authentifizierung verwendet. Für jeden exportierten Datensatz schreibt csvde einen Punkt nach „Writing out entries“. Da wir mit der Option -l die Liste der Attribute begrenzt haben, werden auch nur diese Attribute in die Datei geschrieben. Die Ausgabe des Distinguished Names (DN) erfolgt immer als erstes Attribut, damit die Ausgabe zuordnungsfähig bleibt.

Hier der Inhalt der Datei:

C:\tmp>more < ausgabe.dat
DN,displayName,wWWHomePage,mail
"CN=Norman Kerth,OU=Produktion,DC=shellbook,DC=com",Norm
Kerth, http://
www.retrospectives.com,norm@retrospectives.com
"CN=Julius
Caesar,OU=Produktion,DC=shellbook,DC=com",Caesar, http:/
/www.caesar.spqr,julius@roma.spqr

C:\tmp>

Hinweise

Die Werte für das Attribut userAccountControl regeln den Zustand des Kontos und sind als Bitmaske wie in der Tabelle unten definiert (Auszug, die komplette Auflistung finden Sie in der MSDN).

Ein normaler Benutzer, dessen Passwort nicht abläuft, besitzt also den Wert von hex 10000 und hex 200, zusammen 0x10200 oder dezimal 66048. Für den Import mit csvde können Sie nur einen Wert angeben, der das Flag für Account disabled gesetzt hat, etwa 514.

Tabelle: Die wichtigsten Bitflags für user-AccountControl

Flag

Wert (hex!)

Account disabled

2

Homedir erforderlich

8

Lockout aktiv

10

Kein Passwort erforderlich

20

Benutzer kann Passwort nicht ändern

40

Normaler Account

200

Inter-Domain Trust Account

800

Workstation Trust Account

1000

Server Trust Account

2000

Passwort läuft nie ab

10000

Trusted for delegation

80000

Passwort abgelaufen

800000

Benutzer aus Datei anlegen

Mithilfe von csvde ist es also sehr einfach (sogar einfacher als mit dem WSH) möglich, Benutzer neu anzulegen. Alles, was Sie dazu benötigen, ist eine Textdatei mit den Daten für einen Account in jeder Zeile. csvde besitzt aber einen Nachteil: Es lassen sich keine Passwörter in der Datei übergeben. Falls Sie also in Ihrer Domain Policy definiert haben, dass gewisse Regeln bezüglich Länge und Komplexität des Passworts zu beachten sind, können Sie die Accounts nur dann anlegen, wenn diese deaktiviert (disabled) sind.

Die folgenden Attribute müssen in der Eingabedatei mindestens enthalten sein: DN, objectClass und sAMAccountName. Weitere Attribute wie wWWHomePage, department oder telephoneNumber können Sie nach Belieben ergänzen. Hier ein Beispiel für eine Eingabedatei, mit der ein Benutzer in der OU „Kurs“ angelegt wird (die zweite Zeile mit den Daten steht in einer einzigen Zeile, hier im Buch erfolgt nur ein Umbruch durch das Satzsystem):

DN,objectClass,userAccountControl,sAMAccountName,user PrincipalName
"CN=Student38,OU=Kurs,DC=shellbook,DC=com",user,514,student38,student38@shellbook.com

Jetzt kann csvde mit diesen Daten als Eingabe gestartet werden:

C:\tmp>csvde -i -f eingabe.dat
Connecting to "(null)"
Logging in as current user using SSPI
Importing Verzeichnis from file "eingabe.dat"
Loading entries..
1 entry modified successfully.

The command has completed successfully
C:\tmp>

Denken Sie allerdings daran, dass vor einer Aktivierung des Accounts noch das Passwort so gesetzt werden muss, dass es den Regeln der aktiven Gruppenrichtlinien entspricht.

LDIFDE

Der große Unterschied zwischen csvde und ldifde liegt darin, dass beim letzteren Kommando auch einzelne Attribute eines bestehenden Objekts verändert werden können. Sogar das Löschen von Objekten aus dem Verzeichnis ist möglich. Der zweite Unterschied ist das verwendete Format für die Eingabe und Ausgabe. Wie die Namen der beiden Kommandos bereits andeuten, verwendet csvde kommaseparierte Textdateien und ldifde das LDIF-Format für den Austausch zwischen Verzeichnisdiensten. Die allgemeine Syntax von ldifde ähnelt der von csvde stark:

LDIF Verzeichnis Exchange

General Parameters
==================
-i Turn on Import Mode (The default is Export)
-f filename Input or Output filename
-s servername The server to bind to (Default to DC of computer's domain)
-c FromDN ToDN Replace occurences of FromDN to ToDN
-v Turn on Verbose Mode
-j path Log File Location
-t port Port Number (default = 389)
-u Use Unicode format
-w timeout Terminate execution if the server takes longer than the specified number of seconds to respond to an operation (default = no timeout specified)
-h Enable SASL layer encryption
-? Help

Export Specific
===============
-d RootDN The root of the LDAP search (Default to Naming Context)
-r Filter LDAP search filter (Default to "(objectClass=*)")
-p SearchScope Search Scope (Base/OneLevel/Subtree)
-l list List of attributes (comma separated) to look for in an LDAP search
-o list List of attributes (comma separated) to omit from input.
-g Disable Paged Search.
-m Enable the SAM logic on export.
-n Do not export binary values

Import
======
-k The import will go on ignoring 'Constraint Violation' and 'Object Already Exists' errors
-y The import will use lazy commit for better performance (enabled by default)
-e The import will not use lazy commit
-q threads The import will use the specified number of threads (default is 1)

Credentials Establishment
=========================
Note that if no credentials is specified, LDIFDE will bind as the currently logged on user, using SSPI.
-a UserDN [Password | *] Simple authentication
-b UserName Domain [Password | *] SSPI bind method

Beispiele für LDIFDE

Zuerst soll ein einzelner Kontakt exportiert werden:

ldifde -f ausgabe.dat -d "cn=Julius Caesar, ou=Produktion,dc=shellbook,dc=com

Ohne eine weitere einschränkende Option werden auch hier wieder alle belegten Attribute ausgegeben. Den Inhalt der angegebenen Datei zeigt das nachfolgende Listing:

dn: CN="Julius" Caesar,OU=Produktion,DC=shellbook,DC=com
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: contact
cn: Julius Caesar
sn: Caesar
givenName: Julius
distinguishedName: CN=Julius
Caesar,OU=Produktion,DC=shellbook,DC=com
instanceType: 4
whenCreated: 20040705130736.0Z
whenChanged: 20040705130808.0Z
displayName: Caesar
uSNCreated: 24659
uSNChanged: 24660
wWWHomePage: http://www.caesar.spqr
name: Julius Caesar
objectGUID:: yDxlB1bOEEmPvpMNpD56Ww==
objectCategory:
CN=Person,CN=Schema,CN=Configuration,DC=shellbook,DC=com
mail: julius@roma.spqr

Wie bei csvde lassen sich auch hier Einschränkungen treffen, für die tatsächlich die gleichen Optionen verwendet werden. Daher können wir das Beispiel zum Export der Maildaten von csvde weiter oben unverändert übernehmen. Wir tauschen nur den Namen des Kommandos aus:

ldifde -f ausgabe.dat -d "ou=produktion,dc=shellbook,dc=com" -r "(objectClass=contact)" -l "displayName,wwwhomepage,mail"

Hier der Inhalt der Exportdatei, der diesmal im LDIF-Format erstellt wird:

dn: CN="Norman" Kerth,OU=Produktion,DC=shellbook,DC=com
changetype: add
displayName: Norm Kerth
wWWHomePage: http://www.retrospectives.com
mail: norm@retrospectives.com

dn: CN=Julius Caesar,OU=Produktion,DC=shellbook,DC=com
changetype: add
displayName: Caesar
wWWHomePage: http://www.caesar.spqr
mail: julius@roma.spqr

Interessant wird der Einsatz dieses Kommandos vor allem dann, wenn einzelne Attribute verändert oder ganze Objekte gelöscht werden sollen.

Löschen von Objekten

Nachdem wir gerade die Daten der beiden Kontaktobjekte exportiert haben, ist dies ein guter Zeitpunkt, um das Löschen von Objekten zu demonstrieren. Dazu wird eine LDIF-Datei erstellt, mit der festgelegt wird, welche Objekte gelöscht werden. Der Aufbau hier ist sehr einfach, da lediglich das DN-Attribut benötigt wird. Der changetype in der LDIF-Datei wird auf delete gestellt, und das war auch schon alles. Hier der Inhalt der Datei, mit der die beiden Kontakte aus dem Verzeichnis gelöscht werden:

dn: CN="Norman" Kerth,OU=Produktion,DC=shellbook,DC=com
changetype: delete

dn: CN=Julius Caesar,OU=Produktion,DC=shellbook,DC=com
changetype: delete

Beachten Sie bei beiden Datensätzen die nachfolgende Leerzeile, sonst erhalten Sie eine Fehlermeldung. Jetzt kann damit die Löschaktion gestartet werden, wie der Ausschnitt aus dem Konsolenlog zeigt:

C:\tmp>ldifde -f eingabe.dat –i
Connecting to "bytebag.shellbook.com"
Logging in as current user using SSPI
Importing Verzeichnis from file "eingabe.dat"
Loading entries...
2 entries modified successfully.

The command has completed successfully

C:\tmp>

Importieren von Daten

So, meine Kontakte sind weg, also einfach von der vorher erzeugten Ausgabedatei wieder importieren. Beinahe! Falls Sie dies versuchen, erhalten Sie eine der vielen möglichen Fehlermeldungen:

C:\tmp>ldifde -f ausgabe.dat –i
Connecting to "bytebag.shellbook.com"
Logging in as current user using SSPI
Importing Verzeichnis from file "ausgabe.dat"
Loading entries.
Add error on line 1: Object Class Violation
The server side error is "The object class attribute
must be specified."
0 entries modified successfully.
An error has occurred in the program
No log files were written. In order to generate a log
file, please
specify the log file path via the -j option.

Warum? Nun, als wir diese Beispiele geschrieben haben, ging es uns genauso. Aber im Beispiel für den Export der Kontaktdaten hatten wir angegeben, dass wir nur die drei Attribute displayName, wWWHomepage und mail haben wollten. Mehr war also nicht in der Datei vorhanden, auch nicht die Information über die Objektklasse. Diese muss also in der Eingabedatei manuell oder per Shell Script ergänzt werden. Erst nachdem die Zeile objectClass: contact in beiden Sätzen ergänzt wurde, kann die Datei wie oben angegeben importiert werden.

Allerdings fehlen jetzt die Beschreibungen für beide Kontakte, wie die Abbildung unten aus ACTIVE VERZEICHNIS USERS AND COMPUTERS zeigt:

Abbildung 16.1: Die importierten Kontakte ohne Beschreibung.

Damit haben wir einen guten Grund, als letztes Beispiel in diesem Abschnitt die Veränderung einzelner Attribute bei einem bestehenden Objekt zu erläutern.

Ändern von Attributen

Dies ist der letzte changetype in einer LDIF-Datei: modify. Damit können einzelne Attributwerte geändert werden. Auch hier sollten Sie sich genau an das vorgeschriebene LDIF-Format halten, sonst ist das einzige Ergebnis des Aufrufs von ldifde eine Fehlermeldung. Die allgemeine Form der Änderung eines Attributs sieht wie folgt aus:

dn: <distinguished_name>
changetype: modify
replace: <attribut_name>
<attribut_name>: <neuer_inhalt>
-

Beachten Sie die Leerzeile nach dem Minuszeichen! Um also die beiden Beschreibungen für die Kontakte zu ändern, wird folgende Eingabedatei benötigt:

dn: CN="Norman" Kerth,OU=Produktion,DC=shellbook,DC=com
changetype: modify
replace: description
description: Norm Kerth, Project Post Mortems
-

dn: CN=Julius Caesar,OU=Produktion,DC=shellbook,DC=com
changetype: modify
replace: description
description: Julius, der mit dem Lorbeerkranz
-

Nun kann ldifde im Importmodus aufgerufen werden:

C:\tmp>ldifde -i -f eingabe.dat
Connecting to "bytebag.shellbook.com"
Logging in as current user using SSPI
Importing Verzeichnis from file "eingabe.dat"
Loading entries...
2 entries modified successfully.

The command has completed successfully

C:\tmp>

Der nachfolgende Screenshot zeigt die geänderten Daten in ACTIVE DIRECTORY USERS AND COMPUTERS:

Abbildung 16.2: Die geänderten Beschreibungen im ActiveDirectory.

Auch für ldifde gelten die im Abschnitt „LDAP-Suchfilter“ bei csvde zum Thema LDAP-Filter gemachten Anmerkungen.

Benutzer-Account (de)aktivieren

Dieses Script ist wieder ein Goodie für alle Administratoren, die noch Windows-2000-Systeme betreuen, aber auch eine schöne Demonstration, wie viel Komfort die neuen Kommandos der Shell unter Windows Server 2003 bringen. Nachdem wir das Script vorgestellt haben, verraten wir Ihnen weiter unten, was Sie unter Windows Server 2003 für das gleiche Ergebnis tun müssen.

Parameter

Code

@echo off
if /i !%1 == !enable goto enable
if /i !%1 == !disable goto disable
echo Unbekanntes Kommando "%1", Abbruch.
exit /b

:enable
set mask= ^& 0x8FFFFFD
goto getdata

:disable
set mask= ^| 0x2
goto getdata

:notfound
echo Could not find object "%2" in AD, exiting.
goto :eof
:getdata
ldifde -f output.ldf -d %2 -r "(objectClass=user)" –l
userAccountControl > log.txt
type log.txt | find /i "no entries found" > nul
if not %errorlevel% == 1 goto notfound

:cont
for /F "tokens=1,2" %%f in (output.ldf) do if /i !%%f ==
!userAccountControl: set value=%%g

set /A value="%value% %mask%"
echo Changing userAccountControl to: %value%

:: now build new ldif file
type output.ldf | find /i "dn:" > input.ldf
echo changetype: modify>> input.ldf
echo replace: userAccountControl>> input.ldf
echo userAccountControl: %value%>> input.ldf
echo ->> input.ldf

ldifde -i -f input.ldf

Funktion

Aufgerufen wird das Script beispielsweise so:

account.bat disable "CN=Franz
Testhuber,cn=users,dc=shellbook,dc=com"

Windows Server 2003

Und hier die versprochene Kommandozeile für Windows Server 2003:

:: aktivieren eines kontos:
dsmod user "cn=User,ou=ouname,dc=domain,dc=com" -
disabled no

:: deaktivieren eines kontos
dsmod user "cn=User,ou=ouname,dc=domain,dc=com" -
disabled yes

Wie Sie sehen, ist die Shell mittlerweile durchaus brauchbar, und Sie müssen nicht für jede Kleinigkeit WSH-Programmierung lernen (wenn Sie etwas Zeit haben, sollten Sie dies natürlich trotzdem tun, um Ihr Wissen zu erweitern).

Damit haben wir auch gleich elegant den Übergang zu den neuen ds*-Kommandos von Windows Server 2003geschaffen, welche die Verwaltung des AD wesentlich erleichtern.

dsquery

dsquery ist sozusagen ein Vorsatzadapter zu den restlichen Kommandos. Diese erwarten nämlich immer einen DN, mit dem ein Objekt eindeutig identifiziert wird. Wenn Sie dieses Attribut nicht wissen (weil Sie beispielsweise alle Accounts deaktivieren möchten, die länger als vier Wochen nicht angemeldet waren), dann hilft Ihnen dsquery weiter. Als Ergebnis der Suche wird jeweils der DN auf die Standardausgabe ausgegeben und kann so direkt per Pipelining an dsmod und die anderen Kommandos übergeben werden.

Damit Sie nicht alle LDAP-Queries selbst erstellen müssen, existiert eine ganze Reihe von Unterkommandos für vorbereitete Suchen:

Tabelle: dsquery-Subkommandos

Kommando

Bedeutung

dsquery computer

sucht nach Computerkonten

dsquery contact

sucht nach Kontakten

dsquery subnet

sucht nach Subnets

dsquery group

sucht nach Gruppen

dsquery ou

sucht nach Organisationseinheiten

dsquery site

sucht nach Sites

dsquery server

sucht nach Domain-Controllern

dsquery user

sucht nach Benutzerkonten

dsquery quota

sucht nach Quoteninformationen

dsquery partition

sucht nach Verzeichnispartitionen

dsquery *

erlaubt die freie Definition beliebiger LDAP-Anfragen

Beispiele

Bleiben wir bei unseren Kontakten aus den Beispielen mit csvde und ldifde: Auch hier sollen wieder alle Kontakte aus der OU „produktion“ gesucht werden. Im einfachsten Fall geben Sie folgendes Kommando ein:

dsquery contact

Als Ergebnis erhalten Sie folgende Ausgabe (auf meiner Maschine):

"CN=Norman Kerth,OU=Produktion,DC=shellbook,DC=com"

"CN=Julius Caesar,OU=Produktion,DC=shellbook,DC=com"

Wird nämlich keine Definition des Startpunkts der Suche getroffen, dann gilt Folgendes: Root der Domain und der gesamte Baum abwärts. Dies zeigt sich besonders deutlich beim Subkommando für die Benutzer:

C:\tmp>dsquery user

"CN=Administrator,CN=Users,DC=shellbook,DC=com"
"CN=Guest,CN=Users,DC=shellbook,DC=com"
"CN=SUPPORT_388945a0,CN=Users,DC=shellbook,DC=com"
"CN=krbtgt,CN=Users,DC=shellbook,DC=com"
"CN=Franz Testhuber,OU=Produktion,DC=shellbook,DC=com"
"CN=Student37,OU=Kurs,DC=shellbook,DC=com"
"CN=Student38,OU=Kurs,DC=shellbook,DC=com"
C:\tmp>

Es werden die DNs aller Benutzer aus der gesamten Domain ausgegeben. Soll dies nicht der Fall sein, kann ein Startknoten angegeben werden:

dsquery user "ou=produktion,dc=shellbook,dc=com"

Alternativ ist die Angabe der konstanten Werte forestroot oder domainroot möglich.Ein weiteres Beispiel zeigt, wie leicht unter Windows Server 2003 Abfragen des AD über die Kommandozeile fallen: Aufgelistet werden sollen die DNs aller Gruppen, in deren Namen die Zeichenfolge „domain“ vorkommt.

dsquery group -name *domain*

Optionen

Für jedes Subkommando ist eine Reihe von Optionen möglich, die zum Großteil über alle Subkommandos hin konsistent sind. Sie können sich die Liste der Optionen mit dem Kommando

dsquery <subcmd> /?

ausgeben lassen.

Die wichtigsten gemeinsamen Optionen listet die folgende Tabelle auf. Einzelne Subkommandos definieren weitere Optionen, wie beispielsweise die Option -inactive <wochen> für die Subkommandos user und computer.

Option

Bedeutung

-scope <scopewert>

Legt die Suchtiefe fest. Mögliche Werte sind subtree, onelevel oder base

-u <user>

Verwendet den Benutzernamen zur Anmeldung am AD

-p <password>

Verwendet das Passwort zur Anmeldung am AD

- q

Unterdrückt alle Ausgaben, außer den Ergebnissen

- r

Verfolgt Verweise (referrals) im AD. Ist per Default nicht aktiv

- gc

Sucht im Global Catalog

- limit <anzahl>

Wichtig! Legt fest, wie viele Objekte ausgegeben werden, auf die die Suchbedingungen passen. Ist dieser Wert 0, werden alle Objekte ausgegeben. Wird diese Option nicht angegeben, dann werden nur die ersten 100 Objekte ausgegeben!

- uc[i|o]

Gibt an, dass Ein- oder Ausgaben bei Pipes im Unicode-Format vorliegen

- s <server>

Verwendet den angegebenen DC

- d <domain>

Verwendet die angegebene Domain

Freie LDAP-Suchen

Etwas mehr Erläuterung benötigt das Subkommando *, mit dem Sie in der Lage sind, beliebige Suchen im AD durchzuführen. Hier existieren zusätzliche Optionen: -filter, -attr und -l. Die Option -filter legt (wie bei csvde und ldifde) einen LDAP-Suchfilter fest, während -attr eine Liste der auszugebenden Attribute (oder * für alle) festlegt. Damit alles schön neu und damit anders bleibt, wird hier die Liste der Attribute nicht durch Kommata, sondern durch Leerzeichen getrennt. Die Option -l schließlich schaltet vom Tabellenformat für die Ausgabe in ein Listenformat (ähnlich dem LDIF-Format) um.

Damit dies alles klarer wird, auch hier wieder einige Beispiele. Als Erstes die übliche Suche nach den Kontakten, diesmal über die ganze Domain:

dsquery * -filter "(objectClass=contact)"

Jetzt alle Benutzer, deren Nachname mit einem Buchstaben von L-Z beginnt:

dsquery * -filter "(&(objectCategory=person)(sn>=L*))"

Als Letztes möchten wir eine Datumssuche vorstellen. Angenommen, Sie kommen frisch erholt und tatendurstig aus dem Urlaub und möchten wissen, welche Gruppen nach dem 01.06.2008 (dem ersten Tag Ihres Urlaubs) im Container „users“ erstellt wurden. Ersetzen Sie im folgenden Kommando den Domain-Namen durch den Namen Ihrer Domain.

dsquery * "cn=Users,dc=shellbook,dc=com" -filter "(&(objectClass=group)(whenCreated>=20080601000000.0Z))"

Falls Sie (wie bei csvde und ldifde) Kommata verwenden, erhalten Sie einfach eine leere Ausgabe, da dann als Attributname der gesamte String verwendet wird.

dsmod

dsmod erlaubt die Modifikation einzelner Attribute für bestehende Objekte im AD. Die folgenden Optionen gelten für alle unten aufgeführten Subkommandos:

Option

Bedeutung

- s <server>

verbindet mit dem DC <server>

-d <domain>

verwendet einen DC aus der angegebenen Domain

-u <user>

verwendet den angegebenen Benutzernamen

-p <password>

verwendet das angegebene Passwort

- c

continuous mode; fährt bei Fehlern mit der Abarbeitung fort, sonst wird beim ersten Fehler abgebrochen

- q

quiet mode; unterdrückt alle Ausgaben nach StdOut

- uc[i|o]

legt fest, dass der Eingabekanal (uci) beziehungsweise der Ausgabekanal (uco) oder beide (uc) Daten im Unicode-Format liefern

Ausblick

Dieser Teil der Artikelserie hat sich mit der System- und der Dateiverwaltung beim Shell Scripting unter Windows beschäftigt. Im nächsten Teil der Serie wird es um die Möglichkeiten von Scripts rund ums Netzwerk gehen. (mzu/mja)

Windows 2003 Shell Scripting: Das Buch zu unserer Serie.

Unsere neue Serie zum Shell Scripting unter Windows 2003 basiert auf Kapitel 16 des Standardwerks „Windows 2003 Shell Scripting - Abläufe automatisieren ohne Programmierkenntnisse“ von Armin Hanisch aus dem Haus Pearson Education. Sie können dieses 320 Seiten starke Buch auch in unserem Partner-Buchshop bestellen.

Artikelserie: Shell Scripting unter Windows 2003

Teil 1: Allgemeine Problemstellungen

Teil 2: System- und Dateiverwaltung

Teil 3: ActiveDirectory

Teil 4: Netzwerk