Single line break in body of powershell MailMessage not working - powershell

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>"

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 #> }

Sending a properly email with line breaks

I am attempting to send the log files contents in the body of an email using Send-MailMessage. I tried using `r`n to no effect.
My email in outlook looks like the following....
My desired mail output :
Here is my script :
$SourceDir = "C:\Temp\"
#$GCI_Fiter = '*.txt'
$Include=#("*.log","*.txt")
$FileList = Get-ChildItem -LiteralPath $SourceDir -Include "$Include" -File
$myvar = #()
foreach ($FL_Item in $FileList) {
#$FLI_Content = Get-Content -LiteralPath $FL_Item.FullName
#$ExceptionLines = $FLI_Content | Select-String 'Exception' | ForEach-Object {$_.ToString().Trim()}
#if ($FLI_Content Get-Content -Path $file.FullName | Select-String "Exception" )
#){
$results = Get-Content -Path $FL_Item.FullName | Select-String "Exception"
if ($results) {
Write-Host "$($FL_Item.FullName) Exception found." -BackgroundColor Cyan
#$myvar += $results
$LINE = "$($FL_Item.Name)" + ":"
$EMAILBODY = $LINE + "`r`n"
$myvar += $EMAILBODY + $results + "`r`n"
Write-Output "Exception found"
}
else {
Write-Host "$($FL_Item.FullName) No exception found." -BackgroundColor Green
Write-Output "No exception found"
}
#}
#$ExceptionLines = $FLI_Content | Select-String -SimpleMatch 'Exception olustu'
#$ExceptionLines = $FLI_Content | Select-String -SimpleMatch 'Exception' | ForEach-Object {$_.ToString().Trim()}
#$FLI_Content
}
return $myvar
$MailBody = "Hi,`r
Exception logs. `r
"+$myvar+"
`r
`r
Regards,
"
Send-MailMessage -to $emailto -Subject $subject -SmtpServer $smtp -From $fromaddress -Body $MailBody -Encoding ([System.Text.Encoding]::UTF8) -Credential $creds
Another way is to use $Outlook = New-Object -ComObject Outlook.Application. I have come across a similar case. If you are using Outlook for example use the below code, however you format the email in the $Mail.Body, that is how they will receive the email.
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
$Mail.To = "usermail#something.com"
$Mail.Subject = "Powershell"
$Mail.Body ="email text here"
$Date = (Get-Date).tostring("yyyyMMdd")
$File = "C:\Users\user\Desktop\log$Date.csv"
$Mail.Attachments.Add($File)
$Mail.Send()

Remove-Item cmdlet not working properly

So I have a script that combs through a directory of about 1200 songs, the user selects one song, (which is then put into the $Selected variable) and then through "script magic" (I can provide the code if necessary, but I don't think it is for our purposes) an email is sent to an email account I need it sent to. I then want to delete the song from the directory aaaannnnndddd that is when I run into issues. Here is the code I originally tried to delete the song with:
Remove-Item C:\Users\woafr\Desktop\Songs\$Selected -recurse -force
And with that code I got hit with this error message:
Remove-Item : Cannot remove item C:\Users\woafr\Desktop\Songs\song.mp3: The process cannot access the file C:\Users\woafr\Desktop\Songs\song.mp3' because it is being used by another process
So I then read this artice and this Stack Overflow thread and this Server Fault thread and modified my code to this:
Get-ChildItem C:\Users\woafr\Desktop\Songs\$Selected -recurse -force | Remove-Item
And still got hit with the same errors. Is there something I can do here that will have me delete the songs, or will I have to do it by hand (the horror!)
Here is the whole script for reference:
# Search Engine part
$SearchInput = Read-Host "Enter song name here:"
$Items = Get-ChildItem C:\Users\woafr\Desktop\Songs -Recurse -Filter *$SearchInput*
IF (-Not $Items)
{Write-Host 'Nothing returned...
The search engine does not care about capitilization (so "That" and "that" are read the exact same by the search engine)
But it does care about punctuation (so "That''s" and "Thats" are not read the same by the search engine). Try Again' -ForegroundColor Red}
# Choose you this day what song you want
IF (-Not $Items)
{cmd /c pause}
$Index = 1
$Count = $Items.Count
foreach ($Item in $Items) {
$Item | Add-Member -MemberType NoteProperty -Name "Index" -Value $Index
$Index++
}
$Items | Select-Object Index, Attributes, LastWriteTime, Name | Out-Host
$Input = Read-Host "Select an item by index number, then press enter (1 to $Count)"
$Selected = $Items[$Input - 1]
Write-Host "You have selected $Selected"
# Email account the script is sending from
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "myemail#gmail.com"
$Password = "mypassword"
# Email the script is sending
$to = "emailtoingest#gmail.com"
$subject = "Songs To Ingest"
$body = "Ingest attachment into WideOrbit"
$attachment = New-Object System.Net.Mail.Attachment("C:\Users\woafr\Desktop\Songs\$Selected")
$attachment.ContentDisposition.FileName = "$Selected"
# Act of sending the email
$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.body = $body
$message.to.add($to)
$message.from = $username
$message.attachments.add($attachment)
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.send($message)
write-host "Mail Sent" -ForegroundColor Green
cmd /c pause
# Trying to delete the damn thing
Get-ChildItem C:\Users\woafr\Desktop\Songs\$Selected -recurse -force | Remove-Item
cmd /c pause
So the problem is send mail objects are locking the file ,try using this snippet just before your remove-item commandlet:
$smtp = $null
foreach ($attachment in $message.attachments){
$attachment.dispose();
}
$message.dispose();

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

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)
}

Getting email Notification Folder count

With this powershell script i'm able get file count on inside a folder
Get-ChildItem D:\ -Recurse -File | Measure-Object | %{$_.Count}
here is the script sending email.
$Count = Get-ChildItem D:\ -Recurse -File | Measure-Object | %{$_.Count}
$Status= $Event.Message
$From = "sender#sender.com"
$To = "receiver"
$SMTPServer = "smtp"
$SMTPPort = "587"
$Username = "email#email.us"
$Password = "password"
$Subject = "$computer,Files count"
$Body = "Number of Files is $Count |D drive test "
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $false
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.Send($From, $To, $subject, $body);
$computer = "$env:computername
But the output is simply plain text Number of Files is 58 |D drive test
can we have it to alert us with some more text like If file count is mismatch it should consider a warning like "number of files is 60 which is large" or if it gets less it should be critical and error.
you have comparison operators:
-lt = lower than
-gt = greater than
-ge = greater or equal
-le = less or equal
-eq = equal
And you have if, elseif and else
with that you can change your body message (as suggested in the answer of DarkMoon)
if ($count -le '50') {
$Body = 'your text'
}
elseif (($count -gt '50') -and ($count -le '100')) {
$Body = 'your text'
}
elseif (($count -gt '100') -and ($count -le '500')) {
$Body = 'your text'
}
else {
$Body = 'your text'
}
For the warning, it'd be simply something along the lines of:
if ($Count -lt 60) {
$Body = "Number of Files is low at $Count |D drive test "
} else {
$Body = "Number of Files is $Count which is large |D drive test "
}