Files
powershell-scripts/winrm-https/deployment-package/Setup-WinRM-HTTPS.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

504 lines
16 KiB
PowerShell

#Requires -RunAsAdministrator
<#
.SYNOPSIS
Sets up WinRM HTTPS configuration using a wildcard certificate.
.DESCRIPTION
This script configures WinRM for HTTPS connections using a wildcard certificate
(e.g., *.logon.ds.ge.com). It handles:
1. Certificate installation from PFX file
2. HTTPS listener creation with proper hostname
3. Firewall rule configuration for port 5986
4. WinRM service configuration
.PARAMETER CertificatePath
Path to the PFX certificate file containing the wildcard certificate.
.PARAMETER CertificatePassword
SecureString password for the PFX certificate file.
.PARAMETER Domain
The domain suffix for FQDNs (e.g., "logon.ds.ge.com").
Will construct FQDN as: hostname.domain
.PARAMETER CertificateThumbprint
Use existing certificate by thumbprint instead of importing from PFX.
.PARAMETER Port
HTTPS port for WinRM (default: 5986).
.PARAMETER SkipFirewall
Skip firewall rule creation.
.PARAMETER TestConnection
Test HTTPS connection after setup.
.EXAMPLE
# Import certificate and setup WinRM HTTPS
$certPass = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
.\Setup-WinRM-HTTPS.ps1 -CertificatePath "C:\Certs\wildcard.pfx" `
-CertificatePassword $certPass -Domain "logon.ds.ge.com"
.EXAMPLE
# Use existing certificate by thumbprint
.\Setup-WinRM-HTTPS.ps1 -CertificateThumbprint "AB123..." -Domain "logon.ds.ge.com"
.EXAMPLE
# Prompt for certificate password
.\Setup-WinRM-HTTPS.ps1 -CertificatePath "C:\Certs\wildcard.pfx" -Domain "logon.ds.ge.com"
.NOTES
Author: System Administrator
Date: 2025-10-17
Version: 1.0
Prerequisites:
1. Wildcard certificate PFX file with private key
2. Administrator privileges
3. Windows with PowerShell 5.1 or later
After running this script:
- WinRM will listen on HTTPS (port 5986)
- HTTP listener (port 5985) will remain active
- Connections require -UseSSL flag in PowerShell remoting commands
#>
param(
[Parameter(Mandatory=$false)]
[string]$CertificatePath,
[Parameter(Mandatory=$false)]
[SecureString]$CertificatePassword,
[Parameter(Mandatory=$false)]
[string]$CertificateThumbprint,
[Parameter(Mandatory=$true)]
[string]$Domain,
[Parameter(Mandatory=$false)]
[int]$Port = 5986,
[Parameter(Mandatory=$false)]
[switch]$SkipFirewall = $false,
[Parameter(Mandatory=$false)]
[switch]$TestConnection = $false,
[Parameter(Mandatory=$false)]
[string]$LogFile
)
function Write-ColorOutput {
param([string]$Message, [string]$Color = "White")
Write-Host $Message -ForegroundColor $Color
# Also write to log file if specified
if ($script:LogFile) {
try {
Add-Content -Path $script:LogFile -Value $Message -ErrorAction SilentlyContinue
} catch {
# Silently ignore logging errors to avoid breaking the script
}
}
}
function Show-WinRMStatus {
Write-ColorOutput "`n=== Current WinRM Configuration ===" "Cyan"
try {
$winrmStatus = Get-Service WinRM
$statusColor = if($winrmStatus.Status -eq 'Running') {'Green'} else {'Red'}
Write-ColorOutput "WinRM Service Status: $($winrmStatus.Status)" $statusColor
Write-ColorOutput "`nWinRM Listeners:" "Yellow"
winrm enumerate winrm/config/listener
} catch {
Write-ColorOutput "Error checking WinRM status: $($_.Exception.Message)" "Red"
}
}
function Import-WildcardCertificate {
param(
[string]$CertPath,
[SecureString]$CertPassword
)
Write-ColorOutput "`n=== Importing Certificate ===" "Cyan"
if (-not (Test-Path $CertPath)) {
throw "Certificate file not found: $CertPath"
}
try {
# Prompt for password if not provided
if (-not $CertPassword) {
$CertPassword = Read-Host "Enter certificate password" -AsSecureString
}
# Import certificate to Local Computer Personal store
Write-ColorOutput "Importing certificate from: $CertPath" "Yellow"
$cert = Import-PfxCertificate -FilePath $CertPath `
-CertStoreLocation Cert:\LocalMachine\My `
-Password $CertPassword `
-Exportable
Write-ColorOutput "[OK] Certificate imported successfully" "Green"
Write-ColorOutput " Subject: $($cert.Subject)" "Gray"
Write-ColorOutput " Thumbprint: $($cert.Thumbprint)" "Gray"
Write-ColorOutput " Expiration: $($cert.NotAfter)" "Gray"
return $cert
}
catch {
throw "Failed to import certificate: $($_.Exception.Message)"
}
}
function Get-ExistingCertificate {
param([string]$Thumbprint)
Write-ColorOutput "`n=== Locating Existing Certificate ===" "Cyan"
try {
$cert = Get-ChildItem -Path Cert:\LocalMachine\My |
Where-Object { $_.Thumbprint -eq $Thumbprint }
if (-not $cert) {
throw "Certificate with thumbprint $Thumbprint not found in Local Machine store"
}
Write-ColorOutput "[OK] Certificate found" "Green"
Write-ColorOutput " Subject: $($cert.Subject)" "Gray"
Write-ColorOutput " Thumbprint: $($cert.Thumbprint)" "Gray"
Write-ColorOutput " Expiration: $($cert.NotAfter)" "Gray"
# Check if certificate has private key
if (-not $cert.HasPrivateKey) {
throw "Certificate does not have a private key. WinRM HTTPS requires a certificate with private key."
}
return $cert
}
catch {
throw "Failed to locate certificate: $($_.Exception.Message)"
}
}
function Find-WildcardCertificate {
param([string]$Domain)
Write-ColorOutput "`n=== Searching for Wildcard Certificate ===" "Cyan"
Write-ColorOutput "Looking for certificate matching: *.$Domain" "Yellow"
try {
$certs = Get-ChildItem -Path Cert:\LocalMachine\My |
Where-Object {
$_.Subject -like "*$Domain*" -and
$_.HasPrivateKey -and
$_.NotAfter -gt (Get-Date)
}
if ($certs.Count -eq 0) {
throw "No valid wildcard certificate found for *.$Domain in Local Machine store"
}
if ($certs.Count -gt 1) {
Write-ColorOutput "Multiple certificates found:" "Yellow"
for ($i = 0; $i -lt $certs.Count; $i++) {
Write-ColorOutput " [$i] Subject: $($certs[$i].Subject) | Expires: $($certs[$i].NotAfter)" "White"
}
$selection = Read-Host "Select certificate number (0-$($certs.Count - 1))"
$cert = $certs[$selection]
} else {
$cert = $certs[0]
}
Write-ColorOutput "[OK] Certificate selected" "Green"
Write-ColorOutput " Subject: $($cert.Subject)" "Gray"
Write-ColorOutput " Thumbprint: $($cert.Thumbprint)" "Gray"
Write-ColorOutput " Expiration: $($cert.NotAfter)" "Gray"
return $cert
}
catch {
throw "Failed to find wildcard certificate: $($_.Exception.Message)"
}
}
function Remove-ExistingHTTPSListener {
Write-ColorOutput "`n=== Checking for Existing HTTPS Listeners ===" "Cyan"
try {
$listeners = winrm enumerate winrm/config/listener | Select-String "Transport = HTTPS" -Context 0,10
if ($listeners) {
Write-ColorOutput "Found existing HTTPS listener(s). Removing..." "Yellow"
# Remove all HTTPS listeners
$result = winrm delete winrm/config/Listener?Address=*+Transport=HTTPS 2>&1
if ($LASTEXITCODE -eq 0) {
Write-ColorOutput "[OK] Existing HTTPS listener removed" "Green"
}
} else {
Write-ColorOutput "[OK] No existing HTTPS listener found" "Green"
}
}
catch {
Write-ColorOutput "[WARN] Could not check/remove existing listeners: $($_.Exception.Message)" "Yellow"
}
}
function New-WinRMHTTPSListener {
param(
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate,
[string]$Hostname,
[int]$Port
)
Write-ColorOutput "`n=== Creating WinRM HTTPS Listener ===" "Cyan"
Write-ColorOutput "Computer FQDN: $Hostname" "Gray"
Write-ColorOutput "Port: $Port" "Gray"
try {
# Remove existing HTTPS listener if present
Remove-ExistingHTTPSListener
# Create new HTTPS listener
$thumbprint = $Certificate.Thumbprint
# Extract the wildcard CN from the certificate subject
# For wildcard cert like CN=*.logon.ds.ge.com, we need to use the wildcard format
$certSubject = $Certificate.Subject
Write-ColorOutput "Certificate Subject: $certSubject" "Gray"
# Extract the CN value (e.g., "*.logon.ds.ge.com")
if ($certSubject -match 'CN=([^,]+)') {
$certCN = $matches[1]
Write-ColorOutput "Certificate CN: $certCN" "Gray"
} else {
throw "Could not extract CN from certificate subject"
}
# For wildcard certificates, WinRM listener hostname must match the certificate CN exactly
# So we use the wildcard CN (*.logon.ds.ge.com) not the specific FQDN
$listenerHostname = $certCN
Write-ColorOutput "Creating HTTPS listener..." "Yellow"
Write-ColorOutput "Certificate Thumbprint: $thumbprint" "Gray"
Write-ColorOutput "Listener Hostname: $listenerHostname" "Gray"
# Use cmd.exe to execute winrm command to avoid PowerShell quoting issues
$winrmArgs = "create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname=`"$listenerHostname`";CertificateThumbprint=`"$thumbprint`";Port=`"$Port`"}"
Write-ColorOutput "Executing: winrm $winrmArgs" "Gray"
$result = cmd.exe /c "winrm $winrmArgs" 2>&1
if ($LASTEXITCODE -ne 0) {
Write-ColorOutput "Error output: $result" "Red"
throw "Failed to create HTTPS listener. Error code: $LASTEXITCODE"
}
Write-ColorOutput "[OK] HTTPS listener created successfully" "Green"
Write-ColorOutput "Note: Clients will connect using the specific FQDN ($Hostname)" "Gray"
Write-ColorOutput " but the listener uses the wildcard CN ($listenerHostname)" "Gray"
# Verify listener was created
Write-ColorOutput "`nVerifying HTTPS listener:" "Yellow"
winrm enumerate winrm/config/listener | Select-String "Transport = HTTPS" -Context 0,15
return $true
}
catch {
throw "Failed to create HTTPS listener: $($_.Exception.Message)"
}
}
function Enable-WinRMService {
Write-ColorOutput "`n=== Configuring WinRM Service ===" "Cyan"
try {
# Enable PowerShell Remoting
Write-ColorOutput "Enabling PowerShell Remoting..." "Yellow"
Enable-PSRemoting -Force -SkipNetworkProfileCheck
Write-ColorOutput "[OK] PowerShell Remoting enabled" "Green"
# Start WinRM service
Write-ColorOutput "Configuring WinRM service..." "Yellow"
Start-Service WinRM -ErrorAction SilentlyContinue
Set-Service WinRM -StartupType Automatic
Write-ColorOutput "[OK] WinRM service configured" "Green"
# Configure service settings
Set-Item WSMan:\localhost\Service\Auth\Certificate -Value $true
Write-ColorOutput "[OK] Certificate authentication enabled" "Green"
} catch {
throw "Failed to configure WinRM service: $($_.Exception.Message)"
}
}
function New-FirewallRule {
param([int]$Port)
if ($SkipFirewall) {
Write-ColorOutput "`n[SKIP] Firewall configuration skipped" "Yellow"
return
}
Write-ColorOutput "`n=== Configuring Windows Firewall ===" "Cyan"
try {
$ruleName = "WinRM HTTPS-In"
# Check if rule already exists
$existingRule = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue
if ($existingRule) {
Write-ColorOutput "Removing existing firewall rule..." "Yellow"
Remove-NetFirewallRule -DisplayName $ruleName
}
Write-ColorOutput "Creating firewall rule for port $Port..." "Yellow"
New-NetFirewallRule -DisplayName $ruleName `
-Name $ruleName `
-Profile Any `
-LocalPort $Port `
-Protocol TCP `
-Direction Inbound `
-Action Allow `
-Enabled True | Out-Null
Write-ColorOutput "[OK] Firewall rule created" "Green"
} catch {
Write-ColorOutput "[WARN] Could not configure firewall: $($_.Exception.Message)" "Yellow"
}
}
function Test-WinRMHTTPSConnection {
param([string]$Hostname, [int]$Port)
Write-ColorOutput "`n=== Testing HTTPS Connection ===" "Cyan"
try {
Write-ColorOutput "Testing connection to https://${Hostname}:${Port}/wsman..." "Yellow"
$testResult = Test-WSMan -ComputerName $Hostname -Port $Port -UseSSL -ErrorAction Stop
Write-ColorOutput "[OK] HTTPS connection successful!" "Green"
Write-ColorOutput "`nTest-WSMan Output:" "Gray"
$testResult | Format-List
return $true
}
catch {
Write-ColorOutput "[WARN] HTTPS connection test failed: $($_.Exception.Message)" "Yellow"
Write-ColorOutput "This may be normal if testing from the local machine." "Gray"
Write-ColorOutput "Try testing from a remote computer using:" "Gray"
Write-ColorOutput " Test-WSMan -ComputerName $Hostname -Port $Port -UseSSL" "White"
return $false
}
}
function Show-NextSteps {
param([string]$Hostname, [int]$Port)
Write-ColorOutput "`n=== Next Steps ===" "Cyan"
Write-ColorOutput ""
Write-ColorOutput "WinRM HTTPS is now configured on this computer." "Green"
Write-ColorOutput ""
Write-ColorOutput "To connect from a remote computer:" "Yellow"
Write-ColorOutput ""
Write-ColorOutput " # Test connection" "Gray"
Write-ColorOutput " Test-WSMan -ComputerName $Hostname -Port $Port -UseSSL" "White"
Write-ColorOutput ""
Write-ColorOutput " # Create remote session" "Gray"
Write-ColorOutput " `$cred = Get-Credential" "White"
Write-ColorOutput " New-PSSession -ComputerName $Hostname -Credential `$cred -UseSSL -Port $Port" "White"
Write-ColorOutput ""
Write-ColorOutput " # Or use Enter-PSSession" "Gray"
Write-ColorOutput " Enter-PSSession -ComputerName $Hostname -Credential `$cred -UseSSL -Port $Port" "White"
Write-ColorOutput ""
Write-ColorOutput "Notes:" "Yellow"
Write-ColorOutput " - HTTP listener on port 5985 is still active" "Gray"
Write-ColorOutput " - Always use -UseSSL flag for HTTPS connections" "Gray"
Write-ColorOutput " - Certificate must be trusted on the client computer" "Gray"
Write-ColorOutput ""
}
# Main execution
try {
# Make LogFile available to all functions
$script:LogFile = $LogFile
Write-ColorOutput "=== WinRM HTTPS Setup Script ===" "Cyan"
Write-ColorOutput "Date: $(Get-Date)" "Gray"
if ($LogFile) {
Write-ColorOutput "Logging to: $LogFile" "Gray"
}
Write-ColorOutput ""
# Construct FQDN
$hostname = $env:COMPUTERNAME
$fqdn = "$hostname.$Domain".ToLower()
Write-ColorOutput "Computer FQDN: $fqdn" "Gray"
# Show current status
Show-WinRMStatus
# Get or import certificate
$certificate = $null
if ($CertificateThumbprint) {
# Use existing certificate by thumbprint
$certificate = Get-ExistingCertificate -Thumbprint $CertificateThumbprint
}
elseif ($CertificatePath) {
# Import certificate from PFX
$certificate = Import-WildcardCertificate -CertPath $CertificatePath -CertPassword $CertificatePassword
}
else {
# Try to find existing wildcard certificate
$certificate = Find-WildcardCertificate -Domain $Domain
}
if (-not $certificate) {
throw "No certificate available. Provide -CertificatePath or -CertificateThumbprint"
}
# Verify certificate validity
if ($certificate.NotAfter -lt (Get-Date)) {
throw "Certificate has expired: $($certificate.NotAfter)"
}
# Enable WinRM service
Enable-WinRMService
# Create HTTPS listener
New-WinRMHTTPSListener -Certificate $certificate -Hostname $fqdn -Port $Port
# Configure firewall
New-FirewallRule -Port $Port
# Show updated status
Show-WinRMStatus
# Test connection if requested
if ($TestConnection) {
Test-WinRMHTTPSConnection -Hostname $fqdn -Port $Port
}
# Show next steps
Show-NextSteps -Hostname $fqdn -Port $Port
Write-ColorOutput "`n[SUCCESS] WinRM HTTPS setup completed successfully!" "Green"
} catch {
Write-ColorOutput "`n[ERROR] Setup failed: $($_.Exception.Message)" "Red"
exit 1
}