PowerShellのパイプラインを使って、ログファイルからエラーを抽出・整形する方法を一気通貫で解説します。
備忘録としてまとめました。
想定読者
- PowerShellの基本コマンドは理解している方
- ログファイルなどのテキスト処理を効率化したい方
- 「パイプライン」の可能性をもっと知りたい方
環境準備
この記事のサンプルはPowerShell 5.1以上で動作確認しています。まずは環境を確認しましょう。
# バージョン確認
$PSVersionTable.PSVersion
# 作業用フォルダを作成(存在しない場合)
$workDir = "C:\Temp\PowerShellLogDemo"
if (-not (Test-Path $workDir)) {
New-Item -Path $workDir -ItemType Directory
}
Set-Location $workDir
# 既存のデモファイルがあれば削除
if (Test-Path ".\sample_log.txt") {
Remove-Item ".\sample_log.txt"
}
実践!一気通貫ログ分析パイプライン
STEP 1: サンプルログファイルの作成
まずは分析対象のサンプルログファイルを作成します。実際の環境では既存のログファイルを使いますが、ここではデモ用のファイルを生成します。
# テスト用のログファイルを作成
"2023-05-01 10:15:23 INFO システム起動しました" | Out-File -FilePath .\sample_log.txt
"2023-05-01 10:16:45 ERROR 接続に失敗しました" | Out-File -FilePath .\sample_log.txt -Append
"2023-05-01 10:18:12 WARN リソース使用率が高くなっています" | Out-File -FilePath .\sample_log.txt -Append
"2023-05-01 10:22:30 INFO バックアップ処理を開始します" | Out-File -FilePath .\sample_log.txt -Append
"2023-05-01 10:30:15 ERROR データベース接続がタイムアウトしました" | Out-File -FilePath .\sample_log.txt -Append
"2023-05-01 10:35:42 INFO バックアップ処理が完了しました" | Out-File -FilePath .\sample_log.txt -Append
"2023-05-01 10:40:18 WARN メモリ使用率が80%を超えています" | Out-File -FilePath .\sample_log.txt -Append
"2023-05-01 10:42:53 ERROR 処理がタイムアウトしました: ID=12345" | Out-File -FilePath .\sample_log.txt -Append
# 作成したログファイルの内容を確認
Write-Host "作成したログファイルの内容:" -ForegroundColor Green
Get-Content .\sample_log.txt
実行結果:
作成したログファイルの内容:
2023-05-01 10:15:23 INFO システム起動しました
2023-05-01 10:16:45 ERROR 接続に失敗しました
2023-05-01 10:18:12 WARN リソース使用率が高くなっています
2023-05-01 10:22:30 INFO バックアップ処理を開始します
2023-05-01 10:30:15 ERROR データベース接続がタイムアウトしました
2023-05-01 10:35:42 INFO バックアップ処理が完了しました
2023-05-01 10:40:18 WARN メモリ使用率が80%を超えています
2023-05-01 10:42:53 ERROR 処理がタイムアウトしました: ID=12345
STEP 2: エラーログの抽出(基本)
まずは最も基本的な処理として、エラーログだけを抽出してみましょう。
Write-Host "`nステップ2: エラーログの抽出(基本)" -ForegroundColor Green
Get-Content .\sample_log.txt | Where-Object { $_ -match "ERROR" }
実行結果:
ステップ2: エラーログの抽出(基本)
2023-05-01 10:16:45 ERROR 接続に失敗しました
2023-05-01 10:30:15 ERROR データベース接続がタイムアウトしました
2023-05-01 10:42:53 ERROR 処理がタイムアウトしました: ID=12345
STEP 3: エラーログを整形して表示
続いて、エラーログから必要な情報だけを抽出し、見やすい形に整形します。
Write-Host "`nステップ3: エラーログを整形して表示" -ForegroundColor Green
Get-Content .\sample_log.txt |
Where-Object { $_ -match "ERROR" } |
ForEach-Object {
$parts = $_ -split " ", 4
[PSCustomObject]@{
Time = $parts[1]
Message = $parts[3]
}
} |
Format-Table -AutoSize
実行結果:
ステップ3: エラーログを整形して表示
Time Message
---- -------
10:16:45 接続に失敗しました
10:30:15 データベース接続がタイムアウトしました
10:42:53 処理がタイムアウトしました: ID=12345
STEP 4: 正規表現を使った高度な抽出
正規表現のキャプチャグループを使って、より柔軟にデータを抽出します。
Write-Host "`nステップ4: 正規表現を使った高度な抽出" -ForegroundColor Green
Get-Content .\sample_log.txt |
ForEach-Object {
if ($_ -match "^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (INFO|WARN|ERROR) (.+)") {
[PSCustomObject]@{
Date = $matches[1]
Time = $matches[2]
Level = $matches[3]
Message = $matches[4]
Severity = switch ($matches[3]) {
"INFO" { 1 }
"WARN" { 2 }
"ERROR" { 3 }
}
}
}
} |
Format-Table -AutoSize
実行結果:
ステップ4: 正規表現を使った高度な抽出
Date Time Level Message Severity
---- ---- ----- ------- --------
2023-05-01 10:15:23 INFO システム起動しました 1
2023-05-01 10:16:45 ERROR 接続に失敗しました 3
2023-05-01 10:18:12 WARN リソース使用率が高くなっています 2
2023-05-01 10:22:30 INFO バックアップ処理を開始します 1
2023-05-01 10:30:15 ERROR データベース接続がタイムアウトしました 3
2023-05-01 10:35:42 INFO バックアップ処理が完了しました 1
2023-05-01 10:40:18 WARN メモリ使用率が80%を超えています 2
2023-05-01 10:42:53 ERROR 処理がタイムアウトしました: ID=12345 3
STEP 5: レベル別にグループ化して統計情報を表示
各ログレベル(INFO/WARN/ERROR)ごとの出現回数を集計します。
Write-Host "`nステップ5: レベル別にグループ化して統計情報を表示" -ForegroundColor Green
Get-Content .\sample_log.txt |
ForEach-Object {
if ($_ -match "^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (INFO|WARN|ERROR) (.+)") {
[PSCustomObject]@{
Level = $matches[3]
Message = $matches[4]
}
}
} |
Group-Object -Property Level |
Select-Object Name, Count, @{
Name = 'Percentage';
Expression = { "{0:P1}" -f ($_.Count / 8) } # 合計ログ数に対する割合
}
実行結果:
ステップ5: レベル別にグループ化して統計情報を表示
Name Count Percentage
---- ----- ----------
INFO 3 37.5%
WARN 2 25.0%
ERROR 3 37.5%
STEP 6: 特定の時間帯のログだけを抽出
時間帯で絞り込んでログを抽出します。10:30〜10:45の間のログだけを表示してみましょう。
Write-Host "`nステップ6: 特定の時間帯のログだけを抽出" -ForegroundColor Green
Get-Content .\sample_log.txt |
ForEach-Object {
if ($_ -match "^(\d{4}-\d{2}-\d{2}) (10:[3-4]\d:\d{2}) (INFO|WARN|ERROR) (.+)") {
[PSCustomObject]@{
Time = $matches[2]
Level = $matches[3]
Message = $matches[4]
}
}
} |
Format-Table -AutoSize
実行結果:
ステップ6: 特定の時間帯のログだけを抽出
Time Level Message
---- ----- -------
10:30:15 ERROR データベース接続がタイムアウトしました
10:35:42 INFO バックアップ処理が完了しました
10:40:18 WARN メモリ使用率が80%を超えています
10:42:53 ERROR 処理がタイムアウトしました: ID=12345
STEP 7: 特定のキーワードを含むログを検索
ログメッセージ内の特定のキーワードを検索します。ここでは「タイムアウト」というキーワードを含むログを抽出します。
Write-Host "`nステップ7: 特定のキーワードを含むログを検索" -ForegroundColor Green
Get-Content .\sample_log.txt |
Where-Object { $_ -match "タイムアウト" } |
ForEach-Object {
if ($_ -match "^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (INFO|WARN|ERROR) (.+)") {
[PSCustomObject]@{
Time = $matches[2]
Level = $matches[3]
Message = $matches[4]
}
}
} |
Format-Table -AutoSize
実行結果:
ステップ7: 特定のキーワードを含むログを検索
Time Level Message
---- ----- -------
10:30:15 ERROR データベース接続がタイムアウトしました
10:42:53 ERROR 処理がタイムアウトしました: ID=12345
STEP 8: CSVファイルに出力
分析結果をCSVファイルに保存します。これにより、Excelなどで詳細な分析や共有が容易になります。
Write-Host "`nステップ8: CSVファイルに出力" -ForegroundColor Green
Get-Content .\sample_log.txt |
ForEach-Object {
if ($_ -match "^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (INFO|WARN|ERROR) (.+)") {
[PSCustomObject]@{
Date = $matches[1]
Time = $matches[2]
Level = $matches[3]
Message = $matches[4]
}
}
} |
Export-Csv -Path ".\log_analysis.csv" -NoTypeInformation -Encoding UTF8
# CSVファイルが作成されたことを確認
Get-Item ".\log_analysis.csv" | Select-Object Name, Length, LastWriteTime
# CSVファイルの内容を表示
Import-Csv ".\log_analysis.csv" | Format-Table -AutoSize
実行結果:
ステップ8: CSVファイルに出力
Name Length LastWriteTime
---- ------ -------------
log_analysis.csv 422 2023-05-01 11:00:00
Date Time Level Message
---- ---- ----- -------
2023-05-01 10:15:23 INFO システム起動しました
2023-05-01 10:16:45 ERROR 接続に失敗しました
2023-05-01 10:18:12 WARN リソース使用率が高くなっています
2023-05-01 10:22:30 INFO バックアップ処理を開始します
2023-05-01 10:30:15 ERROR データベース接続がタイムアウトしました
2023-05-01 10:35:42 INFO バックアップ処理が完了しました
2023-05-01 10:40:18 WARN メモリ使用率が80%を超えています
2023-05-01 10:42:53 ERROR 処理がタイムアウトしました: ID=12345
STEP 9: 複数条件でフィルタリング
ERRORログかつ特定の時間帯のみを抽出する、といった複数条件でのフィルタリングを行います。
Write-Host "`nステップ9: 複数条件でフィルタリング" -ForegroundColor Green
Get-Content .\sample_log.txt |
ForEach-Object {
if ($_ -match "^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (INFO|WARN|ERROR) (.+)") {
[PSCustomObject]@{
Time = $matches[2]
Level = $matches[3]
Message = $matches[4]
}
}
} |
Where-Object { $_.Level -eq "ERROR" -and $_.Time -ge "10:30:00" } |
Format-Table -AutoSize
実行結果:
ステップ9: 複数条件でフィルタリング
Time Level Message
---- ----- -------
10:30:15 ERROR データベース接続がタイムアウトしました
10:42:53 ERROR 処理がタイムアウトしました: ID=12345
STEP 10: 実用的な関数化
これまでの処理を再利用可能な関数にまとめます。
Write-Host "`nステップ10: 実用的な関数化" -ForegroundColor Green
function Get-FilteredLog {
param(
[Parameter(Mandatory = $true)]
[string]$LogPath,
[Parameter(Mandatory = $false)]
[ValidateSet("INFO", "WARN", "ERROR", "ALL")]
[string]$Level = "ALL",
[Parameter(Mandatory = $false)]
[string]$StartTime,
[Parameter(Mandatory = $false)]
[string]$EndTime,
[Parameter(Mandatory = $false)]
[string]$Keyword,
[Parameter(Mandatory = $false)]
[switch]$ExportToCsv,
[Parameter(Mandatory = $false)]
[string]$CsvPath = ".\filtered_log.csv"
)
# ログを取得して解析
$logEntries = Get-Content $LogPath |
ForEach-Object {
if ($_ -match "^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (INFO|WARN|ERROR) (.+)") {
[PSCustomObject]@{
Date = $matches[1]
Time = $matches[2]
Level = $matches[3]
Message = $matches[4]
}
}
}
# フィルタリング
$filteredLogs = $logEntries
# レベルでフィルタリング
if ($Level -ne "ALL") {
$filteredLogs = $filteredLogs | Where-Object { $_.Level -eq $Level }
}
# 開始時間でフィルタリング
if ($StartTime) {
$filteredLogs = $filteredLogs | Where-Object { $_.Time -ge $StartTime }
}
# 終了時間でフィルタリング
if ($EndTime) {
$filteredLogs = $filteredLogs | Where-Object { $_.Time -le $EndTime }
}
# キーワードでフィルタリング
if ($Keyword) {
$filteredLogs = $filteredLogs | Where-Object { $_.Message -match $Keyword }
}
# CSVに出力
if ($ExportToCsv) {
$filteredLogs | Export-Csv -Path $CsvPath -NoTypeInformation -Encoding UTF8
Write-Host "CSVファイルを保存しました: $CsvPath" -ForegroundColor Yellow
}
return $filteredLogs
}
# 関数の使用例1: ERRORログのみ表示
Write-Host "`n関数の使用例1: ERRORログのみ表示" -ForegroundColor Yellow
Get-FilteredLog -LogPath ".\sample_log.txt" -Level "ERROR" | Format-Table -AutoSize
# 関数の使用例2: 特定の時間帯の全ログ
Write-Host "`n関数の使用例2: 特定の時間帯の全ログ" -ForegroundColor Yellow
Get-FilteredLog -LogPath ".\sample_log.txt" -StartTime "10:30:00" -EndTime "10:40:00" | Format-Table -AutoSize
# 関数の使用例3: キーワード検索とCSV出力
Write-Host "`n関数の使用例3: キーワード検索とCSV出力" -ForegroundColor Yellow
Get-FilteredLog -LogPath ".\sample_log.txt" -Keyword "処理" -ExportToCsv -CsvPath ".\process_logs.csv" | Format-Table -AutoSize
# CSV出力を確認
if (Test-Path ".\process_logs.csv") {
Write-Host "`nCSV出力の確認:" -ForegroundColor Green
Import-Csv ".\process_logs.csv" | Format-Table -AutoSize
}
実行結果:
ステップ10: 実用的な関数化
関数の使用例1: ERRORログのみ表示
Date Time Level Message
---- ---- ----- -------
2023-05-01 10:16:45 ERROR 接続に失敗しました
2023-05-01 10:30:15 ERROR データベース接続がタイムアウトしました
2023-05-01 10:42:53 ERROR 処理がタイムアウトしました: ID=12345
関数の使用例2: 特定の時間帯の全ログ
Date Time Level Message
---- ---- ----- -------
2023-05-01 10:30:15 ERROR データベース接続がタイムアウトしました
2023-05-01 10:35:42 INFO バックアップ処理が完了しました
関数の使用例3: キーワード検索とCSV出力
CSVファイルを保存しました: .\process_logs.csv
Date Time Level Message
---- ---- ----- -------
2023-05-01 10:22:30 INFO バックアップ処理を開始します
2023-05-01 10:35:42 INFO バックアップ処理が完了しました
2023-05-01 10:42:53 ERROR 処理がタイムアウトしました: ID=12345
CSV出力の確認:
Date Time Level Message
---- ---- ----- -------
2023-05-01 10:22:30 INFO バックアップ処理を開始します
2023-05-01 10:35:42 INFO バックアップ処理が完了しました
2023-05-01 10:42:53 ERROR 処理がタイムアウトしました: ID=12345
まとめ
このチュートリアルでは、PowerShellのパイプラインを使ったログ分析の手法を一気通貫で学びました。
PowerShellのパイプラインを通じて、ログの抽出や整形、正規表現によるパターンマッチ、集計処理、CSV出力、さらには関数化まで幅広く学びました。少ないコードで効率よくデータ処理ができるのが魅力です。日々のログ分析や運用業務に積極的に活用していきたいと思います。
参考資料
この記事は2025年5月に執筆されました。PowerShellのバージョンやコマンドレットの仕様は、今後のアップデートで変更される可能性があります。