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>
373 lines
13 KiB
PowerShell
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
|
|
}
|