Как передать журнал событий Windows в командную строку?

Я хочу сделать эквивалент:

tail -f

в Windows. Я прочитал это, но похоже, что нет возможности передавать журнал событий в потоковом режиме, поэтому он работает в бесконечном цикле и отображает события по мере их возникновения в командной строке. Есть ли какая-либо встроенная опция/флаг команды для этого в Windows?

🤔 А знаете ли вы, что...
С PowerShell можно управлять файлами, реестром, службами, процессами и многими другими аспектами Windows.


2
54
2

Ответы:

Эквивалентом tail -f является Get-Content -Wait. Но это не помогает, потому что вам все равно нужны ваши события в текстовом файле. Windows хранит свои события в файлах .evtx по адресу C:\Windows\System32\winevt\Logs, и они являются двоичными.

В качестве обходного пути вы можете периодически печатать последние x событий:

function Get-WinEventTail {

    param(
        $LogName,
        $MaxEvents = 20
    )

    while ($true) {
        Get-WinEvent -LogName $LogName -MaxEvents $MaxEvents | Select-Object TimeCreated, Message
        Start-Sleep -Seconds 1
    }
}

Get-WinEventTail -LogName System

Более сложный подход — использовать EventLogWatcher для записи входящих событий в текстовый файл и последующего отслеживания этого файла:

function Write-WinEventsToTempFile {

    param(
        $LogName
    )

    try {
        $logFile = New-TemporaryFile
        $query = [System.Diagnostics.Eventing.Reader.EventLogQuery]::new($LogName,[System.Diagnostics.Eventing.Reader.PathType]::LogName)
        $watcher = [System.Diagnostics.Eventing.Reader.EventLogWatcher]::new($query)
        $watcher.Enabled = $true
        $action = {
            $myEvent = Get-WinEvent -LogName $eventArgs.EventRecord.LogName | Where-Object {$_.RecordId -eq $eventArgs.EventRecord.RecordId}
            "[$($myEvent[0].TimeCreated)]: $(($myEvent[0].Message -replace '\r\n', '') -replace '\t|\s{2,}', ' ')" | Out-File $event.MessageData -Append
        }
        $job = Register-ObjectEvent -InputObject $watcher -SourceIdentifier WriteWinEventsToTempFile -EventName 'EventRecordWritten' -MessageData $logFile -Action $action
        Write-Host "Use `"Get-Content '$($logFile.FullName)' -Wait`" in another PowerShell window to tail the log. Press Ctrl+C, if you are done..."
        Wait-Event -SourceIdentifier WriteWinEventsToTempFile
    } finally {
        Remove-Job $job -Force
        Remove-Item $logFile
    }
}

Write-WinEventsToTempFile -LogName System

Решено

Решение на основе [System.Diagnostics.Eventing.Reader.EventLogWatcher] в ответе stackprotector многообещающе, но несколько громоздко из-за необходимости использования временного файла, который необходимо читать отдельно.

Этого можно избежать с помощью следующей функции Trace-WinEvent, которая передает любые новые добавленные записи событий непосредственно в конвейер:

function Trace-WinEvent {

  param(
    [Parameter(Mandatory)] [string] $LogName
  )

  $sourceId = 'TraceWinEvent' # self-chosen
  try {
    $query = [System.Diagnostics.Eventing.Reader.EventLogQuery]::new($LogName, 'LogName')
    $watcher = [System.Diagnostics.Eventing.Reader.EventLogWatcher]::new($query)
    $watcher.Enabled = $true
    Write-Verbose "Registering for EventLogWatcher events for the '$LogName' log..."
    Register-ObjectEvent -InputObject $watcher -SourceIdentifier $sourceId -EventName EventRecordWritten
    Write-Verbose 'Waiting for such events indefinitely; use Ctrl+C to stop...'
    while ($true) {
      $evt = Wait-Event -SourceIdentifier $sourceId
      $evt | Remove-Event
      # Extract the event record.
      $evtRec = $evt.SourceEventArgs.EventRecord
      # Add a .Message NoteProperty member and output the decorated record.
      $evtRec | Add-Member -PassThru Message $evtRec.FormatDescription()
    }
  }
  finally {
    Unregister-Event $sourceId
  }
}

Вызовите его, например, следующим образом:

# Trace (monitor) the Application event log for newly created records 
# and also capture them in variable $records.
# -Verbose provides verbose feedback.
# Use Ctrl-C to stop.
Trace-WinEvent Application -OutVariable records -Verbose 

Пример вывода:

Примечание:

  • Потоковая передача в конвейер не только обеспечивает мгновенный вывод на консоль, но также позволяет программную обработку записей, которые являются экземплярами [System.Diagnostics.Eventing.Reader.EventLogRecord], в конвейере.

  • Чтобы прекратить отслеживание (мониторинг), нажмите Ctrl+C.

  • Реализация основана на:

    • Вызов Register-ObjectEvent без блока сценария -Action, что ставит PowerShell в очередь событий для извлечения по требованию.

    • Это извлечение по требованию выполняется в бесконечном цикле, который вызывает Wait-Event для получения ожидающих событий по одному в блокирующем режиме.

    • Поскольку форматирование экземпляров EventLogRecord в PowerShell для отображения зависит от наличия свойства .Message ETS (типа NoteProperty, которым Get-WinEvent автоматически украшает свои выходные объекты), приведенный выше код вручную декорирует каждый экземпляр, извлеченный из объекта события. таким образом, с помощью метода .FormatDescription(), и выводит декорированный экземпляр в конвейер.


[*]