scenariusz
rozjechały się skrzynki na exchange. trzeba posprawdzać bazy oraz zreperować, co się da, z podglądem tego, co się dzieje w danym momencie.
podstawa
do weryfikacji i naprawy mailboxów online służy New-MailboxRepairRequest. problem polega na tym, że to polecenie nie generuje logu tylko wrzuca informacje do eventvwr. ta zmiana jest określana miałem 'alleluja, teraz jest zajebiście’ ale przeglądanie eventvwr, zwłaszcza na żywym systemie nie jest przyjemna – ani nie wiadomo kiedy co się kończy, co zaczyna, zdarzeń jest od groma, żądanie zrobione z linii poleceń, a weryfikacja w taki sposób… no generalnie słabe.
cel
byłoby fajnie móc mieć podgląd life na konsoli tego, jak przebiegają testy. zwłaszcza, jeśli chcemy co jakiś czas zapuścić weryfikację kolejnej 'podejrzanej’ skrzynki.
rozwiązanie
znalazłem w netcie kilka lamerskich skryptów, do podglądu eventvwr na żywo (-> keyword 'tail eventvwr’). czemu lamerskich? ponieważ działają na zasadzie nieskończonej pętli while($true) co już samo w sobie jest bolesne. w tej pętli co 1 sek pobierane jest ostatnie zdarzenie z logu aplikacji. czyli jeśli system jest na prawdę dociążony (a exchange potrafi taki być), może się okazać, że nie zobaczymy tego, na co czekamy. krótko mówiąc – DA SIĘ LEPIEJ (:
rozwiązaniem jest zastawienie pułapki – to nie my pytamy się logu o ostatni event, tylko niech log nam powie, że takowy się pojawił. kwestie wydajności pomijam bo nie badałem – na pewno trzeba pamiętać o wyrejestrowaniu pułapki, żeby nie dociążać systemu. mechanizmem, który to realizuje jest ’register-ObjectEvent’, który rejestruje pułapkę na przechwycenie zdarzenia dla obiektów .NET.
oczywiście nie każde polecenie zdarzenia generuje /: aby to sprawdzić, wystarczy zwykły get-member. sprawdźmy dla get-eventlog:
[PS] C:\Windows\system32>Get-EventLog -LogName application -Newest 1 |gm TypeName: System.Diagnostics.EventLogEntry#application/MSExchange ADAccess/1074006048 Name MemberType Definition ---- ---------- ---------- Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs) CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedTyp Dispose Method System.Void Dispose() Equals Method bool Equals(System.Diagnostics.EventLogEntry otherEntry), boo GetHashCode Method int GetHashCode() GetLifetimeService Method System.Object GetLifetimeService() GetType Method type GetType() InitializeLifetimeService Method System.Object InitializeLifetimeService() ToString Method string ToString() Category Property System.String Category {get;} CategoryNumber Property System.Int16 CategoryNumber {get;} Container Property System.ComponentModel.IContainer Container {get;} Data Property System.Byte[] Data {get;} EntryType Property System.Diagnostics.EventLogEntryType EntryType {get;} Index Property System.Int32 Index {get;} InstanceId Property System.Int64 InstanceId {get;} MachineName Property System.String MachineName {get;} Message Property System.String Message {get;} ReplacementStrings Property System.String[] ReplacementStrings {get;} Site Property System.ComponentModel.ISite Site {get;set;} Source Property System.String Source {get;} TimeGenerated Property System.DateTime TimeGenerated {get;} TimeWritten Property System.DateTime TimeWritten {get;} UserName Property System.String UserName {get;} EventID ScriptProperty System.Object EventID {get=$this.get_EventID() -band 0xFFFF;}
no i słabo – niby jest 'disposed’ ale to nic nie daje. a to dla tego, że obiektem, który jest zwrócony, jest konkretny 'event’. jest jednak wywołanie polecenia, które 'podłącza się’ do eventlogu a nie do jego zawartości:
[PS] C:\Windows\system32>get-eventlog -List|gm TypeName: System.Diagnostics.EventLog Name MemberType Definition ---- ---------- ---------- Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs) EntryWritten Event System.Diagnostics.EntryWrittenEventHandler EntryWritten(System.Object, System.... BeginInit Method System.Void BeginInit() Clear Method System.Void Clear() Close Method System.Void Close() CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType) Dispose Method System.Void Dispose() EndInit Method System.Void EndInit() Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetLifetimeService Method System.Object GetLifetimeService() GetType Method type GetType() InitializeLifetimeService Method System.Object InitializeLifetimeService() ModifyOverflowPolicy Method System.Void ModifyOverflowPolicy(System.Diagnostics.OverflowAction action, int ... RegisterDisplayName Method System.Void RegisterDisplayName(string resourceFile, long resourceId) ToString Method string ToString() WriteEntry Method System.Void WriteEntry(string message), System.Void WriteEntry(string message, ... WriteEvent Method System.Void WriteEvent(System.Diagnostics.EventInstance instance, Params System... Container Property System.ComponentModel.IContainer Container {get;} EnableRaisingEvents Property System.Boolean EnableRaisingEvents {get;set;} Entries Property System.Diagnostics.EventLogEntryCollection Entries {get;} Log Property System.String Log {get;set;} LogDisplayName Property System.String LogDisplayName {get;} MachineName Property System.String MachineName {get;set;} MaximumKilobytes Property System.Int64 MaximumKilobytes {get;set;} MinimumRetentionDays Property System.Int32 MinimumRetentionDays {get;} OverflowAction Property System.Diagnostics.OverflowAction OverflowAction {get;} Site Property System.ComponentModel.ISite Site {get;set;} Source Property System.String Source {get;set;} SynchronizingObject Property System.ComponentModel.ISynchronizeInvoke SynchronizingObject {get;set;}
bingo! tu pojawia się 'entryWritten’! a więc zarejestrujmy pułapkę, przefiltrujmy zdarzenia, które nas interesują – i jeśli takowe się pojawi, wyświetlmy na ekran. opis eventów, jakie generuje new-mailboxrepairrequset można znaleźć na technecie. poniżej draft skryptu, który można sobie dowolnie rozbudować. dla czytelności zapisany w kilq linijkach.
$evtlog=Get-EventLog -list|?{$_.log -eq 'application'} Register-ObjectEvent -InputObject $evtlog -EventName EntryWritten -SourceIdentifier EventTrap -Action{ $id=$event.SourceEventArgs.Entry.EventID; if($id -gt 10041 -and $id -lt 10062) { write-host "$id -> $($event.SourceEventArgs.Entry.Message)" } }
na początq podłączamy się do konkretnego logu – logu aplikacji. następnie dla tego logu rejestrujemy pułapkę na pojawienie się nowych zdarzeń i definiujemy akcję. ponieważ na poziomie rejestracji nie ma możliwości zdefiniowania żadnych filtrów, wszystko trzeba zdefiniować wewnątrz ciała skryptu. po dokonaniu rejestracji, w konsoli będą się pokazywać wszystkie logi pomiędzy 10041-10062. oczywiście warto je ładniej wyświetlić i zrobić pełną obsługę… aby tego dokonać, kluczowym jest obiekt $event.SourceEventArgs.Entry, który jest de facto eventem pojawiającym się w logu, czyli można dostać się do wszystkich parametrów takich jak przy ’ Get-EventLog -LogName application -Newest 1 |gm’.
na koniec trzeba pamiętać o wyrejestrowaniu!! na skróty, wyrejestrowanie wszystkich:
get-event|unregister-event
eN.