ReadEventLog 返回 PyEventLogRecords([MS.Docs]: _EVENTLOGRECORD structure 上的包装器),而 EvtRender 期望(您需要使用)PyHANDLE s(PyEVT_HANDLEs(更准确地说是 EVT_HANDLE ([MS.Docs]: Windows Event Log Data Types) 的包装))。
因此,为了获取 XML 数据,您需要使用适用于此类型的函数系列:例如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()
注意事项:
- 这两个列表的长度应该相同。它们每个中的 nth 条目应该引用相同的事件(只要调用两个函数的 backwards 参数值相同(阅读下文))
-
get_events_xmls:
-
get_record_data:
- 只是一个方便的函数,它将一个PyEventLogRecord对象转换成一个Python字典
- 转换是基于我们关心的字段以大写字母开头(EventID、C omputerName, TimeGenerated, ...),这就是为什么它不应在生产中使用
- 它不会转换实际值(TimeGenerated 的值是
pywintypes.datetime(2017, 3, 11, 3, 46, 47))
-
get_eventlogs:
- 由于我将所有数据存储在 2 个列表中(而不是就地数据处理),因此我选择的是速度而不是内存消耗。对于 ~20K 事件,这两个列表占用了 ~30MB 的 RAM(现在我认为这已经足够了)
@EDIT0:我找不到使用 Evt* 函数系列获取所有必需信息的方法,所以我'我从两个来源获取它(我增强了我之前发布的脚本):
@EDIT1:根据[MS.Docs]: OpenEventLogW function:
如果您指定了自定义日志但找不到,则事件日志服务打开应用程序日志;但是,不会有关联的消息或类别字符串文件。
[MS.Docs]: Eventlog Key 列出了 3 个标准。所以,这就是它打开 Application 日志的原因。我对脚本做了一些小的改动来测试源代码。我不知道 mmc 从哪里得到 Setup 事件。