Monitoring the Event Log with PowerShell
One of my goals with learning more about PowerShell is to be able to monitor the event logs on servers and notify me via email when certain events happen. The system I’m looking to monitor are not part of a domain, are in remote locations on isolated networks. Some of the main things I’m looking to monitor is the RAID status and drive alerts. While the servers do have the Dell Open Manage Server Administrator (OMSA) on them, it doesn’t support emails so my options seemed to either rely on OMSA to trigger something to run or monitor the event log for the event.
I may setup a trigger as well once I do some more testing but for starters I’m going to monitor the event log for the eventIDs between 2048 and 2368 which should be all of the alerts from OMSA. This will be adjusted along the way I’m sure but it’s a starting point…plus the more events that will trigger it the more testing I can get done.
As I’ve mentioned, I don’t consider myself a programmer by any means…this was put together from the samples and info found on other sites, the two biggest contributors being Windows PowerShell Blog & Dell OMSA Users Guide.
Here’s the script that I’m using, from the Windows PowerShell blog, to parse through the event log and look for the events I’m interested in. The next step will be to take the results and send them, when there’s an event, via email to me.
# Eventlog monitoring script 2006/03/28 JonN # # Event logs can contain hundreds of thousands of items, so # "get-eventlog System | where {<condition>}" can take excessively long # on production systems. Plus, the same failures will be reported # over and over. # This script will remember your last Index position in the log, # and only report events which occurred since then. # It also remembers the TimeGenerated of the oldest log entry, # so that it can detect when the log has been cleared. # Example: # eventlog.msh1 -LogName System -Filter {$_.EventID -eq 4226} -PositionFile "c:\logs\syslogpos.txt"param ( [string]$LogName="System", [ScriptBlock]$Filter= {$true}, [string]$PositionFile=$home+"\"+$LogName+"_position.txt", [switch]$Force, [switch]$Restart ) write-debug "`$LogName = $LogName" write-debug "`$Filter = '$Filter'" write-debug "`$PositionFile = '$PositionFile'" write-debug "`$Force = $Force" write-debug "`$Restart = $Restart" [int]$lastCheckedIndex=-1 [DateTime]$lastCheckedTime= [DateTime]::MaxValue if (!$Restart) { $filecontent= get-content $PositionFile-ea SilentlyContinue if ($null-eq$filecontent) { if (!$Force) { throw"Position file '$PositionFile' does not exist or could not be opened. Use -Force or -Restart to create a new position file." } write-verbose "Position file '$PositionFile' does not exist or could not be opened. Rebuilding position file because -Force was specified." } else { write-debug "Position file contains '$filecontent'"trap { if ($Force) { write-warning "Content of position file '$PositionFile' is invalid. Rebuilding position file because -Force was specified."$lastCheckedIndex=-1$lastCheckedTime= [DateTime]::MaxValue continue } throw"Content of position file '$PositionFile' is invalid. Terminating operation. Use -Force or -Restart to rebuild the position file." } # These lines will throw if the cast fails$lastCheckedIndex=$filecontent[0] $lastCheckedTime=$filecontent[1] } } write-debug "`$lastCheckedIndex = $lastCheckedIndex" write-debug "`$lastCheckedTime = $lastCheckedTime"# I don't simply call get-eventlog $LogName because I don't want to # build an array with all the hundreds of thousands of event log entries. # Instead, I make sure the EventLogEntryCollection is not unrolled.$log= get-eventlog -List | where {$_.Log -ieq$LogName} if ($null-eq$log) { throw"Log not found: $LogName" } $entries=$log.Entries if (0-eq$entries.Count) { write-debug "Log empty: $LogName"return } $oldestEntryTime=$entries[0].TimeGenerated if ($oldestEntryTime-gt$lastCheckedTime) { write-verbose "The log appears to have been cleared since it was last checked: $LogName."$lastCheckedIndex=-1 } # The index can diverge from the number of entries # when the log reaches its maximum size and is configured # to "Overwrite entries as needed"$newestEntryIndex=$entries[$entries.Count -1].Index $newestEntryTime=$entries[$entries.Count -1].TimeGenerated write-debug "Newest entry in log has index $newestEntryIndex" write-debug "Newest entry in log has TimeGenerated $newestEntryTime"# $entries.Count could be more than the maximum range "50000 .. 0"foreach ($iin ($entries.Count -1) .. 0) { $entry=$entries[$i] if ($entry.Index -le$lastCheckedIndex) { break } # This line actually generates the output$entry| where $Filter } write-debug "Writing index $newestEntryIndex to position file '$PositionFile'" write-debug "Writing time $newestEntryTime to position file '$PositionFile'"$newestEntryIndex,$newestEntryTime| set-content $PositionFile
April 14th, 2011 at 9:16 am
Hey, how does your powershell script work with Dell’s Openmanage? I can’t execute powershell even from a .bat file. The weirdest thing — the .bat file gets executed, the powershell within — not.
April 20th, 2011 at 11:06 am
I’m not currently using this script (and just to be clear, I didn’t write it in the first place.) But to answer your question and run PoSh scripts from a command line, which I do daily is easy. Use the following in a batch file to call the script:
powershell -noninteractive -noprofile -command “c:\YourPSScript.ps1″
Obviously change the drive/path/filename to be what you want to run.
One other thing is to make sure you’re using a signed PS script or set the Execution Policy.