Active Directory Country Codes bereinigen

Neulich auf dem Quest Migration Circle in Köln wies einer der anwesenden Partner (sorry mate, didn’t catch the name) darauf hin, dass in Active Directories die Attribute für das Land oft nicht konsistent gepflegt sind und da sonst was reingeschrieben wird, und z.B. das Azure AD Connect sich daran stört, wenn die Angaben dort nicht korrekt sind. Darauf folgte der Hinweis auf https://countrycode.org/ mit der Einschränkung, dass die Daten dort nicht ganz stimmen. Ich hatte die Zugfahrt von Köln nach Berlin dafür genutzt, mir das genauer anzuschauen.

Es geht um drei Attribute:

  • countryCode (Country-Code) – eine ganze Zahl, für Deutschland ist es z.B. 276 (es gab wohl auch die 278 für die DDR, das sollte aber nicht mehr verwendet werden). Dieses Attribut wird erst seit Server 2003 wirklich verwendet, obwohl es auch im 2000er Schema bereits vorhanden war.
  • c (Country-Name) – Zweistelliger alphabetischer Code für das Land (DE für Deutschland)
  • co (Text-Country) – Name ausgeschrieben in der Sprache des Admins, der den Eintrag gesetzt hat (falls es über ADUC gemacht wurde).

Alle drei werden in ADUC gleichzeitig (und konsistent) gesetzt, wenn man auf dem Reiter „Adresse“ eines Benutzer-Objektes unter „Land/Region“ etwas auswählt. Da es eine Dropdown-Liste ist, ist es nicht möglich, falsche Werte der Attribute zu setzen.

Es findet aber keine weitere Validierung statt, und alle drei Attribute sind, Berechtigungen vorausgesetzt, schreibbar. Daher kann man da beliebige Werte reinschreiben, die dem Typ entsprechen: countryCode ist eine ganze Zahl größer oder gleich 0, c ist zweistellig Unicode. Bei vielen slebstgestrickten Migrationen, und ich bin vermutlich auch niucht unschuldig, wird da irgendwas reingepumpt, was aus den Quellsystemen kommt, und countryCode wird gern auch leer gelassen. Nun haben wir plötzlich Situationen, wo sich jemand daran stört, und müssen das also bereinigen.

Microsoft selbst sagt in den Docs, dass die Attribute c und countryCode dem Standard ISO 3166 folgen. Die offizielle ISO-Tabelle kann man unter https://www.iso.org/obp/ui/#search/code/ sehen. Wir brauchen also „Numeric“ für countryCode, „Apha-2-Code“ für c und eine ausführliche Bezeichnung für co. Da im AD der lange Ländername in der sprache steht, die der setzende Administrator als GUI-Sprache in dem Moment eingestellt hatte, dürfte hier nach jedem Dafürhalten die genaue Schreibweise nicht so wichtig sein, da durch ISO 3166 ja nur Englisch und Französisch festgelegt werden.

Das Dropdown-Feld in ADUC hört übrigens ausschließlich auf c – sobald sich den Wert dort ändert, ändert sich auch die Anzeige, selbst wenn co und countryCode falsch sind. Ein weiteres interessantes Phänomen: der countryCode lässt sich nicht löschen – es lässt sich aber ein beliebiger Wert zuweisen, nicht unbedingt nur ein korrekter ISO 3166-Code, und neue Benutzer sind mit dem Wert 0 initialisiert. Beim Versuch, das Attribut zu löschen, bekommt man in ADUC, PowerShell und LDIFDE konsistent die Antwort „WILL_NOT_PERFORM“.

Die Bereinigungsmission ist also folgende:

  • Finde alle User-Objekte, wo eines der drei Attribute gesetzt ist
  • Prüfe, ob c und countryCode übereinstimmen. Falls nicht, prüfe, ob eines davon ungültig ist, und setze den Wert entsprechend dem jeweils anderen Attribut. Sind beide gültig, stimmen aber nicht überein, gib eine Warnung aus.
  • War eine Übereinstimmung zwischen c und countryCode vorhanden oder wurde eine hergestellt, setze co entsprechend der Tabelle, sonst lösche alle Einträge bzw. setze countryCode auf 0.

In PowerShell gegossen, könnte das so aussehen (ohne Paging für große Verzeichnisse, Fehlerbehandlung und Logging, das ist euer Job :-)):

$countries = Import-CSV "$PSScriptRoot\ISO3166.csv" -Delimiter ";" -Encoding UTF8
$users = Get-ADUser -LDAPFilter "(|(|(!(countryCode=0))(c=*))(co=*))" -Properties c,co,countryCode
foreach ($user in $users) {
    $c_valid = $false
    $cc_valid = $false
    if ($null -ne $user.c) {
        $c_country = $countries.Where({$_.Code -eq $user.c})
        if ($c_country.Count -gt 0) {
            $c_valid = $true
        }
    }
    if (0 -ne $user.countryCode) {
            $cc_country = $countries.Where({$_.Numeric -eq $user.countryCode})
            if ($cc_country.Count -gt 0) {
                $cc_valid = $true
            }
    }
    if ($c_valid -and $cc_valid) {
        $country = $countries.Where({($_.Numeric -eq $user.countryCode) -and ($_.Code -eq $user.c)})
        if ($country.Count -gt 0) {
            Set-ADUser -Identity $user.DistinguishedName -Replace @{co=$country.Name}
        } else {
            Write-Warning ("User {0}: c ({1}) and countryCode ({2}) are both set to valid values but belong to different countries!" -f $user.SamAccountName,$user.c,$user.countryCode)
       }
    } elseif ($c_valid) {
        # cc is invalid
        Set-ADUser -Identity $user.DistinguishedName -Replace @{countryCode=$c_country.Numeric;co=$c_country.Name}
    } elseif ($cc_valid) {
        # c is invalid
        Set-ADUser -Identity $user.DistinguishedName -Replace @{c=$cc_country.Code;co=$cc_country.Name}
    } else {
        # both c and cc are invalid, clearing all attributes...
        Set-ADUser -Identity $user.DistinguishedName -Replace @{countryCode=0} -Clear @("c","co")
    }
}

Das Skript könnt ihr hier fertig herunterladen: rectify_country.ps1. Es erwartet die ISO 3166-Definitionen als ISO3166.csv im gleichen Verzeichnis.

Ich habe noch nicht herausgefunden, wo Windows intern die Anzeigenamen und die jeweils gültige Code-Tabelle speichert. Wenn ich es gefunden habe, werde ich es hier updaten. Bisher aber muss man sich mit der Tabelle aus dem Internet begnügen und die Ländernamen selber „erfinden“. Die Tabelle per heute stelle ich hier zur Verfügung: ISO3166.csv Die langen Namen entsprechen dabei nicht 100% der Windows-Schreibweise, sondern wurden von mir zum Teil etwas eingekürzt. Je nachdem, wofür ihr das co-Attribut verwendet, müsst ihr die Tabelle ohnehin anpassen. Mögliche Szenarien, die mir sofort einfallen:

  • Namen in der gleichen Sprache (z.B. Sprache des HQ)
  • Namen in der jeweiligen Landessprache
  • Postalische Namen (<Französisch oder Englisch> / <Landessprache des Absenders>)

Happy Cleanup!

Ersten Kommentar schreiben

Antworten

Deine E-Mail-Adresse wird nicht veröffentlicht.


*


Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.