SSL cert for Exchange 2013

I’m sorry, i miss that part in the video. Thank you for the explanation.

Sorry for the trouble and thanks again for this piece of software, really!

Have a nice day

No problem. I am glad you find the video helpful.

Dean

I’ve attempted to use this method for Exchange 2010, it looked like your script would support it as an option if I’m reading it correctly.

I’m getting the following error when trying to run the script that was provided:

Ampersand not allowed. The & operator is reserved for future use; use “&” to pass ampersand as a string.
At C:\tools\ACME-Exchange.ps1:11 char:163

  • Complete-ACMEChallenge $FQDN -ChallengeType http-01 -Handler iis -HandlerParameters @{ WebSiteRef = 'Default Web
    

Site’ } | select Identifier, status, Expires *>& <<<< 1 >> $acmelog
+ CategoryInfo : ParserError: (:slight_smile: [], ParseException
+ FullyQualifiedErrorId : AmpersandNotAllowed

I’m no PowerShell genius or anything, I thought maybe I have a wrong PowerShell version or something, but everything immediately looks right. However, I could be missing something.

What version of PowerShell are you running on the server - you can check it by pasting the following in PowerShell:

$PSVersionTable.PSVersion

I have followed the instructions set out in this thread to obtain a certificate for (my real domain name is replaced with “mydomain”) remote.mydomain.com and autodiscover.mydomain.com on Exchange 2013. Including the amendments to be made for (only) one SAN in the .ps1 file and the Get/Set-ClientAccessServer in the .txt file. I am stuck in the validation procedure with these errors:


Submit-ACMECertificate : Error creating new cert :: Authorizations for these names not found or expired: autodiscover.mydomain.com, remote.mydomain.com
At C:\acme\ACME-Exchange-mydomain.ps1:68 char:1

  • Submit-ACMECertificate $SANcert_alias *>&1 >> $acmelog
  •   + CategoryInfo          : PermissionDenied: (ACMESharp.Vault.Model.CertificateInfo:CertificateInfo) [Submit-ACMECe
     rtificate], AcmeWebException
      + FullyQualifiedErrorId : urn:acme:error:unauthorized (403),ACMESharp.POSH.SubmitCertificate
    

Update-ACMECertificate : Certificate has not been submitted yet; cannot update status
At C:\acme\ACME-Exchange-mydomain.ps1:70 char:14

  • while (-Not (Update-ACMECertificate $SANcert_alias | select IssuerSerialNumber))
  •          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [Update-ACMECertificate], Exception
    • FullyQualifiedErrorId : System.Exception,ACMESharp.POSH.UpdateCertificate

Update-ACMECertificate : Certificate has not been submitted yet; cannot update status
At C:\acme\ACME-Exchange-mydomain.ps1:76 char:1

  • Update-ACMECertificate $SANcert_alias | select IssuerSerialNumber *>&1 >> $acmel …
  •   + CategoryInfo          : NotSpecified: (:) [Update-ACMECertificate], Exception
      + FullyQualifiedErrorId : System.Exception,ACMESharp.POSH.UpdateCertificate
    
    

Get-ACMECertificate : Cannot export PKCS12; private hasn’t been imported or generated
At C:\acme\ACME-Exchange-mydomain.ps1:80 char:1

  • Get-ACMECertificate $SANcert_alias -ExportPkcs12 $SAN_pfxfile
  •   + CategoryInfo          : NotSpecified: (:) [Get-ACMECertificate], InvalidOperationException
      + FullyQualifiedErrorId : System.InvalidOperationException,ACMESharp.POSH.GetCertificate
    
    

Import-ExchangeCertificate : The imported certificate file for server EXCHANGE2013 failed to access for the following r
eason: Could not find file ‘c:\Certificates\remote.mydomain.com_2017-02-26–16-03.pfx’.
At C:\acme\ACME-Exchange-mydomain.ps1:94 char:1

  • Import-ExchangeCertificate -FileName $SAN_pfxfile -FriendlyName $SANcert_alias | …
  •   + CategoryInfo          : InvalidOperation: (:) [Import-ExchangeCertificate], InvalidOperationException
      + FullyQualifiedErrorId : [Server=EXCHANGE2013,RequestId=178cdd5f-ced0-4be8-b0d0-d2bf723c52d8,TimeStamp=26-2-2017
     15:03:44] [FailureCategory=Cmdlet-InvalidOperationException] B7005C98,Microsoft.Exchange.Management.SystemConfigur
    ationTasks.ImportExchangeCertificate
    
    

Attempting stop…
Internet services successfully stopped
Attempting start…
Internet services successfully restarted
Remove-Item : Cannot find path ‘C:\Certificates\remote.mydomain.com_2017-02-26–16-03.pfx’ because it does not exist.
At C:\acme\ACME-Exchange-mydomain.ps1:99 char:1

  • Remove-Item $SAN_pfxfile -Force
  •   + CategoryInfo          : ObjectNotFound: (C:\Certificates...2-26--16-03.pfx:String) [Remove-Item], ItemNotFoundEx
     ception
      + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
    

Can someone help me out on this? I am coming from StartSSL and my current certificate is about to expire.

Cheers, Dela

Hi Dela,

The first line of the output you've posted says:

You didn't get past the validation process of the domain names that you specified. To get more information, check the generated acme_[timestamp].log under c:\certificates. Do you get "invalid" status for the names? If that's the case, you need to find out why the domain name validation is failing. Try getting the generated validation strings (under C:\inetpub\wwwroot.well-known\acme-challenge) from another computer on the local network first - like "http://exchangeintservername/.well-known/acme-challenge/challenge_file_name". Then try from external machine - it could be the firewall not allowing port 80.

Another reason for the "invalid" status could be the case when you are using a load balancer and multiple Exchange CAS; the files might be generated on one CAS, and the request forwarded to another - you need to configure port 80 to go to just one of the Exchange CAS behind the load balancer.

Last week, I had a very weird failure for validation of the FQDN in the cert - some of the names validated successfully and some failed - because the exchange server was delaying the challenge response. The LE timeout seems to be 5 sec, and for some reason the correct challenge response was provided by the Web Server with delay more than LE timeout. Here is the thread about this issue:

Inconsistent LE responses http-01 invalid/valid - wireshark captures

I am still trying to figure out why the Exchange front-end web site is delaying intermittently the response which consists of a single text file containing a single line - the challenge.

Again, check the logs for more info.

Hi Netometer,

Many thanks for your time to respond. As I had returned my Exchange server to its state prior to trying to obtain the LetsEncrypt certificates I did not have the log files anymore. So I tried again obtaining the certificates to produce new log files. This time the process went smoothly and successful! I did exactly the same as my earlier four or five times trying yesterday. I will install the automatic renewal procedure tomorrow and will see how that will go. Hope to stay out of any further of your help, but we’ll see.

Thanks again, Dela

Hi Netometer,

I'm running Exchange 2010 Rollup 15 on Windows Server 2008 R2.

Using your script I've been successfully able to generate and download the certificate. Thank you so much for this.
I'm having a problem with the command to import the certificate and enable it for Exchange:

Import-ExchangeCertificate -FileName $SAN_pfxfile -FriendlyName $SANcert_alias | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" -force

Firstly the -FileName is not recognised in Ex2010, so I've had to change the command to this:

Import-ExchangeCertificate -FileData ([Byte]$(Get-Content -Path $SAN_pfxfile -Encoding Byte -readCount 0)) -FriendlyName $SANcert_alias | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" -force

Which imports the certificate, but can not enable it, I get the following:

Enable-ExchangeCertificate : The certificate with thumbprint 7E66D71175E706AF48A80A6B7EA69C14D9567857 was found
but is not valid for use with Exchange Server (reason: PrivateKeyMissing).
At line:1 char:186

  • ... ANcert_alias | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" -forc ...
  •                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (: ) [Enable-ExchangeCertificate], InvalidOperationException
    • FullyQualifiedErrorId : 8270670D,Microsoft.Exchange.Management.SystemConfigurationTasks.EnableExchangeCertificate

Checking in the Certificates MMC, I can see the LetsEncrypt certificate, but I can see that the Private Key for the certificate has not been imported along with the LE cert.

If I manually add the Certificate to the Certificates MMC, then the Private key is imported and I can enable the certificate with exchange.

Any ideas how I can use the PowerShell script to correctly import the certificate?
Once this is resolved, I can automate the renewals.

Many thanks in advance,
Jon

Hi Jon,
I’ve been struggling with this script on Exchange 2010 as well, but I have made a little progress. The error you are getting about PrivateKeyMissing is because Exchange requires a password on the cert. To set the password add -CertificatePassword to the Get-ACMECertificate command in the script:

Get-ACMECertificate $SANcert_alias -ExportPkcs12 $SAN_pfxfile -CertificatePassword ‘Your_Password’

Then you will need to use that password when using ImportExchangeCerificate:

Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path $SAN_pfxfile
-Encoding byte -ReadCount 0)) -Password (ConvertTo-SecureString -String ‘Your_Password’ -AsPlainText -Force)

However, I am not a PowerShell expert and this is where I get stuck. The Import-ExchangeCertificate command outputs the thumbprint of the cert which is then required to enable the cert. We need to run this command:

Enable-ExchangeCertificate -Thumbprint FFDD1D5747341E61DA6E7A2E29C47BEE5BEDE02 -Services POP,IMAP,IIS,SMTP

How do you feed the thumbprint from the output of the Import-ExchangeCertificate command into the Enable-ExchangeCertificate command??

If I can figure that out, then the complete script should run under Exchange 2010.

Pat

1 Like

Superb work Pat, thank you so much :slight_smile:

I’ve got it to import and enable the Exchange certificate with the following:

Get-ACMECertificate $SANcert_alias -ExportPkcs12 $SAN_pfxfile -CertificatePassword 'My Password'

Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path $SAN_pfxfile -Encoding Byte -readCount 0)) -FriendlyName $SANcert_alias -Password (ConvertTo-SecureString -String 'My Password' -Force –AsPlainText) | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" -force

You need to pipe (its the | character) the output to the Enable-ExchangeCertificate on the same line as the Import-ExchangeCertificate, this way you don’t need the -Thumbprint option.

Jon

Well done Jon, thanks! Two heads are better than one!

Pat

Hi Netometer, here I am again … The auto renewal via task scheduler as such seems to work, but the new certificate does not appear in ECP or in my browser. It still shows my first/old certificate. The log in the Certificate folder shows no odd information and includes the IssuerSerialNumber. Do you have any idea?

EDIT/UPDATE: it appears that taskcheduler is not causing the problem. It is the Powershell script. It seems not to work well after having obtained a certificate for the first time. This is what I see in the Powershell terminal (run as administrator, on Exchange 2013):


PS C:\acme> .\ACME-Exchange-mydomain.ps1

Directory: C:\inetpub\wwwroot

Mode LastWriteTime Length Name


d---- 1-3-2017 15:44 .well-known
Applied configuration changes to section “system.webServer/security/access” for “MACHINE/WEBROOT/APPHOST/Default Web Sit
e/.well-known” at configuration commit path “MACHINE/WEBROOT/APPHOST”

Creating a new identifier for remote.mydomain.com
New-ACMEIdentifier : An item with the same key has already been added.
At C:\acme\ACME-Exchange-mydomain.ps1:8 char:2

  • New-ACMEIdentifier -Dns $FQDN -Alias $FQDN | select status, Expires
    
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [New-ACMEIdentifier], ArgumentException
    • FullyQualifiedErrorId : System.ArgumentException,ACMESharp.POSH.NewIdentifier

Completing the challenge for the new identifier for remote.mydomain.com

Submitting the new identifier for remote.mydomain.com
Submit-ACMEChallenge : challenge has not been decoded
At C:\acme\ACME-Exchange-mydomain.ps1:14 char:2

  • Submit-ACMEChallenge $FQDN -ChallengeType http-01 | select Identifier, status,  ...
    
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [Submit-ACMEChallenge], InvalidOperationException
    • FullyQualifiedErrorId : System.InvalidOperationException,ACMESharp.POSH.SubmitChallenge

Waiting for a valid authorization … Current status is valid

Creating a new identifier for autodiscover.mydomain.com
New-ACMEIdentifier : An item with the same key has already been added.
At C:\acme\ACME-Exchange-mydomain.ps1:8 char:2

  • New-ACMEIdentifier -Dns $FQDN -Alias $FQDN | select status, Expires
    
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [New-ACMEIdentifier], ArgumentException
    • FullyQualifiedErrorId : System.ArgumentException,ACMESharp.POSH.NewIdentifier

Completing the challenge for the new identifier for autodiscover.mydomain.com

Submitting the new identifier for autodiscover.mydomain.com
Submit-ACMEChallenge : challenge has not been decoded
At C:\acme\ACME-Exchange-mydomain.ps1:14 char:2

  • Submit-ACMEChallenge $FQDN -ChallengeType http-01 | select Identifier, status,  ...
    
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [Submit-ACMEChallenge], InvalidOperationException
    • FullyQualifiedErrorId : System.InvalidOperationException,ACMESharp.POSH.SubmitChallenge

Waiting for a valid authorization … Current status is valid
Get-ACMECertificate : asset file does not exist
At C:\acme\ACME-Exchange-mydomain.ps1:80 char:1

  • Get-ACMECertificate $SANcert_alias -ExportPkcs12 $SAN_pfxfile
  •   + CategoryInfo          : NotSpecified: (:) [Get-ACMECertificate], FileNotFoundException
      + FullyQualifiedErrorId : System.IO.FileNotFoundException,ACMESharp.POSH.GetCertificate
    
    

Import-ExchangeCertificate : The imported certificate file for server EXCHANGE2013 failed to access for the following r
eason: Could not find file ‘c:\Certificates\remote.mydomain.com_2017-03-01–15-44.pfx’.
At C:\acme\ACME-Exchange-mydomain.ps1:94 char:1

  • Import-ExchangeCertificate -FileName $SAN_pfxfile -FriendlyName $SANcert_alias | …
  •   + CategoryInfo          : InvalidOperation: (:) [Import-ExchangeCertificate], InvalidOperationException
      + FullyQualifiedErrorId : [Server=EXCHANGE2013,RequestId=09680899-7f8d-4bdd-ae1c-c0d352081e12,TimeStamp=1-3-2017 1
     4:45:22] [FailureCategory=Cmdlet-InvalidOperationException] B6C1CE14,Microsoft.Exchange.Management.SystemConfigura
    tionTasks.ImportExchangeCertificate
    
    
    

Attempting stop…
Internet services successfully stopped
Attempting start…
Internet services successfully restarted
Remove-Item : Cannot find path ‘C:\Certificates\remote.mydomain.com_2017-03-01–15-44.pfx’ because it does not exist.
At C:\acme\ACME-Exchange-mydomain.ps1:99 char:1

  • Remove-Item $SAN_pfxfile -Force
  •   + CategoryInfo          : ObjectNotFound: (C:\Certificates...3-01--15-44.pfx:String) [Remove-Item], ItemNotFoundEx
     ception
      + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
    

Am I doing something wrong here? Hope you can help me out.

Cheers, Dela

Dela,

I see the following line in your output:

That might happen if line #100 in the script is commented out. Lines #98-100 should look like this:

Delete manually the "sysVault" and try again with the script the way it was provided - lines 98-100 uncommented; that's the way it should be run by the task scheduler for the renewals as well.

Regards,

Dean

Thanks again Netometer, for paying attention to this.

The lines 98-100 in my .ps1 file are exactly the same. I manually deleted the sysvault folder and ran taskscheduler again. No changes in the outcome; still the same certificate. I deleted the sysvault folder once again and ran the .ps1 file manually. Initially it looked good, but then I got the error message “Too many certificates already issued for exact set of domains”. I do not know whether my first retry - with taskscheduler - was also blocked by the same error. I will retry again tomorrow and will report here.

By the way, my sysvault folder only contained the files 00-VAULT and .acme.vault. This is as it should be, correct?

Oh, that could be it.

"Too many certificates already issued for exact set of domains" means you've reached the Let's Encrypt certificates limit - most probably, duplicate certificates (5 certificates per week):

A certificate is considered a duplicate of an earlier certificate if they contain the exact same set of hostnames, ignoring capitalization and ordering of hostnames

For anyone that is interested, I have modified the script to email the ACME log. I inserted it just before the IISRESET command. I am assuming that the SMTP server will not require authorisation and I have only tested this on Exchange 2010 with an anonymous connector:

#Rem E-Mail the Report - You will need to modify $smtpServer along with the relevant E-Mail addresses
#---------------------------------
$smtpServer = “192.168.1.1”
$att = new-object Net.Mail.Attachment($acmelog)
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = "LetsEncrypt@yoursite.com"
$msg.To.Add("recipient@yoursite.com")
$msg.Subject = “LetEncrypt Certificate Renewal”
$msg.Body = “Attached is the LetsEncrypt Cert Renewal Report”
$msg.Attachments.Add($att)
$smtp.Send($msg)
$att.Dispose()

Pat

Hi.
I have just followed your excellent screencast on how to install Let’s Encrypt sertificates with the ACME Sharp Powershell script.
I first ran the script, but got errors, probably since I had forgotten to create the proper firewall rules.

But when I rerun the script, I get errors like these:

Creating a new identifier for post.mydoman.net
New-ACMEIdentifier : An item with the same key has already been added.
At C:\Tools\ACME-Exchange\ACME-Exchange.ps1:8 char:2

  • New-ACMEIdentifier -Dns $FQDN -Alias $FQDN | select status, Expir ...
    
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
  • CategoryInfo : NotSpecified: (:slight_smile: [New-ACMEIdentifier], ArgumentException
  • FullyQualifiedErrorId : System.ArgumentException,ACMESharp.POSH.NewIdentifier

And the script seems to fail.
How do I clean up this so I can try again?

This is on a Server 2016 with Exchange 2016

Edit: I figured it out. I read your other posts, and found out I had to delete the C:\ProgramData\ACMESharp\sysVault manually.
Dare I suggest a small change in the script to make sure this directory gets deleted when the script at some point fails?

Thank you so much for an excellent script and excellent videos that goes with it!

Thank you, Dal.

Actually, the script should clear the registrations in the vault even if they are unsuccessful - the last three lines do the cleaning up. Probably, you’ve hit CTRL-C and interrupted the script.

Anyway, you made a very good point - if there is a registration issue, the script should stop and do the cleaning. Moreover, I am planning to add a check for port 80 using the external ViewDNS API. If port 80 is not open on the firewall and the server is not accessible from the Internet, the script will stop the certificate request process, do the cleaning, and exit.

Glad to hear that it worked for you.

Regards,

Dean

Hi Netometer, it seems that I am facing the same as Dal. Without deleting the sysVault folder manually I keep getting the “An item with the same key has already been added” error. Upon a close re-watch of your third screencast, I see a difference in line 100 of the script. In the script I downloaded line 100 is identical to what you show above, including the two files that are excluded from deletion. In the screencast these two files are not excluded. Does this have something to do with what I am experiencing?

Hope to hear from you.

Cheers, Dela

Hi Dela,

I’ll try to reproduce this issue.

If I understand correctly, when the script fails, it does not cleanup the the ACME Vault automatically, and you have to run the last three lines manually or manually delete the ACME Vault under c:\Program Data?

Dean