Wielki brat patrzy: WMI Watcher

Z racji poprzedniego artykułu tak mi się wzięło na podglądanie pracy systemu, iż postanowiłem opisać również inny mechanizm „Obserwatora”. Mianowicie jest nim ManagementEventWatcher czyli podglądanie zdarzeń związanych z pracą WMI.

Czym tak naprawdę jest WMI: „Usługa WMI zawiera repozytorium obiektów, które jest bazą danych definicji obiektów, oraz menedżera obiektów WMI obsługującego zbieranie obiektów i operacje przeprowadzane na nich w repozytorium, a także gromadzącego informacje od dostawców WMI.

A teraz dla niewtajemniczonych, jest to po prostu zbiór klas i obiektów systemu Windows pozwalający na zarządzanie jego zasobami. Np. każdy proces w systemie jest reprezentowany jako instancja klasy WMI (w tym przypadku klasy Win32_Process). Natomiast dzięki wykorzystaniu ManagementEventWatcher możemy monitorować m.in. tworzenie nowych instancji WMI, czyli jak w naszym przykładzie nowych procesów, usuwanie oraz modyfikowanie ich stanu.

Zacznijmy od najprostszego czyli od przechwycenia zdarzenia o uruchomieniu nowego procesu. Tak naprawdę sposobów podejścia do problemu jest wiele, jednakże postaram się zaprezentować dwa wg. mnie najciekawsze i najwygodniejsze.

Wersja powiedzmy bardziej ręczna. Tworzymy trzy obiekty .NETa

  • ManagementScope – czyli wskazanie zakresu przestrzeni nazw. Dodatkowo mamy również możliwość wskazania maszyny do nasłuchiwania zdalnego.
  • WQLEventQuery– zestaw parametrów charakteryzujący nasze zapytanie WMI, czyli:
    • eventClassName – rodzaj zdarzenia: „__InstanceCreationEvent”, “__InstanceModificationEvent” lub “__InstanceDeletionEvent”
    • withinInterval – okres monitorowania, czyli najlepiej 1s.
    • condition – czyli docelowa klasa jaka ma być monitorowana
  • ManagementEventWatcher – obiekt naszego obserwatora, który wykorzystuje powyższe dwa obiekty.
$ComputerName = "."
$Scope = New-Object System.Management.ManagementScope("\\$ComputerName\root\cimV2")

$withinInterval  = [TimeSpan]::FromSeconds(1)
$Query = New-Object System.Management.WQLEventQuery ("__InstanceCreationEvent", $withinInterval , "TargetInstance ISA 'Win32_Process'" )

$Watcher = New-Object System.Management.ManagementEventWatcher($Scope,$Query)

Gdy posiadamy już obiekt obserwatora, dzięki wywołaniu metody WaitForNextEvent możemy jednorazowo przechwycić wcześniej zdefiniowane zdarzenie, czyli utworzenie nowego procesu:

$WatchedEvent = $watcher.WaitForNextEvent()
$WatchedEvent
$WatchedEvent.TargetInstance | Select-Object Name, ProcessId, CreationDate

Jak widzimy zostało przechwycone jedno zdarzenie, czyli stworzenie procesu notatnika wraz z podstawowymi własnościami jakie go reprezentują.

Natomiast co jeżeli chcemy stale monitorować tworzone procesy? Wtedy wystarczy metodę WaitForNextEvent wprowadzić do pętli. Jednakże, powinniśmy zostawić sobie furtkę pozwalającą na wyjście z pętli np. po naciśnięciu klawisza. Do tego celu tworzymy kolejny obiekt, czyli EventWatcherOptions w którym ustawiamy TimeOut danego przebiegu nasłuchiwania np. na 10 sekund i całość dołączamy do naszego obserwatora.

$Options = new-object System.Management.EventWatcherOptions
$Options.Timeout = [timespan]::FromSeconds(10)
$Watcher.options = $Options

Tworzymy teraz pętlę, w której dołączamy przechwytywanie błędów, gdyż przekroczenie czasu oczekiwania jak wcześniej zdefiniowaliśmy wygeneruje stosowny komunikat błędu. Natomiast jako warunek pętli wstawiamy zaprzeczenie zdarzenia oczekującego klawisza.

do
{
	trap [System.Management.ManagementException] {continue}
	$WatchedEvent = $Watcher.WaitForNextEvent()
	Write-Host "Usługa $($WatchedEvent.TargetInstance.DisplayName) zmieniła stan z $($WatchedEvent.PreviousInstance.state) na  $($WatchedEvent.TargetInstance.state)"
}
while (!$host.UI.RawUI.KeyAvailable)

W momencie gdy chcemy zakończyć przechwytywanie naciskamy dowolny klawisz i czekamy na nasz 10 sekundowy TimeOut obiektu obserwatora.

Drugą metodą jest zastosowanie gotowego cmdletu Register-WMIEvent, gdzie cała nasza praca skupia się jedynie na zdefiniowaniu bloku kodu jaki ma się wykonać podczas wystąpienia zdarzenia oraz zdeklarowaniu zapytania WQL.

Jest ona o tyle wygodniejsza, gdyż bez konieczności żmudnego definiowania obiektów .NET’a można zdefiniować przechwytywanie różnych zdarzeń naraz, np. jednoczesne obserwowanie tworzonych i usuwanych procesów.

[ScriptBlock]$ObjectCreationEventtAction = {
	$EventRecord = $EventArgs.NewEvent.TargetInstance
	Write-Host "Uruchomiono proces $($EventRecord.Name) o ID $($EventRecord.ProcessID)"
}

[ScriptBlock]$ObjectDeletionEventAction = {
	$EventRecord = $EventArgs.NewEvent.TargetInstance
	Write-Host "Zakończono proces $($EventRecord.Name) o ID $($EventRecord.ProcessID)"
}

Register-WMIEvent -query "Select * From __InstanceCreationEvent within 1 Where TargetInstance ISA 'Win32_Process'" `
-sourceIdentifier "CreateProcess" -action $ObjectCreationEventtAction
Register-WMIEvent -query "Select * From __InstanceDeletionEvent within 1 Where TargetInstance ISA 'Win32_Process'" `
-sourceIdentifier "DeleteProcess" -action $ObjectDeletionEventAction

Aby zatrzymać proces nasłuchiwania wystarczy wyrejestrować zdarzenie.

Unregister-Event "CreateProcess"
Unregister-Event "DeleteProcess"

Jeszcze jednym dość ciekawym typem zdarzeń jest „__InstanceModificationEvent”. Co prawda dla obiektów typu proces nie ma zbyt dobrego zastosowania, gdyż procesy pracujące w systemie zmieniając się w sposób ciągły. Jednakże w ten sposób możemy np. monitorować zmianę stanu pracy usług i w przypadku np. zatrzymania usługi wykonać odpowiedni kod korygujący ten stan lub powiadamiający administratora.

[ScriptBlock]$ObjectModificationEventAction = {
	$PreviousEvent = $EventArgs.NewEvent.PreviousInstance
	$EventRecord = $EventArgs.NewEvent.TargetInstance
	Write-Host "Usługa $($EventRecord.DisplayName) zmieniła stan z $($PreviousEvent.State) na $($EventRecord.State)"
}

Register-WMIEvent -query "Select * From __InstanceModificationEvent within 1 Where TargetInstance ISA 'Win32_Service'" `
-sourceIdentifier "ChangeService" -action $ObjectModificationEventAction

Oczywiście jak w przypadku EventLogWatcher’a, kwestia kodu jaki ma być wykonany na wystąpienie zdarzenia zależy tylko i wyłącznie od naszej wyobraźni.

Źródła:
http://technet.microsoft.com/pl-pl/library/cc736575(v=ws.10).aspx
http://technet.microsoft.com/en-us/library/ff730927.aspx
http://msdn.microsoft.com/en-us/library/system.management.managementeventwatcher.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa394652(v=vs.85).aspx

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ń )

Facebook photo

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

Google+ photo

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

Connecting to %s