Windows Serverのイベントログをリアルタイムでメール送信

PowerShellを利用してリモート先からでも簡単にリアルタイム通知を実現

Windows Serverを利用してサービス提供をしている場合、イベントログはサーバー管理者にとって重要な情報源となります。緊急度の高いログが出力された場合、リアルタイムで情報を取得しておきたいものです。

重要と思われるイベントログが出力された場合に携帯などメール通知機能のある端末に情報を送信して、リアルタイムで確認する方法をご紹介します。

タスクスケジューラーを利用したイベントログのメール送信

イベントログが出力された際にメール通知するには、Windows Server標準のタスクスケジューラーやSystemCenter、サードパーティーの製品を利用することで実現可能ですが、数台程度のサーバー規模であればPowerShellを利用して簡単にリアルタイム通知をリモート先からでも実現することができます。

タスクスケジューラーを利用したイベントログのメール送信。
SMTP認証が必要な場合は、PowerShellなどでメール送信部分を記述して、「プログラムの開始」に登録する必要があります。トリガーとなるのはローカルサーバーのイベントログに限定されます。

イベントログのメール通知スクリプトの作成

PowerShellのプロセス監視とメール送信のスクリプトを組み合わせて、実際にイベントログのメール通知スクリプトを作成してみましょう。

PowerShellではプロセスを監視するためのRegister-WmiEventコマンドを使うことで、リアルタイムにイベント発生を取得することが可能です。Register-WmiEventコマンドは、WMIを利用することで、イベントログに限らずWindows上のプロセスの開始や終了など、WMI経由で発生したイベントをリアルタイムで取得することのできる便利なコマンドです。

今回はRegister-WmiEventコマンドが、イベントログにイベントが記録されたことを通知し、スクリプト内でこれをトリガーとしてメール送信を行うことになります。

まずはサンプルのスクリプト全体です。

1:	Write-Host "End to [Ctrl + C]"
2:	 	 	 
3:	$EventLog = "EventLogSink"
4:	Register-WmiEvent -Query "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA 'Win32_NTLogEvent' AND TargetInstance.LogFile = 'System'" -SourceIdentifier $EventLog
5:	 	 	 
6:	Try{	 
7:	 	While ($True) {
8:	 	 	$NewEvent = Wait-Event -SourceIdentifier $EventLog
9:	 	 	$Log = $NewEvent.SourceEventArgs.NewEvent.TargetInstance
10:	 	 	$LogName  = $Log.LogFile
11:	 	 	$SourceName   = $Log.SourceName
12:	 	 	$EventCode  = $Log.EventCode
13:	 	 	$TimeGenerated = $Log.TimeGenerated
14:	 	 	$Year =  $TimeGenerated.SubString(0, 4)
15:	 	 	$Month = $TimeGenerated.SubString(4, 2)
16:	 	 	$Day =  $TimeGenerated.SubString(6, 2)
17:	 	 	$Hour = $TimeGenerated.SubString(8, 2)
18:	 	 	$Minutes =  $TimeGenerated.SubString(10, 2)    
19:	 	 	$Date = $Year + "/" + $Month + "/" + $Day + " " + $Hour + ":" + $Minutes
20:	 	 	$Date = (([DateTime]$Date)).AddHours(9).ToString("yyyy/MM/dd HH:mm:ss")
21:	 	 	$Message = $Log.Message
22:	 	 	 
23:	 	 	$Body = `
24:	@"	 
25:	ソース:$SourceName
26:	イベントID:$EventCode
27:	日時:$Date
28:	メッセージ:
29:	$Message
30:	-----------------------------------------------
31:	"@	 
32:	 	 	 
33:	 	 	$SMTPServer = "smtp.gmail.com"
34:	 	 	$SMTPPort = "587"
35:	 	 	$From = "[email protected]"
36:	 	 	$Password = "PASSWORD"
37:	 	 	$To = "[email protected]"
38:	 	 	$Credential = New-Object System.Management.Automation.PSCredential($From, (ConvertTo-SecureString $Password -AsPlainText -Force))
39:	 	 	$Subject = $Env:COMPUTERNAME + " " + $LogName
40:	 	 	Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Port $SMTPPort -Credential $Credential -UseSsl -Encoding UTF8 
41:	 	 	Write-Output $Body 
42:	 	 	Remove-Event $EventLog
43:	 	}    
44:	}Catch{
45:	 	Write-Warning "Error"
46:	 	$Error[0]
47:	}Finally{
48:	    Get-Event | Remove-Event 
49:	    Get-EventSubscriber | Unregister-Event
50:	}	 	 

スクリプトの大まかな流れはこのようになります。

①Register-WmiEvent監視対象を登録
Try{
 While{
  ②Wait-Eventコマンドでイベント発生まで待機
  ③コード実行
  ④Remove-Eventコマンドで処理が終了したイベントを破棄
  ②~④を繰り返し
 }
}Catch{
⑤エラーが発生した場合にメッセージ表示
}
Finally{
⑥スクリプト終了時、エラー発生時にイベントログ監視登録を削除
}

各ブロックごとに見ていきましょう。

1行目

Write-Host "End to [Ctrl + C]"

このスクリプトは、7行目~39行目までWhile文を使ってイベントが発生するまで待機状態に入ります。このスクリプトを終了するには[Ctrl + C]で強制終了する必要があるため、終了するためのメッセージをコンソールに表示しています。

3~4行目

$EventLog = "EventLogSink"

Register-WmiEvent -Query "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA 'Win32_NTLogEvent' AND TargetInstance.LogFile = 'System'" -SourceIdentifier $EventLog

イベントログの発生を知るためには、Register-WmiEventコマンドにクエリ文を使って、WMIのクラス__InstanceCreationEventを指定します。
WHERE句で
WHERE TargetInstance ISA ‘Win32_NTLogEvent’ AND TargetInstance.LogFile = ‘System’
とすることで、「システム」のイベントログを取得するよう指定しています。必要とするイベントログによってこのWHERE句を書き換えることで、フィルタされたイベントログの発生のみを通知対象とすることができます。

※ 何もフィルタの指定をしていない状態でサービス提供中のサーバーのログをすべてメール送信した場合、短時間で大量のイベントログが出力される場合があります。メールサーバーにかなりの負荷を与えることがありますので、メール送信するイベントログの選択には注意が必要です。


例)
・すべてのイベントログを通知対象とする場合
SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA ‘Win32_NTLogEvent’

・システムログのイベントID 4097のみ取得する場合
SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA ‘Win32_NTLogEvent’ AND TargetInstance.LogFile = ‘System’ AND EventCode=4097

・Windows PowerShell と Microsoft-Windows-Hyper-V-Worker-Admin を取得する場合
“SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA ‘Win32_NTLogEvent’ AND (TargetInstance.LogFile = ‘Windows PowerShell’ OR TargetInstance.LogFile = ‘Microsoft-Windows-Hyper-V-Worker-Admin’)”

取得できるイベントログの種類

TargetInstance.LogFile = **** で指定することのできるイベントログの種類は、既定ではGet-WmiObject Win32_NteventLogFile コマンドで確認することができます。

Get-WmiObject Win32_NteventLogFile | Select LogfileName

LogfileName
-----------
Application
HardwareEvents
Internet Explorer
Key Management Service
Security
System
Windows PowerShell

この一覧は管理ツールの「イベントビューアー」で確認できるものとなります。

イベントビューアーで対応するログ

また、レジストリでも取得できるイベントログを確認することができます。
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\EventLog

レジストリで取得できるイベントログを確認

これら一覧で確認できるものが、WMIで取得できるイベントログとなっています。
ですが、Windows Serverのイベントビューアーでは「アプリケーションとサービスログ」でさらに多くのイベントログを参照できるようになっています。

アプリケーションとサービスログ

これらのイベントログをWMIで取得できるようにするには、先ほどのレジストリにログファイル名を追加しておく必要があります。ここではHyper-V関連のイベントログ「Hyper-V-Worker」を登録してみます。

レジストリの「HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\EventLog」
にキーを追加します。

キー名はイベントログビューアーで確認できる「ログの名前」項目となります。名前に”/”(スラッシュ)がありますが、こちらは”-”(ハイフン)で置き換える必要があります。

Hyper-V-Workerのログの名前 Microsoft-Windows-Hyper-V-Worker-Admin

レジストリへの登録もPowerShellを使いましょう。

New-Item "HKLM:\SYSTEM\ControlSet001\Services\EventLog" -Name "Microsoft-Windows-Hyper-V-Worker-Admin"

レジストリへの登録が完了すればWMIでイベントログを取得できるようになります。

レジストリへの登録が完了

Get-WmiObject Win32_NteventLogFile コマンドで確認すると Microsoft-Windows-Hyper-V-Worker-Admin が追加されています。

Get-WmiObject Win32_NteventLogFile | Select LogfileName

LogfileName
-----------
Application
HardwareEvents
Internet Explorer
Key Management Service
Microsoft-Windows-Hyper-V-Worker-Admin
Security
System
Windows PowerShell

6~7行目
Try~ While からの内容が対象となるイベントログにログが書き込まれた時の処理内容になります。

8~13行目
イベントログ取得時に各プロパティを取得します。注意点として TimeGenerated で取得したイベント発生時刻が世界標準時になっているので、日本時間に合わせるためにはプラス9時間とする必要があります。

$NewEvent = Wait-Event -SourceIdentifier $EventLog
$Log = $NewEvent.SourceEventArgs.NewEvent.TargetInstance
$LogName = $Log.LogFile
$SourceName = $Log.SourceName
$EventCode = $Log.EventCode
$TimeGenerated = $Log.TimeGenerated

14~20行目
TimeGenerated で取得した時刻が特殊な文字列となっているため、日本時間に合わせる加工をします。

$Year = $TimeGenerated.SubString(0, 4)
$Month = $TimeGenerated.SubString(4, 2)
$Day = $TimeGenerated.SubString(6, 2)
$Hour = $TimeGenerated.SubString(8, 2)
$Minutes = $TimeGenerated.SubString(10, 2)
$Date = $Year + "/" + $Month + "/" + $Day + " " + $Hour + ":" + $Minutes
$Date = (([DateTime]$Date)).AddHours(9).ToString("yyyy/MM/dd HH:mm:ss")

23~31行目
メールで送信するときの本文内容を@”<改行>~<改行>”@(ヒア文字列)で記述しています。ヒア文字列はコード内に記述した通りに改行やタブが反映されます。

@"
ソース:$SourceName
イベントID:$EventCode
日時:$Date
メッセージ:
$Message
-----------------------------------------------
"@

33~41行目
GmailのSMTPを利用してメールを送信します。Gmailのアカウントがあればすぐに利用できるのでこのメール送信の部分は他にもいろいろと再利用できるので便利です。
同時に取得したイベントログの内容をPowerShellのコンソールにも出力します。

$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$From = "[email protected]"
$Password = "PASSWORD"
$To = "[email protected]"
$Credential = New-Object System.Management.Automation.PSCredential($From, (ConvertTo-SecureString $Password -AsPlainText -Force))
$Subject = $Env:COMPUTERNAME + " " + $LogName
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Port $SMTPPort -Credential $Credential -UseSsl -Encoding UTF8
Write-Output $Body

42行目
発生したイベントを削除して次のイベント発生に備えます。

Remove-Event $EventLog

44~50行目
エラーが発生した場合、エラーメッセージを表示します。Finally~では登録されたイベント通知オブジェクトを削除します。この部分はスクリプトを[Ctrl + C]を使って強制終了した場合も同様の処理を行います。この処理をきちんとしておかないと、次に同様にイベント監視のスクリプトを実行した場合、予期せぬエラーやリソース不足になる場合がありますので、必ずスクリプト終了時には実行する必要があります。

}Catch{
    Write-Warning "Error"
  $Error[0]
}Finally{
  Get-Event | Remove-Event
  Get-EventSubscriber | Unregister-Event
}

では、早速スクリプトを利用して発生したイベントログをメール送信してみましょう。テスト用にイベントログを発生させるためのEventcreateコマンドが用意されています。

Eventcreate /t Error /id 999 /d "System Test Error Event" /l "System" /so "PowerShell Test"

このコマンドでテストとしてシステムログにイベンログを書き込みます。

スクリプトを実際に実行する
イベントログにログを書き込む
発生したイベントがメールとして通知される

問題なくスクリプトが実行できたら、このスクリプトを監視対象サーバー上のタスクスケジューラーで、サーバー起動時に実行するように登録します。タスクスケジューラーでps1ファイルを実行するようにするためには、「プログラムの開始」の「プログラム/スクリプト」には” C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe”を指定し、「引数の追加」でps1ファイルのパスを-Cオプションを付けて指定します。

サーバーの起動時に実行するようにタスクスケジューラーに登録

ここまでがローカルサーバーにps1ファイルのスクリプトを登録して、イベントログをメール送信する方法となります。リモート先サーバーへイベントログを送信

さらに、PowerShellのInvoke-Commandコマンドを利用すると、リモート先のサーバーに対して同様にイベントログをメール送信することが可能です。リモート先のサーバーに対してアカウントとパスワードを指定します。パスワードはConvertTo-SecureStringコマンドでセキュアなものに変換する必要があります。

$Server = "HV01"
$AdminPassword = "PASSWORD"
$AdminAccount = "DOMAIN\Admin01"
$Password = ConvertTo-SecureString $AdminPassword -AsPlainText -Force
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AdminAccount, $Password

Invoke-Command -ComputerName $Server -FilePath {C:\EventSend.ps1} -Cred $Cred

Invoke-Commandコマンドを利用するときに注意すべきは、呼び出すps1ファイルのスクリプト内にFunctionを使って関数を作成して呼び出すような書き方をすると、エラーとなりますので、Functionは使用せずにすべて平文で書き込む必要があります。

以上が、PowerShellを利用してイベント発生時にイベントログの内容をメール送信する方法となります。

PowerShellは手軽に作成できるうえに多機能なため、サーバー管理者にとってなくてはならないものとなっています。今回紹介した方法以外にも数多くのPowerShellの技があり、アイデア次第でさらに便利になる可能性を秘めています。ぜひチャレンジしてみてください。


サンプルコードをこちらからダウンロードいただけます。 →SampleCode.zip(1.3KB)

著書の紹介欄

Hyper-Vで本格的なサーバー仮想環境を構築。仮想環境を設定・操作できる!

できるPRO Windows Server 2016 Hyper-V

◇Hyper-Vのさまざまな機能がわかる ◇インストールからの操作手順を解説 ◇チェックポイントやレプリカも活用できる Windows Server 2016 Hyper-Vは、仮想化ソフトウェア基盤を提供する機能であり、クラウドの実現に不可欠のものです。 本書では、仮想化の基礎知識から、Hyper-Vでの仮想マシンや仮想スイッチの設定・操作、プライベートクラウドの構築、Azureとの連携などを解説します。

初めてのWindows Azure Pack本が発売

Windows Azure Pack プライベートクラウド構築ガイド

本書は、Windows Azure PackとHyper-Vを利用し、企業内IaaS(仮想マシン提供サービス)を構成するための、IT管理者に向けた手引書です。試用したサーバーは、最小限度の物理サーバーと仮想マシンで構成しています。Windows Azure Packに必要なコンポーネントのダウンロード、実際にプライベートクラウド構築する過程を、手順を追って解説しています。これからプライベートクラウドの構築を検討するうえで、作業負担の軽減に役立つ一冊です。

ブログの著者欄

樋口 勝一

GMOインターネットグループ株式会社

1999年6月GMOインターネットグループ株式会社に入社。Windows Serverをプラットフォームとしたサービス開発から運用・保守まで幅広く担当。講演登壇や出版、ネット記事連載などでマイクロソフト社と強い信頼関係を構築。「マイクロソフトMVPアワード」を15度受賞し、インターネットソリューションのスペシャリストとして活躍。

採用情報

関連記事

KEYWORD

採用情報

SNS FOLLOW

GMOインターネットグループのSNSをフォローして最新情報をチェック