Imagine you have a configuration file critical to an application’s operation, and you want the app to restart itself any time that file is changed. Or perhaps you need to watch a log file for updates and react immediately. PowerShell offers a built-in mechanism, via .NET, to detect file changes in real time—no need for custom-coded scripts in C# or external monitoring tools. By combining the FileSystemWatcher class with event handling, you can automate restarts, reload configurations, or trigger any other action upon file modifications.
This article will guide you step by step: from creating a simple script that watches a particular file, to expanding it for entire folders or Windows services. By the end, you’ll have a working knowledge of how to deploy a robust file monitoring solution using PowerShell in a user-friendly, real-world context.
Understanding FileSystemWatcher
The FileSystemWatcher class in .NET is designed specifically for watching changes to the file system. It can monitor activities such as:
- Created: When a file appears in the directory you’re monitoring.
- Changed: When existing files undergo edits or updates (for instance, when their content or size changes).
- Deleted: When a file is removed.
- Renamed: When a file name changes.
These events are raised in real time, letting you respond automatically with any custom action—like stopping and relaunching an application. PowerShell can consume these .NET events directly, eliminating the need to poll the file system on a fixed schedule.
Building Your First PowerShell Script
a. Setting Up the Watcher
Let’s create a simple script that watches a single file for changes. Suppose we have a file named config.txt
in C:\MyApp\
that our application relies on. Here’s the basic approach:
powershellCopyEdit# Path to watch
$folderPath = "C:\MyApp"
$fileName = "config.txt"
# Create a new FileSystemWatcher object
$watcher = New-Object System.IO.FileSystemWatcher
# Assign the path and filter
$watcher.Path = $folderPath
$watcher.Filter = $fileName
# Decide which aspects of the file should trigger an event
$watcher.NotifyFilter = [System.IO.NotifyFilters]'FileName, LastWrite, Size'
# Enable event raising
$watcher.EnableRaisingEvents = $true
Explanation:
$folderPath
/$fileName
: Specifies the exact file path to watch.System.IO.FileSystemWatcher
: The .NET class handling directory or file monitoring.NotifyFilter
: Instructs the watcher on which file attributes to track. Common filters includeLastWrite
,FileName
,Size
, etc.EnableRaisingEvents = $true
: Tells the watcher to start paying attention.
b. Registering for Events
FileSystemWatcher alone won’t do anything without event registration. PowerShell provides a handy cmdlet called Register-ObjectEvent
that sets up a listener. Once an event fires, PowerShell can execute a block of code.
powershellCopyEdit# Define what should happen upon a change
$action = {
Write-Host "File changed: $($Event.SourceEventArgs.FullPath)"
# We'll add our restart logic next
}
# Register the 'Changed' event
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action $action
Explanation:
-EventName Changed
: We care about modifications to the file. You could also register forCreated
,Deleted
, orRenamed
.-Action $action
: The script block that runs whenever the event occurs. Here, we simply print a message, but we’ll expand on it shortly.
c. Restarting the Application
Now we want to stop and restart the application. Let’s assume we have an application named MyApp.exe
in C:\MyApp
. We can use PowerShell’s Get-Process
and Stop-Process
commands to end it, then Start-Process
to bring it back online.
powershellCopyEdit$appPath = "C:\MyApp\MyApp.exe"
# Define the action that restarts the app
$action = {
Write-Host "File changed: $($Event.SourceEventArgs.FullPath)"
# Stop the running process (if it exists)
$processName = "MyApp" # Name without .exe
Get-Process $processName -ErrorAction SilentlyContinue | Stop-Process -Force
# Restart the app
Write-Host "Restarting the application..."
Start-Process $using:appPath
}
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action $action
Explanation:
$using:appPath
: Because$action
is an event script block, we use$using:
to access variables from the parent scope.Get-Process $processName -ErrorAction SilentlyContinue
: IfMyApp
isn’t running, this command won’t throw an error.Stop-Process -Force
: Ensures the application is forcibly closed.Start-Process
: Launches a fresh instance ofMyApp.exe
.
d. Keeping the Script Alive
For our script to detect changes, it must continue running. Once you exit the PowerShell session, the watcher stops. We can add a simple loop or use Wait-Event
to keep the script open:
powershellCopyEditWrite-Host "Monitoring file changes for $fileName in $folderPath..."
Write-Host "Press Ctrl + C to stop this script."
while ($true) {
Start-Sleep -Seconds 1
}
This loop ensures the script doesn’t terminate. Press Ctrl + C to break out of it and stop monitoring.
Monitoring a Folder Versus a Single File
If you want to watch all files in a directory (or multiple file types), you can set Filter = "*.*"
or some specific extension like Filter = "*.log"
. Register the same or different actions for each event type:
powershellCopyEdit$watcher.Filter = "*.*"
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action {
Write-Host "A file was changed in $($Event.SourceEventArgs.FullPath)"
# ...
}
Register-ObjectEvent -InputObject $watcher -EventName Created -Action {
Write-Host "A file was created in $($Event.SourceEventArgs.FullPath)"
# ...
}
This is helpful if you need to watch an entire folder for new or removed files and respond accordingly (e.g., restarting a microservice whenever a certain config file appears).
Handling Windows Services Instead of Applications
Sometimes you need to restart a Windows service instead of a typical .exe. For instance, maybe you have a service named “MyService”:
powershellCopyEdit$serviceName = "MyService"
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action {
Write-Host "File changed, restarting $serviceName..."
# Stop the service if it's running
Stop-Service -Name $using:serviceName -Force
# Start it again
Start-Service -Name $using:serviceName
}
Make sure you have the necessary permissions to manage services, and consider running PowerShell as an administrator.
Practical Tips and Best Practices
- Debounce Rapid Changes
- File changes might trigger multiple events in quick succession—especially if an editor or program writes in small chunks. This could mean multiple restarts.
- A common solution is a short sleep or lockout period after the first trigger, preventing repeated restarts within a set timeframe.
- Run as a Scheduled Task or Background Job
- If you need constant monitoring, you could run this script on system startup via the Windows Task Scheduler. The task keeps a PowerShell session open, meaning you don’t need an active console.
- Alternatively, use a PowerShell background job or even package it as a Windows service (using tools like NSSM—Non-Sucking Service Manager).
- Logging
- For production, consider logging each event to a file or to the Windows Event Log. This helps troubleshoot if the application is restarting too frequently.
- Security Considerations
- Make sure the user context running the watcher has permission to read the directory, write logs if necessary, and restart the application or service.
- If you watch sensitive directories, keep the script secure to prevent unauthorized editing.
- NotifyFilter Settings
- If you only care about content changes, use
LastWrite
. If you also want to track renaming, includeFileName
. Setting too many filters might lead to extra events, so choose carefully.
- If you only care about content changes, use
- Performance
FileSystemWatcher
is generally lightweight, but monitoring a very large directory or many subfolders can be resource-intensive.- If you need to watch subdirectories too, set
$watcher.IncludeSubdirectories = $true
. Just be aware this can create a lot of events for big directory trees.
Conclusion
PowerShell’s FileSystemWatcher integration offers a straightforward yet powerful way to monitor file changes and automatically restart an application (or service) in real time. By combining a few built-in cmdlets—New-Object System.IO.FileSystemWatcher
and Register-ObjectEvent
—you can create a script that effortlessly listens for file modifications and executes any desired action, whether that’s updating your application’s configuration, rotating logs, or triggering a complete system restart.
As you implement this approach, keep in mind best practices around logging, security, and debouncing rapid events. If you’re looking for a fully automated, always-on solution, consider running your script as a scheduled task or a background service. With just a bit of setup, you’ll have a reliable watchdog in place—one that frees you from manually checking files and ensures your application is always up to date.
Feel free to adjust any of the code samples to fit your unique environment, and remember that PowerShell is extremely versatile. If you have any questions or run into issues, don’t hesitate to explore the rich PowerShell documentation or ask for help within the community. Happy scripting!