Generating wildcard certificate from internal certificate authority using PowerShell

DISCLAIMER: THIS IS NOT INTENDED FOR ANY PRODUCTION ENVIRONMENT

Updated on June 24th 2017: Correction to issue where the server it was running on already has a server authentication certificate. Thank you Eric (@XenAppBlog) for the feedback.

Updated on June 25th 2017: Updated with a new version of the script that requires Windows 10 or Server 2016. The updated version adds support for password protection of the PFX file and it also cleans up private keys after export.

Hi all,

When you are building Citrix environments or any other environment that uses certificates it is often easiest to use a wildcard certificate from your internal PKI infrastructure when you are testing. I had a talk with Dave Brett at Synergy about automating the process of getting a wildcard PFX certificate that can be used during automation of Citrix installations. I thought it would be an easy task since Microsoft has baking in PowerShell in most of their products and services now, but it turned out that I couldn’t find any native PowerShell commands that allowed be to perform the task.

Since I like doing PowerShell scripts an automation that of course wasn’t the end of it, so I started digging into what can be done and I found this script on the Microsoft Script Center: MS Script Center The problem I had with this script is that I wouldn’t do wildcard certificates.

After a while I started to build my own script from scratch, but of course getting a lot of inspiration from the script found on MS Script center. I build the script out so that I would locate the CA inside the domain by itself (only tested when there is one CA in the environment) and the doing an export to a file server as well.

The script needs to be run as a domain user, so that cause a lot of testing when incorporating it with Microsoft MDT, but got that working in the end.

To use the script in MDT follow these steps:

  1. Add a “Run Command Line” action to the task sequence Skærmbillede 2017-06-07 kl. 20.49.56.png
  2. Mark “Run this step as the following account” and enter a domain user name and password as shown below Skærmbillede 2017-06-07 kl. 20.50.17.png
  3. Place the scripts in the scripts folder (or any other place you feel like and can reference) Skærmbillede 2017-06-07 kl. 20.50.46.png
  4. Edit the “New-WildcardCertificate.cmd” file to map the network drive of your choice and execute the PowerShell script. If you follow my guide it will map to your MDT deployment share. Skærmbillede 2017-06-07 kl. 20.51.26.png
  5. Run the task sequence and test it out.

The PowerShell script is shown in the bottom of this post and as always let me know if you have input or questions about it.

You can download the two scripts and ini file here: Download

/Martin

<#
.Synopsis
   Automate the creation of wildcard certificates
.DESCRIPTION
   This script can automate the creation of wildcard certificates from an internal PKI infrastructure.
   The output PFX file will not have a password and it will be placed in the folder the PS1 script is located.
   You will need to have the SSL.INI file in the same folder as this script and you will need to run the script as a domain users.
   Use the function within this script by editing the line in the buttom.
.PARAMETER Path
  Path to where temporary files are stored
.PARAMETER PFXPath
  Path to where the PFX file is exported
.PARAMETER CAName
  Name of the Certificate authority    
.EXAMPLE
   New-WildcardCertificate
.EXAMPLE
   New-WildcardCertificate -Path C:\Temp -PFXPath "\\FILE01\Certificates" 
.EXAMPLE
   New-WildcardCertificate -Path C:\Temp -PFXPath "\\FILE01\Certificates" -CAName "DC01.Domain.Com\Domain-DC01-CA"
#>
Function New-WildcardCertificate {
    [CmdletBinding()]
    Param(
      [Parameter(Mandatory=$False,Position=1)]
       [string]$Path = "C:\Windows\Temp",
       [Parameter(Mandatory=$False,Position=2)]
       [string]$PFXPath	= ".",
       [Parameter(Mandatory=$False,Position=3)]
       [string]$CAName
    )
    Begin {
        $Domain = (Get-ItemProperty -path hklm:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters -Name Domain).Domain
        If (!(Test-Path -Path $PSScriptRoot\ssl.ini)) {
            Write-Host "You don't have the SSL.INI file that is required to run this script" -ForegroundColor Red
            Break;
        }
        If (!(Test-Path -Path $Path)) {
            New-Item -Path $Path -ItemType Directory
        }
        (Get-Content $PSScriptRoot\ssl.ini) | Foreach-Object {$_ -replace 'ServerFQDN',"*.$Domain"}  | Out-File .\Wildcard.ini
    }
    Process {
        If ($CAName -eq "") {
            Write-Verbose "Finding certificate authority"
            $CA = New-Object -ComObject CertificateAuthority.Config
            $CAName = $CA.GetConfig(0)
        }

        Write-Verbose "Requesting certificate" 
        & c:\windows\system32\certreq.exe –new "Wildcard.ini" "$Path\wildcard.req"
        & c:\windows\system32\certreq.exe -config "$CAName" –submit "$Path\wildcard.req" "$Path\wildcard.cer"

        Write-Verbose "Installing certificate" 
        & c:\windows\system32\certreq.exe –accept "$Path\wildcard.cer"

        Write-Verbose "Exporting certificate and private key"
        $cert = new-object security.cryptography.x509certificates.x509certificate2 -arg "$Path\wildcard.cer"
       
        $certbytes = $cert.export([System.Security.Cryptography.X509Certificates.X509ContentType]::pfx)

        $certbytes | Set-Content -Encoding Byte  -Path "$PFXPath\Wildcard.pfx" -ea Stop 
        Write-Verbose "Certificate successfully exportert to wildcard.pfx"
    }   
    End {
        Write-Verbose "deleting exported certificat from computer store"
        Remove-Item -Path cert:\localmachine\my\$($Cert.Thumbprint) -DeleteKey 
        Remove-Item -Path $Path\wildcard.cer -Force
        Remove-Item -Path $Path\wildcard.req -Force
        Remove-Item -Path $Path\wildcard.rsp -Force
    }
}
New-WildcardCertificate -Path C:\Install -PFXPath "\\Server01\Shares" -Verbose

For Windows 10 and 2016 only:

<#
.Synopsis
   Automate the creation of wildcard certificates
.DESCRIPTION
   This script can automate the creation of wildcard certificates from an internal PKI infrastructure.
   The output PFX file will not have a password and it will be placed in the folder the PS1 script is located.
   You will need to have the SSL.INI file in the same folder as this script and you will need to run the script as a domain users.
   Use the function within this script by editing the line in the buttom.
.PARAMETER Path
  Path to where temporary files are stored
.PARAMETER PFXPath
  Path to where the PFX file is exported
.PARAMETER CAName
  Name of the Certificate authority    
.EXAMPLE
   New-WildcardCertificate
.EXAMPLE
   New-WildcardCertificate -Path C:\Temp -PFXPath "\\FILE01\Certificates" 
.EXAMPLE
   New-WildcardCertificate -Path C:\Temp -PFXPath "\\FILE01\Certificates" -CAName "DC01.Domain.Com\Domain-DC01-CA"
#>
Function New-WildcardCertificate {
    [CmdletBinding()]
    Param(
      [Parameter(Mandatory=$False,Position=1)]
       [string]$Path = "C:\Windows\Temp",
       [Parameter(Mandatory=$False,Position=2)]
       [string]$PFXPath	= ".",
       [Parameter(Mandatory=$False,Position=3)]
       [string]$CAName,
       [Parameter(Mandatory=$False,Position=4)]
       [string]$Password
    )
    Begin {
        $Domain = (Get-ItemProperty -path hklm:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters -Name Domain).Domain
        If (!(Test-Path -Path $PSScriptRoot\ssl.ini)) {
            Write-Host "You don't have the SSL.INI file that is required to run this script" -ForegroundColor Red
            Break;
        }
        If (!(Test-Path -Path $Path)) {
            New-Item -Path $Path -ItemType Directory
        }
        (Get-Content $PSScriptRoot\ssl.ini) | Foreach-Object {$_ -replace 'ServerFQDN',"*.$Domain"}  | Out-File .\Wildcard.ini
    }
    Process {
        If ($CAName -eq "") {
            Write-Verbose "Finding certificate authority"
            $CA = New-Object -ComObject CertificateAuthority.Config
            $CAName = $CA.GetConfig(0)            
        }
        Write-Verbose "Requesting certificate" 
        & c:\windows\system32\certreq.exe –new "Wildcard.ini" "$Path\wildcard.req"
        & c:\windows\system32\certreq.exe -config "$CAName" –submit "$Path\wildcard.req" "$Path\wildcard.cer"

        Write-Verbose "Installing certificate" 
        & c:\windows\system32\certreq.exe –accept "$Path\wildcard.cer"

        Write-Verbose "Exporting certificate and private key"
        $PFXPassword = ConvertTo-SecureString -String $Password -Force -AsPlainText
        $cert = new-object security.cryptography.x509certificates.x509certificate2 -arg "$Path\wildcard.cer"
        Get-item cert:\localmachine\my\$($cert.Thumbprint) | Export-PfxCertificate -FilePath "$PFXPath\Wildcard.pfx" -Password $PFXPassword 
        Write-Verbose "Certificate successfully exportert to wildcard.pfx"
    }   
    End {
        Write-Verbose "deleting exported certificat from computer store"
        Remove-Item -Path cert:\localmachine\my\$($Cert.Thumbprint) -DeleteKey 
        Remove-Item -Path $Path\wildcard.cer -Force
        Remove-Item -Path $Path\wildcard.req -Force
        Remove-Item -Path $Path\wildcard.rsp -Force
    }
}
New-WildcardCertificate -Path C:\Install -PFXPath "\\Server01\Shares" -Password "Password1" -Verbose

 

2 thoughts on “Generating wildcard certificate from internal certificate authority using PowerShell”

  1. hi martin:
    here a sample of a ssl.ini file when you want use a SAN Certificate:

    [Version]
    Signature=”$Windows NT$”

    [NewRequest]
    Subject = “CN=test.yourcompany.int,OU=IT,O=yourcompany,L=yourlocation,S=yourstate,C=yourcountry”
    ; For a wildcard use “CN=*.CONTOSO.COM” for example
    ; For an empty subject use the following line instead or remove the Subject line entierely
    ; Subject =
    Exportable = TRUE ; Private key is not exportable
    KeyLength = 4096 ; Common key sizes: 512, 1024, 2048, 4096, 8192, 16384
    KeySpec = 1 ; AT_KEYEXCHANGE
    KeyUsage = 0xA0 ; Digital Signature, Key Encipherment
    MachineKeySet = True ; The key belongs to the local computer account
    ProviderName = “Microsoft Enhanced RSA and AES Cryptographic Provider”
    ProviderType = 12
    SMIME = FALSE
    RequestType = PKCS10
    HashAlgorithm=Sha256

    ; At least certreq.exe shipping with Windows Vista/Server 2008 is required to interpret the [Strings] and [Extensions] sections below

    [Strings]
    szOID_SUBJECT_ALT_NAME2 = “2.5.29.17”
    szOID_ENHANCED_KEY_USAGE = “2.5.29.37”
    szOID_PKIX_KP_SERVER_AUTH = “1.3.6.1.5.5.7.3.1”
    szOID_PKIX_KP_CLIENT_AUTH = “1.3.6.1.5.5.7.3.2”

    [RequestAttributes]
    CertificateTemplate= WebServerSAN5Years
    SAN=”dns=test.yourcompany.com&dns=honululu.yourcompany.com&dns=localhost&ipaddress=192.1.1.4″

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.