#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 }