Es gibt eine Menge Tools da draußen, die diese Aufgabe erledigen. Aber: sobald auch nur ein Hauch an Flexibilität gefordert wird (z.B. ein Exclude-Filter auf die zu synchronisierenden Objekte -> keine Mailboxen die im ExtensionAttribute9 den Wert "VIP" stehen haben) wird die Auswahl an zumindest kostenlosen Lösungen dünn.
Andere wiederum erwarten vom "einfachen" Consultant oder Admin dass er eine nicht ganz triviale Erweiterung schreibt. Der eingebaute GalSync von FIM (Forefront Identity Manager) z.B. schreibt einem vor, wie der Remote PowerShell Connect in die fremde Org abzulaufen hat. Hier hat man keinen Einfluss auf Authentifizierungsmechanismen (Kerberos ist Pflicht) oder auf andere Optionen, wie "Ignore CRL-Checking". Das erschwert den Verbindungsaufbau durch eine Legion an Firewalls und anderen Gemeinheiten. Dabei geht das Ganze in den meisten Fällen eh nicht durchs Internet, sondern wird irgendwo auf der Strecke durch ein VPN geroutet und bringt somit schonmal ein schönes Maß an Sicherheit mit.
Also, hab ich mir gedacht - warum sich mit den Tools anderer rumschlagen, wenn man sowas auch relativ einfach selbst bauen kann und damit ein Maximum an Flexibilität gewinnt. Gesagt, getan - hier ist psGalSync:
psGalSync ist ein PowerShell script das ein Active Directory nach einem anzugebenden LDAP Filter durchforstet und die gefundenen Mail User und Mailboxen mit denen aus einer bestimmten OU im fremden Forest vergleicht und die Unterschiede entsprechend anpasst.
Das ganze geht immer nur in eine Richtung. D.h. wenn Unternehmen A seine Mailboxen zu Unternehmen B synced ist das eine Richtung. Will man auch von Unternehmen B zu Unternehmen A syncen, muss man eine zweite Instanz von psGalSync auf der Seite von Unternehmen B etablieren.
Für das Provisionieren wird lediglich remote PowerShell verwendet - also kommt man mit Port 443 bzw. 80 (falls man das wirklich will) aus. Welche Möglichkeiten es gibt Remote PowerShell Verbindungen aufzubauen steht u.a. hier.
psGalSync nimmt folgende command line Attribute:
Cmd Attribut
|
Kurz
|
Kommentar
|
ExportSource
|
ES
|
Es wird nur eine Export des lokalen ADs in ein Textfile gemacht. (In Abhängigkeit zum LDAP filter).
|
ExportTarget
|
ET
|
Es wird ein Export des Ziel ADs in ein Textfile gemacht (von der angegebenen OU)
|
ExportOnly
|
EO
|
Macht beide der eben beschriebenen Schritte
|
ProvisioningOnly
|
PO
|
Erwaret “outputsource.txt” und “outputtarget.txt”
im root Folder. Provisioning wird in der remote Org durchgeführt.
|
FullRun
|
FR
|
Es werden alle drei bisher erwähnten Schritte durchgeführt.
|
ManualSync
|
MS
|
Hier werden keine Exports gefahren. Es wird lediglich ein angegebener User gesynced. (dessen SamAccountName muss angegeben werden):
psGalSync ms samAccountName
|
Abb 1: Command Line Attribute
Exportieren von der Quelle (z.B.: psGalSync ES)
psGalSync exportiert aus dem lokalen AD mit der adsisearcher Funktion (darauf hat mich erst kürzlich Frank aufmerksam gemacht). Der LDAP Filter hierzu kann nach Belieben verändert werden. Die entsprechenden User müssen eine Email Adresse haben.
Die User werden in ein File exportiert, das "outputsource.txt" heißt. Darin befinden sich alle relevanten Informationen zum jeweiligen User - semikolon-getrennt:
objectGUID,
Mail(WindowEmailAddress), Name, Givenname ,sn (Lastname), initials, displayname,
title, mobile, facsimile (Fax), phone, homephone, streetaddress, l (City),
postalcode, co (Country), st (StateOrRegion), Company, department
Wie man sehen kann, wird "proxyAddresses" nicht gesynced. Meiner Meinung nach sollte das Mail Attribute in den meisten Fällen genügen.
Hier ein Beispiel aus "outputsource.txt":
87-6E-3D-BF-6D-59-5C-42-A7-A4-E8-CD-A7-88-B3-C8,Testuser1@company.com;
Testuser1;Test;;;User1;;;Heidelberg;;;;;;;;
Wie man sehen kann sind hier nur ein paar Attribute gefüllt, andere sind leer.
Primary Key
Die Mailbox Guid wird hier sozusagen als "Primary Key" verwendet. Diese wird auf dem Kontakt auf der Gegenseite ins "Notes" Feld geschrieben, damit dieser der entsprechenden Mailbox auf der Source zugeordnet werden kann (alle anderen Properties inkl. der Email Adresse können sich ja theoretisch ändern).
Exportieren aus dem Ziel (z.B.: psGalSync ET)
Der Export aus dem Ziel erfolgt über das Cmdlet "get-contact" Alle Attribute, aller Kontakte werden in das File "outputtarget.txt" geschrieben.
Provisionierung (z.B.: psGalSync po oder psGalSync fr)
Nachdem sowohl das Source File als auch das Target File exportiert wurden können wir mit dem Provisioning beginnen. Zuerst werden hierbei beide Files in ein Dictionary geladen um besser verglichen werden zu können. Danach foreach-en wir durch das Source Dictionary und überprüfen ob die jeweilige objectGuid auch im Target File existiert.
- Wenn sie existiert werden die beiden Zeilen (aus dem Source- und aus dem Target File) verglichen. Wenn die gleich sind, ist alles gut - keine weitere Action. Wenn sie sich unterscheiden, wird ein Set-Contact im Remote Forest durchgeführt, um den Kontakt auf den aktuellen Stand zu bringen.
- Wenn die Zeile aus dem Source File im Remote File nicht gefunden wird, wird ein "new-MailContact" ausgeführt und der Contact damit angelegt.
- Das gleiche gilt, wenn die Zeile nur im Remote File zu finden ist und nicht mehr im Source File - dann wird eben eine Löschung des Kontakts angestoßen.
R I S I K O
Wenn - aus irgendeinem Grund - das Source File leer wäre, oder nur einige der User darin gelistet wären (z.b. wenn der Export irgendwie unterbrochen würde) und das Target File voll gefüllt wäre, würde das Script annehmen die fehlenden User existierten nicht mehr und würde die Kontakte der fehlenden User im Remote Forest löschen.
Um dieses Risiko etwas abzumildern, kennt das Script zwei "Versicherungs-Variablen":
- $maxSimDeleteCount
- Diese Variable gibt an, wieviel Kontakte auf einmal gelöscht werden dürfen. ABER: angenommen der Wert ist auf 100 gesetzt, bedeutet das, dass bei jedem Run des Scripts 100 Kontakte gelöscht werden dürfen. Also, immer schön die Logfiles lesen!
- $expectdSourceOutputLength
- Einen zweiten Weichmacher stellt diese Variable dar. Man weiß ja ungefähr wie viele Mai Objekte bei einem Export aus dem lokalen AD zu erwarten sind. Die entsprechende Zahl minus einen Schwellenwert schreibt man in diese Variable. Wenn man also z.B. 13.000 Objekte hat kann man 11.500 reinschreiben - somit wird das Script nicht laufen, wenn im Source File weniger als 11.500 User gelistet sind.
Apropos Logfile lesen: Das Skript verschickt auch Mails mit den wichtigsten Informationen zum letzten Lauf. Ganz nett, kann den Blick ins Logfile aber trotzdem nicht ersetzen.
Was heißt hier eigentlich RISIKO? Was soll der ganze Aufwand? Sind die Kontakte auf der Gegenseite gelöscht, erstell ich sie einfach wieder! Bei diesem Denkansatz gibt es ein kleines Problem:
Wenn ein Kontakt gelöscht wird und muss wieder angelegt werden, so erhält er einen neuen legacyExchangeDN. Hier müssen wir mit den bekannten Reply-Problemen wegen dem Outlook Cache rechnen.
Aus diesem Grund schreibt psGalSync beim Löschen eines Kontakts auch dessen legacyExchangeDN ins Logfile. Im Notfall kann so eine entsprechende X500 Adresse angelegt werden.
Konfiguration des Scripts
Wenn das Script über ein Batch File gescheduled werden soll, muss man die Credentials für den Remote Connect irgendwo speichern. Dazu erzeugt man sich einen Secure String:
read-host
-assecurestring | convertfrom-securestring | out-file C:\securestring.txt
Am hierauf folgenden Prompt muss man das Passwort für den Account im Remote Forest eingeben. Dieses wird dann in verschlüsselter Form in der angegebenen Text Datei gespeichert und von psGalSync ausgelesen.
(Achtung: das Passwort wird gegen das Passwort des gerade angemeldeten Users verschlüsselt. Jeder der dieses kennt, kann auch das Passwort des Remote Forests "recovern").
Nun würde ich mit folgendem kleinen Script testen, ob eine Remote Verbindung überhaupt möglich ist:
$connectionURI
= "https://remoteURL/PowerShell"
$username="domain\serviceAccount"
$password
= cat C:\securestring.txt | convertto-securestring
$cred
= new-object -typename System.Management.Automation.PSCredential -argumentlist
$username, $password
$rs
= new-pssession -conf Microsoft.Exchange -conn $connectionURI -auth basic -cred
$cred
Import-PSSession
$rs
Wenn der Remote Powershell Connect erfolgreich durchgeführt werden kann, wird auch psGalSync funktionieren.
Die connectionURI, der UserNamen und die Lokation des Secure String Files müssen im Config-Bereich von psGalSync angepasst werden.
Wenn man den Parameter $debug=$true setzt, wird nur ein Logfile erzeugt, keine Kontakte werden erzeugt oder verändert.
Alle anderen Parameter sollten selbsterklärend sein, bzw erschließen sich aus den Beispielen im Code.
Log Files und Archiv Files
Das Script erzeugt im Root Verzeichnis einen Archive und einen Logs Ordner. Wie nicht anders zu erwarten, werden die Log Files im Logs Ordner abgelegt und die Outputsource.txt und Outputtarget.txt im Archive Ordner.
Schedulen
Möchte man das Ganze über den Taskscheduler (na, wie könnte man da jetzt sagen ... mir fällt nix ein also doch:) schedulen erzeugt man am Besten ein Batch file mit z.B. folgendem Inhalt:
powershell -command "d:\scripts\psGalSync.ps1 fr"
Performance + Erfahrung + Warnung
Ich habe psGalSync seit einigen Monaten im produktiven Einsatz. Es funktioniert sehr zuverlässig und ist auch recht schnell. Sind die Objekte erstmal initial in-sync, dauert es z.B. bei 90.000 Objekten < 2 Stunden bis alles durch ist.
Natürlich muss man das alles sehr gut testen bevor man es selbst in einer Produktivumgebung einsetzt. Jeder muss sich selbst von der Funktionstüchtigkeit überzeugen und handelt dann am Ende eigenverantwortlich.
In diesem Sinne: Viel Spass damit :-)
1 Kommentar:
Hi,
schon mal überlegt das ganze auf http://codeplex.com oder auf http://github.com zu veröffentlichen? Gerade bei so eine Script vielleicht ganz angebracht. Und wenn Verbesserungsvorschläge kommen, kann man die einfach einarbeiten? Ich habe in Kooperation mit Karsten und Thorsten das "SignInAs" Projekt auf Codeplex gehostet:
http://signinas.codeplex.com/
Nur als Anregung. Weiter so.
Kommentar veröffentlichen