Last active
March 1, 2024 22:45
-
-
Save mavaddat/a88d7938bffb8e439b6b9d887406f41c to your computer and use it in GitHub Desktop.
PowerShell script to add all Windows Certificates to the Java keystore for all visible JDK paths. Answer to StackOverflow question here: https://stackoverflow.com/questions/14532383/pem-file-from-microsoft-serialized-store-sst-files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Version 6.0 | |
#Requires -RunAsAdministrator | |
$jdkPaths = Get-Command -Name java -All | Where-Object -FilterScript { Test-Path -Path (Join-Path -Path ($_ | Split-Path -Parent) -ChildPath 'keytool.exe') } | Select-Object -ExpandProperty Path | Split-Path -Parent | Sort-Object -Unique | |
[array]$jdkPaths += Resolve-Path -Path "c:\Users\B0649033\.vscode*\extensions\redhat.java-*\jre\*\bin" | Select-Object -ExpandProperty Path | |
# Calculate existing certs first | |
$certBag = [System.Collections.Concurrent.ConcurrentBag[PSCustomObject]]::new() | |
$jdkPaths | ForEach-Object -Parallel { | |
# Parallel work for each JDK, since their respective stores do not conflict | |
$certBag = $using:certBag | |
$_ | Push-Location | |
$keytoolCerts = .\keytool.exe -keystore cacerts -storepass changeit -list 2>$null | Select-Object -Skip 5 # The first 4 lines are information messages followed by empty newline | |
#region Parse the output of keytool.exe | |
for ($i = 0; $i -lt $keytoolCerts.Count; $i += 2) | |
{ | |
$certBag.Add( | |
( | |
$keytoolCerts[$i] | Select-String -Pattern '(?<alias>[^,]+), (?<date>\w{3}\. \d+, \d{4}), (?<storeType>[^,]+)' | Select-Object -ExpandProperty Matches | ForEach-Object { | |
[PSCustomObject]@{ | |
Keystore = $PWD | |
Alias = $_.Groups['alias'].Value # This is the only information we care about, but I parse of the rest of the output for funsies | |
Date = [datetime]::Parse($_.Groups['date'].Value) | |
StoreType = $_.Groups['storeType'].Value | |
Fingerprint = ( | |
$keytoolCerts[$i + 1] | Select-String -Pattern '[^\(]+\(([^\)]+)\): (.*)' | ForEach-Object { | |
[PSCustomObject]@{ | |
Algorithm = $_.Matches.Groups[1].Value | |
Bytes = [byte[]]($_.Matches.Groups[2].Value -split ':' -replace '^', '0x') | |
} | |
} | |
) | |
} | |
} | |
) | |
) | |
} | |
#endregion Parse the output of keytool.exe | |
Pop-Location | |
} -ThrottleLimit $env:NUMBER_OF_PROCESSORS | |
# Retrieve all certificates under the Cert:\ path (including subdirectories), with a valid Thumbprint property. | |
[System.Security.Cryptography.X509Certificates.X509Certificate2[]]$certs = Get-ChildItem -Path Cert:\ -Recurse | Where-Object { $_.Thumbprint } | |
$jdkPaths | ForEach-Object -Parallel { | |
$addedCertAliases = [System.Collections.Generic.HashSet[string]]::new() | |
$certBag = $using:certBag | |
$jdkPath = $_ | |
foreach($cert in $using:certs) { | |
$thumb = $cert.Thumbprint # This is a hash of the certificate, and is unique | |
$alias = $cert.FriendlyName # Most readable for humans | |
if ([string]::IsNullOrEmpty($alias)) | |
{ | |
$alias = $cert.Subject -replace '\W' # Slightly less readable for humans | |
} | |
if ([string]::IsNullOrEmpty($alias)) | |
{ | |
$alias = $thumb # Least readable for humans | |
} | |
$aliasNum = 1 | |
# Ensure the alias is unique | |
$tempAlias = $alias | |
while ($addedCertAliases.Contains($tempAlias)) | |
{ | |
$tempAlias = "$alias ($aliasNum)" | |
$aliasNum++ | |
} | |
$alias = $tempAlias | |
$addedCertAliases.Add($alias) | Out-Null | |
$exportNameStream = [System.IO.MemoryStream]::new([System.Text.Encoding]::UTF8.GetBytes($thumb + "$jdkPath")) | |
$export = $_ | Export-Certificate -Type CERT -FilePath "$env:TEMP\$thumb.cer" -Force # Export the certificate to a temporary file | |
try | |
{ | |
# Get all the JDK paths | |
$jdkPaths | ForEach-Object { | |
$_ | Push-Location | |
$existingKeys = $certBag | Where-Object -FilterScript { $_.Keystore -like $PWD -and $_.Alias -like $alias } | |
if ($null -ne $existingKeys) | |
{ | |
# Remove the existing certificate from the keystore | |
.\keytool.exe -trustcacerts -keystore cacerts -storepass changeit -noprompt -delete -alias "$alias" | |
} | |
Write-Host 'Adding certificate ' -ForegroundColor DarkCyan -NoNewline | |
Write-Host "$alias" -ForegroundColor Cyan -NoNewline | |
Write-Host ' to keystore ' -ForegroundColor DarkCyan -NoNewline | |
Write-Host "$PWD" -ForegroundColor Cyan -NoNewline | |
Write-Host '...' -ForegroundColor DarkCyan | |
.\keytool.exe -trustcacerts -keystore cacerts -storepass changeit -noprompt -importcert -alias "$alias" -file "$export" | |
Pop-Location | |
} | |
} | |
finally | |
{ | |
Remove-Item -Path $export -Force | |
} | |
} | |
} -ThrottleLimit $env:NUMBER_OF_PROCESSORS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment