none
Hash funktioniert mit Start-Job und Get-Winevent nicht wie erwartet

    Frage

  • Hallo,

    ich möchte mit get-Winevent diverse Event-Logs auf einem Computer auslesen. Die Logs sollen mit Start-Job "parallel"  ausgelesen werden. Dafür wird in einem Foreach-Block für jedes Log mit Start-Job ein Task mit Get-WinEvent gestartet.
    Zum Filtern der Events wird Get-WinEvent das Hash $Filter übergeben. In dieses Hash wird bei jeden Durchlauf der zu filternde  LogName eingetragen. Dies funktioniert so weit - und wiederum auch nicht :-( Als Ergebnis bekomme ich 2 Tasks, die beide Events des "letzten" Logs (Application) enthalten. Hier das Skript und der Output:

    $ComputerName = "localhost"
    $Jobs = @()
    $Logs = 'system', 'application'

    $Filter = @{ StartTime = ((Get-Date).AddMinutes(-90)) }

    $Logs | ForEach-Object {
       $Filter['LogName'] = $_

       # Testausgabe LogName + Filter Anfang
       '*' * 40
       "LogName: $_"
       "`nFilter:"
       $Filter
       '*' * 40
       Testausgabe LogName + Filter Ende

       $Jobs +=Start-Job -ScriptBlock {Get-WinEvent -FilterHashtable $Args[0] -ComputerName $Args[1] -MaxEvents 1} -ArgumentList $Filter, $ComputerName
    }

    $Null = Wait-Job $Jobs
    # Ausgabe EventLogs
    Receive-Job $Jobs |FT -AutoSize LogName, Id
    Remove-Job $Jobs

    # Output:

    ****************************************
    LogName: system
    
    Filter:
    
    Name                           Value                                                                                                                                                                                                                             
    ----                           -----                                                                                                                                                                                                                             
    LogName                        system                                                                                                                                                                                                                            
    StartTime                      06.07.2018 13:31:16                                                                                                                                                                                                               
    ****************************************
    ****************************************
    LogName: application
    
    Filter:
    LogName                        application                                                                                                                                                                                                                       
    StartTime                      06.07.2018 13:31:16                                                                                                                                                                                                               
    ****************************************
    
    LogName     Id
    -------     --
    Application  1
    Application  1

    Im Output kann man sehen, wie in jedem Durchlauf der LogName im Hash $Filter aktualisiert wird und trotzdem bekomme ich als Ergebnis nur 2x die Events von Application.

    Warum bekomme ich von Get-WinEvent nicht alle Logs ausgegeben, obwohl $Filter immer den aktuellen Lognamen enthält?

    Kurios wird es für mich, wenn ich die Zeile
    $Filter = @{ StartTime = ((Get-Date).AddMinutes(-90)) }
    an den Beginn des Foreach-Block verschiebe. Denn dann funktion
    iert das Skript wie gewünscht.

    Kann mir bitte jemand dieses Verhalten erklären?

    Danke und ein schönes Wochenende

    Christoph

    Edit:

    Hier noch ein paar Anmerkungen:
    Der Parameter FilterHashTable von Get-WinEvent erwartet ein Hash mit bis zu 11 vorgegebenen Schlüssel und entsprechenden Werten. Mit diesen Keys/Values können dann Eventlogs nach bestimmten Eigenschaften durchsucht werden. Ich verwende hier die Schlüssel StartTime und LogName im Hash $Filter. StartTime filtert die Log-Eigenschaft TimeCreated und LogName legt das zu durchsuchende Log fest.
    Der Wert des Schlüssels LogName wird nun in jeden Foreach-Durchlauf auf einen neuen Wert aus dem Array $Logs gesetzt. Wie der Output zeigt, wird $Filter jedesmal entsprechend geändert. Was nicht zu funktionieren scheint, ist die Übergabe von $Filter durch Start-Job an Get-Winevent. Get-WinEvent arbeitet immer mit dem letzten Element von $Logs, in diesem Fall Application.






    • Bearbeitet C.Ehlers Sonntag, 8. Juli 2018 21:20
    Freitag, 6. Juli 2018 13:40

Antworten

  • Hier gibt es 2 Varianten:

    a) die Hashtable wird als String-Argument umgewandelt (was ich in der Doku nicht gefudnen habe)
    b) die Hashtable wird von dem Hauptscript schneller geändert, als der Job die Werte aus der Hashtable auswerten kann, da die Übergabe nur eine Referenz auf die Hasttable übergibt, was zu deiner Aussage besser passt.

    Also:

    Merke dir den Startwert vor der Schleife und bilde im Block für jeden Start-Job eine eigene Hashtable.


    Montag, 9. Juli 2018 12:12

Alle Antworten

  • Mit dem Init legst du einen Eintrag fest, der als Schlüssel die Uhrzeit hat.

    Mittels "$Filter['LogName'] = $_" ordnest du dem konstanten Eintrag 'LogName' dann immer den aktuellen Wert zu, erhältst also immer nur 1 Eintrag.

    Dein Zugriff sollte aber wohl eher der Logname sein, der nun in $_ steht.

    Also

    $Filter[$_] = ???

    Allerdings geht nun nicht daraus hervor, was du dem Namen denn zuweisen willst.

    Eine Hashtable besteht aus 2 Werten: 1 Key und 1 Value.


    PS:
    An den Uhrzeit-Eintrag kommst du nur noch per ForEach, da dir der Schlüssel ja nicht bekannt ist.
    • Bearbeitet bfuerchau Freitag, 6. Juli 2018 14:16
    Freitag, 6. Juli 2018 14:15
  • Hallo bfuercha, 

    danke für die Anwort. Allerdings bin ich mir nicht sicher, ob wir das Gleiche meinen. Daher habe ich meine Frage oben noch Anmerkungen hinzugefügt.

    Gruß

    Christoph

    Sonntag, 8. Juli 2018 21:26
  • OK, verstanden.

    Dann schau mal bitte den Aufruf und die Doku dazu an:

    Get-WinEvent -FilterHashtable $Args[0] ...

    Wiso gibst du die Hashtable nicht an dieses Argument weiter?

    Get-WinEvent -FilterHashtable $Filter ...

    https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.diagnostics/get-winevent?view=powershell-6

    Montag, 9. Juli 2018 08:15
  • Hallo bfuercha,

    ich kann $Filter + $Computername nicht direkt an Get-WinEvent übergeben, da Get-WinEvent von Start-Job in einem eigenen PS-Prozess gestartet wird und Get-Winevent daher nicht die Variablen aus dem ausrufenden PS-Prozess kennt. Der Parameter Argumentlist von Start-Job gibt die Variablen $Filter + $Computername an den neuen Prozess weiter. Diese können im neuen Prozess wie Skript-Parameter ausgewertet werden. Ich nutze hier das Array $Args zur Auswertung der Parameter, alternativ wäre auch dies möglich:

    $Jobs+=Start-Job -ScriptBlock {Param($FilterHashTable, $Hostname);Get-WinEvent -FilterHashtable $FilterHashTable -ComputerName $Hostname -MaxEvents 1} -ArgumentList $Filter, $ComputerName

    Und wie der Skript-Output oben zeigt, kommen bei Get-WinEVent Parameter an, allerdings für Logname im nur das letzte Element des Array $Logs (Application).

    Liegt hier vielleicht ein Laufzeitproblem beim Erstellen der Jobs vor?

                 
    Montag, 9. Juli 2018 11:52
  • Hier gibt es 2 Varianten:

    a) die Hashtable wird als String-Argument umgewandelt (was ich in der Doku nicht gefudnen habe)
    b) die Hashtable wird von dem Hauptscript schneller geändert, als der Job die Werte aus der Hashtable auswerten kann, da die Übergabe nur eine Referenz auf die Hasttable übergibt, was zu deiner Aussage besser passt.

    Also:

    Merke dir den Startwert vor der Schleife und bilde im Block für jeden Start-Job eine eigene Hashtable.


    Montag, 9. Juli 2018 12:12