Search code examples
pythonwindowswmievent-logpywin32

How to notify a specific windows log event?


I am working on a program that needs to notify a specific event in windows event log. I do not know the parameters that are needed to be specified in the NotifyChangeEventLog() function.

Below is the code I have been working with:

import win32evtlog 

server = 'localhost' # name of the target computer to get event logs
logtype = 'Application' # 'Application' # 'Security'
hand = win32evtlog.OpenEventLog(server,logtype)
flags = 
win32evtlog.EVENTLOG_BACKWARDS_READ|win32evtlog.EVENTLOG_SEQUENTIAL_READ
total = win32evtlog.GetNumberOfEventLogRecords(hand)
print total
notify = win32evtlog.NotifyChangeEventLog(hand, 1)

I get this error:

notify = win32evtlog.NotifyChangeEventLog(hand, 1)

Traceback (most recent call last):

File "", line 1, in

notify = win32evtlog.NotifyChangeEventLog(hand, 1)

error: (6, 'NotifyChangeEventLog', 'The handle is invalid.')

What are the parameters?


Solution

  • You figured out the 1st parameter, which is a handle to an open event log.

    According to [MS.Docs]: NotifyChangeEventLog function (that win32evtlog.NotifyChangeEventLog wraps):

    hEvent

    A handle to a manual-reset or auto-reset event object. Use the CreateEvent function to create the event object.

    So, you need something like this.

    code.py:

    #!/usr/bin/env python3
    
    import sys
    import win32evtlog
    import win32event
    import win32api
    import win32con
    import msvcrt
    
    
    def main():
        server = None # "localhost" # name of the target computer to get event logs
        source_type = "System" # "Application" # "Security"
        h_log = win32evtlog.OpenEventLog(server, source_type)
        flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
        total = win32evtlog.GetNumberOfEventLogRecords(h_log)
        print(total)
        h_evt = win32event.CreateEvent(None, 1, 0, "evt0")
        win32evtlog.NotifyChangeEventLog(h_log, h_evt)
        print("Waiting for changes in the '{:s}' event log. Press a key to exit...".format(source_type))
        while not msvcrt.kbhit():
            wait_result = win32event.WaitForSingleObject(h_evt, 500)
            if wait_result == win32con.WAIT_OBJECT_0:
                print("The '{:s}' event log has been modified".format(source_type))
                # Any processing goes here
            elif wait_result == win32con.WAIT_ABANDONED:
                print("Abandoned")
    
        win32api.CloseHandle(h_evt)
        win32evtlog.CloseEventLog(h_log)
    
    
    if __name__ == "__main__":
        print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
        main()
    

    Notes:

    • For demo purposes, I am using the "System" event log because there's a simple way of generating events
      • Go to "Services", pick one (preferably one that's not running), and change its "Startup type". When clicking "Apply", an event will be generated, which in turn will generate output from the script.
        At the end, don't forget to undo the changes
    • For details regarding reading log events, check [SO]: Converting Python win32evtlog objects to xml (@CristiFati's answer)

    Output:

    (py27x64_test) e:\Work\Dev\StackOverflow\q051036392>"e:\Work\Dev\VEnvs\py27x64_test\Scripts\python.exe" code.py
    Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:53:40) [MSC v.1500 64 bit (AMD64)] on win32
    
    3430
    Waiting for changes in the 'System' event log. Press a key to exit...
    The 'System' event log has been modified
    The 'System' event log has been modified