【ツールの概要】
・タスクスケジューラ上に特定のWindows イベントログをトリガーとしたタスクを作る。
・Powershell で、フィルターされた直近数分間のイベントログのデータをメールで送る。
【環境(使っている環境)】
・Windows Server2016(+ Windows10)
・Powershell ver5.1
【ソース(AlertLoginError.ps1、メイン処理)】
using module .\class \Class_CommonFunction.psm1
using module .\class \Class_GetEvents.psm1
using module .\class \Class_Sendmail.psm1
$DocRoot = Split-Path (Split-Path $MyInvocation .MyCommand.Path -Parent) -Parent
$YMD = Get-Date -Format "yyyyMMdd"
$yMdHms = Get-Date -Format "yyyyMMddHHmmss"
$mailcfgpath = $DocRoot + '\etc\mailcfg.xml'
$CF = [CommonFunction] ::new()
$CF .logfile = $DocRoot + '\log\AlertLoginError_' + $YMD + '.log' ;
$CF .logwrite("INF" , "AlertLoginError process start." )
$GE = [GetEventLog] ::new()
$str = $GE .GetEvents()
if ($str .Length -ne 0 ) {
$SM = [SendMail] ::new()
$SM .ConfigMailProperty($str , $mailcfgpath , $logfile )
$CF .logwrite("INF" , "Alert mail sended." )
}
$CF .logwrite("INF" , "AlertLoginError process Finished." )
【ソース(class\Class_GetEvents.psm1、イベントログ抽出処理)】
class GetEventLog {
[string] GetEvents() {
$MESSAGES = Get-WinEvent `
-logname security `
-FilterXPath `
"Event [ `
System [ `
Provider [@Name='Microsoft-Windows-Security-Auditing'] `
and ( `
EventID='4625'
) `
and ( `
TimeCreated[timediff(@SystemTime) <= 300000] `
) `
] `
]"
$str = $MESSAGES | ForEach -Object {
if ( $_ .id -eq "4625" ) {
$_ | Select-Object `
@{Name = "TimeCreated" ; Expression = { $_ .TimeCreated.ToString("yyyy-M-d HH:mm:ss" ) } }, `
Id, `
@{Name = "TargetLogonId" ; Expression = { $_ .properties[5] .value } }, `
@{Name = "TargetDomainName" ; Expression = { $_ .properties[6] .value } }, `
@{Name = "TargetUserSid" ; Expression = { $_ .properties[4] .value } }, `
@{Name = "IpAddress" ; Expression = { $_ .properties[19] .value } }, `
@{Name = "Message" ; Expression = { $_ .Message.Substring(0 , 18 ) } }
}
} | ConvertTo-Json
return $str
}
}
【ソース(class\Class_Sendmail .psm1、メール送信処理)】
class SendMail{
[string] ConfigMailProperty($str , $mailcfgpath , $logfile ) {
$Body = "Windows events LoginError catched. `r`n`r`n EventData : `r`n`r`n " + $str
$Result = $this .SendmailbyPS($Body , $mailcfgpath , $logfile )
return $Result
}
[string] SendmailbyPS($Body , $mailcfgpath , $logfile ) {
$Mailconf_info = [xml] (Get-Content $mailcfgpath )
foreach ($data in $Mailconf_info .config.data ) { }
foreach ($data2 in $Mailconf_info .config.data ) { }
$MailSv = $data .MailSv
$Port = $data .Port
$Encode = $data .Encode
$uid = $data .uid
$pwd = $data .pwd
$From = $data .from
$To = $data .To
$Cc = $data .Cc
$Subject = $data .Subject
$pwd = $pwd | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential $uid , $pwd
try {
Send-MailMessage `
-To $To `
-Cc $Cc `
-From $From `
-SmtpServer $MailSv `
-Credential $cred `
-UseSsl `
-Encoding $Encode `
-Port $Port `
-Subject $Subject `
-Body $Body
$result = 'OK'
}
catch {
$ErrorMessage = $_ .Exception_Message
$result = $ErrorMessage + $LASTEXITCODE
Write-Output $LASTEXITCODE | Out-File -Append $logfile -encoding Default
}
if ($result -ne 'OK' ) {
$MailSv = $data2 .MailSv
$Port = $data2 .Port
$Encode = $data2 .Encode
$uid = $data2 .uid
$pwd = $data2 .pwd
$From = $data .from
$pwd = $pwd | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential $uid , $pwd
try {
Send-MailMessage `
-To $To `
-Cc $Cc `
-From $From `
-SmtpServer $MailSv `
-Credential $cred `
-UseSsl `
-Encoding $Encode `
-Port $Port `
-Subject $Subject `
-Body $Body
$result = 'OK'
}
catch {
$ErrorMessage = $_ .Exception_Message
$result = $ErrorMessage + $LASTEXITCODE
Write-Output $LASTEXITCODE | Out-File -Append $logfile -encoding Default
}
}
return $result
}
}
イベントログトリガ設定
【説明】
・タスクスケジューラでイベントIDで発火するように、上記のようなトリガ設定でPowershell スクリプト を実行します。
・Powershell スクリプト ではイベントログをFilterXPathでフィルターし、ConvertTo-Json でイベントログオブジェクトを文字列にしてメールします。
・イベントログの仕様上、一回のログイン失敗に見えても、数回 ID4625のイベントログが記録されることがあります。
【総評】
Classで分けることである程度わかりやすいスクリプト が書けるようになっていると思います。
FilertXPathやForEach-Objectのところで条件を変えれば、いろんな要件も満たせそうですね。
まあでも、業務用途の場合ちゃんとした商用監査ソフトを使うのが一番でしょうね・・・
【参考文献】
Get-wineventで抽出したログから、IDによって参照するフィールドを分けて表示させる方法