1

I am working on a Powershell Script to monitor a folder and when a new item is created the script needs to copy that file to another folder.

The issue I'm experiencing is that when I execute it in Powershell ISE it works perfectly but when executing it on Powershell it only works for the period of time that Powershell window is open (> 1 second).

I tried putting the sleep command at the end, and found that only when the script got ended the action is taken, in this case, when I press CTRL+C to stop the script in Powershell, the actions that should have been taken when I created the items are executed all together.

Don't know if I am doing something wrong or just misunderstanding something.

Here is the script i am using to test it:

$Watcher = New-Object System.IO.FileSystemWatcher
$Watcher.path = "\\192.168.5.127\data\TestWatcher"
$Destination = "C:\TestWatcher"
$Watcher | Get-Member -MemberType Event
$Watcher.EnableRaisingEvents = $true

$action = {
    $path = $event.SourceEventArgs.FullPath
    $name = $event.SourceEventArgs.Name
    $changetype = $event.SourceEventArgs.ChangeType
    Write-Host "File $name at path $path was $changetype at $(get-date)"
    Copy-Item $Watcher.path $Destination
}

Register-ObjectEvent $Watcher 'Created' -Action $action

Any help or advice would be appreciated.

Best Regards,

  • 1
    Try using `-NoExit` when creating the parent process. `powershell.exe -File path.ps1 -NoExit` – Santiago Squarzon May 26 '22 at 12:41
  • Hello Santiago, I have tried it with Windows Run putting these "powershell.exe -File path.ps1 -NoExit" but had the same result, the powershell window just opens for a moment and closes back – Frank Pardo May 26 '22 at 13:30
  • The only thing i been able to is to put a ``` while ($true){ } ``` at the end of the script. This keeps the powershell window open and makes the script work, if someone have an idea for a better option i would be glad, i don't think is the best way to have this window in the screen and if someone closes it the script would terminate. Tried also the option -WindowStyle Hidden but didn't worked. – Frank Pardo May 26 '22 at 13:38
  • Using the while described below and the option -WindowStyle hidden when calling the script makes the script to keep executed in the background, i think for now this will work. But will appreciate if someone have any idea that fits better. – Frank Pardo May 26 '22 at 13:57
  • Wihtout having experiences with this particular topic ... according to this blog post the solution with `while($true)` seems to be a valid solution [Monitoring Folders for File Changes](https://powershell.one/tricks/filesystem/filesystemwatcher) – Olaf May 26 '22 at 17:28
  • 1
    `while($true)` will burn cpu cycles, maybe try `wait-event 'forever'` at the end – Gregor y May 26 '22 at 20:18
  • 1
    also note that the reason it works in the ISE is because the environment isn't disposed, so the object that the event handler is attached to is never given over to the garbage handler. – Gregor y May 26 '22 at 20:49

1 Answers1

3

Gregor y provided the crucial hint in a comment:

To ensure that your script keeps processing events indefinitely, you can use a Wait-Event call at the end of your script to indefinitely wait for events that will never arrive, which keeps your script running, but - unlike Start-Sleep - does not block processing of events via the script block passed to Register-ObjectEvent's -Action parameter:

$Watcher = New-Object System.IO.FileSystemWatcher
$Watcher.path = "\\192.168.5.127\data\TestWatcher"
$Destination = "C:\TestWatcher"
$Watcher.EnableRaisingEvents = $true

$action = {
    $path = $event.SourceEventArgs.FullPath
    $name = $event.SourceEventArgs.Name
    $changetype = $event.SourceEventArgs.ChangeType
    Write-Host "File $name at path $path was $changetype at $(get-date)"
    Copy-Item $Watcher.path $Destination
}

# Register the event with a self-chosen name passed to -SourceIdentifier
# and an -Action script block.
$null = 
  Register-ObjectEvent $Watcher Created -SourceIdentifier FileWatcher -Action $action

# Now wait indefinitely for an event with the same source identifier to arrive.
# NONE will ever arrive, because the events are handled via the -Action script block.
# However, the call will prevent your script from exiting, without
# blocking the processing of events in the -Action script block.
Wait-Event -SourceIdentifier FileWatcher

Alternatively, make do without an -Action script block and process events in a Wait-Event loop:

$Watcher = New-Object System.IO.FileSystemWatcher
$Watcher.path = "\\192.168.5.127\data\TestWatcher"
$Destination = "C:\TestWatcher"
$Watcher.EnableRaisingEvents = $true

# Register the event with a self-chosen name passed to -SourceIdentifier
# but WITHOUT an -Action script block.
$null = Register-ObjectEvent $Watcher 'Created' -SourceIdentifier FileWatcher

# Now use Wait-Event with the chosen source identifier to
# to indefinitely receive and then process the events as they 
# become available.
while ($event = Wait-Event -SourceIdentifier FileWatcher) {
  $path = $event.SourceEventArgs.FullPath
  $name = $event.SourceEventArgs.Name
  $changetype = $event.SourceEventArgs.ChangeType
  Write-Host "File $name at path $path was $changetype at $(Get-Date)"
  Copy-Item $Watcher.path $Destination
  $event | Remove-Event # Note: Events must be manually removed.
}
mklement0
  • 382,024
  • 64
  • 607
  • 775