/
antowka
/
WinFileWatcher
Обзор
Документация
Войти
/
antowka
/
WinFileWatcher
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
fileWatcher.ps1
150 строк
6 KB
NikanorovAN
Initial commit: PowerShell FileSystemWatcher with UTF-8 logging
16 июл 2026, 19:21
16 июл 2026, 19:21
3f028a3
Код
Авторство
О чём код?
param ( [Parameter(Mandatory = $true, Position = 0, HelpMessage = "Укажите путь к отслеживаемой папке")] [ValidateScript({ Test-Path $_ -PathType Container })] [string]$Path, [Parameter(Mandatory = $false, HelpMessage = "Путь к лог-файлу (UTF-8). По умолчанию — в текущей папке")] [string]$LogFile = (Join-Path (Get-Location) ("fileWatcher_" + (Get-Date -Format 'yyyyMMdd_HHmmss') + ".log")), [Parameter(Mandatory = $false, HelpMessage = "Фильтр файлов, например *.txt или *.log")] [string]$Filter = "*.*", [Parameter(Mandatory = $false, HelpMessage = "Окно дедупликации события 'Изменён' в миллисекундах")] [int]$ChangedDebounceMs = 500, [Parameter(Mandatory = $false, HelpMessage = "Интервал heartbeat в секундах (0 = отключить)")] [int]$HeartbeatSeconds = 30, [Parameter(Mandatory = $false, HelpMessage = "Размер внутреннего буфера FileSystemWatcher в байтах (кратно 4096)")] [int]$BufferSize = 65536 ) try { $OutputEncoding = [System.Text.Encoding]::UTF8 } catch {} try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {} try { [Console]::InputEncoding = [System.Text.Encoding]::UTF8 } catch {} $FullPath = (Resolve-Path $Path).Path $ChangedThreshold = [TimeSpan]::FromMilliseconds($ChangedDebounceMs) $SourceIds = @("FSE_Created", "FSE_Changed", "FSE_Deleted", "FSE_Renamed") $LastChanged = @{} $LogStream = $null function Write-LogLine { param( [Parameter(Mandatory = $true)][string]$Text, [ConsoleColor]$Color = [ConsoleColor]::Gray ) $stamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $line = "[$stamp] $Text" Write-Host $line -ForegroundColor $Color if ($null -ne $Script:LogStream) { $Script:LogStream.WriteLine($line) } } try { $LogStream = [System.IO.StreamWriter]::new($LogFile, $true, [System.Text.Encoding]::UTF8) $LogStream.AutoFlush = $true Write-LogLine "Запуск мониторинга папки: $FullPath" Cyan Write-LogLine "Подпапки: да | Фильтр: $Filter | Дедупликация Changed: ${ChangedDebounceMs} мс | Buffer: $BufferSize байт" Cyan Write-LogLine "Лог-файл: $LogFile" Cyan Write-LogLine "Для выхода нажмите [Ctrl + C]" Yellow Write-LogLine "--------------------------------------------------" Gray $Watcher = New-Object System.IO.FileSystemWatcher $Watcher.Path = $FullPath $Watcher.Filter = $Filter $Watcher.IncludeSubdirectories = $true $Watcher.InternalBufferSize = $BufferSize $Watcher.EnableRaisingEvents = $false Register-ObjectEvent $Watcher "Created" -SourceIdentifier "FSE_Created" | Out-Null Register-ObjectEvent $Watcher "Changed" -SourceIdentifier "FSE_Changed" | Out-Null Register-ObjectEvent $Watcher "Deleted" -SourceIdentifier "FSE_Deleted" | Out-Null Register-ObjectEvent $Watcher "Renamed" -SourceIdentifier "FSE_Renamed" | Out-Null Register-ObjectEvent $Watcher "Error" -SourceIdentifier "FSE_Error" | Out-Null Write-LogLine "Watcher инициализирован. Path='$($Watcher.Path)' Filter='$($Watcher.Filter)' InternalBufferSize=$($Watcher.InternalBufferSize)" Gray Write-LogLine "Подписчики зарегистрированы: $($SourceIds -join ', '), FSE_Error" Gray $Watcher.EnableRaisingEvents = $true Write-LogLine "EnableRaisingEvents = true. Мониторинг активен." Green $LastHeartbeat = Get-Date while ($true) { $hadAnyEvent = $false foreach ($sid in $SourceIds) { $Event = Wait-Event -SourceIdentifier $sid -Timeout 1 -ErrorAction SilentlyContinue if ($null -eq $Event) { continue } $hadAnyEvent = $true $args = $Event.SourceEventArgs switch ($sid) { "FSE_Created" { Write-LogLine "Создан: $($args.FullPath)" Green } "FSE_Changed" { $fp = $args.FullPath $now = Get-Date $prev = $LastChanged[$fp] if ($null -ne $prev -and ($now - $prev) -lt $ChangedThreshold) { $LastChanged[$fp] = $now } else { $LastChanged[$fp] = $now Write-LogLine "Изменён: $fp" DarkYellow } } "FSE_Deleted" { Write-LogLine "Удалён: $($args.FullPath)" Red } "FSE_Renamed" { Write-LogLine "Переименован: $($args.OldFullPath) -> $($args.FullPath)" Cyan } } Remove-Event -SourceIdentifier $sid -ErrorAction SilentlyContinue } $errEvent = Wait-Event -SourceIdentifier "FSE_Error" -Timeout 0 -ErrorAction SilentlyContinue if ($null -ne $errEvent) { Write-LogLine "ОШИБКА WATCHER (возможно переполнение буфера): $($errEvent.SourceEventArgs)" Red Remove-Event -SourceIdentifier "FSE_Error" -ErrorAction SilentlyContinue } if (-not $hadAnyEvent -and $HeartbeatSeconds -gt 0) { $since = (Get-Date) - $LastHeartbeat if ($since.TotalSeconds -ge $HeartbeatSeconds) { Write-LogLine "Heartbeat: цикл работает, событий нет." DarkGray $LastHeartbeat = Get-Date } else { Start-Sleep -Milliseconds 200 } } } } catch [System.Management.Automation.PipelineStoppedException] { Write-Host "`nОстановка мониторинга..." -ForegroundColor Yellow } finally { if ($null -ne $Watcher) { $Watcher.EnableRaisingEvents = $false $Watcher.Dispose() } foreach ($sid in ($SourceIds + "FSE_Error")) { if (Get-EventSubscriber -SourceIdentifier $sid -ErrorAction SilentlyContinue) { Unregister-Event -SourceIdentifier $sid -ErrorAction SilentlyContinue } Remove-Event -SourceIdentifier $sid -ErrorAction SilentlyContinue } if ($null -ne $LogStream) { $LogStream.Flush() $LogStream.Dispose() $LogStream = $null } Write-Host "Мониторинг завершён. Ресурсы освобождены. Лог: $LogFile" -ForegroundColor Gray }