System.IO.FileSystemWatcher仅在编辑的文件上通知一次

时间:2018-07-07 13:56:41

标签: powershell file-watcher

该脚本使用文件系统监视程序来监视蜜罐文件夹,并报告所有更改(编辑,重命名,删除或创建),然后执行一些操作。

在创建,重命名和删除操作时工作正常。

但是在编辑时,我只能使脚本触发一次动作。因此,例如,如果测试设备尝试编辑honeypot文件夹上的文件,则会触发操作。但是,如果同一台设备尝试再次编辑同一文件或其他文件,则由于未触发操作,因此用于编辑的观察程序似乎无法正常工作。

因此,我尝试通过任务计划程序每5分钟重置一次脚本(每5分钟启动一次脚本),但结果仍然相同。

代码如下:

### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "\\vmserver2\_Do_Not_Delete_Or_Rename"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true

### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = {
    $path = $Event.SourceEventArgs.FullPath
    $changeType = $Event.SourceEventArgs.ChangeType

    $logline = "$(Get-Date), $changeType, $path"
    #Add-content "D:\log.txt" -value $logline
    #write-host $logline

    $targetdevice = Get-SmbOpenFile |
        select clientusername, clientcomputername, path |
        where {$_.Path -like  'E:\Data\Archive\_Do_Not_Delete_Or_Rename' }

    $targetIP = $targetdevice.clientcomputername
    $targetUser = $targetdevice.clientusername

    Send-ToEmail -email "edu.bit.es@gmail.com" $targetIP
    $targetUser
}

### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher "Created" -Action $action
Register-ObjectEvent $watcher "Changed" -Action $action
Register-ObjectEvent $watcher "Deleted" -Action $action
Register-ObjectEvent $watcher "Renamed" -Action $action
while ($true) {sleep 5}

我对Powershell还是很陌生,所以我不了解其余事件的观察者是否正常工作,而只能进行编辑。

2 个答案:

答案 0 :(得分:4)

您的核心逻辑是正确的。

如果将操作块简化为仅执行写主机部分,则它应始终有效。 我相信您的问题是,在第二次通话中,您遇到了一个未捕获的终止错误,作为回报,它阻止了事件的触发。

尝试用以下内容替换您的动作脚本块

$action = {
  try {
    $path = $Event.SourceEventArgs.FullPath
    $changeType = $Event.SourceEventArgs.ChangeType

    $logline = "$(Get-Date), $changeType, $path"
    #Add-content "D:\log.txt" -value $logline
    #write-host $logline

    $targetdevice = Get-SmbOpenFile |
        select clientusername, clientcomputername, path |
        where {$_.Path -like  'E:\Data\Archive\_Do_Not_Delete_Or_Rename' }

    $targetIP = $targetdevice.clientcomputername
    $targetUser = $targetdevice.clientusername

    Send-ToEmail -email "edu.bit.es@gmail.com" $targetIP
    $targetUser
  }
  catch {
      Write-Host 'an error was thrown :(... Fortunately, it was caught.'
  }
}

这应该解决更改事件仅触发一次的问题。

这是一个使用3个观察程序检查同一目录中文件更改的示例。 您会注意到,计数器达到5后,只有3个观察者中有2个继续正常工作。一个不产生任何错误的watcherNoError,另一个不产生终止错误的错误,但被Try Try watcherErrorsTryCatch捕获。

### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$PathToWatch = "\\127.0.0.1\c$\_"

$watcherNoError = New-Object System.IO.FileSystemWatcher -Property @{Path = $PathToWatch;Filter = '*.*';IncludeSubdirectories=$true;EnableRaisingEvents = $true}
$watcherWithErrors = New-Object System.IO.FileSystemWatcher -Property @{Path = $PathToWatch;Filter = '*.*';IncludeSubdirectories=$true;EnableRaisingEvents = $true}
$watcherErrorsTryCatch = New-Object System.IO.FileSystemWatcher -Property @{Path = $PathToWatch;Filter = '*.*';IncludeSubdirectories=$true;EnableRaisingEvents = $true}

$Global:Counter = @{
    watcherNoError = 0 
    watcherWithErrors = 0 
    watcherErrorsTryCatch = 0
}
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = {

    $path = $Event.SourceEventArgs.FullPath
    $changeType = $Event.SourceEventArgs.ChangeType



    Switch ($Event.MessageData.Name) {
        "NoErrors" {
            $Global:Counter.watcherNoError +=1
            $count = $Global:Counter.watcherNoError
        }
        "WithErrors" {
            $Global:Counter.watcherWithErrors +=1
            $count = $Global:Counter.watcherWithErrors
            if ($count -eq 5) {
                Write-Host 'A terminated errow will be thrown...' -ForegroundColor DarkMagenta
                Throw 'oh no !'
            }

        }
         "WithErrorsTryCatch"  {
            $Global:Counter.watcherErrorsTryCatch +=1
            $count = $Global:Counter.watcherErrorsTryCatch
            if ($count -eq 5) {
                try {
                    Throw 'oh no !'
                }
                catch {
                    Write-Host 'error was caught... You are safe ;)' -ForegroundColor Green
                }
            }

        }
    }

    $logline = "Count: $Count - $($event.MessageData.Name): $changeType, $path" 
    write-host $logline -ForegroundColor $Event.MessageData.ForegroundColor


} 

### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcherNoError "Changed" -Action $action -MessageData @{Name='NoErrors';ForegroundColor='Yellow'}
Register-ObjectEvent $watcherWithErrors "Changed" -Action $action -MessageData @{Name='WithErrors';ForegroundColor='DarkMagenta'}
Register-ObjectEvent $watcherErrorsTryCatch "Changed" -Action $action -MessageData @{Name='WithErrorsTryCatch';ForegroundColor='Green'}

while ($true) {sleep 5}




$action = {
  try {
    $path = $Event.SourceEventArgs.FullPath
    $changeType = $Event.SourceEventArgs.ChangeType

    $logline = "$(Get-Date), $changeType, $path"
    #Add-content "D:\log.txt" -value $logline
    #write-host $logline

    $targetdevice = Get-SmbOpenFile |
        select clientusername, clientcomputername, path |
        where {$_.Path -like  'E:\Data\Archive\_Do_Not_Delete_Or_Rename' }

    $targetIP = $targetdevice.clientcomputername
    $targetUser = $targetdevice.clientusername

    Send-ToEmail -email "edu.bit.es@gmail.com" $targetIP
    $targetUser
  }
  catch {
      Write-Host 'an error was thrown :(... Fortunately, it was caught.'
  }
}

VSCode output of previous sample

附加说明: 即使不是解决问题的方法,也应在该Action脚本块中进行try / catch,因为终止错误将停止对下一个更改的进一步处理。

答案 1 :(得分:3)

您将需要使用

Remove-Event $watcher "Changed"
$ Action脚本块末尾的

要么 使用

Unregister-Event $watcher "Changed"
Register-ObjectEvent $watcher "Changed -Action $action

在$ Action脚本块的末尾。