FAQ - Duplicate Certificate Detection Testing Scenarios
Validate Duplicate Certificate Detection monitoring with automated PowerShell test scripts covering all detection scenarios - from same-store duplicates and cross-store issues to high-risk multiple private key scenarios.
What's on This Page:
- 5 Test Scenarios - Automated PowerShell 7 scripts for Same Store Duplicates, Multiple Private Keys, Cross-Store Duplicates, Threshold Testing, and Proper Renewal Cleanup
- Batch Testing Script - Create all test scenarios with configurable flags
- Cleanup Script - Remove test certificates after validation testing
- Configuration Guide - Enable duplicate detection and configure alert thresholds
- Troubleshooting - Resolve duplicate-specific issues (renewal confusion, private key risk)
Why Test Duplicate Detection?
Duplicate certificate testing prevents production incidents caused by certificate selection ambiguity. Testing ensures monitoring correctly identifies:
- ⚠️ Same-store duplicates (WARNING) - Multiple certificates with identical Subject/SAN in same store
- ❌ Multiple private keys (ERROR) - High-risk scenario where applications may select wrong certificate
- ⚠️ Cross-store duplicates (WARNING) - Certificate exists in both LocalMachine and CurrentUser stores
- ⚠️ Threshold exceeded (WARNING) - Duplicate count exceeds configured maximum
- ✅ Proper cleanup (OK) - Old certificates removed after renewal verification
Related Documentation: See Duplicate Certificate Detection for complete feature documentation, remediation workflows, and configuration options.
Note
These scripts require PowerShell 7+ with Administrator privileges for certificate store access.
Warning
Never deploy test certificates to production environments. Always clean up after validation testing.
Testing Scenarios Overview
| # | Scenario | Purpose | Expected State | Key Focus |
|---|---|---|---|---|
| 1 | Same Store Duplicates | 2+ certificates with identical Subject/SAN | ⚠️ WARNING | Renewal overlap detection |
| 2 | High-Risk Duplicates | Multiple certificates with private keys | ❌ ERROR | Application selection ambiguity |
| 3 | Cross-Store Duplicates | Certificate in LocalMachine & CurrentUser | ⚠️ WARNING | Cross-store inventory issue |
| 4 | Renewal Success | Old certificate removed after renewal | ✅ OK | Proper cleanup verification |
| 5 | Threshold Exceeded | Duplicates exceed configured maximum | ⚠️ WARNING | Threshold enforcement |
Test Scenario Workflow
Diagram: Duplicate certificate detection test workflow showing scenario configuration, expected states, and monitoring verification process with color-coded severity levels.
Test Scenarios
Scenario 1: Same Store Duplicates
Purpose: Validate detection of multiple certificates with identical Subject/SAN in the same store.
Configuration:
| Setting | Value | Rationale |
|---|---|---|
| Certificate Type | Self-signed (test certificates) | Creates controlled duplicate scenario |
| Subject | CN=duplicate.test.com |
Identical Subject for both certificates |
| Store Location | Cert:\LocalMachine\My |
Same store for both certificates |
| Certificate Count | 2 certificates | Simulates renewal overlap |
| Private Keys | Both have private keys initially | Tests detection logic |
| Validity Period | 1 year | Standard test certificate lifetime |
Expected Results:
| Aspect | Value |
|---|---|
| State | ⚠️ WARNING |
| Detection | 2 certificates with identical Subject/SAN detected |
| Alert Message | "Duplicate Certificate Detected - Subject: CN=duplicate.test.com" |
| Details | Shows count: "2 certificates with identical Subject/SAN" |
| Thumbprints | Lists both certificate thumbprints for identification |
| Recommendation | Remove old certificate after renewal verification |
Scenario 2: High-Risk Duplicates (Multiple Private Keys)
Purpose: Validate ERROR state when multiple certificates with identical Subject/SAN all have private keys.
Configuration:
| Setting | Value | Rationale |
|---|---|---|
| Certificate Type | Self-signed (test certificates) | Creates controlled high-risk scenario |
| Subject | CN=privatekey.test.com |
Identical Subject for both certificates |
| Store Location | Cert:\LocalMachine\My |
Same store for both certificates |
| Certificate Count | 2 certificates | Both have private keys |
| Private Keys | YES for both certificates | HIGH RISK: Application selection ambiguity |
| Validity Period | 1 year | Standard test certificate lifetime |
Expected Results:
| Aspect | Value |
|---|---|
| State | ❌ ERROR |
| Risk Level | HIGH RISK |
| Detection | Multiple certificates with identical Subject/SAN all have private keys |
| Alert Message | "High-Risk Duplicate Certificate - Multiple private keys detected" |
| Impact | Applications may select wrong certificate with unpredictable results |
| Recommendation | Remove old certificate immediately |
Scenario 3: Cross-Store Duplicates
Purpose: Validate detection of certificates duplicated across LocalMachine and CurrentUser stores.
Configuration:
| Setting | Value | Rationale |
|---|---|---|
| Certificate Type | Self-signed (test certificate) | Creates controlled cross-store scenario |
| Subject | CN=crossstore.test.com |
Identifies cross-store test |
| Store Locations | Cert:\LocalMachine\My AND Cert:\CurrentUser\My |
Same certificate in both stores |
| Duplication Method | Export from LocalMachine, import to CurrentUser | Simulates accidental duplication |
| Thumbprint | Identical in both stores | Same certificate, different locations |
Expected Results:
| Aspect | Value |
|---|---|
| State | ⚠️ WARNING |
| Detection | Certificate exists in multiple stores |
| Alert Message | "Cross-Store Duplicate Detected - Certificate exists in multiple stores" |
| Store Details | Shows both Cert:\LocalMachine\My and Cert:\CurrentUser\My |
| Recommendation | Remove from unnecessary stores (consolidate to single store) |
Scenario 4: Renewal Success (Single Valid Certificate)
Purpose: Validate OK state when old certificate is properly removed after renewal.
Configuration:
| Setting | Value | Rationale |
|---|---|---|
| Certificate Type | Self-signed (test certificates) | Simulates renewal workflow |
| Subject | CN=renewal.test.com |
Identifies renewal test scenario |
| Store Location | Cert:\LocalMachine\My |
Standard certificate store |
| Original Certificate | Expires in 30 days | Old certificate nearing expiration |
| Renewed Certificate | Expires in 1 year | New certificate with extended validity |
| Cleanup Action | Remove old certificate after renewal | Proper cleanup prevents duplicates |
Expected Results:
| Aspect | Value |
|---|---|
| State | ✅ OK |
| Detection | Single certificate remains after cleanup |
| Duplicate Count | 0 (no duplicates) |
| Recommendation | No action needed (proper certificate management) |
Scenario 5: Allowed Duplicates (Within Threshold)
Purpose: Validate threshold configuration - duplicates within acceptable limit.
Configuration:
| Setting | Value | Rationale |
|---|---|---|
| Certificate Type | Self-signed (test certificates) | Creates controlled threshold test |
| Subject | CN=threshold.test.com |
Identifies threshold test scenario |
| Store Location | Cert:\LocalMachine\My |
Standard certificate store |
| Certificate Count | 2 certificates | Tests threshold enforcement |
| MaxAllowedDuplicates | Configurable (1 or 2) | Determines alert behavior |
Expected Results:
| Configuration | State | Explanation |
|---|---|---|
| MaxAllowedDuplicates = 2, Count = 2 | ✅ OK | At threshold (no alert) |
| MaxAllowedDuplicates = 1, Count = 2 | ⚠️ WARNING | Exceeds threshold (alert triggered) |
Batch Duplicate Certificate Testing Script
Purpose: Create all 5 test scenarios with a single PowerShell script.
# Nodinite Duplicate Certificate Detection Testing Suite
# Tests duplicate detection across same store, cross-store, and private key scenarios
# Requires: PowerShell 7+, Administrator privileges
# Usage: .\Test-DuplicateDetection.ps1
Write-Host "=== Nodinite Duplicate Certificate Detection Testing Suite ===" -ForegroundColor Magenta
Write-Host "Creating comprehensive duplicate certificate test scenarios..." -ForegroundColor Cyan
if ($PSVersionTable.PSVersion.Major -ge 7) {
Write-Host "Note: Running in PowerShell $($PSVersionTable.PSVersion.Major). Some certificate operations work best in Windows PowerShell 5.1" -ForegroundColor Yellow
}
$testCertificates = @()
$testErrors = @()
try {
Write-Host "`n Creating duplicate certificate test scenarios" -ForegroundColor Blue
# Scenario 1: Same Store Duplicates
Write-Host "`n[Scenario 1/5] Creating duplicates in LocalMachine\My store..." -ForegroundColor Green
try {
$dup1 = New-SelfSignedCertificate `
-Subject "CN=duplicate.test.com" `
-DnsName "duplicate.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Duplicate Test - Original" `
-ErrorAction Stop
$dup2 = New-SelfSignedCertificate `
-Subject "CN=duplicate.test.com" `
-DnsName "duplicate.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Duplicate Test - Renewal" `
-ErrorAction Stop
$testCertificates += @{ Scenario = "Same Store"; Subject = "CN=duplicate.test.com"; Count = 2; Store = "LocalMachine\My"; Thumbprints = @($dup1.Thumbprint, $dup2.Thumbprint) }
Write-Host " Created 2 duplicate certificates in LocalMachine\My" -ForegroundColor Green
Write-Host " • Thumbprint 1: $($dup1.Thumbprint.Substring(0,16))..." -ForegroundColor White
Write-Host " • Thumbprint 2: $($dup2.Thumbprint.Substring(0,16))..." -ForegroundColor White
}
catch {
$testErrors += "Scenario 1 (Same Store Duplicates): $_"
Write-Host " Failed to create same-store duplicates: $_" -ForegroundColor Red
}
# Scenario 2: High-Risk Private Key Duplicates
Write-Host "`n[Scenario 2/5] Creating high-risk duplicates with private keys..." -ForegroundColor Green
try {
$privkey1 = New-SelfSignedCertificate `
-Subject "CN=privatekey.test.com" `
-DnsName "privatekey.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Private Key Risk - Original" `
-ErrorAction Stop
$privkey2 = New-SelfSignedCertificate `
-Subject "CN=privatekey.test.com" `
-DnsName "privatekey.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Private Key Risk - Duplicate" `
-ErrorAction Stop
# Verify both have private keys
$key1_has = $privkey1.HasPrivateKey
$key2_has = $privkey2.HasPrivateKey
$testCertificates += @{ Scenario = "High-Risk Private Keys"; Subject = "CN=privatekey.test.com"; Count = 2; PrivateKeys = @($key1_has, $key2_has); RiskLevel = "HIGH" }
Write-Host " Created 2 high-risk duplicate certificates with private keys" -ForegroundColor Green
Write-Host " • Certificate 1 has private key: $key1_has" -ForegroundColor White
Write-Host " • Certificate 2 has private key: $key2_has" -ForegroundColor White
Write-Host " • Expected Alert: ERROR - High-Risk Duplicate (multiple private keys)" -ForegroundColor Yellow
}
catch {
$testErrors += "Scenario 2 (Private Key Duplicates): $_"
Write-Host " Failed to create private key duplicates: $_" -ForegroundColor Red
}
# Scenario 3: Cross-Store Duplicates
Write-Host "`n[Scenario 3/5] Creating cross-store duplicates..." -ForegroundColor Green
try {
# Create in LocalMachine
$crossstore1 = New-SelfSignedCertificate `
-Subject "CN=crossstore.test.com" `
-DnsName "crossstore.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Cross-Store - Machine Store" `
-ErrorAction Stop
# Export for import to CurrentUser
$exportPath = "C:\temp\crossstore-cert-$([Guid]::NewGuid().ToString().Substring(0,8)).cer"
Export-Certificate -Cert $crossstore1 -FilePath $exportPath -Force -ErrorAction Stop | Out-Null
# Import to CurrentUser
Import-Certificate -FilePath $exportPath -CertStoreLocation Cert:\CurrentUser\My -ErrorAction Stop | Out-Null
$testCertificates += @{ Scenario = "Cross-Store"; Subject = "CN=crossstore.test.com"; Stores = @("Cert:\LocalMachine\My", "Cert:\CurrentUser\My"); ExportPath = $exportPath }
Write-Host " Created cross-store duplicate certificate" -ForegroundColor Green
Write-Host " • LocalMachine\My: $($crossstore1.Thumbprint.Substring(0,16))..." -ForegroundColor White
Write-Host " • CurrentUser\My: [Same thumbprint, different store]" -ForegroundColor White
}
catch {
$testErrors += "Scenario 3 (Cross-Store Duplicates): $_"
Write-Host " Failed to create cross-store duplicates: $_" -ForegroundColor Red
}
# Scenario 4: Threshold Test (3 duplicates)
Write-Host "`n[Scenario 4/5] Creating multiple duplicates to test threshold..." -ForegroundColor Green
try {
$threshold1 = New-SelfSignedCertificate `
-Subject "CN=threshold.test.com" `
-DnsName "threshold.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Threshold Test - Cert 1" `
-ErrorAction Stop
$threshold2 = New-SelfSignedCertificate `
-Subject "CN=threshold.test.com" `
-DnsName "threshold.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Threshold Test - Cert 2" `
-ErrorAction Stop
$threshold3 = New-SelfSignedCertificate `
-Subject "CN=threshold.test.com" `
-DnsName "threshold.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Threshold Test - Cert 3" `
-ErrorAction Stop
$testCertificates += @{ Scenario = "Threshold Test"; Subject = "CN=threshold.test.com"; Count = 3; ExpectedAlert = "If MaxAllowedDuplicates < 3" }
Write-Host " Created 3 duplicate certificates to test threshold" -ForegroundColor Green
Write-Host " • Alert if MaxAllowedDuplicates = 1 or 2" -ForegroundColor White
Write-Host " • No alert if MaxAllowedDuplicates >= 3" -ForegroundColor White
}
catch {
$testErrors += "Scenario 4 (Threshold Test): $_"
Write-Host " Failed to create threshold test certificates: $_" -ForegroundColor Red
}
# Scenario 5: Renewal Success (No Duplicates)
Write-Host "`n[Scenario 5/5] Creating proper renewal (no duplicates)..." -ForegroundColor Green
try {
$original = New-SelfSignedCertificate `
-Subject "CN=renewal.test.com" `
-DnsName "renewal.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddDays(30) `
-FriendlyName "Renewal Test - Original (Expiring)" `
-ErrorAction Stop
$renewed = New-SelfSignedCertificate `
-Subject "CN=renewal.test.com" `
-DnsName "renewal.test.com" `
-CertStoreLocation Cert:\LocalMachine\My `
-NotAfter (Get-Date).AddYears(1) `
-FriendlyName "Renewal Test - New" `
-ErrorAction Stop
# Remove old certificate (proper cleanup)
Remove-Item "Cert:\LocalMachine\My\$($original.Thumbprint)" -Force -ErrorAction Stop
$testCertificates += @{ Scenario = "Proper Renewal"; Subject = "CN=renewal.test.com"; Status = "Old removed"; Remaining = $renewed.Thumbprint }
Write-Host " Created and cleaned up renewal (old cert removed)" -ForegroundColor Green
Write-Host " • Old Certificate: $($original.Thumbprint.Substring(0,16))... [REMOVED]" -ForegroundColor White
Write-Host " • New Certificate: $($renewed.Thumbprint.Substring(0,16))... [KEPT]" -ForegroundColor White
Write-Host " • Expected Alert: NONE (proper cleanup)" -ForegroundColor Green
}
catch {
$testErrors += "Scenario 5 (Proper Renewal): $_"
Write-Host " Failed to create proper renewal test: $_" -ForegroundColor Red
}
}
catch {
Write-Host " Unexpected error during test setup: $_" -ForegroundColor Red
}
# Summary Report
Write-Host "`n" -ForegroundColor White
Write-Host "=== Test Scenario Summary ===" -ForegroundColor Cyan
Write-Host " Test Scenarios Created: $($testCertificates.Count)/5" -ForegroundColor Blue
if ($testCertificates.Count -gt 0) {
Write-Host "`nScenarios:" -ForegroundColor Green
foreach ($scenario in $testCertificates) {
Write-Host " • $($scenario.Scenario) - Subject: $($scenario.Subject)" -ForegroundColor White
}
}
if ($testErrors.Count -gt 0) {
Write-Host "`n Errors Encountered:" -ForegroundColor Yellow
foreach ($error in $testErrors) {
Write-Host " • $error" -ForegroundColor Yellow
}
}
Write-Host "`n Configuration:" -ForegroundColor Blue
Write-Host " • Enable in Settings: Administration → Certificate Monitoring → Duplicates tab" -ForegroundColor White
Write-Host " • Set DetectDuplicateCertificates = true" -ForegroundColor White
Write-Host " • Enable AlertOnDuplicatesWithPrivateKey for high-risk detection" -ForegroundColor White
Write-Host " • Set MaxAllowedDuplicates = 1 (strict) or 2 (renewal in progress)" -ForegroundColor White
Write-Host " • Restart monitoring service" -ForegroundColor White
Write-Host " • Verify duplicate alerts appear in Certificate View" -ForegroundColor White
Write-Host "\n Test setup complete! Duplicate detection scenarios ready for validation." -ForegroundColor Green
Cleanup Script
Remove all test certificates after validation:
## Cleanup Script
**Purpose**: Remove all test certificates after validation testing.
```powershell
# Cleanup Nodinite Duplicate Certificate Test Certificates
Write-Host "=== Cleanup: Duplicate Certificate Test Certificates ===" -ForegroundColor Magenta
Write-Host "Removing all test duplicate certificates..." -ForegroundColor Cyan
$testSubjects = @(
"CN=duplicate.test.com",
"CN=privatekey.test.com",
"CN=crossstore.test.com",
"CN=threshold.test.com",
"CN=renewal.test.com"
)
$removedCount = 0
$cleanupErrors = @()
# Remove from LocalMachine store
Write-Host "`n Removing certificates from LocalMachine\My..." -ForegroundColor Blue
foreach ($subject in $testSubjects) {
try {
$certs = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -eq $subject }
foreach ($cert in $certs) {
Remove-Item "Cert:\LocalMachine\My\$($cert.Thumbprint)" -Force -ErrorAction Stop
Write-Host " Removed $($cert.FriendlyName) (Thumbprint: $($cert.Thumbprint.Substring(0,8))...)" -ForegroundColor Green
$removedCount++
}
}
catch {
$cleanupErrors += "Failed to remove subject '$subject' from LocalMachine: $_"
Write-Host " Failed to remove subject '$subject': $_" -ForegroundColor Red
}
}
# Remove from CurrentUser store
Write-Host "`n Removing certificates from CurrentUser\My..." -ForegroundColor Blue
foreach ($subject in $testSubjects) {
try {
$certs = Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -eq $subject }
foreach ($cert in $certs) {
Remove-Item "Cert:\CurrentUser\My\$($cert.Thumbprint)" -Force -ErrorAction Stop
Write-Host " Removed $($cert.FriendlyName) from CurrentUser\My" -ForegroundColor Green
$removedCount++
}
}
catch {
$cleanupErrors += "Failed to remove subject '$subject' from CurrentUser: $_"
Write-Host " Failed to remove from CurrentUser: $_" -ForegroundColor Yellow
}
}
# Cleanup temporary export files
Write-Host "`n Removing temporary export files..." -ForegroundColor Blue
try {
$tempFiles = Get-ChildItem "C:\temp\crossstore-cert-*.cer" -ErrorAction SilentlyContinue
foreach ($file in $tempFiles) {
Remove-Item $file.FullName -Force -ErrorAction Stop
Write-Host " Removed temporary file: $($file.Name)" -ForegroundColor Green
}
}
catch {
Write-Host " Note: Some temporary files may not exist" -ForegroundColor Yellow
}
# Cleanup Summary
Write-Host "`n=== Cleanup Summary ===" -ForegroundColor Cyan
Write-Host " Test Certificates Removed: $removedCount" -ForegroundColor Green
if ($cleanupErrors.Count -gt 0) {
Write-Host "`n Errors During Cleanup:" -ForegroundColor Yellow
foreach ($error in $cleanupErrors) {
Write-Host " • $error" -ForegroundColor Yellow
}
Write-Host "`nNote: Some certificates may have already been removed. Review above for any critical errors." -ForegroundColor Yellow
}
Write-Host "\n Cleanup complete! Test certificates removed." -ForegroundColor Green
Frequently Asked Questions
Q1: Why is cross-store duplication considered a WARNING instead of just informational?
A: Cross-store duplication typically indicates misconfiguration or accidental backup/restore operations. When the same certificate exists in both Cert:\LocalMachine\My and Cert:\CurrentUser\My, it creates management overhead and potential confusion during renewals. Applications and services may look in different stores, leading to inconsistent behavior. WARNING severity ensures administrators are notified to consolidate certificates to the appropriate single store.
Q2: What happens if I have multiple certificates with private keys for the same Subject/SAN?
A: This is a HIGH RISK scenario (ERROR state) because applications may select the wrong certificate unpredictably. For example, IIS rebinds HTTPS connections during application pool recycles and selects certificates by Subject/SAN match, not by expiration date. If multiple certificates with private keys exist, IIS might choose an expired certificate, causing production outages. Always remove old certificates with private keys immediately after renewal verification.
Q3: How do I configure the duplicate certificate threshold?
A: Navigate to Administration → Settings → Certificate Monitoring → Duplicates tab and configure:
- DetectDuplicateCertificates =
true(enables detection) - MaxAllowedDuplicates =
1(strict - alerts on any duplicate) or2(tolerates renewal overlap) - AlertOnDuplicatesWithPrivateKey =
true(enables high-risk ERROR alerts) - TreatDuplicatesAsError =
false(WARNING) ortrue(ERROR for all duplicates)
Restart the monitoring service after configuration changes. Set MaxAllowedDuplicates = 2 during planned renewal windows to avoid false alerts.