PowerShell multiple email recipients (attachment) from csv / empty cell issue - powershell

I recently started to work on PS script for email automation.
Manage to put something together where I have CSV file from where PowerShell is extracting data (multiple recipients, attachment, etc).
The problem is, when some of the cells are empty, script won`t work.
There is one similar question, but I am just not sure how to implement solution on my case:
$importFile = "Users.csv"
$users = import-csv $importFile | select *
foreach($user in $users)
{
$Name = $user.'Name'
$to = $user.'To'
$to2 = $user.'To2'
$Attachment = $user.'Attachment'
$Attachment2 = $user.'Attachment2'
$write = "Emailing account " + $to + " ..."
Write-Host $write
$body = [string]::join([environment]::newline, (Get-Content -path $emailFile))
$body = $body.Replace('[Name]', $Name)
$mail = New-Object System.Net.Mail.MailMessage
$mail.From = $emailFrom
$mail.To.Add($to)
$mail.To.Add($to2)
$mail.Subject = $emailSubject
$mail.IsBodyHtml = $true
$mail.Body = $body
$mail.Attachments.Add($Attachment)
$mail.Attachments.Add($Attachment2)
$smtp = New-Object System.Net.Mail.SmtpClient
$smtp.Host = $smtpServerHost
$smtp.Port = $smtpServerPort
$smtp.EnableSsl = $smtpServerSsl
$smtp.UseDefaultCredentials = $false
$smtp.Credentials = $credentials
$smtp.Send($mail)
This is how looks CSV file
Any suggestion is more than welcome :)

Try Where-Object to filter out rows.
$users = Import-Csv $importFile |
Where-Object {$_.Name -ne ""} |
Select-Object *
For what it is worth: if the whole "row" is blank you can shortcut this to simply be
...
Where-Object {$_} |
...

Implementing IF function resolved the case. For example if ($to2 -ne '') is checking if $to2 cell is empty. If no, then $mail.To.Add($to2). The same situation for $Attachment. Here is the code:
$mail = New-Object System.Net.Mail.MailMessage
$mail.From = $emailFrom
$mail.To.Add($to)
if ($to2 -ne '') {
$mail.To.Add($to2)
}
$mail.Subject = $emailSubject
$mail.IsBodyHtml = $true
$mail.Body = $body
$mail.Attachments.Add($Attachment)
if ($Attachment2 -ne '') {
$mail.Attachments.Add($Attachment2)
}

Related

Powershell to monitor a folder and send email when there are new files

I need some assistance on how to create a powershell to monitor a folder and subfolders and send an email every 15 minutes for example, with a list of files that added to this folder
I will set up a schedule task to run every 15 minutes
Email output will be something like:
File Name, Path
TEST.TXT uploaded to C:\ROOT\BUSINESS
test2.txt uploaded to C:\ROOT\BUSINESS\May2021
Here is what I have so far. Any help is appreciated.
SMTPServer = "EMAIL SERVER (ip)"
$SMTPPort = "111"
$Username = "SENDER#EMAIL.COM"
$path="C:\ROOT\BUSINESS\"
$to = "test1#gmail.com"
$cc = "test2#gmail.com"
$subject = " New File available "
$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.to.add($to)
$message.cc.add($cc)
$message.from = $username
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
#$smtp.Credentials = New-Object System.Net.NetworkCredential $Username;
If ($File = Get-ChildItem $Path | Where { $_.LastWriteTime -ge [datetime]::Now.AddMinutes(-15) }){
$smtp.send($message)}
write-host "Mail Sent"
Thanks
Try this condition:
if ((Get-ChildItem $Path | Where { $_.LastWriteTime -ge [datetime]::Now.AddMinutes(-15) }).Count -ge 1){ <# do something #> }

Using Powershell to Do Action Every Time a Specific Outlook Email is Received

I receive a lot of emails from people to copy a file from one file location to another. I would like my Powershell program to automate this process that whenever I receive an email with a specific subject line, my program completes the action above and sends an email to the sender that this has been completed. My copy and paste code, testing the path, and sending an email by themselves work. Running the code in its entirety doesn't give me an error but also doesn't do anything. I have left comments in the code below where I think the problems are (can't be sure though)
Add-Type -assembly "Microsoft.Office.Interop.Outlook"
$outlook = New-Object -ComObject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
$emails = $inbox.Items | Where-Object {$_.subject -match ‘COPY FILE’} #I think might be wrong
if ($_.subject -match 'COPY FILE') #I think might be wrong
{
Copy-Item -Path ($oldLocation + $fileName) -Destination $newLocation
if (Test-Path -Path ($newLocation + $fileName))
{
$mail = $outlook.CreateItem(0)
$mail.To = $sender
$mail.Subject = "Completed"
$mail.Body = "File has been successfully moved"
$mail.Send()
}
else
{
$mail = $outlook.CreateItem(0)
$mail.To = $sender
$mail.Subject = "Failed"
$mail.Body = "File does not exist in $newLocation"
$mail.Send()
}
}
Your If statement is referring to $_ but there's no surrounding loop or pipeline.
Just a suggestion but maybe:
Add-Type -assembly "Microsoft.Office.Interop.Outlook"
$outlook = New-Object -ComObject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
$emails = $inbox.Items | Where-Object {$_.subject -match ‘COPY FILE’} #I think might be wrong
$Emails |
ForEach-Object{
if ($_.subject -match 'COPY FILE') #I think might be wrong
{
Copy-Item -Path ($oldLocation + $fileName) -Destination $newLocation
if (Test-Path -Path ($newLocation + $fileName))
{
$mail = $outlook.CreateItem(0)
$mail.To = $sender
$mail.Subject = "Completed"
$mail.Body = "File has been successfully moved"
$mail.Send()
}
else
{
$mail = $outlook.CreateItem(0)
$mail.To = $sender
$mail.Subject = "Failed"
$mail.Body = "File does not exist in $newLocation"
$mail.Send()
}
}
}
Also; I don't know if they are defined elsewhere but I don't see any definition for $oldlocation, $filename, or $newlocation. I'd have thought you need to parse those out of the subject or body of the message.
$Sender, might need to be $_.Sender in this example.

Single line break in body of powershell MailMessage not working

For some reason when attempting to populate the body of an email in powershell, a single line break using the `n escape sequence is not working, however a double is.
This is my code...
param([string]$BuildId, [string]$BuildName)
$EmailTo = "[email]"
$EmailFrom = "sepaautomation#gmail.com"
$Subject = "$BuildName $BuildId SpecFlow Reports"
$Body = "The following SpecFlow reports are attached: `n`n"
$SMTPServer = "smtp.sendgrid.net"
$date = Get-Date -Format yyyy-MM-dd
$files = Get-ChildItem "C:\Build\SA.SEPA.Web.UI.Selenium" -Recurse | Where-Object { $_.Name -match "^.*$date.*\.html$" } | % { $_.FullName }
foreach($item in $files)
{
$Body += "$item `n"
}
$SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$EmailTo,$Subject,$Body)
foreach($item in $files)
{
$attachment = New-Object System.Net.Mail.Attachment($item)
$SMTPMessage.Attachments.Add($attachment)
}
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("apikey", "[apiKey]");
$SMTPClient.Send($SMTPMessage)
This is the section that is failing to add a line break
foreach($item in $files)
{
$Body += "$item `n"
}
My email in outlook looks like the following....
You can see that the `n `n double line break has been applied but not the `n. Incidentally if I change to...
foreach($item in $files)
{
$Body += "$item `n`n"
}
I do see a double line break.
How do I get just a single line break?
Just go with [Environment]::NewLine to resolve this one. It will take away most headaches relating to this issue.
Usage:
foreach($item in $files)
{
$Body += "$item " + [Environment]::NewLine
}
If you OK to use HTML body you can use <br> for line breaks.
You will need to set following property on your message variable:
$SMTPMessage.IsBodyHTML = $true
$Body += "$item <br>"

How to attach excel files in an email using powershell

I have the following select statement that extract data from a SQL Server database table:
$QUERY = "SELECT * FROM Table1"
$DataVariable = Invoke-Sqlcmd -ServerInstance "MyInstance" -Database "MyDB" -Query $QUERY
How can I attach the $DataVariable as an excel file in my email?
I am working on the code below:
$Date = get-date -format "dd-MMM-yyyy"
$Day = $Date.DayOfWeek
$DateTested = $Date
$filename = "MYReport_$(get-date -f yyyy-MM-dd).XLS"
$OutputFile = "\\server\c$\Output\$filename"
I don't seem to go anywhere with this. Can anyone assist please?
Thanks
Your code snippets don't seem to be related to one another
there is no attempt to mail anything
I suggest to save $Datavarable to csv (xlsx is also possible)
this raw example script uses gmail and splatting to fill the parameters
$QUERY = "SELECT * FROM Table1"
$DataVariable = Invoke-Sqlcmd -ServerInstance "MyInstance" -Database "MyDB" -Query $QUERY
$filename = "MYReport_$(get-date -f yyyy-MM-dd).csv"
$OutputFile = "\\server\c$\Output\$filename"
$DataVariable | Export-Csv $OutPutFile -NoTypeInformation
$emailAcc = "youraccount#gmail.com"
$Cred = Get-Credential -UserName $emailAcc -Message "Enter gmail password for $emailAcc"
$MsgParam = #{
From = $emailAcc
To = "recipient#domain.com"
Subject = $filename
Body = 'blah blah sending $filename'
Attachments = $OutPutFile
SmtpServer = "smtp.gmail.com"
}
Send-MailMessage #MsgParam -UseSSL -cred $Cred
I have managed to build the code below and it worked for me !!!!!!!!!!!!!!:
$DataVariable = Invoke-Sqlcmd -ServerInstance $ResultsInstance -Database $ResultsDatabase -Query $SQL
$Date = get-date -format "dd-MMM-yyyy"
$Day = $Date.DayOfWeek
$DateTested = $Date
$filename = "MyReport_$(get-date -f yyyy-MM-dd).csv"
$OutputFile = "\\serverName\c$\Output\$filename"
$DataVariable | Export-csv $OutPutFile -NoTypeInformation
$to = "Support"
$body = "Dear <b><font color=black>$to</b></font> <br>"
$body += "<p>Please find attached report.</p> <br>"
$body += "Kind Regards<br>"
$body += "Dev Team <br>"
$fromaddress = "xyz#xyz.com"
#$toaddress = "x#ytm.com"
$toaddress = "x#ytm.com"
$bccaddress = "x#ytm.com"
$CCaddress = "x#ytm.com"
$Subject = "My weekly report"
$attachment = $OutputFile
$smtpserver = "xyzmail"
####################################
$message = new-object System.Net.Mail.MailMessage
$message.From = $fromaddress
$message.To.Add($toaddress)
$message.CC.Add($CCaddress)
$message.Bcc.Add($bccaddress)
$message.IsBodyHtml = $True
$message.Subject = $Subject
$attach = new-object Net.Mail.Attachment($attachment)
$message.Attachments.Add($attach)
$message.body = $body
$message.Priority = [System.Net.Mail.MailPriority]::High
$smtp = new-object Net.Mail.SmtpClient($smtpserver)
if ($DataVariable) {
$smtp.Send($message)
Write-Host "The variable is not null" }

Search for a file that matches a keyword, then attach it to an email

I've written a PowerShell script that searches a folder for a file that matches a keyword eg Japan and then adds the file as an attachment to an email.
The email sends correctly, however the file isn't attached.
Add-PSSnapin Microsoft.Exchange.Management.Powershell.Admin -ErrorAction
SilentlyContinue
$dir = "C:\Users\user\Desktop"
$file = Get-ChildItem -Path $dir | -Filter "$keyword" -Recurse | Select-Object
$keyword = "Japan"
$mailboxdata = (Get-MailboxStatistics | select DisplayName,TotalItemSize,TotalDeletedItemSize, ItemCount, LastLoggedOnUserAccount, LastLogonTime)
$mailboxdata | Export-Csv "$file"
$smtpServer = "192.168.1.100"
$att = New-Object Net.Mail.Attachment($file)
$msg = New-Object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$msg.From = "email#mail.com"
$msg.To.Add("email#othermail.com")
$msg.Subject = "Notification from email server"
$msg.Body = "Attached is the email server mailbox report for Japan"
$msg.Attachments.Add($att)
$smtp.Send($msg)
$att.Dispose()
You've modified a script from another source (that sends Mailbox Statistics from Microsoft Exchange) and you've left in parts of it that you do not need.
$dir = "C:\Users\user\Desktop"
$keyword = "Japan"
$smtpServer = "192.168.1.100"
$file = Get-ChildItem -Path $dir -Filter "*$keyword*" -Recurse
$att = New-Object Net.Mail.Attachment($file)
$msg = New-Object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$msg.From = "email#mail.com"
$msg.To.Add("email#othermail.com")
$msg.Subject = "Notification from email server"
$msg.Body = "Attached is the email server mailbox report for Japan"
$msg.Attachments.Add($att)
$smtp.Send($msg)
$att.Dispose()
I would use Send-MailMessage instead as it's syntax is much easier to use:
$dir = "C:\Users\user\Desktop"
$keyword = "Japan"
$Attachment = Get-ChildItem -Path $dir -Filter "*$keyword*" -Recurse
$From = "email#mail.com"
$To = "email#othermail.com"
$Subject = "Files matching: $keyword"
$Body = "Attached is the file for: $keyword"
$SMTPServer = "192.168.1.100"
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Attachments $Attachment.FullName