Wer kennt es nicht? Man braucht eine Kopie der Struktur des produktiven Active Directorys, um ein paar Tests oder Anpassungen zu machen. Die Struktur beginnt dabei mit den Organizational Units (OUs).
In manchen Fällen reicht es vielleicht aus, ein paar Daten per Hand anzulegen.
Was aber, wenn man komplexere Daten und Strukturen benötigt?
Index
Exporte von OUs und Daten
OU- und Datenexporte funktionieren natürlich recht gut per PowerShell. Jedoch gibt es ein paar Stolpersteine. Wie man OUs einfach und schnell per Skript exportiert und wieder importiert, möchte ich hier kurz zeigen.
AD aufgeteilt in Länder > Städte > User
In unserem Beispiel handelt es sich um eine recht simple Teststruktur:
Unser AD ist aufgeteilt nach Ländern > Städte > User.
Im ersten Schritt können wir folgendes probieren:
- wir fragen einfach alle OUs unterhalb der Basis “Corp” ab,
- lesen den Namen und den DistinguishedName aus und
- schauen, was uns PowerShell (formatiert als Tabelle), dort zurückgibt.
OUs abfragen
Dafür benutzen wir folgenden Befehl:
1 |
Get-ADOrganizationalUnit -filter * -SearchBase "OU=Corp,DC=demofa,DC=net" | Select-Object Name,DistinguishedName | Format-Table |
Wenn wir uns das Ergebnis anschauen, sieht das bereits recht gut aus:
Man kann allerdings sehen, dass die Reihenfolge recht zufällig erscheint. Die FRA-OU sollte eigentlich in der Nähe der anderen deutschen OUs sein, wird aber erst ganz am Ende gelistet. Dabei kann es natürlich passieren, dass eine OU eher in der Tabelle (bzw. in der exportierten Datei) steht, als ihr Parent.
Das birgt beim Anlegen natürlich Probleme: Parents müssen zuerst angelegt werden.
Reihenfolge rekursiv auslesen
Um das zu lösen, müssen wir nicht die gesamte OU-Struktur auslesen, sondern Ebene für Ebene. Das machen wir mit Hilfe einer rekursiven Funktion. Diese liest alle OUs auf der darunterliegenden Ebene auf, formatiert diese und fügt sie der Ausgabe-CSV hinzu. Die Funktion dazu erkläre ich gleich. Als letztes ruft sie sich dann selbst für alle gefundenen OUs wieder auf.
1 2 3 4 5 6 7 8 9 |
function get-ous-recursive($distinguishedName){ $ous = Get-ADOrganizationalUnit -filter * -SearchBase $distinguishedName -SearchScope OneLevel | Select-Object Name,DistinguishedName foreach($ou in $ous) { format-and-add-to-csv -ou $ou } foreach($ou in $ous) { get-ous-recursive $ou.DistinguishedName } } |
Hier noch einmal veranschaulicht:
- Zuerst wird die Ebene der Länder durchsucht,
- dann sind alle Städte unter dem ersten Land dran (DE),
- daraufhin die jeweiligen User-OUs unter den Städten.
Danach geht es mit den anderen Ländern im selben Verfahren weiter.
OUs formatieren
Da wir nun sichergestellt haben, dass die OUs in der richtigen Reihenfolge sind, formatieren wir sie noch ein wenig.
Wir lesen den Namen und den DistinguishedName der OU aus. Eigentlich brauchen wir den zweiten aber gar nicht. Uns interessiert nur, wie der Parent heißt. Deswegen gibt es noch die Funktion “format-and-add-to-csv”. Sie leitet aus dem DistinguishedName den Parent ab. Anschließend packt sie die beiden Eigenschaften in ein PSObject und fügt sie dann zu einer ArrayList hinzu. Diese exportieren wir am Ende als CSV.
1 2 3 4 5 6 7 8 9 10 11 12 |
function format-and-add-to-csv($ou){ $parentNameList = New-Object System.Collections.ArrayList $parentNameList.AddRange($ou.DistinguishedName.Split(',')) $parentNameList.RemoveAt(0) $parentName = $($parentNameList -join ",") $csvou = New-Object PSObject -Property @{ Name = $ou.name Parent = $parentName } $csvous.Add($csvou) } |
Nun haben wir alles, was wir brauchen! Fangen wir also mit dem eigentlichen Skript an.
OUs exportieren
Als erstes initialisieren wir zwei Variablen: unsere ArrayList für den CSV-Export und unsere SearchRoot.
1 2 |
$csvous = New-Object System.Collections.ArrayList $base = "OU=Corp,DC=demofa,DC=net" |
Unsere rekursive Funktion deckt nicht die Root, die wir übergeben, mit ab (Corp in diesem Fall). Wenn wir diese noch mit zur CSV hinzufügen wollen, müssen wir das entweder händisch machen oder wir nutzen einfach die bereits bekannten Methoden.
1 2 |
$baseou = Get-ADOrganizationalUnit -filter * -SearchBase $base -SearchScope Base | Select-Object Name,DistinguishedName format-and-add-to-csv -ou $baseou |
Achtung, hier wird als SearchScope “Base” verwendet im Gegensatz zu dem anderen Aufruf.
Jetzt rufen wir unsere rekursive Funktion auf, die uns den Rest des Arrays füllen wird:
1 |
get-ous-recursive -distinguishedName $base |
Und zu guter Letzt müssen wir das ganze natürlich noch in eine reale CSV-Datei exportieren:
1 2 |
$path = "C:\Export\ad_ou_export.csv" $csvous | Export-Csv -Delimiter ";" -Path $path -NoTypeInformation -Encoding UTF8 |
Auch wenn es insgesamt vielleicht etwas kompliziert klingt, funktioniert es doch sehr gut, wie man auch am Ergebnis sehen kann:
Das Gute an dem Skript ist:
Man kann einfach die Variable $base austauschen und es funktioniert mit jeder beliebigen OU-Struktur wieder. Außerdem wird die Mühe, die man sich gemacht hat, beim Import auch gleich belohnt.
OUs importieren
Der geht nämlich denkbar einfach: Man liest die CSV ein, geht durch jede Zeile und legt die OU mit dem Namen und dem Parent an.
1 2 3 4 5 |
$ous = Import-Csv -Path "C:\Import\ad_ou_export.csv" -Delimiter ";" -Encoding UTF8 foreach($ou in $ous){ New-ADOrganizationalUnit -Name $ou.name -Path $ou.parent -ProtectedFromAccidentalDeletion $False } |
Natürlich sind es noch die Original-Namen aus der Quelldomäne in der CSV. Sollte die Zieldomäne anders heißen, könnt ihr die CSV einfach mit einem Editor eurer Wahl öffnen. Weiter via Suchen & Ersetzen die entsprechenden Teile ändern (in meinem Beispiel wäre das “net” und “demofa”).
Das komplette Skript
Hier noch das Export-Skript in seiner Gänze:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
function get-ous-recursive($distinguishedName){ $ous = Get-ADOrganizationalUnit -filter * -SearchBase $distinguishedName -SearchScope OneLevel | Select-Object Name,DistinguishedName foreach($ou in $ous) { format-and-add-to-csv -ou $ou } foreach($ou in $ous) { get-ous-recursive $ou.DistinguishedName } } function format-and-add-to-csv($ou){ $parentNameList = New-Object System.Collections.ArrayList $parentNameList.AddRange($ou.DistinguishedName.Split(',')) $parentNameList.RemoveAt(0) $parentName = $($parentNameList -join ",") $csvou = New-Object PSObject -Property @{ Name = $ou.name Parent = $parentName } $csvous.Add($csvou) } $csvous = New-Object System.Collections.ArrayList $base = "OU=Corp,DC=demofa,DC=net" $baseou = Get-ADOrganizationalUnit -filter * -SearchBase $base -SearchScope Base | Select-Object Name,DistinguishedName format-and-add-to-csv -ou $baseou get-ous-recursive -distinguishedName $base $path = "C:\Export\ad_ou_export.csv" $csvous | Export-Csv -Delimiter ";" -Path $path -NoTypeInformation -Encoding UTF8 |
Viel mehr steckt nicht dahinter, so einfach exportiert ihr ganze Strukturen aus eurem AD.
Leave a Reply
<p>Danke für Ihre Anregungen, Fragen und Hinweise.<br/>Infos zum <a href="https://www.active-directory-faq.dekontakt/">Datenschutz</a></p>