简体   繁体   English

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

[英]System.IO.FileSystemWatcher only notifies once on edited files

The script uses file system watcher to monitor a honeypot folder, and report back any changes (edit, rename, delete or create), then performs some actions. 该脚本使用文件系统观察程序监视蜜罐文件夹,并报告任何更改(编辑,重命名,删除或创建),然后执行某些操作。

The actions work fine when creating, renaming and deleting. 创建,重命名和删除时,操作可以正常工作。

But when editing, I can only make the script trigger the actions once. 但是在编辑时,我只能让脚本触发一次动作。 So for example, if a test device tries to edit a file on honeypot folder, the actions are triggered. 因此,例如,如果测试设备尝试编辑honeypot文件夹上的文件,则会触发操作。 But is the same device tries to edit again the same file or a different file, the watcher for editing seems to not work because the actions are not triggered. 但是同一设备尝试再次编辑同一个文件或不同的文件,编辑的观察者似乎无法工作,因为没有触发操作。

So I tried to reset the script every 5 minutes via task scheduler (start the script every 5 minutes), but still same results. 所以我尝试通过任务调度程序每5分钟重置一次脚本(每5分钟启动一次脚本),但结果仍然相同。

Here's the code: 这是代码:

### 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}

I'm pretty new to powershell so I don't understand while the watchers for the rest of events work and only editing does not work. 我对powershell很新,所以我不明白,其余事件的观察者工作,只有编辑不起作用。

Your core logic is sound. 你的核心逻辑是合理的。

If you simplify your action block to only do the Write-host part, it should always work. 如果将操作块简化为仅执行Write-host部分,则应始终有效。 I believe your problem is that on the second call, you get a terminating error that you didn't catch and in return, it stop the events from triggering. 我相信你的问题是,在第二次调用时,你得到一个你没有捕获的终止错误,作为回报,它会阻止事件触发。

Try replacing your action scriptblock with the following 尝试使用以下内容替换您的操作脚本块

$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.'
  }
}

This should correct your issue of the changed event triggering only once. 这应该可以解决仅触发一次的已更改事件的问题。

Here's an example using 3 watchers that check for a file change over the same directory. 这是一个使用3个观察者的例子,它检查同一目录下的文件更改。 You will notice that after the counter reached 5, only 2 of the 3 watchers continue to work properly. 您会注意到,在计数器达到5后,3名观察者中只有2名继续正常工作。 The one that do not produce any errors watcherNoError and the one that produce a terminating error but was caught in a Try catch watcherErrorsTryCatch . 没有产生任何错误的watcherNoError和一个产生终止错误但是在Try catch watcherErrorsTryCatch捕获的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输出

Additional note: Even if it was not the solution to your problem, you should still put a try / catch in that Action scriptblock as a terminating error will stop further processing on the next changes. 附加说明:即使它不是您的问题的解决方案,您仍应该在该Action脚本块中放置一个try / catch,因为终止错误将停止对下一个更改的进一步处理。

Either you'll need to use 要么你需要使用

Remove-Event $watcher "Changed"

at the end of the $Action scriptblock OR use 在$ Action脚本块的末尾或者使用

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

at the end of the $Action scriptblock. 在$ Action脚本块的末尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM