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

How to get the template for a windows event log message

我想读取存档的 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 文件,我可以看到该事件的完整描述,类似于基本模板消息(应该来自与应用程序关联的资源文件生成事件的),并将占位符的值替换为这些值:

有什么方法可以让我在特定事件中得到这个 "message template" 吗?

我后来发现那些 "message templates" 可以读取与特定提供者关联的事件元数据(这基本上是事件的注册源)。

这是一个例子:

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);
        } 
    }
}

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

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

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

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

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

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