如何获取Windows事件日志消息的模板

时间:2015-09-29 09:58:25

标签: c# windows event-log

我想阅读已归档的Windows事件日志文件(.evtx),如下例所示:

using System;
using System.Diagnostics.Eventing.Reader;

public static class Program {
    static void Main(string[] args) {
        using (var reader = new EventLogReader(@"C:\tmp\some-log.evtx", PathType.FilePath)) {
            EventRecord record;
            while ((record = reader.ReadEvent()) != null) {
                // do something with record...
            }
        }
    }
}

record对象有一个Properties列表,其中包含事件的替换字符串:

foreach (var property in record.Properties) {
    Console.WriteLine(property.Value);
}

如果我在事件日志查看器中打开.evtx文件,我可以看到该事件的完整描述,这类似于基本模板消息(应该来自与生成的应用程序关联的资源文件)事件),占位符的值替换为这些值:

enter image description here

有没有办法可以为特定事件获取此“消息模板”?

2 个答案:

答案 0 :(得分:1)

如果您在与保存事件日志不同的机器上检查事件日志,那么您将无法享受 EventLogSession.GlobalSession.GetProviderNames(),但前提是您可以找到并安装机器的 {{1} } 注册表配置单元(位于 HKEY_LOCAL_MACHINE 文件中 - 是的,它是一个无扩展名的文件)您可以从此注册表项中获取事件模板:

C:\Windows\System32\config\SYSTEM
  • 其中 HKEY_LOCAL_MACHINE\SYSTEM\{controlSet}\Services\EventLog\{eventLogName}\{providerName} 通常是“{controlSet}”,但如果您正在调查在神秘情况下死亡的机器,您可能需要查看其他键,例如 CurrentControlSet .

    • These "control set" names 参与“最后一次正确配置”引导选项、系统还原和 Windows 引导过程的其他部分。如果计算机无法正确启动,Windows 将尝试其他配置变体,这些变体具有自己单独的事件日志配置副本。
  • 其中 ControlSet001 是您正在查看的日志的名称。仅为单个目标日志注册事件源。

  • 其中 {eventLogName} 对应于 Windows 事件日志查看器中“事件源”列中的值。

查找名为 {providerName} 的注册表值,它为您提供包含 Win32 资源字符串的 Win32 PE(EventMessageFile*.exe)的路径,该字符串包含事件日志消息模板 - 您然后可以使用标准的 Win32 资源函数或其他一些库读取那些来提取 Win32 资源。

注意 reading event-logs without the message templates extracted from the EventMessageFile is an exercise in pain

答案 1 :(得分:0)

我后来发现那些“消息模板”可以读取与某个提供者相关的事件元数据(这基本上是一个注册的事件来源)。

以下是一个例子:

using System;
using System.Diagnostics.Eventing.Reader;
using System.Globalization;

public static class Program {

    static void Main(string[] args) {
        foreach (var providerName in EventLogSession.GlobalSession.GetProviderNames()) {
            DumpMetadata(providerName);
        }
    }

    private static void DumpMetadata(string providerName) {
        try {
            ProviderMetadata providerMetadata = new ProviderMetadata(providerName, EventLogSession.GlobalSession, CultureInfo.InvariantCulture);
            foreach (var eventMetadata in providerMetadata.Events) {
                if (!string.IsNullOrEmpty(eventMetadata.Description)) {
                    Console.WriteLine("{0} ({1}): {2}", eventMetadata.Id, eventMetadata.Version, eventMetadata.Description);
                }
            }
        } catch (EventLogException) {
            Console.WriteLine("Cannot read metadata for provider {0}", providerName);
        } 
    }
}