Skip to main content

The FSWatcherEngineEvent PowerShell module to make these file system watchers easier to use.

---
title: Reusable File System Event Watcher for PowerShell
subtitle: The FSWatcherEngineEvent PowerShell module to make these file system watchers easier to use.
author: Wolfgang Grob
date: March 18th, 2021
source: https://devblogs.microsoft.com/powershell-community/a-reusable-file-system-event-watcher-for-powershell/
github: https://github.com/wgross/fswatcher-engine-event
snippet: https://jonlabelle.com/snippets/view/markdown/reusable-file-system-event-watcher-for-powershell
notoc: false
---

Some time ago I wanted to sync files from a source directory to a destination
directory immediately after they had changed in the source directory. As a C#
developer I'm aware of a .NET Framework class named [FileSystemWatcher](https://docs.microsoft.com/dotnet/api/system.io.filesystemwatcher)
which suits this job perfectly. A file system watcher listens to change
notifications generated by the operating system and invokes a given function if
the file change matches several filter criteria like the directory, the file
name or the type of the change. There are already many examples on the internet
showing how to create and configure the watcher in PowerShell but this isn't
something I can easily recall from memory at the moment I need it. I made the
[FSWatcherEngineEvent PowerShell module](https://www.powershellgallery.com/packages/FSWatcherEngineEvent) to make these file system watchers easier
to use. It hides the C#-API behind a PowerShell command with argument
completion, it keeps track of the created watchers, and provides commands to
pause notifications and to clean up the watchers if they are no longer needed.

After you [install and import the module](https://www.powershellgallery.com/packages/FSWatcherEngineEvent),
you can create a new filesystem watcher.

```powershell
Install-Module -Name FSWatcherEngineEvent
```

As an example, you can watch for changes in directory `C:\Tempfiles`. The
command allows to specify the same parameters (with the same names) as if you
are using the C# class directly. This includes:

- NotifyFilter: what kind of change triggers an event (by default: LastWrite, FileName, DirectoryName)
- Filter: a wildcard to define a subset of files to watch
- IncludeSubdirectory: extends the area of observation to the subdirectories of the specified path

Please refer to the Microsoft's reference documentation of the FileSystemWatcher
class for the details.

```powershell
New-FileSystemWatcher -SourceIdentifier "MyEvent" -Path "C:\Tempfiles"
```

The watcher now sends notifications to PowerShell's engine event queue using the
source identifier "MyEvent". You can consume the event by registering an event
handler for the same source identifier. The following example just writes the
whole event converted to JSON to the console:

```console
PS> Register-EngineEvent -SourceIdentifier "MyEvent" -Action { $event | ConvertTo-Json | Write-Host }

Id     Name      PSJobTypeName   State         HasMoreData     Location    Command
--     ----      -------------   -----         -----------     --------    -------
1      MyEvent                   NotStarted    False                       |ConvertTo-Json|Wr...
```

PowerShell allows you to register more than one handler for a single source
identifier but the FSWatcherEngineEvent module doesn't allow you to create more
than one watcher using the same source identifier.

To produce a new event, just write some characters to a file in the watched
directory:

```console
PS> "foo" >> "C:\Tempfiles\test.txt"
```

```json
{
  "ComputerName": null,
  "RunspaceId": "b92c271b-c147-4bd6-97e4-ffc2308a1fcc",
  "EventIdentifier": 4,
  "Sender": {
    "NotifyFilter": 19,
    "Filters": [],
    "EnableRaisingEvents": true,
    "Filter": "*",
    "IncludeSubdirectories": false,
    "InternalBufferSize": 8192,
    "Path": "C:\\Tempfiles\\",
    "Site": null,
    "SynchronizingObject": null,
    "Container": null
  },
  "SourceEventArgs": null,
  "SourceArgs": null,
  "SourceIdentifier": "MyEvent",
  "TimeGenerated": "2021-03-13T21:39:50.4483088+01:00",
  "MessageData": {
    "ChangeType": 4,
    "FullPath": "C:\\Tempfiles\\test.txt",
    "Name": "test.txt"
  }
}
```

Events raised before a handler is registered remain in the queue until you
consume them using

[Get-Event](https://docs.microsoft.com/powershell/module/Microsoft.PowerShell.Utility/Get-Event)/[Remove-Event](https://docs.microsoft.com/powershell/module/Microsoft.PowerShell.Utility/Remove-Event).

To suspend the notification temporarily and to resume it later the following two
commands can be used:

```powershell
Suspend-FileSystemWatcher -SourceIdentifier "MyEvent"

Resume-FileSystemWatcher -SourceIdentifier "MyEvent"
```

To keep track of all the filesystem watchers created in the current PowerShell
process, you can use the command `Get-FileSystemWatcher`:

```console
PS> Get-FileSystemWatcher

SourceIdentifier      : MyEvent
Path                  : C:\Tempfiles
NotifyFilter          : FileName, DirectoryName, LastWrite
EnableRaisingEvents   : True
IncludeSubdirectories : False
Filter                : *
```

This command writes a state object to the pipe containing the configuration of
all filesystem watchers. Finally, if you want get rid of filesystem watchers the
command `Remove-FileSystemWatcher` disposes a filesystem watcher specified by
the source identifier or by piping in a collection of watchers:

```powershell
# to dispose one watcher
Remove-FileSystemWatcher -SourceIdentifier "MyEvent"

# to dispose all
Get-FileSystemWatcher | Remove-FileSystemWatcher
```

Piping the filesystem watchers also works with the other commands. If you like
the module and want to see more you may inspect or fork its code at
[GitHub](https://github.com/wgross/fswatcher-engine-event).