Sending a properly email with line breaks - powershell

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

Related

Need to append this powershell script, not sure what to do

I need some help expanding on this script. Basically, I need to add when the $inputFileName = 'Report.txt' is not in its default dir when the script runs every morning the job spits out an e-mail saying no file to process, and then the job stops. What I am seeing is when there is no file in the source dir every now and then, the job runs attaching a blank .xls file that is of no use. I appreciate ANY help in advance!
$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -path C:\PATH\Logoutput.txt -append
$emailFilePath = 'C:\PATH\PATH\'
$inputFilePath = 'C:\PATH\PATH\Upload'
$inputFileName = 'Report.txt'
$inputFile = Join-Path $inputFilePath $inputFileName
$outputFileName = 'Report.csv'
$outputFilePath = 'C:\PATH\PATH\Send'
$OutputFile = Join-Path $outputFilePath $outputFileName
$folder = 'C:\PATH\PATH\Upload'
$filter = 'Report.txt'
$destination = $outputFilePath
$dateTime1 = Get-Date -Format s
Write-Host "The file was received: $dateTime1"
Import-CSV $inputFile -Delimiter "`t" -Header "Value 1" , "Value 2" , "Value 3" , "Value 4" , "Value 5" | Tee-Object -Variable Report.txt | Export-CSV $OutputFile -Delimiter "," -NoTypeInformation
$xl = new-object -comobject excel.application
$xl.visible = $false
$Workbook = $xl.workbooks.open("$OutputFile")
$Worksheets = $Workbooks.worksheets
$Workbook.SaveAs("$outputFilePath\Report.xls",1)
$Workbook.Saved = $True
$xl.Quit()
$objExcel = new-object -comobject excel.application
$objExcel.Visible = $false
$objWorkbook = $objExcel.Workbooks.open("$outputFilePath\Report.xls")
$objWorksheet = $objWorkbook.Worksheets.Item(1)
$objRange = $objWorksheet.UsedRange
[void] $objRange.EntireColumn.Autofit()
$objWorkbook.SaveAs("$outputFilePath\Report.xlsx",51)
$objWorkbook.Saved = $True
$objExcel.Quit()
$fromaddress = "user#domain.com"
$toaddress = "user#domain.com"
$bccaddress = ""
$CCaddress = "user#domain.com"
$Subject = "Here Is The Report"
$body = get-content $emailFilePath\content.htm
$attachment = "$outputFilePath\Report.xlsx"
$smtpserver = "smtpdomain"
$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
$smtp = new-object Net.Mail.SmtpClient($smtpserver)
$smtp.Send($message)
$dateTime2 = Get-Date -Format s
Write-Host "The file was parsed and emailed at $dateTime2"
Start-Sleep -Seconds 60
$message.Dispose()
Start-Sleep -Seconds 60
kill -processname Excel
Start-Sleep -Seconds 60
Remove-Item "C:\PATH\PATH\Send\*.*"
$filenameFormat = "Report" + "" + (Get-Date -Format "yyyy-MM-dd") + ".txt"
$updatedFile = "C:\PATH\PATH\Upload\" + $filenameFormat
Rename-Item -Path "C:\PATH\PATH\Upload\Report.txt" -NewName $filenameFormat
Move-Item -Path $updatedFile -Destination C:\PATH\PATH\ArchivedReportData
Stop-Transcript
exit
You need to test for the file before processing as follows:
If ( -not (Test-Path -Path "inputFile")) {
#Write your file not found logic/messages here
Exit
}
Import-CSV $inputFile -Delimiter "`t" -Header "Value 1" , "Value 2" , "Value 3" , "Value 4" , "Value 5" | Tee-Object -Variable Report.txt | Export-CSV $OutputFile -Delimiter "," -NoTypeInformation
$dateTime1 = Get-Date -Format s
Write-Host "The file was received: $dateTime1"
...
HTH

Powershell Event Log Reporting

I'm working on a PS script to collect on certain Event IDs and spit them back every hour or so. I'm doing this because I want to spit it out to email for ease of reading.
My problem right now is that the script will run up to a certain point and hang. If I remove the date filters, it runs well. As soon as I re-add them (either through variables or hard-coded) it does it's hanging thing again. I need the date filters, however, because otherwise I'm getting everything when I'm looking for hourly chunks.
Looking for advice as I'd like to use variables for the one-offs or modifications! I'd also like to use spinoffs for other side reporting as well.
$filedate = (get-date).ToString("MM_dd_yy-hh_mm")
$filename = "bad_logins_DC01 " + $filedate + "_log.txt"
$after = (get-date).addhours(-1)
$before = (get-date)
$eventlog = Get-EventLog -ComputerName DC01 -LogName Security -After $after -Before $before
$eventlog | ?{$_.EventID -eq 4771 -or $_.EventID -eq 4776 } | Select #{Name="Event ID";Expression={$_.InstanceID}},#{Name="UserName";Expression={$_.ReplacementStrings[0]}},#{Name="Failure Code";Expression={$_.ReplacementStrings[4]}},#{Name="Host";Expression={$_.ReplacementStrings[6]}},#{Name="Port";Expression={$_.ReplacementStrings[7]}}, #{Name="Time";Expression={$_.TimeGenerated}} | ft | Out-File $filename -append -noclobber
$to = itsupport#ourdomain.com
$from = itsupport#ourdomain.com
$subject = $filename
$smtp = exchange.ourdomain.com
$contents = cat $filename
$body = $contents
Send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $body -Attachments $filename
Got it!
Big thanks to TheMadTechnicial for the assist on Get-WinEvent instead of Get-EventLog
$query_sec = #"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*`
[System[Provider[#Name='Microsoft-Windows-Security-Auditing'] and `
TimeCreated[timediff(#SystemTime) <= 7200000] and `
(EventID=4771 or EventID=4776)]]</Select>
</Query>
</QueryList>
"#
$time = (Get-Date).ToString("dd-MM_hh-mm")
$to = "itsupport#mydomain.com"
$from = "me#mydomain.com"
$smtpServer = "mxserver.mydomain.com"
Try
{
$domain_controller = "DC01","C02","DC03"
ForEach ($dc in $domain_controller)
{
$Events = Get-WinEvent -ComputerName $dc -FilterXml $query_sec -ErrorAction Stop
ForEach ($event in $Events)
{
$eventXML = [xml]$Event.ToXml()
For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++)
{
Add-Member -InputObject $Event -MemberType NoteProperty -Force `
-Name $eventXML.Event.EventData.Data[$i].Name `
-Value $eventXML.Event.EventData.Data[$i].'#text'
}
}
$filename = "C:\temp\"+$dc+"_failed_logins_"+$time+".txt"
$Events | Select-Object #{Name="UID";Expression={$_.TargetUserName}},`
ServiceName,`
#{Name="Error";Expression={$_.Status}},`
#{Name="IP";Expression={$_.IpAddress}},`
#{Name="Port";Expression={$_.IpPort}},`
#{Name="Event ID";Expression={$_.ID}},`
#{Name="Source";Expression={$_.MachineName}}`
| FT `
| Out-File $filename
$subject = "Bad Logins on " + $dc + " at " + $time
$body = Get-Content -Path $filename -Raw
Send-MailMessage -To $to -Subject $subject -From $from -SmtpServer $smtpServer -Body $body
}
}
Catch [Exception]
{
Write-Output " "
Write-Output "$dc has no relevant event logs!"
}

Powershell search for longfile path names and send the owner of a file a mail to do something about it

I am trying to set up a PowerShell script which reads out a UNC path on Windows and searches for longfiles/paths. After it has found the file it needs to send a mail to the owner of the file.
I have found already a script and tweaked it a bit but it doesn't seems to work yet. The following script can find the long file path now but the mail is not working properly.
$limit = 90
$testpath = "C:\test"
$resultpath = "c:\test"
$admins = "moh#test.com"
$from = "moh#test.com"
$smtpserver = "smtp.office365.com"
Get-ChildItem -Path $testpath -Recurse | ?{$_.fullname.length -gt $limit} |
Select-Object fullname,
#{n="owner";e={
$_.GetAccessControl().GetOwner('System.Security.Principal.NTAccount')}},
#{n="namelength"; e={$_.fullname.length}} |
%{
Out-File -FilePath "$resultpath\Longfiles of $($_.owner -replace "\\","-").txt" -Append -InputObject "$($_.namelength) - $($_.fullname)"
}
Get-ChildItem $resultpath -Filter "longfiles of *" | % {
if($_.name -match "Longfiles\sof\s(.+)\.txt"){
$user = $matches[1] -replace "-","\"
$ntacc = New-Object System.Security.Principal.NTAccount($user)
$sid = $ntacc.Translate([System.Security.Principal.SecurityIdentifier])
$aduser = [ADSI]"LDAP://<SID=$sid>"
$email = $aduser.Properties.mail
if($email) {Send-MailMessage -Attachments $_.fullname -Body "Please change the filenames of the files listed in the attached file to shorter!"
-From $from -SmtpServer $smtpserver -Subject "System notice" -To
$email -cc $admins
}
else {
Send-MailMessage -Attachments $_.fullname -Body "email coudn't be sent to owner" `
-From $from -SmtpServer $smtpserver -Subject "System notice" -To $admins
}
}
else {Write-Host "Some error with file $_"}
}
EDIT: This is what i see, after running the script... it is asking me to fill in the fields, while the fields are already filled in in the script such as (From: moh#test.com to moh#test.com)
[]
You issue was because of line breaks in the middle of a command. In some lines, you had a backtick character which escapes the end of the line. But as you found these are really easy to break and that's why it's best practice to use splatting on commands with many parameters.
I also changed your Select-Object calculated properties into a more readable [pscustomobject] since they are hard to format in a readable way, but this does require PS3+.
$limit = 90
$testpath = "C:\test"
$resultpath = "c:\test"
$admins = "moh#test.com"
$from = "moh#test.com"
$smtpserver = "smtp.office365.com"
Get-ChildItem -Path $testpath -Recurse |
Where-Object {$_.fullname.length -gt $limit} |
ForEach-Object {
[PSCustomObject]#{
'fullname' = $_.fullname
'owner' = $_.GetAccessControl().GetOwner('System.Security.Principal.NTAccount')
'namelength' = $_.fullname.length
}
} |
ForEach-Object {
Out-File -FilePath "$resultpath\Longfiles of $($_.owner -replace "\\","-").txt" -Append -InputObject "$($_.namelength) - $($_.fullname)"
}
Get-ChildItem $resultpath -Filter "longfiles of *" | ForEach-Object {
if ($_.name -match "Longfiles\sof\s(.+)\.txt") {
$user = $matches[1] -replace "-", "\"
$ntacc = New-Object System.Security.Principal.NTAccount($user)
$sid = $ntacc.Translate([System.Security.Principal.SecurityIdentifier])
$aduser = [ADSI]"LDAP://<SID=$sid>"
$email = $aduser.Properties.mail
if ($email) {
$mailparams = #{
'Attachments' = $_.fullname
'Body' = "Please change the filenames of the files listed in the attached file to shorter!"
'From' = $from
'SmtpServer' = $smtpserver
'Subject' = "System notice"
'To' = $email
'cc' = $admins
}
Send-MailMessage #mailparams
} else {
$mailparams = #{
'Attachments' = $_.fullname
'Body' = "email coudn't be sent to owner"
'From' = $from
'SmtpServer' = $smtpserver
'Subject' = "System notice"
'To' = $admins
}
Send-MailMessage #mailparams
}
} else {
Write-Host "Some error with file $_"
}
}
Remove the line breaks or escape them with a backtick: `. Your script must actually look like this:
if ($email) {
Send-MailMessage -Attachments $_.fullname -Body "Please change the filenames of the files listed in the attached file to shorter!"
-From $from -SmtpServer $smtpserver -Subject "System notice" -To
$email -cc $admins
}
else {
Send-MailMessage -Attachments $_.fullname -Body "email coudn't be sent to owner" `
-From $from -SmtpServer $smtpserver -Subject "System notice" -To $admins
}
And Powershell doesn't know that the line beginning with -From is part of Send-MailMessage.

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

Send Email of PowerShell Output

I'm new to PowerShell, I'm running Windows Server 2012 R2. The following Script gives me Output what I want but in the message the output is not appearing and it saying the Body cannot be "null" or "empty".
$fileToLocate = "*"
$Directories = #(
"C:\CtvFTPSite\AE1\ASN\Undelivered\",
"C:\CtvFTPSite\AE1\Invoices\Undelivered\",
"C:\CtvFTPSite\AE1\SO\Undelivered\",
"C:\CtvFTPSite\AE2\ASN\Undelivered\",
"C:\CtvFTPSite\AE2\Invoices\Undelivered\",
"C:\CtvFTPSite\AE2\SO\Undelivered\",
"C:\CtvFTPSite\BH1\ASN\Undelivered\",
"C:\CtvFTPSite\BH1\Invoices\Undelivered\",
"C:\CtvFTPSite\BH1\SO\Undelivered\",
"C:\CtvFTPSite\KW1\ASN\Undelivered\",
"C:\CtvFTPSite\KW1\Invoices\Undelivered\",
"C:\CtvFTPSite\KW1\SO\Undelivered\",
"C:\CtvFTPSite\OM1\ASN\Undelivered\",
"C:\CtvFTPSite\OM1\Invoices\Undelivered\",
"C:\CtvFTPSite\OM1\SO\Undelivered\",
"C:\CtvFTPSite\SA1\ASN\Undelivered\",
"C:\CtvFTPSite\SA1\Invoices\Undelivered\",
"C:\CtvFTPSite\SA1\SO\Undelivered\"
)
$filesUndelivered = Join-Path -Path $Directories -ChildPath $fileToLocate | Where-Object{Test-Path $_} | ForEach-Object{
Get-ChildItem $Directories -Recurse | % { Write-Host $_.FullName }
}
$Max_mins = "-5"
$Curr_date = get-date
$username = "myusername#myemail.com"
$password = Get-Content C:\security\string.txt | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
$localIpAddress = $(ipconfig | where {$_ -match 'IPv4.+\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' } | out-null; $Matches[1])
[string]$messagebody ="$filesUndelivered"
[string]$titlefailed ="Urgent You Have Files in Undelivered Folder in $localIpAddress in $env:computername"
$portno = "25"
$smtpsrv = "mail.server.com"
$smtpto = "myusername#myemail.com"
$smtpfrom ="myusername#myemail.com"
if ($filesfailed.Count)
{
foreach ($file in $filesUndelivered) {[string]$messagebody += $file.FullName + "`r`n"}
Send-MailMessage -To $smtpto -From $smtpfrom -port $portno -SmtpServer $smtpsrv -Credential $cred -Subject $titlefailed -Body $messagebody
}
Fixed
$fileToLocate = "*"
$failedpath = #(
"C:\CtvFTPSite\AE1\ASN\Undelivered\",
"C:\CtvFTPSite\AE1\Invoices\Undelivered\",
"C:\CtvFTPSite\AE1\SO\Undelivered\",
"C:\CtvFTPSite\AE2\ASN\Undelivered\",
"C:\CtvFTPSite\AE2\Invoices\Undelivered\",
"C:\CtvFTPSite\AE2\SO\Undelivered\",
"C:\CtvFTPSite\BH1\ASN\Undelivered\",
"C:\CtvFTPSite\BH1\Invoices\Undelivered\",
"C:\CtvFTPSite\BH1\SO\Undelivered\",
"C:\CtvFTPSite\KW1\ASN\Undelivered\",
"C:\CtvFTPSite\KW1\Invoices\Undelivered\",
"C:\CtvFTPSite\KW1\SO\Undelivered\",
"C:\CtvFTPSite\OM1\ASN\Undelivered\",
"C:\CtvFTPSite\OM1\Invoices\Undelivered\",
"C:\CtvFTPSite\OM1\SO\Undelivered\",
"C:\CtvFTPSite\SA1\ASN\Undelivered\",
"C:\CtvFTPSite\SA1\Invoices\Undelivered\",
"C:\CtvFTPSite\SA1\SO\Undelivered\"
)
$Max_mins = "-5"
$Curr_date = get-date
$username = "username#email.com"
$password = Get-Content C:\security\string.txt | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
$filesfailed = Get-ChildItem -Path $failedpath | Where{$_.CreationTime -lt ($Curr_date).addminutes($Max_mins)}
$localIpAddress = $(ipconfig | where {$_ -match 'IPv4.+\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' } | out-null; $Matches[1])
[string]$messagebody =""
[string]$titlefailed ="Urgent You Have Files in Undelivered Folder in $localIpAddress in $env:computername"
$portno = "25"
$smtpsrv = "mail.server.net"
$smtpto = "username#email.com"
$smtpfrom ="username#email.com"
if ($filesfailed.Count)
{
foreach ($file in $filesfailed) {[string]$messagebody += $file.FullName + "`r`n"}
Send-MailMessage -To $smtpto -From $smtpfrom -port $portno -SmtpServer $smtpsrv -Credential $cred -Subject $titlefailed -Body $messagebody
}