PoshEmail.psm1
$Eol = [System.Environment]::NewLine function Send-HtmlMailMessage { <# .SYNOPSIS Sends a nicely formatted HTML email. .DESCRIPTION Sends a nicely formatted HTML email. This cmdlet is designed to work just like Send-MailMessage, with -Heading, -Body, -BodyFormatted, and -Footer replacing the default -Body of Send-MailMessage. .INPUTS No inputs .OUTPUTS No outputs .EXAMPLE Send-HtmlMailMessage -From "server01@contoso.com" -To "admin@contoso.com" .LINK https://github.com/natescherer/PoshEmail .NOTES Detail on what the function does, if this is needed #> [CmdletBinding(DefaultParameterSetName="Default")] param ( [parameter(ParameterSetName="Default",Mandatory=$true)] [parameter(ParameterSetName="Button",Mandatory=$true)] # Specifies the address from which the mail is sent. Enter a name (optional) and email address, such as Name <someone@example.com>. This parameter is required. [string]$From, [parameter(ParameterSetName="Default",Mandatory=$true)] [parameter(ParameterSetName="Button",Mandatory=$true)] # Specifies the subject of the email message. This parameter is required. [string]$Subject, [parameter(ParameterSetName="Default",Mandatory=$true)] [parameter(ParameterSetName="Button",Mandatory=$true)] # Specifies the addresses to which the mail is sent. Enter names (optional) and the email address, such as Name <someone@example.com>. This parameter is required. [string[]]$To, [parameter(ParameterSetName="Default",Mandatory=$true)] [parameter(ParameterSetName="Button",Mandatory=$true)] [ValidateNotNullOrEmpty()] # Specifies a string (with optional HTML formatting) to include in the body of the message. This parameter is required. # Multiple paragraphs should have each paragraph wrapped as follows: # - <p>Paragraph 1</p><p>Paragraph 2</p> # If you need to include preformatted data, you should use the -BodyPreformatted attribute as well [string]$Body, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateSet("Left", "Center", "Right")] # Specifies how the body should be aligned. The acceptable values for this parameter are: # - Left # - Center # - Right # Left is the default. [string]$BodyAlignment = "Left", [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNullOrEmpty()] # Specifies a string of preformmated text (code, cmdlet output, etc) to include below the body of the message. # This will be displayed either in a horizontally-scrolling box or, if Outlook (which can't support scrolling) wrapped with line numbers. [string]$BodyPreformatted = "", [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNullOrEmpty()] # Specifies the path and file names of files to be attached to the email message. You can use this parameter or pipe the paths and file names to Send-HtmlMailMessage. [string[]]$Attachments, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNullOrEmpty()] # Specifies the email addresses that receive a copy of the mail but are not listed as recipients of the message. Enter names (optional) and the email address, such as Name <someone@example.com>. [string[]]$Bcc, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNullOrEmpty()] # Specifies the email addresses to which a carbon copy (CC) of the email message is sent. Enter names (optional) and the email address, such as Name <someone@example.com>. [string[]]$Cc, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNullOrEmpty()] # Specifies a user account that has permission to perform this action. The default is the current user. # Type a user name, such as User01 or Domain01\User01. Or, enter a PSCredential object, such as one from the Get-Credential cmdlet. [pscredential]$Credential, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateSet("None", "OnSuccess", "OnFailure", "Delay", "Never")] # Specifies the delivery notification options for the email message. You can specify multiple values. None is the default value. The alias for this parameter is dno. # The delivery notifications are sent in an email message to the address specified in the value of the From parameter. The acceptable values for this parameter are: # - None. No notification. # - OnSuccess. Notify if the delivery is successful. # - OnFailure. Notify if the delivery is unsuccessful. # - Delay. Notify if the delivery is delayed. # - Never. Never notify. [string]$DeliveryNotificationOption, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateSet("ASCII", "UTF8", "UTF7", "UTF32", "Unicode", "BigEndianUnicode", "Default", "OEM")] # Specifies the encoding used for the body and subject. The acceptable values for this parameter are: # - ASCII # - UTF8 # - UTF7 # - UTF32 # - Unicode # - BigEndianUnicode # - Default # - OEM # ASCII is the default. [string]$Encoding, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNull()] # Specifies an alternate port on the SMTP server. The default value is 25, which is the default SMTP port. [int]$Port, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNullOrEmpty()] # Specifies the name of the SMTP server that sends the email message. # The default value is the value of the $PSEmailServer preference variable. If the preference variable is not set and this parameter is omitted, the command fails. [string]$SmtpServer, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] # Indicates that the cmdlet uses the Secure Sockets Layer (SSL) protocol to establish a connection to the remote computer to send mail. By default, SSL is not used. [switch]$UseSsl, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateSet("High", "Normal", "Low")] # Specifies the priority of the email message. The acceptable values for this parameter are: # - Normal # - High # - Low # Normal is the default. [string]$Priority, [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNull()] # Specifies a string (with optional HTML formatting) to include in the heading of the message. [string]$Heading = "", [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateSet("Left", "Center", "Right")] # Specifies how the heading should be aligned. The acceptable values for this parameter are: # - Left # - Center # - Right # Center is the default. [string]$HeadingAlignment = "Center", [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNull()] # Specifies a string (with optional HTML formatting) to include in the footer of the message. [string]$Footer = "", [parameter(ParameterSetName="Default",Mandatory=$false)] [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateNotNull()] # Specifies a string (with optional HTML formatting) to include in the last line of the message. [string]$LastLine = "Powered by <a href=`"https://github.com/natescherer/PoshEmail`">PoshEmail</a>.", [parameter(ParameterSetName="Button",Mandatory=$true)] [ValidateNotNullOrEmpty()] # Specifies a string to use as label for an optional button. [string]$ButtonText, [parameter(ParameterSetName="Button",Mandatory=$true)] [ValidateNotNullOrEmpty()] # Specifies a link to use as a target for an optional button. [string]$ButtonLink, [parameter(ParameterSetName="Button",Mandatory=$false)] [ValidateSet("Left", "Center", "Right")] # Specifies how the button should be aligned. The acceptable values for this parameter are: # - Left # - Center # - Right # Center is the default. [string]$ButtonAlignment = "Center" ) process { if ($BodyPreformatted) { $BodyWidth = "1800" } else { $BodyWidth = "580" } $HtmlTop = ("<!doctype html>$Eol" + "<html>$Eol" + " <head>$Eol" + " <meta name=`"viewport`" content=`"width=device-width`">$Eol" + " <meta http-equiv=`"Content-Type`" content=`"text/html; charset=UTF-8`">$Eol" + " <title></title>$Eol" + " <style>$Eol" + " /* -------------------------------------$Eol" + " INLINED WITH htmlemail.io/inline$Eol" + " ------------------------------------- */$Eol" + " /* -------------------------------------$Eol" + " RESPONSIVE AND MOBILE FRIENDLY STYLES$Eol" + " ------------------------------------- */$Eol" + " @media only screen and (max-width: 620px) {$Eol" + " table[class=body] h1 {$Eol" + " font-size: 28px !important;$Eol" + " margin-bottom: 10px !important;$Eol" + " }$Eol" + " table[class=body] p,$Eol" + " table[class=body] ul,$Eol" + " table[class=body] ol,$Eol" + " table[class=body] td,$Eol" + " table[class=body] span,$Eol" + " table[class=body] a {$Eol" + " font-size: 16px !important;$Eol" + " }$Eol" + " table[class=body] .preformatted {$Eol" + " font-size: 11px !important;$Eol" + " }$Eol" + " table[class=body] .wrapper,$Eol" + " table[class=body] .article {$Eol" + " padding: 10px !important;$Eol" + " }$Eol" + " table[class=body] .content {$Eol" + " padding: 0 !important;$Eol" + " }$Eol" + " table[class=body] .container {$Eol" + " padding: 0 !important;$Eol" + " width: 100% !important;$Eol" + " }$Eol" + " table[class=body] .main {$Eol" + " border-left-width: 0 !important;$Eol" + " border-radius: 0 !important;$Eol" + " border-right-width: 0 !important;$Eol" + " }$Eol" + " table[class=body] .btn table {$Eol" + " width: 100% !important;$Eol" + " }$Eol" + " table[class=body] .btn a {$Eol" + " width: 100% !important;$Eol" + " }$Eol" + " table[class=body] .img-responsive {$Eol" + " height: auto !important;$Eol" + " max-width: 100% !important;$Eol" + " width: auto !important;$Eol" + " }$Eol" + " }$Eol" + "$Eol" + " /* -------------------------------------$Eol" + " PRESERVE THESE STYLES IN THE HEAD$Eol" + " ------------------------------------- */$Eol" + " @media all {$Eol" + " .ExternalClass {$Eol" + " width: 100%;$Eol" + " }$Eol" + " .ExternalClass,$Eol" + " .ExternalClass p,$Eol" + " .ExternalClass span,$Eol" + " .ExternalClass font,$Eol" + " .ExternalClass td,$Eol" + " .ExternalClass div {$Eol" + " line-height: 100%;$Eol" + " }$Eol" + " .btn-primary table td:hover {$Eol" + " background-color: #34495e !important;$Eol" + " }$Eol" + " .btn-primary a:hover {$Eol" + " background-color: #34495e !important;$Eol" + " border-color: #34495e !important;$Eol" + " }$Eol" + " }$Eol" + " </style>$Eol" + " </head>$Eol" + " <body class=`"`" style=`"background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;`">$Eol" + " <table border=`"0`" cellpadding=`"0`" cellspacing=`"0`" class=`"body`" style=`"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;`">$Eol" + " <tr>$Eol" + " <td style=`"font-family: sans-serif; font-size: 14px; vertical-align: top;`"> </td>$Eol" + " <td class=`"container`" style=`"font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; margin: 0 auto; max-width: $($BodyWidth)px; padding: 10px;`">$Eol" + " <div class=`"content`" style=`"box-sizing: border-box; display: block; margin: 0 auto; max-width: 100%; padding: 10px;`">$Eol" + "$Eol" + " <!-- START CENTERED WHITE CONTAINER -->$Eol" + " <span class=`"preheader`" style=`"color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;`"></span>$Eol" + " <table class=`"main`" style=`"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;`">$Eol" + "$Eol" + " <!-- START MAIN CONTENT AREA -->$Eol" + " <tr>$Eol" + " <td class=`"wrapper`" style=`"font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;`">$Eol" + " <table border=`"0`" cellpadding=`"0`" cellspacing=`"0`" style=`"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;`">$Eol" + " <tr>$Eol" + " <td style=`"font-family: sans-serif; font-size: 14px; vertical-align: top;`">$Eol") $HtmlButton = (" <table border=`"0`" cellpadding=`"0`" cellspacing=`"0`" class=`"btn btn-primary`" style=`"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;`">$Eol" + " <tbody>$Eol" + " <tr>$Eol" + " <td align=`"$($ButtonAlignment.ToLower())`" style=`"font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;`">$Eol" + " <table border=`"0`" cellpadding=`"0`" cellspacing=`"0`" style=`"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;`">$Eol" + " <tbody>$Eol" + " <tr>$Eol" + " <td style=`"font-family: sans-serif; font-size: 14px; vertical-align: top; background-color: #3498db; border-radius: 5px; text-align: center;`"> <a href=`"$ButtonLink`" target=`"_blank`" style=`"display: inline-block; color: #ffffff; background-color: #3498db; border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 14px; font-weight: bold; margin: 0; padding: 12px 25px; text-transform: capitalize; border-color: #3498db;`">$ButtonText</a> </td>$Eol" + " </tr>$Eol" + " </tbody>$Eol" + " </table>$Eol" + " </td>$Eol" + " </tr>$Eol" + " </tbody>$Eol" + " </table>$Eol") $HtmlDataToFooter = (" </td>$Eol" + " </tr>$Eol" + " </table>$Eol" + " </td>$Eol" + " </tr>$Eol" + "$Eol" + " <!-- END MAIN CONTENT AREA -->$Eol" + " </table>$Eol" + "$Eol" + " <!-- START FOOTER -->$Eol" + " <div class=`"footer`" style=`"clear: both; margin-top: 10px; text-align: center; width: 100%;`">$Eol" + " <table border=`"0`" cellpadding=`"0`" cellspacing=`"0`" style=`"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;`">$Eol" + " <tr>$Eol" + " <td class=`"content-block`" style=`"font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;`">$Eol") $HtmlFooterToLastLine = (" </td>$Eol" + " </tr>$Eol" + " <tr>$Eol" + " <td class=`"content-block powered-by`" style=`"font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;`">$Eol") $HtmlBottom = (" </td>$Eol" + " </tr>$Eol" + " </table>$Eol" + " </div>$Eol" + " <!-- END FOOTER -->$Eol" + "$Eol" + " <!-- END CENTERED WHITE CONTAINER -->$Eol" + " </div>$Eol" + " </td>$Eol" + " <td style=`"font-family: sans-serif; font-size: 14px; vertical-align: top;`"> </td>$Eol" + " </tr>$Eol" + " </table>$Eol" + " </body>$Eol" + "</html>$Eol") if (!$ButtonText) { $HtmlButton = "" } $Heading = " <h2 style=`"text-align: $($HeadingAlignment.ToLower());`">$Heading</h2>$Eol" if ($Body -notlike "*<p>*") { $Body = "<p>$Body</p>" } if ($Footer) { $Footer = " $Footer$Eol" } $LastLine = " $LastLine$Eol" $Body = $Body -replace "<p>"," <p style=`"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px; text-align: $($BodyAlignment.ToLower());`">" $Body = $Body -replace "</p>","</p>$Eol" if ($BodyPreformatted -ne "") { $BodyReformatted = "" foreach ($Line in $BodyPreformatted -split $Eol) { $Line = $Line -replace " "," " $BodyReformatted += " <li style=`"color: #4169E1; font-family: monospace; font-size: 11px;`"><span class=`"preformatted`" style=`"color: black; font-family: monospace; font-size: 11px; white-space: pre-wrap;`">$Line</span></li>$Eol" } $BodyPreformatted = (" </td>$Eol" + " </tr>$Eol" + " <tr>$Eol" + " <td class=`"preformatted`" width=`"100%`" style=`"font-size: 14px; vertical-align: top; max-width: 100%; overflow: auto; padding-top: 15px; padding-right: 15px;background-color: #F5F5F5; border: 1px solid black;`">$Eol" + " <ol class=`"preformatted`">$Eol" + "$BodyReformatted" + " </ol>$Eol") $BodyPreformatted = $BodyPreformatted + (" </td>$Eol" + " </tr>$Eol" + " <tr>$Eol" + " <td style=`"font-family: sans-serif; font-size: 14px; vertical-align: top;`">$Eol" + " <p style=`"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px; text-align: $($BodyAlignment.ToLower());`"> </p>$Eol") } $Footer = $Footer -replace "<a ","<a style=`"text-decoration: underline; color: #999999; font-size: 12px; text-align: center;`" " $LastLine = $LastLine -replace "<a ","<a style=`"text-decoration: underline; color: #999999; font-size: 12px; text-align: center;`" " $CompleteBody = $HtmlTop + $Heading + $Body + $BodyPreformatted + $HtmlButton + $HtmlDataToFooter + $Footer + $HtmlFooterToLastLine + $LastLine + $HtmlBottom $SmmParams = @{ From = $From To = $To Subject = $Subject Body = $CompleteBody BodyAsHtml = $true } if ($Attachments) { $SmmParams += @{Attachments = $Attachments} } if ($Bcc) { $SmmParams += @{Bcc = $Bcc} } if ($Cc) { $SmmParams += @{Cc = $Cc} } if ($Credential) { $SmmParams += @{Credential = $Credential} } if ($DeliveryNotificationOption) { $SmmParams += @{DeliveryNotificationOption = $DeliveryNotificationOption} } if ($Encoding) { $SmmParams += @{Encoding = $Encoding} } if ($Port) { $SmmParams += @{Port = $Port} } if ($Priority) { $SmmParams += @{Priority = $Priority} } if ($SmtpServer) { $SmmParams += @{SmtpServer = $SmtpServer} } if ($UseSsl) { $SmmParams += @{UseSsl = $UseSsl} } # Using Start-Job prevents issues described here: https://stackoverflow.com/questions/43349726/send-mailmessage-closes-every-2nd-connection-when-using-attachments Start-Job -ScriptBlock { Send-MailMessage @using:SmmParams } | Wait-Job | Receive-Job } } function Invoke-CommandWithEmailWrapper { <# .SYNOPSIS Executes a Script or ScriptBlock via Invoke-Command, and provide email alerts either before or before and after execution. .DESCRIPTION Executes a Script or ScriptBlock either locally on on a remote computer. Provides output of Script/ScriptBlock via email after execution completes. Optionally sends an additional email alert at the start of execution. .INPUTS No inputs .OUTPUTS Outputs whatever the Script/ScriptBlock you are invoking outputs. .EXAMPLE Invoke-CommandWithEmailWrapper -ScriptBlock { robocopy c:\source d:\dest } -JobName "RoboCopy" -SmtpServer "smtp01" -EmailTo "admin@contoso.com" Executes the robocopy command in the ScriptBlock on the local computer, then sends an email with the command's output once it completes. .EXAMPLE Invoke-CommandWithEmailWrapper -Script "c:\scripts\script1.ps1" -JobName "Script1" -SmtpServer "smtp01" -EmailTo "admin@contoso.com" -ComputerName "serv01" -EmailMode "BeforeAndAfter" Executes the the script c:\scripts\script1.ps1 (on the local computer) on the remote computer "serv01", sending emails when the script begins and finishes running. .LINK https://github.com/natescherer/PoshEmail #> [CmdletBinding(DefaultParameterSetName="Script")] param ( [parameter(ParameterSetName="Script",Mandatory=$false)] [parameter(ParameterSetName="ScriptBlock",Mandatory=$false)] # Computer to execute the command on. Defaults to localhost. [string]$ComputerName, [parameter(ParameterSetName="Script",Mandatory=$false)] [ValidateScript({Test-Path -Path $_})] # Script to execute. [string]$Script, [parameter(ParameterSetName="ScriptBlock",Mandatory=$false)] [ValidateNotNullOrEmpty()] # ScriptBlock to execute. [scriptblock]$ScriptBlock, [parameter(ParameterSetName="Script",Mandatory=$true)] [parameter(ParameterSetName="ScriptBlock",Mandatory=$true)] [ValidateNotNullOrEmpty()] # A short job name to include in emails to identify this execution. [string]$JobName, [parameter(ParameterSetName="Script",Mandatory=$true)] [parameter(ParameterSetName="ScriptBlock",Mandatory=$true)] [ValidateNotNullOrEmpty()] # Specifies SMTP server used to send email [string]$SmtpServer, [parameter(ParameterSetName="Script",Mandatory=$false)] [parameter(ParameterSetName="ScriptBlock",Mandatory=$false)] # Specifies to send mail either After or BeforeAndAfter command execution. Defaults to After. [ValidateSet("After","BeforeAndAfter")] [string]$EmailMode = "After", [parameter(ParameterSetName="Script",Mandatory=$false)] [parameter(ParameterSetName="ScriptBlock",Mandatory=$false)] # TCP Port to connect to SMTP server on. Defaults to 25. [int]$SmtpPort = 25, [parameter(ParameterSetName="Script",Mandatory=$false)] [parameter(ParameterSetName="ScriptBlock",Mandatory=$false)] # Specifies a source address for messages. Defaults to computername@domain [string]$EmailFrom = "$($env:computername)@$($env:userdnsdomain)", [parameter(ParameterSetName="Script",Mandatory=$true)] [parameter(ParameterSetName="ScriptBlock",Mandatory=$true)] # Specifies a comma-separated (i.e. "a@b.com","b@b.com") list of email addresses to email upon job completion [string[]]$EmailTo, [parameter(ParameterSetName="Script",Mandatory=$false)] [parameter(ParameterSetName="ScriptBlock",Mandatory=$false)] # Indicates that the cmdlet uses the Secure Sockets Layer (SSL) protocol to establish a connection to the remote computer to send mail. Defaults to $true [switch]$EmailUseSsl = $true ) process { if ($ComputerName) { $FriendlyComputerName = $ComputerName } else { $FriendlyComputerName = $env:computername } $StartTime = Get-Date if ($EmailMode -like "BeforeAndAfter") { $SmtpParamsBefore = @{ From = $EmailFrom To = $EmailTo Subject = "'$JobName' Started on $FriendlyComputerName" Heading = "'$JobName' Started on $FriendlyComputerName at $StartTime" Body = "'$JobName' Started on $FriendlyComputerName at $StartTime" SmtpServer = $SmtpServer Port = $SmtpPort UseSsl = $EmailUseSsl } Send-HtmlMailMessage @SMTPParamsBefore } $InvokeCommandParams = @{ ErrorVariable = $CommandVariable WarningVariable = $CommandWarning InformationVariable = $CommandInfo } if ($ScriptBlock) { $InvokeCommandParams += @{ ScriptBlock = { & $ScriptBlock *>&1 } } } if ($Script) { $InvokeCommandParams += @{ ScriptBlock = { & $Script *>&1 } } } if ($ComputerName) { $InvokeCommandParams += @{ ComputerName = $ComputerName } } $CommandOutput = Invoke-Command @InvokeCommandParams if ($EmailMode -like "*After") { $EndTime = Get-Date $Elapsed = $EndTime - $StartTime $ElapsedString = ("$($Elapsed.days) Days $($Elapsed.Hours) Hours $($Elapsed.Minutes) Minutes " + "$($Elapsed.Seconds) Seconds") $SmtpParamsAfter = @{ From = $EmailFrom To = $EmailTo Subject = "'$JobName' Finished on $FriendlyComputerName" Heading = "'$JobName' Finished on $FriendlyComputerName at $EndTime" Body = "Output:" BodyPreformatted = $CommandOutput | Out-String Footer = "Time elapsed: $ElapsedString" SmtpServer = $SmtpServer Port = $SmtpPort UseSsl = $EmailUseSsl } Send-HtmlMailMessage @SMTPParamsAfter } $CommandOutput } } Export-ModuleMember -Function Send-HtmlMailMessage Export-ModuleMember -Function Invoke-CommandWithEmailWrapper |