2016-04-27 11 views
2

Ich muss bei jeder Erstellung einer Datei einen Ordner überwachen und Aktionen ausführen. Ich habe 2 Lösungen - einen WMI verwenden, wo ich diese Filter verwenden kann (so genannten entweder von einer .MOF Datei oder einem Skript Powershell, die permanent MWI Ereignisbindungen registriert) den Ordner in jeder Sekunde abzufragen:Die effizienteste und zuverlässigste Möglichkeit, die Dateierstellung in einem bestimmten Ordner dauerhaft zu überwachen

SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Cim_DirectoryContainsFile" AND TargetInstance.GroupComponent="Win32_Directory.Name='C:\\test'" 

Beispielskript :

$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 

Beispiel MOF-Datei:

#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; 
}; 

Dies scheint eine gute Möglichkeit zu sein, da ich das Intervall selbst einstellen kann, und die Arbeit mit WMI fühlt sich für mich immer sicher an, da es eine eingebaute Lösung in Windows ist.

Ein anderer Weg, dies zu tun, wäre ein Skript zu schreiben, so etwas wie:

$folderpath = 'C:\test' 
$items = Get-ChildItem $folderpath 
$currentdatetime = Get-Date 

foreach($item in $items) { 
    If ($item.CreationTime > $currentdatetime.AddSeconds(-5)){ 
     # Do some action 
    } 
} 

, die dann auf dem System als eine geplante Aufgabe ausgeführt werden kann.

Meine Frage ist - was ist der beste Weg, dies zu tun? Von den 2 Möglichkeiten, die ich gezeigt habe, ist eine von ihnen von Natur aus effizienter in Bezug auf Systemressourcen oder das Potenzial für Fehler?

Gibt es andere Möglichkeiten, dies zu tun, die ich nicht berücksichtigt habe?


Jisaak hat eine Antwort hinzugefügt, die System.IO.FilesystemWatcher verwendet. Leider ist dies nicht ideal für meine Zwecke, da dies nur funktioniert, während die Shell, die es ausgeführt hat, offen ist, während ich eine dauerhafte Lösung möchte (aktualisiert den Titel der Frage, um dies zu reflektieren)

Antwort

1

Auf der Grundlage der Diskussion here, so scheint es, dass es keine Probleme in Bezug auf die Zuverlässigkeit oder Leistung sein sollte, wenn diese Art von Ereignissen verwendet wird.

Der Einfluss des ActiveScript-Verbrauchers ist trivial. Wenn Sie kein Ereignis erstellen, das kontinuierlich ausgelöst wird, ist das Ereignis harmlos. Ich habe diese Vevents für fast zwei Jahrzehnte ohne Probleme verwendet, wenn sie richtig entworfen wurden.

Der WQL-Ereignisfilter WIRD NICHT ABFRAGEN. Es verwendet SENS-Ereignisse, um eine Antwort zu generieren. SENS gehört seit mindestens W2K zu Windows. Es basiert im Kernel. Eine große Anzahl von Windows basiert auf SENS.

Sie erwähnen auch, dass, während Powershell um 100 MB starten kann, WMI-Ereignisüberwachung nicht (und auch nicht VBSCRIPT - die bevorzugte Skriptsprache für ActiveScriptEvent Aktionen).

Da ich nirgendwo anders Informationen darüber finden kann (das ist in Bezug auf Zuverlässigkeit/Leistung) muss ich damit gehen, und so werde ich meine Ordner-Monitor mit WMI/WQL/MOF implementieren .

This Artikel hat auch einige nützliche Informationen für jeden auf der Suche nach weiteren Details. Es schlägt auch vor, dass das Ausführen dieser anstelle einer kontinuierlichen Anwendung eine bessere Nutzung der Systemressourcen ist, es wird jedoch nicht erwähnt, ob dies die Verwendung geplanter Tasks einschließt.

3

Sie wollen nicht Um einen Ordner für Dateiänderungen lange abzufragen, sollten Sie lieber einen Mechanismus verwenden, bei dem Sie benachrichtigt werden, wenn eine Datei erstellt wurde.

Daher können Sie die FileSystemWatcher-Klasse verwenden und auf die createdEreignishandler mit dem Register-ObjectEvent Cmdlets registrieren.

$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". 

} 

Run dies deregistrieren:

Unregister-Event -SourceIdentifier FileCreated 
+0

HI Jisaak danke für Ihre Antwort. Warum ist die Verwendung von 'FileSystemWatcher' eine bessere Lösung? Dazu müsste auch eine geplante Aufgabe eingerichtet werden. Bedeutet dies nicht, dass mehr Wartung erforderlich ist? Was sind die Vorteile, wenn man so vorgeht, und was ist falsch beim langen Polling eines Ordners? Sicherlich könnte ich einfach in meine Aktionsskript für meine permanente Ereignisregistrierung aufnehmen, um eine E-Mail zu senden oder mich auf irgendeine Weise zu benachrichtigen, ohne 'FileSystemWatcher' zu benötigen. Nochmals vielen Dank für die Hilfe! – Bassie

+1

Nun, ich habe nichts zur Performance recherchiert, aber ich denke, dass dies der effizienteste Weg ist, Änderungen in einem Verzeichnis zu verfolgen. Lange Umfragen sind wie immer das Schlimmste, was man tun kann. –

+0

Danke jisaak. Ich hätte erwähnen sollen, dass ich bereits eine ähnliche Methode benutzt habe, bei der ich mich für ein Event in der Shell anmelde. Leider ist dies nicht ideal, da es nur dauert, während die Shell, die das Skript ausgeführt hat, geöffnet bleibt. Die Lösungen, die ich oben gepostet habe, registrieren beide einen permanenten Ereignisfilter (der auch dann weiterläuft, wenn der PC neu gestartet wird), weshalb ich mir diese Methoden ansehe. Ich habe meine Frage aktualisiert, um diese Anforderung zu berücksichtigen. – Bassie