Scripting

About Scripting#

Certify is extensible via PowerShell scripts tasks which can be configured to run before or after the Certificate Request. From v5 onwards these are found under the Tasks tab for your managed certificate. See Tasks for more information.

The scripts are provided a parameter $result which contains the status and details of the managed certificate being requested. You can execute any commands including creating new processes, or using other command line tools.

A common use for scripting is to use your new certificate for services other than IIS websites, such as Microsoft Exchange, RDP Gateway, FTP servers and other services. The app also has a range of built-in deployment tasks which also use scripting internally.

By default the background service runs as Local System, so your scripts will execute in that context, this can be important for issues regarding permissions, file system encryption etc. You can optionally configure your task to run as a specific user if network access or special permissions are required.

Do not store scripts under the C:\Program Files\CertifyTheWeb* folder. File stored there will be deleted next time you update the app

Scripting Basics#

Here is a sample PowerShell script which demonstrates a few commonly accessed pieces of information:

param($result) # required to access the $result parameter
# either $true or $false
$result.IsSuccess
# object containing all information Certify has about the saved Site
$result.ManagedItem
# the IIS (or other service) site ID
$result.ManagedItem.ServerSiteId # ex: 1, 2, 3, ...
# the website root directory (if applicable)
$result.ManagedItem.RequestConfig.WebsiteRootPath # ex: "C:\inetpub\wwwroot"
# the path to the created/renewed certificate PFX file
$result.ManagedItem.CertificatePath # ex: "C:\ProgramData\Certify\certes\assets\pfx\00f9e07e-83ca-4029-a173-4b704ee78996.pfx"
# the certificate thumbprint
$result.ManagedItem.CertificateThumbprintHash # ex: "78b1080a1bf5e7fc0bbb0c0614fc4a18932db5f9"
# the previous certificate thumbprint
$result.ManagedItem.CertificatePreviousThumbprintHash # ex: "18c1060a1be5e6fc0bbb0c0614fc4a18932db5fa"
# You can set $result.Abort to $true in a pre-request hook to prevent the certificate from
# being requested (has no effect in post-request hooks)
$result.Abort = $false

The $result.ManagedItem object is an instance of the ManagedCertificate class, so all of the properties it has will be available in your script:

Pre-Request Tasks#

Notes: Pre-request scripts/tasks are executed immediately before the Certificate Request is about to be made (including the challenge file configuration checks).

  • The $result.IsSuccess value will always be $false.
  • If for some reason your script would like to prevent the Certificate Request from being executed, you may set $result.Abort to $true and the site your script was executed for will be skipped.

Deployment Tasks (Post-Request)#

Deployment task (post-request) scripts are executed immediately after the Certificate Request was completed, and the certificate was automatically installed and configured according to the site configuration within Certify.

By default these run if the request was successful but you can change the task trigger (On Success, On Fail, etc). You can also configure them for manual execution only, so that you can perform them during a maintenance window, or via a windows scheduled task using the command line.

  • The $result.IsSuccess value indicates whether or not the Certificate Request was successfully completed.
  • The $result.Message value provides a message describing the reason for failure, or a message indicating success.

Legacy uses for scripting (v4.x and lower) may have previously included CCS Export, PEM file creation etc however these functions are provided by built-in Deployment Tasks which you should use instead unless the built-in functionality does not meet your requirements.

Example: Output the result properties to a text file#

# Logs results to the given path (modify as required)
param($result)
$logpath = "c:\temp\ps-test.txt"
$date = Get-Date
Add-Content $logpath ("-------------------------------------------------");
Add-Content $logpath ("Script Run Date: " + $date)
Add-Content $logpath ($result | ConvertTo-Json)

Example: Send email via Gmail after unsuccessful renewal#

Note: this is an example only, by default the app will use the certifytheweb.com API to notify you of repeated failures.

param($result)
if (!$result.IsSuccess) {
$EmailFrom = "username@gmail.com"
$EmailTo = "username@gmail.com"
$Subject = "Cert Request Failed: " + $result.ManagedItem.RequestConfig.PrimaryDomain
$Body = "Error: " + $result.Message
$SMTPServer = "smtp.gmail.com"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("username@gmail.com", "password");
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
write-output "Sent notification email"
}

Example: Restart RRAS after successful certificate renewal#

param($result)
if ($result.IsSuccess -and $result.ManagedItem.GroupId -eq 1) {
write-output "Restarting RRAS..."
Net Stop RemoteAccess
Net Start RemoteAccess
write-output "Done"
}

Example: Convert CNG certificate storage to CSP (for Exchange 2013)#

param($result)
$tempfile = "$env:TEMP\CertifyTemp.pfx"
$pfx = get-pfxcertificate -filepath $result.ManagedItem.CertificatePath
certutil -f -p Certify -exportpfx $pfx.SerialNumber $tempfile
certutil -delstore my $pfx.SerialNumber
certutil -p Certify -csp "Microsoft RSA SChannel Cryptographic Provider" -importpfx $tempfile
remove-item $tempfile

Example: Enable certificate for Exchange 2013 / 2016 services on local server#

param($result)
Enable-ExchangeCertificate -Thumbprint $result.ManagedItem.CertificateThumbprintHash -Services POP,IMAP,SMTP,IIS -Force

Example: Update VMWare Horizon certificate#

This example removes any previous certificate with the same FriendlyName (vdm) then renames the Friendly Name property of the new certificate to vmd. It then restarts the wstunnel service.

param($result)
if ($result.IsSuccess) {
$thumbprint = $result.ManagedItem.CertificateThumbprintHash # e.g. 2c127d49b4f63d947dd7b91750c9e57751eced0c
# remove the old cert (by Friendly Name 'vdm') to avoid duplication, if it exists
Get-ChildItem -Path cert:\LocalMachine\My | Where {$_.FriendlyName.Equals("vdm")} | Remove-Item
# rename our new certificate
$cert = Get-ChildItem -Path cert:\LocalMachine\My\$thumbprint
$cert.FriendlyName ="vdm"
# restart the wstunnel service to apply certificate
Restart-Service wstunnel -Force -ErrorAction Stop
}

Example: Update certificate for SSTP VPN#

param($result)
# Store certificate in variable
$cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -match $result.ManagedItem.CertificateThumbprintHash}
# Stop RRAS, set cert, start RRAS
Import-Module RemoteAccess
Stop-Service RemoteAccess
Set-RemoteAccess -SslCertificate $cert
Start-Service RemoteAccess

Troubleshooting#

  • In the Certify UI, you may test scripts by clicking the ▶ button. You should ideally test scripts after you have completed a successful certificate request so that you have real results and a certificate to work with.

  • The $result.ManagedItem.CertificatePath value will be set to the filename (including path) of the PFX file containing the requested certificate, unless the site is new and has not had a successful Certificate Request, in which case the value will not be set.

  • PowerShell Execution Policies may be set by your administrator which affect script execution. The app will try to set the policy to "Unrestricted" by default which may conflict with higher level policy settings. You can set the default script execution policy in the server settings file (then restart the Certify background service) %PROGRAMDATA%\Certify\serviceconfig.json

    • "PowershellExecutionPolicy":"Unrestricted" or
    • "PowershellExecutionPolicy":"Bypass" or
    • "PowershellExecutionPolicy":"" (blank string) to use the default policy set by your administrator.