Tools: Querybased Security Group

Alle Skripte sind Muster ohne jede Gewährleistung oder Funktionsgarantie. für Schäden bin ich nicht verantwortlich. Achten Sie auf Zeilenumbrüche bei der Übernahme.

VBScript und 64Bit !
Viele 32bit COM-Objekte lassen sich auf einem 64bit System nur instanziieren, wenn die 32bit Version von CSCRIPT/WSCRIPT genutzt wird, welcher unter C:\Windows\SysWOW64\cscript.exe liegt.

Diese Sicherheitsgruppen sind auch per OWA zu sehen. Dies ist mit Abfragebasierten Verteilern bis Exchange 2003 SP2 nicht der Fall.

Dieses Skript ist auch in Verbindung mit Office 365 interessant, da man damit lokal Gruppenmitgliedschaften quasi dynamisch pflegen kann, die dann aber dank DirSync in der Cloud aktualisiert werden und damit die dynamischen Verteilerlisten auch in der Cloud nachbilden.

Seit Windows 2003 und Exchange 2003 gibt es die Funktion der "Query based Distribution Groups" (QBDG Verteiler). Hierbei werden die  Mitgliedschaften einer Gruppe nicht fest durch einen Administrator gepflegt, sondern dynamisch anhand einer LDAP-Anfrage bei Bedarf ermittelt. Dies eignet sich wunderbar für Verteiler, die auf bestimmten Eigenschaften der Objekte im Active Directory basieren. Ein Verteiler mit allen Mitarbeitern, deren Postfach auf einem bestimmten Server, einer bestimmten Datenbank liegt, oder die in einem bestimmten Standort arbeiten ist nützlich um bevorstehende Betriebsunterbrechungen (Serverupdate, Leitungsunterbrechung) anzukündigen.

Leider funktioniert dies nur mit Exchange 2003 und Windows 2003 DCs und als Verteiler können diese Gruppen nicht zur Vergabe von Berechtigungen (z.B. auf Verzeichnisse, Dateien oder öffentliche Ordner) genutzt werden. Daher habe ich mir ein VBScript geschrieben, was genau dies auch mit Windows 2000 und Sicherheitsgruppen ermöglicht.

Download und Installation

Zuerst benötigen Sie das VBScript. Der Download legt eine TXT-Datei an, die Sie nach VBS umbenennen müssen.

querybasedsg.2.1.vbs.txt
Download und Erweiterung TXT entfernen.

In meinen TestUmgebungen und bei Kunden hat dieses Script bislang problemlos funktioniert. Trotzdem kann es sein, dass das Script unerwartet abbricht. Dies liegt oft an Sonderzeichen oder Inhalten im AD, die ich noch nicht abgefangen habe. Bitte setzen Sie dann das Debugging auf 6 und senden Sie mir die letzten Zeilen der Protokolldatei und die Zeilennummer des Fehlers des Scripting Hosts. -> Kontakt

Ehe Sie nun das VBS direkt aufrufen, sollten Sie die Parameter und Voraussetzungen können:

  • Parametrisierung
    Das Skript benötigt den Namen der Gruppe, die anzupassen ist und die LDAP-Abfrage, welche Objekte enthalten sein sollen. Ich habe das Skript derart vereinfacht, dass Sie wahlweise einfach das AD-Feld und einen Wert angeben oder eine eigene LDAP-Anfrage mit mehreren Bedingungen eintragen können. Per Default werden aber nur Objekte vom Typ "User" und "Person" ausgewählt. Wenn Sie andere Objekte ebenfalls berücksichtigen wollen, müssen Sie die entsprechenden Zeilen im Quelltext anpassen.
  • Gruppe muss da sein
    Das Skript legt keine Gruppe an. Die Sicherheitsgruppe bzw. der Verteiler muss bereits bestehen. Die bestehenden Mitglieder werden durch die neu ermittelte Liste ersetzt, d.h. jede manuelle Änderung wird beim nächsten Lauf wieder hinfällig.
  • Berechtigungen
    Der Benutzer, welcher das Skript startet, muss natürlich die Berechtigungen besitzen, die Mitgliedschaften der Gruppe zu verändern
  • Beschränkung auf eine Domäne
    Die Abfrage per LDAP nutzt nur die Default Domäne. Wenn ihr Active Directory aus mehreren Domänen besteht, wäre die Anpassung des Skripts erforderlich, um einen GC oder die verschiedenen DCs zu fragen.
  • Zeitplaner
    Das Skript sollte regelmäßig gestartet werden, da es keine Gruppenrichtlinie oder echte "Query Based DL" ist. Dazu eignet sich am besten der Microsoft Taskplaner.
  • Überwachung
    Das Skript schreibt ein Protokoll in einer Textdatei (c:\debug.log). Den Pfad können Sie im Skript anpassen. Enterprise Kunden werden das Skript sicher um Code erweitern, die den Ablauf im Eventlog protokollieren. Dann können Sie z.B. mit Programmen wie MOM2005 eben diese Eventlogs überwachen und beim Ausbleiben eines Events innerhalb einer Zeit auch alarmieren.
  • Gruppen in Gruppen
    Der Einsatz des Skripts ist nicht auf Exchange beschränkt. Durch die Verwendung einer Sicherheitsgruppe können auch Berechtigungen vergeben werden. Sie können auch öffentliche Ordner, andere Gruppen etc. zum Mitglied der Gruppe machen. Achten Sie dabei aber darauf, dass nicht alle Objekte in den Mitgliedschaften aufgeführt werden können. So kann eine universelle Gruppe nicht Mitglied einer lokalen Gruppe sein (Siehe auch Windows Gruppen). Dies wird nicht abgefangen und führt zu einem Fehler.

Da VBScript aber als Source-Code vorliegt ist es problemlos möglich, das Skript an eigene Bedürfnisse anzupassen.

Beispiele

Um eine bestehende Gruppe "Vertrieb" in der OU "Accounts" der Domäne "msxfaq.local" mit den Mitgliedern zu füllen, bei denen in der Abteilung das Wort "Vertrieb" steht, wäre dann folgender Aufruf geeignet:

cscript querybasedsg.2.0.vbs cn=Vertrieb,ou=Account,dc=msxfaq,dc=local Department Vertrieb

Wenn Sie mehrere Felder verwenden wollten, z.B. Vertrieb in den USA, dann wäre folgender Aufruf geeignet.

cscript querybasedsg.2.0.vbs cn=Vertrieb-USA,ou=Account,dc=msxfaq,dc=local "&(department=Vertrieb)(country=US)

Hier sind jede Menge weiterer Filter und Kriterien denkbar. Eventuell ist es besser, den Source Code auch zu erweitern.

Einschränkungen und Hinweise

Das Script hat einige Entwicklungsphasen durchlaufen, die ich nicht verbergen will.

Als Version 1.0 habe ich einen rekursiven Durchlauf durch die OUs einer Domäne genutzt und für jedes Objekt selbst geprüft, ob die Bedingung zutrifft. War dies der Fall, wurde das Objekt in die Gruppe hinzu gefügt, sofern es noch nicht enthalten war. War dies nicht der Fall, aber das Objekt war in der Gruppe, so wurde es entfernt. Damit wurden nur Änderungen einzelner Mitgliedschaften erforderlich, was bei Windows 2003 auch eine verminderte Replikationsbelastung bedeutet. Leider dauerte der Durchlauf aber dadurch sehr lange und die eigentlichen LDAP-Anfragen haben den DC stark belastet

Die vorliegende Version 2 nutzt daher ADO mit einer gefilterten LDAP-Anfrage. Der DC ermittelt die Mitgliedschaften und liefert als Recordset nur die Objekte aus, die in der Gruppe enthalten sein sollen. Dies geht sehr viel schneller und schont Ressourcen. Aus dieser Liste wird ein Array erstellt, was auf einen Schlag die bestehende Mitgliederliste ersetzt. Im Hinblick auf die Laufzeit ist dies sehr schnell, aber bedeutet, dass die DCs immer die komplette Liste der Mitglieder in der Folge replizieren müssen, auch wenn sich nichts geändert hat.

Daher ist es in der Zukunft denkbar, zwar per ADO die Liste der Mitglieder zu ermitteln, aber dann diese gegen die aktuelle Mitgliedsliste zu vergleichen und nur die erforderlichen Änderungen durchzuführen. Der Vorteil dieser Methode macht sich aber sowieso erst ab Windows 2003 bezahlt und auch dann dürfte die Replikation erst bei sehr hohen Anwenderzahlen und derart generierten Mitgliedschaften von Belang sein.

PowerShell-Version

Mit Exchange 2007 und höher bietet es sich natürlich an, die PowerShell zu nutzen. Es ist relativ einfach z.B. die OWA-Benutzer zu erhalten:

Get-CASMailbox | where {$_.owaenabled}

Mit der Liste der User könnte man dann einfach das "Member"-Attribut einer Gruppe füllen. Das folgende Beispielskript macht das per PowerShell für alle Benutzer, die für OWA aktiviert sind.

# Query Based Security Group
#
# (c) Net at Work  2011  frank.carius@netatwork.de
# V 1.0  20100118  Initial release

[string]$groupdn = "LDAP://cn=testgroup,ou=msxfaq,dc=e2010,dc=local"

Write-Host "Collecting Members"
$memberlist = (Get-CASMailbox | where {$_.owaenabled})

Write-Host "Binding Group $groupdn"
$group = [ADSI]$groupdn

Write-Host "Removing all members"
$group.member.Clear()

foreach ($member in $memberlist) {
	Write-Host "Adding DNs" $member.distinguishedname
	$group.member.add($member.distinguishedname)
}

Write-Host "Writing Group membership"
$group.setinfo()

Achtung
Diese "Einfachlösung" löscht erst alle Mitglieder und addiert diese danach wieder. Entsprechend viele "Änderungen " werden dadurch durchgeführt, die eine umfangreiche Replikation verursachen (was man auch an dem USN-Sprung sehen kann). Eine Version die Mitglieder addiert und entfernt reiche ich bei Gelegenheit nach.

Natürlich können Sie das Skript anpassen, indem Sie den "groupdn" ändern und die Generierung der "Memberlist" mit einem anderen Commandlet ausführen.

Weitere Links