New-SelfSignedCertificate on Win2012 r2 has less parameters

Samer picture Samer · Mar 10, 2016 · Viewed 22.1k times · Source

I'm trying to create a self signed certificate with specific encryption parameter values.

On a Win Server 2012 r2 standard running PowerShell 5.0, when I attempt to use

New-SelfSignedCertificate

I receive an error:

New-SelfSignedCertificate : A parameter cannot be found that matches parameter name 'Subject'.

when I attempt to use the -Subject parameter, which in addition to other parameters allowed on my laptop, does not appear in the intellisense.

However on my laptop (Win 10 and PowerShell 5.0) I'm allowed to use these parameters, and I create a self-signed certificate by using the following code

#create a Certificate
# OID for document encryption
    $Oid = New-Object System.Security.Cryptography.Oid "1.3.6.1.4.1.311.80.1"
    $oidCollection = New-Object System.Security.Cryptography.OidCollection
    $oidCollection.Add($oid) > $Null
# Create enhanced key usage extension that allows document encryption
$Ext = New-Object System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension $oidCollection, $true 

$myCert = New-SelfSignedCertificate -Subject 'CN=myservernameasubject' -CertStoreLocation "Cert:\LocalMachine\My" -KeySpec KeyExchange -KeyUsage KeyEncipherment, DataEncipherment -Extension $Ext

Answer

JamieSee picture JamieSee · Mar 10, 2016

Use -DnsName instead without the CN=.

From the PowerShell help:

-DnsName <String> Specifies one or more DNS names to put into the Subject Alternative Name extension of the certificate when a certificate to be copied is not specified via the CloneCert parameter. The first DNS name is also saved as Subject Name and Issuer Name.

The -KeySpec and other related options are, unfortunately, not supported by New-SelfSignedCertificate in Windows Server 2012 R2 and Windows 8.1. Otherwise, you're looking at one of three options to generate the desired certificate; Adapt the COM object based code in the answer to How to create a self-signed certificate using C#? to use in PowerShell, use an external executable like makecert.exe, or generate the certificate/key pair elsewhere and then import it to the certificate store on the other machine.

Update: After further research, it looks like adapting COM based code in PowerShell is a good option. I found a blog entry by Vishal Agarwal, Generating a certificate (self-signed) using powershell and CertEnroll interfaces, that gives the following PowerShell code:

$name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=TestServer", 0)

$key = new-object -com "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 1024
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()

$serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
$ekuoids.add($serverauthoid)
$ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)

$cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = get-date
$cert.NotAfter = $cert.NotBefore.AddDays(90)
$cert.X509Extensions.Add($ekuext)
$cert.Encode()

$enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")