Created
May 4, 2019 09:16
-
-
Save sbingner/49f0e0bd03edb588873a724e60c005a7 to your computer and use it in GitHub Desktop.
letsEncrypt cert updates for Exchange
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import-module ACMESharp | |
# | |
# Script parameters | |
# | |
$domain = "mail.yourdomain.com" | |
$sans = @("autodiscover.yourdomain.com") | |
$exchangeServers = @("EX01", "EX02", "EX03"); | |
$iissitename = "Default Web Site" | |
$certname = "mail.yourdomain.com-$(get-date -format yyyy-MM-dd--HH-mm)" | |
# | |
# Environmental variables | |
# | |
$PSEmailServer = "127.0.0.1" | |
$LocalEmailAddress = "administrator@yourdomain.com" | |
$OwnerEmailAddress = "you@yourdomain.com" | |
$pfxfile = "c:\Certificates\$certname.pfx" | |
# | |
# Script setup - should be no need to change things below this point | |
# | |
$ErrorActionPreference = "Stop" | |
$EmailLog = @() | |
# | |
# Utility functions | |
# | |
function Write-Log { | |
$msg = "$(get-date -Format HH:mm:ss) $($args[0])" | |
Write-Host $msg | |
$script:EmailLog += $msg | |
} | |
function Register-FQDN | |
{ | |
$domain = $args[0] | |
$certname = $args[1] | |
Write-Log "Generating a new identifier for $domain" | |
New-ACMEIdentifier -Dns $domain -Alias $certname | |
Write-Log "Completing a challenge via http" | |
Complete-ACMEChallenge $certname -ChallengeType http-01 -Handler iis -HandlerParameters @{ WebSiteRef = $iissitename } | |
Write-Log "Submitting the challenge" | |
Submit-ACMEChallenge $certname -ChallengeType http-01 | |
# Check the status of the identifier every 6 seconds until we have an answer; fail after one minute | |
$i = 0 | |
do { | |
$identinfo = (Update-ACMEIdentifier $certname -ChallengeType http-01).Challenges | Where-Object {$_.Status -eq "valid"} | |
if($identinfo -eq $null) { | |
Start-Sleep 6 | |
$i++ | |
} | |
} until($identinfo -ne $null -or $i -gt 10) | |
if($identinfo -eq $null) { | |
Write-Log "We did not receive a completed identifier after 60 seconds" | |
$Body = $EmailLog | out-string | |
Send-MailMessage -From $LocalEmailAddress -To $OwnerEmailAddress -Subject "Attempting to renew Let's Encrypt certificate for $domain" -Body $Body | |
Exit | |
} | |
} | |
Try { | |
if (1) { | |
Register-FQDN $domain $certname | |
ForEach ($san in $sans) { | |
Register-FQDN $san "$san.$certname" | |
} | |
# We now have a new identifier... so, let's create a certificate | |
Write-Log "Attempting to renew Let's Encrypt certificate for $domain" | |
# Generate a certificate | |
Write-Log "Generating certificate for $domain" | |
New-ACMECertificate $certname -AlternativeIdentifierRefs $sans -Generate -Alias $certname | |
# Submit the certificate | |
Submit-ACMECertificate $certname | |
# Check the status of the certificate every 6 seconds until we have an answer; fail after a minute | |
$i = 0 | |
do { | |
$certinfo = Update-AcmeCertificate $certname | |
if($certinfo.SerialNumber -ne "") { | |
Start-Sleep 6 | |
$i++ | |
} | |
} until($certinfo.SerialNumber -ne "" -or $i -gt 10) | |
if($i -gt 10) { | |
Write-Log "We did not receive a completed certificate after 60 seconds" | |
$Body = $EmailLog | out-string | |
Send-MailMessage -From $LocalEmailAddress -To $OwnerEmailAddress -Subject "Attempting to renew Let's Encrypt certificate for $domain" -Body $Body | |
Exit | |
} | |
# Export Certificate to PFX file | |
Get-ACMECertificate $certname -ExportPkcs12 $pfxfile | |
} | |
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 | |
$pfx.Import($pfxfile) | |
$certThumbprint = $pfx.Thumbprint | |
$exchver = gcm exsetup | %{$_.fileversioninfo.ProductVersion.Split("{.}")} | |
switch ($exchver[0]) | |
{ | |
8 {$exchsnapin = "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin;"} | |
14 {$exchsnapin = "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010;"} | |
15 {$exchsnapin = "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn;"} | |
default {$exchsnapin = "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010;"} | |
} | |
Invoke-Expression $exchsnapin | |
foreach ($server in $exchangeServers) { | |
$ps = New-PSSession -ComputerName $server | |
Write-Log "Updating certs for $server" | |
Import-ExchangeCertificate -Server $server -FileName $pfxfile -FriendlyName $certname | Enable-ExchangeCertificate -Server $server -DoNotRequireSsl -Services "IIS,IMAP,SMTP,POP" -Force | |
Write-Log "Remove old certificates" | |
$certs = Invoke-Command -Session $ps { Get-ChildItem -Path Cert:\LocalMachine\My\ -DNSName $using:domain } | |
foreach ($oldcert in $certs) { | |
Write-Log "Testing Cert: $($oldcert.Thumbprint)" | |
if ($oldcert.Subject -eq "CN=$domain" -And $oldcert.Issuer.Contains("Let's Encrypt") -And $oldcert.Thumbprint -ne $certThumbprint) { | |
Write-Log "Removing Cert $($oldcert.FriendlyName) ($($oldcert.Thumbprint))" | |
Remove-ExchangeCertificate -Thumbprint $oldcert.Thumbprint -Server $server -Confirm:$false | |
} | |
} | |
iisreset $server | |
} | |
# Finished | |
Write-Log "Finished" | |
$Body = $EmailLog | out-string | |
Send-MailMessage -From $LocalEmailAddress -To $OwnerEmailAddress -Subject "Let's Encrypt certificate renewed for $domain" -Body $Body | |
} Catch { | |
Write-Host $_.Exception | |
$ErrorMessage = $_.Exception | format-list -force | out-string | |
$EmailLog += "Let's Encrypt certificate renewal for $domain failed with exception`n$ErrorMessage`r`n`r`n" | |
$Body = $EmailLog | Out-String | |
Send-MailMessage -From $LocalEmailAddress -To $OwnerEmailAddress -Subject "Let's Encrypt certificate renewal for $domain failed with exception" -Body $Body | |
Exit | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment