使用 Get-WinEvent 有效率地調查事件記錄 ── 篩選的速度決定調查所需的時間

· · PowerShell, Windows, 事件記錄, 故障調查, 維運改善, 資訊系統, 稽核, 疑難排解

「上週五半夜,伺服器好像自己重新開機了」「只有特定的終端機,業務應用程式每個月都會當機好幾次」── 這類調查的起點,幾乎必定是 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 可用的鍵是固定的。LogNameProviderNameIDLevelStartTimeEndTimeKeywordsPathUserID 等。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 的輸出有 CountName 兩欄。因為是用 ProviderName, Id 這樣的多個屬性進行分組,所以 Name 會以逗號分隔列出「來源, 事件識別碼」(例如:Service Control Manager, 7034)。輸出依筆數由多到少排序,第一步要看的是排在前面的來源是否眼生是否有對應到故障發生時段的筆數高峰。先在這裡抓出頭緒,再用下一章的方法深入個別事件。

若沒有任何符合的事件,Get-WinEvent 會回傳錯誤。這裡請不要輕易加上 -ErrorAction SilentlyContinue「沒有符合的項目」、「沒有讀取該日誌的權限」、「無法連線到目標機器」,這三種情況都會變成同樣的「空結果」。在調查現場,這是最麻煩的一種故障模式。

如上面的寫法,用 -ErrorAction Stop 接住錯誤,只有在 FullyQualifiedErrorIdNoMatchingEventsFound 時才把它吞掉,才是正確做法。若用訊息字串判斷,在日文環境下不會相符,因而無法正常運作(關於錯誤處理的思考方式,請參考「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-WinEventGet-EventLog 在 PowerShell 7 中無法使用,能處理的日誌也有限。
  • 篩選請用 -FilterHashtable-FilterXPath 進行。用 Where-Object 做後段篩選,會讓調查所需的時間出現數量級的惡化。
  • 調查重新開機時,除了 41、6008,也要看1074(是誰要求的)。應用程式異常結束則以 1000、1026、1001 為起點。
  • 不用訊息字串、改用 ToXml() 的事件資料,就能寫出不受語言設定影響的腳本。
  • 多台機器的單次調查用 Invoke-Command,恆常性集中收集用 Windows 事件轉送,若需要留存佐證則採集 .evtx 後在本機解析。
  • 想調查的時段的日誌若已經不存在,就什麼都做不了。重新檢視日誌容量,是故障應對準備工作中最優先的事項。

範例程式碼下載

本文提到的程式碼,已整理成可直接執行的形式提供下載。內含重新開機歷程記錄、登入歷程記錄、工作失敗、多台機器收集等範例。

下載範例程式碼(zip)

本文的範例因為依賴 Windows 與租用戶環境,並未實際執行驗證。雖然已對所有檔案進行語法解析與 PSScriptAnalyzer 的靜態分析,但實際運作請務必在您自己的驗證機上確認

# 語法解析 + 靜態分析(非 Windows 環境也能執行)
./Invoke-SampleTests.ps1

如果沒有可以嘗試的環境,也不需要在業務用終端機上拿正式環境的日誌來練習。Windows Sandbox 只要幾分鐘就能啟動乾淨的 Windows,關閉後就會消失(「用 Windows Sandbox 加速應用程式開發驗證的方法」)。不過 Sandbox 是剛啟動的環境,幾乎沒有日誌累積,若要練習重新開機歷程記錄、登入歷程記錄這類「隨時間累積的日誌」,用於評估的虛擬機會更合適。先在自己的終端機上執行第 3 章的指令,親身感受篩選速度的差異,這樣就已經足夠。

設定值(路徑、伺服器名稱、租用戶 ID 等)僅為範例。請勿直接在正式環境中執行,請依自家環境調整後再使用。

相關文章

相關諮詢領域

合同會社小村軟體處理 Windows 環境的故障調查、間歇性發生的重新開機與應用程式異常結束的原因分析,以及日誌收集與監控機制的建置。

參考連結

  1. 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

  2. Microsoft Learn, Active Directory security groups ─ Event Log Readers。關於內建「Event Log Readers」群組的成員可以讀取本機電腦的事件記錄(不需授予系統管理員權限)。變更個別通道存取權限的方法,另請參考 wevtutil 的 sl /ca(通道存取)。  2 3 4

  3. 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

  4. Microsoft Learn, Event Levels。關於事件嚴重程度層級的標準值(1=Critical、2=Error、3=Warning、4=Informational、5=Verbose)。  2

  5. Microsoft Learn, Windows Event Forwarding。關於不需額外安裝代理程式、就能把多台 Windows 的事件轉送到收集伺服器,以及透過訂閱指定收集對象。另外也一併說明透過 Invoke-Command 對多台電腦進行並列執行。  2 3 4

  6. Microsoft Learn, 4624(S): An account was successfully logged on。關於登入成功事件的事件資料所包含的項目(TargetUserName、LogonType、IpAddress 等)與登入類型數值的意義,以及是否記錄會受稽核原則設定影響等內容。 

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

應該使用 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 進行解析。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽