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" }