午前0時に前日のファイルアクセスログをメールで自動送信する


本稿は【ファイルサーバのアクセスログをPowerShellで取得する】の続編。
今回はコードのみ。監査ログの設定方法については、先の記事を参照して欲しい。

次のPowerShellスクリプトをWindowsファイルサーバのタスクスケジューラに登録した。
午前0時になると、前日のファイルアクセスログをZIPファイルに固め、速やかにメールで転送する仕掛けだ。

audit_mail.ps1
$endTime = Get-Date -Hour 0 -Minute 0 -Second 0
$startTime = Get-Date $endTime.AddDays(-1)

$baseFile = Join-Path 'E:\log\audit_' $startTime.ToString('yyyyMMdd')
$csvFile = $baseFile + '.csv'
$zipFile = $baseFile + '.zip'
if (Test-Path $csvFile) { Remove-Item $csvFile }
Write-Host "$startTime - $endTime -> $csvFile"

echo '日時,アクセス,ユーザ名,ファイル/フォルダ名' | Out-File -Append -Encoding default -FilePath $csvFile
# イベントログの取得
$AccessMaskHash = @{ '0x1' = '読込'; '0x2' = '書込'; '0x4' = '追加'; '0x10000' = '削除'}
try {
    Get-WinEvent -FilterHashtable @{
        LogName = 'Security'
        ProviderName = 'Microsoft-Windows-Security-Auditing'
        ID = 4663
        StartTime = $startTime
        EndTime = $endTime
    } -Oldest -ErrorAction Stop | %{
        $xml = [XML]$_.ToXml()   # EventDataにアクセスするためにXML化

        $FileName = ($xml.Event.EventData.Data | ?{$_.Name -eq 'ObjectName'}).'#text'
        if (! $FileName.StartsWith('E:\SHARED\')) { return }
        $AccessMaskCode = ($xml.Event.EventData.Data | ?{$_.Name -eq 'AccessMask'}).'#text'
        $AccessMaskName = $AccessMaskHash[$AccessMaskCode]
        $TimeCreated = ([DateTime]$xml.Event.System.TimeCreated.SystemTime).ToString('yyyy/MM/dd HH:mm:ss.fff')
        $UserName = ($xml.Event.EventData.Data | ?{$_.Name -eq 'SubjectUserName'}).'#text'
        if ("$AccessMaskName,$UserName,$FileName" -eq $uniq) { return }
        $uniq = "$AccessMaskName,$UserName,$FileName"

        echo "$TimeCreated,$AccessMaskName,$UserName,$FileName"
    } | Out-File -Append -Encoding default -FilePath $csvFile
    # ZIPアーカイブ作成
    Compress-Archive -Force -Path $csvFile -DestinationPath $zipFile
    # メール送信
    $password = ConvertTo-SecureString 'PASSWORD' -AsPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential example@gmail.com, $password
    $subject = $startTime.ToString('【自動送信】yyyy年M月d日(ddd) 監査ログ送付')
    $body = @"
このメールはシステムから自動送信しています。
昨日のファイルアクセスログを送付します。
"@
    Send-MailMessage -From 'システム管理者 <[email protected]>' -To user@example.com `
               -SmtpServer smtp.gmail.com -Port 587 -UseSsl `
               -Credential $credential -Encoding UTF8 `
              -Attachments $zipFile `
                  -Subject $subject `
                     -Body $body
    if (Test-Path $zipFile) { Remove-Item $zipFile }
} catch [Exception] {
    Write-Host('エラー:' + $_.Exception)
}

他システムに転送することで、システム管理者による意図的もしくは無意識の改竄を防止するソリューションになる。
今回はZIPファイルをそのまま転送しているが、改竄防止目的なら、ZIPファイルのMD5ハッシュ値のみメールで知らせても良い。それだけでも抑止力になる。

なお、Gmailの場合、初回に次のような警告を出して異常終了するが、「はい」と回答すれば次回からは正常に送信される。

以上、お金を掛けずにできる実効性あるセキュリティ対策の一例として紹介した。簡単だが参考になれば幸いである。