2

I have a simple Powershell script derived from here which is supposed to exit when a certain condition becomes true (file deleted, modified, etc.)

The script:

$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Users\me\Desktop\folder\"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true  
$continue = $true

$action = { 
            Write-Host "Action..."
            $anexe = "C:\Users\me\Desktop\aprogram.exe"
            $params = "-d filename"
            Start $anexe $params
            $continue = $false
          }    

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 ($continue) {sleep 1}

As you can see, the script is supposed to exit when condition is met (an "action" is taken) since value of continue changes to false and the loop should then end and the script should exit. However, it keeps going. The loop is endless even when the condition is met.

I have also tried to use exit to exit out of the powershell script. Does not work either. I tried removing the sleep 1, however, then it ends up killing my cpu because of the infinite loop without any time gap.

How can I fix it to exit when the file change condition is met?

learnerX
  • 1,022
  • 1
  • 18
  • 44
  • 1
    Possible duplicate of [Powershell and System.IO.FileSystemWatcher](https://stackoverflow.com/questions/31795933/powershell-and-system-io-filesystemwatcher) – Theo Jun 28 '19 at 19:12
  • 1
    @Theo: The linked post is related, but not a duplicate, because _this_ issue is about using a variable inside the event handler to communicate information to the main script.. – mklement0 Jun 28 '19 at 23:22

1 Answers1

4

Your $action event-handler script block doesn't run in the same scope as your script[1], so your script never sees the $continue variable you set inside the script block.

As a workaround, you can:

  • initialize a global variable named $continue in your script: $global:continue = $true

  • then set that variable in your event-handler script block: $global:continue = $false

  • and check that global variable's value in your script's loop: while ($global:continue) {sleep 1}

  • be sure to remove your global variable before exiting the script, as it would otherwise linger in the session: Remove-Variable -Scope Global count.

    • Also, generally, as Theo soundly advises, be sure to properly dispose of the System.IO.FileSystemWatcher instance once you're done watching: $watcher.Dispose().

[1] It runs in the same session, but inside a dynamic module.

mklement0
  • 382,024
  • 64
  • 607
  • 775