Friday, May 31, 2013

PowerShell script to enhance the Windows CA SMTP exit module

Windows CA SMTP exit module

the Windows Certification Authority has a built in feature (Windows Enterprise SKU) to send out emails to inform the PKI administrators if a new pending certificate request waiting for approval or if a new certificate has been issued. Just 2 examples.

The configuration must be done in the registry: See here for an example
http://social.technet.microsoft.com/wiki/contents/articles/2004.active-directory-certificate-services-smtp-exit-module-for-windows-server-2008-r2-example.aspx

Unfortunately you cannot configure it to send the issued certificate to the certificate requestor. For that I wrote a PowerShell script what is also working with the Windows Server 2008 R2 Standard Server.

Config file - sendcert_inc.ps1:

$sendcertpath=".\sendcert"
$msgFrom='noreply@frontoso.com'
$smtphost='127.0.0.1'
$certtmpl="1.3.6.1.4.1.311.21.8.5245527.10310595.8014498.11013764.15833798.137.13192380.4508386" #CorpWebServer
$certfileExt="txt" # fyi: extensions cer and der are blocked by Outlook
$mailbody="mailbody.txt"
$dbscanperiod="03:00" # 01:00 = 1 day, 1:15 = 1 day 15 hours; $dbscanperiod is the max time (now - $dbscanperiod) sendcert goes back in the certificate database, e.g. useful if you have already issued certs for years and you going to enable sendcert now


Mailbody.txt

Hello, attached is the requested certificate.

Please download the certificate and proceed with the SSL/TLS setup of your application.

For your convenience the certificate can be found as attachment and in the mail body.


Thank you,


----------------------------------------------------------------------------
Do not reply to this message. It was sent from an unmonitored email account.




sendcert.ps1

#
# Author: lutz.mueller-hipper@tribaldi.net
# Updates: lutz.mueller-hipper@insight.com
# Date: May 23, 2013 - v3.1
#
clear

import-module ActiveDirectory
# if not yet installed please install the ActiveDirectory PowerShell module
#dism /online /enable-feature /featurename:ActiveDirectory-PowerShell

if (-not (Test-Path .\sendcert_inc.ps1))
{
  write-host "Error: sendcert_inc.ps1 configuration file not found." >>sendcert.log
  exit;
} else {
  . .\sendcert_inc.ps1
}

if (-not (Test-Path $sendcertpath)) { mkdir $sendcertpath >$null}

$Arr_SendCert = @()

write-host "=========================="
write-host Start Send certificate via email to certificate requestor
write-host "=========================="
write-host

#Disposition Description
#20 certificate was issued
#21 certificate is revoked
#30 certificate request failed
#31 certificate request is denied

$reqid_db = @()
$reqid_db = get-content $sendcertpath\reqid_do_not_remove.txt

$reqid_db2 = @()

foreach ( $line in $reqid_db) {
 write-host "Line: "$line
 $reqid_db2 = $reqid_db2 + $line
}

certutil.exe -view -out "Request.requestid,Request.requestid" -restrict "CertificateTemplate=$certtmpl,Disposition=20,NotBefore>now-$dbscanperiod" csv > $sendcertpath\sendcert_scope.csv
$collection = @(Import-CSV $sendcertpath\sendcert_scope.csv)
write-host Issued certs during period: $collection.count

if ($collection.count -gt 0) {
  foreach($CADBentry in $collection)
  {

    $reqid = $CADBentry."request id"

    if ($reqid_db2 -notcontains $reqid) {  
    write-host 'Preparing email for request: ' $reqid

    $certview = certutil.exe -view -out "rawcertificate" -restrict "Request.requestid=$reqid"

    $certemail = @()
    $certattach = @()
    foreach($line in $certview)
     {
     #write-host "Line: " $line

     if ( $line -eq "-----BEGIN CERTIFICATE-----" ) { $certbegin="1" }
     if ( $certbegin -eq "1") {
       #write-host "next person in line pls"
       $certemail = $certemail + $line.trim() + "`n" #+ "`r`n"
       $certattach = $certattach + $line.trim() # + "`n" #+ "`r`n"
     
     }
     if ( $line -eq "-----END CERTIFICATE-----" ) { $certbegin="0" }

    }
    $cadb_requser= certutil.exe -view -out "Requester Name" -restrict "Request.requestid=$reqid" csv
    $requser = $cadb_requser[1]
    $requser = $requser.split("\")
    $user = $requser[1]
    $requser = $user.split("`"")
    $user = $requser[0]

$aduser=""

try {
 $aduser = get-aduser $user -Properties mail
  #$aduser.mail
}

catch [Exception] {
   write-host $_.Exception.Message
}

if ($aduser.mail.length -lt 1) {
  write-host "no email address found"
} else {

    $certattach > $sendcertpath\$reqid"."$certfileExt

$msg=new-object System.Net.Mail.MailMessage
$msg.From=$msgFrom
$msg.to.Add($aduser.mail)
$msg.Subject=$env:computername + ": SSL certificate " + $reqid
$msg.IsBodyHtml=$false
$mailbody = @()
$getmailbody = Get-Content mailbody.txt
foreach ($line in $getmailbody) {
  $mailbody = $mailbody + $line + "`n"
}
$msg.Body=@"

$mailbody

$certemail

-
Ref $reqid_$env:computername

"@

$att = new-object Net.Mail.Attachment($sendcertpath + "\" + $reqid + "." + $certfileExt)
$msg.Attachments.Add($att)


$smtp=new-object System.Net.Mail.SmtpClient
$smtp.host=$smtphost

try {
  $smtp.Send($msg)
  $reqid >> $sendcertpath\reqid_do_not_remove.txt
}
catch {
 write-host $_.Exception.Message
}
finally {
  $smtp.dispose
  $att.dispose()
    }
   }
  }
 }
}