Printout Header
RSS Feed

LDAP Verzeichnisobjekte löschen


Dieser Abschnitt des SelfADSI Tutorials beschäftigt sich mit dem Löschen von Objekten in LDAP-Verzeichnissen. Folgende Themen stehen zur Verfügung:


Einzelne Objekte löschen mit DeleteObject
Objekte in Containern löschen mit Delete
Löschen von Subtrees (Objekten mit Subobjekten)


Einzelne Objekte löschen mit DeleteObject


Wenn man ein Objekt innerhalb eines ADSI Scriptes löschen will, so muß man sich mit dem Objekt verbinden und dann die Funktion DeleteObject ausführen.


obj.DeleteObject(0)


Der Parameter ist reserviert und muß stets auf den Wert 0 gesetzt werden.

Set obj = GetObject("LDAP://CN=JohnDoe,OU=users,OU=company,DC=cerrotorre,DC=de") obj.DeleteObject(0)

ADSI Reference im MSDN: DeleteObject()



Objekte in Containern löschen mit Delete


Wenn man viele Objekte innerhalb eines Containers (z.B. einer OU) löschen will, so kann man sich mit dem Container verbinden und dann die ADSI Funktion Delete benutzen.


container.Delete "<object class>", "<object RDN>"


Dabei müssen zwei String-Parameter übergeben werden: Die Objektklasse des zu löschenden Objektes, und der Objektename (der Relative Distinguished Name RDN - inklusive dem Label wie z.B. "cn=").

Set ou = GetObject("LDAP://OU=users,OU=company,DC=cerrotorre,DC=de") ou.Delete "user", "CN=PhilippFoeckeler" 'Einen User Account löschen Set ou = GetObject("LDAP://dc1.cerrotorre.de/OU=computers,OU=company,DC=cerrotorre,DC=de") For Each obj In ou ou.Delete obj.Class, obj.Name 'Alle Objekte im Container löschen Next

Ein anderes Beispiel zu Demonstrationszwecken: So könnte eine Funktion aussehen, die das Verbinden zum "Parent"-Container automatisiert.

DeleteAsChild "CN=Doe\, John,OU=Users,OU=DivisionB,OU=Cerro,DC=ldapexplorer,DC=com" Sub DeleteAsChild(objDN) Dim obj, container Dim objClass, objRDN, containerPath Set obj = GetObject("LDAP://" & objDN)? 'Objectklasse ermittlen objClass = obj.Class objRDN = obj.Name? 'RDN des Objektes ermittleln containerPath = obj.Parent? 'LDAP-Pfad des containers ermitteln Set container = GetObject(containerPath)?'Container-Objekt verbinden und Delete ausf?hren container.Delete objClass, objRDN End Sub

Bedenken Sie jedoch dabei, dass Sie das gleiche Ergebnis mit einem einfachen DeleteObject auch erreicht hätten.

ADSI Reference im MSDN: Delete()


Löschen von Subtrees (Objekte mit Subobjekten)


Wenn Sie versuchen, einen LDAP-Container (z.B. eine OU) zu löschen, in dem sich andere Objekte befinden, dann werden Sie den Laufzeitfehler 0x80072015 (-2147016683: LDAP_ONLY_ALLOWED_ON_LEAFS) bekommen. Die beiden hier vorgestellten Funktionen können nämlich nur Objekte löschen, wenn sich darunter keine Child-Objekte mehr befinden. Um einen gesamten Tree dennoch löschen zu können, benötigt man eine rekursive Funktion, die jeweils auch alle Child-Objekte löscht:

DeleteTree "OU=DivisionB,OU=Cerro,DC=ldapexplorer,DC=com" Sub DeleteTree(objDN) Set obj = GetObject("LDAP://" & objDN) If (obj.Class="organizationalUnit") Then For Each child In obj DeleteTree(child.distinguishedName) Next End If obj.DeleteObject(0) End Sub

In sehr großen Verzeichnis-Substrukturen kann eine solche Rekursion zuviel Zeit und Rechenkraft verschlingen. Deswegen zeige ich hier noch einen anderen Ansatz, der völlig ohne rekusive Aufrufe auskommt. Die Methode kann ebenfalls Subtrees löschen, geht aber nach folgendem Prinzip vor:

- Suche mittels einer LDAP Search Operation (ADO) alle Objekte unterhalb des zu löschenden Containers.
- Sortiere die Ergebnisse nach der Länge der Distinguished Names (entscheident sind hier die Anzahl der echten Kommas im DN)
- Lösche alle Objekte, die mit dem "längeren" DNs zuerst (so werden die Objekte der untersten Hierarchie immer zuerst gelöscht).

Das Script wird durch die LDAP-Suche und die Sortierung nach Länge der Namen syntaktisch komplizierter, ist jedoch viel schneller in der Ausführung, wenn es um wirklich komplexe und große Verzeichnisstrukturen geht:

DeleteTree("OU=DivisionB,OU=Cerro,DC=ldapexplorer,DC=com") Sub DeleteTree(objDN) children = Array() Set ado = CreateObject("ADODB.Connection") 'neue ADO Connection erzeugen ado.Provider = "ADSDSOObject" 'die ADSI-Schnittstelle verwenden ado.Open "ADS-Search" 'beliebigen Namen für die Connection vergeben Set adoCmd = CreateObject("ADODB.Command") 'neues ADO-Kommando erzeugen adoCmd.ActiveConnection = ado 'Zuordnung zur bestehenden ADO-Connection adoCmd.Properties("Page Size") = 1000 'Parameter für Paged Result Suche auf 1000 setzen (=AD Standard) adoCmd.Properties("Cache Results") = True adoCmd.CommandText = "<LDAP://" & objDN & ">;(objectClass=*);distinguishedName;subtree" Set objectList = adoCmd.Execute 'Suche durchführen ReDim children(objectList.RecordCount - 1) 'Arrayvorbereiten für Suchergebnisse i = 0 While Not objectList.EOF 'alle Suchergebnisse ins Array übertragen children(i) = objectList.Fields("distinguishedName") i = i + 1 objectList.MoveNext 'zum nächsten gefundenen Objekt Wend SortLongestFirst children 'Array sortieren, Längste Namen zuerst! For i = 0 To UBound(children) 'Objekte in der Reihenfolge des Arrays löschen Set obj = GetObject("LDAP://" & children(i)) obj.DeleteObject(0) Next End Sub '_________________________________________________________________________________________________________________ Sub SortLongestFirst(ByRef arr) 'ShellSort Funktion Dim value, index, index2, distance, lastEl, numEls lastEl = UBound(arr) numEls = lastEl + 1 distance = 1 Do distance = distance * 3 + 1 Loop Until distance > numEls Do distance = distance \ 3 For index = distance To lastEl value = arr(index) index2 = index Do While (commaCount(arr(index2 - distance)) < commaCount(value)) 'Längen-Vergleich nach Kommas arr(index2) = arr(index2 - distance) index2 = index2 - distance If index2 - distance < 0 Then Exit Do Loop arr(index2) = value Next Loop Until distance = 1 End Sub '_________________________________________________________________________________________________________________ Function commaCount(s) 'Kommas zählen sPure = Replace(s, "\,", " ") commaCount = 0 pos = InStr(sPure, ",") While (pos > 0) commaCount = commaCount + 1 pos = InStr(pos+1, sPure, ",") Wend End Function

Der verwendete Sortieralgorithmus ist übrigens ShellSort.