none
Powershell - утечка памяти в Get-WinEvent RRS feed

  • Вопрос

  • Здравствуйте.

    Один из самописных сценариев мониторинга событий в эвентлоге через SCOM предполагает периодический запуск командлета Get-WinEvent. Обнаружил, что при таком подходе постепенно растёт значение счётчика Process/Private Bytes, что в конечном счёте приводит к рестарту агента со всеми вытекающими (из самых неприятных - сброс счётчика последней прочитанной строки в процессах мониторинга текстовых логов).

    Моделируется так: 

    do { Get-WinEvent -LogName 'application' -MaxEvents 1 | Out-Null } while ($true)

    Пробовал на Windows Server 2008 R2, 2012 R2, Windows 10, результат одинаковый. Удалось также выяснить, что проблема кроется в методах ProcessGet* в библиотеке Microsoft.PowerShell.Commands.Diagnostics.dll. В них создаётся объект EventLogReader, но не освобождается (нет вызова Dispose).

    Как бы победить эту проблему? Заранее спасибо.

Ответы

  • Используйте утилиту: wevtutil qe Application /c:1

    Или реализовать через .Net классы с использованием Dispose:

    using namespace System.Diagnostics.Eventing.Reader

    $query = [EventLogQuery]::new("Application","LogName") $query.ReverseDirection = $true $log = [EventLogReader]::new($query) $evt = $log.ReadEvent() $evt | Add-Member -Type NoteProperty -Name Message -Value $evt.FormatDescription() -Passthru $log.CancelReading() $log.Dispose()


    В PowerShell 6 это поправили:

    https://github.com/PowerShell/PowerShell/blob/c1c5344a8897262433141ecbc13bb06ac2c4bbef/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs

    using (EventLogReader readerObj = newEventLogReader(logQuery))


    Где оператор using - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement

    The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):

    PS. На PowerShell 6.0.2 проблема не воспроизводится, а все что меньше 6,то там  не будут вноситься некритические исправления.




    • Изменено KazunEditor 4 мая 2018 г. 14:33
    • Помечено в качестве ответа Dmitriy.Khandzhyan 4 мая 2018 г. 14:33
    Отвечающий

Все ответы

  • Используйте утилиту: wevtutil qe Application /c:1

    Или реализовать через .Net классы с использованием Dispose:

    using namespace System.Diagnostics.Eventing.Reader

    $query = [EventLogQuery]::new("Application","LogName") $query.ReverseDirection = $true $log = [EventLogReader]::new($query) $evt = $log.ReadEvent() $evt | Add-Member -Type NoteProperty -Name Message -Value $evt.FormatDescription() -Passthru $log.CancelReading() $log.Dispose()


    В PowerShell 6 это поправили:

    https://github.com/PowerShell/PowerShell/blob/c1c5344a8897262433141ecbc13bb06ac2c4bbef/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs

    using (EventLogReader readerObj = newEventLogReader(logQuery))


    Где оператор using - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement

    The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):

    PS. На PowerShell 6.0.2 проблема не воспроизводится, а все что меньше 6,то там  не будут вноситься некритические исправления.




    • Изменено KazunEditor 4 мая 2018 г. 14:33
    • Помечено в качестве ответа Dmitriy.Khandzhyan 4 мая 2018 г. 14:33
    Отвечающий
  • Я не отметил, что у Get-WinEvent есть параметр FilterXml для сложной фильтрации, а wevtutil так, к сожалению, не умеет. Спасибо за наводку на powershell core, будут думать в этом направлении.
  • Я не отметил, что у Get-WinEvent есть параметр FilterXml для сложной фильтрации, а wevtutil так, к сожалению, не умеет. Спасибо за наводку на powershell core, будут думать в этом направлении.

    Eсли не несколько отдельных выражений, то вполне себе можно использовать XPath.

    wevtutil qe Security /q:"*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and Task=12544 and (EventID=4624)] and EventData[Data[@Name='LogonType']='2']]"

    Отвечающий
  • Невнимательно читал. Ещё раз благодарю.