2016-04-27 5 views
2

Мне нужно следить за папкой и выполнять какое-либо действие каждый раз, когда создается файл. У меня есть 2 решения - один с помощью WMI, где я могу использовать этот фильтр (так называемый либо из .MOF файла или сценарий Powershell, который регистрирует постоянные привязки событий MWI) опрашивать папку каждую секунду:Самый эффективный и надежный способ постоянного мониторинга создания файла в конкретной папке

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. К сожалению, это не идеально для моих целей, так как это работает только тогда, когда оболочка, которая его выполнила, открыта, тогда как я хотел бы получить более постоянное решение (обновил название вопроса, чтобы отразить это)

ответ

1

На основе обсуждения here, казалось бы, что там не должно быть никаких проблем с точки зрения надежности и производительности при использовании этих типов событий.

Влияние потребителя ActiveScript тривиально. Если вы не создаете событие, которое постоянно срабатывает, событие является безобидным. Я использовал это в течение почти двух десятилетий без проблем при правильном проектировании.

Фильтр событий WQL НЕ ОПЛАТ. Он использует события SENS для генерации ответа. SENS является частью Windows с по крайней мере W2K. Он основан на ядре. Большое количество Windows основано на SENS.

Они также отмечают, что в то время как PowerShell можно использовать около 100 Мб для запуска, мониторинга событий WMI не нет (и ни делает VBScript - предпочтительный язык сценариев для ActiveScriptEvent действий).

Поскольку я не могу найти какую-либо информацию об этом в другом месте (то есть с точки зрения надежности/производительности), мне придется это сделать, и так будет реализовывать мой монитор папок с использованием WMI/WQL/MOF ,

This статья также содержит полезную информацию для тех, кто ищет более подробную информацию. Он также предполагает, что использование этого вместо некоторого непрерывного приложения - лучшее использование системных ресурсов, однако в нем не упоминается, включает ли это использование запланированных задач.

3

Вы не хотите для длительного опроса папки для изменений файла, вы должны скорее использовать механизм, в котором вы получите уведомление, когда файл был создан.

Таким образом, вы можете использовать FileSystemWatcher класс и зарегистрировать в createdобработчик событий с помощью Register-ObjectEvent командлета.

$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. Я должен был упомянуть, что я уже использовал аналогичный метод, когда я регистрирую событие в оболочке. К сожалению, это не идеально, поскольку он длится только тогда, когда оболочка, выполняющая скрипт, остается открытой. В решениях, которые я разместил выше, зарегистрирован постоянный фильтр событий (который будет продолжать работать, даже если компьютер перезагружен), поэтому я рассматриваю эти методы. Я обновил свой вопрос, чтобы отразить это требование. – Bassie