If you need to monitor a specific folder/file and trigger an automatic action on changes, use the built-in .NET FileSystemWatcher class instead of relying on classic Windows file-system access auditing. Monitoring a folder using the System.IO.FileSystemWatcher class allows you to detect real-time changes, such as file creation, deletion, renaming, or modification, and automatically execute assigned actions when changes are detected (for example: sending a notification, logging the event to the Event Viewer or a text log file, or running a custom script). This article shows how to monitor a specific directory for file system changes using the .NET FileSystemWatcher class and PowerShell.
First, let’s create an instance of the FileSystemWatcher class:
$fs_watch = New-Object System.IO.FileSystemWatcher
Specify the target directory that you want to track:
$fs_watch.Path = "C:\Repo\Config"
To monitor file system events in subdirectories, set the following:
$fs_watch.IncludeSubdirectories = $true
Enable event generation when filesystem changes are detected:
$fs_watch.EnableRaisingEvents = $true
Configure the action that should be performed when the watcher detects changes in the monitored folder:
$reg_action = {
$changeType = $Event.SourceEventArgs.ChangeType
$path = $Event.SourceEventArgs.FullPath
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | $changeType | $path" | Out-File -FilePath "$env:USERPROFILE\watch.log" -Append
}
The next step is to subscribe to the specific event types you want to track. There are four event types available: Created, Changed, Deleted, and Renamed. To track all these types of events, I will register all four file system subscriptions:
Register-ObjectEvent $fs_watch Created -Action $reg_action -SourceIdentifier FSCreate
Register-ObjectEvent $fs_watch Changed -Action $reg_action -SourceIdentifier FSChange
Register-ObjectEvent $fs_watch Deleted -Action $reg_action -SourceIdentifier FSDelete
Register-ObjectEvent $fs_watch Renamed -Action $reg_action -SourceIdentifier FSRename
The FileWatcher will monitor changes in the directory as long as the parent PowerShell.exe process is running. The Windows kernel monitors changes to the file system and sends notifications to your subscriptions. The script runs once, so you don’t need to add polling loops. However, when you run the code through a PS1 script file, you can add an infinite loop at the end:
while ($true) {sleep 10}
Running this script starts continuous folder monitoring and logs all detected file system events in the target log file. In a separate PowerShell console, I configured the log file to display on-screen with real-time updates.
Get-Content -Path $env:USERPROFILE\watch.log -wait
To stop receiving filesystem watcher updates, unregister your subscriptions:
Unregister-Event -SourceIdentifier FSCreate
Unregister-Event -SourceIdentifier FSChange
Unregister-Event -SourceIdentifier FSDelete
Unregister-Event -SourceIdentifier FSRename
To track changes to specific file types only, apply a filter at the beginning of the script:
$filter = "*.ini"
$fs_watch.Filter = $filter
To make FileSystemWatcher respond only to specific events, configure the NotifyFilter property to specify the types of changes to monitor. For example, I only want an action to be triggered if there are changes to the NTFS permissions, file size, or file name.
$fs_watch.NotifyFilter = [System.IO.NotifyFilters]::FileName -bor [System.IO.NotifyFilters]::Size -bor [System.IO.NotifyFilters]::Security
If you need to create a separate handler for a specific event, you can configure this directly in the subscription’s Action property. In this example, I want to log both the old and new file names when a file is renamed:
Register-ObjectEvent $fs_watch Renamed -SourceIdentifier FSRename -Action {
$details = $Event.SourceEventArgs
$timeStamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
$logMessage = "$timeStamp | Renamed | From: $($details.OldFullPath) To: $($details.FullPath)"
$logMessage | Out-File -FilePath $env:USERPROFILE\watch.log -Append
}
To avoid losing events, especially with a high number of events generated (hundreds per second), you can increase the size of the internal buffer to 64 KB:
$fs_watch.InternalBufferSize = 65536
Or, you can run each action in a separate background process by invoking the handler from the Action block with Start-Job cmdlet, which isolates execution and avoids blocking the watcher.
In this article, we demonstrated how to use PowerShell to implement a simple file system monitoring solution capable of tracking file creation, modification, deletion, and rename events within a specified directory and automatically trigger actions in response to these events.

