I recently wrote a PowerShell script that will back and replace a certificate as well assign permissions to the private keys.
Basically, what this script does is:
– First checks if the certificate you want to import exists or not
– Perform a back-up of the certificate
– Import the private certificate
– Assign the Everyone group read access on the private key
– Import the public certificate
Note that these actions take place in the Local Machine certificate store and we will work with .PFX format.
The private certificate is marked as exportable so that when you do backup the certificate, you have the ability to re-deploy if needed.
There are a few values that you will need to adjust in this script however:
1 |
$exportPwd = ConvertTo-SecureString -String "1" -Force -AsPlainText |
This line sets the password of the exported certificate to 1. You can change this to any value you want.
1 2 |
$export = gci -Path Cert:\LocalMachine\my\$privateThumbPrint | Export-PfxCertificate -FilePath C:\Test\$subject.pfx -Password $exportPwd Write-Host "[*] $getCerts backup created at C:\Test\$subject.pfx" |
This section tells you where the certificate is being exported to. By default, it is set to C:\Test\
You will need to change all instances of C:\Test\ to the location you want to export on your machine. You could change this to a variable if you want to save to a different location each time or would like to be prompted.
1 |
$permission = "Everyone","Read","Allow" |
This section tells us what permissions are being assigned and to which user/group. Again, you can change these values as needed.
And finally, here is the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
cls $ErrorActionPreference = "Stop" ## Test if we are running as Administrator IF (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` [Security.Principal.WindowsBuiltInRole] "Administrator")) { Write-Warning "You are not running as Administrator!`nPlease re-launch PowerShell and Run As Administrator.`n`nPress any key to quit..." $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit } ELSE { Write-Host "successfully authenticated as Administrator" -ForegroundColor "green" Write-Host "" ## End Administrator Check } $exportPwd = ConvertTo-SecureString -String "1" -Force -AsPlainText DO { $getCerts = (Read-Host "[*] Enter a certificate name") ### BEGIN PRIVATE CERT $privateThumbPrint = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $getCerts}).Thumbprint IF (!$privateThumbPrint) { DO { Write-Warning "$getCerts does not exist!`nYou will now be guided to install this private certificate." Write-Host "" Write-Host "[*] Importing new private certificate..." $certPath = Read-Host "[*] Provide the full path of the private certificate to import" $certPath = $certPath -Replace """", "" $getPass = Read-Host "[*] Provide the password" -AsSecureString $importCert = Import-PfxCertificate -FilePath $certPath Cert:\LocalMachine\my -Password $getPass –Exportable $validFrom = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $getCerts}).NotBefore $validTo = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $getCerts}).NotAfter $subject = ((gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $getCerts}).Subject).Trim("CN=") $subject = ($subject).Trim(".Cert.Agent") Write-Host "[*] New certificate imported" Write-Host "[*] $subject is valid from $validFrom to $validTo" -ForegroundColor "yellow" # Manage private key permissions Write-Host "[*] Setting private key permissions" Write-Host "" $sslCert = gci Cert:\LocalMachine\My | WHERE {$_.Subject -match $getCerts} $sslCertPrivKey = $sslCert.PrivateKey $privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | WHERE {$_.Name -eq $sslCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} $privKeyAcl = (Get-Item -Path $privKeyCertFile.FullName).GetAccessControl("Access") $permission = "Everyone","Read","Allow" $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission $privKeyAcl.AddAccessRule($accessRule) Set-Acl $privKeyCertFile.FullName $privKeyAcl $privateThumbPrint = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $getCerts}).Thumbprint } UNTIL ($privateThumbPrint) } ELSE { $validFrom = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $getCerts}).NotBefore $validTo = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $getCerts}).NotAfter $subject = ((gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $getCerts}).Subject).Trim("CN=") $subject = ($subject).Trim(".Cert.Agent") $export = gci -Path Cert:\LocalMachine\my\$privateThumbPrint | Export-PfxCertificate -FilePath C:\Test\$subject.pfx -Password $exportPwd Write-Host "[*] $getCerts backup created at C:\Test\$subject.pfx" Write-Host "[*] $subject is valid from $validFrom to $validTo" -ForegroundColor "yellow" ## Verify deletion Write-Host "" $title = Write-Host "[*] Do you want to delete $getCerts ?" Write-Host "" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $result = $host.ui.PromptForChoice($title, $message, $options, 0) SWITCH ($result) { 0 { ## Delete cert Write-Host "[*] Deleting $subject..." $deleteCert = Remove-Item Cert:\LocalMachine\my\$privateThumbPrint ## Import new cert Write-Host "" Write-Host "[*] Importing new certificate..." $certPath = Read-Host "[*] Provide the full path of the private certificate to import" $certPath = $certPath -Replace """", "" $getPass = Read-Host "[*] Provide the password" -AsSecureString $importCert = Import-PfxCertificate –FilePath $certPath Cert:\LocalMachine\my -Password $getPass –Exportable Write-Host "[*] New certiciate imported" Write-Host "[*] $subject is valid from $validFrom to $validTo" -ForegroundColor "yellow" ## Manage private key permissions Write-Host "[*] Setting private key permissions..." Write-Host "" $sslCert = gci Cert:\LocalMachine\My | WHERE {$_.Subject -match $getCerts} $sslCertPrivKey = $sslCert.PrivateKey $privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | WHERE {$_.Name -eq $sslCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} $privKeyAcl = (Get-Item -Path $privKeyCertFile.FullName).GetAccessControl("Access") $permission = "Everyone","Read","Allow" $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission $privKeyAcl.AddAccessRule($accessRule) Set-Acl $privKeyCertFile.FullName $privKeyAcl } 1 { Write-Host "[*] $subject will NOT be deleted" Write-Host "" } } } ### END PRIVATE CERT ### BEGIN PUBLIC CERT $publicCert = $getCerts -Replace "ENS","HWS" $publicThumbPrint = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).Thumbprint IF (!$publicThumbPrint) { DO { Write-Warning "$publicCert does not exist!`nYou will now be guided to install this public certificate." Write-Host "" Write-Host "[*] Importing new certificate..." $certPath = Read-Host "[*] Provide the full path of the public certificate to import" $certPath = $certPath -Replace """", "" $importCrt = Import-Certificate -CertStoreLocation Cert:\LocalMachine\my -FilePath $certPath $validFrom = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).NotBefore $validTo = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).NotAfter $subject = ((gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).Subject).Trim("CN=") $publicThumbPrint = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).Thumbprint Write-Host "[*] New certiciate imported" Write-Host "[*] $subject is valid from $validFrom to $validTo" -ForegroundColor "Yellow" Write-Host "" } UNTIL ($publicThumbPrint) } ELSE { $publicCert = $getCerts -Replace "ENS","HWS" Write-Host "[*] Processing Public Certificate $publicCert..." $publicThumbPrint = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).Thumbprint $validFrom = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).NotBefore $validTo = (gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).NotAfter $subject = ((gci -Path Cert:\LocalMachine\my | Where-Object {$_.Subject -match $publicCert}).Subject).Trim("CN=") $subject = ($subject).Trim(".Cert.Agent") $export = gci -Path Cert:\LocalMachine\my\$publicThumbPrint | Export-Certificate -FilePath C:\Test\$subject.crt Write-Host "[*] $publicCert backup created at C:\Test\$subject.crt" Write-Host "[*] $subject is valid from $validFrom to $validTo" Write-Host "" $title = Write-Host "[*] Do you want to delete $publicCert ?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $result = $host.ui.PromptForChoice($title, $message, $options, 0) SWITCH ($result) { 0 { Write-Host "[*] Deleting $subject..." $deleteCert = Remove-Item Cert:\LocalMachine\my\$publicThumbPrint Write-Host "" Write-Host "[*] Importing new certificate..." $certPath = Read-Host "[*] Provide the full path of the public certificate to import" $certPath = $certPath -Replace """", "" $importCrt = Import-Certificate -CertStoreLocation Cert:\LocalMachine\my -FilePath $certPath Write-Host "[*] New certiciate imported" Write-Host "[*] $subject is valid from $validFrom to $validTo" Write-Host "" } 1 { Write-Host "" Write-Host "[*] $subject will NOT be deleted" } } } ### END PUBLIC CERT $title = Write-Host "[*] Do you have another certificate to process?" Write-Host "" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $quitOrNot = $host.ui.PromptForChoice($title, $message, $options, 0) SWITCH ($quitOrNot) { 0 { Write-Host "" } 1 { Write-Host "" Write-Host "Press any key to quit..." $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit } } } UNTIL ($quitOrNot -eq 'n') |