如何在Windows事件日志中存储对象?

Dar*_*te1 11 powershell events logging

最近,我们为所有脚本添加了选项,以便在Windows事件日志中记录其消息.这对于短消息非常有用,但我们似乎无法找到以结构化方式保存事件的方法,以便以后可以使用它们创建对象.

可以存储多个对象属性的事件示例: 服务控制经理

如何使用PowerShell完成此操作?

我们已经尝试过如下所述,但没有运气:

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

在此输入图像描述

这篇文章中还有其他选项描述,但我们似乎无法弄清楚如何正确地做到这一点.

阅读事件的方法是:

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 *
Run Code Online (Sandbox Code Playgroud)

谢谢您的帮助.

Gra*_*per 5

我找到了两种可能的解决方案来解决“如何用 PowerShell 完成?”这个问题。第一个涉及自定义 PowerShell 方法并利用系统程序集写入事件日志。第二个涉及实现自定义提供程序。应该注意的是,这不会在<Data>节点中存储 XML 。它将数据存储在独立元素中。

方法一:自定义PowerShell函数

这种方法论来自Kevin Holman写的一篇文章, 他的解释非常出色。我在这里复制了代码,所以这里的答案将是完整的。

  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))
      }
    
    Run Code Online (Sandbox Code Playgroud)
  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 
    
    Run Code Online (Sandbox Code Playgroud)

方法 2:自定义事件提供程序

这种方法来自Daniel Gordon撰写的一篇文章, 我降低了他示例的一些复杂性,并在此GitHub 存储库中提供了源代码和说明

  1. 您需要提供的关键数据是事件提供程序清单。此清单包含新事件提供程序的详细信息。而且,最重要的是,事件的自定义负载。此文件中关键的<templates>元素是元素。它定义了最终将变成<Data>事件负载中元素的字段。
#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))
  }
Run Code Online (Sandbox Code Playgroud)
  1. 创建清单后,我们需要在计算机上编译和安装提供程序。我救了我的表现为CustomProvider.manC:\CustomProvider\。如果您不遵循此约定,则必须更新CustomProvider.man. 保存后,以管理员身份打开 Visual Studio 命令提示符并 cd 到 C:\CustomProvider

在此处输入图片说明

  1. 通过执行以下命令编译清单: mc -css Namespace CustomProvider.man

在此处输入图片说明

  1. 执行以下命令创建资源文件: rc CustomProvider.rc

在此处输入图片说明

  1. 编译源码: csc /target:library /unsafe /win32res:CustomProvider.res CustomProvider.cs

在此处输入图片说明

  1. 通过执行注册提供者。 wevtutil im CustomProvider.man

在此处输入图片说明

  1. 您现在将在 Windows 事件查看器中看到自定义提供程序

    在此处输入图片说明

  2. 要写入日志,请打开 Windows Powershell 提示符并执行

    New-WinEvent -ProviderName CustomProvider -Id 10000 -Payload @("MyValue1") 
    
    Run Code Online (Sandbox Code Playgroud)

    然后刷新事件日志,您将看到该事件。

在此处输入图片说明

在此处输入图片说明