快速替换 IIS 8.5 上的 SAN SSL 证书

快速替换 IIS 8.5 上的 SAN SSL 证书

我已经徒劳地寻找这个特定查询的解决方案,但却找不到与我的情况相同的情况。

在 IIS 8.5 中,假设我有多个域,并且我有一个使用 SNI 与每个域绑定的 SAN SSL 证书(不是通配符):

a.domain.com
b.domain.com
c.domain.com

如果我想添加d.domain.com并生成一个包含新域的新 SAN,我希望能够替换当前证书,而不必将新证书重新绑定到上述 3 个域(然后我可以手动绑定新的第 4 个域)。

现在想象一下,在上面的例子中,我实际上有 20 个域名 - 这样做相当耗时,特别是如果您每隔几周添加一个新站点 - 更不用说我在重新绑定 SSL 站点时的停机时间了。

有没有可以应用的解决方案来自动化此过程?如果我有新证书的哈希值,我可以设想一个 PS 脚本来执行此操作,但我的 PS-fu 不够强大,无法弄清楚如何遍历所有站点并重新应用证书(如果需要这样做)。理想情况下,它将是一个自动导入新证书(.pfx)、删除旧证书并重新绑定站点的解决方案。

编辑:为了确认,我对所有网站都使用一个 IP 地址。

答案1

将以下函数复制并粘贴到 PowerShell 窗口中:

function Get-IisSslBinding{
    [CmdletBinding()]
    Param(
        [Parameter(Position=0)] [Alias("fi","sn")]
        [string]$FilterBySiteName,
        [Parameter(Position=1, ValueFromPipelineByPropertyName=$true)] [Alias("co")] [ValidateNotnullOrEmpty()]
        [string[]]$ComputerName=$env:ComputerName
    )
    Begin{
        Write-Verbose ("$(Get-Date) - INFO - Load Microsoft.Web.Administration assembly...")
        $null=[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
    }
    Process{
        Foreach($computer in $ComputerName){
            Try{
                If($computer -eq "$env:ComputerName"){
                    Write-Verbose ("$(Get-Date) - INFO - Open connection to local computer [ {0} ]..." -f $computer)
                    $webServer=New-Object Microsoft.Web.Administration.ServerManager
                    $null=$webServer
                }
                Else{
                    Write-Verbose ("$(Get-Date) - INFO - Open connection to remote computer [ {0} ]..." -f $computer)
                    $webServer=[Microsoft.Web.Administration.ServerManager]::OpenRemote($computer)
                }
                # filter sites
                $sites=($webServer.Sites | Where{$_.Name -match $FilterBySiteName})
                Foreach($site in $sites){
                    Write-Verbose ("$(Get-Date) - INFO - Get binding(s) for [ {0} ]..." -f $site.Name)
                    # filter bindings
                    $siteHttpsBindings=($site.Bindings | Where{$_.Protocol -eq "https"})
                    Foreach($siteHttpsBinding in $siteHttpsBindings){
                        Write-Verbose ("$(Get-Date) - INFO - Get binding information ...")
                        New-Object -Type PSObject -Property @{
                            'ComputerName'=$computer.ToUpper()
                            'SiteId'=$site.ID 
                            'SiteName'=$site.Name
                            'BindingInformation'=$siteHttpsBinding.GetAttributeValue("bindinginformation")
                            'Thumbprint'=$siteHttpsBinding.GetAttributeValue("certificateHash")
                            'CertificateStore'=$siteHttpsBinding.GetAttributeValue("certificateStoreName")
                            'Protocol'=$siteHttpsBinding.GetAttributeValue("protocol")
                        }
                    }
                }
            }
            Catch{
                Write-Verbose ("$(Get-Date) - ERROR - {0}" -f $_.Exception.GetBaseException().Message)
            }
            Finally{
                Write-Verbose ("$(Get-Date) - INFO - Dispose web server resources...")
                $webServer.Dispose()
            }
        }
    }
    End{
        Write-Verbose ("$(Get-Date) - INFO - Done")
    }
}
##
function Set-IisSslBinding{
    [CmdletBinding()]
    Param(
        [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [Alias("oh")] [ValidateNotnullOrEmpty()]
        [string]$Thumbprint,
        [Parameter(Position=1, Mandatory=$true)] [Alias("nh")] [ValidateNotnullOrEmpty()]
        [string]$AfterThumbprint,
        [Parameter(Position=2, Mandatory=$false, ValueFromPipelineByPropertyName=$true)] [Alias("sn")] [ValidateNotnullOrEmpty()]
        $SiteName,
        [Parameter(Position=3, Mandatory=$false, ValueFromPipelineByPropertyName=$true)] [Alias("co")] [ValidateNotnullOrEmpty()]
        [string[]]$ComputerName=$env:ComputerName
    )
    Begin{
        Write-Verbose ("$(Get-Date) - INFO - Load Microsoft.Web.Administration assembly...")
        $null=[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
    }
    Process{
        Foreach($computer in $ComputerName){
            Try{
                If($computer -eq "$env:ComputerName"){
                    Write-Verbose ("$(Get-Date) - INFO - Open connection to local computer [ {0} ]..." -f $computer)
                    $webServer=New-Object Microsoft.Web.Administration.ServerManager
                    $IsCertificateInStore=((Get-ChildItem -Path CERT:\LocalMachine\My) -match $AfterThumbprint)
                }
                Else{
                    Write-Verbose ("$(Get-Date) - INFO - Open connection to remote computer [ {0} ]..." -f $computer)
                    $webServer=[Microsoft.Web.Administration.ServerManager]::OpenRemote($computer)
                }
                # If(-not $IsCertificateInStore){
                    # Write-Verbose ("$(Get-Date) - INFO - The computer [ {0} ] does not contain the certificate [ {1} ]... " -f $computer,$AfterThumbprint)
                    # Break
                # }
                Write-Verbose ("$(Get-Date) - INFO - Filter sites...")
                $sites=($webServer.Sites|where{$_.Name -match $SiteName})
                Foreach($site in $sites){
                    #filter bindings
                    $siteHttpsBindings=($site.Bindings|where{$_.Protocol -eq "https"})
                    Foreach($siteHttpsBinding in $siteHttpsBindings){
                        Switch($siteHttpsBinding.GetAttributeValue("certificateHash")){
                            $Thumbprint{
                                Write-Verbose ("$(Get-Date) - INFO - Remove old certificate [ {0} ]... " -f $siteHttpsBinding.GetAttributeValue("certificateHash"))
                                $BindingMethod=$siteHttpsBinding.Methods["RemoveSslCertificate"]
                                $BindingMethodInstance=$BindingMethod.CreateInstance()
                                $BindingMethodInstance.Execute()
                                Write-Verbose ("$(Get-Date) - INFO - Add new certificate [ {0} ]..." -f $AfterThumbprint)
                                $BindingMethod=$siteHttpsBinding.Methods["AddSslCertificate"]
                                $BindingMethodInstance=$BindingMethod.CreateInstance()
                                $BindingMethodInstance.Input.SetAttributeValue("certificateHash", $AfterThumbprint)
                                $BindingMethodInstance.Input.SetAttributeValue("certificateStoreName", "My")
                                $BindingMethodInstance.Execute()
                                New-Object -Type PSObject -Property @{
                                    'ComputerName'=$computer.ToUpper()
                                    'SiteId'=$site.ID 
                                    'SiteName'=$site.Name
                                    'BindingInformation'=$siteHttpsBinding.GetAttributeValue("bindingInformation")
                                    'Thumbprint'=$siteHttpsBinding.GetAttributeValue("certificateHash")
                                    'PreviousThumbprint'=$Thumbprint
                                }
                            }
                            Default{
                                Write-Verbose ("$(Get-Date) - INFO - Could not get https binding(s) attribute for [ {0} ]" -f $site.Name)
                                break
                            }
                        }                
                    }
                }
            }
            Catch{
                Write-Verbose ("$(Get-Date) - ERROR - {0}" -f $_.Exception.GetBaseException().Message)
            }
            Finally{
                Write-Verbose ("$(Get-Date) - INFO - Dispose web server resources...")
                $webServer.Dispose()
            }
        }
    }
    End{
        Write-Verbose ("$(Get-Date) - INFO - Done.")
    }
}

然后执行:

  1. 列出所有站点及其绑定:

Get-IisSslBinding

  1. 要更新所有站点及其 SSL 绑定:

Get-IisSslBinding | Set-IisSslBinding -AfterThumbprint AAAAAAAAAAABBBBBBBBBBCCCCCCCCCCCCCCCCCCC

** 确保新的 SSL 证书已在 SSL 存储中。此外,该Get-IisSslBinding函数还用作-FilterBySiteName参数,以便您可以定位可能需要接触的确切网站。

相关内容