PowerShell でイベントログをメール送信する
Windows でイベントログに出力されるイベントが発生したときになんらかの形で通知を送りたいと思い、やってみました。
今回は一番お手軽そうなメールを送るという方法を探ってみます。
しらべてみると、よく NotifiEventLog というツールで実現する方法が出てくるのですが、配布ページを訪問すると「開発終了」とのこと。
いまや PowerShell で実現できるだろうからわざわざ開発終了のツールを使うというのはいかがなものかということで、PowerShell で実現する方法を探してみました。
すると、だいたい タスクスケジューラー でイベント発生時のスケジュールを作り、PowerShell スクリプトを起動させ、PowerShell でメールを送信する、というものが見つかります。タスクスケジューラーにもSMTPサーバーを使用してメール送信する機能はあるものの、この機能ではSMTP認証ができないため、代わりに PowerShell で Net.Mail.SmtpClient クラスを使ってメール送信するということですね。
ところが、イベントが発生したことを通知できるものの、イベントの内容は送れない。今回はできたら発生したイベントのイベントログの内容を送信したいと考えていたので、このままではちょっと足りない。
そこで、基本的には上記エントリーにある方法を採用して、タスクスケジューラから起動される PowerShell スクリプトをなんとかイベントログの内容を送信するスクリプトとすべく、以下のスクリプトを考えてみました。
$datetime = Get-Date
$username = “notification@live.jp”
$password = “aaaabbbbccccdddd”
$myhost = “smtp-mail.outlook.com”
$port = 587$from = “notification@live.jp”
$to = “operator@aaa.jp”
$subject = “test mail by powershell”$sc = New-Object Net.Mail.SmtpClient
$sc.Host = $myhost
$sc.Port = $port
$sc.EnableSsl = $true$sc.Credentials = New-Object Net.NetworkCredential
$sc.Credentials.UserName = $username
$sc.Credentials.password = $password$logmessage = Get-EventLog -LogName System -Before ($datetime) -Newest 1 -EntryType Error | Format-List | Out-String
$body = “サーバーイベント “ + $datetime.ToString() + $logmessage$sc.send($from, $to, $subject, $body)
以下のことをやっています。
- まずは時間を取得
- SMTP 関係の各種設定値を変数に格納
- メールのfrom($from),送信先($to),件名($subject)を変数に格納
- Net.Mail.SmtpClient のインスタンスを生成してプロパティーの設定
- Get-EventLog コマンドレットでイベントログ取得。
オプションで各種フィルタを設定(このスクリプトを起動するタスクスケジューラに設定したフィルターと同じフィルターを設定。ここでは-LogName
と-EntryType
)、-Before ($datetime) -Newest 1
とオプションを設定することで、このスクリプトが起動した時刻以前の最新1件目のイベントを取得する。 Format-List コマンドレットにパイプで渡してフォーマット、Out-String コマンドレットにパイプで渡して String にする。 - send メソッドでメール送信。
イベントログの内容を送信するため、Get-EventLog コマンドレットでイベントを取得、 Format-List コマンドレットにパイプで渡してフォーマット、Out-String コマンドレットにパイプで渡して String にして、これをメールの本文にセットして送信しています。
そして、タスクスケジューラのトリガーとして設定したイベントのフィルターと同じようにフィルターしたうえでスクリプトが起動した時点での最新の1件を取得すれば、タスクスケジューラのトリガーとなったイベントが取得できるだろう、と考えて上記のスクリプトにしてみました。
イベントが発生してからスクリプトが動作するまでのタイムラグがあるので、スクリプト動作開始時の時刻以前の1件目というのは厳密度ではいかがなものかとも思いますが、お手軽というコンセプトで、よしとしています。
このスクリプトを作ったあと調べてみると、Send-MailMessage コマンドレットなるものがあるようで、なにも Net.Mail.SmtpClient クラスを使わなくてもよいみたいです…メール送信部分は置き換えてもいいのかもしれません。
厳密にしたい場合は Register-WmiEvent コマンドレットを使う方法がいいのでしょうね。
今のところ今回のスクリプト快調に動作中です。