File System Watcher

Z racji, iż szkoda przerywać serię gdy nie wyczerpało się jeszcze tematu, dlatego znów zaprezentuję mechanizm obserwacji pracy systemu, tym razem będzie to FileSystemWatcher. Opisane rozwiązanie można wykonać na wiele sposobów, choćby w nałożenia formie zwykłych audytów w systemie czy po prostu używając oprogramowanie firm trzecich. Jednakże z racji mojej pasji do PowerShell’a zaprezentuję alternatywną formę jak tego dokonać.

Jak w przypadku obserwacji pracy WMI, tak i dla systemu plików posiadamy powiedzmy dwa podejścia do problemu. Jedno dla bardziej zapalonych skrypciarzy, oraz drugie bardziej przyjazne dla zwykłych użytkowników. Tak naprawdę są to te same rozwiązania tylko inaczej wykone.

Zacznijmy od wersji bardziej zaawansowanej, która wbrew pozorom pozwoli na dokonanie lepszej analizy wyżej wymienionego procesu. Cały proces opiera się o pracę obiektu klasy .NET System.IO.FileSystemWatcher. Dlatego tworzymy instancję obiektu tej klasy. Mamy tutaj do wyboru użycie kilku konstruktorów, dla których albo nie podajemy żadnych parametrów, albo już wstępnie konfigurujemy nasz przyszły obiekt.

$FileSystemWatcher = New-Object System.IO.FileSystemWatcher

Głównym parametrem tego obiektu jest oczywiście ścieżka do obiektu system plików, czyli do naszego testowego katalogu.

$FileSystemWatcher.Path = "P:\Test"

Od teraz obiekt wie, iż będziemy obserwował tylko zdarzenia, które wystąpią wewnątrz tego katalogu. Jeżeli chcemy aby były obserwowane również akcje głębiej, tzn. w pod folderach musimy ustawić odpowiednią flagę.

$FileSystemWatcher.IncludeSubdirectories = $true

Dodatkowo możemy również nałożyć odpowiednie filtry w celu lepszego wyszukiwania zdarzeń. Jednym z nich jest filtr obiektów systemu plików dla których ma być stosowany skrypt.

$FileSystemWatcher.Filter = "*.txt"

Drugim z filtrów jest NotifyFilters, czyli zmiany jakich atrybutów chcemy obserwować. Domyśłnie są to FileName, DirectoryName, LastWrite, ale możemy również obserwować są zmianę rozmiaru pliku czy np. zmianę zabezpieczeń obiektu. Więcej na ten temat możemy znaleźć tutaj.

$FileSystemWatcher.NotifyFilter = [System.IO.NotifyFilters]::Security

Niestety drobnym minusem tutaj jest przechwycenie tylko i wyłącznie samego wystąpienia zdarzenia, bez możliwości podglądu co zostało zmodyfikowane.

Dodatkowo możemy ustawić parametr EnableRaisingEvents na True, aby powiedzmy włączyć komponent. Jednakże dzieje się to automatycznie w momencie wywołania odpowiednich metod do nasłuchiwania, jak np. WaitForChanged. Jest to metoda pozwalająca na jednorazowe przechwycenie szukanego zdarzenia. Jako parametr metody podajemy kolejny rodzaj filtrowania, czyli jakiego rodzaju wystąpienia na obiekcie systemu plików mają być przechwytywane – utworzenie nowego podkatalogu lub pliku, usunięcie, zmiana danych, zmiana nazwy obiektu czy może wszystkie wcześniejsze wystąpienia. Po więcej informacji odsyłam do dokumentacji.

$FileSystemWatcher.WaitForChanged('All')

W celu lepszego zautomatyzowania tego procesu możemy wykorzystać pętlę While np. wraz z warunkiem zmiany statusu o przekroczeniu limitu czasu.

$Result = New-Object System.IO.WaitForChangedResult
While ($Result.TimedOut -eq $False)
{
  $Result = $FileSystemWatcher.WaitForChanged('All',10000)
  $Result | Out-Host
}

Całość wygląda następująco:

$FileSystemWatcher = New-object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = "P:\Test"
$FileSystemWatcher.IncludeSubdirectories = $true
$FileSystemWatcher.EnableRaisingEvents = $true
$FileSystemWatcher.Filter = "*.txt"
$FileSystemWatcher.NotifyFilter = [System.IO.NotifyFilters]::Security

$Result = new-object System.IO.WaitForChangedResult

While ($Result.TimedOut -eq $False)
{
  $Result = $FileSystemWatcher.WaitForChanged('All',10000)
  if($Result.TimedOut -eq $False)
  {
    #Akcja do wykonania zdefiniowana przez użytkownika
    $Result | Out-Host
  }
}

Drugie podejście do problemu jest bardzo zbliżone, a jedyną różnicą jest tutaj możliwość podpięcia się pod przechwycenie odpowiedniego zdarzenia obiektu przy pomocy cmdletu Register-ObjectEvent.

Sam obiekt FileSystemWatcher definiujemy identycznie jak poprzednio w zależności od naszych potrzeb.

$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = "P:\Test"
$FileSystemWatcher.IncludeSubdirectories = $true
$FileSystemWatcher.Filter = "*.txt"
$FileSystemWatcher.EnableRaisingEvents = $true

Następnie definiujemy blok skryptu który ma się wykonać jako akcja danego zdarzenia.

$createdAction = { Write-Host "$(Get-Date): Utworzono obiekt $($eventArgs.FullPath)" }

Ostatecznie wykorzystujemy całość do zarejestrowania przechwycenia zdarzenia obiektu.

Register-ObjectEvent $FileSystemWatcher "Created" -Action $createdAction

Całość wygląda następująco:

$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = "P:\Test"
$FileSystemWatcher.IncludeSubdirectories = $true
$FileSystemWatcher.Filter = "*.txt"
$FileSystemWatcher.EnableRaisingEvents = $true

$createdAction = { Write-Host "$(Get-Date): Utworzono obiekt $($eventArgs.FullPath)" }
$renamedAction = { Write-Host "$(Get-Date): Zmieniono nazwę obiektu z $($eventArgs.OldName) na $($eventArgs.FullPath)" }
$changedAction = { Write-Host "$(Get-Date): Zmodyfikowano obiekt $($eventArgs.FullPath)" }
$deletedAction = { Write-Host "$(Get-Date): Usunięto obiekt $($eventArgs.FullPath)" }

Register-ObjectEvent $FileSystemWatcher "Created" -Action $createdAction
Register-ObjectEvent $FileSystemWatcher "Renamed" -Action $renamedAction
Register-ObjectEvent $FileSystemWatcher "Changed" -Action $changedAction
Register-ObjectEvent $FileSystemWatcher "Deleted" -Action $deletedAction

Źródła:
http://msdn.microsoft.com/en-us/library/x7t1d0ky
http://msdn.microsoft.com/en-us/library/system.io.notifyfilters

Reklamy

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s