简体   繁体   中英

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. 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.

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.

Your core logic is sound.

If you simplify your action block to only do the Write-host part, it should always work. 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. You will notice that after the counter reached 5, only 2 of the 3 watchers continue to work properly. 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 .

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

Either you'll need to use

Remove-Event $watcher "Changed"

at the end of the $Action scriptblock OR use

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

at the end of the $Action scriptblock.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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