Search code examples
c#.netwmievent-log

How to export Windows Event log for a specific source with WMI?


I'm trying to use Win32_NTEventLogFile WMI class to export the Applications branch of the Windows Event log, but filter it only for a specific source. (Otherwise the log contains too much unnecessary information.)

So, just as an example, say, I need to export all records that contain MSSQL$SQLSRVR2012:

enter image description here

I do this:

using System.Management;

    static void Main(string[] args)
    {
        BackupEventLogFilterBySource("Application", "MSSQL$SQLSRVR2012", @"C:\Users\User\Desktop\exp.evtx");
    }


    public static void BackupEventLogFilterBySource(String logName, String applicationName, String targetFile)
    {
        ManagementScope scope = new ManagementScope(@"\\.\root\cimv2");
        scope.Options.EnablePrivileges = true;
        scope.Options.Impersonation = ImpersonationLevel.Impersonate;

        ObjectQuery query = new ObjectQuery(
            String.Format("Select * from Win32_NTEventLogFile Where LogFileName='{0}' And Sources='{1}'",
                logName, applicationName)
        );

        using (ManagementObjectSearcher search = 
            new ManagementObjectSearcher(scope, query))
        {
            foreach (ManagementObject o in search.Get())
            {
                ManagementBaseObject inParams = o.GetMethodParameters("BackupEventlog");
                inParams["ArchiveFileName"] = targetFile;
                ManagementBaseObject outParams = o.InvokeMethod("BackupEventLog", inParams, null);
                var res = outParams.Properties["ReturnValue"].Value;

                Console.Write("result=" + res + "\n");
            }
        }
    }

But that query fails with the following exception:

An unhandled exception of type 'System.Management.ManagementException' occurred in System.Management.dll

Additional information: Invalid query

So what am I doing wrong here?


Solution

  • The internal name used to identify the Source may be different from what is presented in the Computer Management UI.
    For example, the Source Winlogon, internally is referenced as Microsoft-Windows-Winlogon.

    Also, there's a problem with the Sources parameter, since it's an array.

    This modified method uses Win32_NTLogEvent instead of Win32_NTEventLogFile.
    I think it goes more directly to the target.
    The query uses LIKE '%parameter%' to filter the Source, for the reason I mentioned. It's however possible to extract all the sources names using your original method with the LogFileName filter and analyse the content of the Sources { } array.


    The values extracted from the Log Source File are store in a List.
    You can use it's properties to create a report that looks like the one you see in Event Viewer.

    Note: The TimeGenerated and TimeLogged properties can be converted to DateTime using the ManagementDateTimeConverter .ToDateTime Method

    public class WinLogEvent
    {
        public string ComputerName { get; set; }
        public string LogName { get; set; }
        public string Message { get; set; }
        public string Source { get; set; }
        public UInt16 EventCode { get; set; }
        public uint EventIdentifier { get; set; }
        public string EventType { get; set; }
        public uint RecordNumber { get; set; }
        public DateTime? TimeGenerated { get; set; }
        public DateTime? TimeLogged { get; set; }
        public byte[] Data { get; set; }
        public string[] InsertionStrings { get; set; }
    }
    
    private static EnumerationOptions GetEnumerationOptions(bool deepScan)
    {
        var mOptions = new EnumerationOptions()
        {
            Rewindable = false,        //Forward only query => no caching
            ReturnImmediately = true,  //Pseudo-async result
            DirectRead = true,
            EnumerateDeep = deepScan
        };
        return mOptions;
    }
    
    private static ConnectionOptions GetConnectionOptions(string UserName, string Password, string Domain)
    {
        var connOptions = new ConnectionOptions()
        {
            EnablePrivileges = true,
            Timeout = ManagementOptions.InfiniteTimeout,
            Authentication = AuthenticationLevel.PacketPrivacy,
            Impersonation = ImpersonationLevel.Default,
            Username = UserName,
            Password = Password,
            //Authority = "NTLMDOMAIN:[domain]"
            Authority = !string.IsNullOrEmpty(Domain) ? $"NTLMDOMAIN:{Domain}" : string.Empty
        };
        return connOptions;
    }
    
    public static List<WinLogEvent> BackupEventLogFilterBySource(string logName, string sourceName)
    {
        List<WinLogEvent> logEvents = new List<WinLogEvent>();
    
        var connOptions = GetConnectionOptions(null, null, null);
        var options = GetEnumerationOptions(false);
        var scope = new ManagementScope(@"\\" + Environment.MachineName + @"\root\CIMV2", connOptions);
        scope.Connect();
    
        var query = new SelectQuery("SELECT * FROM Win32_NTLogEvent");
        query.Condition = $"Logfile='{logName}' AND SourceName LIKE '%{sourceName}%'";
    
        using (ManagementObjectSearcher moSearch = new ManagementObjectSearcher(scope, query, options))
        {
            foreach (ManagementObject eventLog in moSearch.Get())
            {
                ManagementBaseObject inParams = eventLog.GetMethodParameters("BackupEventlog");
                inParams["ArchiveFileName"] = @"D:\exp.evtx";
                ManagementBaseObject outParams = eventLog.InvokeMethod("BackupEventLog", inParams, null);
                var res = outParams.Properties["ReturnValue"].Value;
    
                logEvents.Add(new WinLogEvent
                {
                    ComputerName = eventLog.GetPropertyValue("ComputerName")?.ToString(),
                    LogName = eventLog.GetPropertyValue("Logfile")?.ToString(),
                    Source = eventLog.GetPropertyValue("SourceName")?.ToString(),
                    EventCode = (UInt16?)eventLog.GetPropertyValue("EventCode") ?? 0,
                    EventIdentifier = (uint?)eventLog.GetPropertyValue("EventIdentifier") ?? 0,
                    EventType = eventLog.GetPropertyValue("Type")?.ToString(),
                    RecordNumber = (uint?)eventLog.GetPropertyValue("RecordNumber") ?? 0,
                    TimeGenerated = ManagementDateTimeConverter.ToDateTime(eventLog.GetPropertyValue("TimeGenerated")?.ToString()),
                    TimeLogged = ManagementDateTimeConverter.ToDateTime(eventLog.GetPropertyValue("TimeWritten")?.ToString()),
                    Message = eventLog.GetPropertyValue("Message")?.ToString(),
                    InsertionStrings = (string[])eventLog.GetPropertyValue("InsertionStrings") ?? null,
                    Data = (byte[])eventLog.GetPropertyValue("Data") ?? null,
                });
                inParams.Dispose();
                outParams.Dispose();
            }
        }
        return logEvents;
    }   //BackupEventLogFilterBySource