Windows Event Log API examples / libs?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Windows Event Log API examples / libs?

28 Sep 2015, 09:35

Does anyone have any code for reading of Event Log entries?

Ideally I need to be able to iterate through events in the log of an exchange server that is on the same LAN / Domain as the machine the script is running on.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Windows Event Log API examples / libs?

29 Sep 2015, 01:33

I just did the first part...
To get the information you need to decode the returns (see here: EventLog.au3)

Experimental Class:

Code: Select all

; GLOBAL SETTINGS ===============================================================================================================

#NoEnv
#SingleInstance Force
#NoTrayIcon

EventFile := "Application"

; SCRIPT ========================================================================================================================

GuiEdit := "Event .............: " EventFile "`n"
GuiEdit .= "Record count ......: " EventLog.Count(EventFile) "`n"
GuiEdit .= "Oldest record .....: " EventLog.Oldest(EventFile) "`n`n"
GuiEdit .= "Record number .....: " EventLog.Read(EventFile).RecordNumber "`n"
GuiEdit .= "Event ID ..........: " EventLog.Read(EventFile).EventID "`n"
GuiEdit .= "Type ..............: " EventLog.Read(EventFile).EventType "`n"
GuiEdit .= "Category ..........: " EventLog.Read(EventFile).EventCategory "`n"

; GUI ===========================================================================================================================

OnMessage(0x0111, "ON_EN_SETFOCUS")

Gui, Margin, 0, 0
Gui, Font, s9, Courier New
Gui, Add, Edit, xm ym w400 h300 -0x200000, % GuiEdit
Gui, Show, AutoSize, % "EventLog"
return

; EXIT ==========================================================================================================================

GuiClose:
GuiEscape:
ExitApp

; FUNCTIONS =====================================================================================================================

ON_EN_SETFOCUS(wParam, lParam)
{
    Critical
    if ((wParam >> 16) = 0x0100)
    {
        DllCall("user32.dll\HideCaret", "Ptr", lParam)
        DllCall("user32.dll\PostMessage", "Ptr", lParam, "UInt", 0x00B1, "Ptr", -1, "Ptr" , 0)
    }
}

; CLASS =========================================================================================================================

Class EventLog
{
    ;static advapi32 := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")

    Open(SourceName)
    {
        if !(hEventLog := DllCall("advapi32.dll\OpenEventLog", "Str", "", "Str", SourceName, "Ptr"))
            MsgBox % ErrorLevel
        return hEventLog
    }

    Count(SourceName)
    {
        hEventLog := this.Open(SourceName)
        if !(DllCall("advapi32.dll\GetNumberOfEventLogRecords", "Ptr", hEventLog, "UInt*", NumberOfRecords))
            MsgBox % ErrorLevel
        this.Close(hEventLog)
        return NumberOfRecords
    }

    Oldest(SourceName)
    {
        hEventLog := this.Open(SourceName)
        if !(DllCall("advapi32.dll\GetOldestEventLogRecord", "Ptr", hEventLog, "UInt*", OldestRecord))
            MsgBox % ErrorLevel
        this.Close(hEventLog)
        return OldestRecord
    }

    Read(SourceName)
    {
        static EventType := { 1: "ERROR", 2: "WARNING", 4: "INFORMATION", 8: "AUDIT_SUCCESS", 16: "AUDIT_FAILURE" }
        hEventLog := this.Open(SourceName)
        VarSetCapacity(EVENTLOGRECORD, 2, 0)
        DllCall("advapi32.dll\ReadEventLog", "Ptr", hEventLog, "UInt", 0x0001|0x0008, "UInt", 0, "Ptr", &EVENTLOGRECORD, "UInt", 0, "UInt*", 0, "UInt*", size)
        VarSetCapacity(EVENTLOGRECORD, size + 1, 0)
        if !(DllCall("advapi32.dll\ReadEventLog", "Ptr", hEventLog, "UInt", 0x0001|0x0008, "UInt", 0, "Ptr", &EVENTLOGRECORD, "UInt", size, "UInt*", 0, "UInt*", 0))
            MsgBox % ErrorLevel
        REL := {}
        REL.Length        := NumGet(EVENTLOGRECORD,  0, "UInt")                 ; Length
		REL.RecordNumber  := NumGet(EVENTLOGRECORD,  8, "UInt")                 ; RecordNumber
        REL.EventID       := NumGet(EVENTLOGRECORD, 20, "UInt") & 0x7FFF        ; EventID
        REL.EventType     := EventType[NumGet(EVENTLOGRECORD, 24, "UShort")]    ; EventType
		REL.EventCategory := NumGet(EVENTLOGRECORD, 28, "UShort")               ; EventCategory
        this.Close(hEventLog)
        return REL
    }

    Close()
    {
        DllCall("advapi32.dll\CloseEventLog", "Ptr", hEventLog)
    }
}
Image
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
Elesar
Posts: 70
Joined: 31 Oct 2013, 07:56

Re: Windows Event Log API examples / libs?

29 Sep 2015, 09:22

As another option, I have used this for a year or two to check that my servers did their backups as scheduled. Simply calling wevtutil and then I go and parse out the resulting XML as needed. This is very fast and simple to use, but could slow down a bit depending on how you build your query. This is filtered to only show "recent" backup events.

Code: Select all

;Get the event log
      objShell := ComObjCreate("WScript.Shell")
      objExec := objShell.Exec(ComSpec " /c wevtutil qe Microsoft-Windows-Backup /q:""*[System[TimeCreated[timediff(@SystemTime) <= 86400000]]]"" /r:" server " /u:" user " /p:" pass)
      while, !objExec.StdOut.AtEndOfStream
         xml := objExec.StdOut.ReadAll()
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Windows Event Log API examples / libs?

06 Nov 2015, 06:06

I am trying to take jNizM's code an modify it to walk back through the event log until it finds a matching record.

However, I cannot seem to work out how to pull the Strings from the Event (ie the "Description" text).

Any help?

Code: Select all

; GLOBAL SETTINGS ===============================================================================================================
 
#NoEnv
#SingleInstance Force
#NoTrayIcon

; GUI ===========================================================================================================================
 
OnMessage(0x0111, "ON_EN_SETFOCUS")
 
Gui, Margin, 0, 0
Gui, Font, s9, Courier New
Gui, Add, Edit, xm ym w400 h300 -0x200000 hwndhEdit
Gui, Show, AutoSize, % "EventLog"

PollEventLog()

return
 
; EXIT ==========================================================================================================================
 
GuiClose:
GuiEscape:
ExitApp
 
; FUNCTIONS =====================================================================================================================

PollEventLog(){
    static LastRecord := 0
    global hEdit
    static EventFile := "Application"
     
    if (LastRecord){
        
    }
     
    GuiEdit := "Event .............: " EventFile "`n"
    GuiEdit .= "Record count ......: " EventLog.Count(EventFile) "`n"
    GuiEdit .= "Oldest record .....: " EventLog.Oldest(EventFile) "`n`n"
    GuiEdit .= "Record number .....: " EventLog.Read(EventFile).RecordNumber "`n"
    GuiEdit .= "Event ID ..........: " EventLog.Read(EventFile).EventID "`n"
    GuiEdit .= "Type ..............: " EventLog.Read(EventFile).EventType "`n"
    GuiEdit .= "Category ..........: " EventLog.Read(EventFile).EventCategory "`n"
    GuiEdit .= "NumStrings ........: " EventLog.Read(EventFile).NumStrings "`n"
    GuiEdit .= "StringOffset ......: " EventLog.Read(EventFile).StringOffset "`n"
    GuiControl, , % hEdit, % GuiEdit
    LastRecord := EventLog.Read(EventFile).RecordNumber
}

ON_EN_SETFOCUS(wParam, lParam)
{
    Critical
    if ((wParam >> 16) = 0x0100)
    {
        DllCall("user32.dll\HideCaret", "Ptr", lParam)
        DllCall("user32.dll\PostMessage", "Ptr", lParam, "UInt", 0x00B1, "Ptr", -1, "Ptr" , 0)
    }
}
 
; CLASS =========================================================================================================================
 
Class EventLog
{
    ;static advapi32 := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")
 
    Open(SourceName)
    {
        if !(hEventLog := DllCall("advapi32.dll\OpenEventLog", "Str", "", "Str", SourceName, "Ptr"))
            MsgBox % ErrorLevel
        return hEventLog
    }
 
    Count(SourceName)
    {
        hEventLog := this.Open(SourceName)
        if !(DllCall("advapi32.dll\GetNumberOfEventLogRecords", "Ptr", hEventLog, "UInt*", NumberOfRecords))
            MsgBox % ErrorLevel
        this.Close(hEventLog)
        return NumberOfRecords
    }
 
    Oldest(SourceName)
    {
        hEventLog := this.Open(SourceName)
        if !(DllCall("advapi32.dll\GetOldestEventLogRecord", "Ptr", hEventLog, "UInt*", OldestRecord))
            MsgBox % ErrorLevel
        this.Close(hEventLog)
        return OldestRecord
    }
 
    Read(SourceName)
    {
        static EventType := { 1: "ERROR", 2: "WARNING", 4: "INFORMATION", 8: "AUDIT_SUCCESS", 16: "AUDIT_FAILURE" }
        static LastRecord := 0
        
        hEventLog := this.Open(SourceName)
        
        VarSetCapacity(EVENTLOGRECORD, 2, 0)
        DllCall("advapi32.dll\ReadEventLog", "Ptr", hEventLog, "UInt", 0x0001|0x0008, "UInt", 0, "Ptr", &EVENTLOGRECORD, "UInt", 0, "UInt*", 0, "UInt*", size)
        VarSetCapacity(EVENTLOGRECORD, size + 1, 0)
        if !(DllCall("advapi32.dll\ReadEventLog", "Ptr", hEventLog, "UInt", 0x0001|0x0008, "UInt", 0, "Ptr", &EVENTLOGRECORD, "UInt", size, "UInt*", 0, "UInt*", 0))
            MsgBox % ErrorLevel
        REL := {}
        REL.Length        := NumGet(EVENTLOGRECORD,  0, "UInt")                 ; Length
        REL.RecordNumber  := NumGet(EVENTLOGRECORD,  8, "UInt")                 ; RecordNumber
        REL.EventID       := NumGet(EVENTLOGRECORD, 20, "UInt") & 0x7FFF        ; EventID
        REL.EventType     := EventType[NumGet(EVENTLOGRECORD, 24, "UShort")]    ; EventType
        REL.NumStrings    := NumGet(EVENTLOGRECORD, 26, "UShort")               ; NumStrings
        REL.EventCategory := NumGet(EVENTLOGRECORD, 28, "UShort")               ; EventCategory
        REL.StringOffset := NumGet(EVENTLOGRECORD, 36, "UShort")                ; StringOffset
        
        LastRecord := REL.RecordNumber
        ; How to read Strings??
        
        this.Close(hEventLog)
        return REL
    }
 
    Close()
    {
        DllCall("advapi32.dll\CloseEventLog", "Ptr", hEventLog)
    }
}
just me
Posts: 9451
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Windows Event Log API examples / libs?

06 Nov 2015, 07:40

The strings stored in the EVENTLOGRECORD structure are/can be message inserts. So this might be only the first step.

Code: Select all

    Read(SourceName)
    {
        static EventType := { 1: "ERROR", 2: "WARNING", 4: "INFORMATION", 8: "AUDIT_SUCCESS", 16: "AUDIT_FAILURE" }
        static LastRecord := 0

        hEventLog := this.Open(SourceName)

        VarSetCapacity(EVENTLOGRECORD, 2, 0)
        DllCall("advapi32.dll\ReadEventLog", "Ptr", hEventLog, "UInt", 0x0001|0x0008, "UInt", 0, "Ptr", &EVENTLOGRECORD, "UInt", 0, "UInt*", 0, "UInt*", size)
        VarSetCapacity(EVENTLOGRECORD, size + 1, 0)
        if !(DllCall("advapi32.dll\ReadEventLog", "Ptr", hEventLog, "UInt", 0x0001|0x0008, "UInt", 0, "Ptr", &EVENTLOGRECORD, "UInt", size, "UInt*", 0, "UInt*", 0))
            MsgBox % ErrorLevel
        REL := {}
        REL.Length        := NumGet(EVENTLOGRECORD,  0, "UInt")                 ; Length
        REL.RecordNumber  := NumGet(EVENTLOGRECORD,  8, "UInt")                 ; RecordNumber
        REL.EventID       := NumGet(EVENTLOGRECORD, 20, "UInt") & 0x7FFF        ; EventID
        REL.EventType     := EventType[NumGet(EVENTLOGRECORD, 24, "UShort")]    ; EventType
        REL.NumStrings    := NumGet(EVENTLOGRECORD, 26, "UShort")               ; NumStrings
        REL.EventCategory := NumGet(EVENTLOGRECORD, 28, "UShort")               ; EventCategory
        REL.StringOffset  := NumGet(EVENTLOGRECORD, 36, "UInt") ;<<<< UInt      ; StringOffset

        LastRecord := REL.RecordNumber
        ; -----------------------------------------------------------------------
        ; How to read Strings??
        Description := ""
        StringAddr := &EVENTLOGRECORD + REL.StringOffset
        Loop, % Rel.NumStrings {
            String := StrGet(StringAddr, "UTF-16")
            Description .= String . "`n"
            StringAddr += (StrLen(String) + 1) * 2
        }
        MsgBox, %Description%
        ; -----------------------------------------------------------------------
        this.Close(hEventLog)
        return REL
    }
Notes:
- related to sequential reading I think it's not good idea to open and close the eventlog each time you read a record
- you should fill the Gui using object returned by the first EventLog.Read()
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Windows Event Log API examples / libs?

06 Nov 2015, 11:23

Awesome, this worked fine.
- related to sequential reading I think it's not good idea to open and close the eventlog each time you read a record
Yeah, I was in the process of modifying the function to loop through the event log and only return new items that matched criteria.

Here is what I ended up with:
You can pass an EventId and a Regex to match on the description text.
It places matches in the returned object, along with a return code.
0 = nothing found, -1 = nothing found since last match, n = Record Number of new match

Code: Select all

Class EventLog
{
    ;static advapi32 := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")
 
    Open(SourceName)
    {
        if !(hEventLog := DllCall("advapi32.dll\OpenEventLog", "Str", "", "Str", SourceName, "Ptr"))
            MsgBox % ErrorLevel
        return hEventLog
    }
 
    Count(SourceName)
    {
        hEventLog := this.Open(SourceName)
        if !(DllCall("advapi32.dll\GetNumberOfEventLogRecords", "Ptr", hEventLog, "UInt*", NumberOfRecords))
            MsgBox % ErrorLevel
        this.Close(hEventLog)
        return NumberOfRecords
    }
 
    Oldest(SourceName)
    {
        hEventLog := this.Open(SourceName)
        if !(DllCall("advapi32.dll\GetOldestEventLogRecord", "Ptr", hEventLog, "UInt*", OldestRecord))
            MsgBox % ErrorLevel
        this.Close(hEventLog)
        return OldestRecord
    }
 
    Read(SourceName, eventid := -1, descregex := "")
    {
        static EventType := { 1: "ERROR", 2: "WARNING", 4: "INFORMATION", 8: "AUDIT_SUCCESS", 16: "AUDIT_FAILURE" }
		static last_message := 0
		count := 0
		
        hEventLog := this.Open(SourceName)
 
		Loop {
			VarSetCapacity(EVENTLOGRECORD, 2, 0)
			DllCall("advapi32.dll\ReadEventLog", "Ptr", hEventLog, "UInt", 0x0001|0x0008, "UInt", 0, "Ptr", &EVENTLOGRECORD, "UInt", 0, "UInt*", 0, "UInt*", size)
			VarSetCapacity(EVENTLOGRECORD, size + 1, 0)
			if !(DllCall("advapi32.dll\ReadEventLog", "Ptr", hEventLog, "UInt", 0x0001|0x0008, "UInt", 0, "Ptr", &EVENTLOGRECORD, "UInt", size, "UInt*", 0, "UInt*", 0)){
				MsgBox % "ReadEventLog Failed with code " ErrorLevel
				break
			}
			REL := {}
			REL.Length        := NumGet(EVENTLOGRECORD,  0, "UInt")                  ; Length
			REL.RecordNumber  := NumGet(EVENTLOGRECORD,  8, "UInt")                  ; RecordNumber
			REL.TimeGenerated := NumGet(EVENTLOGRECORD,  12, "UInt")                 ; TimeGenerated
			REL.EventID       := NumGet(EVENTLOGRECORD,  20, "UInt") & 0x7FFF        ; EventID
			REL.EventType     := EventType[NumGet(EVENTLOGRECORD, 24, "UShort")]     ; EventType
			REL.NumStrings    := NumGet(EVENTLOGRECORD,  26, "UShort")               ; NumStrings
			REL.EventCategory := NumGet(EVENTLOGRECORD,  28, "UShort")               ; EventCategory
			REL.StringOffset  := NumGet(EVENTLOGRECORD,  36, "UInt") ;<<<< UInt      ; StringOffset
			REL.Match         := 0
			if (!count){
				; On first loop through
				if (last_message){
					if (last_message = REL.RecordNumber){
						; No new messages since last loop - abort
						REL.match := -1
						return REL
					}
				}
				last_message := REL.RecordNumber
			}
			count++
			if (eventid != -1 && REL.EventID = eventid){
				Description := ""
				StringAddr := &EVENTLOGRECORD + REL.StringOffset
				Loop, % Rel.NumStrings {
					String := StrGet(StringAddr, "UTF-16")
					Description .= String . "`n"
					StringAddr += (StrLen(String) + 1) * 2
				}
				if (RegExMatch(Description, "O)" descregex, match)){
					REL.Match := match
					break
				}
			}
		}
 
        ; -----------------------------------------------------------------------
        this.Close(hEventLog)
        return REL
    }
 
    Close()
    {
        DllCall("advapi32.dll\CloseEventLog", "Ptr", hEventLog)
    }
}
User avatar
vescou
Posts: 6
Joined: 25 Oct 2016, 15:05

Re: Windows Event Log API examples / libs?

22 Oct 2019, 05:42

Hello,
I cant understand how to get ERROR log only - or search for specific EventID
My idea is to SetTimer and create Service to login automatically and parse the EventLog .. but this Class is the only one i found for WinEvents in AHK :(
User avatar
vescou
Posts: 6
Joined: 25 Oct 2016, 15:05

Re: Windows Event Log API examples / libs?

22 Oct 2019, 07:55

May someone explain me what is the jNizM function do: ON_EN_SETFOCUS(wParam, lParam) also ?

This is how i ended for today. (working)

Code: Select all

#SingleInstance Force
#Warn UseUnsetLocal, Off
#NoEnv
;#NoTrayIcon
#Persistent
SetWorkingDir %A_ScriptDir%
SetBatchLines -1

VarSetCapacity(vOutput, 1000000*2)

vSourceName := "Security"
vEventID := 4625	; Logon Failures

SetTimer, LogParser, -1000
Return

LogParser:
if !(hEventLog := DllCall("advapi32\OpenEventLog", Str,"", Str,vSourceName, Ptr))
{
	MsgBox, % "error"
	return
}

vOutput := ""
Loop
{
	VarSetCapacity(EVENTLOGRECORD, 2, 0)
	DllCall("advapi32\ReadEventLog", Ptr,hEventLog, UInt,0x9, UInt,0, Ptr,&EVENTLOGRECORD, UInt,0, UIntP,0, UIntP,vSize)
	VarSetCapacity(EVENTLOGRECORD, vSize+1, 0)
	if !(DllCall("advapi32\ReadEventLog", Ptr,hEventLog, UInt,0x9, UInt,0, Ptr,&EVENTLOGRECORD, UInt,vSize, UIntP,0, UIntP,0)) 
	{
		break
	}
	Else
	{
		vNumStrings := NumGet(EVENTLOGRECORD,  26, "UShort")               		; NumStrings			- Used for vDescription
		vStringOffset  := NumGet(EVENTLOGRECORD,  36, "UInt") ;<<<< UInt      ; StringOffset		- Used for vDescription
		vDate := NumGet(EVENTLOGRECORD, 12, "UInt")														; EventDate
		vEventCategory := NumGet(EVENTLOGRECORD,  28, "UShort")               ; EventCategory
		vEventID2 := NumGet(EVENTLOGRECORD, 20, "UInt") & 0x7FFF							; EventID
		if !(vEventID2 = vEventID)
		{
			continue
		}
		Else
		{
			vDescription := ""
			StringAddr := &EVENTLOGRECORD + vStringOffset
			Loop, % vNumStrings
			{
				String := StrGet(StringAddr, "UTF-16")
				vDescription .= String . "`n"
				StringAddr += (StrLen(String) + 1) * 2
			}

			vDate2 := vDate
			vDate := 1970
			vDate += vDate2, Seconds
			vOutput .= "(" vEventCategory ") - " vDate " - " vDescription "`n"
		}
	}
}

MsgBox, % vOutput
Return 
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Windows Event Log API examples / libs?

22 Oct 2019, 08:00

ON_EN_SETFOCUS has nothing todo with the Event Log API.
It's a function to hide the Edit Focus from a Gui in AHK.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
vescou
Posts: 6
Joined: 25 Oct 2016, 15:05

Re: Windows Event Log API examples / libs?

31 Oct 2019, 04:19

Does someone know how to Read Events from SMBClient EventLog folder ? :crazy:
User avatar
vescou
Posts: 6
Joined: 25 Oct 2016, 15:05

Re: Windows Event Log API examples / libs?

31 Oct 2019, 05:30

I found this in C#:

Code: Select all

https stackoverflow.com /questions/33080746/reading-event-logs-from-application-and-services-logs-using-c-sharp-printservi
Broken Link for safety Broken Link for safety

But cant make it work in Ahk for reading and finding EventID in:
Microsoft-Windows-SmbClient/Connectivity
Microsoft-Windows-SmbClient/Security
Microsoft-Windows-SmbClient/Audit

Please help me out, i really want to Monitor those events in my Environment ..

@jNizM - you are my hero here .. i start Autohotkey because of your good examples back in the days .. save me again please
User avatar
vescou
Posts: 6
Joined: 25 Oct 2016, 15:05

Re: Windows Event Log API examples / libs?

08 Nov 2019, 05:12

It cant be done .. i get lost in this :headwall:
chaoscreater
Posts: 60
Joined: 12 Sep 2019, 21:15

Re: Windows Event Log API examples / libs?

17 Jul 2023, 17:59

How can I read from the Application and Services Logs?
Attachments
image.png
image.png (25.16 KiB) Viewed 1040 times

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: AHK_user and 242 guests