Pass powershell exception to html body for sending mail - html

I have written a powershell script which will check website's 200 status. If it fails to find status 200, then powershell throws exception message and will mail for notification with html body. But i can not pass the throw exception message to html body, it shows direct variable name on html page. Is it possible to pass the varible value to html body?
Here is the script,
try {
$HTTP_Request = [System.Net.WebRequest]::Create('https://google.com/')
$HTTP_Response = $HTTP_Request.GetResponse()
$HTTP_Status = [int]$HTTP_Response.StatusCode
If ($HTTP_Status -eq 200) {
Write-Host "Site is OK!"
}
}
catch {
Write-Host "Website not Okay"
$string_err = $_ | Out-String
Write-Host $string_err
$body = #'
<!DOCTYPE html>
<html>
<body>
<p>Error: $string_err</p>
</body>
</html>
'#
$secpasswd = ConvertTo-SecureString "xxxxxxx" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("xxxxx#gmail.com", $secpasswd)
Send-MailMessage -SmtpServer smtp.gmail.com -Credential $cred -UseSsl -From 'xxxxx#gmail.com' -To 'yyyyyy#gmail.com' -Subject 'Website status Error' -Body $body -BodyAsHtml
Continue
}

Related

How do I embed HTML file content in email body using PowerShell script?

I have one HTML file which contains css and HTML code as shown below.
I want this content to be embedded in email body using Powershell script.
Below is my Powershell script for Email.
$toUsers = #('xxxx#microsoft.com','xxxx#microsoft.com')
$fromUser = "xxxx#microsoft.com"
$smtpServer = "xxx.XXX.corp.xxxx.com"
#$ccUsers = "xxxx#microsoft.com"
$msg = New-Object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.UseDefaultCredentials = $true
#$msg.Body = $html
$msg.Subject="c360 UX test run report" -f (Get-Date -format "yyyy-MM-dd")
foreach($toUser in $toUsers)
{
$msg.To.Add($toUser)
write-host $toUser
}
$body = "<b>Build Number:- $(Build.BuildNumber)<br>"
$body += "Branch Name:- $(Build.SourceBranch) </b> <br>"
$body += "Product Name:- $env:PRODUCT_NAME <br>"
$body +='Click here'
$msg.From = $fromUser
#$msg.CC.Add($ccUsers)
$msg.IsBodyHTML = $true
$msg.Body = $body
$attachmentObject = new-object Net.Mail.Attachment($(Get-ChildItem -Recurse -Path $(System.ArtifactsDirectory) -Filter 'Report.zip').FullName)
$msg.Attachments.Add($attachmentObject)
$msg.Priority="High"
$smtp.Send($msg)
$smtp.Dispose()
$msg.Dispose()
#Wait for a sec to let dispose complete.
sleep 2`enter code here`

Embed images in email and send via Powershell

I am editing one of my old scripts to send an email to a user with images embedded into the text. I am trying to use the Send-MailMessage function to send the email as opposed to the older method of $smtp.send($msg). However, when trying to update the script, the images are no longer being embedded.
I know how to attach them to the email as actual attachments, but I am not sure what I am doing wrong to have them show as actual embedded images.
NOTE: for brevity, I removed some of the full email since it is large and as long as I can get an image or two working, it will all work.
# force powershell to run as an x86 process
Set-ExecutionPolicy -Scope CurrentUser Unrestricted
if ($env:Processor_Architecture -ne "x86") {
&"$env:windir\syswow64\windowspowershell\v1.0\powershell.exe" -file $myinvocation.Mycommand.path
exit
}
# initialize the script
if ($startupvariables) { try {Remove-Variable -Name startupvariables -Scope Global -ErrorAction SilentlyContinue } catch { } }
New-Variable -force -name startupVariables -value ( Get-Variable | ForEach-Object { $_.Name } )
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
$Separator = ".", "#"
# advise what the script does
Add-Type -AssemblyName PresentationCore,PresentationFramework
$ButtonType = [System.Windows.MessageBoxButton]::OKCancel
$MessageIcon = [System.Windows.MessageBoxImage]::Warning
$MessageTitle = "Shared Drive Access Assistance"
$MessageBody = "This script asks the user to provide more information regarding a network drive that they would like access to.`n`nTo use it, enter the below information:`n`n`n`tTicket Number`n`n`tUser's Email Address`n`n`tRequestor's Email Address`n`n`nIf this is the script you want to use, click OK.`nIf not, click Cancel."
$Result = [System.Windows.MessageBox]::Show($MessageBody,$MessageTitle,$ButtonType,$MessageIcon)
if ($Result -eq "Cancel")
{
Exit-PSSession
}
else
{
# get the ticket number
$Ticket = [Microsoft.VisualBasic.Interaction]::InputBox("Enter the SCTask ticket number" , "Ticket Number")
# get the user id via the email address
$UserID = [Microsoft.VisualBasic.Interaction]::InputBox("Enter the user's email address" , "User Email Address")
$User = $UserID.split($Separator)
$Firstname = $User[0].substring(0,1).toupper()+$User[0].substring(1).tolower()
$Lastname = $User[1].substring(0,1).toupper()+$User[1].substring(1).tolower()
$User = $Firstname, $Lastname
# get local username
$Username = [System.Environment]::UserName
# create email
$subject = "Ticket $Ticket on Hold for User Response - Shared Drive Access for $User - Awaiting Additional Information"
$body = #"
<html>
<body style="font-family:calibri">
To $Requestor, $User,<br>
<br>
<br>
In order to proceed with your request for shared drive access, we require the server name and full path to the folder you need access to. If you do not already know this information, you will need to provide these instructions to someone that already has access to the folder that you need access to.<br>
<br>
1) Click the Start menu<br>
<br>
<img src="cid:image1.png"><br>
<img src="cid:image2.png"><br>
<img src="cid:image3.png"><br>
<br>
<br>
2) Navigate to "Computer"<br>
<br>
<img src="cid:image4.png"><br>
<br>
<br>
<br>
If you have any questions or need assistance with this process, please contact the Service Desk via one of the methods listed below.
<br>
<br>
Thank You,<br>
<br>
IT Service Desk<br>
</body>
</html>
"#
$att1 = new-object Net.Mail.Attachment ("T:\PS Scripts\Images\shareddrive1.png")
$att2 = new-object Net.Mail.Attachment ("T:\PS Scripts\Images\shareddrive2.png")
$att3 = new-object Net.Mail.Attachment ("T:\PS Scripts\Images\shareddrive3.png")
$att4 = new-object Net.Mail.Attachment ("T:\PS Scripts\Images\shareddrive4.png")
$att1.ContentId = "image1.png"
$att2.ContentId = "image2.png"
$att3.ContentId = "image3.png"
$att4.ContentId = "image4.png"
# $msg.Attachments.Add($att1)
# $msg.Attachments.Add($att2)
# $msg.Attachments.Add($att3)
# $msg.Attachments.Add($att4)
# create confirmation message
$ButtonType = [System.Windows.MessageBoxButton]::YesNo
$MessageIcon = [System.Windows.MessageBoxImage]::Warning
$MessageTitle = "Shared Drive Access Assistance"
$MessageBody = "The information you have entered is show below:`n`n`nTicket Number: $Ticket`n`nUser's Email Address: $UserID`n`nRequstor's Email Address: $RequestorID`n`n`nIf you would like to send the email, click Yes.`nOtherwise, click No."
$Result = [System.Windows.MessageBox]::Show($MessageBody,$MessageTitle,$ButtonType,$MessageIcon)
if ($Result -eq "No")
{
Exit-PSSession
}
else
# send email
{
Send-MailMessage -To "<$UserID>" -bcc "<$Username#dana.com>" -from "<itservicedesk#x.com>" -Subject $global:subject -SmtpServer "mailrelay.x.com" -BodyAsHtml -body $global:body
}
}
Function Clean-Memory {
Get-Variable |
Where-Object { $startupVariables -notcontains $_.Name } |
ForEach-Object {
try { Remove-Variable -Name "$($_.Name)" -Force -Scope "global" -ErrorAction SilentlyContinue -WarningAction SilentlyContinue}
catch { }
}
}
So the real question is how to embed a image into the HTML document from a attachment
CID aka Content ID will allow you to attach a image and then use that attached image in the document. Avoid using spaces in the Content ID name.
Send-MailMessage -To "Test#Test.com" -from "Test2#Test.com" -SmtpServer SMTP.TEST.NET -Subject "Hello" -BodyAsHtml -Body "<img src='cid:Test.png'>" -Port 25 -Attachments "C:\Users\Test\Test.png"
You are using
$att1 = new-object Net.Mail.Attachment ("T:\PS Scripts\Images\shareddrive1.png")
$att2 = new-object Net.Mail.Attachment ("T:\PS Scripts\Images\shareddrive2.png")
$att3 = new-object Net.Mail.Attachment ("T:\PS Scripts\Images\shareddrive3.png")
$att4 = new-object Net.Mail.Attachment ("T:\PS Scripts\Images\shareddrive4.png")
$att1.ContentId = "image1.png"
$att2.ContentId = "image2.png"
$att3.ContentId = "image3.png"
$att4.ContentId = "image4.png"
but when you send the mail you are not attaching those attachments
Send-MailMessage -To "<$UserID>" -bcc "<$Username#dana.com>" -from "<itservicedesk#x.com>" -Subject $global:subject -SmtpServer "mailrelay.x.com" -BodyAsHtml -body $global:body
You could stop using the Net.Mail.Attachment and instead do something like
$Body = #"
<html>
<body style="font-family:calibri">
<b>This is image 1</b>
<img src='cid:TEST1.png'>
<b>This is image 2</b>
<img src='cid:Test2.png'>
</body>
</html>
"#
Send-MailMessage -To "Test#Test.com" `
-from "Test2#Test.com" `
-SmtpServer Test.smtp.com `
-Subject "Hello" `
-BodyAsHtml -body $body `
-Attachments "C:\Test\TEST1.png", "C:\Test\TEST2.png"
You can embed the image into the HTML, therefore there are no extra files.
It is replacing
{img=file}
with data URL
{src="data:image/png;base64,[base64 encoded long string representing the image]}
There are many online converters that can convert your image file into the required code.
Just google for Image to Data URI converter.
Here is a simple example using MailKit. I had do download the packages from https://www.nuget.org/packages/MimeKit and https://www.nuget.org/packages/MailKit and unpack with 7Zip as PowerShell was struggling to install from the CLI. I got some ideas from here but wanted to add an example of an embedded image, https://adamtheautomator.com/powershell-email.
You can do all sorts with MimeKit and MailKit including modern Auth which is great. It's also supper fast and the Client and even a Connection can be used in a loop to send lots of messages. There is probably an upper bound on how long to use a connection without refreshing?
$mailServer = "domain-com.mail.protection.outlook.com"
$SMTP = New-Object MailKit.Net.Smtp.SmtpClient
Add-Type -Path ".\mailkit.3.3.0\netstandard2.0\MailKit.dll"
Add-Type -Path ".\mimekit.3.3.0\netstandard2.0\MimeKit.dll"
$SMTP.Connect($mailServer, 25, [MailKit.Security.SecureSocketOptions]::StartTls, $False)
$Message = New-Object MimeKit.MimeMessage
$message.From.Add("a.person#domain.com");
$message.To.Add("b.person#domain.com");
$message.Subject = "Some Subject";
$builder = [MimeKit.BodyBuilder]::new();
$image = $builder.LinkedResources.Add($path);
$image.ContentId = [MimeKit.Utils.MimeUtils]::GenerateMessageId();
$body = #"
<html>
<body style="font-family:calibri">
<b>This is image 1</b>
<img src='cid:$($image.ContentId)'>
</body>
</html>
"#
$builder.HtmlBody = $body
#Now we just need to set the message body and we're done
$message.Body = $builder.ToMessageBody();
$SMTP.Send($Message)
$SMTP.Disconnect($true)
$SMTP.Dispose()

Powershell REST request wont return server response if 404

I am still new to Powershell and haven't been able to find anything on this. I am running a REST GET request to a URI which I know for a fact returns a 404 from the server since the resource is not found.
I would like to be able to run a conditional that checks if it's a 404 and skip over it for further processing if this is the case however when I assign the request to a variable, then calling on that later, it just gives me the contents of what my request was. I have never seen anything like this before in other languages...
My basic premise is the following. I first fetch all group names, then loop through that array of names, include the current one in a new URL and make an additional request for that specific group which looks for a SHIFT which will always have the same name. If the group doesn't have that shift by name I want to skip to the next group, otherwise alter some attributes of that newly found shift object.
Here is what my code looks like, as you can see it's not acting correctly
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$user = '******'
$pass = ConvertTo-SecureString '*******' -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $pass
$req = Invoke-WebRequest -Credential $cred -Uri https://********-np.xmatters.com/api/xm/1/groups
$res = ConvertFrom-Json $req.Content
$content = $res.data
$base = "https://********-np.xmatters.com/api/xm/1/groups"
$group_name = $content[0].targetName
$path = "$base/$group_name/shifts/MAX-Default Shift"
$shift = Invoke-RestMethod -Credential $cred -Uri $path
Write-Host '-----------------------'
Write-Host $shift
Write-Host '-----------------------'
... RESPONSE BELOW ....
Invoke-RestMethod : The remote server returned an error: (404) Not Found.
At \\MMFILE\********$\MyDocuments\Group Supers PReliminary.ps1:16 char:10
+ $shift = Invoke-RestMethod -Credential $cred -Uri $path
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
-----------------------
#{id=***********; group=; name=MAX-Default Shift; description="; start=2018-08-21T04:00:00.000Z; end=2018-08-22T04:00:00.000Z; timezone=America/New_York; recurrence=;
links=}
-----------------------
PS C:\WINDOWS\system32>
What I would like to do is something like, in shorthand code, if $shift.code == 404 ... skip ... else ... run additional query
You need to use a try ... catch.
$code = ""
try{
$shift = Invoke-RestMethod -Credential $cred -Uri $path
}
catch{
$code = $_.Exception.Response.StatusCode.value__
}
if($code -eq "404")
{
continue
# Other things
}
else
{
Write-Host '-----------------------'
Write-Host $shift
Write-Host '-----------------------'
}
You could suppress the error message via Try..Catch and in so doing allow the script to continue:
Try {
$Shift = Invoke-RestMethod http://www.google.com/fakeurl -ErrorAction Stop
#Do other things here if the URL exists..
} Catch {
if ($_.Exception -eq 'The remote server returned an error: (404) Not Found.') {
#Do other things here that you want to happen if the URL does not exist..
}
}
Note this will hide all terminating errors from Invoke-ResetMethod. You could then use an if statement to see if the exception was a 404 and then perform further actions accordingly.

importing HTML and outputting with variables

I'm looking for a method to import a template HTML file in PowerShell and being able to populate it with variables, which in turn sends an e-mail in HTML format containing user data.
I already know how to send the HTML e-mail. And, currently have HTML in a 'here' string embedded in the code. I want to take it a step further, by being able to grab an HTML template based on country code. So, if the user is in the US, it'll get a English HTML data filled e-mail, if they're dutch, they'll get it in Dutch, etc.
function SendMessage {
Param(
[Parameter(Position=0,Mandatory=$true)]
[string]$Identity,
[Parameter(Position=1,Mandatory=$true)]
[string]$Body
)
$Subject = "Important information - Do not delete this email. Welcome to Voicemail"
$SmtpClient = New-object system.net.mail.smtpClient
$MailMessage = New-Object system.net.mail.mailmessage
$CredentialFile = ".\UMcloud-creds.txt"
$password = Get-Content $CredentialFile| ConvertTo-SecureString -Force
$UMCloudAdmin = ""
$SmtpClient.Credentials = New-Object System.Net.NetworkCredential($UMCloudAdmin, $Password)
$smtpclient.Host = "smtp-in.net"
$MailMessage.From = "Voicemail <P#domain.net>"
$MailMessage.To.clear()
$MailMessage.To.Add($Identity)
$MailMessage.Subject = $Subject
$Mailmessage.Body = $body
$MailMessage.IsBodyHtml = 1
$Logofilepath = ((Resolve-Path .\).Path) + "\logo.jpg"
$attachment = New-Object System.Net.Mail.Attachment -ArgumentList $LogoFilePath
$attachment.ContentDisposition.Inline = $True
$attachment.ContentDisposition.DispositionType = "Inline"
$attachment.ContentType.MediaType = "image/jpg"
$attachment.ContentId = "logo.jpg"
$MailMessage.Attachments.Add($attachment)
do {
$Continue = $false
try {
$smtpclient.Send($MailMessage)
Write-LogFile $OutputLogFile ("[SUCCESS] {0} {1}" -f $identity, $UMExtension)
Write-LogFile $customemaillog ("[SUCCESS] {0} {1}" -f $identity, $UMExtension) | out-null
$Continue = $true
} catch {
sleep -s 10
Write-LogFile $OutputLogFile "[ERROR] $Identity $_.Exception.Message"
Write-LogFile $CustomEmailLog "[ERROR] $Identity $UMExtension"
Write-Error $_.Exception.Message
}
} until($Continue -eq $true)
} # End send message
$WelcomeText = Get-Content -Path ".\$CountryID.txt"
$Body = #"
<html>
...
</html>
"#
The here string is part of the script, I'd like to be able to import it from TXT file as not to clutter the script.
Instead of using a text file, create a powershell file (ps1) for each html language format you want. Within those files, you can set a single variable as the html text (file EN_US.ps1):
$bodyENUS = #"Dear <b><font color=red>user</b></font> <br>
This is a test <b>HTML</b> email for your language preference<br>
Sincerely,<br> PdeRover<br>"
You can then pass the variable into the main ps file using two ways: Dot Sourcing or using a Global Variable.
Dot Sourcing: calling the variable by providing the file name.
In the main file:
..\EN_US.ps1
..\PT_PT.ps1
$smtp = "Exchange-Server"
$to = $Identity
$from = "Voicemail <P#domain.net>"
$subject = "This is a Test of HTML Email"
if (user is English speaking){
$bodyByLang = $bodyENUS}
elseif (user is Portuguese speaking) {
$bodyByLang = $bodyPTPT}
send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $bodyByLang -BodyAsHtml -Priority high
Global Variable: prefixing a variable with $Global:and calling the file during runtime. $Global: bodyENUS Then calling it using $bodyENUS
I asked my own SO question about the difference/best practice of using them. May be worth a read.
This should be enough to point you in the right direction.

powershell script to attach the html file in body of email

Iam looking for a Powershell script to attach the html file in the body of email.Please help me by providing a sample script .My current script is not working .Iam not able to get the html file content in the body of email.Name of the html file changes every time.
i used 2 scripts but i suppose you could use one
Make the html file
$FILENAME = HTMLfilename
$head = #'
<title>page title</title>
<style> maybe some css</style>
'#
$title01 = #'
<h1>some text above html file</h1>
'#
$body = #"
<a href='$FILENAME.html'>filename</a>
'#
$x = some code
$x | Select-object Name | ConvertTo-HTML -head $head -PreContent $title01 -PostContent "some text" -body $body | Out-File "PATH\TO\HTML\FILE\$FILENAME.html"
Send the email
$Credential = New-Object System.Management.Automation.PsCredential($EmailUsername, $Emailpassword)
$EmailFrom = "from#domain.com"
$EmailTo = #("<to#domain.com>")
#$EmailCc = #("<EMAIL>")
$EmailSubject = "email subject"
$EmailBody = "a link to html file"
#OR maybe Attach it
#$EmailAttachments = "PATH\TO\HTML\FILE\$FILENAME.html"
$SMTPServer = "smtp.#domain.com"
$SMTPPort = ####
$SMTPSsl = $True
$param = #{
SmtpServer = $SMTPServer
Port = $SMTPPort
UseSsl = $SMTPSsl
Credential = $Credential
From = $EmailFrom
To = $EmailTo
#Cc = $EmailCc
Subject = $EmailSubject
Body = $EmailBody
#Attachments = $EmailAttachments
}
Send-MailMessage #param