永久监控特定文件夹中文件创建的最有效和可靠的方法
Most Efficient and Reliable Way to Permanently Monitor File Creation in a Specific Folder
我需要监控文件夹并在每次创建文件时执行一些操作。我有 2 个解决方案 - 一个使用 WMI,我可以在其中使用此过滤器(从 .MOF
文件或注册永久 MWI 事件绑定的 Powershell 脚本调用)每秒轮询文件夹 :
SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Cim_DirectoryContainsFile" AND TargetInstance.GroupComponent="Win32_Directory.Name='C:\test'"
示例脚本:
$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
示例 MOF 文件:
#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;
};
这似乎是一个很好的方法,因为我可以自己设置时间间隔,而且使用 WMI 对我来说总是很安全,因为它本质上是 Windows 中的内置解决方案。
另一种方法是编写脚本,例如:
$folderpath = 'C:\test'
$items = Get-ChildItem $folderpath
$currentdatetime = Get-Date
foreach($item in $items) {
If ($item.CreationTime > $currentdatetime.AddSeconds(-5)){
# Do some action
}
}
然后可以 运行 在系统上作为计划任务。
我的问题是 - 这样做的最佳方法是什么?在我展示的 2 个选项中,就系统资源或潜在错误而言,其中一个在本质上更有效吗?
是否还有其他我没有考虑过的方法?
Jisaak 添加了一个使用 System.IO.FilesystemWatcher
的答案。不幸的是,这对我的目的来说并不理想,因为这只在执行它的 shell 打开时有效,而我想要一个更永久的解决方案(更新问题的标题以反映这一点)
您不想长时间轮询文件夹以获取文件更改,您应该使用一种机制,在文件创建时您会收到通知。
因此您可以使用 FileSystemWatcher
class and register to the created
event handler using the Register-ObjectEvent
cmdlet。
$folder = 'C:\test'
$filter = '*.*'
$fileSystemWatcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{
IncludeSubdirectories = $true # Set this according to your requirements.
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fileSystemWatcher Created -SourceIdentifier FileCreated -Action {
$path = $Event.SourceEventArgs.FullPath
Write-Host "File $Path was created".
}
运行 取消注册:
Unregister-Event -SourceIdentifier FileCreated
根据讨论 here,使用这些类型的事件时,似乎在可靠性或性能方面应该没有任何问题。
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.
他们还提到,虽然 PowerShell 可以使用大约 100MB 的空间来启动,但 WMI 事件监控却不能(VBScript 也不能——ActiveScriptEvent
操作的首选脚本语言)。
因为我似乎无法在其他任何地方找到关于此的任何信息(即 reliability/performance)我将不得不这样做,因此将使用 [= 实现我的文件夹监视器23=].
This 文章还提供了一些有用的信息,供任何寻求更多详细信息的人使用。它还建议 运行 这而不是一些连续的应用程序可以更好地利用系统资源,但是它没有提到这是否包括计划任务的使用。
我需要监控文件夹并在每次创建文件时执行一些操作。我有 2 个解决方案 - 一个使用 WMI,我可以在其中使用此过滤器(从 .MOF
文件或注册永久 MWI 事件绑定的 Powershell 脚本调用)每秒轮询文件夹 :
SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Cim_DirectoryContainsFile" AND TargetInstance.GroupComponent="Win32_Directory.Name='C:\test'"
示例脚本:
$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
示例 MOF 文件:
#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;
};
这似乎是一个很好的方法,因为我可以自己设置时间间隔,而且使用 WMI 对我来说总是很安全,因为它本质上是 Windows 中的内置解决方案。
另一种方法是编写脚本,例如:
$folderpath = 'C:\test'
$items = Get-ChildItem $folderpath
$currentdatetime = Get-Date
foreach($item in $items) {
If ($item.CreationTime > $currentdatetime.AddSeconds(-5)){
# Do some action
}
}
然后可以 运行 在系统上作为计划任务。
我的问题是 - 这样做的最佳方法是什么?在我展示的 2 个选项中,就系统资源或潜在错误而言,其中一个在本质上更有效吗?
是否还有其他我没有考虑过的方法?
Jisaak 添加了一个使用 System.IO.FilesystemWatcher
的答案。不幸的是,这对我的目的来说并不理想,因为这只在执行它的 shell 打开时有效,而我想要一个更永久的解决方案(更新问题的标题以反映这一点)
您不想长时间轮询文件夹以获取文件更改,您应该使用一种机制,在文件创建时您会收到通知。
因此您可以使用 FileSystemWatcher
class and register to the created
event handler using the Register-ObjectEvent
cmdlet。
$folder = 'C:\test'
$filter = '*.*'
$fileSystemWatcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{
IncludeSubdirectories = $true # Set this according to your requirements.
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fileSystemWatcher Created -SourceIdentifier FileCreated -Action {
$path = $Event.SourceEventArgs.FullPath
Write-Host "File $Path was created".
}
运行 取消注册:
Unregister-Event -SourceIdentifier FileCreated
根据讨论 here,使用这些类型的事件时,似乎在可靠性或性能方面应该没有任何问题。
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.
他们还提到,虽然 PowerShell 可以使用大约 100MB 的空间来启动,但 WMI 事件监控却不能(VBScript 也不能——ActiveScriptEvent
操作的首选脚本语言)。
因为我似乎无法在其他任何地方找到关于此的任何信息(即 reliability/performance)我将不得不这样做,因此将使用 [= 实现我的文件夹监视器23=].
This 文章还提供了一些有用的信息,供任何寻求更多详细信息的人使用。它还建议 运行 这而不是一些连续的应用程序可以更好地利用系统资源,但是它没有提到这是否包括计划任务的使用。