はじめに
PowerShell でイベントログを JSON 形式で出力するスクリプトの紹介です。
イベントログを収集して他のプログラムで読み込むことを想定して JSON 形式にしています。
本記事の構成は以下です。
- 実行環境
- イベントログを取得
- イベントログのフィルタリング
- 取得したイベントログを JSON 形式で出力
- 補足情報
実行環境
- Windows 10
- .NET Framework 4.7
- Windows PowerShell 5.0 (推奨 : 3.0 以上)
イベントログを取得
PowerShell でイベントログを取得し、コンソールに表示してみます。
イベントログの取得には、Get-WinEvent コマンドを使用します。1
なお、管理者権限で PowerShell を起動しないと、セキュリティのイベントログを取得出来ないので注意して下さい。
PS C:\powershell> Get-WinEvent -ListLog *
LogMode MaximumSizeInBytes RecordCount LogName
------- ------------------ ----------- -------
Circular 20971520 23091 Application
Circular 20971520 0 HardwareEvents
Circular 20971520 30119 Security
Circular 20971520 15717 System
# (中略)
Circular 1052672 Network Isolation Operational
Circular 1052672 188 Setup
Circular 1052672 Windows Networking Vpn Plugin Platform/Operational
Circular 1052672 Windows Networking Vpn Plugin Platform/OperationalVerbose
Get-WinEvent コマンドでイベントログを取得できる事を確認できました。
しかし、出力結果の通り__全イベントログが出力__されているため、欲しい情報へのアクセス性がよくありません。
次に、イベントログから任意の情報のみをフィルタリングして取得する方法を紹介します。
イベントログのフィルタリング
Get-WinEvent で取得するイベントログにフィルタをかけたい場合は、-FilterHashtable オプションを使います。
-FilterHashtable オプションでは、連想配列 @{} を用いてフィルタ条件を指定します。
例として、以下のスクリプトにて取得するイベントログの__種類__と__レベル__をフィルタリングしてみます。
# (1) ログの種類を指定
$logName = "Security", "System", "Application"
# (2) ログレベルを指定 (1:Critical, 2:Error, 3:Warning)
$eventLevel = 1, 2, 3
# (3) (1) と (2) の条件でイベントログ取得のフィルタを作成
$filter = @{}
$filter.Add("LogName", $logName)
$filter.Add("Level", $eventLevel )
$filter.Add("StartTime", (Get-Date).AddHours(-24))
$filter.Add("EndTime", (Get-Date))
# (4) イベントログを取得
$eventLogs = Get-WinEvent -FilterHashtable $filter
それでは早速、GetFilteredEventLog.ps1 を実行してみます。
.ps1 ファイルを PowerShell で実行するためには ExecutionPolicy を RemoteSigned に設定しなければなりません。
しかし、ExecutionPolicy の設定変更の影響はシステムワイドなので、本記事では、PowerShell 実行時に -ExecutionPolicy オプションをつけることで一時的に RemoteSigned に設定します。
PS C:\powershell> PowerShell -ExecutionPolicy RemoteSigned .\GetFilteredEventLog.ps1
ProviderName: Microsoft-Windows-DistributedCOM
TimeCreated Id LevelDisplayName Message
----------- -- ---------------- -------
2017/07/24 19:53:43 10016 エラー アプリケーション固有 のアクセス許可の設定では、CLSID ...
2017/07/24 12:00:44 10016 エラー アプリケーション固有 のアクセス許可の設定では、CLSID ...
ProviderName: Microsoft-Windows-Kernel-Processor-Power
TimeCreated Id LevelDisplayName Message
----------- -- ---------------- -------
2017/07/24 15:54:51 37 警告 グループ 0 のプロセッサ 3 のスピードはシステム ファームウェアに...
フィルタに設定した通り、エラーと警告に関するイベントログを取得できました。
しかし、このままではログの可読性に欠けるので、JSON 形式で出力してみます。
取得したイベントログを JSON 形式で出力
JSON 形式で出力
JSON 形式での出力には、ConvertTo-Json コマンド を使用します。
(※) ConvertTo-Json は __Windows PowerShell 3.0 以降__でしか動作しません。
先程のスクリプトに、以下のコメント #(5) 以降を追記します。
# ((1) ~ (3) 省略)
# (4) イベントログを取得
$eventLogs = Get-WinEvent -FilterHashtable $filter
# (これより下を追記)
# (5) イベントログを JSON 形式で出力
$eventLogs | ConvertTo-Json
同様に、追記した GetFilteredEventLog.ps1 を実行してみたいのですが、ここで 1 点問題があります。
それは、上記のスクリプトを実行すると Get-WinEvent コマンドで取得できる__イベントログの全項目が出力__されてしまうことです。
そこで、欲しい項目のみ出力できるようにイベントログをフィルタリングします。
任意の項目を抽出して JSON 形式で出力
任意の項目を抽出するには、Select-Object コマンドを利用します。
以下のスクリプトの通り、$queryItems のリストにイベントログから抽出したい項目だけを設定しておきます。(#(3'))2
そして、Get-WinEvent でイベントログを取得する際に、先に述べたフィルタ条件に加え __Select-Object の処理を連結__します。(#(4))
例として、イベントログから以下の項目を抽出してみます。
- ID(id)
- 種類(logName)
- レベル(levelDisplayName)
- イベントの発生時刻(datetime)
- プロバイダ名(providerName)
- メッセージ(message)
# ((1) ~ (3) 省略)
# (3') イベントログから抽出したい必要な項目だけを設定
$queryItems = New-Object System.Collections.ArrayList
[void]$queryItems.Add(@{Name="id";Expression={$_.id}})
[void]$queryItems.Add(@{Name="logName";Expression={$_.LogName}})
[void]$queryItems.Add(@{Name="levelDisplayName";Expression={$_.LevelDisplayName}})
[void]$queryItems.Add(@{Name="datetime";Expression={$_.TimeCreated.datetime}})
[void]$queryItems.Add(@{Name="providerName";Expression={$_.ProviderName}})
[void]$queryItems.Add(@{Name="message";Expression={$_.Message}})
# (4) イベントログを取得
$eventLogs = Get-WinEvent -FilterHashtable $filter | Select-Object $queryItems
# (5) イベントログを JSON 形式で出力
$eventLogs | ConvertTo-Json
それでは最後に、完成した GetFilteredEventLog.ps1 を実行してみましょう。
PS C:\powershell> PowerShell -ExecutionPolicy RemoteSigned .\GetFilteredEventLog.ps1
[
{
"id": 10016,
"logName": "System",
"levelDisplayName": "エラー",
"datetime": "2017年7月24日 19:53:43",
"providerName": "Microsoft-Windows-DistributedCOM",
"message": "アプリケーション固有 のアクセス許可の設定では、CLSID \r\n{D63B10C5-BB46-4990-A94F-E40B9D520160}\r\n および APPID \r\n{9CA88EE3-ACB7-47C8-AFC4-AB702511C276}\r\n の COM サーバー アプリケーションに対するローカルアクティブ化のアクセス許可を、アプリケーション コンテナー 利用不可 SID (利用不可) で実行中のアドレス LocalHost (LRPC 使用) のユーザー NT AUTHORITY\\SYSTEM SID (S-1-5-18) に与えることはできません。このセキュリティ アクセス許可は、コンポーネント サービス管理ツールを使って変更できます。"
},
{
"id": 37,
"logName": "System",
"levelDisplayName": "警告",
"datetime": "2017年7月24日 15:54:51",
"providerName": "Microsoft-Windows-Kernel-Processor-Power",
"message": "グループ 0 のプロセッサ 3 のスピードはシステム ファームウェアによって制限されます。プロセッサは、最後のレポート後 602804 秒間このパフォーマンスが制限された状態にあります。"
},
{
"id": 10016,
"logName": "System",
"levelDisplayName": "エラー",
"datetime": "2017年7月24日 12:00:44",
"providerName": "Microsoft-Windows-DistributedCOM",
"message": "アプリケーション固有 のアクセス許可の設定では、CLSID \r\n{D63B10C5-BB46-4990-A94F-E40B9D520160}\r\n および APPID \r\n{9CA88EE3-ACB7-47C8-AFC4-AB702511C276}\r\n の COM サーバー アプリケーションに対するローカルアクティブ化のアクセス許可を、アプリケーション コンテナー 利用不可 SID (利用不可) で実行中のアドレス LocalHost (LRPC 使用) のユーザー NT AUTHORITY\\SYSTEM SID (S-1-5-18) に与えることはできません。このセキュリティ アクセス許可は、コンポーネント サービス管理ツールを使って変更できます。"
}
]
$queryItems で設定した項目だけが抽出されて JSON 形式でイベントログが出力出来ました。
おわりに
今回は以下の 3 つを紹介しました。
- イベントログを取得
- イベントログのフィルタリング
- 取得したイベントログを JSON 形式で出力
今後は、JSON 形式で出力したイベントログを他のプログラムで読み込み、定期的にイベントログを取得してレポートを表示する仕組みを整えてみようと思います。
補足情報
フィルタで設定したログレベル値の対応関係を補足しておきます。
ログレベルと値の対応関係は、Windows のイベントビューアーの 現在のログをフィルター から確認することが出来ます。
XMLタブの Query 内を確認すると、 "Level = 4 or Level = 0" と記載があります。
これより、情報レベルのイベントログを PowerShell から取得したい場合は、上記スクリプトの $eventLevel に 0, 4 を設定すれば良いです。
参考
-
Visual Studioなしでmingw-w64だけでWindowsのイベントログに出力する機能を実現する方法 - ククログ(2015-09-10)
-
PowerShell Windows Event Log Monitoring - Feature Requests - LogicMonitor Communities