The Surly Admin

Father, husband, IT Pro, cancer survivor

Scan a Folder For Changes

Another fun little project popped up at Spiceworks yesterday.  OP (Original Poster) was looking to create a vbScript that would scan a folder for new files.  The Folder was actually part of an FTP site he had setup and he wanted to be notified by email whenever something new was uploaded to it.  Here’s how I went after the script.

So how do you figure out new files have been uploaded into a Folder?  There are a few things you can do.  One is you can save all of the filenames into a database/text file, then compare that file to what’s actually in the folder, if there’s a difference you have a hit!  Another method is you can use Windows event handling and actually trigger the script whenever there is a change.  But there is another way that turns out to be the easiest.  The script runs every 10 minutes, so we could do a simple search for files that have been updated in the past 10 minutes.  If we get a hit we get notified.  Now, you could edit a file and trigger the script too but in this case I believe that’s acceptable.

Turns out the actual code to detect a changed file in the past 10 minutes is pretty easy:

Get-ChildItem * | where ( $_.LastWriteTime -ge [datetime]::Now.AddMinutes(-10) }

You use Get-ChildItem to scan for all files in the folder you want (if you want to scan sub-folders too you would add the -recurse parameter) then pipe it into the Where cmdlet where you check the .LastWriteTime with the time right now minus 10 minutes.

Ryan Witschger made a great comment in his blog about declaring all of his variable as Parameters, which is a great idea.  By doing that it allows you to really make your script flexible as you can change these values on the fly and even run your script in multiple ways without changing code.  If you’ve ever had a script that you run for different things and then have to update that script “x” times because you made an update to it you know what I mean!  So on this script let’s declare some variables.


Param (
 [string]$Path = "D:\FTPSites\",
 [string]$SMTPServer = "smtpservername",
 [string]$From = "SFTPAlert@domain.com",
 [string]$To = "user@domain.com",
 [string]$Subject = "New File Uploaded to FTP Site"
 )

Since we’re sending an email we want to use the Send-MailMessage cmdlet to accomplish that.  Now, you could just run it with every property you need and the variables you’ve declared above but honestly it makes for pretty ugly looking code.  A nice workaround for that is a method called “splatting“.  In a nutshell you create a hash table with all of the properties you want to use, then when you call the Send-MailMessage cmdlet you use your hash table with a “@” symbol and that will apply the table as your properties.  Here’s how:


$SMTPMessage = @{
To = $To
From = $From
Subject = "$Subject at $Path"
Smtpserver = $SMTPServer
}
Send-MailMessage @SMTPMessage

Notice the Subject line?  I love the fact that in Powershell you don’t have to break out of a string to add variables within the text.  Such a time saver!

Now we’ve got all of our files located (if any), we’ve got the header information for our Send-MailMessage cmdlet, we just need the body.  For me, looks are everything so let’s have the script notify you that not only have files been uploaded, but which ones.  You’ll notice some odd code in the string declarations: “`n“.   The back tick character is the Powershell escape character, this allows you to put in reserved characters like the $ sign or the hash simple # in a string (which Powershell will try to interpret as a variable or comment) or you can also add special characters.  `n is a carriage return or new line.


If ($File)
{ $SMTPBody = "`nThe following files have recently been uploaded to your FTP site:`n`n"
$File | ForEach { $SMTPBody += "$($_.FullName)`n" }

We start by assigning a variable some simple information about what’s happened, then loop through all of the objects in $File and put the FullName property–which is the full path of the file.

And there you have it.  Create a scheduled task and run Powershell.exe as your program, and the following as the argument:

-ExecutionPolicy Bypass <pathtoscript>\Scan-FolderForFiles.ps1

You’ve also decided that you want to scan a folder on the file server called Suggestion Box and anytime someone places a file in there to email HR.  Schedule another task (doesn’t have to be on the file server) with these parameters:

<pathtoscript>\Scan-FolderForFiles.ps1 -Path "\\<fileserver>\<share>\Suggestion Box" -From SuggestionBox@domain.com -Subject "New File in Suggestion Box" -To HR@domain.com

This will override the Path, From, To and Subject fields while leaving the SMTPServer (your SMTP relay) field alone.

Here’s the full code with a little change to make some of the messaging more generic:

Param (
[string]$Path = "D:\FTPSites\",
[string]$SMTPServer = "smtpservername",
[string]$From = "SFTPAlert@domain.com",
[string]$To = "user@domain.com",
[string]$Subject = "New File Uploaded to FTP Site"
)

$SMTPMessage = @{
To = $To
From = $From
Subject = "$Subject at $Path"
Smtpserver = $SMTPServer
}

$File = Get-ChildItem $Path | Where { $_.LastWriteTime -ge [datetime]::Now.AddMinutes(-10) }
If ($File)
{ $SMTPBody = "`nThe following files have recently been added/changed:`n`n"
$File | ForEach { $SMTPBody += "$($_.FullName)`n" }
Send-MailMessage @SMTPMessage -Body $SMTPBody
}
Advertisement

September 11, 2012 - Posted by | PowerShell | , , , , ,

24 Comments »

  1. […] Load up a hash table with all of static properties we’ll need for Send-MailMessage–another splat! […]

    Pingback by Report When New Users are Added to Active Directory « The Surly Admin | October 22, 2012 | Reply

  2. I am not very PS savvy but generally I know when something says Line-Char to diagnose a problem. I am getting “Missing Expression after unary operator ‘-‘ at Line:1 char:2” of this exact script that was created. I am using Notepad++ to write this out. I know this post is old but this is exactly what my company needs and no PS admin to do it. 🙂 Thank you.

    Comment by MichaelH | August 22, 2013 | Reply

  3. Great script! I stopped coding years ago so rather than me beat my head on the wall, can you post a modification to the script that will allow for multiple directories to be searched with each notifying a different user?

    For example USER A Path = “\\serverA\users\UserA\”
    To = “usera@domain.com”

    User B path = “\\serverA\users\UserB”
    To = “userB@domain.com”

    Comment by JDG | September 2, 2014 | Reply

  4. Is there a way to exclude a particular file type?

    Comment by JasonM | October 23, 2014 | Reply

    • Sure. Line 16 is here the Get-ChildItem occurs, you should be able to use the -Exclude parameter to exclude the files you want. Might have to add a *.* at the end of $Path. Let me know what ends up working!

      Comment by Martin9700 | October 23, 2014 | Reply

  5. Would like to know if there’s a way to save to .txt (and appending to file) file instead of sending an email.

    Comment by Opayque | March 26, 2015 | Reply

  6. I am looking into do something in reverse of this. When a file or specific set of files are not updated after a period of time I would like to get a notification. I am thinking about after 30 minutes or 1 hour the script would send out a notification via email to indicate a file has not been updated.

    Comment by Israel Anthony Lopez | November 24, 2015 | Reply

    • Do you find a wat to be notify when no fo=iles was updated?

      Comment by Jacques Bergeron | April 24, 2017 | Reply

  7. hi,

    i would like to use your script but i need a script who looked on a specified folder and when we add a new files , this will send a email to other person to inform her that a new file was added , can you help me with this??

    thanks

    Comment by Maxim | June 7, 2016 | Reply

    • That’s what this script already does. Are you having a problem with it?

      Comment by Martin9700 | June 7, 2016 | Reply

      • no , it’s not working, i have a person who every wednesday , drop a file on a specified folder, i made a scheduled task and it’s not working , the script seems work only for 10 minutes changed…

        Comment by Maxim Robert Bergeron | June 7, 2016

  8. This worked great! Thank you for posting this.

    Comment by Adam Rivera | August 8, 2016 | Reply

  9. I was playing with this and found it very useful. Looks like the perfect tool to let users know there are new uploads on an FTP folder they need to monitor. Thank you. Is there a variable or command that would allow it to search and report on files and folders contained within sub-folders also?

    Comment by Christopher Hiatt | September 27, 2016 | Reply

    • Sure, just add a -Recurse to the Get-ChildItem cmdlet: $File = Get-ChildItem $Path -Recurse | Where …

      Comment by Martin9700 | September 28, 2016 | Reply

  10. Works great. One question, how to add the size of the files that have been added/changed?

    Comment by Theo2000 | March 2, 2017 | Reply

  11. Hi, How can I send to update to multiply recipients. when I try to add a second email in $to variable I get an error

    Comment by Kosta | March 27, 2017 | Reply

  12. Works awesome, I adopted it with gmail credentials and it works well so far. One problem I am having is the file path has spaces so we aren’t able to click the link from outlook. ex: \\FileServer1\Public\Inspection Dept\example1.txt Is there any way around this?

    Comment by Freddie Vierra | January 5, 2018 | Reply

  13. Fantastic!!!

    Comment by Jerome Dorasamy | April 5, 2018 | Reply

  14. Kudos on this script, it’s helped a ton – BUT… 🙂 I’m with a previous requester here (JDG) needing a solution for checking multiple paths for a new file. I’ve played around with parameters but not having any luck. Would you be able to offer some advice?

    Either Get-Content for a list of paths.
    or…
    “\\server1\folder1”, “\\server2\folder2”, etc.

    Comment by mojoboxdesigns | May 16, 2018 | Reply

  15. Thanks for the script. I can run the script from the command line and I get an email with the info. When I add it the task i do not get anything. Do you have any troubleshooting tips? Thanks

    Comment by Mike Scott | June 21, 2019 | Reply

  16. I got it to work. Thanks

    Comment by Mike Scott | June 21, 2019 | Reply

  17. [string]$recipients = “a@a.com,b@b.com,c@c.com”,
    [string[]]$To = $recipients.Split(‘,’),

    https://stackoverflow.com/questions/10241816/powershell-send-mailmessage-email-to-multiple-recipients

    Comment by Gregory Brown | September 12, 2019 | Reply

  18. Hi there i have this script working but i would like to be able to have the file name listed in the email also.
    currently it just sends the folder location/s

    Comment by Kevan | April 14, 2022 | Reply


Leave a Reply to Israel Anthony Lopez Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: