c# - 如何使用 WMI 导出特定来源的 Windows 事件日志?

标签 c# .net wmi event-log

我正在尝试使用 Win32_NTEventLogFile WMI 类导出 Windows 事件日志的 Applications 分支,但仅为特定源过滤它。 (否则日志包含太多不必要的信息。)

因此,举个例子,我需要导出包含 MSSQL$SQLSRVR2012 的所有记录:

enter image description here

我这样做:

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

但是该查询失败并出现以下异常:

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

Additional information: Invalid query

那么我做错了什么?

最佳答案

用于标识的内部名称可能与计算机管理 UI 中显示的名称不同。
例如,源代码 Winlogon,在内部被引用为 Microsoft-Windows-Winlogon

此外,Sources 参数也有问题,因为它是一个数组。

此修改后的方法使用 Win32_NTLogEvent 而不是 Win32_NTEventLogFile
我认为它更直接地达到了目标。
由于我提到的原因,查询使用 LIKE '%parameter%' 来过滤源。但是,可以使用带有 LogFileName 过滤器的原始方法提取所有源名称,并分析 Sources { } 数组的内容。


从日志源文件中提取的值存储在列表中。
您可以使用它的属性来创建类似于您在事件查看器中看到的报告。

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

关于c# - 如何使用 WMI 导出特定来源的 Windows 事件日志?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48972882/

相关文章:

c# - 如何找出分布式事务有什么问题?

.net - 如何使用 PowerShell 中的凭据从本地复制到远程位置?

c# - 如何使用 WMI 读取 IIS 6 网站的目录结构?

c# - 以编程方式创建共享失败并出现错误 9

c# - 方法中的类耦合警告

c# - 将 Ninject 与 ASP.NET MVC 和服务层结合使用

.net - System.BadImageFormatException 尝试加载格式不正确的程序

.net - .NET 中的异步 WMI 事件处理

c# - 如何获取在 C# 中使用给定文件名的 PID?

c# - 从荷兰语到英语的日期格式