Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm trying to replicate the following from the Event Viewer:

enter image description here

I'm having trouble with a few things.

  1. Some of the names I get back are not the display names or friendly names. For example, for "Microsoft Office Alerts" I just get back "OAlerts". How can I get the full "Microsoft Office Alerts" from "OAlerts"?
  2. Figuring out the hierarchy. It seems all I can do is parse out the dashes and do some sort of a best guess. There doesn't seem to be an easy way in the API to figure it out. The GetLogNames just gives you a flat list of all the logs

    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);
    }  
    
like image 288
Mark Avatar asked Jun 06 '16 16:06

Mark


1 Answers

This blog here: The EventSource NuGet package and support for the Windows Event Log (Channel Support) has a link to a rare EventSource User's Guide document that states this:

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>”.

Which tends to indicate the dashes are more a convention than a strict requirement (So I believe you can parse it by yourself). Note the blog is still open for comments.

As for names that don't match, there is an undocumented EvtIntGetClassicLogDisplayName function that can get you the name displayed in Event Viewer. Here is how to use it with a session and a log name:

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

And here is the support code (since it's undocumented, use at your own risks, plus it seems to be useful mostly for this 'OAlert' entry, so I'm not sure it's worth it):

    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);
like image 190
Simon Mourier Avatar answered Oct 13 '22 22:10

Simon Mourier