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
4
  • 1
    The easiest way is to put your output into a variable and then use the -Body "$variable" parameter... Have you tried that?
    – Colyn1337
    Commented Jul 10, 2014 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
    Commented Jul 10, 2014 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
    Commented Jul 10, 2014 at 19:13
  • Yes, that is the output of the script within the PowerShell CLI.
    – DangeRuss
    Commented Jul 10, 2014 at 19:16

2 Answers 2

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 = "[email protected]"
$smtpTo = "[email protected]"
$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"

11
  • 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
    Commented Jul 10, 2014 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
    Commented Jul 10, 2014 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 Commented Jul 10, 2014 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
    Commented Jul 10, 2014 at 19:48
  • 1
    Add -BodyAsHtml:$true to Send-MailMessage Commented Jul 10, 2014 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 = "[email protected]"
$smtpTo = "[email protected]"
$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)"
4
  • 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
    Commented Jul 10, 2014 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
    Commented Jul 10, 2014 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
    Commented Jul 10, 2014 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
    Commented Jul 10, 2014 at 19:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .