Skip to content

Instantly share code, notes, and snippets.

@deadlydog
Last active January 28, 2022 20:03
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save deadlydog/9f87fba75d611b4f1757af7767aa2d05 to your computer and use it in GitHub Desktop.
Save deadlydog/9f87fba75d611b4f1757af7767aa2d05 to your computer and use it in GitHub Desktop.
PowerShell script that imports a .pfx certificate file. Useful to do before building the solution on a build server. For more info, see https://blog.danskingdom.com/creating-a-pfx-certificate-and-applying-it-on-the-build-server-at-build-time/
param([string] $PfxFilePath, $Password)
# You may provide a [string] or a [SecureString] for the $Password parameter.
$absolutePfxFilePath = Resolve-Path -Path $PfxFilePath
Write-Output "Importing store certificate '$absolutePfxFilePath'..."
Add-Type -AssemblyName System.Security
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($absolutePfxFilePath, $Password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet")
$store = new-object system.security.cryptography.X509Certificates.X509Store -argumentlist "MY", CurrentUser
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::"ReadWrite")
$store.Add($cert)
$store.Close()
@deadlydog
Copy link
Author

@deadlydog, What the value should be set for "MY"?

MY is the correct value. See the docs for more info.

@coreyperkins
Copy link

What the hell is this?

System.Security.Cryptography.CryptographicException: Keyset does not exist

@armplinker
Copy link

Umm, import-pfxcertificate is a native PS capability?

@deadlydog
Copy link
Author

@armplinker Import-PfxCertificate is the name of the PowerShell script file here; not a native PowerShell cmdlet. So you would want to copy the code from this gist into a file called Import-PfxCertificate.ps1 and then call it with the appropriate parameter values.

@armplinker
Copy link

armplinker commented Jan 28, 2022

Yes, thank you @deadlydog for your clarification. Configuring this particular cmdlet is something of a black art, as I have come to appreciate in the last horrible 24 hours, after I realized my ole MakeCert.exe etc. approach was obsolete. In particular there is one cmdlet parameter
-KeyUsage None that seems to misbehave, in ways I am not sure affect me.

The cert location should be cert:LocalMachine/my as indicated by @deadlydog. The following not only assumes that, but has the arrogance to stick the cert into Cert:\LocalMachine\AuthRoot

Here is where my current attempt to create a signing certificate from scratch for signing SQL Server CLR assemblies is:
# if you want a PFX file as a result
$pfxFileName="<your PFX_FILE_NAME_GOES_HERE.pfx";
$certFileName="<your CERT_FILE_NAME GOES HERE.cer";
$certStoreLocation="Cert:\LocalMachine\AuthRoot";
# *.TestDomainname.org is a dummy, like me...
$cert=New-SelfSignedCertificate -Type CodeSigningCert -DnsName *.TestDomainName.org,$env:COMPUTERNAME -FriendlyName RIDOT_BrM_TestCert -Subject $env:COMPUTERNAME
-Provider "Microsoft Strong Cryptographic Provider" -HashAlgorithm "SHA256" #and you may want to use a different HashAlgorithm
-KeyLength 2048 -KeyExportPolicy Exportable -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(10) -KeyUsageProperty All
-KeyUsage None `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.3")
# the TextExtension thing is the black art. These magic strings make the certificate cable of Server Authentication, Client Authentication, and Code Signing
$CertPassword = ConvertTo-SecureString -String "<YOUR ULTRA SECURE PASSWORD GOES HERE IN TEXT" -Force -AsPlainText

make a .cer file

$certFile = Export-Certificate -Cert $cert -FilePath $certFileName -Type CERT -Verbose -Force
Import-Certificate -CertStoreLocation $certStoreLocation -FilePath $certFile.FullName

Remove-Item $certFile.FullName

_# I kept my cer file around because SQL Server wants one to import to create a login to associate with a signed DLL...

HOWEVER, the cer does not provide a PVK directly, so, you may wish to export the certificate from the server using the windows certificate manager

because you can elect to export a private key file - This is discussed abundantly elsewhere..._

$ips = [System.Net.Dns]::GetHostAddresses("").IPAddressToString -like "."
_# again, you need to let your host know that this domain you are using is ok in the server's hosts file. I actually don't need this AFAIC_T
Add-Content C:\Windows\System32\drivers\etc\hosts "$ips *.TestDomainName.org"

make a pfx file

$cert | Export-PfxCertificate -FilePath $pfxFileName -Password $CertPassword -Verbose -Force

# and at the end of this, you still have an untrusted certificate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment