Monitor Folder and Email as Attachement

Hi All,
Just getting into Powershell by way of demands from the business.

I am wanting to monitor a folder or set of folders, and if a file(s) appear, email them as an attachement to an address or maybe a couple of email addresses.

I have tried various things, but nothing I do seems to do the job.

Would anyone be kind enough to advise on a script to carry out this task.

Thanks

This is not something PowerShell is awesomely suited for, but do some searched on “PowerShell FileSystemWatcher” and see if anything meets your needs. The FilesystemWatcher is a .NET Framework component that’s much better at watching for changes, and it can then (sort of) call your PowerShell code to do whatever it is your’e after.

Graeme,

It will depend on your exact requirements. I am going to assume that you don’t need this to happen instantly, that new files can wait and be sent in aggregate every 5 minutes, or whatever. I am also going to assume for simplicity that the folders are a drop-off point, and the files are to be deleted (or moved to a backup folder) after they have been emailed. (It gets a bit more complex otherwise.)

Use your favorite automation tool (or a simple scheduled task) to run something like this every 5 minutes, or every hour, or whatever. Be sure to run it as an account that has the required rights on the folders in question.

$Folders = @( 'C:\Test1'
              'C:\Test2' )
$DestFolder = 'C:\TestProcessed'

$EmailList = @( 'User1@contoso.com'
                'User2@contoso.com' )

$From       = 'admin@contoso.com'
$Subject    = 'New files'
$SMTPServer = 'smtp.contoso.com'

#  Get new files
$NewFiles = $Folders | Get-ChildItem -File -Recurse

#  If there are an new files...
If ( $NewFiles )
    {
    #  Add the file count and file names to the body of the email
    $Body = '$($NewFiles.Count) new files attached'
    $NewFiles | ForEach { $Body += $_.Name + "" }

    #  Send the email with attachments
    Send-MailMessage -From $From -To $EmailList -Subject $Subject -Body $Body -BodyAsHTML -Attachments $NewFiles.FullName -SmtpServer $SMTPServer

    #  Move the emailed files to the destination folder
    $NewFiles.FullName | Move-Item -Destination $DestFolder -Force
    }

Don many thanks for your information, I shall do a bit of searching and see how that pans out.

Tim,

Your assumptions were spot on, once the file has been sent it can be deleted, its of no use anymore, and I would just schedule to run every 15 mins or so.

Really appreciate the time you have taken too post this information. I shall have a play around with it today and see how it goes, I will feedback later today when I have connectivity back as I am on the move.

Once again many thanks

Just a couple of quick updates to Tim’s script.

  1. Leverage splatting
  2. when passing multiple parameters
  3. The body of the email is HTML, so leverage ConvertTo-HTML when providing file information about the files attached
  4. This is more personal preference, but I don't like implicit foreach (e.g. $NewFile.FullName). I like to see the foreach construct and try to make script compatible with PS versions under V3.

Here is a slightly tweaked version of Tim’s script:

$Folders = @( 'C:\Temp','C:\Test2' )
$DestFolder = 'C:\TestProcessed'

$emailSplat = @{
    To =  @( 'user1@contoso.com','user2@contoso.com' )
    From       = 'admin@contoso.com'
    Subject    = 'New files'
    SMTPServer = 'smtpserver'
    BodyAsHTML = $true
}

#  Get new files
$NewFiles = Get-ChildItem -Path $Folders -File -Recurse -Include *.txt

#  If there are an new files...
If ( $NewFiles ) {
    #  Add the file count and file names to the body of the email
    $Body = $NewFiles | Select Name, FullName, LastWriteTime | ConvertTo-HTML -PreContent ("Attached Files ({0}):" -f $NewFiles.Count) -As Table
    $emailSplat.Add("Body", ($Body | Out-String))

    #Take attachements and add
    $Attachments = $NewFiles | Select -ExpandProperty FullName
    $emailSplat.Add("Attachments", $Attachments)
    
    #  Send the email with attachments
    Send-MailMessage @emailSplat

    #  Move the emailed files to the destination folder
    foreach ($file in $NewFiles) {Move-Item $file.FullName -Destination $DestFolder -Force}
}

How can I modify this script so that it e-mails each file individually?

Thanks.

You could just do a foreach on each file, just remember to do some cleanup after each one. And if you want to edit the text (which you probably do), just do something similar, with a foreach on the $newfiles, and remove the body each time as well

 foreach ($attachment in $Attachments){
      $emailSplat.Add("Attachments", $Attachment)
      #  Send the email with attachment
      Send-MailMessage @emailSplat
      $emailSplat.Remove("Attachments")
    }