CSV2Mailcontact

Auf der Seite MiniSync habe ich ein VBScript beschrieben, welches per LDAP die Postfächer ausliest und in einem anderen Forest als Kontakte anlegt. Lange Jahre hat das Skript gute Dienste getan aber je mehr Exchange 2007/2010 Server entstehen, desto weniger ist VBScript noch geeignet, denn diverse direkte LDAP-Modifikationen sind nicht mehr erlaubt. Dafür gibt es einen umfangreichen Satz von Commandlets. Da wurde es Zeit für eine PowerShell-Version.

Die erste Version liest aber nicht mehr direkte per LDAP eine Quelle aus, da auch Firmen mittlerweile verteilter und verbundener sind. Eine Firma könnte durch aus die Empfänger eines Zulieferers bei sich pflegen wollen oder Kunden aus ERP als Kontakte in Exchange nutzen wollen. Gerade mit der Trennung von Empfänger über Adressbook Polices kann dies durchaus interessant sein.

Grundfunktion

CSV2MailContact macht ziemlich genau das, was der Name suggeriert: Es liest eine CSV-Datei ein und pflegt mit den Daten die Kontakte in einer Ziel-OU.

Achtung: Das Skript ist keine "Lösung", sondern ein Baustein, der angepasst werden muss. Sie müssen auf jeden Fall die Zuordnung der Felder codieren. Zudem löscht das Skript in der ZielOU alle Objekte, die nicht in der CSV-Quelle enthalten sind.

Auch sind aktuell die Überwachungsfunktionen eher rudimentär, d.h. hier kann sicher noch einiges passieren. Aber Kontakte aus einer CSV-Datei werden im Active Directory als Mailcontacts angelegt und können in Exchange genutzt werden. Bei einem erneuten Lauf werden Felder auch aktualisiert. Und nach jedem Update werden die Objekte in der Ziel-OU, welche nicht durch den Import gekommen oder aktualisiert wurden, wieder entfernt. Um dies zu erreichen wird der DistinguishedName der verwalteten Zielobjekte im einer Hashtable gespeichert und am Ende wieder "abgehakt".

Einschränkungen

Die Grenzen dieses einfachen Skripte erkennen Sie am besten, wenn Sie die Einschränkungen und Problemfälle können.

  • Multi-Value und binäre Werte
    Der Schwerpunkt des Skripts liegt auf der Pflege von Kontakten im Ziel mit den entsprechenden "Textfeldern". Das Skript nimmt im moment keine Rücksicht auf Binäre Werte und selbst Arrays (z.B. mehrere Adressen) sind nicht besonders behandelt.
  • Keine SID, SIDHistory, Password
    Diese Werte können nicht beschrieben werden, was aber bei Kontakten sowieso nicht relevant ist. Aber wenn Sie das "new-Mailcontact" durch ein "New-MailUser" oder "New-Mailbox" ersetzen, fehlt immer noch sehr viel bis zu einem echten Verzeichnisabgleich
  • Keine Erkennen von Änderungen im Ziel (OneWay)
    Das Skript nimmt die Quelle als "Autoritativ" an und setzt die Werte im Ziel, Wurde in der Zwischenzeit im Ziel etwas geändert, werden diese Werte beim nächsten Lauf überschrieben. Eleganter weise erkennt das Active Directory selbst, dann ein Schreiben der gleichen Werte keine AD-Replikation auslöst. Aus Performanceaspekten lohnt es sich also nicht einen Vergleich der Bestandsdaten mit den neu zu schreibenden Daten zu machen. Aber Konflikte werden so auch nicht erkannt.
  • Keine Member von Gruppen
    Das Skript enthält keinen Code um Gruppen zu synchronisieren. Ein Verteiler in der Quelle kann natürlich zu einem Kontakt im Ziel werden, aber es wird im Ziel keine Gruppe mit aktuellen Mitgliedschaften gepflegt. Allerdings werden einmal angelegte Objekte nicht bei jedem Lauf neu gelöscht und wieder angelegt. Sie können also ein Kontaktobjekt in eine bestehende Verteilergruppe im Ziel aufnehmen und es bleibt dort auch drin, bis in der Quelle das Objekt nicht mehr vorhanden ist und es im Ziel dann "gelöscht" wird.
  • Keine Fremdobjekte in der OU
    Durch das Verhalten, am Ende alle "fremden" Objekte in der Ziel-OU zu löschen, verbietet es sich, diese OU auch für andere Objekte zu nutzen. Wer also mehrere Quellen nicht in einer CSV-Datei zusammenfassen kann, weil es unterschiedliche Felder gibt, sollte für jede "Partnerschaft" eine eigene Ziel-OU vorsehen
  • kein Metadirectory
    Das Skript ist nicht mal ansatzweise eine Lösung für ein Metadirectory.

Mit diesen Informationen sollten Sie also wirklich das Skript nur als "One-Way" Abgleich in Kontakte im Ziel in eine extra dafür bereit gestellte OU vorsehen.

Weiterentwicklung

Trotz dieser systembedingten Einschränkungen kann das Skript durchaus in Umgebungen auch als Lösung arbeiten. Dennoch möchte ich zukünftig die ein oder andere Verbesserung noch einbauen, wenn ich die Zeit dazu finde, z.B.

  • Import der Objekte von der Pipeline, also wenn "csvfile" = $null ist
    Für PowerShell ist es ja geradezu Konzept, die Daten nicht von einer Datei auszulesen, sondern direkt von der Pipeline einzulesen.
  • Prüfung der Exchange Commandlets auch nach dem Load der SnapIns
    Aktuell prüfe ich auf die Snapins um sie nachzuladen, wenn diese Fehlen.
  • Anzahl Vergleich und Stopp bei zu vielen Änderungen .
    Bei einem Abgleich kann es quasi Tödlich sein, wenn Daten nur Partiell übertragen werden. In der Regel "ändert" sich ja nicht sehr viel. Besonders beim Aufräumen am Ende ist eine doppelte Sicherung ratsam, d.h. abzubrechen, wenn z.B. zu viele Objekte gelöscht werden würden.
  • Logging und Error-Handling
    Aktuell beenden Fehler direkt das Skript. Besser stoppen als etwas kaputt machen. Mittelfristig wäre ein eleganterer umgang mit Fehlern wünschenswert, z.B. Konflikte zu melden und zu überspringen. Das natürlich am besten auch im Eventlog für eine zentrale Überwachung
  • Exchange und Lync-Commandlets nur optional
    Aktuell wird der Kontakt durch ein "New-Mailcontact" angelegt, was natürlich eine Abhängigkeit zu Exchange enthält

Download

Beachten Sie, dass das PowerShell-Skript ein Rahmen für eine weitere eigene Entwicklung ist. Sie müssen zumindest die Felder der CSV-Datei, welche Sie im Ziel übertragen wollen, auch im Skript codieren. Zudem ist es oft ratsam, auch bestimmte Felder zu errechnen, z.B.: den Firmenname im Displaynamen zu hinterlegen oder die Firma gleich vorzugeben.

csv2mailcontact.1.0.ps1

Weitere Links