#Requires -RunAsAdministrator param( [Parameter(Mandatory=$false)] [string]$HostnameFile = "shopfloor-hostnames.txt", [Parameter(Mandatory=$false)] [string]$CAPfxPath, [string]$Domain = "logon.ds.ge.com", [string]$OutputPath = ".\pc-certificates", [int]$ValidityYears = 2, [SecureString]$CAPassword, [SecureString]$CertificatePassword ) Write-Host "" Write-Host "=== Bulk PC Certificate Signing ===" -ForegroundColor Cyan Write-Host "" # Check hostname file if (-not (Test-Path $HostnameFile)) { Write-Host "[ERROR] Hostname file not found: $HostnameFile" -ForegroundColor Red Write-Host "Looking for: $HostnameFile" -ForegroundColor Yellow exit 1 } $hostnames = Get-Content $HostnameFile | Where-Object {$_ -match '\S'} | ForEach-Object {$_.Trim()} Write-Host "Found $($hostnames.Count) hostnames to process" Write-Host "" # Auto-detect CA file if not specified if (-not $CAPfxPath) { Write-Host "Looking for CA certificate file..." -ForegroundColor Yellow $caFiles = Get-ChildItem -Filter "*CA*.pfx" | Sort-Object LastWriteTime -Descending if ($caFiles.Count -eq 0) { Write-Host "[ERROR] No CA PFX file found in current directory" -ForegroundColor Red Write-Host "Please specify -CAPfxPath parameter or ensure CA PFX file is in current directory" -ForegroundColor Yellow exit 1 } if ($caFiles.Count -gt 1) { Write-Host "Multiple CA files found:" -ForegroundColor Yellow for ($i = 0; $i -lt $caFiles.Count; $i++) { Write-Host " [$i] $($caFiles[$i].Name) (Modified: $($caFiles[$i].LastWriteTime))" } $selection = Read-Host "Select CA file number (0-$($caFiles.Count - 1))" $CAPfxPath = $caFiles[$selection].FullName } else { $CAPfxPath = $caFiles[0].FullName Write-Host "[OK] Found CA file: $($caFiles[0].Name)" -ForegroundColor Green } Write-Host "" } # Check CA file if (-not (Test-Path $CAPfxPath)) { Write-Host "[ERROR] CA PFX file not found: $CAPfxPath" -ForegroundColor Red exit 1 } # Get passwords if (-not $CAPassword) { $CAPassword = Read-Host "Enter CA certificate password" -AsSecureString } if (-not $CertificatePassword) { $CertificatePassword = Read-Host "Enter password for PC certificates (same for all)" -AsSecureString } # Load CA certificate Write-Host "Loading CA certificate..." try { $caCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CAPfxPath, $CAPassword, 'Exportable') Write-Host "[OK] CA loaded: $($caCert.Subject)" Write-Host " Thumbprint: $($caCert.Thumbprint)" Write-Host "" } catch { Write-Host "[ERROR] Failed to load CA: $($_.Exception.Message)" -ForegroundColor Red exit 1 } if (-not $caCert.HasPrivateKey) { Write-Host "[ERROR] CA certificate does not have private key" -ForegroundColor Red exit 1 } # Create output directory $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $batchPath = Join-Path $OutputPath "batch-$timestamp" New-Item -ItemType Directory -Path $batchPath -Force | Out-Null Write-Host "Output directory: $batchPath" Write-Host "" Write-Host "Processing certificates..." Write-Host "" $results = @() $successCount = 0 $failCount = 0 $counter = 0 foreach ($hostname in $hostnames) { $counter++ $hostname = $hostname.Trim() -replace "\.$Domain$", "" $fqdn = "$hostname.$Domain".ToLower() Write-Host "[$counter/$($hostnames.Count)] $hostname ... " -NoNewline try { $notAfter = (Get-Date).AddYears($ValidityYears) $pcCert = New-SelfSignedCertificate ` -Subject "CN=$fqdn" ` -DnsName @($fqdn, $hostname) ` -KeyExportPolicy Exportable ` -KeyUsage DigitalSignature,KeyEncipherment ` -KeyLength 2048 ` -KeyAlgorithm RSA ` -HashAlgorithm SHA256 ` -CertStoreLocation 'Cert:\LocalMachine\My' ` -NotAfter $notAfter ` -TextExtension '2.5.29.37={text}1.3.6.1.5.5.7.3.1' ` -Signer $caCert # Export PFX $pfxPath = Join-Path $batchPath "$hostname-$Domain-$timestamp.pfx" Export-PfxCertificate -Cert $pcCert -FilePath $pfxPath -Password $CertificatePassword | Out-Null # Export CER $cerPath = Join-Path $batchPath "$hostname-$Domain-$timestamp.cer" Export-Certificate -Cert $pcCert -FilePath $cerPath | Out-Null # Remove from store Remove-Item "Cert:\LocalMachine\My\$($pcCert.Thumbprint)" -Force -ErrorAction SilentlyContinue Write-Host "OK" -ForegroundColor Green $results += [PSCustomObject]@{ Hostname = $hostname FQDN = $fqdn Thumbprint = $pcCert.Thumbprint ValidUntil = $pcCert.NotAfter PFXFile = Split-Path $pfxPath -Leaf Status = "Success" Error = $null } $successCount++ } catch { Write-Host "FAILED: $($_.Exception.Message)" -ForegroundColor Red $results += [PSCustomObject]@{ Hostname = $hostname FQDN = $fqdn Thumbprint = $null ValidUntil = $null PFXFile = $null Status = "Failed" Error = $_.Exception.Message } $failCount++ } } # Export results $csvPath = Join-Path $batchPath "certificate-list.csv" $results | Export-Csv -Path $csvPath -NoTypeInformation $summaryPath = Join-Path $batchPath "SUMMARY.txt" $summaryContent = @" Certificate Signing Summary =========================== Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') Batch: $timestamp Statistics: Total: $($hostnames.Count) Successful: $successCount Failed: $failCount CA Certificate: Subject: $($caCert.Subject) Thumbprint: $($caCert.Thumbprint) Output Directory: $batchPath Files: - $successCount PFX files (certificates with private keys) - $successCount CER files (public certificates) - certificate-list.csv (spreadsheet) Next Steps: 1. Install CA certificate on management computers: Import-Certificate -FilePath 'CA.cer' -CertStoreLocation Cert:\LocalMachine\Root 2. Deploy certificates to PCs (each PC gets its own): - Copy PFX file to PC - Import: Import-PfxCertificate -FilePath 'HOSTNAME.pfx' -CertStoreLocation Cert:\LocalMachine\My -Password `$pass - Configure WinRM: .\Setup-WinRM-HTTPS.ps1 -CertificateThumbprint THUMBPRINT -Domain logon.ds.ge.com 3. Connect from management computer: Enter-PSSession -ComputerName HOSTNAME.logon.ds.ge.com -Credential `$cred -UseSSL -Port 5986 (No -SessionOption needed!) "@ $summaryContent | Out-File -FilePath $summaryPath -Encoding UTF8 Write-Host "" Write-Host "=== CERTIFICATE SIGNING COMPLETE ===" -ForegroundColor Green Write-Host "" Write-Host "Summary:" Write-Host " Total: $($hostnames.Count)" Write-Host " Successful: $successCount" -ForegroundColor Green Write-Host " Failed: $failCount" -ForegroundColor $(if($failCount -gt 0){'Red'}else{'Green'}) Write-Host "" Write-Host "Output: $batchPath" Write-Host "" Write-Host "Files:" Write-Host " - certificate-list.csv (list of all certificates)" Write-Host " - SUMMARY.txt (detailed summary)" Write-Host " - $successCount PFX files (one per PC)" Write-Host ""