3

I have a powershell script that check the certificate store for expiring certificates. It will display these results within the CLI. I want to modify this script to email the results of the output in the body of the email. I know how to send an email through PowerShell using the send-mailmessage CmdLet but I am uncertain how to take the results of the script and send it in an email...

Here is the script:

param([int]$InNumberOfDays=180,[switch]$ExcludeAutoEnroll)

function WriteCertInfo($cert)
{
    #just a lot of code to get the fields into an object
    $certObj = "" | Select RequesterName,RequestType,ExpirationDate,CommonName,EnrollmentFlags

    $RequesterName=$cert -match "Requester Name:.*Request Type:"
    $startLength="Requester Name:".Length
    $lineLength=$matches[0].Length -("Request Type:".Length + $startLength)
    $OutRequesterName=$matches[0].SubString($startLength,$lineLength)
    $certObj.RequesterName=$OutRequesterName    

    $RequestType=$cert -match "Request Type:.*Certificate Expiration Date:"
    $startLength="Request Type:".Length
    $lineLength=$matches[0].Length - ("Certificate Expiration Date:".Length + $startLength)
    $OutRequestType=$matches[0].SubString($startLength,$lineLength)
    $certObj.RequestType=$OutRequestType    

    $ExpirationDate = $cert -match "Certificate Expiration Date:.*Issued Common Name:"
    $startLength="Certificate Expiration Date:".Length
    $lineLength=$matches[0].Length - ("Issued Common Name:".Length + $startLength)
    $OutExpirationDate=$matches[0].SubString($startLength,$lineLength)
    $certObj.ExpirationDate=$OutExpirationDate

    $IssuedCommonName= $cert -match "Issued Common Name:.*Template Enrollment Flags:"
    $startLength="Issued Common Name:".Length
    $lineLength=$matches[0].Length - ("Template Enrollment Flags:".Length + $startLength)
    $OutCommonName=$matches[0].SubString($startLength,$lineLength)
    $certObj.CommonName=$OutCommonName

    $EnrollmentFlags= $cert -match "Template Enrollment Flags:.*"
    $startLength="Template Enrollment Flags:".Length
    $lineLength=$matches[0].Length - ($startLength)
    $OutEnrollmentFlags=$matches[0].SubString($startLength,$lineLength)
    $certObj.EnrollmentFlags=$OutEnrollmentFlags

    if($ExcludeAutoEnroll)
    {

        if(($OutEnrollmentFlags -match "CT_FLAG_AUTO_ENROLLMENT") -eq $false)
        {
            $script:CertToList+=$certObj    
        }
    }
    else
    {

        $script:CertToList+=$certObj

    }
}


$CertToList=@()
$today=Get-Date
$endperiod=$today.AddDays($InNumberOfDays)

$tester=certutil -view -restrict "NotAfter>=$today,NotAfter<=$endperiod" -out 

"RequestID,RequesterName,RequestType,NotAfter,CommonName,EnrollmentFlags"
$arr=$tester -match "Row \d*:"

$numberOfCerts=$arr.length

$line=[string]::join(" ",$tester)

for($certNo=0;$certNo -lt $numberOfCerts;$certNo=$certNo+1)
{

    $r1=$arr[$certNo] 
    if($certNo -ne ($numberOfCerts-1))
    {
        $r2=$arr[$certNo+1]
    }
    else
    {
        $r2="Maximum Row Index"
    }   
    $isFound=$line -match "$r1 .* $r2"
    $NumberOfChars=$matches[0].Length - $r2.Length
    $thisCert=$matches[0].SubString(0,$NumberOfChars)
    WriteCertInfo($thisCert)

}
$CertToList
  • 1
    The easiest way is to put your output into a variable and then use the -Body "$variable" parameter... Have you tried that? – Colyn1337 Jul 10 '14 at 19:06
  • I'm not exactly sure how I would do that. Do I insert it into the script itself OR upon execution of the script do I add it as a parameter? – DangeRuss Jul 10 '14 at 19:11
  • The first step is to decide what you want to be emailed. I'm guessing it's the $CertToList variable, is that right? – Colyn1337 Jul 10 '14 at 19:13
  • Yes, that is the output of the script within the PowerShell CLI. – DangeRuss Jul 10 '14 at 19:16
4

Since the output formatting in the PowerShell prompt happens when you actually output $CertToList, and you're not interested in that here, you might want to construct a HTML structure to present the output in the mail message.

Update Since you want to embed an inline attachment in the form of an image, we'll have to do the work of creating and sending the email ourselves, instead of relying on Send-MailMessage:

# Smtp details as outlined by Colyn1337
$smtpServer = "server.domain.com"
$smtpFrom = "emailfrom@address.com"
$smtpTo = "emailto@address.com"
$messageSubject = "The subject line of the email"

# Set up an SmtpClient for sending the message
$smtpClient = New-Object Net.Mail.SmtpClient
$smtpClient.Host = $smtpServer

# Create the MailMessage you want to send
$mailMessage = New-Object Net.Mail.MailMessage
$mailMessage.From = $smtpFrom
$mailMessage.To.Add($smtpTo)
$mailMessage.Subject = $messageSubject

# Create the html content for the mail
# Add embedded image resource to HTML
$htmlReport  = "<image src=cid:DangeRussLogo>"

# And then the table with your data
$htmlReport += "<table>"
$htmlReport += "`n"
$htmlReport += "<tr>"
$htmlReport += "<th>RequestID</th>"
$htmlReport += "<th>RequesterName</th>"
$htmlReport += "<th>RequestType</th>"
$htmlReport += "<th>NotAfter</th>"
$htmlReport += "<th>CommonName</th>"
$htmlReport += "<th>EnrollmentFlags</th>"
$htmlReport += "</tr>"
$htmlReport += "`n"
foreach($cert in $CertToList)
{
    $htmlReport += "<tr>"
    $htmlReport += "<td>$($cert.RequestID)</td>"
    $htmlReport += "<td>$($cert.RequesterName)</td>"
    $htmlReport += "<td>$($cert.RequestType)</td>"
    $htmlReport += "<td>$($cert.NotAfter)</td>"
    $htmlReport += "<td>$($cert.CommonName)</td>"
    $htmlReport += "<td>$($cert.EnrollmentFlags)</td>"
    $htmlReport += "</tr>"
    $htmlReport += "`n"
}

$htmlReport += "</table>"

# Now create an AlternateView from the HTML contents
$messageBody = [Net.Mail.AlternateView]::CreateAlternateViewFromString($htmlReport, 'text/html')

# Create a Linked Resource from the logo image
$imageMimeType = New-Object System.Net.Mime.ContentType("image/png")
$embeddedImage = New-Object Net.Mail.LinkedResource("C:\Users\DangeRuss\logo.png", $imageMimeType)
$embeddedImage.ContentId = "DangeRussLogo"

# Add the resource to the HTML view
$messageBody.LinkedResources.Add($embeddedImage)

# Add the HTML view to the MailMessage
$mailMessage.AlternateViews.Add($messageBody)

# And finally send the message
$smtpClient.Send($mailMessage)

If you want to use a .jpeg or .jpg file instead on PNG, change the MimeType from "image/png" to "image/jpeg"

|improve this answer|||||
  • Thanks Mathias this looks very interesting... Would I just add this to the bottom of my script after $CertToList? The replace -Body "$($CertToList)" with -Body "$($htmlReport)"? – DangeRuss Jul 10 '14 at 19:45
  • @DangeRuss You'd replace the variable ;) You're not going to need to protect the variable with $($variable) anymore as it's not an array. You'll also add that code at the end of your original script and before the Send-MailMessage. – Colyn1337 Jul 10 '14 at 19:46
  • Replace the last line in your original script (the line that just says $CertToList) with mine, and add sender details etc. to Send-MailMessage, just like in the answer from @Colyn1337 – Mathias R. Jessen Jul 10 '14 at 19:46
  • That seems to work Mathias, but the email shows the formatting of the html, it doesnt actually send an html email it appears. – DangeRuss Jul 10 '14 at 19:48
  • 1
    Add -BodyAsHtml:$true to Send-MailMessage – Mathias R. Jessen Jul 10 '14 at 19:50
4

So you've already done the hard part of generating your list in $CertToList. You're probably over thinking how to do the email and that's what's tripping you up. Remember, Powershell is there to make your life easier. If it seems too complicated, there's likely an easier way to do it. Anyway you need to figure out the following variables and add them to your code:

$smtpServer = "server.domain.com"
$smtpFrom = "emailfrom@address.com"
$smtpTo = "emailto@address.com"
$messageSubject = "The subject line of the email"

Then add this line at the very end of your code:

Send-MailMessage -From "$smtpFrom" -To "$smtpTo" -Subject "$messageSubject" -Body "$($CertToList)" -SMTPServer "$smtpServer"

You'll notice I've noted your $CertToList variable in special way. I've done this so Powershell know's for sure that $CertToList is a variable and to pull its contents into the body. Now, you can make the body however you want, you can do something like:

-Body "This email contains the cert list: `n`n $($CertToList)"
|improve this answer|||||
  • Colyn, thanks! This seems to work... I had one question. I did a test and the first test I received an email with the output. The script prints out the output and also sends an email. So the first email it sent out, I received the printed output. In the script you can have parameters like -InNumberofDays 5 and -ExcludeAutoEnroll. So with those, I can specify a set of certs to view in a certain amount of time OR/AND exclude auto renew certs. When I tested the script changing the days to 30 instead of 5 which was my original test, it printed the results but did not email them. – DangeRuss Jul 10 '14 at 19:40
  • So the original way I ran it was: Get-ExpiringCertificates.ps1 -InNumberofDays 5 -ExcludeAutoEnroll - this printed the result in the CLI and also emailed the result. When I run it this way: Get-ExpiringCertificates.ps1 -InNumberofDays 30 -ExcludeAutoEnroll it prints results but doesnt email anything... – DangeRuss Jul 10 '14 at 19:42
  • @DangeRuss Check out Mathias R. Jessen's answer to this question. He's got the work to do more customization of the output. you'd want to adapt his code with what you've already got and what I've given you as well. – Colyn1337 Jul 10 '14 at 19:46
  • 2
    I cant make both the answer but for anyone who may stumble upon this post, please be aware both answers were very helpful! Thanks Colyn! – DangeRuss Jul 10 '14 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.