Search code examples
powershelleventsfilesystemwatcher

How can I pass variables into a Powershell ObjectEvent action


I'm writing a tool which will take an action whenever a new file is written into a folder on a windows server. I'm using the following

$action = {
write-host "action fired"
Process-file $event.SourceEventArgs.FullPath $DestFolder
}    
$onCreated = Register-ObjectEvent $fileSystemWatcher Created -SourceIdentifier FileCreated -Action $Action

I've got two problems. The process-file command is a placeholder for a few lines of code which are working fine. My issue is with the $Destfolder variable. This is a global variable which exists when I assign $Action but which does not exist when the event fires. I know I need to either force evaluation of the variable or somehow create a delegate, but I can't see how I can do this. I'm probably not searching for the correct names.

The second is that in its current state my script runs and exits and then the events start firing. This works fine from the command line but how should I be doing this if its to be run as a background task. I'm not sure how I should be keeping my script 'open'. I tried just adding a sleep at the end of my script but that prevented the events from firing, so looping sleeps isn't going to work. Once again I have probably been searching for the wrong thing and theres a good technique for doing this. All I need is to be pointed in the right direction.


Solution

    • Use Register-ObjectEvent's -MessageData parameter to pass data from the caller to the -Action script block.

      # Access the value passed from the caller with 
      # Register-ObjectEvent -MessageData via $Event.MessageData
      $action = {
        write-host "action fired"
        Process-file $event.SourceEventArgs.FullPath $Event.MessageData
      }    
      
      # Pass the value of the local $destFolder variable via -MessageData
      $onCreated = Register-ObjectEvent -MessageData $destFolder $fileSystemWatcher Created -SourceIdentifier FileCreated -Action $Action
      
    • Keep your script running in order to keep processing events indefinitely, and clean up the event job returned by Register-ObjectEvent on termination.

      try {
        # Indefinitely wait for events to arrive.
        # NONE EVER WILL, due to use of an -Action script block,
        # but this wait allows event processing via the script block
        # to occur (it would *not* if you used Start-Sleep).
        # Note: With this approach, the script must be terminated
        #       with Ctrl-C, or the hosting PowerShell process must be terminated
        Wait-Event -SourceIdentifier FileCreated
      } 
      finally {
        # Clean up the event job, which also unregisters the event subscription.
        $onCreated | Remove-Job -Force
      }