Browsers have implemented all sorts of great new security measures to ensure that certificates are pretty valid. So, using a self-signed certificate today is more difficult than it used to be. Also, IIS for Win8/10 gained access for using a Central Certificate Store. So, here’s some scripts that:
- Create a Self-Signed Cert
- Creates a self-signed cert with a DNS Name (browsers don’t like it when the Subject Alternative Name doesn’t list the DNS Name).
- Creates a Shared SSL folder on disk and adds permissions for IIS’s Central Certificate Store account will read the certs with.
- Exports the cert to the Shared SSL folder as a .pfx.
- Reimports the certs to the machines Trusted Root Authority (needed for browsers to verify the cert is trusted)
- Adds the 443/SSL binding to the site (if it exists) in IIS
- Re-Add Cert to Trusted Root Authority
- Before Win10, Microsoft implemented a background task which will periodically check the certs installed in your Machine Trusted Root Authority which are self-signed and removes them. So, this script re-installs them.
- It will look through the shared SSL folder created in the previous script and add any certs back to the local Machine Trusted Root Authority that are missing.
- Re-Add Cert to Trusted Root Authority Scheduled Task
- Schedules the script to run hourly
### Create-SelfSignedCert.ps1
$name = "site.name.com" # only need to edit this
# get the shared ssl password for dev - this will be applied to the cert
$pfxPassword = "your pfx password"
# you can only create a self-signed cert in the \My store
$certLoc = "Cert:\LocalMachine\My"
$cert = New-SelfSignedCertificate `
-FriendlyName $name `
-KeyAlgorithm RSA `
-KeyLength 4096 `
-CertStoreLocation $certLoc `
-DnsName $name
# ensure the path the directory for the central certificate store is setup with permissions
# NOTE: This assumes that IIS is already setup with Central Cert Store, where
# 1) The user account is "Domain\AccountName"
# 2) The $pfxPassword Certificate Private Key Password
$sharedPath = "D:\AllContent\SharedSSL\Local"
if((Test-Path $sharedPath) -eq $false) {
mkdir $sharedPath
$acl = Get-Acl $sharedPath
$objUser = New-Object System.Security.Principal.NTAccount("Domain\AccountName")
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($objUser, "ReadAndExecute,ListDirectory", "ContainerInherit, ObjectInherit", "None", "Allow")
$acl.AddAccessRule($rule)
Set-Acl $sharedPath $acl
}
# export from the \My store to the Central Cert Store on disk
$thumbprint = $cert.Thumbprint
$certPath = "$certLoc\$thumbprint"
$pfxPath = "$sharedPath\$name.pfx"
if(Test-Path $pfxPath) { del $pfxPath }
Export-PfxCertificate `
-Cert $certPath `
-FilePath $pfxPath `
-Password $pfxPassword
# reimport the cert into the Trusted Root Authorities
$authRootLoc = "Cert:\LocalMachine\AuthRoot"
Import-PfxCertificate `
-FilePath $pfxPath `
-CertStoreLocation $authRootLoc `
-Password $pfxPassword `
-Exportable
# delete it from the \My store
del $certPath # removes from cert:\localmachine\my
# if the website doesn't have the https binding, add it
Import-Module WebAdministration
if(Test-Path "IIS:\Sites\$name") {
$httpsBindings = Get-WebBinding -Name $name -Protocol "https"
$found = $httpsBindings |? { $_.bindingInformation -eq "*:443:$name" -and $_.sslFlags -eq 3 }
if($found -eq $null) {
New-WebBinding -Name $name -Protocol "https" -Port 443 -IPAddress "*" -HostHeader $name -SslFlags 3
}
}
### Add-SslCertsToAuthRoot.ps1
$Error.Clear()
Import-Module PowerShellLogging
$name = "Add-SslCertsToAuthRoot"
$start = [DateTime]::Now
$startFormatted = $start.ToString("yyyyMMddHHmmss")
$logdir = "E:\Logs\Scripts\IIS\$name"
$logpath = "$logdir\$name-log-$startFormatted.txt"
$log = Enable-LogFile $logpath
try {
#### FUNCTIONS - START ####
Function Get-X509Certificate {
Param (
[Parameter(Mandatory=$True)]
[ValidateScript({Test-Path $_})]
[String]$PfxFile,
[Parameter(Mandatory=$True)]
[string]$PfxPassword=$null
)
# Create new, empty X509 Certificate (v2) object
$X509Certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
# Call class import method using password
try {
$X509Certificate.Import($PfxFile,$PfxPassword,"PersistKeySet")
Write-Verbose "Successfully accessed Pfx certificate $PfxFile."
} catch {
Write-Warning "Error processing $PfxFile. Please check the Pfx certificate password."
Return $false
}
Return $X509Certificate
}
# http://www.orcsweb.com/blog/james/powershell-ing-on-windows-server-how-to-import-certificates-using-powershell/
Function Import-PfxCertificate {
Param(
[Parameter(Mandatory = $true)]
[String]$CertPath,
[ValidateSet("CurrentUser","LocalMachine")]
[String]$CertRootStore = "LocalMachine",
[String]$CertStore = "My",
$PfxPass = $null
)
Process {
$pfx = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
if ($pfxPass -eq $null) {$pfxPass = read-host "Enter the pfx password" -assecurestring}
$pfx.import($certPath,$pfxPass,"Exportable,PersistKeySet")
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($certStore,$certRootStore)
$serverName = [System.Net.Dns]::GetHostName();
Write-Warning ("Adding certificate " + $pfx.FriendlyName + " to $CertRootStore/$CertStore on $serverName. Thumbprint = " + $pfx.Thumbprint)
$store.open("MaxAllowed")
$store.add($pfx)
$store.close()
Write-Host ("Added certificate " + $pfx.FriendlyName + " to $CertRootStore/$CertStore on $serverName. Thumbprint = " + $pfx.Thumbprint)
}
}
#### FUNCTIONS - END ####
#### SCRIPT - START ####
$sharedPath = "D:\AllContent\SharedSSL\Local"
$authRootLoc = "Cert:\LocalMachine\AuthRoot"
$pfxPassword = "your password" # need to set this
$pfxs = dir $sharedPath -file -Filter *.pfx
foreach($pfx in $pfxs) {
$cert = Get-X509Certificate -PfxFile $pfx.FullName -PfxPassword $pfxSecret.Password
$certPath = "$authRootLoc\$($cert.Thumbprint)"
if((Test-Path $certPath) -eq $false) {
$null = Import-PfxCertificate -FilePath $pfx.FullName -CertStoreLocation $authRootLoc -Password $pfxPassword -Exportable
Write-Host "$($cert.Subject) ($($cert.Thumbprint)) Added"
} else {
Write-Host "$($cert.Subject) ($($cert.Thumbprint)) Already Exists"
}
}
#### SCRIPT - END ####
} finally {
foreach($er in $Error) { $er }
Disable-LogFile $log
}
### Install-Add-SslCertsToAuthRoot.ps1
$yourUsername = "your username" # needs local admin rights on your machine (you probably have it)
$yourPassword = "your password"
$name = "Add-SslCertsToAuthRoot"
$filename = "$name.ps1"
$fp = "D:\AllContent\Scripts\IIS\$filename"
$taskName = $name
$fp = "powershell $fp"
$found = . schtasks.exe /query /tn "$taskName" 2>null
if($found -ne $null) {
. schtasks.exe /delete /tn "$taskName" /f
$found = $null
}
if($found -eq $null) {
. schtasks.exe /create /ru $yourUsername /rp $yourPassword /tn "$taskName" /sc daily /st "01:00" /tr "$fp"
. schtasks.exe /run /tn "$taskName"
}