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
Löschen von Subtrees (Objekten mit Subobjekten)
Objekte in Containern löschen mit Delete
 


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.