ちょっと前に他のチームからの引き継ぎで新たな顧客のIT基盤の保守運用担当にアサインされました。
その際に引き継ぎドキュメントの運用手順書を確認していたら、毎月の定常運用の中で自動化したほうが効率も良くリスクも少なくなると思われる箇所が多かったので運用改善作としていくつかのスクリプトを作りました。
この記事ではその時の成果物の内、もっとも汎用的でどの顧客の運用にも使えそうな「イベントログ自動取得スクリプト」をご紹介します。
(※ちなみにWindowsサーバです。)
スクリプトの内容としては、Windowsサーバの「システム」と「アプリケーション」のイベントログを前月1日から末日までの期間を保存するという動きです。
このスクリプトを毎月1日にタスクスケジューラで実行させる事で毎月自動的にイベントログをバックアップする事が可能になります。
まずは早速スクリプトの中身をご紹介します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# イベントログ自動取得スクリプト(前月分を取得) # 対応OS:Windows Server 2012以降 # 取得対象のイベントログとして「システム」と「アプリケーション」を指定する $lognames = @("System","Application") # 先月時点のyyyyMM文字列を取得 $yyyyMM = (Get-Date).AddMonths(-1).ToString("yyyyMM") # 出力先として「C:\EventLog\(ホスト名)\yyyyMM」フォルダを指定・作成する。 $dstFolder = ("C:\EventLog\" + $Env:COMPUTERNAME + "\" + $yyyyMM) if((Test-Path $dstFolder) -eq $False){New-Item $dstFolder -ItemType Directory} # イベントログを取得する対象の期間を指定する(先月1日から末日までの1ヶ月間を指定) $startJTime = (Get-Date -Day 1 -hour 0 -minute 0 -second 0).AddMonths(-1) $endJTime = (Get-Date -Day 1 -hour 0 -minute 0 -second 0) $startUtcTime = [System.TimeZoneInfo]::ConvertTimeToUtc($startJTime).ToString("yyyy-MM-ddTHH:mm:ssZ") $endUtcTime = [System.TimeZoneInfo]::ConvertTimeToUtc($endJTime).ToString("yyyy-MM-ddTHH:mm:ssZ") $filter = @" Event/System/TimeCreated[@SystemTime>='$startUtcTime'] and Event/System/TimeCreated[@SystemTime<'$endUtcTime'] "@ # イベントログ出力用のオブジェクトを作成 $evsession = New-Object -TypeName System.Diagnostics.Eventing.Reader.EventLogSession # イベントログをevtx形式で出力する(「LocaleMetaData」も日本語の表示情報で出力させる) foreach($logname in $lognames){ $outfile = $dstFolder + "\" + $Env:COMPUTERNAME + "_" + $logname + "_" + $yyyyMM + ".evtx" $locale = [System.Globalization.CultureInfo]::CreateSpecificCulture("ja-JP") $evsession.ExportLogAndMessages($logname,"LogName",$filter,$outfile,$True,$locale) } WScript.Quit |
上記のテキストボックスの上部にある「Copy」アイコンをクリックしてコピーし、ご自身の端末のテキストエディタ上に貼り付け「GetEvLog.ps1」という名前で保存してください。
それでは、実際に使い方を説明していきます。
実際に使ってみよう!
まずはWindows Serverにログオンします。
スクリプトが対応しているOSですが、PowerShellのバージョンの都合でWindows Server 2012以降となります。
(PowerShellのバージョンを3以上に上げれば今のところ現役の2008 R2でも使えます。)
今回のps1スクリプトを任意のフォルダにコピーします。
イベントログの出力先については今回はスクリプト内に絶対パスで記述しているのでps1ファイルはどこに置いてあっても良いです。
「タスクスケジューラ」を立ち上げて今回のスクリプトを定期的に実行するためのタスクを作成します。
どこでも良いですが、上図の「タスクスケジューラライブラリ」辺りの何も無いところを右クリック⇒「新しいタスクの作成」でタスクを新規作成します。
「タスクの作成」画面が表れるので、適当なタスク名を付けたら「ユーザーまたはグループの変更」ボタンをクリックします。
「選択するオブジェクト名を入力してください」の欄には「system」とだけ入力し、「OK」ボタンをクリックして閉じてください。
(ちなみに、私はタスクスケジューラの実行ユーザはほぼ全てSystem権限にする派です。ただしドメイン管理者権限が必要な場合のみドメインの権限にしたりします。)
タスク実行ユーザーが「NT AUTHORITY\SYSTEM」に変更されたことを確認します。
ちなみに「最上位の特権で実行する」にはチェックを入れても入れなくても良いです。(というよりSystemより上位の権限はありません。)
「トリガー」タブに切り替えて、下の「新規」ボタンをクリックします。
スケジュール画面が表れるので左の設定で「毎月」にチェックを入れた後、右側の「月」の項目で「<すべての月を選択>」にチェックを入れます。
次に「日」にチェックを入れた後、実行日で「1」にチェックを入れます。
設定できたら画像のように「毎月1日」に実行する、というスケジュールになります。このまま「OK」ボタンをクリックします。
(実行時刻についてはここでは特に設定していませんが、顧客の本番サーバで設定する時は基本的には深夜帯で且つバックアップの時間を避けた時間を指定してください。)
「トリガー」が正常に追加されたことを確認します。
「操作」タブに切り替えて、下の「新規」ボタンをクリックします。
「プログラム/スクリプト」は「powershell」とだけ入力してください。(もちろん、powershell.exeの絶対パスを入れても良いです。)
「引数の追加」は、画像では見切れてしまっていますが「-Command “.\GetEvLog.ps1″」と入力してください。
「開始」は先ほどps1ファイルを置いたフォルダの絶対パスである「C:\EventLog\bin」を入力してください。
全て入力したら「OK」ボタンをクリックします。
「操作」が正常に追加されたことを確認します。
これで全ての設定が完了なので「OK」ボタンをクリックします。
これでタスクスケジューラに今回のタスクを追加出来ました。
これで毎月1日に自動的に実行されますが、テストの為に一旦手動で実行しましょう。
先月分のイベントログの量にもよりますが、だいたい十数秒程度で処理が完了します。
完了すると画像のように指定したフォルダにイベントログが自動的に出力されます。
保存されたイベントログを開いて、目的の種類のイベントログが指定した期間(先月)分が取れていることを確認します。
以上が基本的な手順になります。
スクリプトの詳細な内容について
ここからはある程度スクリプトをカスタマイズできるSEの方向けに説明していきます。
このスクリプトではイベントビューアーで見られるほぼ全てのログを取得できます。
今回の場合は「『システム』と『アプリケーション』」で、「先月1日から末日」で、「LocaleMetaDataを含んだevtx形式」で出力する。という記載にしています。
まずはログ種別ですが、スクリプトでは下記のように記載しています。
1 2 |
# 取得対象のイベントログとして「システム」と「アプリケーション」を指定する $lognames = @("System","Application") |
これに追加して、「セキュリティ」ログも取りたい!と顧客に言われた場合はスクリプトを下記のように修正します。
1 2 |
# 取得対象のイベントログとして「システム」と「アプリケーション」を指定する $lognames = @("System","Application","Security") |
「@」は指定されたStringの数の分だけ自動的に配列の要素数を拡張してくれます。
この$lognames配列はforeach関数で要素数の分だけ一つずつ実行されます。
基本的に取得するログは「システム」「アプリケーション」のみで良いはずですが、顧客によっては「セキュリティ」と各種アプリケーションの詳細ログを求められる場合があります。
アプリケーションの詳細ログを指定するには、対象のログの詳細情報にある「ログの名前」を指定してあげれば良いです。
次はフィルターです。
今回は下記のように「開始日」(先月1日)と「終了日」(先月末日)とだけ指定してフィルタリングしました。
1 2 3 4 |
$filter = @" Event/System/TimeCreated[@SystemTime>='$startUtcTime'] and Event/System/TimeCreated[@SystemTime<'$endUtcTime'] "@ |
これにandで接続してさらに条件を追加できます。
よくあるケースとして「『重大』と『エラー』と『警告』のログだけで良い」と指定される場合があります。
(個人的には『情報』ログを含めないのはかなり危険だと思いますが……(復旧情報が分からないし)。それでもなおこの種類のログだけで良いと言われたら設定してあげてください。)
そういった場合は下記のように対象のログレベルを条件に追加することで目的のログレベルのログだけ取得できます。
1 2 3 4 5 |
$filter = @" Event/System/TimeCreated[@SystemTime>='$startUtcTime'] and Event/System/TimeCreated[@SystemTime<'$endUtcTime'] and Event/System[(Level=1 or Level=2 or Level=3)] "@ |
上記の「Level=1」が重大ログ、「Level=2」がエラーログ、「Level=3」が警告ログとなります。
警告ログは不要で、前者の2つだけで良いと言われたら「or Level=3」は削除してください。
次はログを出力する際の形式です。他のブログではevtxで出力してそれで終わり、となっている場合がほとんどでしたが、
個人的にはどんなパソコン環境でもサーバで見た時と同じ内容のログを見られるようにしたいため、「LocaleMetaData」は必ず作成しています。
そのため、私は下記のように指定しています。
1 2 3 4 5 6 |
# イベントログをevtx形式で出力する(「LocaleMetaData」も日本語の表示情報で出力させる) foreach($logname in $lognames){ $outfile = $dstFolder + "\" + $Env:COMPUTERNAME + "_" + $logname + "_" + $yyyyMM + ".evtx" $locale = [System.Globalization.CultureInfo]::CreateSpecificCulture("ja-JP") $evsession.ExportLogAndMessages($logname,"LogName",$filter,$outfile,$True,$locale) } |
上記では$localeに日本語の環境情報を付与して、拡張オブジェクトである「ExportLogAndMessages」で明示的に日本語を指定して出力しています。
(ちなみに$localeを省略すると既定の言語でLocaleMetaDataが作成されます。)
「LocaleMetaData」なんていらない!俺は普通にイベントログを出力したいんだ!といった場合は下記のように書き換えることで通常のevtx形式のログを出力できます。
1 2 3 4 5 |
# イベントログをevtx形式で出力する foreach($logname in $lognames){ $outfile = $dstFolder + "\" + $Env:COMPUTERNAME + "_" + $logname + "_" + $yyyyMM + ".evtx" $evsession.ExportLog($logname,"LogName",$filter,$outfile) } |
「ExportLogAndMessages」の代わりに「ExportLog」を使っています。ここらへんはお好みで決めてください。
以上がイベントログ自動取得スクリプトのご紹介になります。
ご参考になれば幸甚です。