0
0

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 業務自動化レシピ #7】大量ログからエラー行だけ抽出して日次レポート化(Select-String+正規表現)

0
Posted at

株式会社Good Labでエンジニアをしている コータロー です。
日々、Java・SQL・Gitなどの技術情報や、新人エンジニア向けの学習ノウハウ、
AI活用についての情報を発信しています。

Good Labについて気になった方は、コーポレートサイトもぜひご覧ください。
コーポレートサイト


本記事は 「PowerShell 業務自動化レシピ」 シリーズの第7回です。このシリーズは、文法解説ではなく 「1記事=1つの業務課題」を、コピペで動く検証済みスクリプトで解決することを目的とした実務レシピ集です(全12回想定)。SES・受託・社内運用の現場で、いまだに手作業でやっている地味な作業を片っ端から自動化していきます。

第1回 では「大量ファイルの一括リネーム」、第2回 では「古いログファイルの抽出・自動削除」、第6回 では「Compare-Object で2つのリスト/ファイルの差分を突き合わせる」を扱いました。第2回はログを 「消す」 話でしたが、今回はログの 「中身を読んで異常を拾う」 話です。同じ「ログ」でも、やることは正反対です。

第7回のテーマは 「大量ログからエラー行だけ抽出して日次レポート化」。サーバやバッチが吐く大量のログから、毎朝 ERRORWARN の行を目視(あるいは手で findstr / grep)で拾っている作業を、Select-String +正規表現で自動化します。エラー種別ごとの件数・発生時刻帯・初出/最終時刻まで一覧化して、テキスト/CSVの日次レポートに落とします。

本記事は PowerShell 7(pwsh、クロスプラットフォーム) を基準にしています。Windows標準の Windows PowerShell 5.1 での差異は、各所と最後の章で明記します。

今回は 読み取り+レポート出力のみ で、元のログを書き換えたり消したりはしません(破壊的操作なし)。安心して試せます。出力先レポートの上書きにだけ軽く注意します(後述)。


Before:手作業のつらいシーン

シーン1:毎朝、巨大ログをスクロールして目視grep

夜間バッチやアプリサーバが C:\logsapp-2026-06-29.log のような日次ログを吐く。1ファイル数万行。出社後、テキストエディタで開いて ERROR を検索 → ヒットした箇所をスクロールで追って、エラーの種類と件数を頭の中で数える。

  • ファイルが大きいとエディタが固まる。検索ヒットが100件超えると、もう数えきれない
  • 「今日は何のエラーが何件出たか」を毎朝メモ帳に手で書き写す。所要 20〜30分
  • 複数サーバ分(app1app5)があると、それを台数分くり返す

シーン2:「いつ・どのエラーが・何件」が集計できない

findstr ERROR app-2026-06-29.log で行は出せても、種別ごとの件数何時台に集中したかは出ない。結局、ヒット行をExcelに貼って、メッセージでソートして、目で数える羽目になる。エラーメッセージの末尾にIDや件数が混ざっていると、「同じ種類のエラー」をまとめるのも一苦労。

これ、複数ログからエラー行を抽出 → 正規表現で「日時・レベル・メッセージ」に分解 → 種別ごとに件数集計 → 初出/最終時刻つきで日次レポート化——ここまで全部スクリプト一本で終わります。


After:スクリプト一本で完了

進め方は ①複数ログから ERROR 行を抽出 → ②正規表現で日時・レベル・メッセージにパース → ③種別ごとに件数集計 → ④日次サマリをCSV/テキスト出力 → ⑤当日分・直近N分だけに絞る の順です。

この記事では、サーバが C:\logs(macOS/Linuxなら ~/logs)に吐く日次ログが集まっている前提で進めます。ログの中身はこんな形(よくあるアプリログのフォーマット)です。

app-2026-06-29.log

2026-06-29 09:00:01 [INFO] アプリケーションを起動しました
2026-06-29 09:03:12 [INFO] ユーザー alice がログインしました
2026-06-29 09:15:45 [WARN] レスポンスが遅延しています (1200ms)
2026-06-29 10:02:33 [ERROR] DB接続に失敗しました host=db01
2026-06-29 10:02:34 [ERROR] DB接続に失敗しました host=db01
2026-06-29 10:30:07 [INFO] バッチ job=daily を開始しました
2026-06-29 11:45:50 [ERROR] ファイルが見つかりません path=C:\data\in.csv
2026-06-29 13:20:18 [WARN] メモリ使用率が高い状態です (88%)
2026-06-29 14:05:09 [ERROR] DB接続に失敗しました host=db02
2026-06-29 18:55:42 [INFO] アプリケーションを停止しました

この app-2026-06-29.log には ERRORが4行・WARNが2行・INFOが4行含まれています(以降の出力例はこの中身を前提にしています)。レシピを順に当てていきます。

レシピ1:複数ログから ERROR 行だけを抽出する

まずは一番シンプルに、Select-StringERROR を含む行だけを拾います。

# ===== 設定 =====
$logDir  = "C:\logs"            # ログがあるフォルダ
$filter  = "app-*.log"         # 対象ログファイル
$pattern = "\[ERROR\]"         # 抽出パターン(正規表現)

# ===== 本体 =====
# 対象ログをまとめて Select-String にかける
$hits = Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern $pattern

# ヒットした「ファイル名・行番号・行の内容」を表示
$hits | Select-Object Filename, LineNumber, Line | Format-Table -AutoSize

Write-Host "ERROR行: $($hits.Count) 件"

出力イメージ(app-2026-06-29.log 1ファイルだけを処理した場合):

Filename            LineNumber Line
--------            ---------- ----
app-2026-06-29.log           4 2026-06-29 10:02:33 [ERROR] DB接続に失敗しました host=db01
app-2026-06-29.log           5 2026-06-29 10:02:34 [ERROR] DB接続に失敗しました host=db01
app-2026-06-29.log           7 2026-06-29 11:45:50 [ERROR] ファイルが見つかりません path=C:\data\in.csv
app-2026-06-29.log           9 2026-06-29 14:05:09 [ERROR] DB接続に失敗しました host=db02

ERROR行: 4 件

Select-String の戻り値は ただの文字列ではなく MatchInfo オブジェクトで、.Filename(ファイル名).LineNumber(行番号).Line(行の内容).Path(フルパス).Matches(マッチ詳細)といったプロパティを持ちます。だから「どのファイルの何行目か」がそのまま取れます。ここが findstr との大きな違いです。

-Pattern既定で正規表現 として解釈されます。[ERROR] をそのまま書くと「E/R/Oいずれか1文字」という文字クラスになってしまうため、角カッコをリテラルとして扱うには \[ERROR\] のようにエスケープします(あるいは後述の -SimpleMatch)。

ERRORWARN両方 拾いたいときは、-Pattern に配列を渡します(いずれかにマッチした行が対象)。

# ERROR か WARN のどちらかを含む行
$hits = Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern "\[ERROR\]", "\[WARN\]"

これで先ほどのログなら、ERROR4行+WARN2行=6件がヒットします。

レシピ2:正規表現で「日時・レベル・メッセージ」に分解する

行をただ拾うだけでは集計できません。名前付きグループ (?<名前>...) を使って、各行を「日時・レベル・メッセージ」の3要素に分解します。

# ===== 設定 =====
$logDir  = "C:\logs"
$filter  = "app-*.log"

# 1行を「日時 [レベル] メッセージ」に分解する正規表現(名前付きグループ)
$lineRegex = '^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<msg>.+)$'

# ===== 本体 =====
# ERROR / WARN 行を抽出
$hits = Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern "\[ERROR\]", "\[WARN\]"

# 各ヒット行を分解してオブジェクト化
$records = foreach ($h in $hits) {
    if ($h.Line -match $lineRegex) {
        [PSCustomObject]@{
            Time    = [datetime]$Matches['time']  # 文字列を日時に変換
            Level   = $Matches['level']
            Message = $Matches['msg']
            File    = $h.Filename
            Line    = $h.LineNumber
        }
    }
}

$records | Format-Table Time, Level, Message -AutoSize

出力イメージ(app-2026-06-29.log):

Time                Level Message
----                ----- -------
2026/06/29 9:15:45  WARN  レスポンスが遅延しています (1200ms)
2026/06/29 10:02:33 ERROR DB接続に失敗しました host=db01
2026/06/29 10:02:34 ERROR DB接続に失敗しました host=db01
2026/06/29 11:45:50 ERROR ファイルが見つかりません path=C:\data\in.csv
2026/06/29 13:20:18 WARN  メモリ使用率が高い状態です (88%)
2026/06/29 14:05:09 ERROR DB接続に失敗しました host=db02

ポイントは2つです。

  • $h.Line -match $lineRegex が成功すると、自動変数 $Matches に名前付きグループの結果が入る($Matches['time'] のように取り出せる)
  • Time[datetime] にキャストしておくと、後で 時刻でソート・時間帯で集計 ができる

-match$true$false を返し、副作用として $Matches を埋める 演算子です。Select-String でも $h.Matches.Groups['time'].Value のようにグループを取れますが、1行ずつ確実に分解するなら -match$Matches が読みやすいです。

レシピ3:エラーメッセージ種別ごとに件数集計する

$recordsGroup-Object で「メッセージ種別」ごとにまとめ、件数・初出・最終時刻を出します。

ただし DB接続に失敗しました host=db01host=db02 のように 末尾だけ違うメッセージは、そのままだと別種別に数えられてしまいます。そこで host=...(1200ms) のような 可変部分を正規化 してからグループ化します。

# ===== 設定 =====
$logDir  = "C:\logs"
$filter  = "app-*.log"
$lineRegex = '^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<msg>.+)$'

# ===== 本体 =====
$hits = Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern "\[ERROR\]", "\[WARN\]"

$records = foreach ($h in $hits) {
    if ($h.Line -match $lineRegex) {
        $msg = $Matches['msg']

        # 可変部分を正規化して「同じ種類」をまとめる
        $kind = $msg `
            -replace 'host=\S+',  'host=***' `
            -replace 'path=\S+',  'path=***' `
            -replace '\(\d+ms\)',  '(***ms)' `
            -replace '\(\d+%\)',   '(***%)'

        [PSCustomObject]@{
            Time    = [datetime]$Matches['time']
            Level   = $Matches['level']
            Kind    = $kind
        }
    }
}

# 種別ごとに集計(件数の多い順)
$summary = $records |
    Group-Object Kind |
    ForEach-Object {
        [PSCustomObject]@{
            Level = $_.Group[0].Level
            Kind  = $_.Name
            Count = $_.Count
            First = ($_.Group.Time | Measure-Object -Minimum).Minimum
            Last  = ($_.Group.Time | Measure-Object -Maximum).Maximum
        }
    } |
    Sort-Object Count -Descending

$summary | Format-Table Level, Count, First, Last, Kind -AutoSize

出力イメージ(app-2026-06-29.log):

Level Count First               Last                Kind
----- ----- -----               ----                ----
ERROR     3 2026/06/29 10:02:33 2026/06/29 14:05:09 DB接続に失敗しました host=***
WARN      1 2026/06/29 9:15:45  2026/06/29 9:15:45  レスポンスが遅延しています (***ms)
ERROR     1 2026/06/29 11:45:50 2026/06/29 11:45:50 ファイルが見つかりません path=***
WARN      1 2026/06/29 13:20:18 2026/06/29 13:20:18 メモリ使用率が高い状態です (***%)

host=db01 host=db02 の2種類+同一の db01 重複が、「DB接続に失敗しました host=」3件* に正しくまとまりました。FirstLast で「いつ最初に出て、いつまで続いたか」が一目で分かります。

正規化のルール(-replace の行)は ログの内容に合わせて足し引き してください。IDや数値が末尾に付くメッセージは、これをやらないと「ほぼ同じなのに全部バラバラの種別」になり、集計の意味が薄れます。

レシピ4:日次サマリをCSV/テキストに出力する

レシピ3の $summary を、そのまま日次レポートとして書き出します。CSVとテキストの両方を出しておくと、CSVは集計・グラフ化に、テキストはそのままメール・チャット貼り付けに使えて便利です。

# ===== 設定 =====
$logDir    = "C:\logs"
$filter    = "app-*.log"
$reportDir = "C:\logs\_report"   # レポート出力先(ログ対象に含めない場所)
$lineRegex = '^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<msg>.+)$'

# ===== 本体 =====
if (-not (Test-Path -LiteralPath $reportDir)) {
    New-Item -ItemType Directory -Path $reportDir | Out-Null
}

$hits = Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern "\[ERROR\]", "\[WARN\]"

$records = foreach ($h in $hits) {
    if ($h.Line -match $lineRegex) {
        $kind = $Matches['msg'] `
            -replace 'host=\S+', 'host=***' `
            -replace 'path=\S+', 'path=***' `
            -replace '\(\d+ms\)', '(***ms)' `
            -replace '\(\d+%\)',  '(***%)'
        [PSCustomObject]@{
            Time  = [datetime]$Matches['time']
            Level = $Matches['level']
            Kind  = $kind
        }
    }
}

$summary = $records |
    Group-Object Kind |
    ForEach-Object {
        [PSCustomObject]@{
            Level = $_.Group[0].Level
            Count = $_.Count
            First = ($_.Group.Time | Measure-Object -Minimum).Minimum
            Last  = ($_.Group.Time | Measure-Object -Maximum).Maximum
            Kind  = $_.Name
        }
    } |
    Sort-Object Count -Descending

# レポート名に当日の日付を入れる
$stamp     = Get-Date -Format "yyyyMMdd"
$csvPath   = Join-Path $reportDir "error_report_$stamp.csv"
$txtPath   = Join-Path $reportDir "error_report_$stamp.txt"

# 1) CSV出力(Excel/BIで使う用)。文字化け防止に UTF-8(BOM) を明示
$summary | Export-Csv -Path $csvPath -NoTypeInformation -Encoding utf8BOM

# 2) テキスト出力(メール・チャット貼り付け用)
$total = ($records | Measure-Object).Count
$header = @(
    "=== エラー日次レポート $((Get-Date).ToString('yyyy-MM-dd')) ==="
    "対象ログ: $logDir\$filter"
    "抽出total: $total 件(ERROR/WARN)"
    ""
)
$body = $summary |
    Format-Table Level, Count, First, Last, Kind -AutoSize |
    Out-String

($header -join "`r`n") + $body | Set-Content -Path $txtPath -Encoding utf8

Write-Host "レポート出力: $csvPath"
Write-Host "レポート出力: $txtPath"

出力された error_report_20260629.csv(中身):

"Level","Count","First","Last","Kind"
"ERROR","3","2026/06/29 10:02:33","2026/06/29 14:05:09","DB接続に失敗しました host=***"
"WARN","1","2026/06/29 9:15:45","2026/06/29 9:15:45","レスポンスが遅延しています (***ms)"
"ERROR","1","2026/06/29 11:45:50","2026/06/29 11:45:50","ファイルが見つかりません path=***"
"WARN","1","2026/06/29 13:20:18","2026/06/29 13:20:18","メモリ使用率が高い状態です (***%)"

出力された error_report_20260629.txt(中身):

=== エラー日次レポート 2026-06-29 ===
対象ログ: C:\logs\app-*.log
抽出total: 6 件(ERROR/WARN)

Level Count First               Last                Kind
----- ----- -----               ----                ----
ERROR     3 2026/06/29 10:02:33 2026/06/29 14:05:09 DB接続に失敗しました host=***
WARN      1 2026/06/29 9:15:45  2026/06/29 9:15:45  レスポンスが遅延しています (***ms)
ERROR     1 2026/06/29 11:45:50 2026/06/29 11:45:50 ファイルが見つかりません path=***
WARN      1 2026/06/29 13:20:18 2026/06/29 13:20:18 メモリ使用率が高い状態です (***%)

抽出total: 6 件 は ERROR4+WARN2 の合計で、レシピ1・2の件数と一致します。これをタスクスケジューラで毎朝動かせば(定期化の方法は第2回のレシピ4と同じ要領)、出社前にレポートが出来上がっています。

レシピ5:当日分・直近N分だけに絞る

1つのログファイルに複数日分が混ざっている場合や、「直近30分のエラーだけ見たい」監視用途では、Where-Object で時刻を絞ります。レシピ2の $recordsTime[datetime])があれば1行です。

# 当日(実行日の 00:00:00 以降)のエラーだけに絞る
$today = (Get-Date).Date
$todayRecords = $records | Where-Object { $_.Time -ge $today }

# 直近30分のエラーだけに絞る(簡易監視向け)
$since = (Get-Date).AddMinutes(-30)
$recent = $records | Where-Object { $_.Time -ge $since }

Write-Host "当日: $($todayRecords.Count) 件 / 直近30分: $($recent.Count) 件"

Time[datetime] にしておいたおかげで、-ge(以上)での比較がそのまま使えます。文字列のままだと正しく時刻比較できないので、レシピ2のキャストが効いてくる場面です。


コードの要点解説(なぜこの書き方か)

文法そのものではなく、現場でハマりやすいポイントを中心に解説します。

1. Select-String の戻り値は文字列ではなく MatchInfo

Select-String がヒットを返すとき、それは行の文字列ではなく MatchInfo オブジェクトです。主なプロパティは次のとおり。

プロパティ 内容
.Line ヒットした行の文字列全体
.LineNumber その行が何行目か(1始まり)
.Filename ファイル名(パスなし)
.Path フルパス
.Matches 正規表現マッチの詳細(グループ含む)

$hits | Select-Object Filename, LineNumber, Line のように 必要なプロパティを取り出せるのが findstr / grep との決定的な違いです。「どのファイルの何行目で出たか」がそのままレポートに使えます。

2. -Pattern は正規表現。リテラル一致は -SimpleMatch

-Pattern既定で正規表現 として扱われます。便利な反面、[ERROR]C:\data のように正規表現で意味を持つ文字([ ] \ . ( ) など)をそのまま書くと意図しないマッチになります。

# 角カッコをリテラルとして扱うにはエスケープが必要
Select-String -Pattern "\[ERROR\]"

# そもそも正規表現を使わず「ただの文字列一致」でよいなら -SimpleMatch
Select-String -Pattern "[ERROR]" -SimpleMatch   # この場合 [ERROR] という並びをそのまま探す

「決まった固定文字列を探すだけ」なら -SimpleMatch のほうが事故りません。逆に「日時パターンや種別をまとめて拾う」なら正規表現の出番です。

3. -CaseSensitive は既定オフ(大文字小文字を区別しない)

Select-String既定で大文字小文字を区別しませんerror でも ERROR でも Error でもヒットします。ログのレベル表記が揺れている(Error / ERROR 混在)現場ではむしろ好都合です。区別したいときだけ -CaseSensitive を付けます。

# 大文字の ERROR だけに厳密一致させたいとき
Select-String -Pattern "\[ERROR\]" -CaseSensitive

4. 名前付きグループ (?<name>...)$Matches で構造化する

ログ1行を構造データに変えるのが、解析の肝です。-match が成功すると自動変数 $Matches にグループ結果が入ります。

  • $Matches[0] … マッチ全体
  • $Matches['time'] … 名前付きグループ (?<time>...) の中身
  • $Matches[1] … 1番目のグループ(番号でもアクセス可)

[PSCustomObject] に詰め直すことで、以降は Group-ObjectWhere-ObjectExport-Csv といったPowerShellの集計・出力コマンドにそのまま乗せられます。「テキスト → オブジェクト」に変換した瞬間から作業が一気に楽になるのがPowerShellの強みです。

5. メッセージの「可変部分」を正規化してから集計する

host=db01 host=db02 のように毎回変わる値を含むメッセージは、-replace 'host=\S+', 'host=***'ならしてから Group-Object にかけます。\S+ は「空白以外の1文字以上」で、host= に続くサーバ名・パス・IDをまとめて潰せます。これをやるかどうかで、集計結果の有用さが大きく変わります。

6. 巨大ファイルはパイプ処理でメモリを節約する

Get-Content -Raw で全行をメモリに載せてから処理すると、数百MBのログでメモリを食い潰します。Select-Stringファイルを1行ずつストリーム処理するため、Get-ChildItem ... | Select-String の形なら巨大ログでもメモリ消費を抑えられます。さらに Get-Content -ReadCount でチャンク読みする手もありますが、まずは Select-String に直接ファイルを渡すのが素直で速いです。


応用・注意点

① 前後の行も一緒に見たい(-Context

エラー行だけ見ても原因が分からないとき、-Context で前後の行を一緒に表示できます。

# ヒット行の「前2行・後1行」も表示する
Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern "\[ERROR\]" -Context 2, 1

スタックトレースや「直前に何をしていたか」を追うのに有効です。-Context 前, 後 の順で行数を指定します(前後の行は .Context.PreContext / .Context.PostContext で取得可)。

② 複数パターンの「すべて」にマッチさせたいとき

-Pattern "A", "B"どれか1つにマッチ(OR) です。「AとBの両方を含む行」を取りたいときは、パイプでもう一度 Select-String を重ねます。

# "ERROR" を含み、かつ "DB" も含む行
Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern "\[ERROR\]" |
    Select-String -Pattern "DB"

③ ログの文字コードに注意(-Encoding

Select-String は既定でファイルのエンコーディングを推測しますが、日本語ログが Shift_JIS(ANSI) で書かれていると文字化けすることがあります。その場合は -Encoding を明示します。

# Shift_JIS のログを読む場合(PowerShell 7)
Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern "\[ERROR\]" -Encoding Default

PowerShell 7 では Default がOS既定のANSIコードページ(日本語Windowsなら概ねShift_JIS相当)を指します。出力側のCSVは、Excelでの文字化けを避けるため本記事のように utf8BOM で書き出すのが無難です。

④ レポート出力先を「対象ログ」に含めない

レシピ4では _report フォルダを C:\logs 配下に置いていますが、-Filter "app-*.log" で絞っているのでレポート(error_report_*.csv/.txt)は次回の対象に拾われません。とはいえ運用上は、レポートやアーカイブは対象フォルダの外に置くほうが事故が少ないです(第2回の _archive と同じ考え方)。同名レポートを再実行すると上書きされるので、日付(yyyyMMdd)を名前に入れて履歴を残しています。

⑤ Windows PowerShell 5.1 との差異

本記事のスクリプトは、コアな部分は 5.1 でもそのまま動作します。ただし以下に注意してください。

項目 PowerShell 7(pwsh) Windows PowerShell 5.1
Export-Csv -Encoding utf8BOM utf8BOM 指定可(BOM付きUTF-8) utf8BOM は未対応-Encoding UTF8 がBOM付きUTF-8になる
Set-Content -Encoding utf8 BOMなしUTF-8 -Encoding UTF8BOM付きUTF-8
Select-String -Encoding Default OS既定ANSI(日本語環境で概ねShift_JIS) 同様にANSI。挙動はほぼ同じ
$records.Count(0件時) 0件でも安全に 0 0件($null)で .Count が取れないことがある
正規表現エンジン .NET(同一) .NET(同一)。パターンは共通で動く

5.1 互換にするなら、CSV出力は -Encoding UTF8(5.1ではBOM付きになる)に変え、0件対策として結果を @(...) で配列化しておくのが安全です。

# 5.1 でも 0 件で落ちないよう配列化しておく
$hits = @(Get-ChildItem -Path $logDir -File -Filter $filter |
    Select-String -Pattern "\[ERROR\]", "\[WARN\]")

if ($hits.Count -eq 0) {
    Write-Host "対象期間のエラーはありませんでした。"
    return
}

まとめ

  • ログ抽出は Get-ChildItem ... | Select-String -Pattern "\[ERROR\]"。戻り値は MatchInfo.Line .LineNumber .Filename
  • -Pattern既定で正規表現。固定文字列なら -SimpleMatch、大文字小文字を区別するなら -CaseSensitive
  • 名前付きグループ (?<time>...)-match$Matches「テキスト → オブジェクト」 に変換するのが集計の起点
  • host=\S+ などの 可変部分を正規化 してから Group-Object。種別ごとの件数・初出・最終が正しくまとまる
  • レポートは日付入りファイル名でCSV/テキスト出力。巨大ログは Select-String のストリーム処理でメモリ節約

これで、毎朝20〜30分かけていた「ログ目視grep+手集計」が、タスクスケジューラ任せで0分になります。

次回 第8回は「サーバの死活・ディスク容量・サービス状態をまとめて確認」Test-ConnectionGet-PSDriveGet-Service で複数サーバの状態を一括チェックし、運用の朝のルーティンを1スクリプトにまとめるレシピを扱います。お楽しみに。


参考


@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?