Inhaltsverzeichnis > LDAP Verzeichnisobjekte löschen
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
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.