[MHo]: Program for [tail]ing ms windows event logs using twapi. Work in progress. use it in any way you want, but at your own risk. This is the main prog of a starpack which will later be made downloadable somewhere. ====== package provide app-wineltail 1.0 # wineltail # 06.03.2013 # (c) Matthias Hoffmann # Monitor Windows Event Logs package require twapi ::twapi::import_commands proc trapClose {type} { global hevl hmon hname puts stderr $type foreach h [array names hmon] { puts stderr "Stoppe Monitor Instanz $hmon($h) für $hname($h)" catch {eventlog_monitor_stop $hmon($h)} } foreach h [array names hevl] { # später die Namen der Logs anzeigen puts stderr "Schliesse Eventloginstanz $hevl($h) für $hname($h)" catch {eventlog_close $hevl($h)} } exit 0 } proc formatSID {sid} { if {[string length $sid]} { if {![catch {lookup_account_sid $sid} rc]} { return $rc } } return [string range $sid end-6 end] } proc formatEventID {eid} { # diese merkwürdige Logik muss auch noch gecheckt werden! set e [expr {$eid-1073741824}] if {$e < 0} { set e 1 } return $e } proc formatOutput {} { foreach {l lbuf} $::buffer { foreach eventrec $lbuf { array set event $eventrec # $event(-sid) später nur optional!! Bzw. Ausgabe gemäss variabler Schablone. # Verwendung von lookup_account_sid direkt in eventSink führt zum Verschlucken von Events, # daher hier asynchron # [list [string range $event(-sid) end-6 end]] puts "[list [clock format $event(-timegenerated) -format {%Y%m%d %T}]] \ [list $event(-system)] \ [list [formatSID $event(-sid)]] \ [list $l] \ [list $event(-recordnum)] \ [list [string range $event(-type) 0 6]] \ [list $event(-source)] \ [list [eventlog_format_category $eventrec -width -1]] \ [list [formatEventID $event(-eventid)]] \ [list [eventlog_format_message $eventrec -width -1]]" array set event {} } } set ::buffer [list] } # der Monitorhandle wird immer als letztes Übergeben (nicht benötigt) # wird nur gefeuert, wenn tatsächlich ein Signal anliegt proc eventSink {e l m} { while {[llength [set events [eventlog_read $e]]]} { # Events asynchron weiterverarbeiten lappend ::buffer $l $events } set ::signal 1 } # für eigenes Polling proc eventPoll {e l} { set foundNew 0 while {[llength [set events [eventlog_read $e]]]} { # Events asynchron weiterverarbeiten lappend ::buffer $l $events incr foundNew } if {$foundNew > 0} { set ::signal 1 } after 5000 [info level 1]; # sich selbst erneut aufrufen } if {$argc == 0} { puts stderr {Parameter: (engl.) Name(n) der zu überwachenden Eventquelle(n), Bsp.: System Es können mehrere Quellen angegeben werden, Bsp.: System Application Es kann je Quelle ein Systemname angegeben werden, Bsp.: "System Matthias" Application (in diesem Fall wird versucht, die System-Events vom remote Rechner Matthias zu lesen, und Application-Events vom lokalen Rechner). Das Auflösen von Benutzernamen funktioniert ggF. nicht. Es werden dann die letzten Stellen der SID zurückgegeben. Das Programm kann mit Strg+C beendet werden. } exit 255 } set_console_control_handler [list trapClose] set ix 0 array set hevl {} array set hmon {} array set hname {} foreach log $argv { if {[llength $log] == 2} { set logname [lindex $log end] set logsys [lindex $log 1] } else { set logname $log set logsys $::env(computername) } if {![catch {set hevl($ix) [eventlog_open -source $logname -system $logsys]} rc]} { if {[catch { # RecordPointer zum Ende (es gibt kein SEEK...), aber gelesenes nicht anzeigen while {[llength [eventlog_read $hevl($ix)]]} {} if {[catch {set hmon($ix) [eventlog_monitor_start $hevl($ix) [list eventSink $hevl($ix) $logname]]}]} { # Monitoring auf remote_logs soll nicht funktionieren; also hier eigenes Polling verwenden (ungetestet) after 5000 [list eventPoll $hevl($ix) $logname]; # später Intervall bestimmbar machen } set hname($ix) "$logsys $logname"; # nur für Anzeige beim späteren Schließen incr ix } rc]} { puts stderr "(2) $rc" } } else { puts stderr "(1) $rc"; # im Heimnetz nicht testbar!? ("der RPC-Server ist nicht verfpgbar") } } if {$ix == 0} { puts stderr "Es konnten keine Logs geöffnet werden!" exit 1 } set buffer [list] set signal 0 while 1 { vwait signal formatOutput } ====== <>Enter Category Here