I need to monitor a folder and perform some action each time a file is created. I have 2 solutions - one using WMI, where I can use this filter (called from either a .MOF
file or a Powershell script which registers permanent MWI event bindings) to poll the folder every second :
SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Cim_DirectoryContainsFile" AND TargetInstance.GroupComponent="Win32_Directory.Name='C:\\test'"
Example Script :
$query = @"
SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Cim_DirectoryContainsFile" AND TargetInstance.GroupComponent="Win32_Directory.Name='C:\\test'"
"@
#Set up hash table for splatting
$wmiParams = @{
Computername = $env:COMPUTERNAME
ErrorAction = 'Stop'
NameSpace = 'root\subscription'
}
######################################################################################################################### Filter
#Creating a new event filter
$wmiParams.Class = '__EventFilter'
$wmiParams.Arguments = @{
Name = 'WatchFiles'
EventNamespace = 'root\CIMV2'
QueryLanguage = 'WQL'
Query = $query
}
$filterResult = Set-WmiInstance @wmiParams
######################################################################################################################### Consumer
$wmiParams.Class = 'ActiveScriptEventConsumer'
$wmiParams.Arguments = @{
KillTimeout = 0
MachineName = $env:COMPUTERNAME
ScriptingEngine = 'VBScript'
ScriptText =
@"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("c:\test\Log.log", 8, True)
objFile.WriteLine "hellohellohellohellohellohello"
objFile.Close
"@
ScriptFileName = $null
Name = 'ActiveScriptEventConsumer'
}
$consumerResult = Set-WmiInstance @wmiParams
######################################################################################################################### Binding
$wmiParams.Class = '__FilterToConsumerBinding'
$wmiParams.Arguments = @{
Filter = $filterResult
Consumer = $consumerResult
}
$bindingResult = Set-WmiInstance @wmiParams
Example MOF File :
#PRAGMA AUTOREOVER
#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter
{
Name = "Event Filter Instance Name";
EventNamespace = "Root\\Cimv2";
Query = "Select * From __InstanceCreationEvent Within 1 "
"Where TargetInstance Isa \"Cim_DirectoryContainsFile\" "
"and TargetInstance.GroupComponent=\"Win32_Directory.Name=\'C:\\\\test\'\"";
QueryLanguage = "WQL";
};
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "TestConsumer";
ScriptingEngine = "VBScript";
ScriptFileName = "C:\\test\\test.vbs"
};
instance of __FilterToConsumerBinding
{
Filter = $EventFilter;
Consumer = $Consumer;
};
This seems like a good way of doing it, as I can set the interval myself, and working with WMI always feels safe to me as it is essentialy a built in solution in Windows.
Another way of doing this would be to write a script, something like :
$folderpath = 'C:\test'
$items = Get-ChildItem $folderpath
$currentdatetime = Get-Date
foreach($item in $items) {
If ($item.CreationTime > $currentdatetime.AddSeconds(-5)){
# Do some action
}
}
Which can then be run on the system as a scheduled task.
My question is - what is the best way of doing this? Of the 2 options I have shown, is one of them inherently more efficient in terms of system resources or potential for errors?
Are there any other ways of doing this which I have not considered?
Jisaak added an answer which uses System.IO.FilesystemWatcher
. Unfortunately this is not ideal for my purposes, as this only works while the shell which executed it is open, whereas I would like a more permanent solution (updated the title of the question to reflect this)
Based on the discussion here, it would seem that there shouldn't be any issues in terms of reliability or performance when using these types of events.
The impact of the ActiveScript consumer is trivial. If you do not create an event that fires continuously then the event is innocuous. I have used thises vevents for almosttwo decades without issue when designed correctly.
The WQL event filter DOES NOT POLL. It use SENS events to generate a response. SENS has been part of Windows since at least W2K. It is based in the kernel. A great amount of Windows is based on SENS.
They also mention that while PowerShell can use around 100MB to start up, WMI event monitoring does not (and neither does VBSCript - the preferred scripting language for ActiveScriptEvent
actions).
As I can't seem to find any information about this anywhere else (that is in terms of reliability/performance) I will have to go by this, and so will be implementing my folder monitor using WMI/WQL/MOF.
This article also has some useful information for anyone looking for more details. It also suggests that running this instead of some continuous application is a better use of system resources, however it doesn't mention whether this includes the use of scheduled tasks.