Files
powershell-scripts/winrm-https/Generate-WildcardCert-Alternative.ps1
cproudlock 62c0c7bb06 Initial commit: Organized PowerShell scripts for ShopDB asset collection
Structure:
- asset-collection/: Local PC data collection scripts
- remote-execution/: WinRM remote execution scripts
- setup-utilities/: Configuration and testing utilities
- registry-backup/: GE registry backup scripts
- winrm-https/: WinRM HTTPS certificate setup
- docs/: Complete documentation

Each folder includes a README with detailed documentation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 10:57:54 -05:00

373 lines
13 KiB
PowerShell

#Requires -RunAsAdministrator
<#
.SYNOPSIS
Alternative wildcard certificate generator that bypasses smart card issues.
.DESCRIPTION
Creates a self-signed wildcard certificate for *.logon.ds.ge.com using
alternative methods that work around smart card reader or read-only device errors.
This script uses certreq.exe and OpenSSL-style certificate creation to avoid
the smart card device error that can occur with New-SelfSignedCertificate.
.PARAMETER Domain
The domain for the wildcard certificate (default: logon.ds.ge.com).
.PARAMETER ExportPath
Path where the PFX file will be exported (default: current directory).
.PARAMETER Password
Password for the PFX file. If not provided, will prompt securely.
.PARAMETER ValidityYears
Certificate validity in years (default: 2).
.PARAMETER Method
Certificate generation method: 'CertReq' or 'Fallback' (default: CertReq).
.EXAMPLE
.\Generate-WildcardCert-Alternative.ps1
.EXAMPLE
$pass = ConvertTo-SecureString "MyPassword123!" -AsPlainText -Force
.\Generate-WildcardCert-Alternative.ps1 -Password $pass -Method CertReq
.NOTES
Author: System Administrator
Date: 2025-10-17
Version: 1.0
This script uses certreq.exe which bypasses smart card device issues.
#>
param(
[Parameter(Mandatory=$false)]
[string]$Domain = "logon.ds.ge.com",
[Parameter(Mandatory=$false)]
[string]$ExportPath = ".",
[Parameter(Mandatory=$false)]
[SecureString]$Password,
[Parameter(Mandatory=$false)]
[int]$ValidityYears = 2,
[Parameter(Mandatory=$false)]
[ValidateSet('CertReq', 'Fallback')]
[string]$Method = 'CertReq'
)
function Write-ColorOutput {
param([string]$Message, [string]$Color = "White")
Write-Host $Message -ForegroundColor $Color
}
function New-CertificateWithCertReq {
param(
[string]$Domain,
[int]$ValidityYears,
[SecureString]$Password
)
Write-ColorOutput "`n=== Generating Certificate Using CertReq ===" "Cyan"
Write-ColorOutput "This method bypasses smart card device errors" "Gray"
try {
# Create temp directory for certificate files
$tempPath = Join-Path $env:TEMP "WinRM-Cert-$(Get-Date -Format 'yyyyMMddHHmmss')"
New-Item -ItemType Directory -Path $tempPath -Force | Out-Null
Write-ColorOutput "Temp directory: $tempPath" "Gray"
# Create certificate request configuration file
$infFile = Join-Path $tempPath "cert-request.inf"
$infContent = @"
[Version]
Signature="`$Windows NT`$"
[NewRequest]
Subject="CN=*.$Domain"
KeyLength=2048
KeyAlgorithm=RSA
HashAlgorithm=SHA256
MachineKeySet=TRUE
Exportable=TRUE
RequestType=Cert
KeyUsage=0xA0
KeyUsageProperty=0x02
[Extensions]
2.5.29.17 = "{text}"
_continue_ = "dns=*.$Domain&"
_continue_ = "dns=$Domain&"
2.5.29.37 = "{text}"
_continue_ = "1.3.6.1.5.5.7.3.1,"
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.1
"@
Write-ColorOutput "`nCreating certificate request file..." "Yellow"
$infContent | Out-File -FilePath $infFile -Encoding ASCII -Force
# Certificate output files
$cerFile = Join-Path $tempPath "wildcard.cer"
# Create the certificate using certreq
Write-ColorOutput "Generating self-signed certificate..." "Yellow"
$certReqResult = certreq.exe -new -f $infFile $cerFile 2>&1
if ($LASTEXITCODE -ne 0) {
throw "certreq.exe failed: $certReqResult"
}
Write-ColorOutput "[OK] Certificate created successfully" "Green"
# Import the certificate to get the certificate object
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($cerFile)
# Find the certificate in the store by thumbprint
$installedCert = Get-ChildItem Cert:\LocalMachine\My |
Where-Object { $_.Thumbprint -eq $cert.Thumbprint }
if (-not $installedCert) {
throw "Certificate was not installed to the certificate store"
}
Write-ColorOutput "`nCertificate Details:" "Cyan"
Write-ColorOutput " Subject: $($installedCert.Subject)" "White"
Write-ColorOutput " Thumbprint: $($installedCert.Thumbprint)" "White"
Write-ColorOutput " Valid From: $($installedCert.NotBefore)" "White"
Write-ColorOutput " Valid To: $($installedCert.NotAfter)" "White"
Write-ColorOutput " Has Private Key: $($installedCert.HasPrivateKey)" "White"
# Clean up temp files but keep the certificate
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
return $installedCert
}
catch {
# Clean up on error
if (Test-Path $tempPath) {
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
}
throw "Failed to create certificate with CertReq: $($_.Exception.Message)"
}
}
function New-CertificateWithFallback {
param(
[string]$Domain,
[int]$ValidityYears
)
Write-ColorOutput "`n=== Using Fallback Method ===" "Cyan"
Write-ColorOutput "Attempting to create certificate with minimal settings..." "Gray"
try {
$notAfter = (Get-Date).AddYears($ValidityYears)
# Try with minimal parameters and explicitly set KeyProtection to None
$certParams = @{
DnsName = @("*.$Domain", $Domain)
CertStoreLocation = "Cert:\LocalMachine\My"
NotAfter = $notAfter
Subject = "CN=*.$Domain"
FriendlyName = "Wildcard Certificate for *.$Domain (Self-Signed)"
KeyUsage = "DigitalSignature", "KeyEncipherment"
TextExtension = @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")
Type = "Custom"
KeyExportPolicy = "Exportable"
KeySpec = "KeyExchange"
Provider = "Microsoft Enhanced RSA and AES Cryptographic Provider"
}
Write-ColorOutput "Creating certificate with fallback method..." "Yellow"
$cert = New-SelfSignedCertificate @certParams
Write-ColorOutput "[OK] Certificate created successfully" "Green"
Write-ColorOutput "`nCertificate Details:" "Cyan"
Write-ColorOutput " Subject: $($cert.Subject)" "White"
Write-ColorOutput " Thumbprint: $($cert.Thumbprint)" "White"
Write-ColorOutput " Valid From: $($cert.NotBefore)" "White"
Write-ColorOutput " Valid To: $($cert.NotAfter)" "White"
Write-ColorOutput " Has Private Key: $($cert.HasPrivateKey)" "White"
return $cert
}
catch {
throw "Failed to create certificate with fallback method: $($_.Exception.Message)"
}
}
function Export-CertificateToPFX {
param(
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate,
[string]$ExportPath,
[string]$Domain,
[SecureString]$Password
)
Write-ColorOutput "`n=== Exporting Certificate to PFX ===" "Cyan"
try {
# Ensure export directory exists
if (-not (Test-Path $ExportPath)) {
New-Item -ItemType Directory -Path $ExportPath -Force | Out-Null
}
# Construct filename
$filename = "wildcard-$($Domain.Replace('.', '-'))-$(Get-Date -Format 'yyyyMMdd').pfx"
$fullPath = Join-Path $ExportPath $filename
Write-ColorOutput "Export path: $fullPath" "Gray"
# Export certificate with private key
Export-PfxCertificate -Cert $Certificate -FilePath $fullPath -Password $Password | Out-Null
Write-ColorOutput "[OK] Certificate exported successfully" "Green"
# Get file size
$fileSize = (Get-Item $fullPath).Length
Write-ColorOutput " File size: $([math]::Round($fileSize / 1KB, 2)) KB" "White"
return $fullPath
}
catch {
throw "Failed to export certificate: $($_.Exception.Message)"
}
}
function Install-CertificateToTrustedRoot {
param(
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate
)
Write-ColorOutput "`n=== Installing to Trusted Root ===" "Cyan"
Write-ColorOutput "This allows the self-signed cert to be trusted on this machine" "Gray"
try {
$rootStore = New-Object System.Security.Cryptography.X509Certificates.X509Store(
"Root", "LocalMachine"
)
$rootStore.Open("ReadWrite")
# Check if already exists
$existing = $rootStore.Certificates | Where-Object { $_.Thumbprint -eq $Certificate.Thumbprint }
if ($existing) {
Write-ColorOutput "[OK] Certificate already in Trusted Root" "Yellow"
}
else {
$rootStore.Add($Certificate)
Write-ColorOutput "[OK] Certificate added to Trusted Root Certification Authorities" "Green"
}
$rootStore.Close()
}
catch {
Write-ColorOutput "[WARN] Could not add to Trusted Root: $($_.Exception.Message)" "Yellow"
Write-ColorOutput "You may need to manually trust this certificate on client machines" "Yellow"
}
}
function Show-NextSteps {
param([string]$PfxPath, [string]$Domain)
Write-ColorOutput "`n=== Next Steps ===" "Cyan"
Write-ColorOutput ""
Write-ColorOutput "1. The wildcard certificate has been generated and exported to:" "Yellow"
Write-ColorOutput " $PfxPath" "White"
Write-ColorOutput ""
Write-ColorOutput "2. To set up WinRM HTTPS on a computer, copy the PFX file and run:" "Yellow"
Write-ColorOutput " .\Setup-WinRM-HTTPS.ps1 -CertificatePath '$PfxPath' -Domain '$Domain'" "White"
Write-ColorOutput " (Will prompt for password)" "Gray"
Write-ColorOutput ""
Write-ColorOutput "3. For client machines to trust this certificate:" "Yellow"
Write-ColorOutput " Import to Trusted Root on each client or use -SkipCertificateCheck" "White"
Write-ColorOutput ""
Write-ColorOutput "4. Test the setup:" "Yellow"
Write-ColorOutput " .\Invoke-RemoteAssetCollection-HTTPS.ps1 ``" "White"
Write-ColorOutput " -HostnameList @('hostname') -Domain '$Domain' -TestConnections" "White"
Write-ColorOutput ""
Write-ColorOutput "IMPORTANT: This is a SELF-SIGNED certificate for TESTING only!" "Red"
Write-ColorOutput "For production, obtain a certificate from a trusted CA." "Red"
Write-ColorOutput ""
}
# Main execution
try {
Write-ColorOutput "=== Alternative Wildcard Certificate Generator ===" "Cyan"
Write-ColorOutput "Date: $(Get-Date)" "Gray"
Write-ColorOutput "Method: $Method" "Gray"
Write-ColorOutput ""
# Get password if not provided
if (-not $Password) {
Write-ColorOutput "Enter password for PFX file:" "Yellow"
$Password = Read-Host "Password" -AsSecureString
$Password2 = Read-Host "Confirm password" -AsSecureString
# Compare passwords
$pwd1 = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
)
$pwd2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password2)
)
if ($pwd1 -ne $pwd2) {
throw "Passwords do not match"
}
}
# Generate certificate using selected method
$cert = $null
if ($Method -eq 'CertReq') {
try {
$cert = New-CertificateWithCertReq -Domain $Domain -ValidityYears $ValidityYears -Password $Password
}
catch {
Write-ColorOutput "[WARN] CertReq method failed: $($_.Exception.Message)" "Yellow"
Write-ColorOutput "Trying fallback method..." "Yellow"
$cert = New-CertificateWithFallback -Domain $Domain -ValidityYears $ValidityYears
}
}
else {
$cert = New-CertificateWithFallback -Domain $Domain -ValidityYears $ValidityYears
}
if (-not $cert) {
throw "Failed to create certificate with any method"
}
# Export to PFX
$pfxPath = Export-CertificateToPFX -Certificate $cert -ExportPath $ExportPath -Domain $Domain -Password $Password
# Install to trusted root (optional)
$installToRoot = Read-Host "`nInstall to Trusted Root Certification Authorities on this machine? (Y/N)"
if ($installToRoot -eq 'Y' -or $installToRoot -eq 'y') {
Install-CertificateToTrustedRoot -Certificate $cert
}
# Show next steps
Show-NextSteps -PfxPath $pfxPath -Domain $Domain
Write-ColorOutput "`n[SUCCESS] Wildcard certificate generation completed!" "Green"
Write-ColorOutput "Certificate Thumbprint: $($cert.Thumbprint)" "Cyan"
Write-ColorOutput "PFX File: $pfxPath" "Cyan"
} catch {
Write-ColorOutput "`n[ERROR] Certificate generation failed: $($_.Exception.Message)" "Red"
Write-ColorOutput "`nTroubleshooting:" "Yellow"
Write-ColorOutput "1. Ensure you're running as Administrator" "White"
Write-ColorOutput "2. Check if Group Policy restricts certificate creation" "White"
Write-ColorOutput "3. Try running: certlm.msc to verify certificate store access" "White"
Write-ColorOutput "4. Disable smart card readers temporarily if present" "White"
Write-ColorOutput "5. Try the other method: -Method Fallback or -Method CertReq" "White"
exit 1
}