How Can I Return Only the Last Record Written to an Event Log?

Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I read only the last record written to an event log? In other words, what is the WMI equivalent to the SQL statement Select Top 1?

— KM

SpacerHey, Scripting Guy! AnswerScript Center

Hey, KM. Well, as it turns out WMI doesn’t have an equivalent to the Select Top command; for better or worse, the WMI Query Language (WQL) has only a small subset of the commands found in SQL. That doesn’t mean we can’t return only the last record written to an event log, it just means we have to be a bit sneaky about it.


To get just the last record we need to do two things. To begin with, we need to figure out how many records are in an event log. That’s important information, because events are numbered sequentially when they are added to an event log; in other words, the first event written to an event log is record 1, the second is record 2, etc. If there are 4,912 events in an event log, then the very last record written to the log has to be record number 4912. After we know the total number of records, we can then write a query that returns only events with a record number equal to the total number of records. That record is the last record written to the log.


Here’s a simple little script that determines the total number of records in the Application event log, and stores that value in the variable intRecords:

strComputer = “.”
Set objWMIService = GetObject(“winmgmts:” _
& “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2”)

Set objInstalledLogFiles = objWMIService.ExecQuery _
(“Select * from Win32_NTEventLogFile Where LogFileName = ‘Application'”)

For Each objLogfile in objInstalledLogFiles
intRecords = objLogFile.NumberOfRecords
Next


Now we need a query that returns all events from the Application event log where the RecordNumber is equal to value of intRecords (and there will only be one such record, seeing as how record numbers are unique). Here’s a query that does just that:

Set colLoggedEvents = objWMIService.ExecQuery _
(“Select * From Win32_NTLogEvent Where Logfile = ‘Application’ AND ” & _
“RecordNumber = ” & intRecords)

All that’s left now is to put these two script snippets together, and then add a For Each loop in which we echo the properties of this record:

strComputer = “.”
Set objWMIService = GetObject(“winmgmts:” _
& “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2”)

Set objInstalledLogFiles = objWMIService.ExecQuery _
(“Select * from Win32_NTEventLogFile Where LogFileName = ‘Application'”)

For Each objLogfile in objInstalledLogFiles
intRecords = objLogFile.NumberOfRecords
Next

Set colLoggedEvents = objWMIService.ExecQuery _
(“Select * From Win32_NTLogEvent Where Logfile = ‘Application’ AND ” & _
“RecordNumber = ” & intRecords)

For Each objEvent in colLoggedEvents
Wscript.Echo “Category: ” & objEvent.Category
Wscript.Echo “Computer Name: ” & objEvent.ComputerName
Wscript.Echo “Event Code: ” & objEvent.EventCode
Wscript.Echo “Message: ” & objEvent.Message
Wscript.Echo “Record Number: ” & objEvent.RecordNumber
Wscript.Echo “Source Name: ” & objEvent.SourceName
Wscript.Echo “Time Written: ” & objEvent.TimeWritten
Wscript.Echo “Event Type: ” & objEvent.Type
Wscript.Echo “User: ” & objEvent.User
Next


That should do the trick.