2017-04-24 52 views
10

最近我们添加了所有脚本的选项,以便在Windows事件日志中记录他们的消息。这对于短消息非常适用,但我们似乎无法找到一种以结构化方式保存事件的方式,因此我们可以稍后使用它们创建对象。如何在Windows事件日志中存储对象?

可以存储多个对象根据企业的性质事件的一个例子: Service Control Manager

这是如何使用PowerShell做了什么?

我们试过下面所描述的here但没有运气:

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

enter image description here

this post其它选项描述的也有,但我们似乎无法弄清楚如何做到这一点正常。

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 * 

谢谢您的帮助:

读活动与完成。

+0

我_suppose_的问题是,你在做什么,并没有定义的模式也许匹配吗?它是否必须是您存储的XML?你可以很容易地在这里工作JSON或其他基于文本的对象结构。我不太了解XML,但也许可以让它忽略模式?或许这与它无关,在这种情况下,我的不好。 – Matt

+0

它不一定是XML,但是它是Windows事件日志使用的标准。我们是否选择使用别的东西,可能是因为消息没有在GUI中正确显示。 XML通常只在Event的XML详细信息窗格中可见。 – DarkLite1

回答

2

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

方法1:自定义的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)) 
        } 
    
  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:自定义事件提供

这种方法来形成由Daniel Gordon撰写的文章中,我已经减少了一些他的榜样的复杂性,并在此GitHub Repository提供的源和说明

  1. 您需要提供的关键数据是事件提供程序M anifest。该清单包含新事件提供者的详细信息。而且,最重要的是,事件的自定义有效载荷。该文件中至关重要的元素是<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> 
    
  2. 一旦清单被创建,我们需要在计算机上编译和安装提供程序。我在C:\CustomProvider\保存我的清单为CustomProvider.man。如果您不遵循此惯例,则必须更新CustomProvider.man中的路径。一旦保存,打开Visual Studio命令提示为管理员和cd到C:\ CustomProvider

enter image description here

  • 通过执行编译清单:mc -css Namespace CustomProvider.man
  • enter image description here

  • 通过执行创建的资源文件:rc CustomProvider.rc
  • enter image description here

  • 编译源:csc /target:library /unsafe /win32res:CustomProvider.res CustomProvider.cs
  • enter image description here

  • 通过执行注册提供程序。 wevtutil im CustomProvider.man
  • enter image description here

  • 现在你会看到在Windows事件自定义提供商观众

    enter image description here

  • 要写入日志,打开Windows Powershell提示符并执行New-WinEvent -ProviderName CustomProvider -Id 10000 -Payload @("MyValue1"),然后刷新事件日志,您将看到该事件。

  • enter image description here

    enter image description here

    +0

    Thx的详细解释。当试图远离Visio时,我尝试了方法1.这很好用,但似乎无法将属性名称与属性值一起存储。例如'MyKey1'='MyValue1',如上一张截图所示。此处的目标是稍后将信息恢复为对象。 – DarkLite1