You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 17:57:04