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

C# 如何使用WMI导出特定源的Windows事件日志?,c#,.net,wmi,event-log,C#,.net,Wmi,Event Log,我试图使用WMI类导出Windows事件日志的应用程序分支,但仅对特定源进行筛选。(否则,日志包含太多不必要的信息。) 例如,我需要导出包含MSSQL$SQLSRVR2012的所有记录: 我这样做: using System.Management; static void Main(string[] args) { BackupEventLogFilterBySource("Application", "MSSQL$SQLSRVR2012", @"C:\Use

我试图使用WMI类导出Windows事件日志的
应用程序
分支,但仅对特定源进行筛选。(否则,日志包含太多不必要的信息。)

例如,我需要导出包含
MSSQL$SQLSRVR2012
的所有记录:

我这样做:

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");
            }
        }
    }
但该查询失败,出现以下异常:

“System.Management.ManagementException”类型的未处理异常 发生在System.Management.dll中

其他信息:无效查询


那么我做错了什么呢?

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

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

此修改的方法使用
Win32\u NTLogEvent
而不是
Win32\u NTEventLogFile

我认为它更直接地指向目标。
由于我提到的原因,查询使用像“%parameter%”这样的
来过滤源代码。但是,可以使用原始方法通过
LogFileName
过滤器提取所有源名称,并分析
sources{}
数组的内容


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

注意:可以使用

公共类WinLogEvent
{
公共字符串ComputerName{get;set;}
公共字符串日志名{get;set;}
公共字符串消息{get;set;}
公共字符串源{get;set;}
公共UInt16事件代码{get;set;}
公共uint事件标识符{get;set;}
公共字符串事件类型{get;set;}
公共uint记录编号{get;set;}
public DateTime?TimeGenerated{get;set;}
公共日期时间?时间记录{get;set;}
公共字节[]数据{get;set;}
公共字符串[]插入字符串{get;set;}
}
私有静态枚举选项GetEnumerationOptions(布尔深度扫描)
{
var mOptions=新枚举选项()
{
Rewindable=false,//仅向前查询=>无缓存
return立即=true,//伪异步结果
DirectRead=true,
枚举深度=深度扫描
};
返回运动;
}
私有静态连接选项GetConnectionOptions(字符串用户名、字符串密码、字符串域)
{
var connpoptions=新连接选项()
{
EnablePrivileges=true,
超时=ManagementOptions.InfiniteTimeout,
身份验证=AuthenticationLevel.PacketPrivacy,
模拟=模拟级别。默认值,
用户名=用户名,
密码=密码,
//Authority=“NTLMDOMAIN:[域]”
Authority=!string.IsNullOrEmpty(域)?$“NTLMDOMAIN:{Domain}”:string.Empty
};
返回选项;
}
公共静态列表BackupEventLogFilterBySource(字符串logName,字符串sourceName)
{
List logEvents=新列表();
var connpoptions=GetConnectionOptions(null,null,null);
var options=GetEnumerationOptions(false);
var scope=new ManagementScope(@“\\”+Environment.MachineName+@“\root\CIMV2”,connOptions);
scope.Connect();
var query=new SelectQuery(“从Win32\u NTLogEvent中选择*);
query.Condition=$“Logfile='{logName}'和SourceName类似'{SourceName}%'”;
使用(ManagementObjectSearcher-moSearch=新的ManagementObjectSearcher(范围、查询、选项))
{
foreach(moSearch.Get()中的ManagementObject事件日志)
{
ManagementBaseObject inParams=eventLog.GetMethodParameters(“BackupEventlog”);
inParams[“ArchiveFileName”]=@“D:\exp.evtx”;
ManagementBaseObject outParams=eventLog.InvokeMethod(“BackupEventLog”,inParams,null);
var res=outParams.Properties[“ReturnValue”].Value;
添加(新的WinLogEvent
{
ComputerName=eventLog.GetPropertyValue(“ComputerName”)?.ToString(),
LogName=eventLog.GetPropertyValue(“日志文件”)?.ToString(),
Source=eventLog.GetPropertyValue(“SourceName”)?.ToString(),
EventCode=(UInt16?)eventLog.GetPropertyValue(“EventCode”)??0,
EventIdentifier=(uint?)eventLog.GetPropertyValue(“EventIdentifier”)??0,
EventType=eventLog.GetPropertyValue(“类型”)?.ToString(),
RecordNumber=(uint?)eventLog.GetPropertyValue(“RecordNumber”)??0,
TimeGenerated=ManagementDateTimeConverter.ToDateTime(eventLog.GetPropertyValue(“TimeGenerated”)?.ToString(),
TimeLogged=ManagementDateTimeConverter.ToDateTime(eventLog.GetPropertyValue(“TimeWrited”)?.ToString(),
Message=eventLog.GetPropertyValue(“Message”)?.ToString(),
InsertionString=(string[])eventLog.GetPropertyValue(“InsertionString”)??空,
数据=(字节[])eventLog.GetPropertyValue(“数据”)??空,
});
inParams.Dispose();
outParams.Dispose();
}
}
返回日志事件;
}//BackupEventLogFilterBySource

在查询中,必须将
替换为
源名称
。为了获得正确的WMI查询,请使用
wbemtest
,它将准确地让您知道要查询的字段。

我不确定,但是,如果您阅读了此文档:它说
Sources
是一个字符串数组type@FaizanRabbani:是的,我也看到了。虽然我不知道那是什么意思?这并不是真的让人感到惊讶
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