「上週五半夜,伺服器好像自己重新開機了」「只有特定的終端機,業務應用程式每個月都會當機好幾次」── 這類調查的起點,幾乎必定是 Windows 的事件記錄。然而,若在事件檢視器的 GUI 中捲動數十萬筆日誌,光是這樣一個上午就過去了。
使用 PowerShell 的 Get-WinEvent,這項工作只要幾十秒就能完成。不過有個條件:必須在正確的地方進行篩選。如果寫成 Get-WinEvent | Where-Object { ... },就會先讀入全部事件之後再丟棄,甚至可能比 GUI 還慢。
本文將整理正確使用 Get-WinEvent 篩選功能的方法、實務現場常見的調查手法(非預期的重新開機、登入、應用程式異常結束、服務停止),以及跨多台機器收集記錄的做法。
前提環境
| 項目 | 內容 |
|---|---|
| 對象作業系統 | Windows 10/11、Windows Server。Get-WinEvent 讀取的是Windows Vista 之後的事件記錄基礎架構,可同時處理傳統(Classic)日誌與 ETW 日誌1 |
| PowerShell 版本 | Windows PowerShell 5.1 與 PowerShell 7 皆可使用(Get-WinEvent 是僅限 Windows 使用的命令,在 Linux/macOS 的 PowerShell 7 中無法使用)。本文的程式碼採用可在 5.1 與 7 都能執行的寫法1 |
| 權限 | System、Application 等多數日誌一般使用者也能讀取,但讀取 Security 日誌需要系統管理員權限,或取得等效的權限授予。有些日誌若不是以系統管理員身分執行就無法取得資訊(第 4 章 (2) 有權限授予的步驟)12 |
| 遠端取得 | 第 5 章的方法 1(-ComputerName)不依賴 PowerShell 遠端處理(WinRM)。取而代之的是,需要在目標機器的防火牆上允許對事件記錄服務的遠端存取。方法 2(Invoke-Command)則以 WinRM 為前提1 |
1. 先講結論
- 請使用
Get-WinEvent,而不是Get-EventLog。前者僅限 Windows PowerShell 使用,而且只能處理傳統日誌,在 PowerShell 7 中無法使用。1 - 篩選請用
-FilterHashtable進行。因為篩選是在事件記錄那一側進行,比起用Where-Object做後段篩選要快上好幾個數量級。3 -FilterHashtable可用的鍵是固定的。有LogName、ProviderName、ID、Level、StartTime、EndTime、Keywords、Path、UserID等。3- 複雜條件或依事件資料篩選時使用 XPath(
-FilterXPath)。可以從事件檢視器的「自訂檢視表」複製出 XPath。1 Level是數值。1=重大、2=錯誤、3=警告、4=資訊、5=詳細。4- 讀取 Security 日誌需要特別的權限。以系統管理員身分執行雖然方便,但對負責調查的人員來說,透過「Event Log Readers」群組或通道 ACL 只授予讀取權限,比較符合最小權限原則。12
- 請看事件資料,而不是訊息字串。用
ToXml()取得結構化資料,就能寫出不受作業系統顯示語言影響的腳本。1 .evtx檔案也可以解析。指定-Path就能在本機分析現場採集回來的日誌。1- 恆常性的集中收集請用 Windows 事件轉送(WEF)。若只是單次調查,用
Invoke-Command並列執行就足夠了。5
2. 兩種日誌與命令的選擇
Windows 的事件記錄大致上分為兩個系統。
| 種類 | 例子 | 可讀取的命令 |
|---|---|---|
| 傳統(Classic)日誌 | System / Application / Security | Get-EventLog(僅限 5.1)・Get-WinEvent |
| 應用程式與服務記錄 | Microsoft-Windows-TaskScheduler/Operational 等 |
僅限 Get-WinEvent |
後者才是包含調查所需重要資訊的地方。工作排程器的執行歷程記錄、PowerShell 的指令碼區塊記錄、Windows Update 的套用歷程等,許多能決定原因的關鍵日誌都在這一側。因此,往後要寫的腳本統一使用 Get-WinEvent 才是正解。1
首先確認有哪些日誌。
# 日誌清單(依筆數多寡排序)。RecordCount 為 0 的日誌代表尚未記錄任何內容
Get-WinEvent -ListLog * -ErrorAction SilentlyContinue |
Where-Object RecordCount -gt 0 |
Sort-Object RecordCount -Descending |
Select-Object LogName, RecordCount, MaximumSizeInBytes, IsEnabled -First 20
# 尋找特定產品的日誌
Get-WinEvent -ListLog *TaskScheduler* | Format-Table LogName, IsEnabled, RecordCount
Get-WinEvent -ListProvider *PowerShell* | Select-Object Name
3. 篩選的關鍵在於「在哪裡進行」
比較三種能得到相同結果的寫法。
# 【最差】讀入全部之後才在 PowerShell 端丟棄
Get-WinEvent -LogName System | Where-Object { $_.Id -eq 41 }
# 【建議】在事件記錄那一側篩選(FilterHashtable)
Get-WinEvent -FilterHashtable @{ LogName = 'System'; ID = 41 }
# 【複雜條件】用 XPath 篩選
Get-WinEvent -LogName System -FilterXPath "*[System[EventID=41]]"
第一種寫法會先把數十萬筆事件全部物件化之後再丟棄,絕大部分的等待時間都是浪費的。第二種、第三種則是在事件記錄的 API 端進行篩選,只會傳回需要的內容。3
-FilterHashtable 可用的鍵是固定的。3
| 鍵 | 指定的內容 | 範例 |
|---|---|---|
LogName |
日誌名稱 | 'System', 'Microsoft-Windows-TaskScheduler/Operational' |
ProviderName |
事件的來源 | 'Application Error', 'Service Control Manager' |
ID |
事件識別碼(可用陣列) | 41, @(1000, 1001) |
Level |
嚴重程度(數值) | 2(錯誤), @(1,2) |
StartTime / EndTime |
時間範圍 | (Get-Date).AddDays(-7) |
Keywords |
關鍵字(稽核成功/失敗等) | 9007199254740992(稽核成功) |
Path |
.evtx 檔案 |
'D:\collect\srv01_System.evtx' |
UserID |
使用者 SID | 'S-1-5-21-...' |
Level 的數值如下所示。4
值(Level) |
日文環境的顯示 | 英文環境的顯示 |
|---|---|---|
| 1 | 重大 | Critical |
| 2 | エラー | Error |
| 3 | 警告 | Warning |
| 4 | 情報 | Information |
| 5 | 詳細 | Verbose |
右邊兩欄,分別是事件檢視器的「層級」欄,以及 Get-WinEvent 結果中 LevelDisplayName 屬性所顯示的字串(此表僅供比對用,因此照原樣列出各語言環境實際顯示的文字)。LevelDisplayName 會隨作業系統的顯示語言而改變。用肉眼比對輸出結果時可以參考這張對照表,但在腳本中進行篩選時,請務必指定數值型的 Level(若用顯示名稱判斷,腳本在英文環境下就無法運作)。
整理成實務上可用的形式,會是這樣。
# 統計最近 7 天內的錯誤・重大事件,依來源分組(掌握現況的第一步)
$filter = @{
LogName = 'System', 'Application'
Level = 1, 2
StartTime = (Get-Date).AddDays(-7)
}
try {
Get-WinEvent -FilterHashtable $filter -ErrorAction Stop |
Group-Object ProviderName, Id |
Sort-Object Count -Descending |
Select-Object Count, Name -First 15
}
catch {
# 只安靜地忽略「找不到符合的事件」。不依賴地區設定,
# 用 FullyQualifiedErrorId 判斷(訊息字串在日文環境下不會相符)
if ($_.FullyQualifiedErrorId -notlike 'NoMatchingEventsFound*') { throw }
}
結果的判讀方式。Group-Object 的輸出有 Count 與 Name 兩欄。因為是用 ProviderName, Id 這樣的多個屬性進行分組,所以 Name 會以逗號分隔列出「來源, 事件識別碼」(例如:Service Control Manager, 7034)。輸出依筆數由多到少排序,第一步要看的是排在前面的來源是否眼生、是否有對應到故障發生時段的筆數高峰。先在這裡抓出頭緒,再用下一章的方法深入個別事件。
若沒有任何符合的事件,Get-WinEvent 會回傳錯誤。這裡請不要輕易加上 -ErrorAction SilentlyContinue。「沒有符合的項目」、「沒有讀取該日誌的權限」、「無法連線到目標機器」,這三種情況都會變成同樣的「空結果」。在調查現場,這是最麻煩的一種故障模式。
如上面的寫法,用 -ErrorAction Stop 接住錯誤,只有在 FullyQualifiedErrorId 是 NoMatchingEventsFound 時才把它吞掉,才是正確做法。若用訊息字串判斷,在日文環境下不會相符,因而無法正常運作(關於錯誤處理的思考方式,請參考「PowerShell 的錯誤處理與重試設計」)。
4. 現場常見的調查手法
(1) 非預期的重新開機・關機
# 41:未經正常關機程序就重新開機(Kernel-Power)
# 6008:非預期的關機(EventLog)
# 1074:由處理程序/使用者要求的關機(可得知是誰、什麼東西讓機器關機)
# 6005/6006:事件記錄服務的啟動/停止(= 開機/關機的標記)
Get-WinEvent -FilterHashtable @{
LogName = 'System'
ID = 41, 1074, 6005, 6006, 6008
StartTime = (Get-Date).AddDays(-30)
} | Select-Object TimeCreated, Id, ProviderName,
@{ n = 'Message'; e = { ($_.Message -split "`r?`n")[0] } } |
Sort-Object TimeCreated -Descending | Format-Table -AutoSize
結果的判讀方式。輸出是 TimeCreated / Id / ProviderName / Message(內容很長,只取第一行)這 4 欄,依新到舊排序。要看的重點不是每一行的內容,而是每一次重新開機,是哪些識別碼、依什麼順序排列。如果是計劃性的重新開機,會出現 1074(有人提出要求)→ 6006(事件記錄服務停止=正常關機)→ 6005(啟動=開機完成)這樣成組出現的模式。
1074 是能得知「是誰要求重新開機」的重要事件。如果這裡出現 WindowsUpdate 或特定的處理程序名稱,原因幾乎就能確定。如果只出現 41 和 6008、卻沒有 1074,就要懷疑是斷電或當機造成的異常停止。
(2) 登入・登出的追蹤(Security 日誌)
# 4624:登入成功 / 4625:登入失敗 / 4634:登出
# 需要讀取 Security 日誌的權限(以系統管理員身分執行,
# 或先把執行帳戶加入 Event Log Readers 群組)
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
ID = 4624, 4625, 4634
StartTime = (Get-Date).AddDays(-1)
} | ForEach-Object {
$xml = [xml]$_.ToXml()
$d = @{}
foreach ($n in $xml.Event.EventData.Data) { $d[$n.Name] = $n.'#text' }
[pscustomobject]@{
時間 = $_.TimeCreated
類型 = switch ($_.Id) { 4624 { '登入成功' } 4625 { '登入失敗' } 4634 { '登出' } }
使用者 = $d['TargetUserName']
登入類型 = $d['LogonType'] # 2=互動式 3=網路 10=RDP
來源 = $d['IpAddress']
}
} | Where-Object 使用者 -notlike '*$' | Format-Table -AutoSize
這是使用事件資料的典型範例。若用正規表示式切割 Message,會受作業系統的顯示語言影響,但 ToXml() 的 EventData 可以用名稱來參照,因此不論是日文環境還是英文環境,同一支腳本都能正常運作。6
結果的判讀方式。輸出是 時間 / 類型 / 使用者 / 登入類型 / 來源 這 5 欄(因為是用 [pscustomobject] 自行組合的,所以欄位名稱與順序都可以自己決定)。最後加上 Where-Object 使用者 -notlike '*$',把電腦帳戶(名稱以 $ 結尾)排除掉,因此留下的都是人的帳戶。要看的重點是:登入類型 為 3(網路)或 10(RDP)的資料列中,來源 是否出現眼生的 IP 位址、同一個使用者的 4625(失敗)是否在短時間內連續出現。
若稽核功能未啟用,事件本身就不會被記錄,這一點也請留意。「一筆都沒有」不代表「什麼都沒發生」,也可能是「根本沒被記錄下來」。
只把「讀取權限」交給負責調查的人員。為了讓對方能讀取 Security 日誌而配發系統管理員權限,是應該避免的做法。只要把帳戶加入內建的 Event Log Readers 群組(SID 為 S-1-5-32-573),不需要系統管理員權限也能讀取事件記錄。2
# 在目標電腦上執行(需要系統管理員權限)。
# 內建群組的顯示名稱可能因作業系統語言而不同,用 SID 指定較為可靠
Add-LocalGroupMember -SID 'S-1-5-32-573' -Member 'EXAMPLE\稽核負責人'
# 確認是否已成功加入
Get-LocalGroupMember -SID 'S-1-5-32-573'
若要配發到多台機器,可以使用群組原則的「電腦設定 > 原則 > Windows 設定 > 安全性設定 > 受限制的群組」,或群組原則喜好設定的「電腦設定 > 喜好設定 > 控制台設定 > 本機使用者和群組」,設定將網域群組加入各伺服器本機的 Event Log Readers。
若要進一步以個別通道為單位縮小範圍,可以用 wevtutil 確認・變更每個日誌的存取權限(SDDL)。2
wevtutil gl Security # 顯示目前的設定(channelAccess 為 SDDL)
# wevtutil sl Security /ca:<SDDL> # 變更設定。/ca 是「取代」既有的 SDDL
/ca 不是附加,而是取代。變更之前請務必先保留 wevtutil gl 的輸出結果。
(3) 應用程式異常結束
# 1000:Application Error(應用程式當機)
# 1026:.NET Runtime(因受控例外而終止)
# 1001:Windows Error Reporting(錯誤儲存區資訊)
Get-WinEvent -FilterHashtable @{
LogName = 'Application'
ID = 1000, 1001, 1026
StartTime = (Get-Date).AddDays(-14)
} | Select-Object TimeCreated, Id, ProviderName, Message |
Sort-Object TimeCreated -Descending | Format-List
1000 裡面會有當機的模組名稱與位移量,1026 裡面則會有.NET 的例外堆疊。先在這裡抓出頭緒,再進入傾印檔分析會比較有效率(「Windows 當機傾印檔收集入門」「用 WinDbg + SOS 解讀當機傾印檔」)。
(4) 服務的停止・重新啟動
# 7034:服務非預期終止 / 7031:終止後執行復原動作 / 7045:安裝了新服務
Get-WinEvent -FilterHashtable @{
LogName = 'System'
ProviderName = 'Service Control Manager'
ID = 7031, 7034, 7045
StartTime = (Get-Date).AddDays(-30)
} | Select-Object TimeCreated, Id, Message | Format-List
7045(安裝新服務)也很適合用來偵測非預期安裝的軟體。關於 Windows 服務的維運設計,請參考「Windows 服務的建立與維運」。
(5) 工作排程器的執行歷程記錄
此節會用到 XPath,因此先掌握一下基本架構。事件記錄的 XPath 實際上只要記住兩種寫法即可。1
| 寫法 | 指向的內容 | 範例 |
|---|---|---|
*[System[ ... ]] |
任何事件都共通的項目(事件識別碼、時間、層級、提供者) | *[System[EventID=41]] |
*[EventData[Data[@Name='項目名']='值']] |
該事件特有的項目(具名的事件資料) | *[EventData[Data[@Name='TaskName']='\夜間彙總']] |
只要用 and / or 把這兩者串起來即可。因為值的比對要用單引號,在 PowerShell 端請放進 here-string(@" ~ "@)中,就不必為了引號的巢狀而傷腦筋(下面的程式碼就是這種寫法)。
比起自己手動組出來,讓事件檢視器幫忙寫、再複製過來更快也更可靠。在「事件檢視器 > (在目標日誌上按右鍵) > 篩選目前的日誌」中透過 GUI 指定條件,切換到對話方塊的「XML」分頁,就會顯示出相同條件的 XML 查詢。其中夾在 <Select Path="..."> 和 </Select> 之間的部分,就可以原封不動地傳給 -FilterXPath 使用。1
# 【NG】先取得全部資料,再用顯示用訊息(受語言影響)篩選
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-TaskScheduler/Operational'
StartTime = (Get-Date).AddDays(-3)
} -ErrorAction SilentlyContinue |
Where-Object { $_.Message -like '*夜間彙總*' }
# 【OK】用工作名稱(事件資料)在伺服器端篩選。速度快,也不受語言影響
$xpath = @"
*[System[TimeCreated[timediff(@SystemTime) <= 259200000]]]
and
*[EventData[Data[@Name='TaskName']='\夜間彙總']]
"@
Get-WinEvent -LogName 'Microsoft-Windows-TaskScheduler/Operational' `
-FilterXPath $xpath -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, LevelDisplayName, Message | Format-List
timediff 是用毫秒為單位指定「距離現在經過多久」的 XPath 函式,259200000 就是 3 天。工作名稱要用註冊時的完整路徑(位於根目錄底下時為 \工作名稱)指定。顯示用的 Message 會受語言設定影響,而且是在用戶端進行篩選,因此請依照本文的方針,改用事件資料進行篩選。
這個日誌預設可能是停用的。啟用方法與工作無法執行時的排查方式,整理在「工作排程器的工作不執行、以 0x1 結束」中。
5. 調查多台・不同機器上的日誌
方法 1:直接遠端讀取
Get-WinEvent -ComputerName 'srv01' -FilterHashtable @{ LogName='System'; ID=41 } -MaxEvents 10
方法 2:用 Invoke-Command 並列查詢(機台數量多時適用)
$servers = 'srv01', 'srv02', 'srv03'
Invoke-Command -ComputerName $servers -ScriptBlock {
Get-WinEvent -FilterHashtable @{
LogName = 'System'; Level = 1, 2; StartTime = (Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, ProviderName, LevelDisplayName
} | Sort-Object PSComputerName, TimeCreated
Invoke-Command 會對多台電腦並列執行(「PowerShell Remoting(WinRM)入門」「PowerShell 的並列處理」)。
方法 3:採集 .evtx 後在本機解析
現場人員匯出的檔案,可以直接拿來讀取。比起透過網路反覆查詢要快,也能留下佐證紀錄。
# 在現場執行:wevtutil epl System D:\collect\srv01_System.evtx
Get-WinEvent -Path 'D:\collect\srv01_System.evtx' -FilterXPath "*[System[(Level=1 or Level=2)]]" |
Select-Object TimeCreated, Id, ProviderName, Message
方法 4:Windows 事件轉送(WEF) ── 若要恆常性地集中收集,就用這個方法。這是把各終端機的事件轉送到收集伺服器的標準功能,不需要額外安裝代理程式。5
6. 日誌的大小與保留期間
「想調查的時候才發現,那個時段的日誌早就被覆寫掉了」是非常常見的失敗案例。預設的最大大小偏小,在事件量大的環境中,可能幾天就會循環覆寫一輪。
# 確認目前的大小設定與保留狀況
Get-WinEvent -ListLog 'System', 'Application', 'Security' |
Select-Object LogName, IsEnabled, LogMode,
@{ n='MaxMB'; e={ [math]::Round($_.MaximumSizeInBytes / 1MB, 1) } },
RecordCount, OldestRecordNumber
# 變更最大大小(需要系統管理員權限。範例:把 System 日誌調整為 256MB)
wevtutil sl System /ms:268435456
對於預期需要調查的伺服器,或已發生故障的終端機,先把日誌容量調大,再等待問題重現是常見的做法。關於日誌的世代管理與自動封存,也請參考「PowerShell 腳本應用 ── 日誌調查、封存、報表化」。
7. 實務上的判斷準則(對照表)
| 情況 | 選擇 | 補充 |
|---|---|---|
| 往後要寫的腳本 | Get-WinEvent |
Get-EventLog 僅限 5.1、只能處理傳統日誌1 |
| 依日誌名稱・識別碼・時間範圍篩選 | -FilterHashtable |
最快、也最易讀3 |
| 依事件資料的內容篩選 | -FilterXPath / -FilterXml |
可從事件檢視器的自訂檢視表複製1 |
| 筆數多、耗時長 | 縮小時間範圍・-MaxEvents |
不要在 PowerShell 端做篩選 |
| 想從訊息中擷取值 | ToXml() 的 EventData |
不受語言設定影響的腳本1 |
| 多台機器的單次調查 | Invoke-Command |
會並列執行5 |
| 恆常性集中收集 | Windows 事件轉送(WEF) | 不需額外代理程式的標準功能5 |
| 過去的日誌已消失 | 擴大日誌容量 | 在等待問題重現之前先做好 |
8. 總結
- 統一使用
Get-WinEvent。Get-EventLog在 PowerShell 7 中無法使用,能處理的日誌也有限。 - 篩選請用
-FilterHashtable或-FilterXPath進行。用Where-Object做後段篩選,會讓調查所需的時間出現數量級的惡化。 - 調查重新開機時,除了 41、6008,也要看1074(是誰要求的)。應用程式異常結束則以 1000、1026、1001 為起點。
- 不用訊息字串、改用
ToXml()的事件資料,就能寫出不受語言設定影響的腳本。 - 多台機器的單次調查用
Invoke-Command,恆常性集中收集用 Windows 事件轉送,若需要留存佐證則採集.evtx後在本機解析。 - 想調查的時段的日誌若已經不存在,就什麼都做不了。重新檢視日誌容量,是故障應對準備工作中最優先的事項。
範例程式碼下載
本文提到的程式碼,已整理成可直接執行的形式提供下載。內含重新開機歷程記錄、登入歷程記錄、工作失敗、多台機器收集等範例。
本文的範例因為依賴 Windows 與租用戶環境,並未實際執行驗證。雖然已對所有檔案進行語法解析與 PSScriptAnalyzer 的靜態分析,但實際運作請務必在您自己的驗證機上確認。
# 語法解析 + 靜態分析(非 Windows 環境也能執行)
./Invoke-SampleTests.ps1
如果沒有可以嘗試的環境,也不需要在業務用終端機上拿正式環境的日誌來練習。Windows Sandbox 只要幾分鐘就能啟動乾淨的 Windows,關閉後就會消失(「用 Windows Sandbox 加速應用程式開發驗證的方法」)。不過 Sandbox 是剛啟動的環境,幾乎沒有日誌累積,若要練習重新開機歷程記錄、登入歷程記錄這類「隨時間累積的日誌」,用於評估的虛擬機會更合適。先在自己的終端機上執行第 3 章的指令,親身感受篩選速度的差異,這樣就已經足夠。
設定值(路徑、伺服器名稱、租用戶 ID 等)僅為範例。請勿直接在正式環境中執行,請依自家環境調整後再使用。
相關文章
- 工作排程器的工作不執行、以 0x1 結束 ── 原因排查與安全的維運設計
- Windows 事件記錄・ETW 入門 ── 讓業務應用程式的日誌搭上 OS 標準機制
- Windows 應用的 crash dump 收集入門 - 先搞清楚 WER / ProcDump / WinDbg 怎麼分工
- PowerShell Remoting(WinRM)入門 ── 一次管理多台 Windows
- Windows 服務的建立與維運 ── 從工作排程器的取捨到 BackgroundService 服務化
- PowerShell 腳本應用 ── 安全地自動化日誌調查、封存與報表化
相關諮詢領域
合同會社小村軟體處理 Windows 環境的故障調查、間歇性發生的重新開機與應用程式異常結束的原因分析,以及日誌收集與監控機制的建置。
參考連結
-
Microsoft Learn, Get-WinEvent。關於可同時取得傳統日誌與 Windows Vista 之後的事件記錄、用 -ListLog / -ListProvider 取得清單、用 -FilterHashtable / -FilterXPath / -FilterXml 篩選、用 -Path 讀取已封存的日誌(.evtx)、用 -ComputerName 進行遠端取得、用 -MaxEvents 限制筆數、讀取 Security 日誌需要系統管理員權限,以及各事件可透過 ToXml() 方法取得 XML 表示形式等內容。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15
-
Microsoft Learn, Active Directory security groups ─ Event Log Readers。關於內建「Event Log Readers」群組的成員可以讀取本機電腦的事件記錄(不需授予系統管理員權限)。變更個別通道存取權限的方法,另請參考 wevtutil 的 sl /ca(通道存取)。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Creating Get-WinEvent queries with FilterHashtable。關於 -FilterHashtable 可指定的鍵(LogName、ProviderName、Path、Keywords、ID、Level、StartTime、EndTime、UserID、Data 等)、因為是在伺服器端篩選、所以比用 Where-Object 篩選更有效率,以及關鍵字與嚴重程度數值的指定方式。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Event Levels。關於事件嚴重程度層級的標準值(1=Critical、2=Error、3=Warning、4=Informational、5=Verbose)。 ↩ ↩2
-
Microsoft Learn, Windows Event Forwarding。關於不需額外安裝代理程式、就能把多台 Windows 的事件轉送到收集伺服器,以及透過訂閱指定收集對象。另外也一併說明透過 Invoke-Command 對多台電腦進行並列執行。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, 4624(S): An account was successfully logged on。關於登入成功事件的事件資料所包含的項目(TargetUserName、LogonType、IpAddress 等)與登入類型數值的意義,以及是否記錄會受稽核原則設定影響等內容。 ↩
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
PowerShell 的安全性強化 ── 日誌・AMSI・語言模式・JEA
本文整理在不禁止 PowerShell 的前提下安全使用它的實務做法。內容涵蓋啟用指令碼區塊記錄與逐字稿記錄、停用 AMSI 與舊版本、以語言模式進行限制,以及透過 JEA 委派權限。
Windows 安全性稽核原則與事件記錄調查實務 ── 成為看得懂 4625 的資訊系統人員
這是一份實務指南,用來回應「請幫忙查一下登入失敗的記錄」這類需求。內容涵蓋基本與詳細稽核原則的關係、最低限度應啟用的子類別、事件 ID 4624/4625/4688 的判讀方式、Security 記錄檔的容量設計,以及使用 Get-WinEvent 擷取的方法。
用 winget + PowerShell 自動化 PC 配置 ── 讓操作手冊變得可執行
本文整理讓新進員工 PC 的環境建置可重現的方法,涵蓋以 winget 進行應用程式導入與 export/import、WinGet Configuration 的宣告式組態、以 PowerShell 補充的設定,以及無人執行時的注意事項。
群組原則(GPO)實務入門 ── 運作機制、生效確認與 Intune 的分工
你是否在不清楚「用 GPO 分發」是什麼意思的情況下,就在操作 AD 環境?本文從實務角度說明群組原則的運作機制與 LSDOU 套用順序、以 gpupdate、gpresult 確認生效狀況、與 Intune 的分工,以及客戶端 GPO 改變應用程式行為的陷阱。
Windows LAPS 實務指南 ── 停止在所有電腦共用同一組本機系統管理員密碼
所有電腦共用同一組本機系統管理員密碼,是讓一台遭入侵就波及全部電腦的 Pass-the-Hash 攻擊溫床。本文說明已成為作業系統標準功能的 Windows LAPS 如何自動輪替密碼、AD/Entra ID 的儲存設定,以及實務運用上的陷阱。
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
故障調查 & 長期運行故障
整理間歇性故障、通訊診斷、長期運行當機、失敗路徑測試基礎的主題頁面。
與本主題相關的服務
本文連結到以下服務頁面,歡迎從最接近的入口查看。
Windows 應用程式開發
支援包含常駐處理、設備連動、運作日誌與可維護結構的 Windows 桌面應用程式。
故障調查 & 根本原因分析
調查難以重現的故障、長時間執行後的問題、記憶體洩漏、通訊停滯等棘手的正式環境問題。
常見問題
整理諮詢這個主題時常見的問題。
- 應該使用 Get-EventLog 還是 Get-WinEvent?
- 應該使用 Get-WinEvent。Get-EventLog 只能在 Windows PowerShell 5.1 中使用,而且只能處理 System、Application、Security 這類傳統(Classic)日誌。Windows Vista 之後新增的「應用程式與服務記錄」底下的日誌,例如 Microsoft-Windows-TaskScheduler/Operational 這類詳細日誌,非用 Get-WinEvent 不可。由於 PowerShell 7 本身不支援 Get-EventLog,往後要寫的腳本請統一使用 Get-WinEvent。
- Get-WinEvent 太慢,根本沒辦法拿來調查。
- 很可能是在管線後端用 Where-Object 進行篩選。這種寫法會先把日誌中的全部事件物件化並讀入 PowerShell,之後才丟棄不需要的部分。面對數十萬筆的日誌,這種做法並不實際。若改用 -FilterHashtable 或 -FilterXPath,篩選會在事件記錄那一側進行,只會傳回需要的事件,速度會有數量級的差異。請養成先用 FilterHashtable 指定日誌名稱、時間範圍、事件識別碼的習慣。
- 嘗試讀取 Security 日誌時,出現存取被拒。
- 讀取 Security 日誌預設需要特別的權限。如果只是自己動手確認,「以系統管理員身分執行」PowerShell 就能解決;但如果不想把系統管理員權限交給負責調查的人員,可以將帳戶加入內建的「Event Log Readers(事件記錄讀取者)」群組,或是透過通道的存取權限(ACL)只授予讀取權限。從最小權限的角度來看,建議採用後者。另外也要注意,有時稽核記錄本身根本沒有被記錄下來。登入稽核等功能取決於稽核原則的設定,因此若一筆事件都找不到,也要確認原則本身是否已啟用。
- 想從事件的訊息中,只取出特定的值(例如使用者名稱或處理程序名稱)。
- 與其用正規表示式從 Message 屬性中擷取,不如使用 Properties 或事件資料(EventData)更為可靠。每個事件都能透過 ToXml() 方法取得 XML 表示形式,其中 EventData 底下會有具名的項目。用來顯示的訊息字串會隨作業系統的顯示語言而改變,但事件資料的結構不會變,因此可以寫出在日文環境與英文環境都能運作的腳本。
- 想一次調查多台伺服器的事件記錄。
- 如果台數不多,用 Get-WinEvent 的 -ComputerName 參數,或透過 Invoke-Command 進行遠端執行就足夠了。Invoke-Command 會對指定的多台機器並列執行,數十台左右都還算實用。若想恆常性地集中收集,建議研議透過 Windows 事件轉送(WEF)集中到收集伺服器的機制。如果只是單次調查,也可以在各伺服器匯出 evtx 檔案,再於本機用 Get-WinEvent -Path 進行解析。