将 Python win32evtlog 对象转换为 xml [英] Converting Python win32evtlog objects to xml
问题描述
我有一个使用 win32evtlog 来获取和显示不同事件的应用程序,我想将显示限制为特定级别的事件,但 win32evtlog 不返回此内容.似乎您可以将事件转换为 XML,然后提取此信息,但我无法弄清楚如何将事件从循环获取到 XML.
I have a app that uses win32evtlog to get and display different events and I would like to limit the display to events of a specific level but win32evtlog doesn't return this. It seems that you can convert an event to XML and then pull this info but I can't work out how you get the event from a loop to XML.
我可以得到以下内容并使用它来显示 LogObject 具有的数据,例如 LogObject.TimeGenerated
I can get up to the following and use it to display data the LogObject has such as 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
所以我知道我需要获得某种句柄对象,我可以用它来将 EvtRender 指向正确的事件,但不知道我是如何做到的.
So I know I need to get some sort of handle object that I can use to point the EvtRender at the correct event but can't work out how I do that.
这个问题很像如何从Python中检索win32evtlog rest信息?但是那里的解决方案没有回答我们如何将对象转换为 XML 的关键部分.
This question is quite similar to How retrieve from Python win32evtlog rest of info? but the solution there didn't answer the critical bit of how we convert the object to XML.
--== 编辑了有关 CristiFati 的 XML 的信息 ==--
--== Edited with information about the XML for CristiFati ==--
以下是事件消息读取的应用程序事件示例:-
Below is an example of an Application event where the event message reads:-
Updated Windows Defender status successfully to SECURITY_PRODUCT_STATE_ON.
每个事件查看器的 XML 如下
The XML as per event viewer is as below
- <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>
推荐答案
ReadEventLog 返回 PyEventLogRecords(封装在 [MS.Docs]: _EVENTLOGRECORD 结构),而 EvtRender 期望(您需要使用)PyHANDLE(PyEVT_HANDLE(EVT_HANDLE 上的包装器([MS.Docs]:Windows 事件日志数据类型)更精确)).
因此,要获取 XML 数据,您需要使用适用于此类型的函数系列:例如EvtQuery、EvtNext.
ReadEventLog returns PyEventLogRecords (wrapper over [MS.Docs]: _EVENTLOGRECORD structure), while EvtRender expects (you need to work with) PyHANDLEs (PyEVT_HANDLEs (wrapper over EVT_HANDLE ([MS.Docs]: Windows Event Log Data Types) to be more precise)).
So, for getting XML data, you need to use the functions family that works with this type: e.g. EvtQuery, EvtNext.
code.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()
注意事项:
- 这 2 个列表的长度应该相同.每个函数中的 nth 条目应该引用相同的事件(只要两个函数的 backwards 参数(阅读下文))
- get_events_xmls:
- 返回与事件关联的 XML blob 列表
- 错误处理不是最好的,您可以将所有 API 调用包装在
try
/except
子句中(我没有遇到错误,所以我不确定在什么情况下可能会引发异常) - 您可以使用 [MS.Docs]:EvtNext 函数的参数(Timeout 和 EventsSize 用于性能微调;对我来说,~20k事件在 <10 秒内处理完毕 - 其中文本打印和转换花费最多)
- 在Python 3中,XML是字节([Python 3.Docs]:内置类型 - class bytes([source[, encoding[, errors]]])) 而不是普通字符串(我不得不对它们进行编码,因为有些包含一些非ASCII字符,并尝试打印它们会引发 UnicodeEncodeError)
- 事件过滤是可能的,检查[MS.Docs]:EvtQuery 函数的参数(Flags 和 Query)
- 注意 backwards 参数,它允许以相反的(时间顺序)顺序遍历事件(默认设置为 True).
- The 2 lists should have the same length. The nth entry in each of them should reference the same event (as long as both functions are called with same value for backwards argument (read below))
- get_events_xmls:
- Returns a list of XML blobs associated to the events
- The error handling is not the best, you could wrap all API calls in
try
/except
clauses (I didn't run into errors, so I'm not sure what are the situations where exception could be raised) - You can play a little bit with [MS.Docs]: EvtNext function's arguments (Timeout and EventsSize for performance fine tuning; for me, ~20k events were processed in a matter of <10 seconds - out of which text printing and conversions took the most)
- In Python 3, the XMLs are bytes ([Python 3.Docs]: Built-in Types - class bytes([source[, encoding[, errors]]])) rather than normal strings (I had to encode them because some contain some non-ASCII chars, and attempting to print them would raise UnicodeEncodeError)
- Event filtering is possible, check [MS.Docs]: EvtQuery function's args (Flags and Query)
- Note the backwards argument which allows traversing the events in reversed (chronological) order (default set to True).
- 这只是一个方便的函数,它将PyEventLogRecord 对象转换为Python 字典
- 转换基于这样一个事实,即我们关心的字段以大写字母开头(EventID、ComputerName、TimeGenerated、...),这就是为什么它不应该用于生产
- 它不会转换实际值(TimeGenerated 的值为
pywintypes.datetime(2017, 3, 11, 3, 46, 47)
)立>
- It's just a convenience function, it converts a PyEventLogRecord object into a Python dictionary
- The conversion is based on the fact that fields that we care about start with a capital letter (EventID, ComputerName, TimeGenerated, ...), that's why it shouldn't be used in production
- It doesn't convert the actual values (TimeGenerated's value is
pywintypes.datetime(2017, 3, 11, 3, 46, 47)
)
- 返回 PyEventLogRecord 的列表
- 在 get_events_xmls 的案例中,注意 backwards 参数
- 我必须坚持 buf_size.作为 [MS.Docs]:ReadEventLogW 函数 表示,在获取事件时,可以使用最大 512K 的缓冲区.现在(从 PyWin32 版本 220 开始),可以将它作为参数(最后一个)传递给
win32evtlog.ReadEventLog
.检查 [SourceForge.hg]: mhammond/pywin32 - 添加缓冲区ReadEventLog 的大小参数(来自 cristi fati 的补丁 #143) 了解更多详细信息.默认情况下,有一个限制,因此缓冲区大小被硬编码为 1K.由于每个 ReadEventLog 都在访问磁盘,使用新的缓冲区大小,我获得了 10X 的速度提升(对于 ~180K 个事件)
- Returns a list of PyEventLogRecords
- As in get_events_xmls's case note the backwards argument
- I must insist on buf_size. As [MS.Docs]: ReadEventLogW function states, when getting the events, a buffer of max 512K can be used. Now (starting with PyWin32 version 220), it's possible to pass it as an argument (the last one) to
win32evtlog.ReadEventLog
. Check [SourceForge.hg]: mhammond/pywin32 - Add buffer size parameter for ReadEventLog (patch #143 from cristi fati) for more details. By default, there was a limitation so that the buffer size was hardcoded to 1K. Since every ReadEventLog was accessing the disk, with the new buffer size I got a 10X speed improvement (for ~180K events)
@EDIT0:我找不到使用 Evt* 函数系列获取所有必需信息的方法,所以我'我从两个来源获取它(我增强了我之前发布的脚本):
@EDIT0: I couldn't find a way to get all the required info with the Evt* functions family, so I'm getting it from both sources (I enhanced the script that I've previously posted):
@EDIT1:根据 [MS.Docs]:OpenEventLogW 函数:
如果您指定自定义日志但找不到,则事件日志服务会打开应用程序日志;但是,不会有关联的消息或类别字符串文件.
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]:事件日志密钥 列出了 3 个标准.所以,这就是它打开 Application 日志的原因.我对脚本做了一些小的改动来测试源代码.我不知道 mmc 从哪里获取 Setup 事件.
[MS.Docs]: Eventlog Key lists the 3 standard ones. So, that's why it opens the Application log. I've done some small changes to the script to test the sources. I don't know where mmc gets the Setup events from.
这篇关于将 Python win32evtlog 对象转换为 xml的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!