FileSystemWatcher : Monitor FileSystem changes

POWERSHELL

In this article, I would like to talk about The FileSystemWatcher which is a pretty handy .NET feature that consist in monitoring file or directory changes within a specific folder.
Basically, this feature allow you configure what kind of change you would like get noticed about while your script is running, and take actions when it occurs.
The FileSystemWatcher object allow you to listen to the following events :

  • Changed
  • Renamed
  • Created
  • Deleted


To set this up, we will have to perform this sequence in our script :

  • Create and configure a filesystemwatcher object
  • Register this object to subscribe to a particular event


The FileSystemWatcher object

#We will start by creating the object inside a variable :
[IO.FileSystemWatcher]$FileSystemWatcher = New-Object System.IO.FileSystemWatcher 
#We can have a look at its properties in order to figure out what we need to care about
$FileSystemWatcher
FileSystemWatcher object properties
FileSystemWatcher object properties

Here is the list of the main FileSystemWatcher parameters with their respective descriptions. Full documentation

Path Sets or Gets the Path of the directory to watch
EnableRaisingEvents Enable or disable the component
FilterGets or sets the filter string, used to determine what files are monitored in a directory. Default value is (*.*)

IncludeSubdirectories
Enables or disables including subdirectories to be watched
InternalBufferSize Gets or sets the size of internal buffer. Default is 8K, should be a multiple of 4k for best performances on intel based hardware. It could not be lower than 4K.
NotifyFilter Gets or sets the type of changes to watch for


The NotifyFilter property

Usually, you will configure NotifyFilter, Filter, IncludeSubdirectories and Path.

For the NotifyFilter property, you will have to use NotifyFilters enumeration. The default value is set to LastWrite, FileName and DirectoryName.
You can access the possible values by calling this .NET enumerator and pressing CTRL + SPACE to force the intellisense :

[System.IO.NotifyFilters]:: # CTRL + SPACE
NotifyFilter accepted values
NotifyFilter accepted values

Here are the values you can monitor with their respective descriptions :

Attributes The attributes of the file or folder
CreationTimeThe time the file or folder was created
DirectoryNameThe name of the directory
FileNameThe name of the file
LastAccessThe date the file or folder was last opened
LastWriteThe date the file or folder last had anything written to it
SecurityThe security settings of the file or folder
SizeThe size of the file or folder


Bear in mind that you can monitor all of the values above for a Change.
Renamed, created and deleted events will fire only from the DirectoryName and FileName values

Now that we understand how this concept works, let’s take some full examples…

Watch changes in all script file in a directory

#Create a hashtable for our FileSystemWatcher object properties
$param = @{
    Path = "C:\Scripts";
    Filter = "*.ps1";
    IncludeSubDirectories = $False;
    NotifyFilter = [System.IO.NotifyFilters]::FileName,[System.IO.NotifyFilters]::LastWrite
}

#Create the .NET FileSystemWatcher object and passing our properties
[IO.FileSystemWatcher]$scriptAccessWatcher = New-Object IO.FileSystemWatcher -property $param

#Register the object to the Changed Event
#$scriptAccessWatcher | gm |?{$_.MemberType -like 'Event'} #to see the available event names
Register-ObjectEvent $scriptAccessWatcher Changed -Action {

    #The event raised properties can be accessed with the $Event variable
    #You can uncomment the line bellow to make it a global variable 
    #and access it in your session by typing the variable name
    #$Global:MyEventRaised = $Event
    $name = $Event.SourceEventArgs.Name
    $timeStamp = $Event.TimeGenerated   
    $changeType = $Event.SourceEventArgs.ChangeType
    Write-Host "$name has been $changeType at $timeStamp"
}
Event occurs - Output for file edition
Event occurs – Output for file edition

Watch folder creation in a directory (and subdirectories)

#Create a hashtable for our FileSystemWatcher object properties
$param = @{
    Path = "C:\Scripts";
    Filter = "*.*";
    IncludeSubDirectories = $True;
    NotifyFilter = [System.IO.NotifyFilters]::DirectoryName
}

#Create the .NET FileSystemWatcher object and passing our properties
[IO.FileSystemWatcher]$FolderCreationWatcher = New-Object IO.FileSystemWatcher -property $param

#Register the object to the Created Event
#$scriptAccessWatcher | gm |?{$_.MemberType -like 'Event'} #to see the available event names
Register-ObjectEvent $FolderCreationWatcher Created -Action {

    #The event raised properties can be accessed with the $Event variable
    #You can uncomment the line bellow to make it a global variable 
    #and access it in your session by typing the variable name
    #$Global:MyEventRaised = $Event
    $name = $Event.SourceEventArgs.Name
    $timeStamp = $Event.TimeGenerated   
    $changeType = $Event.SourceEventArgs.ChangeType
    Write-Host "$name has been $changeType at $timeStamp"
}
Event occurs - Output for folder creation
Event occurs – Output for folder creation

Additionally, here is a way to check if an event already exists in your session :

#You can filter event using the SourceObject which is our FileSystemObject and compare values
$objEvents = Get-EventSubscriber | ?{($_.SourceObject.Path -eq $param.Path) -and ($_.SourceObject.Filter -eq $param.Filter) -and ($_.EventName -eq 'Created')}
#If necessary, we can unregister this event se we will not get noticed anymore
$objEvents | Unregister-Event

I like to use this .NET feature to dynamically load configuration files. I hope that it gave you some ideas 😉

See you soon in the blog !

Comments

  1. Mark Gregory

    Thanks for that list of properties. Knew there were more than the 3 or 4 listed on MS, but couldn’t find them. Spent more time than I am willing to admin trying to find the Last Access Time.

  2. Post
    Author

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.