Option Explicit
' ------------------------------
' パソコンごとの設定(ここから)
' ------------------------------
Const strMailFrom = "□□□@□□□□.□□.□□" ' 送信元メールアドレス
Const strMailTo = "□□□□@□□□□.□□.□□" ' 送信先メールアドレス
Const strSMTPServer = "□□□□.□□.□□" ' SMTPサーバ
Const intSMTPPort = 25 ' SMTPポート
Const strSubjectOK = "○ログ収集テスト" ' 正常時の件名
Const strSubjectNG = "●ログ収集テスト" ' 異常時の件名
Const intInterval = 1442 ' イベントログを収集する期間(分)
' 抽出条件
Const strWhere0 = "Logfile='System' or Logfile='Application'" ' システムとアプリケーションのログを収集
Const strWhere1 = "SourceName<>'MSSQLServer' or EventCode<>'19011'" ' SQL-Server起動時に出ることがあるが無視
Const strWhere2 = "SourceName<>'W3SVC'" ' W3SVC(IIS)の警告を無視
Const strWhere3 = "SourceName<>'DNS'" ' DNS関連のメッセージを無視
Const strWhere4 = ""
Const strWhere5 = ""
Const strWhere6 = ""
Const strWhere7 = ""
Const strWhere8 = ""
Const strWhere9 = ""
' 例)
' Logfile='System' or Logfile='Application' ← システムかアプリケーション
' SourceName<>'SecurityCenter' and SourceName<>'Service Control Manager' ← 特定ソースの除外
' EventCode<>'33' and EventCode<>'7035' ← 特定イベントコードの除外
' ------------------------------
' パソコンごとの設定(ここまで)
' ------------------------------
|
| ↑ | |
送信元メールアドレスや送信先メールアドレスなどを設定します。
当然ですが、実行するパソコンはeメールが送信できる環境にある必要があります。
SMTPポートの変更が必要な場合は、ここで直して下さい。
SMTPサーバに「POP before SMTP」の制限がある場合の可否は未確認です。
このスクリプトは、『エラー』または『警告』のログを判定するように作っています。
『エラー』または『警告』があった場合、メールの件名に『異常時の件名』を設定します。
異常でなければ、ログの詳細を確認する手間を省くこともできそうです。
サンプルは、1日=60分×24時間/分=1440分プラス2分の余裕を見て、約1日分のログを送る設定です。
「intInterval」の値は起動する間隔などによって調整して下さい。
収集するログの『抽出条件』を最大10コ指定することができます。
『抽出条件』を複数指定した場合、各条件は論理積(AND)になります。
『抽出条件』が必要ない場合、「strWhere0〜9」変数を空文字にしておいて下さい。
『抽出条件』に当てはまらないログは、無視されます。(メールの本文にも編集されません。)
|
' ------------
' 変数の宣言
' ------------
dim dtmStartDateTime
dim strBias
dim strQuery
dim strComputer
dim objWMIService
dim colLoggedEvents
dim objEvent
dim intEventCount
dim intErrorCount
dim intI
dim intJ
dim strSubject
dim strTextBody
dim strKeyLogfile
' --------------------------------------------------
' 対象とする開始日時を変数(dtmStartDateTime)に編集
' --------------------------------------------------
On Error Resume Next ' エラー中断を停止
' XPならOK、2000ではエラーになる
Set dtmStartDateTime = CreateObject("WbemScripting.SWbemDateTime")
if Err = 0 then
On Error goto 0 ' エラー中断を再開
' dtmStartDateTimeをSWbemで編集
dtmStartDateTime.SetVarDate DateAdd("n",- intInterval,Now), True
|
| ↑ | |
イベントログを参照する手段として、「WMI」を利用します。
「WMI」は、「Windows Management Instrumentation」の略で、「Windows 2000」以降で利用できるそうです。
「DMTF(Desktop Management Task Force)」という、システム管理を目的とした標準化団体があるそうです。
「WBEM(Web-based Enterprise Management)」は、「DMTF」が策定した標準仕様だそうです。
「WMI」は、「WBEM」に従っているそうです。
「いつから」という条件でイベントログを抽出したいのですが、日付時刻は「WBEM」の書式で表す必要があります。
OSが「Windows XP」以降なら、「SWbemDateTime」が使えました。
上記は、「SWbemDateTime」の「SetVarDate」を用いてdtmStartDateTime変数に「いつから」を設定しています。
|
else
Error.Clear
On Error goto 0 ' エラー中断を再開
dim objSWbemServices
dim objTimeZone
dim colTimeZone
strComputer = "."
' 時差(分)を取得
Set objSWbemServices = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colTimeZone = objSWbemServices.ExecQuery ("SELECT * FROM Win32_TimeZone")
For Each objTimeZone in colTimeZone
strBias = objTimeZone.Bias
Next
' dtmStartDateTimeをコーディングで編集
dtmStartDateTime = DateAdd("n",- intInterval,Now)
dtmStartDateTime = Year(dtmStartDateTime) & _
right("0" & Month(dtmStartDateTime),2) & _
right("0" & Day(dtmStartDateTime),2) & _
right("0" & Hour(dtmStartDateTime), 2) & _
right("0" & Minute(dtmStartDateTime), 2) & _
right("0" & Second(dtmStartDateTime), 2) & ".000000"
if strBias < 0 then
dtmStartDateTime = dtmStartDateTime & "-" & Abs(strBias)
else
dtmStartDateTime = dtmStartDateTime & "+" & Abs(strBias)
end if
|
| ↑ | |
「Windows 2000」では、「SWbemDateTime」が使えなので、dtmStartDateTime変数をコーディングで編集しています。
実行するパソコンのOSが「Windows XP」以降なら、ここは実行されないハズなので、必要ありません。
環境やご意向に応じて、コーディングを修正して下さい。
|
end if
' -----------------------------------
' WMIからイベントログを参照する準備
' -----------------------------------
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
strQuery = "Select * from Win32_NTLogEvent Where (EventType='1' or EventType='2' or EventType='3')" ' 1,2,3のイベントを見ます。
strQuery = strQuery & " and (TimeWritten > '" & dtmStartDateTime & "')"
|
| ↑ | |
ここでdtmStartDateTime変数(いつから)を使っています。
|
' 抽出条件(追加分)
if strWhere0 <> "" then
strQuery = strQuery & " and (" & strWhere0 & ")"
end if
if strWhere1 <> "" then
strQuery = strQuery & " and (" & strWhere1 & ")"
end if
if strWhere2 <> "" then
strQuery = strQuery & " and (" & strWhere2 & ")"
end if
if strWhere3 <> "" then
strQuery = strQuery & " and (" & strWhere3 & ")"
end if
if strWhere4 <> "" then
strQuery = strQuery & " and (" & strWhere4 & ")"
end if
if strWhere5 <> "" then
strQuery = strQuery & " and (" & strWhere5 & ")"
end if
if strWhere6 <> "" then
strQuery = strQuery & " and (" & strWhere6 & ")"
end if
if strWhere7 <> "" then
strQuery = strQuery & " and (" & strWhere7 & ")"
end if
if strWhere8 <> "" then
strQuery = strQuery & " and (" & strWhere8 & ")"
end if
if strWhere9 <> "" then
strQuery = strQuery & " and (" & strWhere9 & ")"
end if
Set colLoggedEvents = objWMIService.ExecQuery (strQuery)
'Wscript.Echo strQuery
|
| ↑ | |
ここまでで、イベントログを参照するするためのSQL文を編集しています。
残念なのは、SQL文に「ORDER BY」区の指定ができなかったことです。
仕方ないので、いったん配列変数に取り込んで、後続のステップで並べ替えています。
|
intEventCount = 0 ' イベント件数を初期化
intErrorCount = 0 ' エラー件数を初期化
strTextBody = "" ' メール本文用変数を初期化
strKeyLogfile = "" ' ログの種類変数を初期化
' -----------------------------------
' WMIからイベントログを参照して編集
' -----------------------------------
if colLoggedEvents.Count > 0 then
dim strLogfile()
dim intRecordNumber()
dim strType()
dim strTimeWritten()
dim strEventCode()
dim strSourceName()
dim strMessage()
|
| ↑ | |
イベントログはこの配列変数に取り込みます。
strType変数には、『エラー』,『警告』,『情報』に対して『●』,『▲』,『○』を設定しています。
|
For Each objEvent in colLoggedEvents
intEventCount = intEventCount + 1
redim Preserve strLogfile(intEventCount)
redim Preserve intRecordNumber(intEventCount)
redim Preserve strType(intEventCount)
redim Preserve strTimeWritten(intEventCount)
redim Preserve strEventCode(intEventCount)
redim Preserve strSourceName(intEventCount)
redim Preserve strMessage(intEventCount)
' テーブルに取り込み
strLogfile(intEventCount) = objEvent.Logfile ' ログの種類
intRecordNumber(intEventCount) = objEvent.RecordNumber
' エラーを判定
if objEvent.EventType = "1" then
' エラーのとき
intErrorCount = intErrorCount + 1
strType(intEventCount) = "●"
elseif objEvent.EventType = "2" then
' 警告のとき
' -------------------------------------------------------
' 拾う必要が無い警告を無視するよう判定を追加(ここから)
' -------------------------------------------------------
if objEvent.SourceName = "@@@@" then
strType(intEventCount) = "○"
'elseif objEvent.SourceName = "XXXX" then
' strType(intEventCount) = "○"
' -------------------------------------------------------
' 拾う必要が無い警告を無視するよう判定を追加(ここまで)
' -------------------------------------------------------
|
| ↑ | |
予め原因等が判っていて、危険のない『警告』があるかも知れません。
毎回のメールで『警告』としてマークされると、検出すべき問題を見逃す危険性が高くなります。
必要に応じ、『拾う必要が無い警告を……(ここから)〜(ここまで)』の間のコーディングを追加/修正して下さい。
明細には編集されますが、『警告』としてはカウントされないように変更できます。
|
else
strType(intEventCount) = "▲"
intErrorCount = intErrorCount + 1
end if
else
' -----------------------------------------------------------
' アプリケーションが出すエラーを拾うよう判定を追加(ここから)
' -----------------------------------------------------------
' DNSと通信ができないとき
if objEvent.SourceName = "@@@@" and left(objEvent.Message,4) = "@@@@" then
strType(intEventCount) = "▲"
intErrorCount = intErrorCount + 1
'elseif objEvent.SourceName = "XXXX" and objEvent.EventCode = "9999" then
' strType(intEventCount) = "▲"
' intErrorCount = intErrorCount + 1
' -----------------------------------------------------------
' アプリケーションが出すエラーを拾うよう判定を追加(ここまで)
' -----------------------------------------------------------
|
| ↑ | |
『エラー』として検出したい内容にも関わらず、『情報』として出力されるログがあります。
必要に応じ、『アプリケーションが出すエラーを……(ここから)〜(ここまで)』の間のコーディングを追加/修正して下さい。
ここで指定した条件に適合した場合、強制的に『エラー』や『警告』としてカウントすることが可能になります。
RAIDのアプリケーションによっては、全てのログが『情報』として出力されるようなので、注意が必要です。
|
else
strType(intEventCount) = "○"
end if
end if
strType(intEventCount) = strType(intEventCount) & objEvent.Type ' エラー,警告,情報
strTimeWritten(intEventCount) = WMIDateStringToDate(objEvent.TimeWritten) '発生日時
strEventCode(intEventCount) = objEvent.EventCode ' イベントコード
strSourceName(intEventCount) = objEvent.SourceName 'ソース
strMessage(intEventCount) = objEvent.Message ' 詳細
' 最後の改行を除く
if strMessage(intEventCount) & "" <> "" then
Do While right(strMessage(intEventCount),2) = vbCrLf
strMessage(intEventCount) = left(strMessage(intEventCount),len(strMessage(intEventCount))-2)
if strMessage(intEventCount) & "" = "" then
exit do
end if
Loop
end if
Next
' 並べ替え
intI = 1
Do While intI < intEventCount
intJ = intI + 1
Do While intJ <= intEventCount
if (strLogfile(intJ) < strLogfile(intI)) or _
(strLogfile(intJ) = strLogfile(intI) and intRecordNumber(intJ) < intRecordNumber(intI)) then
strLogfile(0) = strLogfile(intI)
strLogfile(intI) = strLogfile(intJ)
strLogfile(intJ) = strLogfile(0)
intRecordNumber(0) = intRecordNumber(intI)
intRecordNumber(intI) = intRecordNumber(intJ)
intRecordNumber(intJ) = intRecordNumber(0)
strType(0) = strType(intI)
strType(intI) = strType(intJ)
strType(intJ) = strType(0)
strTimeWritten(0) = strTimeWritten(intI)
strTimeWritten(intI) = strTimeWritten(intJ)
strTimeWritten(intJ) = strTimeWritten(0)
strEventCode(0) = strEventCode(intI)
strEventCode(intI) = strEventCode(intJ)
strEventCode(intJ) = strEventCode(0)
strSourceName(0) = strSourceName(intI)
strSourceName(intI) = strSourceName(intJ)
strSourceName(intJ) = strSourceName(0)
strMessage(0) = strMessage(intI)
strMessage(intI) = strMessage(intJ)
strMessage(intJ) = strMessage(0)
end if
intJ = intJ + 1
Loop
intI = intI + 1
Loop
|
| ↑ | |
配列変数に取り込んだ内容を、「アプリケーション」,「システム」などの『種類』+『レコード番号』で並べ替えています。
|
intI = 1
Do While intI <= intEventCount
' メール本文を編集
if strTextBody <> "" then
strTextBody = strTextBody & vbCrLf
end if
if strKeyLogfile <> strLogfile(intI) then
strTextBody = strTextBody & "■" & strLogfile(intI) ' ログの種類
strTextBody = strTextBody & vbCrLf & vbCrLf
strKeyLogfile = strLogfile(intI)
end if
strTextBody = strTextBody & strType(intI) ' エラー,警告,情報
|
| ↑ | |
イベントごとの先頭にstrType変数から『エラー』は『●』,『警告』は『▲』,『情報』は『○』のマークを付けています。
メールの本文を見るとき、『エラー』や『警告』を目立たせる目的です。
|
strTextBody = strTextBody & " " & strTimeWritten(intI) '発生日時
strTextBody = strTextBody & " (" & strEventCode(intI) & ")" ' イベントコード
strTextBody = strTextBody & strSourceName(intI) 'ソース
strTextBody = strTextBody & vbCrLf
strTextBody = strTextBody & strMessage(intI) ' 詳細
strTextBody = strTextBody & vbCrLf
intI = intI + 1
Loop
end if
' -----------
' WMIの解放
' -----------
Set objEvent = Nothing
Set colLoggedEvents = Nothing
Set objWMIService = Nothing
' ----------------------------------
' エラーの有無を判定して件名を編集
' ----------------------------------
if intErrorCount = 0 then
strSubject = strSubjectOK
else
strSubject = strSubjectNG
end if
strSubject = strSubject & " " & Mid(Year(Now),3) & Right("0" & Month(Now), 2) & Right("0" & Day(Now), 2)
strSubject = strSubject & " " & Right("0" & Hour(Now), 2) & Right("0" & Minute(Now), 2) & Right("0" & Second(Now), 2)
strSubject = strSubject & " " & intErrorCount & "/" & intEventCount & "件"
|
| ↑ | |
件名の後ろに、日付(年月日を示す6桁)と時刻(時分秒を示す6桁)を付けています。
さらにその後ろに、□/□件の形式で、『警告』以上のログ件数と収集したログの全件数を付けています。
|
' -------------------
' CDOでメールを送信
' -------------------
call sMail(strSubject ,strTextBody)
|
| ↑ | |
「CDO」は、「Microsoft Collaboration Data Objects」の略です。
このサンプルでは無条件でeメールを送信しています。
intErrorCount変数を判定すれば、異常が見つかった時だけ送ることも可能です。
|
Function WMIDateStringToDate(dtmEventDate)
' --------------------------------------
' WMIの日付をyyyy/mm/dd hh:nn:ssに変換
' --------------------------------------
WMIDateStringToDate = CDate(Mid(dtmEventDate, 5, 2) & "/" & Mid(dtmEventDate, 7, 2) & "/" & Left(dtmEventDate, 4) _
& " " & Mid(dtmEventDate, 9, 2) & ":" & Mid(dtmEventDate, 11, 2) & ":" & Mid(dtmEventDate, 13, 2))
End Function
|
| ↑ | |
「WMI」で参照される日付時刻は「WBEM」の書式になっているので、このサブルーチンで書式を変換しています。
|
Function sMail(strSubject ,strTextBody)
' --------------
' メールを送信
' --------------
dim oMsg
Set oMsg = CreateObject("CDO.Message")
oMsg.From = strMailFrom
oMsg.To = strMailTo
oMsg.Subject = strSubject
oMsg.TextBody = strTextBody
oMsg.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
oMsg.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSMTPServer
oMsg.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = intSMTPPort
oMsg.Configuration.Fields.Update
oMsg.Send
End Function
|
| ↑ | |
このサブルーチンで、eメールを送信しています。
他のページに載っていたコーディングの猿真似です。
「CDO」でeメールを送信する場合でも、SMTPサーバのユーザ認証に対応できるようです。
このサンプルは、SMTPサーバのユーザ認証に対応していません。
|
ソースのダウンロード
※ ダウンロードされるファイルは、LZH形式で圧縮されています。
●著作権および免責事項
私どもは、公開したソースコードに対する著作権を放棄します。
また、公開したソースコードの使用により損害が発生した場合でも、
その責めは一切負いませんことをご承知下さい。
ご意見、お問い合わせは →
ACCESSの使い方トップページ
|