Batch Testing Script – Certificate Purpose and EKU Validation
Create all 6 test certificate scenarios in one script run with a signed test Root CA for chain validation compatibility.
Tip
Chain Validation Compatible: This script creates a test Root CA and issues all 6 certificates signed by that CA. The Root CA is automatically installed to the Trusted Root store, ensuring chain validation passes while testing Purpose/EKU validation. No need to disable chain validation or enable dev mode!
Note
Requires PowerShell 7+ with Administrator privileges. Verify with
$PSVersionTable.PSVersion.
Warning
Never deploy test certificates to production environments. Always run the Cleanup Script after validation testing.
Running the Script
- Open PowerShell 7 as Administrator
- Optionally edit the
$scenarioshashtable to enable/disable specific scenarios - Copy and run the full script below
- Review output — each scenario will show ✅ OK, ⚠️ Warning, or ❌ Critical
- Wait for Nodinite agent discovery (or force sync), then validate monitoring results
- Run the Cleanup Script when finished
Full Script
# Nodinite Certificate Purpose & EKU Validation Testing Suite
# Creates comprehensive test scenarios for Enhanced Key Usage validation
Write-Host "=== Certificate Purpose & EKU Validation Testing Suite ===" -ForegroundColor Magenta
# ============================================================================
# CONFIGURATION - Enable/Disable Test Scenarios
# ============================================================================
$scenarios = @{
ServerAuth = $true # Scenario 1: Server Authentication (EKU 1.3.6.1.5.5.7.3.1)
ClientAuth = $true # Scenario 2: Client Authentication (EKU 1.3.6.1.5.5.7.3.2)
CodeSigning = $true # Scenario 3: Code Signing (EKU 1.3.6.1.5.5.7.3.3)
MultiPurpose = $true # Scenario 4: Multi-Purpose (Warning)
AnyPurpose = $true # Scenario 5: Any Purpose (EKU 2.5.29.37.0 - Critical Risk)
MissingEKU = $true # Scenario 6: Missing EKU (no Extended Key Usage)
}
$certificates = @()
$errorCount = 0
$rootCA = $null
# ============================================================================
# Create Test Root CA (for chain validation)
# ============================================================================
Write-Host "`n[CA] Creating Nodinite Test Root CA..." -ForegroundColor Cyan
Write-Host " This CA will sign all test certificates to ensure chain validation passes." -ForegroundColor Gray
try {
$rootCA = New-SelfSignedCertificate `
-Subject "CN=Nodinite Test Root CA, O=Nodinite Testing, OU=Test PKI" `
-FriendlyName "Nodinite Test - Root CA" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-KeyLength 4096 `
-HashAlgorithm SHA256 `
-KeyUsage CertSign, CRLSign, DigitalSignature `
-KeyExportPolicy Exportable `
-NotBefore (Get-Date).AddMinutes(-5) `
-NotAfter (Get-Date).AddYears(5) `
-Extension @(
New-Object System.Security.Cryptography.X509Certificates.X509BasicConstraintsExtension($true, $true, 0, $true)
)
# Copy CA to Trusted Root store (so chain validation passes)
$rootCertBytes = $rootCA.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
$rootCertObj = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(,$rootCertBytes)
$rootStore = New-Object System.Security.Cryptography.X509Certificates.X509Store("Root", "LocalMachine")
$rootStore.Open("ReadWrite")
$rootStore.Add($rootCertObj)
$rootStore.Close()
Write-Host " ✅ Root CA Created: $($rootCA.Thumbprint)" -ForegroundColor Green
Write-Host " ✅ Installed to Trusted Root store (chain validation will pass)" -ForegroundColor Green
} catch {
Write-Host " ✗ Failed to create Root CA: $($_.Exception.Message)" -ForegroundColor Red
Write-Host " Cannot continue without CA. Exiting." -ForegroundColor Red
exit 1
}
# ============================================================================
# Scenario 1: Server Authentication Certificate
# OID 1.3.6.1.5.5.7.3.1 = Server Authentication
# ============================================================================
if ($scenarios.ServerAuth) {
Write-Host "`n[1/6] Creating Server Authentication certificate..." -ForegroundColor Cyan
try {
$cert = New-SelfSignedCertificate `
-Subject "CN=Nodinite-Test-ServerAuth, O=Nodinite Testing" `
-FriendlyName "Nodinite Test - Server Authentication" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-Signer $rootCA `
-KeyLength 2048 `
-HashAlgorithm SHA256 `
-KeyUsage DigitalSignature, KeyEncipherment `
-KeyExportPolicy Exportable `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1") `
-NotBefore (Get-Date).AddMinutes(-5) `
-NotAfter (Get-Date).AddDays(90)
$certificates += @{ Name = "Server Authentication"; Thumbprint = $cert.Thumbprint; Store = "LocalMachine\My"; Expected = "OK" }
Write-Host " ✅ Created: $($cert.Thumbprint)" -ForegroundColor Green
} catch {
Write-Host " ✗ Failed: $($_.Exception.Message)" -ForegroundColor Red
$errorCount++
}
}
# ============================================================================
# Scenario 2: Client Authentication Certificate
# OID 1.3.6.1.5.5.7.3.2 = Client Authentication
# ============================================================================
if ($scenarios.ClientAuth) {
Write-Host "`n[2/6] Creating Client Authentication certificate..." -ForegroundColor Cyan
try {
$cert = New-SelfSignedCertificate `
-Subject "CN=Nodinite-Test-ClientAuth, O=Nodinite Testing" `
-FriendlyName "Nodinite Test - Client Authentication" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-Signer $rootCA `
-KeyLength 2048 `
-HashAlgorithm SHA256 `
-KeyUsage DigitalSignature `
-KeyExportPolicy Exportable `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2") `
-NotBefore (Get-Date).AddMinutes(-5) `
-NotAfter (Get-Date).AddDays(90)
$certificates += @{ Name = "Client Authentication"; Thumbprint = $cert.Thumbprint; Store = "LocalMachine\My"; Expected = "OK" }
Write-Host " ✅ Created: $($cert.Thumbprint)" -ForegroundColor Green
} catch {
Write-Host " ✗ Failed: $($_.Exception.Message)" -ForegroundColor Red
$errorCount++
}
}
# ============================================================================
# Scenario 3: Code Signing Certificate
# OID 1.3.6.1.5.5.7.3.3 = Code Signing
# ============================================================================
if ($scenarios.CodeSigning) {
Write-Host "`n[3/6] Creating Code Signing certificate..." -ForegroundColor Cyan
try {
$cert = New-SelfSignedCertificate `
-Subject "CN=Nodinite-Test-CodeSigning, O=Nodinite Testing" `
-FriendlyName "Nodinite Test - Code Signing" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-Signer $rootCA `
-KeyLength 2048 `
-HashAlgorithm SHA256 `
-KeyUsage DigitalSignature `
-KeyExportPolicy Exportable `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3") `
-NotBefore (Get-Date).AddMinutes(-5) `
-NotAfter (Get-Date).AddDays(90)
$certificates += @{ Name = "Code Signing"; Thumbprint = $cert.Thumbprint; Store = "LocalMachine\My"; Expected = "OK" }
Write-Host " ✅ Created: $($cert.Thumbprint)" -ForegroundColor Green
} catch {
Write-Host " ✗ Failed: $($_.Exception.Message)" -ForegroundColor Red
$errorCount++
}
}
# ============================================================================
# Scenario 4: Multi-Purpose Certificate (Warning)
# OID 1.3.6.1.5.5.7.3.1 = Server Auth + OID 1.3.6.1.5.5.7.3.2 = Client Auth
# ============================================================================
if ($scenarios.MultiPurpose) {
Write-Host "`n[4/6] Creating Multi-Purpose certificate..." -ForegroundColor Yellow
try {
$cert = New-SelfSignedCertificate `
-Subject "CN=Nodinite-Test-MultiPurpose, O=Nodinite Testing, OU=Warning" `
-FriendlyName "Nodinite Test - Multi-Purpose (Warning)" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-Signer $rootCA `
-KeyLength 2048 `
-HashAlgorithm SHA256 `
-KeyUsage DigitalSignature, KeyEncipherment `
-KeyExportPolicy Exportable `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2") `
-NotBefore (Get-Date).AddMinutes(-5) `
-NotAfter (Get-Date).AddDays(90)
$certificates += @{ Name = "Multi-Purpose"; Thumbprint = $cert.Thumbprint; Store = "LocalMachine\My"; Expected = "Warning" }
Write-Host " ⚠️ Created: $($cert.Thumbprint)" -ForegroundColor Yellow
} catch {
Write-Host " ✗ Failed: $($_.Exception.Message)" -ForegroundColor Red
$errorCount++
}
}
# ============================================================================
# Scenario 5: Any Purpose Certificate (Critical Risk)
# OID 2.5.29.37.0 = Any Purpose (unrestricted usage - maximum security risk)
# ============================================================================
if ($scenarios.AnyPurpose) {
Write-Host "`n[5/6] Creating Any Purpose certificate (SECURITY RISK)..." -ForegroundColor Red
try {
$cert = New-SelfSignedCertificate `
-Subject "CN=Nodinite-Test-AnyPurpose, O=Nodinite Testing, OU=CRITICAL RISK" `
-FriendlyName "Nodinite Test - Any Purpose (CRITICAL)" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-Signer $rootCA `
-KeyLength 2048 `
-HashAlgorithm SHA256 `
-KeyUsage DigitalSignature, KeyEncipherment `
-KeyExportPolicy Exportable `
-TextExtension @("2.5.29.37={text}2.5.29.37.0") `
-NotBefore (Get-Date).AddMinutes(-5) `
-NotAfter (Get-Date).AddDays(90)
$certificates += @{ Name = "Any Purpose"; Thumbprint = $cert.Thumbprint; Store = "LocalMachine\My"; Expected = "Critical" }
Write-Host " ❌ Created: $($cert.Thumbprint)" -ForegroundColor Red
} catch {
Write-Host " ✗ Failed: $($_.Exception.Message)" -ForegroundColor Red
$errorCount++
}
}
# ============================================================================
# Scenario 6: Missing EKU (no Extended Key Usage)
# ============================================================================
if ($scenarios.MissingEKU) {
Write-Host "`n[6/6] Creating certificate with missing EKU..." -ForegroundColor Yellow
try {
# Omitting -TextExtension to create cert without EKU extension
$cert = New-SelfSignedCertificate `
-Subject "CN=Nodinite-Test-MissingEKU, O=Nodinite Testing, OU=Review Required" `
-FriendlyName "Nodinite Test - Missing EKU (Warning)" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-Signer $rootCA `
-KeyLength 2048 `
-HashAlgorithm SHA256 `
-KeyExportPolicy Exportable `
-NotBefore (Get-Date).AddMinutes(-5) `
-NotAfter (Get-Date).AddDays(90)
$certificates += @{ Name = "Missing EKU"; Thumbprint = $cert.Thumbprint; Store = "LocalMachine\My"; Expected = "Warning" }
Write-Host " ⚠️ Created: $($cert.Thumbprint)" -ForegroundColor Yellow
Write-Host " Note: No EKU extension. PowerShell adds default Key Usage." -ForegroundColor Gray
} catch {
Write-Host " ✗ Failed: $($_.Exception.Message)" -ForegroundColor Red
$errorCount++
}
}
# ============================================================================
# Summary Report
# ============================================================================
Write-Host "`n=== Test Certificate Summary ===" -ForegroundColor Magenta
Write-Host "Created: $($certificates.Count) certificates" -ForegroundColor Cyan
Write-Host "Failed: $errorCount scenarios" -ForegroundColor $(if ($errorCount -gt 0) { "Red" } else { "Green" })
if ($certificates.Count -gt 0) {
Write-Host "`nCertificate Details:" -ForegroundColor Cyan
foreach ($cert in $certificates) {
$color = switch ($cert.Expected) {
"OK" { "Green" }
"Warning" { "Yellow" }
"Critical" { "Red" }
default { "White" }
}
Write-Host " $($cert.Name.PadRight(30)) | $($cert.Thumbprint) | Expected: $($cert.Expected)" -ForegroundColor $color
}
}
Write-Host "`nNext Steps:" -ForegroundColor Cyan
Write-Host " 1. Verify chain validation passes (Root CA installed to Trusted Root store)" -ForegroundColor White
Write-Host " 2. Wait for Nodinite agent discovery (or force sync)" -ForegroundColor White
Write-Host " 3. Verify each certificate shows the expected validation state" -ForegroundColor White
Write-Host " 4. Validate alert notifications for Warning/Critical certificates" -ForegroundColor White
Write-Host " 5. Run cleanup script when testing complete" -ForegroundColor White
Next Steps
- Validate monitoring results against the Testing Scenarios Overview
- Run the Cleanup and Diagnostic Script when finished