Как сохранить объект в журнале событий Windows?

Недавно мы добавили возможность ко всем нашим скриптам регистрировать свои сообщения в журнале событий Windows. Это отлично подходит для коротких сообщений, но мы не можем найти способ сохранить события структурированным способом, чтобы впоследствии создавать объекты с ними.

Пример события, которое может хранить несколько свойств объекта: Service Control Manager

Как это делается с PowerShell?

Мы пробовали следующее, как описано здесь, но не повезло:

Write-EventLog -LogName HCScripts -Source 'Test (Brecht)' -EventId 4 -Message "<Data Name=""MyKey1"">MyValue1</Data>"

введите описание изображения здесь

В этот пост есть другие варианты, но мы не можем понять, как это сделать должным образом.

Чтение событий выполняется с помощью

Function Get-WinEventDataHC {
    Param (
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [System.Diagnostics.Eventing.Reader.EventLogRecord[]]$Event
    )

    Process {
        foreach ($E in $Event){
            $XML = [XML]$E.ToXml()

            # Some events use other nodes, like 'UserData' on Applocker events...
            $XMLData = $null
            if ($XMLData = @($XML.Event.EventData.Data)){
                For ($i=0; $i -lt $XMLData.count; $i++){
                    $Params = @{
                        InputObject       = $E
                        NotePropertyName  = $EventXML.Event.EventData.Data[$i].Name
                        NotePropertyValue = $EventXML.Event.EventData.Data[$i].’#text’
                    }
                    Add-Member @Params
                }
            }

            $E
        }
    }
}
Get-WinEvent -ProviderName 'Test (Brecht)' | Select-Object -First 1 | Get-WinEventDataHC | fl *

Благодарим вас за помощь.

Ответ 1

Я нашел два возможных решения вопроса "Как это сделать с PowerShell?". Первый включает пользовательский метод PowerShell и использование системных сборок для записи в журнал событий. Второй включает в себя реализацию собственного провайдера. Следует отметить, что это не хранит XML в узле <Data>. Хранит данные в независимых элементах.

Метод 1: Пользовательская функция PowerShell

Эта методология взята из статьи, написанной Кевином Холменом. Его объяснение является выдающимся. Я продублировал здесь код, поэтому ответ здесь будет полным.

  1. Определите журнал событий и источник, который вы хотите регистрировать, загрузите сборку System.Diagnostics.EventLog и, наконец, создайте функцию CreateParamEvent которая будет записывать в журнал событий с конкретными параметрами.

    #Define the event log and your custom event source
    $evtlog = "Application"
    $source = "MyEventSource"
    
    #Load the event source to the log if not already loaded.  This will fail if the event source is already assigned to a different log.
    if ([System.Diagnostics.EventLog]::SourceExists($source) -eq $false) {
        [System.Diagnostics.EventLog]::CreateEventSource($source, $evtlog)
    }
    
    #function to create the events with parameters
    function CreateParamEvent ($evtID, $param1, $param2, $param3)
      {
        $id = New-Object System.Diagnostics.EventInstance($evtID,1); #INFORMATION EVENT
        #$id = New-Object System.Diagnostics.EventInstance($evtID,1,2); #WARNING EVENT
        #$id = New-Object System.Diagnostics.EventInstance($evtID,1,1); #ERROR EVENT
        $evtObject = New-Object System.Diagnostics.EventLog;
        $evtObject.Log = $evtlog;
        $evtObject.Source = $source;
        $evtObject.WriteEvent($id, @($param1,$param2,$param3))
      }
    
  2. Следующим шагом будет настройка параметров, которые вы хотите записать в журнал, и вызов функции.

    #These are just examples to pass as parameters to the event
    $hostname = "computername.domain.net"
    $timestamp = (get-date)
    
    #Command line to call the function and pass whatever you like
    CreateParamEvent 1234 "The server $hostname was logged at $timestamp" $hostname $timestamp 
    

Способ 2: пользовательский поставщик событий

Эта методология взята из статьи, написанной Дэниелом Гордоном. Я немного усложнил его пример и предоставил источник и инструкции в этом репозитории GitHub.

  1. Ключевым элементом данных, который вам нужно предоставить, является Манифест поставщика событий. Этот манифест содержит сведения о новом поставщике событий. И, самое главное, пользовательская полезная нагрузка мероприятия. Важным элементом в этом файле является элемент <templates>. Он определяет поля, которые в конечном итоге превратятся в элементы <Data> в полезной нагрузке вашего события.
    <?xml version="1.0" encoding="UTF-8"?>
    <instrumentationManifest xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd"
        xmlns="http://schemas.microsoft.com/win/2004/08/events"
        xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xs="http://www.w3.org/2001/XMLSchema" 
         xmlns:trace="http://schemas.microsoft.com/win/2004/08/events/trace">
        <instrumentation>
            <events>
                <provider name="CustomProvider"
                     symbol="CustomProvider"
                     guid="{10ABB82A-BB5A-45FF-A7D6-D7369B235DD8}"
                     resourceFileName="C:\CustomProvider\CustomProvider.dll"
                     messageFileName="C:\CustomProvider\CustomProvider.dll">  
                    <events>
                        <event symbol="CustomEvent" value="10000" version="1" channel="CustomProvider/Log" template="CustomTemplate" />
                    </events>
                    <levels/>
                    <tasks/>
                    <opcodes/>
                    <channels>
                        <channel name="CustomProvider/Log" value="0x10" type="Operational" enabled="true" />
                    </channels>
                    <templates>
                        <template tid="CustomTemplate">
                            <data name="MyKey1" inType="win:UnicodeString" outType="xs:string" />
                        </template>
                    </templates>
                </provider>
            </events>
        </instrumentation>
        <localization/>
     </instrumentationManifest>
  1. После создания манифеста нам нужно скомпилировать и установить провайдер на компьютере. Я сохранил свой манифест как CustomProvider.man в C:\CustomProvider\. Если вы не следуете этому соглашению, вам придется обновить пути в CustomProvider.man. После сохранения откройте командную строку Visual Studio от имени администратора и перейдите к C:\CustomProvider

enter image description here

  1. Скомпилируйте манифест, выполнив: mc -css Namespace CustomProvider.man

enter image description here

  1. Создайте файл ресурса, выполнив: rc CustomProvider.rc

enter image description here

  1. Скомпилируйте источник: csc/target:library/unsafe/win32res:CustomProvider.res CustomProvider.cs

enter image description here

  1. Зарегистрируйте провайдера, выполнив. wevtutil im CustomProvider.man

enter image description here

  1. Теперь вы увидите пользовательский поставщик в средстве просмотра событий Windows

    enter image description here

  2. Чтобы записать в журнал, откройте окно Windows Powershell и выполните

    New-WinEvent -ProviderName CustomProvider -Id 10000 -Payload @("MyValue1") 
    

    затем обновите журнал событий, и вы увидите событие.

enter image description here

enter image description here