using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Diagnostics.Eventing.Reader;
using System.Security.Principal;
using System.Threading.Tasks;
namespace EventLogQueryTool
{
public class LogReader
{
private bool _hasAdminPrivileges = false;
private bool _privilegeChecked = false;
private readonly Dictionary<int, (EventType, string)> _eventDescriptionMap = new Dictionary<int, (EventType, string)>
{
{ 6005, (EventType.Startup, "系統已正常啟動") },
{ 6006, (EventType.Shutdown, "系統已正常關機") },
{ 6008, (EventType.Shutdown, "系統上次未正常關機,可能是意外斷電") },
{ 12, (EventType.Startup, "系統已啟動,操作系統已加載完成") },
{ 41, (EventType.Error, "系統意外斷電或重啟") },
{ 1074, (EventType.Shutdown, "用戶發起關機或重啟操作") },
{ 1, (EventType.Hibernate, "系統從睡眠狀態中喚醒") },
{ 42, (EventType.Hibernate, "系統進入睡眠狀態") },
{ 506, (EventType.Hibernate, "系統從休眠狀態恢復") },
{ 16, (EventType.Other, "IOMMU錯誤報告已初始化") },
{ 2, (EventType.Other, "Intel管理引擎接口驅動已啟動") },
{ 6, (EventType.Other, "文件系統篩選器已成功加載") },
{ 98, (EventType.Other, "磁盤卷運行狀況良好") },
{ 55, (EventType.Other, "處理器電源管理功能已配置") },
{ 125, (EventType.Other, "已枚舉電源管理熱區域") },
{ 172, (EventType.Other, "備用連接已斷開") },
{ 20, (EventType.Other, "閏秒配置已更新") },
{ 14, (EventType.Other, "憑證保護已配置") },
{ 15, (EventType.Other, "憑證保護和虛擬化安全已配置") },
{ 6155, (EventType.Other, "憑證保護可能受影響,LSA包簽名異常") },
{ 36871, (EventType.Other, "安全連接創建失敗,可能影響網絡通信") },
{ 4000, (EventType.Other, "無線網絡自動配置服務已啟動") },
{ 7000, (EventType.Error, "系統文件保護服務啟動失敗") },
{ 7001, (EventType.Error, "IP硬件服務啟動失敗") },
{ 1003, (EventType.Other, "系統搜索服務已啟動") },
{ 900, (EventType.Other, "軟件保護服務正在啟動") },
{ 902, (EventType.Other, "軟件保護服務已啟動") },
{ 1000, (EventType.Error, "應用程序錯誤") },
{ 1001, (EventType.Other, "Windows錯誤報告") },
{ 1026, (EventType.Error, "應用程序異常終止") },
{ 1008, (EventType.Other, "性能數據將不可用") },
{ 153, (EventType.Other, "基于虛擬化的安全性已禁用") },
{ 18, (EventType.Other, "系統有多個啟動選項") },
{ 19, (EventType.Other, "系統有多個引導工具選項") },
{ 17, (EventType.Other, "已顯示多系統選擇啟動菜單") },
{ 32, (EventType.Other, "引導程序等待用戶輸入時間很短") },
{ 25, (EventType.Other, "引導菜單策略已設置") },
{ 27, (EventType.Other, "系統引導類型已確認") },
{ 30, (EventType.Other, "系統已報告啟動指標") },
{ 24, (EventType.Other, "時區信息已更新") },
{ 7026, (EventType.Other, "部分引導啟動驅動程序未加載") },
{ 11, (EventType.Other, "文件系統篩選器不支持繞過IO") }
};
private readonly string[] _logNames = new[]
{
"System",
"Application",
"Microsoft-Windows-Diagnostics-Performance/Operational"
};
public List<EventItem> ReadEvents(DateTime start, DateTime end)
{
Debug.WriteLine($"📅 查詢時間范圍: {start:yyyy-MM-dd HH:mm:ss} 到 {end:yyyy-MM-dd HH:mm:ss}");
bool hasAdminPrivileges = CheckAdminPrivileges();
Debug.WriteLine($"開始讀取事件日志,權限狀態: 管理員 = {hasAdminPrivileges}");
var availableLogs = GetAvailableLogNames().ToList();
if (availableLogs.Count > 0)
{
if ((end - start).TotalDays > 7)
{
Debug.WriteLine("時間范圍較大,啟用分塊讀取策略");
return ReadWithEventLogReaderInChunks(start, end, availableLogs);
}
else
{
var result = ReadWithEventLogReader(start, end, availableLogs);
if (result.Count > 0) return result;
}
}
try
{
var result = ReadWithEventLog(start, end);
if (result.Count > 0) return result;
}
catch (Exception ex) { Debug.WriteLine($"EventLog 讀取失敗: {ex.Message}"); }
try
{
var result = ReadWithWmi(start, end);
if (result.Count > 0) return result;
}
catch (Exception ex) { Debug.WriteLine($"WMI 讀取失敗: {ex.Message}"); }
Debug.WriteLine("所有讀取策略均失敗,返回空列表");
return new List<EventItem>();
}
private List<EventItem> ReadWithEventLogReader(DateTime start, DateTime end, IEnumerable<string> logNames)
{
var allEvents = new List<EventItem>();
var availableLogs = logNames.Where(IsLogAvailable).ToList();
if (availableLogs.Count == 0) return allEvents;
int maxParallelism = (end - start).TotalDays > 7 ? 2 : 4;
Parallel.ForEach(availableLogs, new ParallelOptions { MaxDegreeOfParallelism = maxParallelism }, logName =>
{
var stopwatch = Stopwatch.StartNew();
var events = SafeReadEventLog(logName, start, end);
stopwatch.Stop();
Debug.WriteLine($"日志 {logName}: {events.Count} 條記錄,耗時 {stopwatch.ElapsedMilliseconds}ms");
lock (allEvents) allEvents.AddRange(events);
});
return allEvents;
}
private List<EventItem> ReadWithEventLogReaderInChunks(DateTime start, DateTime end, IEnumerable<string> logNames)
{
var allEvents = new List<EventItem>();
double totalDays = (end - start).TotalDays;
TimeSpan chunkSize = totalDays > 30 ? TimeSpan.FromDays(5) :
totalDays > 7 ? TimeSpan.FromDays(3) :
TimeSpan.FromDays(1);
Debug.WriteLine($"分塊讀取: 塊大小 {chunkSize.Days} 天");
foreach (var logName in logNames)
{
if (!IsLogAvailable(logName)) continue;
var currentStart = start;
while (currentStart < end)
{
var currentEnd = currentStart + chunkSize;
if (currentEnd > end) currentEnd = end;
var chunkEvents = SafeReadEventLogChunk(logName, currentStart, currentEnd);
if (chunkEvents.Count > 0)
allEvents.AddRange(chunkEvents);
currentStart = currentEnd;
if (currentStart < end) System.Threading.Thread.Sleep(50);
}
}
return allEvents;
}
private List<EventItem> ReadWithEventLog(DateTime start, DateTime end)
{
var events = new List<EventItem>();
foreach (string logName in _logNames)
{
if (!EventLog.Exists(logName)) continue;
try
{
using (EventLog log = new EventLog(logName))
{
foreach (EventLogEntry entry in log.Entries)
{
if (entry.TimeGenerated >= start && entry.TimeGenerated <= end)
{
var item = ConvertEventLogEntry(entry);
if (item != null) events.Add(item);
}
}
}
}
catch (Exception ex) { Debug.WriteLine($"EventLog 讀取 {logName} 失敗: {ex.Message}"); }
}
return events;
}
private List<EventItem> ReadWithWmi(DateTime start, DateTime end)
{
var events = new List<EventItem>();
try
{
string startWmi = ManagementDateTimeConverter.ToDmtfDateTime(start);
string endWmi = ManagementDateTimeConverter.ToDmtfDateTime(end);
string query = $"SELECT * FROM Win32_NTLogEvent WHERE TimeGenerated >= '{startWmi}' AND TimeGenerated <= '{endWmi}'";
using (var searcher = new ManagementObjectSearcher(query))
{
foreach (var obj in searcher.Get().Cast<ManagementObject>())
{
var item = ConvertManagementObject(obj);
if (item != null) events.Add(item);
}
}
}
catch (Exception ex) { Debug.WriteLine($"WMI 查詢失敗: {ex.Message}"); }
return events;
}
private EventItem ConvertEventRecord(EventRecord record)
{
try
{
int eventId = (int)record.Id;
string source = record.ProviderName;
string description = GetFriendlyDescription(eventId, source, record.FormatDescription());
return new EventItem
{
Time = record.TimeCreated?.ToLocalTime() ?? DateTime.MinValue,
EventId = eventId,
Level = record.LevelDisplayName,
Source = OptimizeSourceName(source),
Type = GetEventType(eventId, source),
Description = description
};
}
catch { return null; }
}
private EventItem ConvertEventLogEntry(EventLogEntry entry)
{
try
{
int eventId = (int)entry.InstanceId;
string source = entry.Source;
string description = GetFriendlyDescription(eventId, source, entry.Message);
return new EventItem
{
Time = entry.TimeGenerated,
EventId = eventId,
Level = entry.EntryType.ToString(),
Source = OptimizeSourceName(source),
Type = GetEventType(eventId, source),
Description = description
};
}
catch { return null; }
}
private EventItem ConvertManagementObject(ManagementObject obj)
{
try
{
int eventId = Convert.ToInt32(obj["EventCode"]);
string source = obj["SourceName"]?.ToString() ?? "";
string level = obj["Type"]?.ToString() ?? "";
DateTime? time = ManagementDateTimeConverter.ToDateTime(obj["TimeGenerated"]?.ToString());
string description = GetFriendlyDescription(eventId, source, obj["Message"]?.ToString() ?? "");
return new EventItem
{
Time = time ?? DateTime.MinValue,
EventId = eventId,
Level = level,
Source = OptimizeSourceName(source),
Type = GetEventType(eventId, source),
Description = description
};
}
catch { return null; }
}
private EventType GetEventType(int eventId, string source)
{
if (_eventDescriptionMap.TryGetValue(eventId, out var tuple))
return tuple.Item1;
if (source.Contains("Power") || source.Contains("Power-Troubleshooter")) return EventType.Other;
if (source.Contains("Security") || source.Contains("SPP")) return EventType.Other;
if (source.Contains("Service") || source.Contains("Control Manager")) return EventType.Other;
if (source.Contains("Winlogon") || source.Contains("User Profiles")) return EventType.Other;
if (source.Contains("Startup") || source.Contains("Boot") || source.Contains("Kernel-Boot")) return EventType.Startup;
if (source.Contains("Hardware") || source.Contains("Kernel") || source.Contains("Driver")) return EventType.Other;
if (source.Contains("Shutdown") || source.Contains("Kernel-Power")) return EventType.Shutdown;
if (source.Contains("Hibernate") || source.Contains("Sleep") || source.Contains("Resume")) return EventType.Hibernate;
if (source.Contains("Error") || source.Contains("Critical") || source.Contains("Failure")) return EventType.Error;
return EventType.Other;
}
private string GetFriendlyDescription(int eventId, string source, string description)
{
if (string.IsNullOrEmpty(description))
return "無描述信息";
if (_eventDescriptionMap.TryGetValue(eventId, out var tuple))
return tuple.Item2;
if (description.Contains("系統啟動時間為") || description.Contains("system startup time is"))
{
var match = System.Text.RegularExpressions.Regex.Match(description, @"(\d+)\s*秒");
if (match.Success && int.TryParse(match.Groups[1].Value, out int seconds))
{
string timeDesc = $"系統啟動完成,啟動耗時: {seconds}秒";
if (seconds < 10) timeDesc += "(快速啟動)";
else if (seconds < 20) timeDesc += "(正常啟動)";
else timeDesc += "(較慢啟動)";
return timeDesc;
}
return "系統啟動完成";
}
return OptimizeEventDescription(description, eventId, source);
}
private string OptimizeEventDescription(string description, int _, string __)
{
if (string.IsNullOrEmpty(description)) return "無描述信息";
description = description.Replace("Microsoft-Windows-", "")
.Replace("EventLog", "事件日志")
.Replace("Service Control Manager", "服務管理器")
.Replace("The ", "")
.Replace("Windows", "系統");
if (description.Length > 100)
description = description.Substring(0, 100) + "...";
return description;
}
private string OptimizeSourceName(string source)
{
const int MAX_LEN = 30;
if (string.IsNullOrEmpty(source)) return "未知來源";
var mappings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "Microsoft-Windows-Kernel-Power", "電源管理" },
{ "Microsoft-Windows-Kernel-Boot", "系統啟動" },
{ "Microsoft-Windows-Power-Troubleshooter", "電源問題" },
{ "Service Control Manager", "服務管理器" },
{ "EventLog", "事件日志" },
{ "Microsoft-Windows-Diagnostics-Performance", "性能診斷" },
{ "Microsoft-Windows-Winlogon", "用戶登錄" },
{ "Microsoft-Windows-Security-SPP", "軟件保護" },
{ "Microsoft-Windows-FilterManager", "文件系統" },
{ "Microsoft-Windows-Ntfs", "NTFS文件系統" },
{ "Microsoft-Windows-WLAN-AutoConfig", "無線網絡" },
{ "Microsoft-Windows-Schannel", "安全連接" }
};
foreach (var m in mappings)
if (source.Contains(m.Key))
return m.Value;
if (source.StartsWith("Microsoft-Windows-"))
{
string keyPart = source.Substring("Microsoft-Windows-".Length);
int slash = keyPart.IndexOf('/');
if (slash > 0) keyPart = keyPart.Substring(0, slash);
keyPart = keyPart.Replace("-", " ");
if (keyPart.Length > MAX_LEN)
{
var parts = keyPart.Split(' ');
keyPart = parts.Length > 1 ? parts[parts.Length - 1] : keyPart;
if (keyPart.Length > MAX_LEN) keyPart = keyPart.Substring(0, MAX_LEN) + "...";
}
return keyPart;
}
return source.Length > MAX_LEN ? source.Substring(0, MAX_LEN) + "..." : source;
}
private bool CheckAdminPrivileges()
{
if (_privilegeChecked) return _hasAdminPrivileges;
try
{
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
_hasAdminPrivileges = principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch { _hasAdminPrivileges = false; }
_privilegeChecked = true;
return _hasAdminPrivileges;
}
public string GetPrivilegeWarningMessage()
{
return CheckAdminPrivileges() ?
"當前具有管理員權限,可以讀取所有事件日志。" :
"當前權限不足,只能讀取部分事件日志。建議以管理員身份運行程序以獲得完整功能。";
}
private bool IsLogAvailable(string logName)
{
var known = new[] { "System", "Application", "Microsoft-Windows-Diagnostics-Performance/Operational" };
if (known.Contains(logName, StringComparer.OrdinalIgnoreCase)) return true;
try { return EventLog.Exists(logName); }
catch { return false; }
}
private List<EventItem> SafeReadEventLog(string logName, DateTime start, DateTime end)
{
if (end - start > TimeSpan.FromDays(7))
return ReadEventLogInChunks(logName, start, end);
var events = new List<EventItem>();
string query = $"*[System[TimeCreated[@SystemTime >= '{start.ToUniversalTime():o}' and @SystemTime <= '{end.ToUniversalTime():o}']]]";
try
{
using (var reader = new EventLogReader(new EventLogQuery(logName, PathType.LogName, query)))
{
EventRecord record;
while ((record = reader.ReadEvent()) != null)
{
var item = ConvertEventRecord(record);
if (item != null) events.Add(item);
}
}
}
catch (Exception ex) { Debug.WriteLine($"SafeReadEventLog 錯誤: {ex.Message}"); }
return events;
}
private List<EventItem> ReadEventLogInChunks(string logName, DateTime start, DateTime end)
{
var all = new List<EventItem>();
double days = (end - start).TotalDays;
TimeSpan chunk = days > 30 ? TimeSpan.FromDays(5) : days > 7 ? TimeSpan.FromDays(3) : TimeSpan.FromDays(1);
var current = start;
while (current < end)
{
var chunkEnd = current + chunk;
if (chunkEnd > end) chunkEnd = end;
var chunkEvents = SafeReadEventLogChunk(logName, current, chunkEnd);
if (chunkEvents.Count > 0) all.AddRange(chunkEvents);
current = chunkEnd;
if (current < end) System.Threading.Thread.Sleep(50);
}
return all;
}
private List<EventItem> SafeReadEventLogChunk(string logName, DateTime start, DateTime end)
{
var events = new List<EventItem>();
string query = $"*[System[TimeCreated[@SystemTime >= '{start.ToUniversalTime():o}' and @SystemTime <= '{end.ToUniversalTime():o}']]]";
try
{
using (var reader = new EventLogReader(new EventLogQuery(logName, PathType.LogName, query)))
{
EventRecord record;
int count = 0;
while ((record = reader.ReadEvent()) != null && count < 10000)
{
var item = ConvertEventRecord(record);
if (item != null) { events.Add(item); count++; }
}
}
}
catch { /* 靜默失敗 */ }
return events;
}
private IEnumerable<string> GetAvailableLogNames()
{
foreach (var name in _logNames)
if (IsLogAvailable(name))
yield return name;
}
}
}