В сценариях, когда вам нужно отслеживать изменения в определенной папке и выполнять какое-то автоматические действие при обнаружении изменений в файле/директории (отправить уведомление, логировать событие в текстовый файл или журнал событий, запускать скрипт обработки и т.д.) вместо использования классического аудита событий доступа к папкам в Windows, можно использовать встроенный .Net класс FileSystemWatcher. Этот класс позволяет в реальном времени отслеживать события создания, удаления, переименования и редактирования файлов (и папок). В статье мы рассмотрим, как следить за изменениями объектов файловой системы в определенной директории через FileSystemWatcher из PowerShell.
Создадим объект класса FileSystemWatcher:
$watcher = New-Object System.IO.FileSystemWatcher
Хотите ли вы отслеживать события во вложенных директориях:
$watcher.IncludeSubdirectories = $true
Указать целевую директорию, которой будете мониторить:
$watcher.Path = "C:\Configs"
Включить генерацию событий при обнаружении изменений:
$watcher.EnableRaisingEvents = $true
Настраиваем действие, которое нужно выполнить, если обнаружены изменения в отслеживаемой директории.
$action = {
$changeType = $Event.SourceEventArgs.ChangeType
$path = $Event.SourceEventArgs.FullPath
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | $changeType | $path" | Out-File -FilePath "C:\logs\watch.log" -Append
}
Осталось подписаться на определенные типы событий, которые вы хотите отслеживать. Всего доступно четыре типа событий Created, Changed, Deleted, Renamed. Я хочу отслеживать все эти типы событий, поэтому зарегистрирую все четыре подписки:
Register-ObjectEvent $watcher Created -Action $action -SourceIdentifier FSCreate
Register-ObjectEvent $watcher Changed -Action $action -SourceIdentifier FSChange
Register-ObjectEvent $watcher Deleted -Action $action -SourceIdentifier FSDelete
Register-ObjectEvent $watcher Renamed -Action $action -SourceIdentifier FSRename

Мониторинг изменений в директории будет работать до тех пор, пока жив родительский процесс powershell.exe. Ядро Windows само отслеживает изменения в файловой системе и отправляет уведомления в ваши подписки. Cкрипт запускается один раз, поэтому не нужно добавлять в него циклы опроса. Но при запуске кода через PS1 скрипт, можно добавить в конец бесконечный цикл:
while ($true) {sleep 5}
Если запустить такой скрипт, то при любых изменениях в отслеживаемой папке, информация о каждом событии будет записываться в указанный лог файл. В отдельной PowerShell консоли я настроил вывод содержимого лог файла на экран с обновлением в реальном времени:
Get-Content -Path "C:\logs\watch.log" -wait

Чтобы остановить мониторинг, выполните:
Unregister-Event -SourceIdentifier FSCreate
Unregister-Event -SourceIdentifier FSChange
Unregister-Event -SourceIdentifier FSDelete
Unregister-Event -SourceIdentifier FSRename
Если нужно отслеживать изменения только в определенных типах файлах, в начале скрипта можно определить фильтр:
$filter = "*.cfg"
$watcher.Filter = $filter
Чтобы FileSystemWatcher реагировал только на определенные события, можно использовать NotifyFilter. Например, я хочу реагировать только если изменены NTFS права доступа, размер или имя файла:
$watcher.NotifyFilter = [System.IO.NotifyFilters]::FileName -bor [System.IO.NotifyFilters]::Size -bor [System.IO.NotifyFilters]::Security
Если нужно для определенного события сделать отдельный обработчик (действие), его можно указать сразу при подписке через параметр Action. В этом примере я хочу при переименовании файла, записывать в лог старое и новое имя файла.
Register-ObjectEvent $watcher Renamed -SourceIdentifier FSRename -Action {
$details = $Event.SourceEventArgs
$timeStamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
$logMessage = "$timeStamp | Renamed | From: $($details.OldFullPath) To: $($details.FullPath)"
$logMessage | Out-File -FilePath "C:\logs\watch.log" -Append
}
При большом количестве событий (десятки/сотни в секунду), чтобы не терять события, можно увеличить размер внутреннего буфера до 64 кб:
$watcher.InternalBufferSize = 65536
или запускать каждой действие через отдельный фоновый процесс, добавив в Action вызов кода обработчика через
Start-Job
Итак, мы рассмотрели, как с помощью PowerShell реализовать простую систему отслеживания изменения, создания, удаления и переименования файлов в указанной папке и автоматической реакции на события.

