The PowerShell script discussed in this post uses certreq.exe to generate certificate signing request (CSR) files with a maintained Subject Alternative Name (SAN) field.

To avoid transmitting credentials in clear text, SSL/TLS should protect administrative web frontends. The primary purpose of certificates is proving authenticity. Certificate authorities (CAs) only issue certificates after proving the requester's information is correct and legit.

Browser showing certificate naming mismatch

Browser showing certificate naming mismatch

CSR files via Internet Information Services (IIS) Microsoft Management Console (MMC) only provide the common name (CN) attribute as the name holder. The problem is that Chrome since version 58 does not support the CN attribute anymore. It requires the name in a correctly maintained Subject Alternative Name (SAN) field. By using the SAN section, it is possible to add multiple alias names to a certificate. My PowerShell script simplifies CSR file creation with alias name support.

Chrome's error message when connecting to a site with SSL certificate that has no maintained SAN field

Chrome's error message when connecting to a site with SSL certificate that has no maintained SAN field

Windows maintains a storage of trusted root certificate authorities. As a result, it automatically trusts the identity that presents a certificate coming from a trusted root certificate authority. In a subsequent step, it will check whether the CN of the certificate matches the name of the accessed resource. If not, error messages appear in the Internet Explorer.

Creating a certificate with certreq.exe ^

Besides the wizard within IIS, certreq.exe can create CSR files. This is a built-in Windows command-line utility. To generate a new CSR file, use the following syntax:

certreq.exe -new [Options] <INF file> <CSR file>

The INF file needs to store detailed information required to generate the file. Save the following content as plain text to use it with certreq.exe:

Signature = $Windows NT$	

Subject	= "CN=ServerName.Nwtraders.msft"
KeySpec	= 1
KeyLength	= 2048
Exportable = False
MachineKeySet = True
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
RequestType	= PKCS10
KeyUsage =	0xa0


[Extensions]  = "{text}"
_continue_ = "dns=servername.nwtraders.msft&"
_continue_ = "dns=servername&"
_continue_ = "dns=serveralias.nwtraders.msft&"
_continue_ = "dns=serveralias&"

The table below explains the content of the INF file for better understanding:

ParameterValue (example)Meaning
Signature$Windows NT$Indicates the operating systems for which this INF is valid—on Windows it must be $Windows NT$
SubjectCN=ServerName.Nwtraders.msftCN used for the fully qualified domain name (FQDN) of the individual resource
KeySpec1Indicates use of the certificate for encryption and signature
KeyLength2048Length of public and private keys—2048 bits is a common value
ExportableFalseDisallows exporting the private key—someone can only use the certificate on the machine where the request is performed
MachineKeySettrueIndicates it's a computer certificate, not suitable for user-related scenarios
ProviderNameMicrosoft RSA SChannel Cryptographic ProviderSpecifies the encryption algorithm
RequestTypePKCS10Determines the format of the request file type sent to the CA
KeyUsage0xa0Further restricts of the certificate—0xa0 stands for digital signature and key encipherment
OID1. authentication is the intended use of this certificate.
[Extensions]"{text}"If the client OS is Windows Server 2008 and higher, we can include SANs in the extensions section by using the text format below


Must be the same as the CN in the subject parameter
_continue_"dns=servername&"e.g., NetbiosName
_continue_"dns=serveralias.nwtraders.msft&"e.g., Alias as FQDN
_continue_"dns=serveralias&"e.g., Alias as NetbiosName

The PowerShell script ^

The Powershell script New-CertReqWithAlias.ps1 uses certreq.exe to generate CSR files with a maintained SAN field. The SAN field may contain alias names as well. I've explained how the script works in the comments.

Creates a certificate signing request (CSR) file, which can contain aliases (CNames).
- Creates a CSR file for a certificate authority, which includes aliases (CNames).
- Alias names need to be comma separated.
- Run the script on the server that hosts the web service (e.g., IIS), since it needs to access the private key storage.

- This uses certreq.exe to transform the input of this script into a well-formed request file.
- For easy usage, the script exposes only the required and a few popular certutil parameters.
$certReqParams = @{
    FQDN                = servername01.nwtraders.msft
    Aliases             = servername01, devmachine, devmachine.nwtraders.msft,
    DestinationFilePath = C:\Temp
New-CertFileReqWithAlias.ps1 @certReqParams
Requests a certificate for the fully qualified domain name (FQDN) for the system (e.g., a website or a server)
Length of keys used for encryption; 2048 bits is the standard and default value
.PARAMETER Exportable
Defines exportability of the private key included in the certificate; the default for security reasons is false
.PARAMETER EncryptionAlgorithm
Sets the algorithm used for encryption; the available choices are the most popular according to research
Comma-separated list of alias names (CNames) to include in the certificate;
all names in the list can access the target resource without name-mismatch errors
.PARAMETER DestinationFilePath
Specifies the name and path for the certificate signing request (CSR) file; the name of the CSR file will be FQDN.csr
None--you cannot pipe objects to New-CertReqWithAlias
PKCS10-formatted CSR file
AUTHOR: Ruben Zimmermann @ruben8z
LASTEDIT: 2018-08-27
REQUIRES: PowerShell Version 4, Windows Management Foundation 4, and at least Windows 7 or Windows Server 2008 R2.
NAME: New-CertFileReqWithAlias
KEYWORDS: certreq, pki, ca, alias
This PS script comes with ABSOLUTELY NO WARRANTY; for details see gnu-gpl. This is free software, and you are welcome to redistribute it under certain conditions; see gnu-gpl for details.


    [Parameter(Mandatory = $true)]

    [Parameter(Mandatory = $false)]
    [int]$KeyLength = 2048,

    [Parameter(Mandatory = $false)]
    [string]$Exportable = 'False',

    [Parameter(Mandatory = $false)]
    [ValidateSet('Microsoft RSA SChannel Cryptographic Provider',`
    'Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider')]
    [string]$EncryptionAlgorithm = 'Microsoft RSA SChannel Cryptographic Provider',




#region checking_parameters

#Check if the FQDN matches valid syntax
if ($FQDN -notMatch '\w{1,}\.\w{1,}\.?[\w.]*') {
    Write-Warning -Message "The FQDN: $($FQDN) seems to be invalid.`n The expected syntax is host.domain.<optional>"

#Check if aliases match valid syntax
if ($Aliases -notMatch '[\w\.\s,]{1,}') {
    Write-Warning -Message "Aliases: $($Aliases) don't seem to be valid. Use a comma ',' to separate multiple aliases."

#Check if the destination file path exists
if (-not (Test-Path -Path $DestinationFilePath)) {
    Write-Warning -Message "Path: $($DestinationFilePath) does not exist. Please specify a valid path."

#Check if the specified file path has a training backslash; if not, add it.
if ($DestinationFilePath.Substring($DestinationFilePath.Length -1,1) -eq '\') {
    $DestinationFilePath = $DestinationFilePath + $FQDN + '.csr'
} else {
    $DestinationFilePath = $DestinationFilePath + '\' + $FQDN + '.csr'

#endregion checking_parameters

#region program_main

    If a comma occurs in an aliases value, 'split' will convert the string
    to an array. Building a valid extensions section requires a loop.
    In case only one value is specified as an alias value, the script will embed it into the required information.
    [System.Environment]::NewLine ensures one alias per line.

if ($Aliases -match ',') {
    $tmpAliases = $Aliases -split ','
    foreach($itmAlias in $tmpAliases) {
        $dnsAliases += '_continue_ = "DNS=' + $itmAlias + '&"' + [System.Environment]::NewLine
} else {
    $dnsAliases = '_continue_ = "DNS=' + $Aliases + '&"' + [System.Environment]::NewLine

$certificateINF = @"
Signature= '`$Windows NT$'

Subject = "CN=${FQDN}"
KeySpec = 1
KeyLength = ${KeyLength}
Exportable = ${Exportable}
MachineKeySet = TRUE
ProviderName = ${EncryptionAlgorithm}
RequestType = PKCS10
KeyUsage = 0xa0


[Extensions] = "{text}"
_continue_ = "DNS=${FQDN}&"

[System.IO.Path]::GetTmpFileName() creates a temporary file to store the information of the
certificateINF variable. The operating system will automatically drop it.
$tmpFile        = [System.IO.Path]::GetTempFileName()
$certificateINF | Out-File $tmpFile

& certreq.exe -new $tmpFile $DestinationFilePath

#endregion program_main

Example using the script ^

Open PowerShell with elevated rights on the computer you require the certificate for. The command below shows how you can use the script:

.\New-CertReqWithAlias.ps1 -FQDN servername.nwtraders.msft -Aliases "servername,serveralias.nwtraders.msft,serveralias," -DestinationFilePath C:\Temp

The command creates a CSR file in the folder C:\Temp for the FQDN servername.nwtraders.msft with the aliases servername, serveralias.nwtraders.msft, and serveralias. Use Notepad to open the request file:

notepad.exe .\servername.nwtraders.msft.csr

Paste the file content into the CA's certificate enrollment page, and issue the certificate.

Pasting the file content into the CA web enrollment page

Pasting the file content into the CA web enrollment page

The resulting certificate will look as follows:

Subscribe to 4sysops newsletter!

Certificate general page

Certificate general page

Certificate details page showing specified aliases

Certificate details page showing specified aliases

Further reading ^

This Microsoft document explains certreq.exe and all you need to know in greater detail, and here is more on Chrome's support for CN matching in certificates.