Active Directory-Scripting

10.02.2007 von Martin Kuppinger
Über ADSI lassen sich viele Aufgaben im Active Directory durchführen. Zu den wichtigsten zählt die Verwaltung von Benutzern, die im zweiten Teil dieser Serie näher beleuchtet wird. Dabei werden verschiedene Aspekte wie insbesondere die Aktivierung von Benutzerkonten und das Kennwortmanagement besprochen.

In diesem zweiten Teil der Serie wird die Verwaltung von Benutzern weiter ausgeführt, nachdem im ersten Teil (Ausgabe 10/2005) Grundzüge besprochen wurden. Zu den Themen gehört neben der Erstellung von Benutzerkonten auch ihre Aktivierung und der Umgang mit Kennwörtern und Kennwortoptionen.

Außerdem wird näher darauf eingegangen, wie weitere Attribute gesetzt werden können und wo sich weiterführenden Informationen zu diesen finden, um sie gezielt setzen zu können.

Benutzer anlegen

An einem Beispiel wurde im ersten Teil unserer Artikelserie bereits gezeigt, wie OUs und Benutzerkonten erstellt werden können. Dieses Beispiel findet sich noch einmal in Listing 1.

Listing 1: Die Erstellung einer OU und eines Benutzers
set domObject = GetObject("LDAP://dc=kuppinger,dc=net")
set ouObject1 = domObject.Create("organizationalUnit","ou=Testbenutzer")
ouObject1.Put "description","OU für Testbenutzer"
ouObject1.SetInfo
WScript.Echo "OU wurde erstellt"
set ouObject2 = GetObject("LDAP://ou=Testbenutzer,dc=kuppinger,dc=net")
set userObject = ouObject2.Create("user","cn=Testbenutzer1")
userObject.Put "sAMAccountName","Testbenutzer1"
userObject.Put "description", "Erster Testbenutzer"
userObject.SetInfo
WScript.Echo "Benutzer wurde angelegt"

Dabei wird deutlich, dass die Grundstruktur von Anwendungen zum Anlegen neuer Benutzer recht einfach ist. Der Kontext wird auf eine OU gesetzt, in der anschließend ein Objekt der Klasse user erstellt wird. Für dieses Objekt werden Attribute definiert, die mit der Methode SetInfo in das Active Directory geschrieben werden. Der einzige Fehler bei diesem sehr einfachen Ansatz ist, dass die so erstellten Benutzerobjekte noch nicht aktiviert sind.

Das lässt sich allerdings mit relativ wenig Code ändern, wobei es nicht ganz so trivial ist, den Code zu verstehen. Bevor diese Änderung in Listing 2 vorgestellt wird, macht es aber Sinn, sich näher zu betrachten, was genau beim Anlegen von Benutzern geschieht.

Auch wenn, wie in Listing 1 zu sehen ist, zunächst nur zwei Attribute gesetzt werden, von denen sogar nur eines wirklich zwingend ist, werden doch tatsächlich über vierzig Attribute definiert. Das liegt daran, dass viele Attribute auf Standardwerte gesetzt werden:

Das Attribut userAccountControl ist daher auch für die Aktivierung von Kennwörtern von Bedeutung. Es handelt sich um eines der Attribute im Active Directory, bei dem jedes Bit eine andere Bedeutung hat und aktiviert bzw. deaktiviert werden kann. Diese Attribute sind bedauerlicherweise etwas unhandlich, weil man genau wissen muss, welches Bit man innerhalb des Attributs jeweils zu manipulieren ist.

Dass einige Einstellungen bereits bei der Erstellung gesetzt werden, wird beim Blick auf die Eigenschaften eines Benutzers deutlich. Dort sind zwar viele Felder leer, aber für Optionen wie Konto läuft ab im Register Konto wird bereits ein Standardwert definiert (Bild 1).

Bild 1: Viele Attribute von Benutzern werden mit Standardwerten konfiguriert.


Wichtig ist, dass alle zwingend erforderlichen Attribute bereits gesetzt wurden. Um ein Benutzerkonto zu aktivieren, muss also nur noch der Wert des Feldes userAccountControl angepasst werden. Listing 2 zeigt eine mögliche Vorgehensweise dafür.

Listing 2: Listing zum Anlegen und Aktivieren von
Benutzerkonten
Const ADS_UF_ACCOUNTDISABLE = 2
set ouObject2 = GetObject("LDAP://ou=Testbenutzer,dc=windowstest,dc=intra")
set userObject = ouObject2.Create("user","cn=Testbenutzer2")
userObject.Put "sAMAccountName","Testbenutzer2"
userObject.Put "description", "Zweiter Testbenutzer"
userObject.SetInfo
WScript.Echo "Benutzer wurde angelegt"
intUAC = userObject.Get("userAccountControl")
If intUAC AND ADS_UF_ACCOUNTDISABLE Then
userObject.Put "userAccountControl", intUAC XOR ADS_UF_ACCOUNTDISABLE
userObject.SetInfo
End If
WScript.Echo "Benutzer wurde aktiviert"

In diesem Skript wird zunächst eine Konstante definiert, die beim User Flag, also dem Attribut userAccountControl, die Deaktivierung des Benutzerkontos steuert. Dabei wird der Wert 2 verwendet, der die Position des entsprechenden Bits identifiziert. In diesem Fall muss man sich noch nicht allzu viele Gedanken machen, weil der Wert im Dezimal- und Hexadezimalsystem identisch ist. In der Regel ist aber der hexadezimale Wert anzugeben, was durch die Notation &H2 erfolgen würde. Über dieses Bit wird die Aktivierung beziehungsweise Deaktivierung durchgeführt. Anschließend wird wie gehabt ein Benutzer angelegt.

Im Beispiel werden die Werte zunächst geschrieben, bevor das Attribut userAccountControl modifiziert wird. Dabei wird der Wert zunächst überprüft. Falls das Konto nicht aktiviert ist, wird mit einer XOR-Operation das entsprechende Bit geändert und die Information wieder geschrieben. XOR ist ein Operator, der bitweise
arbeitet und in diesem Fall eben das zweite Bit anpasst. Das Ergebnis ist ein aktiviertes Benutzerkonto (Bild 2).

Bild 2: Die OU mit einem deaktivierten und einem aktivierten Benutzer.

Damit sind die ersten Attribute für einen Benutzer gesetzt. Der nächste wichtige Schritt ist das Setzen des Kennworts und von Kennwortoptionen. Das Kennwort kann von Benutzern mit entsprechenden Berechtigungen über SetPassword gesetzt werden. Dabei wird eigentlich ein Reset durchgeführt. Das Kennwort wird also auf den neuen Wert zurückgesetzt. Das Listing 3 zeigt, wie diese Methode angewendet wird. Neben dem Setzen von Kennwörtern müssen in den meisten Fällen auch Kennwortoptionen angepasst werden. Die Änderungen werden in zwei Attributen durchgeführt. Beim Attribut userAccountControl können die Einstellungen

Listing 3: Anlegen von Benutzern und Setzen von Kennwörtern
Const ADS_UF_ACCOUNTDISABLE = 2
set ouObject = GetObject("LDAP://ou=Testbenutzer,dc=windowstest,dc=intra")
set userObject = ouObject.Create("user","cn=Testbenutzer5")
userObject.Put "sAMAccountName","Testbenutzer5"
userObject.Put "description", "Fünfter Testbenutzer"
userObject.SetInfo
WScript.Echo "Benutzer wurde angelegt"
intUAC = userObject.Get("userAccountControl")
If intUAC AND ADS_UF_ACCOUNTDISABLE Then
userObject.Put "userAccountControl", intUAC XOR ADS_UF_ACCOUNTDISABLE
userObject.SetInfo
End If
WScript.Echo "Benutzer wurde aktiviert"
userObject.SetPassword "!1ngh24$sDe"

gesetzt werden. Bei pwdLastSet wird dagegen gesteuert, ob das Kennwort bei der nächsten Anmeldung
vom Benutzer geändert werden muss oder nicht. Die Veränderung des Attributs user-AccountControl wurde in den Grundzügen bereits in Listing 2 erläutert. Eine umfassende Dokumentation des Attributs findet sich unter

http://msdn.microsoft.com/library/en-us/adschema/adschema/a_useraccountcontrol.asp

Dort sind alle Teile des Attributs mit ihren jeweiligen hexadezimalen Werten erläutert. Wichtige Werte sind beispielsweise

Um ein Bit zu deaktivieren, verwenden Sie generell die XOR-Operation. Für die Aktivierung wird dagegen mit der OR-Operation gearbeitet. Das Listing 4 zeigt ein Beispiel, in dem zusätzlich zum Setzen des Kennworts auch noch die Änderung des Kennworts bei der nächsten Anmeldung erzwungen wird.

Listing 4: Erzwingen einer Kennwortänderung bei der nächsten
Anmeldung
Const ADS_UF_ACCOUNTDISABLE = 2
set ouObject = GetObject("LDAP://ou=Testbenutzer,dc=windowstest,dc=intra")
set userObject = ouObject.Create("user","cn=Testbenutzer6")
userObject.Put "sAMAccountName","Testbenutzer6"
userObject.Put "description", "Sechster Testbenutzer"
userObject.SetInfo
WScript.Echo "Benutzer wurde angelegt"
intUAC = userObject.Get("userAccountControl")
If intUAC AND ADS_UF_ACCOUNTDISABLE Then
userObject.Put "userAccountControl", intUAC XOR ADS_UF_ACCOUNTDISABLE
userObject.SetInfo
End If
WScript.Echo "Benutzer wurde aktiviert"
userObject.SetPassword "!1ngh24$sDe"
userObject.Put "pwdLastSet", 0
userObject.SetInfo

Bild 3: Die meisten Attribute sind zunächst nicht mit Werten belegt.

Wenn man ein so erstelltes Benutzerkonto öffnet, enthält es aber immer noch recht wenige Informationen
(Bild 3). Das liegt daran, dass die meisten Attribute noch nicht mit Werten belegt wurden. Die Vorgehensweise dafür ist im Grundsatz sehr einfach:

Dabei können natürlich auch mehrere Werte angepasst werden, bevor die Änderung einmalig in das Active Directory geschrieben wird. Das ist sogar unbedingt sinnvoll, um die Last zu minimieren. Insofern ist auch das Listing 4 kein optimales Beispiel, weil hier mehrfach Änderungen geschrieben werden.

Die Herausforderung liegt darin, die Attribute zu ermitteln, die mit Werten belegt werden sollen. Dafür gibt es zwei wichtige Hilfsmittel. Eines ist die bereits erwähnte Dokumentation zu den Attributen, die im Zusammenhang mit userAccountControl schon angesprochen wurde. Das andere ist das Verwaltungsprogramm Active Directory-Schema. Es muss allerdings zunächst aktiviert werden, damit es über die MMC ausgeführt werden kann. Nach der Ausführung von

regsvr32 schmmgmt.dll


kann das Snap-In für das Schema-Management in der MMC eingebunden werden, in dem die Struktur des Schemas betrachtet werden kann. Um alle Attribute von Benutzern zu ermitteln, müssen Sie auf das Objekt user zugreifen. Im rechten Teil des Bildschirms wird dadurch die Liste der Attribute angezeigt (Bild 4). Viele Attribute sind selbsterklärend. Bei anderen empfiehlt sich ein zusätzlicher Blick in die Dokumentation.

Bild 4: Die Liste der Attribute der Objektklasse user im Active Directory.


Mit diesen Informationen lassen sich Benutzerkonten mit Attributen in beliebigem Umfang konfigurieren.

Benutzerkonten modifizieren und löschen

Um Benutzerkonten verändern zu können, ist es zunächst erforderlich, dass man Informationen auslesen kann. Listing 5 zeigt ein Beispiel für ein Skript, das Informationen liest.

Listing 5: Das Auslesen von Informationen über einen Benutzer
ouObject = ",ou=Testbenutzer,dc=windowstest,dc=intra"
set userObject = GetObject("LDAP://" & "cn=Testbenutzer6" & ouObject)
userObject.GetInfo
userSamName = userObject.Get("sAMAccountName")
userDescription = userObject.Get("description")
WScript.Echo userSamName
WScript.Echo userDescription

In diesem Fall wird zunächst eine Variable definiert, die die OU enthält, die damit nicht jedes Mal vollständig ausgeschrieben werden muss. Diese Variable wird beim Zugriff auf das Objekt angegeben. Anschließend wird die Methode Get-Info auf das Objekt angewendet. Diese Methode ist das Gegenstück zu SetInfo und öffnet ein Objekt zum Lesen. Entsprechend muss sie vor den späteren Get-Anweisungen stehen. Die Attributwerte werden anschließend mit Get ausgelesen und Variablen zugeordnet, bevor zum Schluss die
Ausgabe der entsprechenden Informationen erfolgt.

Änderungen sind nun sehr einfach durchzuführen, weil sie genau wie beim Erstellen von Benutzerkonten mit den Methoden Put und SetInfo erfolgen. Es ist also nicht zwingend erforderlich, zunächst Informationen auszulesen. Das Auslesen ist nur erforderlich, wenn zunächst eine Abfrage erfolgen soll, über die entschieden wird, ob eine Änderung erforderlich ist.

Ein Sonderfall ist das Ändern von Kennwörtern, das nicht einfach mit Put erfolgen kann. Ein Auslesen von Kennwörtern über Get ist ohnehin nicht möglich. Um Kennwörter zurückzusetzen kann, wie oben beschrieben, die Methode Set-Password verwendet werden.

Um ein Kennwort zu ändern, wird dagegen mit ChangePassword gearbeitet. Bei dieser Methode müssen als Parameter das alte und das neue Kennwort angegeben werden, also beispielsweise

userObject.ChangePassword "AltesKennwort", "Neues-Kennwort"

Diese Methode ist vor allem bei Skripts interessant, die in irgendeiner Form vom Endbenutzer ausgeführt werden können und bei denen das alte und das neue Kennwort erfragt werden.

Auf Basis der vorgestellten Methoden können bereits recht umfassende Lösungen entwickelt werden, da damit der Zugriff auf alle Objekte und fast alle Attribute im Active Directory möglich ist. Die wichtigste Ausnahme davon sind mehrwertige Attribute.

Zusammen mit den in Heft 10/2005 von Expert’s inside Windows NT/2000 erläuterten Grundlagen zum Scripting können so mit überschaubarem Aufwand Automatisierungslösungen rund um das Active Directory-Management entwickelt werden – soweit man weiß, welche Objekte und Attribute erstellt, modifiziert oder gelöscht werden müssen. Und dabei hilft die umfassende Dokumentation in der MSDN-Library.

Wie geht es weiter?

Im dritten Teil der Serie wird auf das Management von Gruppen eingegangen. Dazu gehören die Erstellung
von Gruppen und die Zuordnung von Benutzern zu Gruppen. Außerdem wird gezeigt, wie Listen von Zuordnungen zwischen Benutzern und Gruppen erzeugt werden können. Ein weiterer wichtiger Punkt sind Skripts, mit denen Systemumgebungen für Batches mit sehr vielen Benutzerkonten und Gruppen schnell erzeugt werden können. Das ist beispielsweise für Performance-Tests wichtig, bei denen mehrere hundert
oder tausend Benutzer benötigt werden. Außerdem wird auf den Umgang mit mehrwertigen Attributen eingegangen, die als Array ausgelesen werden müssen.