none
Compare-Object txt-file & Variable RRS feed

  • Frage

  • ## Script zum Versenden von Änderungen an den ## Gruppenzugehörigkeiten der Gruppen ## "Domain Admins" und "Administrators" ## Zwischenspeicher des letzten Standes $lastresultfolder = "C:\TEMP\admins.txt" ### E-Mail Variablen: ## Deklarieren des E-Mail Empfängers $xemail = "HierEinName@domain.com" ## Deklarieren des E-Mail Absenders $xabsender = "PowerShell@domain.local" ## Deklarieren des E-Mail Betreffs $xbetreff = "Administratoren - Accounts" ## Deklarieren des E-Mail Inhalts $xinhalt = ("Änderungen an den Administrator Berechtigungen: "+$compare+"Aktueller Stand: "+$newresult+"Letzter Stand: "+$lastresult) ## Deklarieren des SMTP-Servers $xsmtp = "smtp.domain.local" ## Test, ob ein letzter Stand existiert. $TestP = (Test-Path $lastresultfolder) ## Wenn kein letzter Stand vorhanden ist, ## wird die .txt erstellt. if($TestP -eq 0){ New-Item $lastresultfolder -type file } ## letzten Stand auslesen $lastresult = (Get-Content $lastresultfolder) ## Aktuelle Administratoren auslesen $domainadmins = (Get-ADGroupMember -Identity "Domain Admins" | %{$_.SamAccountName+" - "+$_.name+"`n"}) $admins = (Get-ADGroupMember -Identity "Administrators" | %{$_.SamAccountName+" - "+$_.name+"`n"}) $newresult = "`nFolgende User sind in der Gruppe Domain Admins:`n`n"+$domainadmins+"`n`nFolgende User sind in der Gruppe Administrators:`n`n"+$admins ## letzten Stand mit aktuellem Stand vergleichen $compare = (Compare-Object -referenceObject $lastresult -differenceObject $newresult -IncludeEqual) ## Versenden der E-Mail #Send-MailMessage -to $xemail -from $xabsender -Subject $xbetreff -body $xinhalt -SmtpServer $xsmtp Write-Host $compare ## Aktuellen Stand speichern $newresult | Out-File $lastresultfolder

    Dieses Skript habe ich geschrieben, um die aktuellen Veränderungen der Gruppen "Domain Admins" und "Administrators" zu dokumentieren. Leider scheint Compare-Object hier nicht zu funktionieren oder ich habe einen Fehler gemacht, den ich besten Willens nicht erkennen kann, denn er zeigt mir bei der Auswertung immer alle Daten an, nicht nur die Unterschiede zwischen den Variablen.

    Wenn jemand Ideen hat, sind die sehr willkommen. :)

    Lieber Gruß,

    Grunch

    Mittwoch, 2. August 2017 16:09

Antworten

  • Ich würde diese Aufgabe etwas anders angehen .... hier also mal ein Vorschlag:

    $TimeStamp = Get-Date -Format 'yyyy-MM-dd_HH-mm-ss'
    $ResultRoot = 'C:\temp'
    Get-ADGroupMember -Identity 'Administrators' -OutVariable CurrentAdministratoren | Export-Clixml -Path (Join-Path -Path $ResultRoot -ChildPath ('Admins_' + $TimeStamp + '.xml')) -Encoding UTF8
    Get-ADGroupMember -Identity 'Domain Admins' -OutVariable CurrentDomainAdmins | Export-Clixml -Path (Join-Path -Path $ResultRoot -ChildPath ('DomainAdmins_' + $TimeStamp + '.xml')) -Encoding UTF8
    
    Get-ChildItem -Path $ResultRoot -Filter 'Admins*.xml' | Sort-Object -Property BaseName | Select-Object -Last 2 -OutVariable AdminFiles
    Get-ChildItem -Path $ResultRoot -Filter 'DomainAdmins*.xml' | Sort-Object -Property BaseName | Select-Object -Last 2 -OutVariable DomainAdminFiles
    
    $AdminResult = Compare-Object -ReferenceObject (Import-Clixml -Path $AdminFiles[0].FullName) -DifferenceObject (Import-Clixml -Path $AdminFiles[1].FullName) -Property SamAccountName -IncludeEqual -PassThru
    $DomainAdminResult = Compare-Object -ReferenceObject (Import-Clixml -Path $DomainAdminFiles[0].FullName) -DifferenceObject (Import-Clixml -Path $DomainAdminFiles[1].FullName) -Property SamAccountName -IncludeEqual -PassThru
    
    $AdminResult | Select-Object -Property SamAccountName,Name,SideIndicator | Format-Table -AutoSize
    $DomainAdminResult | Select-Object -Property SamAccountName,Name,SideIndicator | Format-Table -AutoSize

    ... und hier ein paar Erklärungen dazu:

    Ich habe mich mal auf die eigentliche Kernaufgabe konzentriert und den Email-Kram weggelassen. ich bin kein Freund von zu viel schmückendem Beiwerk in eigentlich technischen Informationen/Daten. Deshalb hab ich deine "Texte"/"Erklärungen" auch weggelassen. Die kannst Du ja, wenn nötig, als Header in der Email platzieren .... 

    Ich halte es für weniger robust oder zuverlässig, aus Objekten extrahierte und in Strings umgewandelte Werte zu vergleichen. Ich denke, wenn wir schon die Powershell benutzen und deren Mehrwert richtige Objekte sind, dann sollten wir die auch nutzen. Das halte ich auch für deutlich flexibler.

    ... und noch'n Tipp für Deine Formatierungen. Da die Powershell-Syntax quasi selbst-dokumentierend ist, machen Kommentare, die die gut lesbaren nächsten zwei Code-Zeilen nochmal kommentieren, den Code eher unübersichtlich und blähen ihn auf. Übermäßig viele Leerzeilen sind, speziell hier im Forum, auch eher hinderlich, genau wie Aliasse oder Abkürzungen. Einrückungen sollten möglichst die Code-Struktur abbilden/unterstützen (Schleifen und Bedingungen).

    Die Ausgabe am Schluss kann natürlich nach Belieben verändert werden. Dadurch, dass es die unveränderten Objekte sind, kannst Du sie einmal als Tabelle auf der Konsole ausgeben, als GridView z.B. so:

    $AdminResult | Out-GridView
    $DomainAdminResult | Out-GridView

    .... oder eben als html-formatierte Mail für den Chef.  ;-)



    Grüße - Best regards

    PS:> (79,108,97,102|%{[char]$_})-join''


    • Bearbeitet BOfH-666 Mittwoch, 2. August 2017 20:22
    • Als Antwort markiert Grunch83 Donnerstag, 10. August 2017 11:42
    Mittwoch, 2. August 2017 18:10

Alle Antworten

  • Ich würde diese Aufgabe etwas anders angehen .... hier also mal ein Vorschlag:

    $TimeStamp = Get-Date -Format 'yyyy-MM-dd_HH-mm-ss'
    $ResultRoot = 'C:\temp'
    Get-ADGroupMember -Identity 'Administrators' -OutVariable CurrentAdministratoren | Export-Clixml -Path (Join-Path -Path $ResultRoot -ChildPath ('Admins_' + $TimeStamp + '.xml')) -Encoding UTF8
    Get-ADGroupMember -Identity 'Domain Admins' -OutVariable CurrentDomainAdmins | Export-Clixml -Path (Join-Path -Path $ResultRoot -ChildPath ('DomainAdmins_' + $TimeStamp + '.xml')) -Encoding UTF8
    
    Get-ChildItem -Path $ResultRoot -Filter 'Admins*.xml' | Sort-Object -Property BaseName | Select-Object -Last 2 -OutVariable AdminFiles
    Get-ChildItem -Path $ResultRoot -Filter 'DomainAdmins*.xml' | Sort-Object -Property BaseName | Select-Object -Last 2 -OutVariable DomainAdminFiles
    
    $AdminResult = Compare-Object -ReferenceObject (Import-Clixml -Path $AdminFiles[0].FullName) -DifferenceObject (Import-Clixml -Path $AdminFiles[1].FullName) -Property SamAccountName -IncludeEqual -PassThru
    $DomainAdminResult = Compare-Object -ReferenceObject (Import-Clixml -Path $DomainAdminFiles[0].FullName) -DifferenceObject (Import-Clixml -Path $DomainAdminFiles[1].FullName) -Property SamAccountName -IncludeEqual -PassThru
    
    $AdminResult | Select-Object -Property SamAccountName,Name,SideIndicator | Format-Table -AutoSize
    $DomainAdminResult | Select-Object -Property SamAccountName,Name,SideIndicator | Format-Table -AutoSize

    ... und hier ein paar Erklärungen dazu:

    Ich habe mich mal auf die eigentliche Kernaufgabe konzentriert und den Email-Kram weggelassen. ich bin kein Freund von zu viel schmückendem Beiwerk in eigentlich technischen Informationen/Daten. Deshalb hab ich deine "Texte"/"Erklärungen" auch weggelassen. Die kannst Du ja, wenn nötig, als Header in der Email platzieren .... 

    Ich halte es für weniger robust oder zuverlässig, aus Objekten extrahierte und in Strings umgewandelte Werte zu vergleichen. Ich denke, wenn wir schon die Powershell benutzen und deren Mehrwert richtige Objekte sind, dann sollten wir die auch nutzen. Das halte ich auch für deutlich flexibler.

    ... und noch'n Tipp für Deine Formatierungen. Da die Powershell-Syntax quasi selbst-dokumentierend ist, machen Kommentare, die die gut lesbaren nächsten zwei Code-Zeilen nochmal kommentieren, den Code eher unübersichtlich und blähen ihn auf. Übermäßig viele Leerzeilen sind, speziell hier im Forum, auch eher hinderlich, genau wie Aliasse oder Abkürzungen. Einrückungen sollten möglichst die Code-Struktur abbilden/unterstützen (Schleifen und Bedingungen).

    Die Ausgabe am Schluss kann natürlich nach Belieben verändert werden. Dadurch, dass es die unveränderten Objekte sind, kannst Du sie einmal als Tabelle auf der Konsole ausgeben, als GridView z.B. so:

    $AdminResult | Out-GridView
    $DomainAdminResult | Out-GridView

    .... oder eben als html-formatierte Mail für den Chef.  ;-)



    Grüße - Best regards

    PS:> (79,108,97,102|%{[char]$_})-join''


    • Bearbeitet BOfH-666 Mittwoch, 2. August 2017 20:22
    • Als Antwort markiert Grunch83 Donnerstag, 10. August 2017 11:42
    Mittwoch, 2. August 2017 18:10
  • > Ich würde diese Aufgabe etwas anders angehen ....

    Und ich würde das noch mal anders machen :-)

    Aktiviere Auditing - DS Access - Verzeichnisdienständerungen überwachen. Dann aktiviere in den Sicherheitseinstellungen der beiden Gruppen die Überwachung "Jeder" - "Alle Eigenschaften schreiben" (ist standardmäßig aktiviert...)

    Ab jetzt wird auf dem ausführenden Domain Controller ein Security Audit Event erzeugt, wenn jemand "egal was" an diesen Gruppen ändert.
    Die Events, die Dich interessieren, findest Du in https://support.microsoft.com/de-de/help/977519/description-of-security-events-in-windows-7-and-in-windows-server-2008

    Der Rest ist eine Fingerübung: Entweder Skript an die Events binden oder Event Forwarding einrichten. Oder Ihr habt schon eine entsprechende Lösung im Einsatz, dann da einbinden.

    Donnerstag, 3. August 2017 07:11
  • Und noch ein Kommentar zur ursprünglichen Frage:

    $compare = (Compare-Object -referenceObject $lastresult -differenceObject $newresult -IncludeEqual)
    zeigt mir bei der Auswertung immer _alle_Daten an, nicht nur die Unterschiede zwischen den Variablen.

    Na, was denkst Du, was "-IncludeEqual" genau bewirkt? :-)

    Donnerstag, 3. August 2017 07:14
  • Nee nee nee ... das gilt nicht!!  Wir suchen hier POWERSHELL-Lösungen!!!  :-D ;-) 

    Ja, manchmal übersieht man (ich), dass die beste Lösung für ein Script einfach kein Script ist. Und robuster/zuverlässiger isses wahrscheinlich auch noch.


    Grüße - Best regards

    PS:> (79,108,97,102|%{[char]$_})-join''

    Donnerstag, 3. August 2017 09:02
  • > Nee nee nee ... das gilt nicht!!  Wir suchen hier POWERSHELL-Lösungen!!!  :-D ;-)

    Oft hilft es, einen Schritt zurück zu treten und sich die Anforderung noch mal genau anzuschauen :) Viele Threads hier entstehen, weil sich der TO vorher zu wenig um die generellen Fragen kümmerte und sofort ins technische einsteigt.

    Ich habe gelernt: Je besser Du Pflichtenheft und Fachkonzept ausarbeitest, um so schneller bist Du hinterher mit der Umsetzung fertig. Und "insgesamt" geht es immer noch deutlich schneller.

    Um das auf diesen Thread zu übertragen: Die Frage hätte nicht "Compare-Object" sein dürfen, sondern "Wie überwache ich Gruppenmitgliedschaften". Und das mit den LastResult finde ich eh nicht prickelnd - wenn das entsorgt wird, geht alles schief :)

    PS: Um noch was produktives zu sagen - wenn ich PoSh-Objekte in Dateien speichern will, nehme ich dafür gerne Export/Import-CliXML. Dann werden das beim Importieren nämlich wieder die ursprünglichen Objekte, und damit kann Compare-Object besser umgehen als im Fall des TO, wo nur String-Arrays verglichen werden.

    Donnerstag, 3. August 2017 10:43