I am trying to create a WQLEventQuery to run in a C# applet that triggers whenever a new folder is created within a specified folder. I have used WMI before and I am familiar with how it works. I successfully created the same type of eventquery for when a new file is added to a specific folder. The weird part is that I get an exception when running the applet in debugging, but if I take the same query and run it from the 'wbemtest' utility built into windows, no 'invalid query' is thrown when I remove the Within clause. However, if I do not set the WithinInterval property on the WQLEventQuery object in C# code, a different exception is thrown related to the polling interval being required. Here are some Code snippets for context:
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();
}
}
}
My event registering class
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;
}
}
}
my WMI Utility class
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 + @"\root\CIMV2");
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);
}
}
}
my EventQuery Manager class
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);
}
}
}
the orchestrator class
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);
}
}
}
So the query string is essentially "select * from __InstanceCreationEvent within 1 where TargetInstance isa 'Win32_SubDirectory' And TargetInstance.GroupComponent = 'Win32_Directory.Name=C:\\MonitoredDocs'"
If take that query string and remove the within clause, wbemtest accepts it as a valid WMI query. When the within clause is present, it says it is an invalid query. I am using an answer from this article. Any help to figure out how to get this WQL Event Query to work would be appreciated.