Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps-integration/windows-cmp-enrollment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ Files are prefixed with the CN (Common Name) from the Subject DN:
- Installs to the certificate store(s) specified by `-CertificateStore`:
- **LocalMachine** (default): installs to `LocalMachine\Personal`; private key stored in machine key store
- **CurrentUser**: installs to `CurrentUser\Personal`; private key stored in user key store
- **Both**: installs to `LocalMachine\Personal` first, then copies the certificate and private key into `CurrentUser\Personal` via a temporary PFX
- **Both**: installs to `LocalMachine\Personal` first, then copies the certificate and private key into `CurrentUser\Personal` via a temporary PFX. Uses `Export/Import-PfxCertificate` on Windows 8+, or `certutil -exportPFX` / `certutil -user -importPFX` on Windows 7
- Associates certificate with private key generated in Step 1

### Step 5: Export to PFX (Optional)
Expand All @@ -252,6 +252,8 @@ The target store is controlled by the `-CertificateStore` parameter:
| `CurrentUser` | `CurrentUser\Personal` | User key store (current user only) | None |
| `Both` | `LocalMachine\Personal` and `CurrentUser\Personal` | Both key stores | Administrator |

When `Both` is selected, the script installs to `LocalMachine\Personal` first (via `certreq -accept`), then copies the certificate and private key into `CurrentUser\Personal` using a temporary PFX with a randomly generated password. On Windows 7, where `Export-PfxCertificate` and `Import-PfxCertificate` are unavailable, `certutil -exportPFX` and `certutil -user -importPFX` are used instead.

## Troubleshooting

### Common Issues
Expand Down
72 changes: 49 additions & 23 deletions apps-integration/windows-cmp-enrollment/cmp-enrollment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -560,30 +560,56 @@ if ($CertificateStore -eq "Both") {
$bothThumbprint = $matches[1] -replace ":", ""
Write-Log "Thumbprint for cross-store copy: $bothThumbprint"

$lmCert = Get-ChildItem -Path "Cert:\LocalMachine\My" |
Where-Object { $_.Thumbprint -ieq $bothThumbprint } |
Select-Object -First 1

if ($null -eq $lmCert) {
Write-Log "WARNING: Could not find certificate in LocalMachine\My by thumbprint. Skipping CurrentUser install." -AlwaysShow
} else {
# Export to a temporary PFX with a random password, import into CurrentUser\My, then delete
$tempPfxPath = Join-Path $BasePath "$sanitizedCN-temp-cross-store.pfx"
$tempPfxBytes = New-Object byte[] 32
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($tempPfxBytes)
$tempPfxPassword = [Convert]::ToBase64String($tempPfxBytes)
$tempPfxSecure = ConvertTo-SecureString -String $tempPfxPassword -AsPlainText -Force

try {
Export-PfxCertificate -Cert $lmCert -FilePath $tempPfxPath -Password $tempPfxSecure -ChainOption BuildChain | Out-Null
Import-PfxCertificate -FilePath $tempPfxPath -CertStoreLocation "Cert:\CurrentUser\My" -Password $tempPfxSecure | Out-Null
Write-Log "Certificate and private key installed to: CurrentUser\Personal"
} catch {
Write-Log "ERROR installing certificate to CurrentUser\Personal: $_" -AlwaysShow
} finally {
if (Test-Path $tempPfxPath) { Remove-Item -Force $tempPfxPath -ErrorAction SilentlyContinue }
$tempPfxPassword = $null
$tempPfxPath = Join-Path $BasePath "$sanitizedCN-temp-cross-store.pfx"

# Generate a cryptographically random temporary PFX password
$tempPfxBytes = New-Object byte[] 32
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($tempPfxBytes)
$tempPfxPassword = [Convert]::ToBase64String($tempPfxBytes)

$bothOsVersion = [System.Environment]::OSVersion.Version
$bothIsWin7OrOlder = ($bothOsVersion.Major -lt 6) -or ($bothOsVersion.Major -eq 6 -and $bothOsVersion.Minor -lt 2)

try {
if ($bothIsWin7OrOlder) {
# Windows 7 / older: Export-PfxCertificate and Import-PfxCertificate are not available.
# Use certutil -exportPFX / certutil -user -importPFX instead.
Write-Log "Detected Windows 7 or older - using certutil for cross-store copy"

$exportArgs = @("-exportPFX", "-p", $tempPfxPassword, "My", $bothThumbprint, "`"$tempPfxPath`"")
$exportOut = & certutil.exe @exportArgs 2>&1
Write-Log "certutil -exportPFX output: $exportOut"

if (!(Test-Path $tempPfxPath)) {
Write-Log "WARNING: certutil -exportPFX did not produce a file. Skipping CurrentUser install." -AlwaysShow
} else {
$importArgs = @("-user", "-p", $tempPfxPassword, "-importPFX", "My", "`"$tempPfxPath`"")
$importOut = & certutil.exe @importArgs 2>&1
Write-Log "certutil -importPFX output: $importOut"
Write-Log "Certificate and private key installed to: CurrentUser\Personal"
}
} else {
# Windows 8+: use the PKI cmdlets
Write-Log "Detected Windows 8 or newer - using Export/Import-PfxCertificate for cross-store copy"

$lmCert = Get-ChildItem -Path "Cert:\LocalMachine\My" |
Where-Object { $_.Thumbprint -ieq $bothThumbprint } |
Select-Object -First 1

if ($null -eq $lmCert) {
Write-Log "WARNING: Could not find certificate in LocalMachine\My by thumbprint. Skipping CurrentUser install." -AlwaysShow
} else {
$tempPfxSecure = ConvertTo-SecureString -String $tempPfxPassword -AsPlainText -Force
Export-PfxCertificate -Cert $lmCert -FilePath $tempPfxPath -Password $tempPfxSecure -ChainOption BuildChain | Out-Null
Import-PfxCertificate -FilePath $tempPfxPath -CertStoreLocation "Cert:\CurrentUser\My" -Password $tempPfxSecure | Out-Null
Write-Log "Certificate and private key installed to: CurrentUser\Personal"
}
}
} catch {
Write-Log "ERROR installing certificate to CurrentUser\Personal: $_" -AlwaysShow
} finally {
if (Test-Path $tempPfxPath) { Remove-Item -Force $tempPfxPath -ErrorAction SilentlyContinue }
$tempPfxPassword = $null
}
} else {
Write-Log "WARNING: Could not parse thumbprint for CurrentUser install. Skipping." -AlwaysShow
Expand Down