Get-USNChanges
Get-USNChanges ist der kleine Partner von GET-ADChanges und ermittelt geänderte Objekte anhand der USN, also der "unique Sequence Number", die im Active Directory pro Domaincontroller verwaltet und mit jeder Änderung hochgezählt wird. Im Gegensatz zu GET-ADChanges kann daher Get-USNChanges nur erkennen, dass sich ein Objekt verändert hat, aber nicht welche Feld betroffen war. Es ist also etwas allgemeiner.
Beachten Sie dazu auch die generelle Seite zu AD Change Detection
Hintergrundwissen
Durch den Verzicht auf die DirSync-API reichen aber z.B. "Lese-Rechte" aus das Active Directory und die relevanten Objekte. Das Recht hat eigentlich jeder Domänenbenutzer. Das gleiche Verfahren zur Erkennen von Änderungen nutzt z.B. auch der Exchange 2000/2003 RUS oder der Active Directory Connector, um Änderungen an Objekten zu erkennen und zu verarbeiten. Auch der Lync "User Replicator", verschiedene Spamfilter und Faxserver nutzen die USNs, um Änderungen an der Quelle nach zu verfolgen. Besondere Rücksicht muss man aber beim Löschen von Objekten an den Tag legen. Diese "erkennt" man nur, wenn Sie noch innerhalb der Tombstone-Zeit ab und an auch die gelöschten Objekte getrennt abfragen. Da USNs pro DC gültig sind, müssen Sie auch immer den gleichen DC als Quelle nutzen. Ist der DC down, dann sollten Sie warten. Bei einem Wechsel auf einen anderen DC sollten Sie bei USN=0 wieder starten. Ein Script sollte daher immer den gleichen DC nutzen, da die USNs für den Server gelten. Dabei sind die LDAP-Partitionen egal. Sie können also sogar einen GC derart überwachen, dann allerdings nur die Änderungen der Felder, die auch im GC ankommen.
Aktion | Ergebnis | Beschreibung |
---|---|---|
Object CREATE |
|
Neue USN
wird angelegt |
Object RENAME (DN Änderung) |
|
usnChanged wird erhöht |
Object DELETE |
|
nicht sichtbar. das Objekt "verschwindet" und wird im Dumpster nicht gefunden. |
Property ADD |
|
usnChanged wird erhöht |
Property CHANGE |
|
usnChanged wird erhöht |
Property DEL |
|
usnChanged wird erhöht |
Linked Property CHANGE |
|
Wird z.B. ein Benutzer in eine Gruppe aufgenommen, dann ändert sich an der Gruppe das Feld "Member" und wird durch eine USN-Änderung detektiert. Das Feld "MemberOf" beim Benutzer hingegen ist ein Linked Attribute und ist zwar geändert aber wird nur errechnet. Beim Benutzer ändert sich also keine USN. |
Es gibt also nur ganz wenige Dinge, die man per USN nicht erkennen kann. Die größte Einschränkung ist natürlich, dass man nur erkennen kann, dass sich ein Objekt aber nicht welches Feld sich geändert hat. Die USN ist übrigens pro Domain Controller eigenständig, d.h. jeder DC zählt "seine" USN-Kette hoch. Das gleiche gilt auch für den Zeitstempel, wann ein Objekt das letzte Mal geändert wurde.
(Get-ADForest).globalcatalogs ` | %{` $_;Get-ADObject ` -Server "$($_):3268" ` -LDAPFilter "(samaccountname=fc)" ` -Properties whenchanged,usnchanged } ` | ft usnchanged,whenchanged Usnchanged whenchanged ---------- ----------- DC1.msxfaq.net 39061482 10/10/2016 11:46:26 AM DC2.msxfaq.net 45411805 10/10/2016 11:46:22 AM DC3.msxfaq.net 47315602 10/10/2016 11:45:04 AM DC4.msxfaq.net 42164718 10/10/2016 11:45:01 AM
Sowohl die USN als auch das WhenChanged-Datum ist auf den verschiedenen Servern unabhängig. Anstatt von einem DC sich die letzte höchste USN zu merken könnte man auch über WhenChanged filtern. Bei einem Wechsel des DCs sollten sie aber immer wieder bei 0 beginnen, um kein Element zu übersehen. Der Zugriff über "WhenChanged" mit einem Sicherheitsabstand funktioniert nur, wenn sie sicher sein, das die AD-Replikation nicht doch länger gebraucht hat.
USN, MultiDomain und GC
In einer Umgebung mit mehreren Domain hat ebenfalls jeder GC seinen eigenen USNChanged-Counter für die Objekte in seiner Partition. Auch hier müssen Sie sich den letzten USN-Wert merken, wenn Sie wieder aufsetzen wollen und bei einer Änderung wieder am Start anfangen. Bei mehreren Domain müssen sie auch beachten, dass nicht alle DCs dann die Objekte finden. Hier eine Testserie mit unterschiedlichen Servern und Ports:
Get-ADUser ` -LDAPFilter "(samaccountname=fc)" ` -Server "$($server):$($port)" ` -Properties usnchanged,whenchanged
Das Konto lag in der SUB-Domain.
Server | Port | usnchanged | whenchanged |
---|---|---|---|
subdc.sub.msxfaq.net |
3268 |
1106997945 |
10.03.2025 09:38:17 |
subdc.sub.msxfaq.net |
389 |
1106997945 |
10.03.2025 09:38:17 |
roordc.msxfaq.net |
3268 |
870742343 |
10.03.2025 09:39:47 |
roordc.msxfaq.net |
389 |
not found |
notfound |
Sie können erkennen, dass der DC in der Subdomain sowohl bei der Abfrage über den LDAP-Port als auch GC die gleiche Informationen liefert. Die Abfrage gegen einen DC in einer andere Domain liefert über den LDAP-Port natürlich keinen Treffer aber über den Global Catalog wird das Objekt gefunden. Allerdings mit einer anderen USN.
Dennoch sollten sie nicht über den GC suchen, selbst wenn Sie mit der Teilmenge der Felder zufrieden wären und sich danach mit dem FQDN des Objekts verbinden. Besser ist es pro Domain eine eigene Abfrage zu nutzen.
Als Beispiel können Sie das Feld "EmployeeID" und nehmen, welches normalerweise nicht im GC enthalten ist
Ich habe das Feld auf einem "SubDC" geändert und nach Abschluss der Replikation auf den verschiedenen Servern abgefragt
Server | Port | EmployeeID | usnchanged | whenchanged |
---|---|---|---|---|
subdc.sub.msxfaq.net |
3268 |
nicht sichtbar! |
geändert |
geändert |
subdc.sub.msxfaq.net |
389 |
geändert |
geändert |
geändert |
roordc.msxfaq.net |
3268 |
nicht sichtbar |
keine Änderung des USN |
keine Änderung des USN |
roordc.msxfaq.net |
389 |
Objekt nicht gefunden |
Objekt nicht gefunden |
Objekt nicht gefunden |
Da sich der GC und die Domain die gleiche Datenbank teilen, ist auch die USN in der Rückgabe immer identisch. Ein Objekt einer Domain ist auf einem anderen DC einer anderen Domain natürlich nicht per LDAP:389/636 auffindbar. Sehr wohl aber über den GC:3268. Allerdings ändert sich dort die USN nur, wenn sie an dem Objekt ein Feld ändert, welches auch in den GC übertragen wird. Eine Änderung von "EmployeeID" am Objekt wird nicht zu einem GC in anderen Domains repliziert und damit ändert sich dort die USN auch nicht
Für Get-USNChange bedeutet dies, dass Sie für eine vollständige Liste immer einen DC der Heimatdomain fragen müssen. Wenn Sie einen GC fragen, dann erhalten Sie zwar alle Objekte aber sehen nur Änderungen für Felder, die auch im GC vorhanden sind.
Es kann durchaus interessant sein, auf das Feld "WhenChanged" zu gehen, um bei einem Wechsel eines DCs z.B. einen neuen USNChanged-Wert zu ermitteln, mit dem man dann relativ sicher wieder aufsetzen kann. Denken Sie aber daran, dass auch das "WhenChanged"-Feld nicht auf allen DCs und GCs gleich ist, sondern ebenfalls individuell verwaltet wird.
- Finding the Global Catalog Servers in a
Forest
https://technet.microsoft.com/de-de/library/dd378935(v=ws.10).aspx
Funktion und Einsatz
Trotzdem ist "Get-USNChanges" kein Skript zweiter Wahl. Es ist durchaus interessant für den Einsatz in automatischen Prozessen und zur Fehlersuche. Es ermittelt die geänderten Objekte und sendet diese über die Pipeline nach nachfolgende Prozesse. Beispielhafte Anwendungen sind z.B. Exports von Einstellungen nach einer Änderung. Wer z.B. Gruppen anlegt oder ändert kann dies über die USN-Änderung erkennen und entsprechend ausgeben. Wer sich daher vorher das fragliche Objekt gespeichert hat, kann sogar die Werte vergleichen. Wer z.B. Änderungen an kritischen Gruppen (z.B. Domänen Administratoren) nachverfolgen will, ist mit Get-USNChanges schon sehr gut unterwegs. Er muss quasi nur noch ein paar Zeilen addieren und das Skript über den Taskplaner regelmäßig starten. Doch dazu später mehr.
Get-USNChanges im Einsatz
https://youtu.be/VTp9oX5n0fE
Aufruf
Das Skript selbst benötigt keine weiteren Eingaben oder Voraussetzungen und einfach nur eine PowerShell auf einem PC, welcher Mitglied eines Active Directory ist. Im Gegensatz zu GET-ADChanges sind auch keine privilegierte Berechtigungen erforderlich Beispielhafte Aufrufe sind:
# Aufruf ohne Paramter überwacht Default Domain alle 3 Sekunden mit Ausgabe auf Bildschirm und CSV get-usnchanges.ps1 # Überwachung der Konfigurationpartition in eigenes Log get-usnchanges.ps1 -basedn "cn=configuration,dc=msxfaq,dc=local" -csvfilename ".\config.csv" # Sinnloser Aufruf. Once ohne LastUSN als Default startet und beendet sich get-usnchanges.ps1 -once
Alle Änderungen werden so erst mal auf den Bildschirm geschrieben:
Die meisten Leser werden Get-USNChanges als Diagnosewerkzeug einsetzen und daher das CSV-Protokoll und die Bildschirmausgabe nutzen. Sie können das Skript aber auch auf zwei Arten leistungsfähiger nutzen:
- get-usnchanges.ps1 |
process-changes.ps1
Sie schreiben sich ein eigenes Programm, welche die Ausgaben von Get-USNChanges als Eingaben einliest und nutzt. Das entspricht dem klassischen Pipelining in PowerShell ist ist für schnelle Lösungen interessant. - Funktion in eigenem Skript.
Daher können Sie natürlich auch einfach in ihrem Skript auf die Funktion von Get-USNChanges zurück greifen und diese im Skript als Routine einbinden oder aufrufen und verarbeiten. Interessant ist dies dann, wenn Sie Get-USNChanges mit "-once" und LastUSN, da Sie so mit jedem Aufruf die Änderungen erhalten und Verarbeiten können. im Fehlerfall können Sie dann leistungsfähiger darauf reagieren, z.B. die Anfrage mit der vorherigen LastUSN einfach noch mal ablaufen zu lassen.
Die Parameterdefaults sind so gewählt, dass Get-USNChanges einfach nur die aktuelle Anmeldedomäne überwacht und alle Änderungen seit dem Start des Programms auf den Bildschirm ausgegeben werden. Frühere Änderungen werden übersprungen.
Parameter
Die verschiedenen Optionen des Aufrufs von Get-USNChanges werden deutlich, wenn Sie sich die Parameter und deren Funktion anschauen. Die Parameter bedeuten im Einzelnen:
Typ | Parameter | Default | Bedeutung |
---|---|---|---|
[string] |
$lastusn |
"-1" |
USN, bei der angefangen werden soll
zu suchen. Ein Wert von -1 ignoriert
alle bisherigen Änderungen und fängt
nach der letzten Änderung an. |
[string] |
$domaincontroller |
localhost |
Name des DCs, welcher genutzt wird. Es muss sich aktuell dabei auch um einen GC handeln und wenn Sie mit LastUSN arbeiten, muss es immer der gleiche DC sein. |
[string] |
$ldappath |
GC://localhost |
Optionaler LDAP-Pfad. Wenn, dann
bitte komplett mit DC angeben, z.B.: |
[string] |
$usnfilename |
$null |
Dateipfad und Name zum Abspeichern und laden der USN, z.B. wenn mit "-once" das Skript immer nur einmalig gestartet wird oder auch nach einem Reboot des PCs wieder an der alten Stelle aufgesetzt werden soll. |
[string] |
$csvfilename |
$null |
Optionale Angabe einer CSV-Datei, in welcher die geänderten Objekte protokolliert werden. |
[int] |
$sleeptime |
3 Sek |
Immer wenn das Skript eine Suche abgeschlossen und die Elemente ausgegeben hat, legt es eine "Pause" ein. Kürzere Pausen belasten das System mehr aber sie können schneller reagieren. Bedenken Sie aber, dass auch die DCs sich untereinander nicht "realtime" abgleichen. |
[switch] |
$once |
$false |
Wird der Schalter "-once" gesetzt, dann beendet sich das Skript nach einem Durchlauf. Beachten Sie, dass dies nur in Verbindung mit einem Cookie-File Sinn macht. Ansonsten gibt es keine Änderungen zu melden |
[switch] |
$noscreen |
$false |
Deaktiviert die zusätzliche Ausgabe auf den Bildschirm der gefundenen Änderungen . Sinnvoll, wenn die normale Ausgabe in die Pipeline nicht mit "| out-null" unterdrückt oder mit einem anderen Prozess weiter verarbeitet wird. |
[switch] |
$verbose |
$false |
Durch die Angabe von "-verbose" werden detailliertere Ausgaben während der Verarbeitung gemacht, die bei eier Fehlersuche helfen können. |
Da PowerShell-Skripte nicht wirklich "verschlüsselt" sind, können Sie entsprechende Änderungen leicht selbst vornehmen.
Ausgaben
Die Bildschirmausgaben sind natürlich nur eine Funktion der PowerShell, welche die Pipeline am Ende auf die Konsole schreibt. Eine Weiterverarbeitung ist natürlich sehr einfach möglich.
... in die Pipeline
Das übergebene Objekte hat folgende Eigenschaften:
Property | Typ | Beispiel | Bedeutung |
---|---|---|---|
Timestamp | DateTime |
Donnerstag, 16. Juni 2011 05:45:34 |
Zeitstempel, wann die Aktion erkannt wurde. Dies ist nicht identisch mit dem Zeitpunkt der Änderung. Diese kann auf einem anderen DC schon früher erfolgt sein und durch AD-Replikation verzögert sein. |
usn | String |
32122412 |
Die aktuelle "USNChanged" des Objekts |
class | string |
User |
Objektklasse des geänderten Objekts |
lastmodified | DateTIME |
Donnerstag, 16. Juni 2011 05:43:34 |
Aktueller Inhalt von "LastModified" des Objekts. Beschreibt aber nur die Änderung des Objekts auf diesem DC. |
dn | String |
cn=User1 |
DistinguishedName des Objekts |
Die Ausgaben sind "Objekte", d.h. per Pipeline können Sie die Ausgaben auch weiter verarbeiten. Das einfachste ist natürlich die Ausgabe in einer CSV-Datei
get-usnchanges.ps1 | export-csv .\aenderungen.csv
... CSV-Datei
Get-USNChanges schreibt aber zusätzlich die Änderungen auch in eine Datei ".changes.csv", sofern diese angegeben wird. Der Inhalt entspricht der Ausgabe in die Pipeline. Der Inhalt einer solchen Datei ist entsprechend überschaubar:
Diese Datei ist aber wirklich eher wie ein IISLog als Protokoll zu sehen und kann natürlich mit einer Volltextsuche o.ä. bearbeitet werden. für eine zeitnahe Ausführung von Aktionen sollte jedoch besser die Pipeline-Ausgabe ausgewertet werden. Aufgrund der begrenzen AusgabeMöglichkeiten enthält die Spalte "Value" nur als Text darstellbaren Daten, d.h. String, numerische Werte. Arrays und andere komplexe Konstruktionen werden nicht ausgegeben.
Erweiterte Nutzung
Interessant wird der Einsatz natürlich, wenn man die letzte USN mit angibt oder die Funktion nutzt, die USN speichern zu lassen und dann immer wieder dort aufsetzt. Das funktioniert sehr gut für "AdHoc-Skripte", die über die Pipeline arbeiten.
Ein alternativer Weg ist, dass Sie das Skript aus ihrem Skript aufrufen und selbst anhand der durch die Pipeline erhaltenen Objekte die höchste USN ermitteln und sich selbst wegspeichern. Wenn Sie dann das Skript regelmäßig mit "once" aufrufen und die vormals letzte erhaltene USN wieder als Parameter angeben, haben Sie die volle Kontrolle.
Get-USNChanges ist "ReadOnly", d.h. es reichen "Lese-Rechte" als Domänenbenutzer aus. Erst wenn Sie die Ergebnisse natürlich nutzen, um ihrerseits Aktionen anzustoßen, muss das Skript entsprechende Berechtigungen vorweisen.
Einschränkungen
- Ein DC als Ziel
Um USNs nutzen zu können, muss immer der gleiche DC verwendet werden. Der Wechsel eines DC kann dazu führen, dass frühere Änderungen erneut gemeldet oder übersehen werden. Ist ein Wechsel des DCs erforderlich, dann sollten Sie mit der USN =0 wieder starten. Die gleiche Technik nutzte der Exchange RUS - GC:
Aktuell bindet sich Get-USNChanges gegen "GC://" auf Localhost bzw. den angegeben Domaincontroller. Es ist möglich, auch einen normalen DC zu verwenden. - "Lese-Rechte"
Eine LDAP-Suche mit einer USN als Kriterium liefert eine ganze Menge von Objekten. Allerdings beachtet dabei das Active Directory auch die Berechtigungen. Die Funktion ist nur dann sicher, wenn der ausführende Benutzer die Objekte auch lesen kann., Zumindest das Feld "USNChanged". Kann dieses Feld nicht gelesen werden, dann wird das Objekt dennoch gemeldet. Nur kann das Skript die USNs nicht weiter hochzählen. Das Problem tritt aber nur auf, wenn das letzte Elemente nicht lesbar ist. - Kein Wer und Wo und Wann
Sie können nicht sehen, welcher Benutzer oder Prozess das Feld geändert hat. Auch sehen Sie die Änderung erst, wenn sie auf dem DC angekommen ist, den Sie abfragen. Wer genauere Informationen braucht, muss auf den Domain Controllern eine Zusatzsoftware installiere oder die Überwachung aktivieren (-> Auditing) - Letzte Änderung gewinnt
Wird ein Feld mehrfach geändert, dann erhält man nur die letzte Änderung. Das ist kritisch, wenn Sie z.B. die Mitglieder der Domänen Administratoren überwachen wollen und jemand sich zwischen zwei Abfragen kurz addiert, anmeldet und wieder entfernt. Dazu ist diese API nicht gedacht (-> Auditing) - Gelöschte Objekte
Leider liefert die normale LDAP-Abfrage keine gelöschten Objekte mit, d.h. wenn ein Objekt entfernt wird, dann verschwindet es einfach. Microsoft schreibt auf Polling für Changes using USNChanged (http://msdn.microsoft.com/en-us/library/ms677627.aspx), dass Sie regelmäßig separat nach gelöschten Elementen suchen wollten.
Zudem gibt es die Einschränkungen, dass z.B. nur direkte Änderungen erkannt werden. Wir ein Benutzer also in eine Gruppe aufgenommen, dann wird nur eine Änderung von "Member" an der Gruppe erkannt. Beim Benutzer ändert sich das Feld "MemberOf" nicht. Eine Aufzählung aller Besonderheiten würde aber den Rahmen dieses Artikels sprengen.
Download
Das Skript nutzt nur die in PowerShell 2.0 vorhandenen Bordmittel. Wenn Sie aber als Weiterverarbeitung zusätzliche Befehle ausführen wollen, dann müssen Sie eventuell die erforderlichen Snapins erst nachladen
Das Skript arbeitet von Hause aus "ReadOnly"
USN-Changes als PRTG Monitor
Die Anzahl der Änderungen über einen zeitlichen Verlauf kann man auch als Counter für die Active -Bewegung nutzen. Die Abfrage der USNs habe ich auch als Counter für PRTG gebaut.
Weitere Links
-
AD Change Detection
So können Sie Änderungen an AD-Objekten überwachen - DirSync-API Änderungen von Active Directory Inhalten per Software ermitteln
- GET-ADChanges Änderungen in AD-Feldern verfolgen, protokollieren und darauf reagieren
-
Exchange 2007 RUS
Nachbildung einer RUS-Funktion als PowerShell Skript für Exchange 2007, nutzt allerdings USNs - PowerShell Beispiele
- .NET für Administratoren
- RUSMon
- Overview of Change Tracking Techniques
http://msdn.microsoft.com/en-us/library/ms677625(VS.85).aspx - Polling für Changes using USNChanged
http://msdn.microsoft.com/en-us/library/ms677627.aspx - Retrieving Deleted Objects
http://msdn.microsoft.com/en-us/library/ms677927.aspx - Change Notifications in Active Directory
Domain Services
http://msdn.microsoft.com/en-us/library/aa772153(VS.85).aspx - Active Directory - Tracking Changes
http://msdn.microsoft.com/en-us/library/ms677974%28VS.85%29.aspx - Keeping Track of Changes That Have Occurred Over a
Period of Time
http://technet.microsoft.com/en-us/library/cc811562(WS.10).aspx
Mit REPADMIN Änderungen verfolgen - Updating the Lync 2010 Address Book
http://blog.schertz.name/2010/09/updating-the-lync-2010-address-book/ - NetWrix Active Directory Change Reporter
http://www.netwrix.com/active_directory_change_reporting_freeware.html - Monitor Active Directory Group Membership changes
http://www.lazywinadmin.com/p/monitor-active-directory-group.html - ActiveDirectoryFever: Functions/Get-ADDirSyncChange.ps1
https://www.powershellgallery.com/packages/ActiveDirectoryFever/1.0.0/Content/Functions%5CGet-ADDirSyncChange.ps1