ADSI und LDAP
Sehr viele Informationen zu Exchange stehen gar nicht in der Exchange Datenbank sondern im Active Directory. Damit ist natürlich ein Zugriff per LDAP und ADSI auf diese Informationen möglich. Zwar sollten Sie es vermeiden, direkt die Felder zu beschreiben, es sei denn Sie wissen um die Zusammenhänge aber auch zum Auslesen ist dies Schnittstelle wunderbar geeignet.
Folgende Informationen liegen z.B. im Active Directory und können per LDAP/ADSI ausgelesen werden:
- Eigenschaften der Empfänger
z.B.: die Mailadressen von Anwendern, Verteilern etc. - Mitgliedschaften von Verteilern
Verteiler sind auch nur "Windows Gruppen", die sie auslesen können - Liste der Exchange Server
Sogar die Versionsnummer ist im AD hinterlegt, genauso wie Daten zum Nachrichtentracking, Die Pfade der Exchange Datenbanken etc. - Übersicht über die Empfängerrichtlinien
Welche SMTP-Adressen werden von RUS vergeben ? - Eigenschaften des ADC
z.B.: um zu prüfen, wie aktuell der ADC gerade ist. - und vieles mehr
Wie verbinden ?
ADSI können ist über zwei Wege nutzen:
- Binden eines Objekts
Sie können in VBScript einfach ein Objekt "binden", wenn Sie den Pfad dorthin kennen und dann dieses Objekt auch verändern. Wenn Sie z.B.: eine OU "binden", dann können Sie auch mit einer Schleife alle Unterobjekte durchlaufen, z.B.:
set oObject = GetObject("LDAP://cn=Administrator,cn=Users,dc=msxfaq,dc=de")
- ADO Abfragen
Die zweite Option nutzt LDAP ähnlich einer Datenbankabfragen.
Bei allen Optionen müssen Sie nun den Pfad angeben. Diesen können Sie natürlich im Skript fest hinterlegen aber schön ist das nicht, da Sie dann das Skript immer anpassen müssen. Daher gibt es einige "vordefinierte" Pfade, die Sie einfach nutzen können z.B.:
set strRootDSE = GetObject ("LDAP://rootDSE")
wscript.echo strRootDSE.get ("defaultNamingContext")
wscript.echo strRootDSE.get ("schemaNamingContext")
wscript.echo strRootDSE.get ("configurationNamingContext")
wscript.echo strRootDSE.get ("rootDomainNamingContext")
wscript.echo join(strRootDSE.get ("namingContexts"),vbcrlf)
'hier kommt ein Array !!
Das Ergebnis ist nicht sonderlich überraschend:

Diese Werte können Sie nun aber ganz einfach in ihren eigenen Skripten verwenden.
Beachten Sie, dass der Eintrag "NamingContexts" ihnen in der Regel ein Array zurückliefert, welches sie nicht einfach per wscript.echo ausgeben können.
Suchen und Auslesen von Objekten aus dem GC
Neben der direkte Verbindung zu einem bekannten benannten Objekt, kann man mit ADSI natürlich auch LDAP-Abfragen absetzen und so gezielt nach bestimmten Objekten suchen. Hier ein Beispiel, wie sie einen GC nach allen Mailobjekten (mailnickname=*) befragen.
wscript.echo "Looking for GC"
dim oCont, oGC
Set oCont = GetObject("GC:")
For Each oGC In oCont
strGCPath = oGC.ADsPath
Next
wscript.echo "strGCPath=" & strGCPath, 3
wscript.echo "Querying AD for Objects" & strGCPath
Set oConnection = CreateObject("ADODB.Connection")
Set oRecordset = CreateObject("ADODB.Recordset")
Set oCommand = CreateObject("ADODB.Command")
oConnection.Provider = "ADsDSOObject" 'The ADSI OLE-DB provider
oConnection.Open "ADs Provider"
oCommand.ActiveConnection = oConnection
oCommand.Properties("Page Size") = 100
oCommand.CommandText = "<" & strGCPath & ">;" & _
"(mailnickname=*);" & _
"distinguishedName,ObjectClass,displayName,mail" & _
";subtree"
Set oRecordset = oCommand.Execute
wscript.echo "Done Total Records found:" & oRecordset.recordcount
do until oRecordset.EOF
wscript.echo "---- Infos aus dem ADO-Recordset ----"
wscript.echo "Klasse:" & lcase(join(oRecordset.Fields("ObjectClass"),","))
wscript.echo
wscript.echo "distinguishedName:" & oRecordset.Fields("distinguishedName")
wscript.echo "displayName :" & oRecordset.Fields("displayName")
wscript.echo "Mail :" & oRecordset.Fields("mail")
wscript.echo "---- Infos aus dem gebundenen Object ----"
set oObject = GetObject("LDAP:// " & oRecordset.Fields("distinguishedName"))
wscript.echo "name :" & oObject.name
wscript.echo "SamAccountName:" & oObject.samAccountName
oRecordset.MoveNext
loop
Natürlich können Sie das Script auch einfach für eigene Tests herunterladen.
gcsearch.vbs
Nach dem Download als VBS-Datei speichern und mit CSCRIPT aufrufen
Wenn Sie den GC befragen, müssen Sie sich nicht um die verschiedenen Domains in ihrem Forest kümmern. Aber Sie sollten eine wichtige Einschränkung kennen:
Leider liefert solch eine Anfrage nur die Ergebnisse, die
der globale Katalog auch vorhält. Speziell MultiValue-Felder sind hier
kritisch. So können Sie die Fehler "msExchPolicyIncluded" und "msExchPolicyExcluded"
nicht über den GC auslesen. Die Inhalte sind einfach "null".
Dieser Fehler fällt ihnen normalerweise nicht auf, wenn Sie "genau
eine" Domäne betreiben, da dann der GC natürlich auch die anderen Felder
"seiner" Domäne liefern kann.
Ob ein Feld in den GC repliziert wird, können Sie im Schema selbst nachschauen.

Auch Microsoft veröffentlicht auf der Webseite die Information, welche Felder im GC per Default enthalten sind:
- Global Attributes im GC
http://msdn2.microsoft.com/en-us/library/ms675094.aspx
Sie sollten aber nun nicht aus Verzweiflung ihre gewünschten Felder im Schema für den GC aktivieren. Dies ergibt eine hohe Replikationslast und ist nicht sinnvoll.
Es gibt noch eine zweite "Abfragesprache" um den LDAP-Query zu erstellen. Sie ähnelt eher einer SQL-Abfragen.
Set objADO = CreateObject("ADODB.Connection")
objADO.Provider = "AdsDSOObject"
objADO.Open
strSQL = "SELECT mail, st FROM 'LDAP://server/o=msxfaq' WHERE objectClass='person'"
Set rs = objADO.Execute(strSQL)
For i = 0 to rs.Fields.Count - 1
strHead = strHead & rs.Fields(i).Name & vbTab
Next
While Not rs.EOF
strOut = strOut & GetRows(rs) & vbCrLf
rs.MoveNext
Wend
Das Ergebnis ist aber das gleiche. Bei der Suche muss man aber ein paar Einschränkungen wissen:
- Systemfelder wie MemberOf
Diese Felder werden z.B. "errechnet", d.h. sie sind sogar nicht da und durchsuchbar, sondern das AD ermittelt den Inhalt aus dem Feld "Members" der jeweiligen Gruppen. - Numerische Felder "USNChanged" etc
Sie können natürlich auch auf diese Felder filtern. Dabei können Sie aber nur die Optionen "<=" und ">=" nutzen. Eine Suche nach ">" oder "<" ist nicht direkt möglich. Sie könne aber natürlich ">" ersetzen durch "!(feld<=wert).
Siehe dazu auch http://tools.ietf.org/html/rfc4515 (and, or, not, equalityMatch, substrings, greaterOrEqual,lessOrEqual,present,approxMatch,extensibleMatch)
Auslesen über das Objekt
Um diese Felder zu erhalten, können Sie, wie im Beispielskript schon exemplarisch umgesetzt, sich einfach mit dem Objekt verbinden und dann auf alle Felder zugreifen. Dieser Vorgang ist aber "langsam" und belastet das Netzwerk, wenn Sie wirklich nur Daten auslesen wollen.
Auslesen aller Objekte aus allen Domänen
Der bessere Weg ist dann eine Verbindung mit der jeweiligen Domäne herzustellen. Folgender Beispielcode holt sich auf der Konfiguration des Active Directory alle Partitionen und verbindet sich dann sequentiell mit den einzelnen Domains und holt die gewünschten Daten ab.
set strRootDSE = GetObject ("LDAP://rootDSE")
wscript.echo "Loading Domains at LDAP://CN=Partitions," & strRootDSE.get ("configurationNamingContext")
set opartition = GetObject("LDAP://CN=Partitions," & strRootDSE.get ("configurationNamingContext"))
for each oDomain in opartition
if oDomain.netbiosname = "" then
wscript.echo "Skip Domain: " & oDomain.dnsroot
else
wscript.echo "Processing Domain: " & oDomain.dnsroot
call ParseDomain(oDomain.dnsroot)
end if
next
sub ParseDomain(strdomainname)
wscript.echo "Querying AD for Objects at Domain:" & strdomainname
Set oConnection = CreateObject("ADODB.Connection")
Set oRecordset = CreateObject("ADODB.Recordset")
Set oCommand = CreateObject("ADODB.Command")
oConnection.Provider = "ADsDSOObject" 'The ADSI OLE-DB provider
oConnection.Open "ADs Provider"
oCommand.ActiveConnection = oConnection
oCommand.Properties("Page Size") = 100
oCommand.CommandText = "<LDAP://" & strdomainname & ">;" & _
"(mailnickname=*);" & _
"distinguishedName,ObjectClass,displayName,mail" & _
";subtree"
Set oRecordset = oCommand.Execute
wscript.echo "Done Total Records found:" & oRecordset.recordcount
do until oRecordset.EOF
wscript.echo "distinguishedName:" & oRecordset.Fields("distinguishedName")
wscript.echo "displayName :" & oRecordset.Fields("displayName")
wscript.echo "Mail :" & oRecordset.Fields("mail")
oRecordset.MoveNext
loop
end sub
Hier das ganze auch als Download:
domainsearch.vbs
Bitte als VBS-Datei speichern und mit CSCRIPT starten
Dieser Weg ist zwar auch nicht grade "hübsch", aber wenn sie bei der Auswertung von 100.000 Objekten nicht mehrere Stunden sondern nur einige Minuten warten wollen, dann ist dieser Weg immer besser als ein Bind auf jedes einzelne Objekt.
Achtung: Das Script nimmt nur die Partitionen mit einem NETBIOS-Namen des Active Directory.Seit Windows 2003 gibt es z.B. auch die DNS-Partitionen. Zudem könnten von ihnen gesuchte Objekte auch in der Konfigurationspartition liegen. Dies sollten Sie beim Programmieren beachten um Dubletten zu vermeiden.
GetInfo, SetInfo und GetInfoEx
ADSI lädt per Default immer die "Standardfelder" in den lokalen Cache und arbeitet damit. d.h. wen Sie nun über Minuten hinweg mit einem Objekte arbeiten, könnte es sein, dass dieses auf dem Domänencontroller schon wieder geändert wurde. Um eben diesen Cache wieder aktualisieren muss man dann "Getinfo" verwenden. Getinfo sorgt dafür, dass das ADSI-Objekt neu geladen wird.
Wenn Sie Feldinhalte verändern, dann werden auch diese nicht sofort in das LDAP-Verzeichnis zurück geschrieben, sondern erst ein "SetInfo" schreibt die Inhalte letztlich zurück. Wenn Sie viele Werte ändern, dann kann es sich anbieten, mehrere SetInfo einzubauen, damit man bei Fehlern auch besser sieht, welches Feld gerade nicht "gemocht" wird. Wenn Sie jedoch sicherstellen wollen, dass mehrere Fehler immer "als Block" geändert werden (analog zu einem BeginTransaction und EndTrancaction bei Datenbanken) dann sollten Sie das SetInfo nach der letzten Änderung durchführen.
Wenn Sie nicht genau wissen, welche Felder das Objekt ihnen anbietet, dann kann folgende Codesequenz helfen:
for count = 0 to object.propertycount
wscript.echo object.item(count).name & vbtab & object.item(count).value
next
Sie holt erst die Anzahl der Properties und gibt dann die Namen und Werte der einzelnen Eigenschaften aus.
Einige besondere Eigenschaften können Sie so aber nicht erhalten. Die so genannten "Operationalen Attribute", d.h. Felder die Sie nicht setzen können, aber durch das LDAP-Verzeichnis einfach befüllt werden, erhalten Sie erst durch einen "GetInfoEx". Allerdings sorgt dieser Befehl indirekt auch dafür, dass nun alle Felder, die einfach nur ein "String" sind, nun durch ein Array mit der Größe 1 ersetzt werden. Beim Zugriff muss man also auf das Feld 0 zugreifen.
- SelfADSI - Das LDAP / ADSI Scripting Tutorial Objekt-Attribute lesen
http://www.selfadsi.de/read.htm
ADSI und Last
ADSI hat unter Entwicklern manchmal den Ruf, dass es zwar nett und einfach zu nutzen ist, aber die Performance nicht gerade zum besten ist. Das ist auch bei .NET 1.1 noch so, das hier auf ADIS zurück gegriffen wird. Erst mit .NET 2.0 hat sich dies wohl geändert. Um die Funktion von ADSI und die Belastung besser zu verstehen, habe ich ein ganz kleines Script gebaut und den Traffic mitgeschnitten:
WScript "1. Bind Object"
set test = GetObject("LDAP://CN=Carius\, Frank,OU=Technik,OU=Abteilung,DC=netatwork,DC=de")
WScript.echo "1. Ausgabe von: test.ADsPath " & test.ADsPath
WScript.echo "1. Zugriff auf Feld test.msExchPoliciesIncluded" & vartype(test.msExchPoliciesIncluded)
WScript.echo "2. Zugriff auf Feld test.msExchPoliciesIncluded" & vartype(test.msExchPoliciesIncluded)
WScript "2. Bind Object"
set test = GetObject("LDAP://CN=Carius\, Frank,OU=Technik,OU=Abteilung,DC=netatwork,DC=de")
WScript.echo "2. Ausgabe von: test.ADsPath " & test.ADsPath
WScript.echo "3. Zugriff auf Feld test.msExchPoliciesIncluded" & vartype(test.msExchPoliciesIncluded)
Die Screen Captures wurden mit Insight Active Directory erstellt, welches Sie auf www.winternals.com als Bestandteil des Administrators Pack kostenpflichtig kaufen können.
Diese Script bindet sich einfach an meinen Benutzer und gibt ein paar Werte aus. Dabei ist folgendes zu sehen:
- Erstes Binden mit dem Objekt
Hierbei gehen sehr wenige Daten über die Leitung
.
Eigentlich wird der Zugriff zuerst anonym versucht, was natürlich nicht funktioniert und dann mit meinen Credentials. Das Object wird schnell gefunden - Ausgabe des ADSPath
Für diese Ausgabe wird keine weitere Verbindung zum LDAP-Server benutzt. Die Information ist also schon im ADSI-Objekt enthalten - Ausgabe eines "Nutzfelds" (hier msExchPoliciesIncluded)
Für die Ausgabe dieses einen Felds kommt sehr viel Bewegung in das Active Directory. Es schein so, als ob das ADSI-Objekt einfach alle Felder dieses Objekts vorsorglich einliest. Und weil damit nicht genug ist, wird auch noch schnell ein Teil des Schemas eingelesen.

Das mag auf den ersten Blick erst mal als Verschwendung angesehen werden, da hierbei natürlich viele Daten auch überflüssigerweise gelesen werden. Das müssen wir erst mal so hinnehmen - Weiteres Feld ausgeben
Wird dann ein weiteres Feld des gleichen Objekts ausgegeben, dann werden die Daten des lokalen Cache genutzt, d.h. die Daten werden nicht erneut vom LDAP-Server gelesen. Da kann natürlich bedeuten, dass ein Script, welches noch andere Funktionen ausführt und erst später auf das Objekt zurück kommt auf alten Daten aufsetzt. - Objekt erneut binden
Im nächsten Schritt wurde das Objekt einfach noch mal gebunden. Wie nicht anders zu erwarten wird das bestehende Objekt nicht "recycled", sondern die Bindung wird komplett frisch aufgebaut. Das Feld "ADSPAth" wird dann noch direkt ausgegeben. Beim Zugriff auf ein anderes Feld wird erneut das komplette Objekt in den Speicher übertragen.
Besonders "unschön" ist, dass auch die verbundenen Informationen im Schema ebenfalls erneut geladen werden, obwohl diese ja unverändert sind. Ich kann nur vermuten, dass die Entwickler hier die Aktualität und Gültigkeit der Daten höher priorisiert haben als Bandbreite und Belastung einsparen.
Abhilfe ist hierbei nicht einfach möglich. Wenn Sie große Datenmengen auslesen wollen, dann sollten Sie besser mit ADO die Daten unter Angabe entsprechender LDAP-Filter und Feldangaben abfragen, wobei diese jedoch nur zum Lesen geeignet sind. Um ein Objekt zu verändern, müssen Sie es binden und schreiben.
ADSI und VBScript-Besonderheiten
Wenn Sie nun schon am Skripten sind, dann sollten Sie auf jeden Fall genug Code für Debugging einbauen und einzelne Funktionen oder Teile ausführlich Testen. VBScript aber auch ADSI haben einige Besonderheiten, die man nicht auf Anhieb erkennt. Folgendes Beispiel soll das verdeutlichen:
set objUser = GetObject("LDAP://cn=user1,ou=Anwender,dc=msxfaq,dc=de")
wscript.echo "Test1:" & objUser.name
wscript.echo "Test2:" & objUser.get("name")
Beide Mal soll der Inhalt des Feldes "Name" ausgegeben werden. Die tatsächliche Ausgabe sieht aber wie folgt an:
Test1:CN=user1 Test2:user1
Diese "Besonderheit" hat mich schon einige Stunden gekostet, wenn ein VBScript z.B. anhand des Namens eines Objekts dann weitere Verarbeitungen durchführen soll.
ADSI und Powershell
Natürlich kann man auch per Powershell über das ADSI-Kürzel direkt auf Objekte zugreifen.
$objUser = [adsi]"LDAP://cn=user1,ou=Anwender,dc=msxfaq,dc=de"
Wichtig ist hier die genaue Schreibweise mit LDAP in Großbuchstaben und "//"-Zeichen. Ein paar sehr gute Anleitungen gibt es auf:
- Mastering PowerShell in your Lunch Break
Day 6: ADSI Connecting to Domains/Computers and Binding to Objects
http://powershelllive.com/blogs/lunch/archive/2007/04/04/day-6-adsi-connecting-to-domains-computers-and-binding-to-objects.aspx - Mastering PowerShell in your Lunch Break
Day 7: Manage Users
http://powershelllive.com/blogs/lunch/archive/2007/04/05/day-7-manage-users.aspx - Powershell Beispiele
ADSI und mehrere Domains
Kniffliger wird die Arbeit mit mehreren Domänen oder Forests. Per Default verbindet sich ADSI immer mit dem DC, der für den angemeldeten Benutzer maßgeblich ist. Eine Suche gegen den globalen Katalog ist zumindest im Bezug auf den Forest fast immer vollständig (Sonderfall Domain lokale Gruppen). Aber Änderungen an Objekten müssen immer auf einem DC durchgeführt werden, welcher auch eine beschreibbare Partition hat. Den muss man sich aber selbst suchen oder unter expliziter Angabe der Domäne suchen lassen.
Interessant wird hier auch die Aufgabenstellung, einen Benutzer in einer Domäne anzulegen und im gleichen Schritt in eine Gruppe in einer anderen Domäne zu addieren, welche in einem anderen Standort ist. Spätestens hier kommt dann die "Replikation" ins Spiel, dass der DC der Gruppe den Benutzer noch gar nicht auflösen kann. Die einfache Variante der folgenden Form funktioniert daher nicht:
Set GroupObj = GetObject("WinNT://domain01/gruppe01")
GroupObj.Add ("WinNT://domain02/user01)
Auch der Versuch per LDAP schlägt fehlt:
Set objUser = GetObject("LDAP://cn=user01,ou=test,dc=domain,dc=tldde")
Set objGroup = GetObject("LDAP://cn=gruppe01,ou=test,dc=domain02,dc=tld")
objGroup.Add(objUser.ADsPath)
Allerdings gibt es ja noch andere Schreibweisen, um einen Benutzer in eine Gruppe zu addieren. Eine spezielle Syntax erlaubt die Angabe der SID:
GroupObj.Add ("WinNT://SID=<sid>")
Allerdings müssen Sie dazu die SID natürlich erst noch in das SDDL-Format bringen, um dieses zu addieren. Ein einfaches "objuser.SID" liefert nur ein Byte-Array zurück. Die erforderliche Konvertierung ist in VBScript etwas mühselig aber von anderen Autoren schon beschrieben.
- Developer Support ADSI, WMI, Powershell Team Blog
http://blogs.msdn.com/dsadsi/archive/2009/05/27/cross-forest-iadsgroup-add-receiving-error-80072030-there-is-no-such-object-on-the-server.aspx - Hey, Scripting Guy!
http://www.microsoft.com/technet/scriptcenter/resources/qanda/oct05/hey1014.mspx - WinNT:// provider searching for user by SID
http://www.tek-tips.com/viewthread.cfm?qid=1247882&page=1 - ADSI FAQ
http://cwashington.netreach.net/depo/default.asp?topic=adsifaq
Nach meinen Erfahrungen funktioniert der Weg über die SID aber nur, wenn die SID nicht im gleichen Forest sind. Ein Addieren einer SID eines Objekts aus einer andere Domäne im gleichen Forest konnte ich nicht durchführen. Anscheinend erkennt der DC, dass es sich um eine SID im Forest handelt und versucht den DN aufzulösen, genau wie bei allen anderen Wegen. Und dies funktioniert nur, wenn das Objekt schon im über den GC auflösbar ist.
ADSI/LDAP und Update von Objekten
Bei meiner Umsetzung der Skripte zur Verzeichnissynchronisation (MiniSync) ist mir ein interessante Verhalten aufgefallen. Wenn ein Skript Felder wieder beschreibt und am Ende mit SETINFO an den LDAP-Server sendet, dann aktualisiert der Server die Daten und erhöht die USN.
Wenn ich per VBScript jedoch ein Feld mit einem Wert beschreibe, der dem alten Wert entspricht, dann kann ich sehr oft ein SETINFO aufrufen und die Daten werden auch an den Server übertragen, aber das Windows 2003 Active Directory führt die Änderungen nicht aus. Das ist auch kein Fehler sondern eher eine sinnvolle Optimierung, denn wenn ein Feld nicht wirklich geändert wird, dann muss man auch keine Datenbankaktivität und Replikation provozieren. Interessant ist das in der Hinsicht, dass die Skripte nicht mehr selbst diese Optimierung durchgehen müssen. Mich würde interessieren, ob andere LDAP-Server das gleiche Verhalten zeigen.
Auch wenn das Objekt direkt per LDAP mit LDP.EXE beschrieben wird, zeigt sich das gleiche Verhalten. Es ist also keine Funktion des ADSI-Clients.
ADSI und Performance beim Suchen
Bei der Abfrage eines LDAP-Verzeichnisses per ADSI sollten Sie auch noch ein Blick auf ihre Filterkriterien werfen. Nicht alle Felder sind mit einem Index versehen. So kann eine Anfrage wie "(telephoneNumber=*)" sehr viel Last erzeugen, weil die Telefonnummer nicht mit einem Index versehen ist. Es kann daher sogar günstiger sein, eine andere Abfrage zu wählen, bei der mehr Antworten kommen und dann das richtige Objekt auszusuchen. Auch Exchange macht solche Anfragen. Sie "suche" nach einem Objekt anhand des DN ist ungünstig, da dieser Name nicht im Index ist, der CN hingegen ist indexiert. Wenn Sie daher nach dem CN suchen, dann gibt dies meist auch nur genau einen Treffer. Selbst wenn es mehrere Objekte mit dem gleichen CN in unterschiedlichen OUs gibt, dann ist die Abfrage um ein vielfaches schneller, so dass die nachfolgende Prüfung der Liste auf der gewünschte Objekt sehr schnell erfolgt.
In dem Zuge sollten Sie auch die Besonderheit von der Eigenschaft "Recordcount" kennen. Nach einer ADO-Suche kann man über den Recordcount die Anzahl der gefundenen Elemente erhalten. Schlecht ist allerdings, dass auch der DC die genauer Anzahl eigentlich nicht weiß und ADSI für die Bestimmung alle Objekte abholt. Wenn Sie daher bei einer Anfrage z.B.: 30000 Einträge erhalten, dann dauert eine schlichte Ausgabe von objRecordset.recordcount durchaus einige Sekunden oder gar Minuten. Wenn Sie also sowieso mit einem "While not EOF"-Schleife die Ergebnisse abarbeiten wollen und keine Fortschrittsanzeige benötigen, dann verzichten Sie doch einfach darauf. Gerade wenn z.B.: ein Skript unbeobachtet läuft, ist dies problemlos möglich. (Ich habe bei MiniSync mittlerweile auch drauf verzichtet).
Übrigens gibt es bei Windows 2003 auf der OU ein Property "msDS-Approx-Immed-Subordinates", welches eine geschätzte Anzahl der Unterobjekte enthält. Das hilft aber nicht bei einer Suche über die Domäne oder den GC, sondern nur bei einer Auflistung in dieser OU. Und auch dann ist das eher ein Schätzwert.
Das setzen der "Page Size" hat nach meinen Erfahrungen keinen merklichen Einfluss auf die Geschwindigkeit. Daher bleibe ich hierbei besser unter der Grenze des LDAP-Servers (Ex55 = 1000. W2k=1000, WW3K=1500), z.B. durch
objCommand.Properties("Page Size") = 100 ' Pageing akivieren
Übrigens können Skripte auf Servern kräftig gebremst werden, wenn die Performance des Servers für Hintergrundprozesse optimiert wird.
Weitere Links
Sehr viele Beispiele und Tools auf dieser Webseite nutzen VBScript und ADSI, um bestimmte Tätigkeiten durchzuführen.
- AddSelf
- WSH - Benutzer mit Postfach anlegen
- CheckADC
- CheckAGMode
- CheckExObjects
- CheckTracking
- CheckRUS mit MOM
- CheckRUS
- DumpRecipientPolicies
- FINDSMTP
- RUSMon
- Grp2ExInet
- LDAP 5.5
- EX55 LDAPFelder
- Windows Hilfsprogramme - LDIFDE
- Active Directory Service Interfaces Overview
www.Microsoft.com/adsi - Microsoft Windows 2000 - Scripting-Handbuch (Teil 1)
Scripting-Konzepte und -Technologien zur Systemadministration: Kapitel 5 - ADSI-Scripting
http://www.Microsoft.com/germany/technet/datenbank/articles/600361.mspx#EZBAE - Beispiele für ADSI 2.5 gegen Exchange 5.5
http://dev.coadmin.dk/Resources/ADSI%20SDK%205%20HTML/exchange.htm - 922258 How to use a VBScript to write proxy addresses to an Ldifde.exe-compatible import file in Exchange Server 2003
- 313114 HOW TO: Create a Mailbox-Enabled Recipient by Using C# .NET
-
Property Sets in Exchange Server 2007
http://msexchangeteam.com/archive/2006/09/14/428922.aspx - RFC 2254, A String Representation of LDAP Search Filters"
- Microsoft® Windows® 2000 - Scripting-Handbuch (Teil 1)
Scripting-Konzepte und -Technologien zur Systemadministration
Kapitel 5- ADSI
http://www.Microsoft.com/germany/technet/datenbank/articles/600361.mspx - SelfADSI
http://www.cerrotorre.de/selfadsi/selfadsi.htm
http://www.selfadsi.de/selfadsi/selfadsi-ldapfilter.htm
http://www.selfadsi.de/user-attributes.htm
http://www.selfadsi.de/group-attributes.htm
http://www.selfadsi.de/selfadsi/selfadsi-att55mbx.htm Exchange 5.5. Felder
SelfADSI - Das LDAP / ADSI Scripting Tutorial Objekt-Attribute lesen
http://www.selfadsi.de/read.htm - ADSI mit Beispielcode und XLS-Übersichten der Attribute
http://www.rlmueller.net/ - AD-Automaten - mit VBScript das Active Directory bearbeiten
WebCast http://go.Microsoft.com/?linkid=4954331 - Scripts to manage Active Directory Users
http://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/usersgroups/users - http://www.peregrinehw.com/downloads/ldap/test-ldap-gen.pl
- http://www.mimedefang.org/kwiki/index.cgi?Exchange2Access
- http://groups.google.com/group/mailing.postfix.users/browse_frm/thread/1f0ba481d5216626/c0b1e2142d1b415e
-
HOWTO: Dump out Contacts using CDOEX and ADO
http://blogs.msdn.com/akashb/archive/2008/11/14/howto-dump-out-contacts-using-cdoex-and-ado.aspx









