5 min read
Steigere deine IT Automations-Effizienz mit neuer ScriptRunner Version
Wir haben unser neuestes ScriptRunner-Update, Version 7.1, veröffentlicht. Dieses Update ist vollgepackt mit...
ScriptRunner Blog
Auditing ist keine eingebaute Funktion und die Nachverfolgung von Änderungen müssen manuell durchgeführt werden - wer mit PowerShell arbeitet, hat vielleicht schon überlegt, wie dieses Problem zu lösen ist. In diesem Artikel wird es darum gehen, einige Szenarien zu betrachten, in denen ein angemessenes Maß an Auditing mit verschiedenen Techniken durchgeführt wird, um dies zu bewältigen. Die angebotenen Lösungen sind nicht szenario-spezifisch, sondern werden an den jeweiligen Bedarf angepasst. Auditing (Überprüfung/Überwachung/Protokollierung) ist ein breiter Begriff für das, was in diesem Artikel gezeigt wird. Einfach ausgedrückt, exportiert der nachstehende Script-Code wichtige Informationen in Textdateien, also Logs, zur späteren Verwendung.
Bei der Erstellung dieser Textdateien können wir das Cmdlet Out-File verwenden, mit dem Informationen in Dateien abgelegt werden können. Wir können einfache CSV-Dateien erstellen, indem wir eine Kopfzeile und dann eine Zeile pro CSV-Ausgabe mit durch Komma getrennten Werten angeben. Nachstehend finden Sie ein Beispiel für eine CSV-Datei:
Erklärung zum Inhalt der Zeilen
Bevor wir eines der beiden Szenarien durchgehen, sollten wir grundlegende Log-Dateien für die Nachverfolgung und Prüfung erstellen. Zunächst müssen wir eine Basis für diese Berichtsdateien erstellen. Hierfür verwenden wir eine Variable ($BasePath), um den aktuellen Pfad zu speichern. Für Log-Dateien wird ein Ordner mit dem Namen "Reports" als Ziel für alle Protokolldateien verwendet.
$BasePath = (Get-Item -Path ".\" -Verbose).FullName
$Path = $BasePath+"\"+"Reports"
Bevor wir Dateien in diesem Ordner speichern, prüfen wir, ob der Ordner existiert. Falls er nicht existiert, erstellen wir ihn:
if(Test-Path $Path -ErrorAction SilentlyContinue){
Write-Host "'nLogging directory exists - $($Path)'n"
}
else{
New-Item -ItemType Directory -Path $Path -Force
}
Außerdem legen wir die Breite des Fensters der PowerShell-Sitzung fest, da dies die Protokollierung langer Zeilen erleichtert.
$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size (500, 9999)
Um den Überblick zu behalten, wann ein Ereignis eingetreten ist, verwenden wir eine Variable zum Speichern eines Einzeilers, der bei Bedarf aufgerufen werden kann:
$Date = { Get-Date -Format "MM.dd.yyyy-hh.mm" }
Zum Schluss legen wir die Namen unserer Log-Dateien fest:
$LogFileName = "ScriptExecutionLog.txt"
$LogDestination = $Path+"\"+$LogFileName
Jetzt kann es mit den Szenarien losgehen!
In unserem ersten Szenario handelt es sich um ein großes Unternehmen, das von einer lokalen Lösung zu Microsoft 365 migriert. Innerhalb der Umgebung gibt es eine grundlegende Active Directory-Konfiguration in Bezug auf Domänen und Forests - eins und eins - Forest- und Domänenebene sind beide auf Windows 2012 R2 eingestellt. Die Umgebung umfasst über 40.000 Benutzer und Tausende von Gruppen.
Vor der Migration wurde beschlossen, die primäre SMTP-Adresse mit dem User Principal Name (UPN) abzugleichen, um die Benutzerfreundlichkeit zu erhöhen. Bei einer Überprüfung stellten wir fest, dass über 14.000 Konten nicht übereinstimmten und wir Änderungen vornehmen mussten. Wir hatten auch gehört, dass es Anwendungen gibt, die Konten mit den falschen Informationen neu einrichten (siehe UPN-Änderungen). Es wurde keine Anwendung identifiziert, die sich auf die UPN-Anmeldung stützt, aber wir wollten alle Änderungen verfolgen, für den Fall, dass eine Rückgängigmachung erforderlich ist.
Zunächst müssen wir einen Zeitstempel für den Start des Skripts eingeben (beachten Sie, dass das Datumsformat für die USA üblich ist und internationale Leser möglicherweise etwas anderes benötigen):
$Line = ' ' | Out-File $Destination -Append
$Line = "### START @ $($Date.Invoke()) ###" | Out-File $LogDestination -Append
$Line = ' ' | Out-File $LogDestination -Append
Out-File ist das Cmdlet, das Werte in die zuvor definierte Protokolldatei schreibt.
Für den ersten Teil des Logs definieren wir unsere neue Protokolldatei und die Kopfzeile der Datei (denken Sie an Spaltenüberschriften in einer CSV-Datei):
$BeforeFileName = "BeforeChanges.txt"
$BeforeDestination = $Path+"\"+$BeforeFileName
$FileHeader = 'DisplayName,Alias,PrimarySMTPAddress,UPN' | Out-File $BeforeDestination
Dann nehmen wir für jeden Benutzer die Eigenschaftswerte (properties values) des Anzeigenamens (Display Name), des Benutzer-Alias, der primären SMTP-Adresse und des Hauptbenutzernamens (UPN, User Principle Name):
$Line = "$DisplayName,$Alias,$PrimarySMTPAddress,$UPN" | Out-File $BeforeDestination -Append
Beachten Sie, dass die Zeile an die Datei angehängt wird, da wir jede Zeile zur Datei hinzufügen und die Datei nicht überschreiben wollen. Wir können auch ausführlicher sein und jeden verarbeiteten Benutzer loggen:
$Output = "The mailbox $DisplayName was processed." | Out-File $LogDestination -Append
** Beachten Sie, dass die verwendete Variable ($Output oder $Line) unerheblich ist, da wir jeden akzeptablen PowerShell-Variablennamen wählen können.
In diesem Code gibt es einen Codeabschnitt, der sich mit der Änderung des UPN (User Principle Name) des Benutzers befasst. Der Code ist als Try {} Catch {}-Block aufgebaut, so dass wir gute Änderungen (im Try {}-Block) oder Fehlschläge (Catch {}-Block) protokollieren können.
If ($UPN -ne $PrimarySMTP) {
Try {
Set-Mailbox $User -UserPrincipalName $NewUPN -ErrorAction STOP
$Line = "$($Date.Invoke()),Successfully changed the UPN to $PrimarySMTPto the correct matching value for the $User." | Out-File $LogDestination -Append
} Catch {
$Line = "$($Date.Invoke()) , Failed to set the UPN to $PrimarySMTP to the correct matching value for the $User." | Out-File $LogDestination -Append
$Line = "$($Date.Invoke()) , Error message - $_.Exception.Message" | Out-File $LogDestination -Append
}
} Else {
$Line = "$($Date.Invoke()) , UPN for $User is correct, no change needed." | Out-File $LogDestination -Append
}
Beachten Sie die Variable $_.Exception.Message in der Mitte. Damit können wir alle PowerShell-Fehler erfassen, die normalerweise angezeigt worden wären - diese werden nun zur späteren Überprüfung in eine Protokolldatei kopiert.
Dieser Code sieht genauso aus wie der Abschnitt, den wir für die Protokollierung der Anfangseinstellungen verwendet haben, nur dass unsere Zieldatei eine andere ist, da wir eine Vorher- und eine Nachher-Datei benötigen:
$AfterFileName = "AfterChanges.txt"
$AfterDestination = $Path+"\"+$AfterFileName
$FileHeader = 'DisplayName,Alias,PrimarySMTPAddress,UPN' | Out-File $AfterDestination
$Line = "$DisplayName,$Alias,$PrimarySMTPAddress,$UPN" | Out-File $AfterDestination -Append
Zum Schluss fügen wir wieder einen Zeitstempel für das Ende des Skripts hinzu.
$Line = ' ' | Out-File $LogDestination -Append
$Line = "### END @ $($Date.Invoke()) ###" | Out-File $LogDestination -Append
$Line = ' ' | Out-File $LogDestination -Append
Nachfolgend finden Sie ein Beispiel für eine Log-Datei mit einem Start-/Endzeitstempel sowie einem Log der Ereignisse in der Mitte:
START- und END-Zeitstempel
Weiter zum nächsten Szenario!
Bei diesem Szenario handelt es sich um eine Exchange-to-Exchange Online-Migration, bei der über 10.000 Postfächer aus mehreren geografischen Regionen in einen einzigen Exchange Online-Tenant verschoben werden. Beim Verschieben dieser Benutzer nutzen wir ein Skript wie das hier beschriebene, das Administratoren für Migrationen verwenden. Um dieses Skript weiter zu verbessern, können wir PowerShell verwenden, um Logs für kritische Elemente im Skript zu erstellen.
Dies ist die Zusammenfassung der Logs, die wir durchführen können:
Jede Aktion sowie ein Start- und Stoppdatum für die Skriptausführung im Log festhalten.
Fehler protokollieren - den Fehler, den PowerShell generiert hätte, auf dem Bildschirm darstellen.
Start des Skripts - entsprechender Header für die Datei zum Starten des Skripts:
$FileName = "MailboxMoveAdministrationLogging.txt"
$Destination = $Path+"\"+$FileName
$FileCheck = Test-Path $Destination
If (-not($FileCheck)) {
$Line = "This file logs all changes made to move requests in this script" | Out-File $Destination
$Line = "---------------------------------------------------------------" | Out-File $Destination -Append
$Line = " " | Out-File $Destination -Append
}
$Line = ' ' | Out-File $Destination -Append
$Line = "### START @ $($Date.Invoke()) ###" | Out-File $Destination -Append
$Line = ' ' | Out-File $Destination -Append
Mit dieser Funktion wird lediglich der gesamte Report-Wert exportiert, der eine detaillierte Analyse einer Postfachverschiebung in die Cloud liefert und dazu verwendet wird, festzustellen, warum die Verschiebung fehlgeschlagen ist oder pausiert wurde. Im Folgenden wird die primäre SMTP-Adresse des Postfachs abgerufen, eine Ausgabedatei angegeben (spezifisch für die Postfachverschiebung, die wir abfragen), der Bericht des Postfachs abgerufen und dann der gesamte Bericht in die Datei exportiert, die wir in Zeile 2 angegeben haben:
$Mailbox = $MoveRequest.PrimarySMTPAddress
$OutputFile ="$Path"+"\"+"$Mailbox"+"-Report.txt"
$Report = (Get-MoveRequestStatistics -Identity $Mailbox -IncludeReport).Report
$Report.Entries | Ft | Out-File -FilePath $OutputFile
In diesem Teil des Skripts erstellen wir eine neue Anforderung für eine Postfachmigration, wiederum unter Verwendung eines Try {} Catch {}-Blocks. Wenn die Erstellung erfolgreich war, wird dies protokolliert, und wenn ein Fehler auftritt, wird die Fehlermeldung ebenfalls protokolliert:
$Mailbox = $User.PrimarySMTPAddress
If ($Null -eq (Get-MoveRequest $Mailbox -ErrorAction Silentlycontinue)){
Try {
$Creation = New-MoveRequest -Identity $Mailbox -Remote -RemoteHostName $Endpoint -TargetDeliveryDomain $TargetDomain -RemoteCredential $OPCred -SuspendWhenReadyToComplete -ErrorAction STOP
$Line = "The mailbox move for $Mailbox was successfully created." | Out-File $Destination -Append
} Catch {
$Line = "The mailbox move for $Mailbox was NOT successfully created." | Out-File $Destination -Append
$Line = "$($Date.Invoke()) , Error message - $_.Exception.Message" | Out-File $Destination -Append
}
}
In diesem Codeabschnitt haben wir einen Codeblock, der Move Requests entfernt, z. B. weil der Benutzer warten muss oder aus der aktuellen Umzugsliste entfernt wird, weil er das Unternehmen verlässt. Dieser Vorgang ähnelt dem zuvor gezeigten neuen Move Request, und wir haben diesen Codeabschnitt:
Write-host "Removing move request for " -ForegroundColor White -NoNewline
Write-host "$SMTPAddress....." -ForegroundColor Yellow
Try {
Remove-MoveRequest $SMTPAddress -Confirm:$False -ErrorAction STOP
$Line = "$($Date.Invoke()) , Remove move request for $SMTPAddress succeeded." | Out-File $Destination -Append
} Catch {
$Line = "$($Date.Invoke()) , Remove request for $SMTPAddress failed." | Out-File $Destination -Append
$Line = "$($Date.Invoke()) , Error message - $_.Exception.Message" | Out-File $Destination -Append
}
Eine Log-Datei mit START, ENDE und protokollierten Aktionen
Eine Log-Datei mit START, ENDE und in diesem Fall auch mit protokollierten Fehlern
Welche Szenarien können Sie sich noch vorstellen? Würden Sie separate Protokolle für gute und schlechte Ergebnisse erstellen? Eine weitere mögliche Verwendung von Out-File ist die Dokumentation, z. B. tägliche Postfachstatistiken für alle Benutzer in Exchange Online. Mit anderen Worten, es gibt viele Möglichkeiten, also machen Sie weiter und protokollieren Sie, oder auditieren Sie, oder setzen andere Ideen um mit PowerShell.
Die Zahl 10.000 ist in beiden Szenarien wichtig. PowerShell verwendet ein Limit von 1.000 Ergebnissen. Da beide Umgebungen groß sind, ist die Verwendung von -ResultSize Unlimited für einige Cmdlets die einzige Möglichkeit, um Ergebnisse zu erhalten. Ein weiterer Leistungstipp für große Umgebungen: Wenn ein Cmdlet über 'Filter'-Parameter verfügt, verwenden Sie diese, bevor Sie 'Where' zum Filtern der Ergebnisse verwenden. Die Verwendung von 'Where' in einer großen Umgebung kann die Verarbeitungszeit für ein Skript erheblich verlängern.
Governance und Compliance Readiness verlangen immer öfter die komplette Nachvollziehbarkeit aller Vorgänge. Auch die Anwendung von PowerShell-Scripten ist davon nicht ausgenommen. Mit der externen Datenbank können Sie über die geforderten Zeiträume hinweg jederzeit nachweisen, welche Skripte auf welchem System mit welchen Parametern ausgeführt worden sind, was die Ergebnisse waren usw. Egal, ob Sie einen oder mehrere ScriptRunner Hosts einsetzen.
Der ScriptRunner Report/Audit DB Connector verbindet den ScriptRunner Host mit der Datenbank auf einem Microsoft SQL-Server. Wenn Sie mehrere ScriptRunner Hosts betreiben, können Sie alle in die gleiche Datenbank schreiben. Somit haben Sie alle Reporting-Informationen über alle Systeme hinweg in einer einzigen Datenbank.
Wurde durch eine Aktion ein Report erzeugt, so wird dieser zuerst in die Umlaufdatenbank auf dem ScriptRunner Host geschrieben. Der Connector erzeugt zusätzlich eine XML-Datei, deren Inhalte automatisch an die Datenbank auf den SQL-Server übertragen werden. Ein Wiederaufsetzen nach Fehlern sorgt dafür, dass kein Report verloren geht und alle zwischenzeitlich angefallenen Daten in der Datenbank gespeichert werden.
Sep 30, 2024 by Frank Kresse
Wir haben unser neuestes ScriptRunner-Update, Version 7.1, veröffentlicht. Dieses Update ist vollgepackt mit...
Aug 16, 2024 by Heiko Brenn
Willkommen im Scriptember! Wir freuen uns, einen ganz besonderen Monat ankündigen zu können: Wir feiern einen Monat...
Aug 14, 2024 by Jeffery Hicks
Wie gut bist du mit dem Thema vertraut? Vielleicht gibt dir dieser Artikel nur einen Überblick. Aus meiner Erfahrung in...
Damian Scoles ist ein zehnfacher Microsoft MVP mit Spezialisierung auf Exchange, Office 365 und PowerShell, der über 25 Jahre Erfahrung in der IT-Branche mitbringt. Er ist im Großraum Chicago ansässig und begann mit der Verwaltung von Exchange 5.5 und Windows NT. Im Laufe der Jahre hat er mit Office 365 seit BPOS gearbeitet und darüber hinaus Erfahrung mit Azure AD, Security and Compliance Admin Centers und Exchange Online. Zu seinem Engagement in der Community gehören Beiträge in TechNet-Foren, die Erstellung von PowerShell-Skripten, die in seinen Blogs zu finden sind, das Schreiben von ausführlichen PowerShell/Office365/Exchange-Blogartikeln, Tweets und die Erstellung von PowerShell-Videos auf YouTube. Er hat fünf PowerShell-Bücher geschrieben und arbeitet außerdem aktiv an dem Buch "Microsoft 365 Security for IT Pros".