PowerShellをつかってWindowsイベントログをXML形式で取得する

#はじめに
PowerShellのGet-WinEventコマンドレットを使ってWindowsイベントログを取得すると、ログの詳細はMessageプロパティにフォーマットされていない文字列で入っています。

そのため、例えば、プロセスの生成を記録したログを検索し、個々のログに記録されているプロセスID、プロセス名を取得したいとき、Messageプロパティから正規表現で取り出すしかなさそうに見えます。

しかしイベントビューアーのGUIでは、個々のログの「詳細」タブからXML形式でプロセスID、プロセス名などを閲覧できるので、PowerShellでもXML形式で取り出す方法があるはずだ。

そう思って調べた結果が以下の方法です。

#方法

たとえばローカルコンピュータの一定時間内のプロセス生成ログを検索します。(SecurityログのEventID 4688番)

```PowerShell
$logs = Get-WinEvent -FilterHashtable @{LogName="Security";Id=4688;StartTime="2020-11-11 10:00";EndTime="2020-11-11 10:03"}
```

個々のログに記録されている新規生成プロセスはMessageプロパティのテキストにしか現れないように見えます。

```
PS C:\WINDOWS\system32> $logs[1].Message
新しいプロセスが作成されました。

作成元サブジェクト:
	セキュリティ ID:		S-1-5-21-1390067357-nnnnnnnnn-nnnnnnnnn-nnnn
	アカウント名:		yamada.taro
	アカウント ドメイン:		HOGEHOGE
	ログオン ID:		0xD4E06

ターゲット サブジェクト:
	セキュリティ ID:		S-1-0-0
	アカウント名:		-
	アカウント ドメイン:		-
	ログオン ID:		0x0

プロセス情報:
	新しいプロセス ID:		0x2454
	新しいプロセス名:	C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
	トークン昇格の種類:	%%1936
	必須ラベル:		S-1-16-4096
	作成元プロセス ID:	0x3f08
	作成元プロセス名:	C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
	プロセスのコマンド ライン:	

(以下略)
```

しかし、ToXml()メソッドを使うと、XML形式で取り出すことができます。

```XML
PS C:\WINDOWS\system32> $logs[1].ToXml()
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-a5ba-3e3b0328c30d}'/><EventID>4688</EventID><Version>2</Version><Level>0</Level><Task>13312</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2020-11-11T01:02:33.227966500Z'/><EventRecordID>632158</EventRecordID><Correlation/><Execution ProcessID='4' ThreadID='13816'/><Channel>Security</Channel><Computer>XXXXX.hogehoge.com</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-5-21-1390067357-nnnnnnnnn-nnnnnnnnn-nnnn</Data><Data Name='SubjectUserName'>yamada.taro</Data><Data Name='SubjectDomainName'>HOGEHOGE</Data><Data Name='SubjectLogonId'>0xd4e06</Data><Data Name='NewProcessId'>0x2454</Data><Data Name='NewProcessName'>C:\Program Files (x86)\Google\Chrome\Application\chrome.exe</Data><Data Name='TokenElevationType'>%%1936</Data><Data Name='ProcessId'>0x3f08</Data><Data Name='CommandLine'></Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>-</Data><Data Name='TargetDomainName'>-</Data><Data Name='TargetLogonId'>0x0</Data><Data Name='ParentProcessName'>C:\Program Files (x86)\Google\Chrome\Application\chrome.exe</Data><Data Name='MandatoryLabel'>S-1-16-4096</Data></EventData></Event>
```

このXMLをパースして変数に代入します。

```PowerShell
$xml = [XML]($logs[1].ToXml())
```

これでEventノードの子ノードEventDataから必要なデータを取り出せます。

```
PS C:\WINDOWS\system32> $xml.Event.EventData.ChildNodes

Name               #text                                                      
----               -----                                                      
SubjectUserSid     S-1-5-21-1390067357-nnnnnnnnn-nnnnnnnnn-nnnn               
SubjectUserName    yamada.taro
SubjectDomainName  HOGEHOGE                                                    
SubjectLogonId     0xd4e06                                                    
NewProcessId       0x2454                                                     
NewProcessName     C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
TokenElevationType %%1936                                                     
ProcessId          0x3f08                                                     
CommandLine                                                                   
TargetUserSid      S-1-0-0                                                    
TargetUserName     -                                                          
TargetDomainName   -                                                          
TargetLogonId      0x0                                                        
ParentProcessName  C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
MandatoryLabel     S-1-16-4096                                                
```

例えば、新規作成されたプロセス名(NewProcessName)を取り出すには以下のとおり。

```PowerShell
$procname = ($xml.Event.EventData.Data | where Name -eq "NewProcessName")."#text"
```

これを検索したログについてループ処理すればよい、ということです。

以上です。