PowerShell批量安装WildCard证书显示成功但实际未生效求助
批量安装WildCard证书脚本执行显示成功但实际未生效的排查与解决
本人是PowerShell新手,参考相关资料编写了批量在多台服务器安装WildCard证书的脚本。脚本执行输出显示操作成功,但实际检查服务器时发现新证书并未安装,仅存在即将过期的旧证书,过程无任何报错,无法定位问题,恳请提供排查思路或帮助。
脚本代码
$username = 'myusername' $password = 'mypassword' Write-Output "Starting Cert-Install as on $env:username. But $username will be used under the hood.." Start-Sleep -Seconds 5 $securePassword = ConvertTo-SecureString $password -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential $username, $securePassword $sourceCertFile="wildcard_my_org.pfx" $certPlaintextPassword='certpwd' # Function to copy cert to remote servers and install them function importCert { param( #[string[]]$computerNames=$env:computername, [string]$sourceCertFile, [string]$certPlaintextPassword ) $certFileName=Split-Path $sourceCertFile -leaf $certFolder=Split-Path $sourceCertFile $targetLocalCertPath='C:\CertsPS\'+$certFileName $results=@() if([System.IO.File]::Exists('serverlist.txt')) { try{ foreach($computerName in [System.IO.File]::ReadLines("serverlist.txt")){ #foreach ($computerName in $computerNames){ $destinationDirectory="\\$computerName`\c`$\CertsPS" $destinationFile="$destinationDirectory\$certFileName" $copySuccess=if(!(test-path $destinationFile)){ #$command="robocopy $certFolder $destinationDirectory $certFileName" write-host "Copying certs to $destinationFile" if(!(test-path $(split-path $destinationFile -Parent))){ $null=new-item $(split-path $destinationFile -Parent) -ItemType Directory } Copy-Item $sourceCertFile -Destination $destinationFile -Force -EA Stop }else{$true} $psSession=new-pssession $computername -SessionOption $(New-PSSessionOption -OpenTimeOut 10000) -Credential $credential if($copySuccess -and $psSession){ $result=Invoke-Command -session $psSession -ScriptBlock { param($targetLocalCertPath,$certPlaintextPassword) Write-Output "Importing cert on $env:computername. Currently logged in as $env:username" try{ $certEncryptedPassword=ConvertTo-SecureString $certPlaintextPassword -AsPlainText -Force $newCert = Import-PfxCertificate -CertStoreLocation Cert:\LocalMachine\My -FilePath $targetLocalCertPath -Password $certEncryptedPassword Import-Module Webadministration $sites = Get-ChildItem -Path IIS:\Sites foreach ($site in $sites) { foreach ($binding in $site.Bindings.Collection) { if ($binding.protocol -eq 'https') { $search = "Cert:\LocalMachine\My\$($binding.certificateHash)" $certs = Get-ChildItem -path $search -Recurse $hostname = hostname if (($certs.count -gt 0) -and ($certs[0].Subject.StartsWith("CN=*.mycomp.org"))) { echo "Updating $hostname, site: `"$($site.name)`", binding: `"$($binding.bindingInformation)`", current cert: `"$($certs[0].Subject)`", Expiry Date: `"$($certs[0].NotAfter)`"" $binding.AddSslCertificate($newCert.Thumbprint, "my") } } } } return $true }catch{ write-warning $_ return $false } } -ArgumentList $targetLocalCertPath,$certPlaintextPassword -EA Stop $results+=$result remove-pssession $psSession } } }catch{ write-warning $_ continue } } else { Write-Output "File serverlist.txt does not exist ! " Write-Output "Make sure serverlist.txt exists at the same dir level as this script ! " } return $results } importCert $sourceCertFile $certPlaintextPassword
执行输出
Starting Cert-Install as on adminuser1. But adminuser1 will be used under the hood.. Importing cert on server01. Currently logged in as adminuser1 Updating server01, site: "Default Web Site", binding: "*:443:", current cert: "CN=*.mycomp.org, O=ORG, S=New York, C=US", Expiry Date: "04/22/2024 19:59:59" True Importing cert on server10. Currently logged in as adminuser1 Updating server10, site: "Default Web Site", binding: "*:443:", current cert: "CN=*.mycomp.org, O=ORG, S=New York, C=US", Expiry Date: "04/22/2024 19:59:59" True Importing cert on server02. Currently logged in as adminuser1 Updating server02, site: "Default Web Site", binding: "*:443:", current cert: "CN=*.mycomp.org, O=ORG, S=New York, C=US", Expiry Date: "04/22/2024 19:59:59" True
排查思路与解决建议
1. 验证证书是否真的被导入
在远程服务器上执行以下命令,检查新证书是否存在于LocalMachine\My存储中:
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -eq "CN=*.mycomp.org" } | Select-Object Thumbprint, NotAfter
- 如果新证书未出现,说明
Import-PfxCertificate执行失败但未抛出异常,可能原因:- PFX文件损坏或密码错误:在远程服务器手动尝试导入PFX文件,确认是否能成功。
- 权限问题:执行脚本的账户需要本地管理员权限才能写入
LocalMachine证书存储,检查$credential对应的账户是否具备该权限。 - 文件路径问题:确认
$targetLocalCertPath指向的文件确实存在,可在Invoke-Command中添加Test-Path $targetLocalCertPath的输出验证。
2. 检查IIS绑定更新是否生效
AddSslCertificate方法调用后,需要确认绑定是否真的更新:
- 在
$binding.AddSslCertificate(...)之后添加以下代码,输出更新后的证书指纹,验证是否为新证书的指纹:# 重新获取绑定信息,确认更新 $binding.Refresh() Write-Output "Updated certificate thumbprint: $($binding.certificateHash)" - IIS绑定修改后需要重启站点或应用池才能生效,可在脚本末尾添加:
Restart-WebSite -Name $site.name # 或重启应用池 # Restart-WebAppPool -Name $site.ApplicationPoolName
3. 脚本逻辑缺陷修复
- 证书覆盖判断问题:当前脚本仅当目标路径不存在PFX文件时才复制,但如果旧PFX文件存在且不是新证书,会导致导入旧证书。修改
copySuccess逻辑,强制复制新证书:$copySuccess = $true write-host "Copying certs to $destinationFile" if(!(test-path $(split-path $destinationFile -Parent))){ $null=new-item $(split-path $destinationFile -Parent) -ItemType Directory } Copy-Item $sourceCertFile -Destination $destinationFile -Force -EA Stop - 导入后的证书验证:在
Import-PfxCertificate后添加验证,确保$newCert不为空:if (-not $newCert) { Write-Warning "Failed to import certificate from $targetLocalCertPath" return $false } Write-Output "New certificate thumbprint: $($newCert.Thumbprint), Expiry: $($newCert.NotAfter)" - IIS模块加载时机:将
Import-Module Webadministration移到脚本块开头,确保模块加载完成后再操作IIS对象。
4. 增强脚本日志
在关键步骤添加详细日志,便于定位问题:
- 在复制文件后输出文件哈希,确认与源文件一致:
$sourceHash = (Get-FileHash $sourceCertFile).Hash $destHash = (Get-FileHash $destinationFile).Hash Write-Host "Source file hash: $sourceHash, Destination file hash: $destHash" if ($sourceHash -ne $destHash) { Write-Warning "File copy corrupted!" $copySuccess = $false } - 在
Invoke-Command的catch块中输出更详细的错误信息:catch{ Write-Warning "Error on $env:computername : $_" Write-Warning "Error details: $($_.Exception.Message)" return $false }
内容的提问来源于stack exchange,提问作者Ajay Kumar
相关产品推荐
相关产品推荐

