1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[備忘録] PowerShellパイプラインでログファイル処理を効率化!シンプルに実装するエラー抽出術

Last updated at Posted at 2025-05-12

PowerShellのパイプラインを使って、ログファイルからエラーを抽出・整形する方法を一気通貫で解説します。
備忘録としてまとめました。

powershell-pipeline-diagram.png

想定読者

  • 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-pipeline-summary.png

このチュートリアルでは、PowerShellのパイプラインを使ったログ分析の手法を一気通貫で学びました。

PowerShellのパイプラインを通じて、ログの抽出や整形、正規表現によるパターンマッチ、集計処理、CSV出力、さらには関数化まで幅広く学びました。少ないコードで効率よくデータ処理ができるのが魅力です。日々のログ分析や運用業務に積極的に活用していきたいと思います。

参考資料


この記事は2025年5月に執筆されました。PowerShellのバージョンやコマンドレットの仕様は、今後のアップデートで変更される可能性があります。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?