将Python win32evtlog对象转换为xm

2024-09-26 18:08:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个应用程序使用win32evtlog获取和显示不同的事件,我希望将显示限制为特定级别的事件,但win32evtlog不返回此值。似乎您可以将事件转换为XML,然后提取此信息,但我无法确定如何将事件从循环获取为XML。

我可以使用它来显示LogObject拥有的数据,比如LogObject.TimeGenerated

Log = win32evtlog.OpenEventLog('localhost', 'Application')
while 1:
    LogObjects = winev32tlog.ReadEventLog(Log, win32evtlog.EVENTLOG_BACKWARDS_READ|wine32vtlog.EVENTLOG_SEQUENTIAL_READ, 0)
    if not LogObjects:
        break
    for LogObject in LogObjects:

我试着用

LogObjectXML = win32evtlog.EvtRender(LogObject, 1)

不幸的是这又回来了

TypeError: The object is not a PyHANDLE object

所以我知道我需要得到某种handle对象,可以用来将EvtRender指向正确的事件,但无法计算出我是如何做到的。

这个问题与How retrieve from Python win32evtlog rest of info?非常相似,但是那里的解决方案没有回答我们如何将对象转换为XML的关键问题。

--==使用有关CristiFati的XML的信息进行编辑=--

下面是事件消息读取的应用程序事件的示例:

Updated Windows Defender status successfully to SECURITY_PRODUCT_STATE_ON.

根据事件查看器的XML如下

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="SecurityCenter" /> 
  <EventID Qualifiers="0">15</EventID> 
  <Level>4</Level> 
  <Task>0</Task> 
  <Keywords>0x80000000000000</Keywords> 
  <TimeCreated SystemTime="2017-05-23T07:36:27.627108000Z" /> 
  <EventRecordID>49419</EventRecordID> 
  <Channel>Application</Channel> 
  <Computer>Name.domain.here</Computer> 
  <Security /> 
  </System>
- <EventData>
  <Data>Windows Defender</Data> 
  <Data>SECURITY_PRODUCT_STATE_ON</Data> 
  </EventData>
  </Event>

Tags: log信息应用程序readdataobjectapplication事件
1条回答
网友
1楼 · 发布于 2024-09-26 18:08:54

ReadEventLog返回PyEventLogRecords(wrapper over[MS.Docs]: _EVENTLOGRECORD structure),而EvtRender期望(您需要使用)PyHANDLEs(PyEVT\u HANDLEs(wrapper overEVT\u HANDLE[MS.Docs]: Windows Event Log Data Types)更精确)。
因此,要获取XML数据,需要使用与此类型一起工作的函数族:例如EvtQueryEvtNext

代码.py

#!/usr/bin/env python3

import sys
import pywintypes
import win32evtlog

INFINITE = 0xFFFFFFFF
EVTLOG_READ_BUF_LEN_MAX = 0x7FFFF


def get_record_data(eventlog_record):
    ret = dict()
    for key in dir(eventlog_record):
        if 'A' < key[0] < 'Z':
            ret[key] = getattr(eventlog_record, key)
    return ret


def get_eventlogs(source_name="Application", buf_size=EVTLOG_READ_BUF_LEN_MAX, backwards=True):
    ret = list()
    evt_log = win32evtlog.OpenEventLog(None, source_name)
    read_flags = win32evtlog.EVENTLOG_SEQUENTIAL_READ
    if backwards:
        read_flags |= win32evtlog.EVENTLOG_BACKWARDS_READ
    else:
        read_flags |= win32evtlog.EVENTLOG_FORWARDS_READ
    offset = 0
    eventlog_records = win32evtlog.ReadEventLog(evt_log, read_flags, offset, buf_size)
    while eventlog_records:
        ret.extend(eventlog_records)
        offset += len(eventlog_records)
        eventlog_records = win32evtlog.ReadEventLog(evt_log, read_flags, offset, buf_size)
    win32evtlog.CloseEventLog(evt_log)
    return ret


def get_events_xmls(channel_name="Application", events_batch_num=100, backwards=True):
    ret = list()
    flags = win32evtlog.EvtQueryChannelPath
    if backwards:
        flags |= win32evtlog.EvtQueryReverseDirection
    try:
        query_results = win32evtlog.EvtQuery(channel_name, flags, None, None)
    except pywintypes.error as e:
        print(e)
        return ret
    events = win32evtlog.EvtNext(query_results, events_batch_num, INFINITE, 0)
    while events:
        for event in events:
            ret.append(win32evtlog.EvtRender(event, win32evtlog.EvtRenderEventXml))
        events = win32evtlog.EvtNext(query_results, events_batch_num, INFINITE, 0)
    return ret


def main():
    import sys, os
    from collections import OrderedDict
    standard_log_names = ["Application", "System", "Security"]
    source_channel_dict = OrderedDict()

    for item in standard_log_names:
        source_channel_dict[item] = item

    for item in ["Windows Powershell"]: # !!! This works on my machine (96 events)
        source_channel_dict[item] = item

    for source, channel in source_channel_dict.items():
        print(source, channel)
        logs = get_eventlogs(source_name=source)
        xmls = get_events_xmls(channel_name=channel)
        #print("\n", get_record_data(logs[0]))
        #print(xmls[0])
        #print("\n", get_record_data(logs[-1]))
        #print(xmls[-1])
        print(len(logs))
        print(len(xmls))

if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

注意:

  • 两个列表的长度应该相同。每个函数中的nth项都应该引用相同的事件(只要两个函数对backward参数使用相同的值调用(read below
  • 获取事件:
    • 返回与事件关联的XMLblob的列表
    • 错误处理不是最好的,您可以将所有API调用包装在try/except子句中(我没有遇到错误,所以我不确定什么情况下会引发异常)
    • 您可以稍微使用[MS.Docs]: EvtNext function的参数(TimeoutEventsSize进行性能微调;对我来说,~20k事件在<;10秒内被处理,其中文本打印和转换占用最多)
    • Python 3中,XMLs是字节[Python 3.Docs]: Built-in Types - classbytes([source[, encoding[, errors]]]))而不是普通字符串(我必须对它们进行编码,因为有些字符串包含一些非-ASCII字符,试图打印它们会引发unicodeerror
    • 事件过滤是可能的,检查[MS.Docs]: EvtQuery function的参数(标志查询
    • 注意backward参数,该参数允许按相反(时间顺序)顺序遍历事件(默认设置为True)。
  • 获取记录数据:
    • 这只是一个方便的函数,它将PyEventLogRecord对象转换为Python字典
    • 转换基于这样一个事实:我们关心的字段以大写字母开头(EventID,C计算机名,TimeGenerated,…),这就是为什么它不应该在生产中使用的原因
    • 它不转换实际值(TimeGenerated的值是pywintypes.datetime(2017, 3, 11, 3, 46, 47)
  • 获取事件日志:
  • 因为我将所有数据存储在2个列表中(而不是就地数据处理),所以我选择的是速度而不是内存消耗。对于~20K事件,这两个列表采用~30MBRAM(现在我认为这已经足够了)

@EDIT0:我找不到使用Evt*函数系列获取所有必需信息的方法,因此我从两个来源获取信息(我增强了先前发布的脚本):

@EDIT1:根据[MS.Docs]: OpenEventLogW function

If you specify a custom log and it cannot be found, the event logging service opens the Application log; however, there will be no associated message or category string file.

[MS.Docs]: Eventlog Key列出了3个标准值。所以,这就是它打开应用程序日志的原因。我对脚本做了一些小改动来测试源代码。我不知道从哪里得到的nts来自。

相关问题 更多 >

    热门问题