みなさんこんにちは!ヒロポンです!
サーバーのイベントログ、毎朝目視で見てませんか??
俺もそうでした。流通系の基幹システムの保守をやってた頃、朝イチでサーバーにリモート接続して、イベントビューア開いて、赤いエラーが出てないか目で追う。これを毎日。
で、ある朝。前夜にサービスが落ちてたのを半日気付かなかった。目視って、見落とすんですよ。人間だもん。
これ、PowerShell イベントログ 監視を組めば自動化できます。エラーが出たら勝手にメールが飛んでくる。朝の目視チェックがまるごと消える。
この記事では、Get-WinEvent で対象エラーを絞って、Send-MailMessage で通知して、タスクスケジューラで定期実行するところまで、1人運用の業務SEが組める手順で書いていきます。
この記事でできること(完成イメージ)
組み上がると、こういう流れが10分おきに勝手に回ります。

ゴールは「エラーが出た時だけメールが来る」状態。平常時は何も鳴らない。だからメールが来た=何か起きた、と即わかります。
前提条件・必要なもの
- Windows Server(クライアント Windows でも可)
- PowerShell 5.1(Windows 標準。この記事は 5.1 前提で書きます)
- 送信できる SMTP サーバー(社内のメールサーバー等)
- スクリプトを置くフォルダ(例:
C:\scripts\)
PowerShell 7 を使ってる人向けの注意は、後ろのトラブルシューティングで1つ触れます。
この記事のコードは Windows 専用 cmdlet(Get-WinEvent / タスクスケジューラ系 / Send-MailMessage)が中心です。構文は検証済みですが、実行は Windows + PowerShell 5.1 環境でやってください。
Step 1: Get-WinEvent で対象ログのエラーを絞る
まずはイベントログから「直近のエラーだけ」を取り出す。使うのは Get-WinEvent の FilterHashtable です。
# System ログから直近10分の Error を取得
$since = (Get-Date).AddMinutes(-10)
$events = Get-WinEvent -FilterHashtable @{
LogName = 'System'
Level = 2 # 1=Critical, 2=Error, 3=Warning, 4=Information
StartTime = $since
} -ErrorAction SilentlyContinue
Level = 2 が Error。StartTime で「直近10分」に絞ってます。
地味だけど重要なのが -ErrorAction SilentlyContinue。Get-WinEvent は該当ログが0件だとエラーを吐く仕様なんですよ。だからこれを付けないと「エラーが無いのにスクリプトがコケる」っていう、なんとも変な動きになります。
古い Get-EventLog でも似たことはできるんですが、新しいログ(セットアップログや一部のアプリログ)を拾えない場面があって、今は Get-WinEvent が定番です。
Step 2: 拾う条件を組み立てる(Level / EventID / 直近N分)
「全部の Error」だと、現場によっては多すぎる。そういう時は EventID で絞ります。
# 特定の EventID だけ拾う
# (例: 7=ディスクのコントローラエラー, 7034=サービスが予期せず終了)
$events = Get-WinEvent -FilterHashtable @{
LogName = 'System'
Level = 2
Id = 7, 7034
StartTime = $since
} -ErrorAction SilentlyContinue
Id = 7, 7034 みたいにカンマで複数指定できます。自分の現場で「これは絶対拾いたい」EventID を、ここに足していく感じ。
LogName を 'Application' にすればアプリケーションログ、'Security' ならセキュリティログも見られます。こんな感じで、監視したいログと条件を組み合わせていきます。
Step 3: 引っかかったらメールで通知する(Send-MailMessage)
対象イベントがあったら、メールを飛ばす。
if ($events) {
# 本文を読みやすく整形
$body = $events |
Select-Object TimeCreated, Id, LevelDisplayName, Message |
Format-List | Out-String
Send-MailMessage `
-From 'monitor@example.co.jp' `
-To 'admin@example.co.jp' `
-Subject "[警告] $($env:COMPUTERNAME) でエラー $($events.Count) 件" `
-Body $body `
-SmtpServer 'smtp.example.co.jp'
}
if ($events) で「1件でもあれば」通知。$events.Count で件数、$env:COMPUTERNAME でどのサーバーかを件名に突っ込んでおくと、メールを見た瞬間に状況がつかめます。
平常時は $events が空なので、if に入らず何も送りません。いい感じに「異常時だけ鳴る」が実現します。
⚠️
Send-MailMessageは PowerShell 7 で非推奨(obsolete)になっています。5.1 ではそのまま使えますが、7 や新規構築ならMailKitなどの代替を検討してください(詳細はトラブルシューティングに)。
Step 4: タスクスケジューラで定期実行する
ここまでを1つの .ps1(例: C:\scripts\EventMonitor.ps1)にまとめたら、タスクスケジューラで10分おきに回します。
# 監視スクリプトを10分ごとに実行するタスクを登録
$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
-Argument '-NoProfile -ExecutionPolicy Bypass -File "C:\scripts\EventMonitor.ps1"'
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) `
-RepetitionInterval (New-TimeSpan -Minutes 10)
Register-ScheduledTask -TaskName 'EventLogMonitor' `
-Action $action -Trigger $trigger `
-User 'SYSTEM' -RunLevel Highest
-User 'SYSTEM' で実行アカウントを指定、-RunLevel Highest で管理者権限で動かす。ここの権限設定が後でじわっと効いてくるので、覚えておいてください。
動作確認
組んだら、本番を待たずにわざとエラーを起こして確認します。
# テスト用に Application ログへ Error を1件書き込む
New-EventLog -LogName Application -Source 'MonitorTest' -ErrorAction SilentlyContinue
Write-EventLog -LogName Application -Source 'MonitorTest' `
-EntryType Error -EventId 9999 -Message 'テストエラーです'
このあと監視スクリプトを手で1回流して(または10分待って)、メールが届けばOK。届かなかったら、次のトラブルシューティングを見てください。
動作確認メモ: ここまでのコードは Windows + PowerShell 5.1 専用 cmdlet が中心のため、開発機の Linux / pwsh では構文検証までしか通せません(構文は全ブロック検証済み)。実機(Windows Server)での動作確認をおすすめします。
トラブルシューティング(こんなエラーが出たら)
Get-WinEvent で「No events were found」と出る
これ、エラーじゃなくて0件だっただけってことが多いです。Get-WinEvent は該当0件で例外を投げる仕様なので、Step 1 みたいに -ErrorAction SilentlyContinue を付けて握りつぶします。
ただし握りつぶしすぎると本当のエラーまで消える。-ErrorAction の扱いは PowerShell の ErrorAction で踏む3パターン も合わせて見ておくと安全です。
メールが飛ばない(Send-MailMessage が非推奨の件)
正直に言うと、俺もここで30分溶かしました。
Send-MailMessage は PowerShell 7 系で非推奨(obsolete)になっていて、Microsoft も「安全な接続を保証しない」として新規利用を推奨していません。5.1 では動きますが、7 で組むなら MailKit(NuGet)、Microsoft 365 環境なら Microsoft Graph 経由が今の定番です。
5.1 で動かない時は、SMTP サーバー側が認証や TLS を要求してるケースが多いので、-Credential や -UseSsl を足して試してみてください。
タスクは動くのにメールが来ない(権限で空振り)
タスクスケジューラの実行アカウントにログの読み取り権限がないと、Get-WinEvent が空振りして何も拾えません。手で実行すると動くのにタスクだと鳴らない。ん?手だと動くのに??ってなる、典型パターンです。
Security ログを読むなら、特に権限が要ります。Step 4 の -User 'SYSTEM' で動かすか、ログ読み取り権限を持つアカウントを指定してください。
まとめ
要点はこれだけ。
- 取得は
Get-WinEvent -FilterHashtable、Level=2とStartTimeでエラーを直近N分に絞る Get-WinEventは0件で例外を吐くので-ErrorAction SilentlyContinue必須- 通知は
Send-MailMessage(5.1 はOK・7 は非推奨なので代替検討) - タスクスケジューラで定期実行。実行アカウントのログ読み取り権限に注意
監視を1回組んでおくだけで、朝の目視が消えて、夜中の事故にも気付ける。こんな感じで、1人運用ほど効きます!!
PowerShell の運用自動化まわりを体系的に押さえたいなら、スクリプト系の解説書を1冊持っておくと、この手の「どう組むのが定番か」を調べる時間がまるっと浮きます。
このスクリプト、C:\scripts\ に置いてそのまま回してください。
よくある質問
Q1. Get-EventLog と Get-WinEvent はどちらを使うべきですか?
新規に書くなら Get-WinEvent を推奨します。Get-EventLog は古い API で、Windows Vista 以降に追加されたログ(セットアップログや一部のアプリログ)を拾えない場合があります。Get-WinEvent は FilterHashtable でサーバー側フィルタが効くので、大量ログでも速いです。
Q2. 直近N分ではなく「前回実行以降」で拾えますか?
できます。前回実行時刻をファイルに保存しておき、次回その時刻を StartTime に渡す方式が定番です。ただし実装が増えるので、まずは「実行間隔と同じN分」で重複なく拾える設計(10分間隔なら直近10分)から始めるのがシンプルです。
Q3. メール以外(Teams / Slack)に通知できますか?
できます。Send-MailMessage の部分を、各サービスの Webhook(Incoming Webhook)に Invoke-RestMethod で POST する形に差し替えるだけです。通知先がチャットなら、その場で気付けるので1人運用との相性は良いです。
Q4. PowerShell 7 でこのスクリプトは動きますか?
Get-WinEvent とタスクスケジューラ系は 7 でも動きます。問題は Send-MailMessage だけで、7 では非推奨です。7 で組むなら通知部分を MailKit か Webhook に置き換えれば、残りはそのまま使えます。
次に読むべき記事




以上!
同じ目視チェックで疲れてる人いたら、どんどんシェア待ってるぜ!!
執筆者
バイブス父さん — 業務 SE 7 年 (SIer 正社員 2 / フリーランス 5)。 現職は SEO 直轄部の AI アドバイザー兼 PL、 副業で中小 SIer の CTO。 SIer の正社員からフリーランスに転じ、 複数のエージェント経由で案件を回してきた経験ベースで「業務 SE 視点」 の技術 + キャリア記事を書いています。
🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る

