Search code examples
powershellfilesystemwatcher

Pause FileSystemWatcher during action


I have this PowerShell Script that monitors if a file has been saved inside a folder, and then does a call to a relay to control traffic lights. When a new image is found, the traffic light goes to red, waits 60 seconds and then goes back to green.

As is to be expected - when during those 60 seconds a new file is added to this folder, it goes into the queue - so when the lights go back to green, they switch back to red for 60 seconds.

What is the cleanest way to stop the filesystemwatcher when a file is created, and restart it? Stopping the FileSystemWatcher is no problem, when I dispose of the $FileSystemWatcher - but restarting it doesn't work. Also I would like to be the code as least redundant if possible, without copying all the FSW code inside my Action (if possible)

Write-Host "Auto Relay Change On Detection"
Add-Type -AssemblyName PresentationCore,PresentationFramework
$settingsFile = "$PSScriptRoot\settings.json"
$j = Get-Content -Raw -Path $settingsFile | ConvertFrom-Json
$PathToMonitor = $j.imageFolder

If(!(test-path $PathToMonitor))
{
      New-Item -ItemType Directory -Force -Path $PathToMonitor
}

$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path  = $PathToMonitor
$FileSystemWatcher.IncludeSubdirectories = $true

# make sure the watcher emits events
$FileSystemWatcher.EnableRaisingEvents = $true

# define the code that should execute when a file change is detected
$Action = {
    $details = $event.SourceEventArgs
    $Name = $details.Name
    $FullPath = $details.FullPath
    $OldFullPath = $details.OldFullPath
    $OldName = $details.OldName
    $ChangeType = $details.ChangeType
    $Timestamp = $event.TimeGenerated
    $text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp

    # you can also execute code based on change type here
    switch ($ChangeType)
    {
        'Changed' { "CHANGE" }
        'Created' { "CREATED"
            $text = "File {0} was created." -f $Name
            Write-Host $text -ForegroundColor Yellow  
            Write-Host  "Relay = detected at $(Get-Date)" -ForegroundColor Yellow 
            #DO API CALL
            $timeout = $j.timer
            Start-Sleep -s $timeout
            #DO API CALL
            Write-Host  "Relay = default at $(Get-Date)" -ForegroundColor Yellow 
        }
        'Deleted' { "DELETED" }
        'Renamed' { "RENAMED" }
        default { Write-Host $_ -ForegroundColor Red -BackgroundColor White }
    }
}

# add event handlers
$handlers = . {
    Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action $Action -SourceIdentifier FSCreate
}

try
{
    do
    {
        Wait-Event -Timeout 1
        ##Write-Host "." -NoNewline
        
    } while ($true)
}
finally
{
    Unregister-Event -SourceIdentifier FSCreate
    $handlers | Remove-Job
    $FileSystemWatcher.EnableRaisingEvents = $false
    $FileSystemWatcher.Dispose()
    "Event Handler disabled."
}

Solution

  • $Action = {
        try {
            $FileSystemWatcher.EnableRaisingEvents = $false
            $details = $event.SourceEventArgs
            $Name = $details.Name
            $FullPath = $details.FullPath
            $OldFullPath = $details.OldFullPath
            $OldName = $details.OldName
            $ChangeType = $details.ChangeType
            $Timestamp = $event.TimeGenerated
            $text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp
    
            # you can also execute code based on change type here
            switch ($ChangeType)
            {
                'Changed' { "CHANGE" }
                'Created' { "CREATED"
                    $text = "File {0} was created." -f $Name
                    Write-Host $text -ForegroundColor Yellow  
                    Write-Host  "Relay = detected at $(Get-Date)" -ForegroundColor Yellow 
                    #DO API CALL
                    $timeout = $j.timer
                    Start-Sleep -s $timeout
                    #DO API CALL
                    Write-Host  "Relay = default at $(Get-Date)" -ForegroundColor Yellow 
                }
                'Deleted' { "DELETED" }
                'Renamed' { "RENAMED" }
                default { Write-Host $_ -ForegroundColor Red -BackgroundColor White }
            }
        } finally {
            $FileSystemWatcher.EnableRaisingEvents = $true
        }
    }