WMI在C#中无效查询,但在wbemtest实用程序中有效



我正在尝试创建一个WQLEventQuery,以便在C#小程序中运行,每当在指定文件夹中创建新文件夹时,该小程序就会触发。我以前使用过WMI,我对它的工作原理很熟悉。当将新文件添加到特定文件夹时,我成功地创建了相同类型的事件查询。奇怪的是,我在调试中运行小程序时会遇到异常,但如果我使用相同的查询并从内置在窗口中的"wbemtest"实用程序中运行它,则在删除Within子句时不会抛出"无效查询"。但是,如果我没有在C#代码中的WQLEventQuery对象上设置WithinInterval属性,则会引发与所需轮询间隔相关的不同异常。以下是一些上下文代码片段:

FolderMonitor.cs

using System;
using System.Configuration;
using System.Management;
using MyProject.core.interfaces;
namespace MyProject.monitor.WmiEventMonitors
{
public class FolderMonitor : IWQLMonitor
{
private const string _eventClassName = "__InstanceCreationEvent";
private const string _isaType = "Win32_SubDirectory";
private readonly IEventListenerManager _eListenerManager;
private readonly IFileProcessService _fileProcessService;
public WqlEventQuery Query { get; }
public string Path { get; }
public FolderMonitor(string path, IEventListenerManager eListenerManager, IFileProcessService fileProcessService)
{
_eListenerManager = eListenerManager;
_fileProcessService = fileProcessService;
if (string.IsNullOrEmpty(path))
path = GetConfiguredDirectory();
Path = path;
var queryParamPath = path.Replace(@"", @"\");
//Query = new WqlEventQuery();
//Query.QueryString = $@"Select * From {_eventClassName} Within 1 Where TargetInstance Isa '{_isaType}' And TargetInstance.GroupComponent = 'Win32_Directory.Name={queryParamPath}'";
Query = new WqlEventQuery
{
EventClassName = _eventClassName,
Condition = $"TargetInstance isa '{_isaType}' And TargetInstance.GroupComponent = 'Win32_Directory.Name={queryParamPath}'"
WithinInterval = new TimeSpan(0,5,0)
};
}
public void HandleEvent(object sender, EventArrivedEventArgs e)
{
// when a new subfolder is created:
// 1) Log it somewhere?
// 2) Create a new WMI listener for that subfolder to detect file creation
string newDirPath = null;
try
{
foreach (PropertyData pd in e.NewEvent.Properties)
{
if (pd.Name != "TargetInstance") continue;
ManagementBaseObject mbo;
if ((mbo = pd.Value as ManagementBaseObject) != null)
{
using (mbo)
{
var newSubDir = mbo.Properties["PartComponent"];
var newDir = newSubDir.Value as ManagementBaseObject;
newDirPath = $"{newDir.Properties["Drive"].Value}{newDir.Properties["Path"].Value}";
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
throw;
}
if (!string.IsNullOrEmpty(newDirPath))
{
var newFileMonitorEvent = new FileMonitor(newDirPath, _fileProcessService);
_eListenerManager.Add(newFileMonitorEvent);
}
}

private static string GetConfiguredDirectory()
{
return ConfigurationManager.AppSettings["Directory"].Trim();
}
}
}

我的活动注册类

using System;
using System.Management;
using MyProject.monitor.WmiEventMonitors;
namespace MyProject.monitor
{
public interface IFileMonitorEventRegistrar
{
ManagementEventWatcher RegisterEventListener(IWQLMonitor newMonitorCandidate);
bool UnregisterEventListener(ManagementEventWatcher listener);
}
public class FileMonitorEventRegistrar : IFileMonitorEventRegistrar
{
public ManagementEventWatcher RegisterEventListener(IWQLMonitor newMonitorCandidate)
{
var scope = WmiUtility.GetConnectionScope();
ManagementEventWatcher watcher = null;
try
{
watcher = new ManagementEventWatcher(scope, newMonitorCandidate.Query);
watcher.EventArrived += new EventArrivedEventHandler(newMonitorCandidate.HandleEvent);
watcher.Start();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
throw;
}
return watcher;
}
public bool UnregisterEventListener(ManagementEventWatcher listener)
{
listener.Stop();
listener.Dispose();
return true;
}
}
}

我的WMI实用程序类

using System;
using System.Management;
namespace MyProject.monitor
{
public static class WmiUtility
{
private static ManagementScope _connectionScope;
private static ConnectionOptions _connectionOptions;

public static ManagementScope GetConnectionScope()
{
EstablishConnection(null, null, null, Environment.MachineName);
return _connectionScope;
}

private static ConnectionOptions SetConnectionOptions()
{
return new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.Default,
EnablePrivileges = true
};
}

private static ManagementScope SetConnectionScope(string machineName, ConnectionOptions options)
{
ManagementScope connectScope = new ManagementScope();
connectScope.Path = new ManagementPath(@"\" + machineName + @"rootCIMV2");
connectScope.Options = options;
try
{
connectScope.Connect();
}
catch (ManagementException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
throw;
}
return connectScope;
}

private static void EstablishConnection(string userName, string password, string domain, string machineName)
{
_connectionOptions = SetConnectionOptions();
if (domain != null || userName != null)
{
_connectionOptions.Username = domain + "\" + userName;
_connectionOptions.Password = password;
}
_connectionScope = SetConnectionScope(machineName, _connectionOptions);
}
}
}

我的EventQuery Manager类

using System;
using System.Collections.Generic;
using System.Management;
using MyProejct.monitor.WmiEventMonitors;
namespace MyProject.monitor
{
public interface IEventListenerManager : IDisposable
{
IDictionary<string, ManagementEventWatcher> RegisteredEvents { get; }
bool Add(IWQLMonitor eListener);
bool Remove(string monitoredPath);
}
public class EventListenerManager : IEventListenerManager
{
private bool _disposed;
private readonly IFileMonitorEventRegistrar _eventRegistrar;
public IDictionary<string, ManagementEventWatcher> RegisteredEvents { get; }

public EventListenerManager(IFileMonitorEventRegistrar eventRegistrar)
{
_eventRegistrar = eventRegistrar;
RegisteredEvents = new Dictionary<string, ManagementEventWatcher>();
}

public bool Add(IWQLMonitor eListener)
{
RegisteredEvents.Add(eListener.Path, _eventRegistrar.RegisterEventListener(eListener));
return true;
}
public bool Remove(string monitoredPath)
{
if (RegisteredEvents.ContainsKey(monitoredPath))
{
_eventRegistrar.UnregisterEventListener(RegisteredEvents[monitoredPath]);
return RegisteredEvents.Remove(monitoredPath);
}
return true;
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
foreach (var item in RegisteredEvents)
{
Remove(item.Key);
}
}
_disposed = true;
}
}

public void Dispose()
{
Dispose(true);
}
}
}

配器类

using System;
using System.Configuration;
using System.IO;
using System.Linq;
using MyProejct.monitor.WmiEventMonitors;
using MyProject.core.interfaces;
namespace MyProject.monitor
{
public interface IFileMonitorService : IDisposable
{
void Initialize();
}
public class FileMonitorService : IFileMonitorService
{
private bool _disposed;
private readonly IEventListenerManager _eventListenerManager;
private readonly IFileMonitorEventRegistrar _eventRegistrar;
private readonly IFileProcessService _fileProcessService;
private string _parentDirectory;
public FileMonitorService(IFileMonitorEventRegistrar eventRegistrar, IFileProcessService fileProcessService)
{
_eventRegistrar = eventRegistrar;
_fileProcessService = fileProcessService;
_eventListenerManager = new EventListenerManager(_eventRegistrar);
}

public void Initialize()
{
if (string.IsNullOrEmpty(_parentDirectory))
_parentDirectory = ConfigurationManager.AppSettings["SFTPDirectory"].Trim();
if (!_eventListenerManager.RegisteredEvents.Any())
{
GenerateFileEventListeners();
GenerateParentFolderListener();
}
}
public void GenerateFileEventListeners()
{
if (!Directory.Exists(_parentDirectory))
return;
var foldersToMonitor = Directory.EnumerateDirectories(_parentDirectory);
foreach (var folderPath in foldersToMonitor)
{
// Create a listener
var fileMonitor = new FileMonitor(folderPath, _fileProcessService);
_eventListenerManager.Add(fileMonitor);
}
}
public void GenerateParentFolderListener()
{
var folderMonitor = new FolderMonitor(_parentDirectory, _eventListenerManager, _fileProcessService);
_eventListenerManager.Add(folderMonitor);
}
public virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_eventListenerManager.Dispose();
_parentDirectory = null;
}
_disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
}

因此,查询字符串本质上是"从1中的__InstanceCreationEvent中选择*,其中TargetInstance是'Win32_SubDirectory',TargetInstance.GroupComponent='Win32_Directory.Name=C:\\MonitoredDocs'">

如果使用该查询字符串并删除within子句,wbemtest将其作为有效的WMI查询接受。当内部子句存在时,它表示这是一个无效的查询。我用的是这篇文章的答案。如果您能帮助我们了解如何让这个WQL事件查询工作,我们将不胜感激。

所以我仔细阅读了上面发布的文章,并找到了一个实际有效的替代查询。查询字符串如下所示:

选择*From __InstanceCreationEvent Within 1其中TargetInstance Isa为Win32_Directory和TargetInstance.Drive='C:和TargetInstance.Path='\\Path\\to\\monitored\\Directory\\'

*一个可能令人困惑的细节是,路径值必须包含尾随的"\\">

在代码方面,我修改后的FolderMonitor.cs类如下所示:(用*!*!*标记的更改)

public class FolderMonitor : IWQLMonitor
{
private const string _eventClassName = "__InstanceCreationEvent";
*!*!*private const string _isaType = "Win32_Directory";*!*!*
private readonly IEventListenerManager _eListenerManager;
private readonly IFileProcessService _fileProcessService;
public WqlEventQuery Query { get; }
public string Path { get; }
public FolderMonitor(string path, IEventListenerManager eListenerManager, IFileProcessService fileProcessService)
{
_eListenerManager = eListenerManager;
_fileProcessService = fileProcessService;
if (string.IsNullOrEmpty(path))
path = GetConfiguredDirectory();
Path = path;
*!*!*var drive = Path.Substring(0, 2);*!*!*
*!*!*var queryPath = Path.Substring(2) + @"";*!*!*
var queryParamPath = queryPath.Replace(@"", @"\");
Query = new WqlEventQuery
{
EventClassName = _eventClassName,
*!*!*Condition = $"TargetInstance Isa '{_isaType}' And TargetInstance.Drive = '{drive}' And TargetInstance.Path = '{queryParamPath}'",*!*!*
WithinInterval = new TimeSpan(0,0,1)
};
} 
}

相关内容

最新更新