Search code examples
pythonevent-logpywin32

Get an event object from win32evtlog.EvtQuery results


I'd like to search the Windows Event Log for events by their attributes. win32evtlog.EvtQuery looks like just the thing.

So, I can e.g. query for system starting events and retrieve the last one like this:

import win32evtlog
hevq=win32evtlog.EvtQuery("System",win32evtlog.EvtQueryReverseDirection,\
        "*[System[Provider[@Name='eventlog'] and (EventID=6009)]]",None)
hev=win32evtlog.EvtNext(hevq,1)[0]

But what I get is some random handle which all I can do with, according to the EvtNext docs, is pass it to EvtRender to get an XML representation.

But, I don't want to parse it and would like to get a good ol' PyEventLogRecord instead like I do with win32evtlog.ReadEventLog.

Is there a way to do this while still using EvtQuery? I don't wanna read all the events sequentially, there are tens of thousands of them.


Solution

  • The Vista Event Log API (functions with names starting with Evt) does not use the EVENTLOGRECORD structure (which is what PyEventLogRecord wraps), nor are the "new" events designed to be representable with it. A string in XML format actually is the "native" export representation now rather than some C structure (this explains why Vista's Event Viewer is so extremely sluggish, unlike its XP's counterpart). And only with this API one can access the Vista-introduced "Application and Service logs".

    • The only alternative to the XML is to only output some fields by calling EvtCreateRenderContext first (which is not supported by pywin32. It only supports outputting the full XML out of the box).

    pywin32 doesn't include any facilities to parse the XML - probably because the original API doesn't either and the authors didn't want to encumber the library with irrelevant stuff. Wevtapi.dll doesn't use a full-fledged XML library so it likely only outputs some small subset of XML which can be parsed in a similarly ad-hoc manner - but this would be a time bomb as M$ gives no guarantees about what subset it is.


    I ended up parsing "this sh1t" with lxml. Knowing that, loony as it is, it's the native representation now, made me feel better about installing and encumbering my program with such a major library for such a simple and unrelated task.