–update, I have included a way that differentiates between XP and newer OS versions. This was causing some problems with some events getting missed.
Today I have started to share out some of my powershell scripts I’ve had knocking around for a while, on Microsoft’s Script Repository. While I’m an enthusiast, it’s not the bread and butter of my daily work, so I appreciate my code comments and such can be on the scruffy side.
During this, I discovered a nifty script by mck74 & mjolinor that monitors MS Windows event logs for particular events across a network of computers. Even better, you can set the script to run every x minutes, and streamline that with Task Scheduler so when you login to your workstation, your alert monitoring is going.
Unfortunately the script they provide in the repository wasn’t pulling back ALL events I was seeking out. This was because the filter on the events was not filtering on the actual EventId, but another value called InstanceID.
InstanceID usually matches up to EventIDs but not always (as is the case with SceCli events). That said, I suggest to monitor the script at line 74.
## Powershell Log Monitor Script ##
## Contributing authors – mck74,mjolinor,
param([switch]$ShowEvents = $false,[switch]$NoEmail = $false)
$log = “Security”
$hist_file = $log + “_loghist.xml”
$seed_depth = 200
#run interval in minutes – set to zero for runonce, “C” for 0 delay continuous loop.
$run_interval = 0
$EmailFrom = “<youremail@domain.tls>”
$EmailTo = “<youremail@domain.tls>”
$EmailSubject = “Server event notification”
$SMTPServer = “smtpServer”
$SMTPAuthUsername = “username”
$SMTPAuthPassword = “password”
$computers = @(gc monitored_computers.txt)
$event_list = @{}
Import-Csv alert_events.csv |% {$event_list[$_.source + '#' + $_.id] = 1}
#see if we have a history file to use, if not create an empty $histlog
if (Test-Path $hist_file){$loghist = Import-Clixml $hist_file}
else {$loghist = @{}}
$timer = [System.Diagnostics.Stopwatch]::StartNew()
function send_email {
$mailmessage = New-Object system.net.mail.mailmessage
$mailmessage.from = ($emailfrom)
$mailmessage.To.add($emailto)
$mailmessage.Subject = $emailsubject
$mailmessage.Body = $emailbody
$mailmessage.IsBodyHTML = $true
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 25)
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential(“$SMTPAuthUsername”, “$SMTPAuthPassword”)
$SMTPClient.Send($mailmessage)
}
#START OF RUN PASS
$run_pass = {
$EmailBody = “Log monitor found monitored events. `n”
$computers |%{
$timer.reset()
$timer.start()
Write-Host “Started processing $($_)”
## Get the OS version number below. If it is older than Vista process the EventID. If it is Vista or Newer (version 6) process
## the InstanceID
$os = gwmi win32_operatingsystem -computer $server | % {$_.version}
if ($ver -lt 6){
$useID = ‘EventID’
}
else {
$useID = ‘InstanceID’
}
#Get the index number of the last log entry
$index = (Get-EventLog -ComputerName $_ -LogName $log -newest 1).index
#if we have a history entry calculate number of events to retrieve
# if we don’t have an event history, use the $seed_depth to do initial seeding
if ($loghist[$_]){$n = $index – $loghist[$_]}
else {$n = $seed_depth}
if ($n -lt 0){
Write-Host “Log index changed since last run. The log may have been cleared. Re-seeding index.”
$events_found = $true
$EmailBody += “`n Possible Log Reset $($_)`nEvent Index reset detected by Log Monitor`n” | ConvertTo-Html
$n = $seed_depth
}
Write-Host “Processing $($n) events.”
#get the log entries
$log_hits = Get-EventLog -ComputerName $_ -LogName $log -Newest $n |
? {$event_list[$_.source + "#" + $_.$useID]}
#save the current index to $loghist for the next pass
$loghist[$_] = $index
#report number of alert events found and how long it took to do it
if ($log_hits){
$events_found = $true
$hits = $log_hits.count
$EmailBody += “`n Alert Events on server $($_)`n”
$log_hits |%{
$emailbody += “<br><br>”
$emailbody += $_ | select MachineName,EventID,Message | ConvertTo-Html
$emailbody += “<br><br>”
}
}
else {$hits = 0}
$duration = ($timer.elapsed).totalseconds
write-host “Found $($hits) alert events in $($duration) seconds.”
“-”*60
” ”
if ($ShowEvents){$log_hits | fl | Out-String |? {$_}}
}
#save the history file to disk for next script run
$loghist | export-clixml $hist_file
#Send email if there were any monitored events found
if ($events_found -and -not $NoEmail){send_email}
}
#END OF RUN PASS
Write-Host “`n$(“*”*60)”
Write-Host “Log monitor started at $(get-date)”
Write-Host “$(“*”*60)`n”
#run the first pass
$start_pass = Get-Date
&$run_pass
#if $run_interval is set, calculate how long to sleep before the next pass
while ($run_interval -gt 0){
if ($run_interval -eq “C”){&$run_pass}
else{
$last_run = (Get-Date) – $start_pass
$sleep_time = ([TimeSpan]::FromMinutes($run_interval) – $last_run).totalseconds
Write-Host “`n$(“*”*10) Sleeping for $($sleep_time) seconds `n”
#sleep, and then start the next pass
Start-Sleep -seconds $sleep_time
$start_pass = Get-Date
&$run_pass
}
}