Script to send new files via email from monitored folder - email

I'm wondering if anyone can point me in the direction of how to automate the sending of newly added files located in a monitored folder via email (Exchange), ideally without Outlook installed on the server.
I use scripts daily to notify me of changes in a watched folder via email, but none of these actually attach the files on the email, and at best only list the new files names etc.
We have software that outputs 3 small text files at roughly the same time day, but someone then has to email those manually to the same external address each day. I'd like to automate that process.
I'm running Server 2008 R2, and don't mind PowerShell and VB etc. Any help is appreciated.
Thank you.

This should get you going.
$watchPath = "c:\folder\"
$sendToList = #("toUser#domain.com")
$sendFrom = "fromUser#domain.com"
$emailSubject = "File '{0}' changed"
$smtpHost = "smtp.server"
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $watchPath
$watcher.IncludeSubdirectories = $false
$watcher.EnableRaisingEvents = $true
$changed = Register-ObjectEvent $watcher "Changed" -Action {
Send-MailMessage -SmtpServer $smtpHost -To $sendToList -from $sendFrom -Subject ($emailSubject -f $eventArgs.Name) -Attachments $eventArgs.FullPath
}

Related

Simple Email Message to an 0365 email Acccount

I know that the Send-MailMessage ins powershell is already obsolete based on the https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage?view=powershell-7.3
enter image description here
Is there any alternate way to send email message? its fine if there is no attachment, just an email message that successfully received by recipient like Hello World? I will appreciate any sample or assistance. I'm still learning PowerShell.
I've tried using the Mimekit and MailKit but it seems it doesn't work for me. Maybe there is other way which is much simpler. Thank you in advance guys
Based on the Youtube Video - https://www.youtube.com/watch?v=wy5vs0gEei0
Mimekit and Mailkit works for me fine.
Below the Example from the Youtube Video, hope it will help you
Add-Type -Path "C:\Temp\MailKit\mimekit.3.4.2\lib\netstandard2.0\MimeKit.dll"
Add-Type -Path "C:\Temp\MailKit\mailkit.3.4.2\lib\netstandard2.0\MailKit.dll"
$SMTP = New-Object MailKit.Net.Smtp.SmtpClient
$Message = New-Object MimeKit.MimeMessage
$Builder = New-Object MimeKit.BodyBuilder
# Create Credentials File
Get-Credential | Export-Clixml -Path C:\Temp\SendMail.xml
$Account = Import-Clixml -Path C:\Temp\SendMail.xml
$Message.From.Add("from#from.com")
$Message.To.Add("to#to.com")
$Message.Subject = "Test Message"
$Builder.TextBody = "This is a test Email message"
$Message.Body = $Builder.ToMessageBody()
$SMTP.Connect("smtp.office365.com", 587, $false)
$SMTP.Authenticate($Account)
$SMTP.Send($Message)
$SMTP.Disconnect($true)
$SMTP.Dispose()

Register-ObjectEvent of System.IO.FileSystemWatcher not working as expected

I use a powershell script to watch a folder and get notification when a new file is created.
The script is the following
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Users\Desktop\test\"
$watcher.Filter = "*.nrrd"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action =
{
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
Write-Host "The file '$path' was $changeType at '$(Get-Date)'" -fore green
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher "Created" -Action $action
while ($true) {sleep 5}
It works fine even if I create the file manually or with a .bat, PHP or even python.
The only way it does not work is when another user (or session?) is creating the file.
For example:
I created a folder on my computer, shared it with other computer over LAN.
When the file is created by me (or one of my script), the script is well working and the sentence is displayed.
If I use another computer on the LAN to add a file in the same folder, it does not work. Nothing is displayed.
(But if I copy/past the file created by the other user, the script is working, so is not a issue with the file itself).
I found this and this but the posts are outdated.
Do you have any workaround or idea to solve this?
UPDATE
The file created by hand (or copy/pasted) has owner DEBIAN\root but the original one have Unix User\www-data.
Maybe powershell (windows) is not able to "catch" this kind of user that's maybe why the event is not even created?
Try giving the shared folder's UNC path
$watcher.Path = "\\server\share"

Send email with Powershell from different mailbox

I have created a small PS script to create an email for my pipeline to send out whenever there is a deployment. the problem is i dont want the email to be sent from my personal email but from the company outlook email. i searched and saw different SMTP server names and using mail.from but i cant get it to work. can someone help me out?
param(
[Parameter(Mandatory=$true,Position=0)]
[string]$Address1,
[Parameter(Mandatory=$true,Position=1)]
[string]$Address2,
[switch]$Recurse,
[switch]$Force
)
$ol = New-Object -comObject Outlook.Application
$mail = $ol.CreateItem(0)
$Mail.Recipients.Add($Address1)
$Mail.Recipients.Add($Address2)
$Mail.Subject = "DSC Deployment in Progress"
$Mail.Body = "There is a DSC install beginning. . ."
$Mail.Send()
You need to assign a value to the SendUsingAccount property. The account can be found in the (outlook).Session.Accounts collection.
$sendSmtpAddress = "some.name#somedomain.com"
$account = $ol.session.acounts | ? { $_.smtpAddress -eq $sendSmtpAddress }
then, assign to the SendUsingAccount property before sending
$mail.SendUsingAccount = $account
$mail.Send()
Full example
$sendSmtpAddress = "some.name#somedomain.com"
$ol = new-object -comobject "outlook.application"
$account = $ol.session.accounts | ? { $_.smtpAddress -eq $sendSmtpAddress }
$mail = $ol.CreateItem(0)
$mail.recipients.add("target.user#somedomain.com") | out-null
$mail.subject = "test email"
$mail.body = "test email"
$mail.SendUsingAccount = $account
$mail.Send()
For what it's worth, I gave up trying to send email via Outlook a long time ago, it's much easier to use plain SMTP. Depending on the security policy on your local SMTP server (Exchange?), you may be able to 'send as' any user on your local domain. Ask your IT people for the name/IP of an internal SMTP server that you can use to send email, and then it's as easy as:
send-mailmessage -smtpServer (servername or IP) -from sender.name#domain.com -to #(recipient1#domain.com, recipient2#domain.com) -subject "Email Subject" -body "Email Body"
If using send-mailmessage, it's possible to set a Display Name for the sender by using the form "Display Name <sender.name#domain.com>" e.g.
-from "Deployment Alerts <sender.name#domain.com>"
Recipients will see the Display Name in their email client, rather than the SMTP address.
A couple of points that I consider to be good practice:
Depending on the config of the SMTP server, there may be little, or no verification of the 'sender' address. It is worth using a genuine account that you have access to, so that you have sight of any bounce / non-delivery reports.
Consider including something in the mail body (perhaps a footer) that mentions where the alert came from and what process generated it. This can help your successor or colleague track down the script in the future.
The assignment like
$mail.SendUsingAccount = $account
worked for me since Windows Server 2000 till Windows Server 2008 and from Outlook 2007 till Outlook 2016. Since Windows Server 2016 I've got an exception (The server threw an exception. (Exception from HRESULT: 0x80010105 (RPC_E_SERVERFAULT))).
But there is an alternative way to assign this property.
[Void] $mail.GetType().InvokeMember("SendUsingAccount","SetProperty",$NULL,$mail,$account)

Register-ObjectEvent Event Subscription Uptime

We have a data dump come from an external entity on a daily basis. Once we receive the file, a Object Event Listener triggers, moves the file into two separate locations (one live, one backup) and then calls a MS SQL stored procedure to import the file into the database.
The process and my script seem to function perfectly fine. The file moves, and the SQL is executed. However, every morning when I check to see if it triggered, nothing triggered. I check for event-subscribers by calling Get-EventSubscriber and there are no listeners registered. Once I register the listeners and move the file into the input location, everything runs fine.
I understand that the Event Subscriptions do not persist through reboots, but how long do they stay open? is it possible that something is closing them? or do they time out?
$watchFolder = "\\server\c$\path\to\inbound\"
$filter = "*.txt"
$fsw = New-Object IO.FileSystemWatcher $watchFolder, $filter -Property #{
IncludeSubdirectories = $false
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileMonitor -Action {
$filePath = $Event.SourceEventArgs.FullPath
$fileName = $Event.SourceEventArgs.Name
Write-Host "Source File: $fileName"
$success = copyFile($fileName, $filePath) #custom function to copy file to multiple destinations
if ($success) {
Write-Host "Starting SQL_JOB_NAME Job"
Set-Location SQLSERVER:\SQL\server\DEFAULT\Databases\msdb\
$execute_import = "EXEC dbo.sp_start_job N'SQL_JOB_NAME';"
Invoke-Sqlcmd -SuppressProviderContextWarning -Query $execute_import
} else {
Write-Host "Something failed along the way: `r`n"
}
}
As silly as it seems, I learned here that calling Register-ObjectEvent if the PowerShell process is closed, the ObjectEvent is also unregistered.
Because the nature of the project required us to have an always-on file listener, we decided that Powershell was not the correct implementation for us.
Instead we implemented a Windows service using the .NET libraries, which are the same used here in PowerShell.
Thanks to PetSerAl for his prompt answer.

Send email via Powershell and Outlook

I have a .msg file on my filesystem. With powershell I can open a Outlook window with the message simply like this:
Invoke-Item "MY MAIL.msg"
How to change the subject and forward it to a given address via Powershell?
Thanks in advance
We had a problem that required the email to be forwarded from Outlook, there was 3000~ emails to do.
The answer Iain had given led me down the path to success, so thank you.
However it did not work for me as given, it failed. I noticed that you need to save the method of the forward to a variable and then execute the code from that, below is my complete script for looping through each msg file in a folder and forwarding it to a person.
I also left the subject as it was and gave no body as this was not needed.
#Open Outlook and get a list of emails to forward
$Outlook = New-Object -comObject Outlook.Application
$Emails = Get-ChildItem -Path C:\Users\APerson\Documents -Filter *.msg
#Loop through each email and open it up
Foreach($Email IN $Emails){
$Message = $Outlook.Session.OpenSharedItem($($Email.FullName))
$Forward = $Message.Forward()
$Forward.Recipients.Add('a.person#gmail.com')
$Forward.Send()
#Sleep is optional :D
Start-Sleep -Seconds 1
}
#Close Outlook
$Outlook.Quit()
Also noticed if you have a security policy applied to Outlook that is stopping you from running this script, for example it will remove the Add() on recipients, just import these registry settings (can be saved as a reg file):
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Policies\Microsoft\office\14.0\outlook\security]
"PromptOOMSend"=dword:00000002
"PromptOOMAddressBookAccess"=dword:00000002
"PromptOOMAddressInformationAccess"=dword:00000002
"PromptOOMMeetingTaskRequestResponse"=dword:00000002
"PromptOOMSaveAs"=dword:00000002
"PromptOOMFormulaAccess"=dword:00000002
"PromptSimpleMAPISend"=dword:00000002
"PromptSimpleMAPINameResolve"=dword:00000002
"PromptSimpleMAPIOpenMessage"=dword:00000002
You could try something like this, works with outlook 2010
$ol = New-Object -comObject Outlook.Application
gm -InputObject $ol
$mail = $ol.Session.OpenSharedItem("C:\Users\fred\Desktop\Test Email Subject.msg")
$mail.Forward()
$Mail.Recipients.Add("fred#bloggs.com")
$Mail.Subject = "Test Mail"
$Mail.Body = " Test Mail 22222 "
$Mail.Send()
In PowerShell 2.0 there is a Send-MailMessage cmdlet that allows you to attach files, specify a subject and a recipient e.g.:
Send-MailMessage -smtpServer smtp.doe.com -from 'joe#doe.com' `
-to 'jane#doe.com' -subject 'Testing' -attachment foo.txt
Not sure how that plays with .msg files but you might give it a try.