«Внедрение SRP» или «А вдруг получится?» II

Промаявшись несколько дней с уменьшением объема логов аудита SRP передающихся по узким каналам, я понял что без фильтрации (хотя бы частичной) на пользовательских компьютерах не обойтись. Для удобства, исключения я решил цеплять прямо из реестра, т.к. пока исключения относятся только к путям запуска, и устанавливаются только разрешающие пути, большой проблемы это не составило. Для начала я добавил несколько исключений в политике SRP_Audit и зашел в реестр посмотреть, что же там хорошего изменилось. В ветке HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers я увидел два раздела «0» и «262144». В «0», закономерно, был пустой раздел «Paths», а в «262144» в таком же разделе «Paths» обнаружились подразделы с интересующими меня ключами «ItemData», в которых и содержались добавленные в политику разрешения. Однако, чтобы не прописывать пути к этим самым разделам каждый раз, и не париться на тот момент когда (или если) политика будет включена, первым делом я взял значение ключа «DefaultLevel», находящегося в корне раздела «HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers». Этот ключ, отвечает за включение/выключение политики путем изменения уровня разрешений, причем значение его указывает правила из какого подраздела «CodeIdentifiers» мы будем использовать. При помощи изменения этого ключа можно временно отключать и обратно включать SRP, разумеется, если есть права администратора. Как это сделать можно почитать здесь или здесь.

Итак сначала берем текущее значение «DefaulLevel» и с его помощью обращаемся уже к конкретной, используемой сейчас, ветке реестра. Далее выдергиваем наши исключения, и пока оставляем их в переменной:

$DLvl = (Get-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\Safer\CodeIdentifiers -Name DefaultLevel).DefaultLevel
$LvlPaths = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\' + $DLvl + '\Paths\*'

$ex = (Get-ChildItem -Path $LvlPaths | ForEach-Object {
$ItemDataPath = $_.Name
$ItemDataPath = $ItemDataPath.Replace("HKEY_LOCAL_MACHINE","HKLM:")
(Get-ItemProperty -Path $ItemDataPath -Name ItemData).ItemData
}) -join "|"
$ex = [regex]::escape($ex).replace("\\\|","\\|")

Теперь у нас есть список исключений, и логично было бы натравить почти готовый скрипт на папку с заранее усеченными при помощи SRP_LogRotation.ps1 логами, однако зачем делать лишнюю работу: SRP_LogRotation.ps1 все равно копается в логах, пожалуй стоит просто добавить ему функционала. Таким образом уже работающий скрипт был доведен до вот такого состояния:

$CurrentLogFileName = (Get-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\Safer\CodeIdentifiers -Name LogFileName).LogFileName
$LoggingDepth = (Get-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\Safer\CodeIdentifiers -Name LoggingDepth).LoggingDepth
$ServerLogFolder = (Get-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\Safer\CodeIdentifiers -Name ServerLogFolder).ServerLogFolder

if ($CurrentLogFileName -ne $null) {
$CurrentLogFolder = Split-Path -Path $CurrentLogFileName
$Yesterday = ((Get-Date).AddDays(-1)).ToString('yyyyMMdd')
$ComputerName = $env:ComputerName

if ($LoggingDepth -ne $null) {
$EventHorizon = (Get-Date).AddDays(-$LoggingDepth)
Get-ChildItem $CurrentLogFolder -filter ("SRP_"+ $ComputerName +"_*.log") | ?{$_.LastWriteTime -lt $EventHorizon} | del
}

$OldLogFileName = Join-Path $CurrentLogFolder "SRP_$ComputerName`_$Yesterday`.log"
$OldLogFileNamecut = Join-Path $CurrentLogFolder "SRP_$ComputerName`_$Yesterday`_cut.log"
if (!(Test-Path "$OldLogFileNamecut")) {
try {Copy-Item "$CurrentLogFileName" "$OldLogFileName"}
finally {Clear-Content "$CurrentLogFileName"}
}

$DLvl = (Get-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\Safer\CodeIdentifiers -Name DefaultLevel).DefaultLevel
$LvlPaths = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\' + $DLvl + '\Paths\*'

$ex = (Get-ChildItem -Path $LvlPaths | ForEach-Object {
$ItemDataPath = $_.Name
$ItemDataPath = $ItemDataPath.Replace("HKEY_LOCAL_MACHINE","HKLM:")
(Get-ItemProperty -Path $ItemDataPath -Name ItemData).ItemData
}) -join "|"
$ex = [regex]::escape($ex).replace("\\\|","\\|")
Get-ChildItem -Path $CurrentLogFolder -exclude *cut.log,SRP.log | ForEach-Object {
$nname = $_.DirectoryName + '\' + $_.BaseName + '_Cut' + $_.Extension
Get-Content $_.FullName | Where {$_ -notmatch $ex} >> $nname
$_.FullName
Remove-Item $_.FullName}

if (Test-Path $ServerLogFolder) {
$DestinationFolder = Join-Path $ServerLogFolder $ComputerName
if (!(Test-Path $DestinationFolder)) {New-Item $DestinationFolder -type Directory}
Get-ChildItem $CurrentLogFolder -filter ("SRP_"+ $ComputerName +"_*_cut.log") | ForEach-Object {if (!(Test-Path ($DestinationFolder +"\"+ $_.BaseName +"_cut.*"))) {Copy-Item $_.FullName $DestinationFolder}}
if ($LoggingDepth -ne $null) {Get-ChildItem $DestinationFolder -filter ("SRP_"+ $ComputerName +"_*.bak") | ?{$_.LastWriteTime -lt $EventHorizon} | del }
}
}

Теперь папки с логами успевшие разрастись до внушительных размеров, изрядно уменьшились на компьютерах пользователей (на сервере старые «большие» логи были удалены вручную). Для примера, папка логов одного из компьютеров весившая около 200MB уменьшилась до 1,5 MB. Возможно, для кого-то покажется минусом то, что полные логи удаляются, если так и есть, никто не мешает изменить одну строку в скрипте, для того чтобы полные логи переносились в отдельное место и хранились там хоть сколько угодно.
Пока усовершенствованный SRP_LogRotation.ps1 работает только на нескольких компьютерах, по результатам его работы в тестовый период, возможно, он будет распространен шире, логов станет еще больше и придется придумывать что-то еще.