Centrum Skrypciarzy - Systemy Operacyjne

Jak napisać skrypt zwiększający wskazanie licznika po każdej aktualizacji dziennika zdarzeń?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak napisać skrypt zwiększający wskazanie licznika po każdej aktualizacji dziennika zdarzeń?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Jak napisać skrypt zwiększający wskazanie licznika za każdym razem, gdy zaktualizowany zostanie dziennik zdarzeń?

-- HJ

Cześć Skrypciarze! Odpowiedź

Cześć, HJ. Skrypciarz piszący te słowa czuje się dziś parszywie. Boli go wszystko. Głowa, gardło, nos, plecy – jednym słowem grypa. Gdyby to było możliwe, najchętniej zleciłby jakiejś maszynie napisanie skryptu zwiększającego wskazanie licznika za każdym razem, gdy zaktualizowany zostanie dziennik zdarzeń, ale przecież żadna maszyna nie poradzi sobie z takim pytaniem. Z tego też powodu zacisnąwszy zęby Skrypciarz piszący te słowa połknął kolejną tabletkę przeciwbólową i napisał ten oto skrypt:

intModifications = 0



strComputer = "."



Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")



Set colMonitoredEvents = objWMIService.ExecNotificationQuery _

    ("SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE " _

        & "TargetInstance ISA 'CIM_DataFile' and " _

            & "TargetInstance.Name='C:\\Scripts\\Test.txt'")



Do

    Set objLatestEvent = colMonitoredEvents.NextEvent

    If objLatestEvent.TargetInstance.LastModified <> objLatestEvent.PreviousInstance.LastModified Then

        intModifications = intModifications + 1

        Wscript.Echo "File modified: " & Now

        Wscript.Echo "Number of modifications: " & intModifications

        Wscript.Echo

    End If

Loop

Tu zaczyna się cała zabawa: rozpracowanie, jak ten skrypt naprawdę działa. Jak widzimy, początek jest prosty: przypisujemy wartość 0 do zmiennej o nazwie intModifications (która, jak się pewnie domyślacie, jest zmienną licznika, którą wykorzystamy do liczenia modyfikacji danego pliku na bieżąco). Następnie łączymy się z usługą WMI na lokalnym komputerze, chociaż – to już słyszeliście wiele razy – skrypt działa także w przypadku komputerów zdalnych; wystarczy tylko przypisać nazwę tego komputera do zmiennej strComputer.

Dochodzimy teraz do dziwnie wyglądającego fragmentu kodu:

Set colMonitoredEvents = objWMIService.ExecNotificationQuery _

    ("SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE " _

        & "TargetInstance ISA 'CIM_DataFile' and " _

            & "TargetInstance.Name='C:\\Scripts\\Test.txt'")

Możecie wierzyć albo nie, ale jest to nasza kwerenda dotycząca subskrypcji zdarzeń. Nie będziemy się dzisiaj zagłębiać we wszystkie szczegóły dotyczące subskrypcji zdarzeń; jeżeli potrzebujecie więcej informacji na ten temat, sugerujemy zajrzeć do webcastu Scripting Week 2 (j.ang.), który dotyczący zdarzeń WMI. Krótko mówiąc, prosimy skrypt, aby co sekundę (WITHIN 1) sprawdzał czy utworzone zostały jakieś nowe elementy należące do klasy __InstanceModificationEvent. (Jak sama nazwa wskazuje, wystąpienia tej klasy są tworzone za każdym razem, gdy dokonana zostanie modyfikacja obiektu.) Rzecz jasna, w komputerze obiekty modyfikowane są nieustannie: różne procesy wykorzystują mniej (lub więcej) mocy obliczeniowej; wykorzystanie pamięci zwiększa się lub zmniejsza; zmienia się status połączeń sieciowych. Wszystko pięknie, ale przecież my nie chcemy być powiadamiani w przypadku zaistnienia żadnej z powyższych zmian. Dlatego też, do naszej kwerendy dodaliśmy kilka zastrzeżeń:

Chcemy otrzymywać powiadomienia tylko w przypadku, gdy nowe wystąpienie (TargetInstance) klasy __InstanceModificationEvent będzie plikiem (CIM_DataFile).
Chcemy otrzymywać powiadomienie, jeżeli ten nowy plik będzie miał właściwość Name (ścieżkę) równą C:\\Scripts\\Test.txt.
Uwaga. Do czego są potrzebne dodatkowe znaki \ w ścieżce dostępu do pliku? To proste: okazuje się, że \ jest znakiem zarezerwowanym w usłudze WMI. Dlatego też, zawsze, kiedy używamy \ w zdaniu z Where, musimy go „ominąć”; oznacza to po prostu, że musimy poprzedzić każdy znak \ kolejnym znakiem \. W wyniku tego, ścieżka C:\Scripts\Test.txt zostanie zapisana jako C:\\Scripts\\Test.txt.

Nadążacie? Dobrze. Następnie tworzymy pętlę Do, która będzie działać bez końca. Zauważcie, że nie określamy żadnego warunku końcowego (jak na przykład, jakieś zdarzenie albo osiągnięta wartość):

Do

Wewnątrz tej pętli stosujemy poniższy wiersz kodu w celu wydania skryptowi polecenia oczekiwania na zmodyfikowanie pliku docelowego (C:\Scripts\Test.txt):

Set objLatestEvent = colMonitoredEvents.NextEvent

A co się stanie, jeżeli ten plik nigdy nie zostanie zmodyfikowany? Nic, skrypt zablokuje się na tym wierszu kodu, dopóki świat będzie istniał. A o tak nawet potem, dalej będzie czekał, aż plik zostanie zmodyfikowany. Co się stanie, gdy plik zostanie zmodyfikowany? Dwie rzeczy. Najpierw utworzony zostanie nowy element należący do klasy __InstanceModificationEvent. Potem, z uwagi na fakt, iż ten nowy element klasy spełnia nasze kryteria subskrypcji zdarzeń, skrypt zostanie odblokowany. To z kolei spowoduje, że skrypt zastosuje następujący wiersz kodu:

If objLatestEvent.TargetInstance.LastModified <> objLatestEvent.PreviousInstance.LastModified Then

W zależności od tego, co chcemy osiągnąć, ten wiersz kodu może być opcjonalny. Podczas testowania skryptu odkryliśmy, że samo otwieranie pliku, bez wprowadzania do niego żadnej zmiany, powoduje utworzenie nowego elementu należącego do klasy __InstanceModificationEvent class. Nie spodobało nam się to w ogóle; spowodowało utrudnienie w rozróżnieniu rzeczywiście dokonanych zmian od zwykłego przeglądania zawartości pliku. Żeby obejść ten problem, zastosowaliśmy powyższy wiersz kodu w celu określenia, kiedy plik został ostatnio zmodyfikowany (coś, co robimy sprawdzając właściwość LastModified). W szczególności, porównujemy właściwość LastModified z najnowszą wersją pliku (TargetInstance) z właściwością LastModified poprzedniej wersji pliku (PreviousInstance); zatem porównujemy plik w formie istniejącej obecnie z plikiem, który istniał zanim został utworzony nowy element klasy __InstanceModificationEvent. Jeżeli te dwie daty i godziny do siebie pasują, wiemy, że plik nie został zmodyfikowany.

A jeżeli do siebie nie pasują, oznacza to, że jakaś zmiana została wprowadzona. Dlatego też uruchamiamy poniższy fragment kodu:

intModifications = intModifications + 1

Wscript.Echo "File modified: " & Now

Wscript.Echo "Number of modifications: " & intModifications

Wscript.Echo

Zaczynamy od zwiększenia wartości zmiennej licznika intModifications o 1; a to dlatego, że właśnie dokonano w pliku jakiejś zmiany. Następnie wywołujemy echo dwóch informacji: 1) faktu, że plik został zmodyfikowany, wraz z bieżącą datą i godziną (Now); oraz 2) całkowitej liczby modyfikacji wprowadzonych do pliku (intModifications). Potem uruchamiamy pętlę i powtarzamy cały proces od początku.

W sumie to jest całkiem proste. Maszyna mogłaby sobie z tym poradzić.

Ale to nie koniec; należy mieć na uwadze jeszcze kilka rzeczy. Po pierwsze, zalecamy uruchomienie tego skryptu w oknie poleceń hosta skryptów CScript. Dlaczego? Ponieważ w ten sposób skrypt będzie mógł wpisać swoje powiadomienie do okna poleceń i działać dalej. Jeżeli użyjemy hosta skryptów WScript, pojawi się koniczność zamykania kilku okien dialogowych po każdej modyfikacji pliku. A fe…! Po drugie, liczenie ma miejsce tylko podczas pracy skryptu; jak się pewnie domyślacie, jeżeli skrypt zostanie wyłączony, nie będziemy mogli śledzić zmian w pliku. (Bieżący licznik zostanie utracony na zawsze.) Z tego powodu, chcemy, aby tak zmienić skrypt, żeby zamiast wywoływania echa informacji na monitorze, zapisywał wynik liczenia do pliku tekstowego. Dodatkowo, możemy zastanowić się nad opcją stałego odbiorcy zdarzeń, który umożliwiłby usłudze WMI śledzenie zmian w pliku bez potrzeby stosowania skryptu. Nie jest to bardzo trudne, ale może zaskoczyć. Więcej informacji o stałym odbiorcy zdarzeń znajduje się w artykule WMI SDK (j.ang.) w witrynie MSDN.

 Do początku strony Do początku strony

Centrum Skrypciarzy - Systemy Operacyjne