2016-04-27 35 views
2

我需要监控一个文件夹并在每次创建文件时执行一些操作。我有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 
    } 
} 

然后可以在系统上作为计划任务运行。

我的问题是 - 这样做的最好方法是什么?在我已经展示的两个选项中,其中一个在系统资源或错误潜在性方面本质上更高效?

有没有其他方法可以做到这一点,我没有考虑过?


Jisaak添加了一个使用System.IO.FilesystemWatcher的答案。不幸的是,这对于我的目的并不理想,因为这只适用于执行它的shell是开放的,而我想要一个更持久的解决方案(更新问题的标题以反映这一点)

回答

1

根据讨论here,它似乎是使用这些类型的事件时,不应该有在可靠性和性能方面的任何问题。

ActiveScript使用者的影响是微不足道的。如果你没有创建一个连续发射的事件,那么这个事件是无害的。设计正确时,我几乎用了二十年,没有任何问题。

WQL事件过滤器不是POLL。它使用SENS事件来生成响应。至少W2K以来,SENS一直是Windows的一部分。它基于内核。大量的Windows基于SENS。

他们还提到,尽管PowerShell中可以使用100MB左右启动,WMI事件监控不(而且也不VBSCRIPT - 首选脚本语言ActiveScriptEvent动作)。

由于我似乎无法在其他任何地方发现任何信息(即在可靠性/性能方面),我将不得不这样做,所以将使用WMI/WQL/MOF来实现我的文件夹监视器。

This文章还为任何寻找更多细节的人提供了一些有用的信息。它也表明,运行这个而不是一些连续的应用程序可以更好地利用系统资源,但是它没有提到这是否包括使用计划任务。

3

你不想要要长时间轮询文件夹以进行文件更改,您应该使用一种机制,其中在创建文件时收到通知

因此你可以使用FileSystemWatcher类和使用Register-ObjectEvent cmdlet的注册到created事件处理程序

$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 
+0

HI Jisaak感谢您的回答。你为什么认为使用FileSystemWatcher是一个更好的解决方案?这也需要建立一个计划任务,所以这不意味着有更多的维护?这样做有什么好处,以及长轮询文件夹有什么问题?当然,我可以在我的行动脚本中加入我的永久活动注册,以发送电子邮件或以某种方式通知我自己,而无需使用FileSystemWatcher再次感谢您的帮助! – Bassie

+1

那么,我没有研究任何性能,但我认为这是追踪目录变化的最有效方式。长时间轮询总是最糟糕的,你可以做。 –

+0

谢谢jisaak。我应该提到我已经使用了一个类似的方法,在shell中注册一个事件。不幸的是,这并不理想,因为它只能在执行脚本的shell保持打开的情况下持续。我上面发布的解决方案都注册了一个永久事件过滤器(即使PC重新启动也会继续运行),这就是为什么我正在查看这些方法。我更新了我的问题以反映这一要求。 – Bassie

相关问题