<# Garry Geller http://www.cyberforum.ru/powershell/thread1561433.html#post10781770 mod by YuS (скорректирована реакция кода на появление двойных и более событий по одному и тому же файлу) 29.05.2019 Набор функций-командлетов для наблюдения за изменениями файлов\директорий на основе класса FileSystemWatcher. Для удобства использования можно поместить их в файл powershell профиля - тогда они будут доступны наравне с прочими командами сразу из консоли, либо поместить файл модуля watchdog.ps1 в папку powershell модулей. #> # required -version 3.0 set-alias swatch Set-Watch function Set-Watch() { <# .SYNOPSIS Запускает фоновый процесс отслеживания изменений файловой системы на основе класса FileSystemWatcher .DESCRIPTION Существующие фильтры отслеживаемых изменений: NotifyFilters.CreationTime NotifyFilters.LastAccess NotifyFilters.LastWrite NotifyFilters.FileName NotifyFilters.DirectoryName NotifyFilters.Security NotifyFilters.Size NotifyFilters.Attributes .EXAMPLE PS C:\> . .\watchdog.ps1 PS C:\> swatch -path "d:\test" -filter "*.txt" -event Created,Deleted .EXAMPLE PS C:\> swatch -path "d:\test" -filter "*.txt" -event Created,Deleted -command "start-process notepad.exe" -test .LINK https://msdn.microsoft.com/ru-ru/library/system.io.filesystemwatcher(v=vs.110).aspx .LINK Remove-Watch .LINK Disable-Watch .LINK Enable-Watch .LINK Get-Watch #> [CmdletBinding()] param( # путь до отслеживаемой директории [parameter(Mandatory=$true,Position=1)] [alias("p")][string]$path, [parameter(Mandatory=$true,Position=2)] # фильтр типов отслеживаемых файлов [alias("f")][string]$filter="*.*", # задает тип отслеживаемых изменений [alias("n")][string]$notify='FileName, LastWrite', # нужно ли рекурсивно отслеживать субдиректории [alias("r")][switch]$recurse, # событи(e|я) на котор(ое|ые) нужно реагировать [parameter(Mandatory=$true,Position=3)] [ValidateSet("Created","Deleted","Renamed","Changed")] [alias("e")][string[]]$events, [parameter(Mandatory=$false)] # строковые идентифкаторы событий [alias("name")][string[]]$id=@(), # действие которое нужно выполнить - передается одной строкой вместе с аругментами [string]$command, # вывод переданных аргументов [switch]$test ) $fsw = New-Object IO.FileSystemWatcher -Property @{ Path = $path Filter = $filter IncludeSubdirectories = $recurse NotifyFilter = [IO.NotifyFilters]$notify } Set-Variable __watcher -Value $fsw -Scope Script Set-Variable command -Value $command -Scope Script $action = { $fullPath = $event.SourceEventArgs.FullPath $fileName = $event.SourceEventArgs.Name $changeType = $event.SourceEventArgs.ChangeType $timeStamp = $event.TimeGenerated if (!$tmptime){$tmptime = $timeStamp} $dif = ((get-date($timeStamp)) - (get-date($tmptime))).totalseconds #write-host $dif -for red if ($dif -gt 1.0 -or $changeType -ne $tmpType -or $fileName -ne $tmpName){ #$command = Get-Variable command -valueOnly -Scope Global Write-Host $('The file "{1}" was {2} at {0:dd.MM.yyyy HH:mm:ss,ffff}' -f $timeStamp,$fileName,$changeType) -for green if ($command) { Invoke-Expression $command } $tmptime,$tmpType,$tmpName = $timeStamp,$changeType,$fileName } } $calls = [Collections.ArrayList]::new() for ($i=0; $i -lt $events.length; $i++) { if ($id.Length -eq $events.Length){ $jobname = $id[$i] } else { $jobname = $events[$i] } $params = @{SourceIdentifier = $jobname; Action = $action} if ((get-job).Name -ccontains $jobname) { Write-Host "Задание $jobname уже существует" -f Red } else { $regEvent = Register-ObjectEvent $fsw $events[$i] @params $calls.Add($regEvent)|Out-Null } } # выводим аргументы функции if ($test) { $MyInvocation.BoundParameters.GetEnumerator() | Foreach { echo "-$($_.Key): $($_.Value)" } $MyInvocation.UnboundArguments '----------------------------' } return $calls } set-alias unwatch Disable-Watch function Disable-Watch() { <# .SYNOPSIS Временно отключает обработку событий .LINK Enable-Watch .LINK Remove-Watch .LINK Get-Watch .LINK Set-Watch #> if ($__watcher) { $__watcher.EnableRaisingEvents = $false Write-Host "Отслеживание событий отключено" -f Yellow -b DarkGray } } set-alias watch Enable-Watch function Enable-Watch() { <# .SYNOPSIS Включает обработку событий .LINK Disable-Watch .LINK Remove-Watch .LINK Get-Watch .LINK Set-Watch #> if ($__watcher) { $__watcher.EnableRaisingEvents = $true Write-Host "Отслеживание событий включено" -f Green -b DarkGray } } set-alias gwatch Get-Watch function Get-Watch() { <# .SYNOPSIS Получает сторожевой объект для установки новых свойств (если указаны) и возвращает его .EXAMPLE PS C:\> (gwatch).filter = "*.*" # установить новый файловый фильтр PS C:\> gwatch -Filter *.* .EXAMPLE PS C:\> (gwatch).path= "c:\windows" # установить новую директорию для отслеживания PS C:\> gwatch -Path "c:\windows" .EXAMPLE PS C:\> gwatch -NotifyFilter "Filename,LastWrite,LastAccess" -Filter "*.*" .EXAMPLE PS C:\> gwatch -IncludeSubdirectories PS C:\> gwatch -IncludeSubdirectories:$false .OUTPUTS FileSystemWatcher .LINK Set-Watch .LINK Disable-Watch .LINK Remove-Watch .LINK Get-Watch #> param( [string]$Path, [string]$Filter, [switch][Boolean]$IncludeSubdirectories, [string]$NotifyFilter ) if ($__watcher -eq $null) { Write-Host "Объект FileSystemWatcher не определен" -f Red } else { $type_watcher = $__watcher.gettype() $MyInvocation.BoundParameters.GetEnumerator() | %{ $key = $_.Key $value = $_.Value if ($key -eq "NotifyFilter") { $value = [IO.NotifyFilters]$value } if ($key -eq "IncludeSubdirectories") { [Boolean]$value = $value } $prop = $type_watcher.GetProperty($key) $prop.SetValue($__watcher, $value) } return $__watcher } } set-alias rwatch Remove-Watch function Remove-Watch() { <# .SYNOPSIS Удаляет задание по списку имен, либо все .EXAMPLE PS C:\> rwatch Created,Deleted # удалить задания по именам .EXAMPLE PS C:\> rwatch # удалить все задания .LINK Set-Watch #> [CmdletBinding()] param( [string[]]$names ) if ($names.Length -eq 0) { $names = (get-job).Name } foreach ($jobname in $names) { if ((get-job).Name -ccontains $jobname) { Unregister-Event $jobname -Force Remove-Job -Name $jobname -Force Write-Host "Задание $jobname удалено" -f Green -b DarkGray } else { Write-Host "Задание $jobname не найдено" -f Yellow -b DarkMagenta } } Set-Variable __watcher -Value $null -Scope Script } |