Reemplace el certificado SAN SSL en IIS 8.5 rápidamente

Reemplace el certificado SAN SSL en IIS 8.5 rápidamente

He buscado en vano para encontrar una solución a esta consulta específica pero no puedo encontrar una situación idéntica a la mía.

En IIS 8.5, digamos que tengo varios dominios y tengo un certificado SAN SSL (no comodín) vinculado a cada uno mediante SNI:

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

Si quisiera agregar d.domain.comy generar una nueva SAN que incluya el nuevo dominio, quiero poder reemplazar el certificado actual sin tener que volver a vincular el nuevo a los 3 dominios anteriores (luego puedo vincular manualmente el nuevo cuarto dominio). ).

Ahora imagine en mi ejemplo anterior que en realidad tengo 20 dominios; hacer esto lleva bastante tiempo, especialmente si agrega un nuevo sitio cada dos semanas, sin mencionar el tiempo de inactividad mientras vuelvo a vincular el sitio SSL por cada sitio.

¿Existe alguna solución que pueda aplicar para automatizar este proceso? Podría imaginarme un script de PS haciéndolo siempre que tenga el hash del nuevo certificado, pero mi PS-fu no es lo suficientemente fuerte como para descubrir cómo iterar a través de todos los sitios y volver a aplicar el certificado (si así es como debe hacerse). ). Lo ideal sería una solución que importe automáticamente el nuevo certificado (.pfx), elimine el antiguo y vuelva a vincular los sitios.

EDITAR:Para confirmar, estoy usando una dirección IP para todos los sitios.

Respuesta1

Copie y pegue las siguientes funciones en su ventana de 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.")
    }
}

Luego ejecuta:

  1. Para enumerar todos los sitios y sus enlaces:

Get-IisSslBinding

  1. Para actualizar todos los sitios y sus enlaces SSL:

Get-IisSslBinding | Set-IisSslBinding -AfterThumbprint AAAAAAAAAAABBBBBBBBBBCCCCCCCCCCCCCCCCCCC

** Asegúrese de que el nuevo certificado SSL ya esté en el almacén SSL. Además, Get-IisSslBindingfunciona como -FilterBySiteNameparámetro para que pueda apuntar a los sitios exactos que quizás necesite tocar.

información relacionada