如何在 C# 中获取所有 Windows 事件日志(事件查看器日志)及其层次结构和友好名称的列表

How to get a list of all Windows Event Logs (Event Viewer Logs) with their hierarchy and friendly names in C#

我正在尝试从事件查看器中复制以下内容:

我遇到了一些问题。

  1. 我取回的一些名称不是显示名称或友好名称。例如,对于 "Microsoft Office Alerts" 我只是返回 "OAlerts"。我怎样才能从 "OAlerts" 得到完整的 "Microsoft Office Alerts"?
  2. 找出层次结构。看来我所能做的就是解析破折号并做出某种最佳猜测。 API 中似乎没有简单的方法来解决这个问题。 GetLogNames 只是为您提供所有日志的简单列表

    EventLogSession session = new EventLogSession();
    List<string> logNames = new List<string>(session.GetLogNames());
    foreach (string name in logNames)
    {
        //EventLogConfiguration config = new EventLogConfiguration(name); //looks useful but doesn't give me any of the info i'm looking for.
    
       Console.WriteLine(name);
    }  
    

此博客位于此处:The EventSource NuGet package and support for the Windows Event Log (Channel Support) has a link to a rare EventSource User's Guide 说明此内容的文档:

Do use the EventSourceAttribute’s Name property to provide a descriptive, qualified name for the ETW event provider represented by your event source. The default is the short name of your event source type, which can easily lead to collisions, as ETW provider names share one machine-wide namespace. An example of a good provider name “<CompanyName>-<Product>-<Component>”. Following this 3-element convention will ensure Event Viewer displays your event logs in a logical folder hierarchy: “Application and Services Logs/<CompanyName>/<Product>/<Component>”.

这往往表明破折号更多的是一种约定而非严格的要求(所以我相信你可以自己解析它)。请注意,该博客仍开放征求意见。

至于不匹配的名称,有一个未记录的 EvtIntGetClassicLogDisplayName 函数可以让您在事件查看器中显示名称。以下是如何将它与会话和日志名称一起使用:

    static void Main(string[] args)
    {
        var session = new EventLogSession();
        foreach (string name in session.GetLogNames())
        {
            Console.WriteLine(GetDisplayName(session, name));
        }
    }

这是支持代码(因为它没有记录,使用风险自负,而且它似乎主要用于这个 'OAlert' 条目,所以我不确定它是否值得):

    public static string GetDisplayName(EventLogSession session, string logName)
    {
        var sb = new StringBuilder(512);
        int bufferUsed = 0;
        if (EvtIntGetClassicLogDisplayName(GetSessionHandle(session).DangerousGetHandle(), logName, 0, 0, sb.Capacity, sb, out bufferUsed))
            return sb.ToString();

        return logName;
    }

    private static SafeHandle GetSessionHandle(EventLogSession session)
    {
        return (SafeHandle)session.GetType().GetProperty("Handle", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(session);
    }

    [DllImport("wevtapi.dll", CharSet = CharSet.Unicode)]
    private static extern bool EvtIntGetClassicLogDisplayName(IntPtr session, [MarshalAs(UnmanagedType.LPWStr)] string logName, int locale, int flags, int bufferSize, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder displayName, out int bufferUsed);