简体   繁体   English

使用PowerShell将IIS SSL证书分配给与主机标头绑定

[英]Assign IIS SSL Certificate to Binding with Host Header using PowerShell

I'm trying to assign a certificate to a HTTPS binding. 我正在尝试将证书分配给HTTPS绑定。 Unfortunately, I get this error from PowerShell: 不幸的是,我从PowerShell收到此错误:

new-item : Cannot create a file when that file already exists
At line:3 char:56
+         get-item -Path "cert:\localmachine\my\$cert" | new-item -path IIS:\SslBi ...
+                                                        ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [New-Item], Win32Exception
    + FullyQualifiedErrorId : System.ComponentModel.Win32Exception,Microsoft.PowerShell.Commands.NewItemCommand

My PowerShell which I execute is: 我执行的PowerShell是:

 New-WebBinding -name $Name -Protocol https -HostHeader "$Name.domain.com" -Port 443 -SslFlags 1
 $cert = Get-ChildItem -Path Cert:\LocalMachine\My | where-Object {$_.subject -like "*cloud.domain.com*"} | Select-Object -ExpandProperty Thumbprint
 get-item -Path "cert:\localmachine\my\$cert" | new-item -path IIS:\SslBindings\0.0.0.0!443!$Name.domain.com

It seems to be able to find the certificate, but is not able to assign it to the created binding. 它似乎能够找到证书,但无法将其分配给创建的绑定。 The binding gets created with the right IP/Port/HostHeader, SNI is checked, but SSL Certificate is "Not selected" 使用正确的IP / Port / HostHeader创建绑定,检查SNI,但SSL证书是“未选中”

It all works fine from IIS Manager 从IIS管理器一切正常

I have tried various instructions from SO and other sites, eg: 我尝试过来自SO和其他网站的各种指示,例如:
http://technet.microsoft.com/en-us/magazine/jj871065.aspx http://technet.microsoft.com/en-us/magazine/jj871065.aspx
Powershell IIS7 Snap in Assign SSL certificate to https binding Powershell IIS7 Snap in将SSL证书分配给https绑定
Powershell - Add SSL binding using shared certificate Powershell - 使用共享证书添加SSL绑定

Also, I have tried with 另外,我试过了

IIS:\SslBindings\0.0.0.0!443!$Name.domain.com

and

IIS:\SslBindings\0.0.0.0!443

The Certificate has a subject of cloud.domain.com , and multiple SAN attributes, eg for **.domain.com*, domain.com , **.seconddomain.com*, seconddomain.com , cloud.domain.com 证书有一个cloud.domain.com主题和多个SAN属性,例如**。domain.com *, domain.com ,**。seconddomain.com *, seconddomain.comcloud.domain.com

Edit: 编辑:

Right now I'm using this approach, which does work: 现在我正在使用这种方法,它确实有效:

$guid = [guid]::NewGuid().ToString("B")
netsh http add sslcert hostnameport=$Name.domain.com:443 certhash=b58e54ca68c94f93c134c5da00a388ab0642a648 certstorename=MY appid="$guid"

I'm still interested however in a solution without netsh / appcmd 我仍然对没有netsh / appcmd的解决方案感兴趣

Here is how I was able to generate a self-signed certificate for the machine FQDN and Add the SSL Certificate and Binding. 以下是我能够为机器FQDN生成自签名证书以及添加SSL证书和绑定的方法。

$fqdn = "$((Get-WmiObject win32_computersystem).DNSHostName).$((Get-WmiObject win32_computersystem).Domain)" 
$cert=(Get-ChildItem cert:\LocalMachine\My | where-object { $_.Subject -match "CN=$fqdn" } | Select-Object -First 1) 
if ($cert  -eq $null) { 
$cert = New-SelfSignedCertificate -DnsName $fqdn -CertStoreLocation "Cert:\LocalMachine\My" 
} 
$binding = (Get-WebBinding -Name SiteNameHere | where-object {$_.protocol -eq "https"})
if($binding -ne $null) {
    Remove-WebBinding -Name SiteNameHere -Port 443 -Protocol "https" -HostHeader $fqdn
} 
New-WebBinding -Name SiteNameHere -Port 443 -Protocol https -HostHeader $fqdn 
(Get-WebBinding -Name SiteNameHere -Port 443 -Protocol "https" -HostHeader $fqdn).AddSslCertificate($cert.Thumbprint, "my")

Right now I'm using this approach, which does work: 现在我正在使用这种方法,它确实有效:

$guid = [guid]::NewGuid().ToString("B")
netsh http add sslcert hostnameport=$Name.domain.com:443 certhash=b58e54ca68c94f93c134c5da00a388ab0642a648 certstorename=MY appid="$guid"

Based on @ElanHasson's answer, I made this script which will make a self-signed TLS certificate and apply it to a website. 基于@ElanHasson的回答,我制作了这个脚本,它将制作一个自签名的TLS证书并将其应用到网站上。 It could be tidied a bit, but it works: 它可以整理一下,但它有效:

Clear-Host
$certificateDnsName = 'my.localcert.ssl' # a name you want to give to your certificate (can be anything you want for localhost)

$siteName = "Default Web Site" # the website to apply the bindings/cert to (top level, not an application underneath!).
$fqdn = ""                     #fully qualified domain name (empty, or e.g 'contoso.com')


# ----------------------------------------------------------------------------------------
# SSL CERTIFICATE CREATION
# ----------------------------------------------------------------------------------------

# create the ssl certificate that will expire in 2 years
$newCert = New-SelfSignedCertificate -DnsName $certificateDnsName -CertStoreLocation cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(2)
"Certificate Details:`r`n`r`n $newCert"


# ----------------------------------------------------------------------------------------
# IIS BINDINGS
# ----------------------------------------------------------------------------------------


$webbindings = Get-WebBinding -Name $siteName
$webbindings


$hasSsl = $webbindings | Where-Object { $_.protocol -like "*https*" }

if($hasSsl)
{
    Write-Output "ERROR: An SSL certificate is already assigned. Please remove it manually before adding this certificate."
    Write-Output "Alternatively, you could just use that certificate (provided it's recent/secure)."
}
else
{
    "Applying TLS/SSL Certificate"
    New-WebBinding -Name $siteName -Port 443 -Protocol https -HostHeader $fqdn #could add -IPAddress here if needed (and for the get below)
    (Get-WebBinding -Name $siteName -Port 443 -Protocol "https" -HostHeader $fqdn).AddSslCertificate($newCert.Thumbprint, "my")

    "`r`n`r`nNew web bindings"
    $webbindings = Get-WebBinding -Name $siteName
    $webbindings
}


"`r`n`r`nTLS/SSL Assignment Complete"

With fqdn empty (and no -IPAddress assigned), it will give you this in IIS: 使用fqdn为空(并且没有分配-IPAddress ),它将在IIS中为您提供:

IIS自签名证书绑定

I'm not familiar with IIS, but the error says that the binding(file) already exists, so you're not adding a SSL binding, you're updating one it seems. 我不熟悉IIS,但是错误说绑定(文件)已经存在,所以你没有添加SSL绑定,你似乎正在更新它。 Try adding -Force to the New-Item command. 尝试将-Force添加到New-Item命令。 If it works like with files, it should overwrite the existing binding. 如果它像文件一样工作,它应该覆盖现有的绑定。 Like: 喜欢:

New-WebBinding -name $Name -Protocol https -HostHeader "$Name.domain.com" -Port 443 -SslFlags 1
$cert = Get-ChildItem -Path Cert:\LocalMachine\My | where-Object {$_.subject -like "*cloud.domain.com*"} | Select-Object -ExpandProperty Thumbprint
get-item -Path "cert:\localmachine\my\$cert" | new-item -path IIS:\SslBindings\0.0.0.0!443!$Name.domain.com -Force

The below method worked for me: 以下方法对我有用:

After adding a new SSL configuration in HTTP.sys add a new binding to the website with SslFlags set to 1 as below 在HTTP.sys中添加新的SSL配置后,将新绑定添加到网站,并将SslFlags设置为1,如下所示

  1. Add a new binding in HTTP.sys 在HTTP.sys中添加新绑定
$guid = [guid]::NewGuid().ToString("B")

$certHash = (gci Cert:\LocalMachine\My | where {$_.Subject -match "CN\=TestSSLBinding"} | Select -First 1).Thumbprint

netsh http add sslcert hostnameport=TestsslBinding:443 certhash="$certHash" certstorename=MY appid="$guid"
  1. Add a new binding to the website using New-WebBinding 使用New-WebBinding向网站添加新绑定
New-WebBinding -Name TestWebsite -Protocol https -Port 443 -HostHeader TestsslBinding -IPAddress 192.168.1.108 -SslFlags 1

Setting existing SSL certificate on an IIS website which uses hostheader 在使用hostheader的IIS网站上设置现有SSL证书

I ran into some problems with SNI and powershell as well. 我遇到了SNI和powershell的一些问题。 The one important step I missed was actually during the import process of the certificate. 我错过的一个重要步骤实际上是在证书的导入过程中。 You need to make sure that the certificate is marked as "exportable", otherwise the webadministration module won't be able to bind with it. 您需要确保证书被标记为“可导出”,否则webadministration模块将无法与其绑定。

If you have that, then your original script should work. 如果你有,那么你的原始脚本应该工作。 Although, I personally prefer to use a certificate variable rather than a thumbprint. 虽然,我个人更喜欢使用证书变量而不是指纹。

Like this: 像这样:

New-WebBinding -name $Name -Protocol https -HostHeader "$Name.domain.com" -Port 443 -SslFlags 1
$cert = Get-ChildItem -Path Cert:\LocalMachine\My | where-Object {$_.subject -like "*cloud.domain.com*"}
New-Item -Path "IIS:\SslBindings\!443!$Name.domain.com" -Value $cert -SSLFlags 1

new-item : Cannot create a file when that file already exists new-item:当该文件已存在时,无法创建文件

Dropping the 0.0.0.0!443 binding beforehand fixes this for me: 事先删除0.0.0.0!443绑定为我解决了这个问题:

Get-Item IIS:\SslBindings\0.0.0.0!443 | Remove-Item

FYI: Here's a Powershell script I made to bulk assign a wildcard certificate to sites using SNI/SSL host headers without explicit IP bindings, and where the friendly name of the new certificate is like *.example.com 2019 仅供参考:以下是我为使用SNI / SSL主机标头而没有显式IP绑定的网站批量分配通配符证书而制作的Powershell脚本,以及新证书的友好名称如*.example.com 2019

#SCRIPT FOR ADMIN POWERSHELL TO BULK ASSIGN A WILDCARD SSL CERTIFICATE TO ONE OR MORE WEBSITES USING SSL HOST HEADERS WITHOUT EXPLICIT IPS


# —————————————————————————————
# User Configurable Variables:
# —————————————————————————————
$wildcardDomain="*.example.com";    # This string should be present in the friendly name of the new SSL certificate

$yearMatchingNewCert="2019";    # This string should be UNIQUELY present in the friendly name of the new SSL certificate


# Make the IIS: drive available
Import-Module WebAdministration;



# —————————————————————————————
# Auto-Determine the certificate store to use from the usual 'My' or 'WebHosting' locations
# —————————————————————————————
$certInWebHostingStore=dir Cert:\localmachine\WebHosting | where-Object {$_.subject -like "$wildcardDomain*"};
$certInPersonalStore=dir Cert:\localmachine\My | where-Object {$_.subject -like "$wildcardDomain*"};
if ($certInWebHostingStore) {$certStoreDir="WebHosting"} elseif ($certInPersonalStore) {$certStoreDir="My"} else {$certStoreDir=null};
$certStorePath="\localmachine\$certStoreDir";
echo "███ The NEW certificate is living in this store: $certStorePath";


# —————————————————————————————
# Get the Thumbprint of the NEW certificate
# —————————————————————————————
$certThumbHashNew=Get-ChildItem -Path Cert:$certStorePath | where-Object {$_.subject -like "$wildcardDomain*" -and $_.FriendlyName -like "*$yearMatchingNewCert*"} | Select-Object -ExpandProperty Thumbprint;
echo "███ The NEW certificate's thumbprint hash is: $certThumbHashNew"; # If this displays as empty then you have either not installed the certificate, it's not in the usual Certificate stores or the certificate friendly name doesn't match the pattern "*.example.com 2019" e.g. "*.example.com (2018-2021)"



# —————————————————————————————
# Display the existing bindings
# —————————————————————————————
#Dir IIS:\SslBindings;                      # Shows all bindings
#Dir IIS:\SslBindings\!443!*;               # Shows all port 443 bindings
Dir IIS:\SslBindings\!443!$wildcardDomain;  # Shows all bindings in use matching the wildcard certificate



# —————————————————————————————
# Remove the Existing Bindings
# —————————————————————————————
# NOTE: SNI settings are in the Registry if all else fails: HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\HTTP\Parameters\SslSniBindingInfo
Get-Item IIS:\SslBindings\!443!$wildcardDomain | Remove-Item;



# —————————————————————————————
# Add the New Bindings
# —————————————————————————————
Get-Item -Path "cert:$certStorePath\$certThumbHashNew" | New-Item -Path IIS:\SslBindings\!443!$wildcardDomain;



# —————————————————————————————
# The IIS Manager doesn't seem to update its GUI without this bit
# —————————————————————————————
#(Get-WebBinding -Port 443 -Protocol "https" -HostHeader $wildcardDomain).RemoveSslCertificate($certThumbHashNew, $certStoreDir);
(Get-WebBinding -Port 443 -Protocol "https" -HostHeader $wildcardDomain).AddSslCertificate($certThumbHashNew, $certStoreDir);

Weirdly, viewing the changes in PowerShell (listing the bindings) doesn't show the changes until you get a new console session, so close and re-open the Admin PowerShell window. 奇怪的是,在获得新的控制台会话之前,查看PowerShell中的更改(列出绑定)不会显示更改,因此请关闭并重新打开Admin PowerShell窗口。

# —————————————————————————————
# User Configurable Variables:
# —————————————————————————————
$wildcardDomain="*.example.com";
# —————————————————————————————


# Make the IIS: drive available
Import-Module WebAdministration;


# —————————————————————————————
# Display the new bindings
# —————————————————————————————
Dir IIS:\SslBindings\!443!$wildcardDomain



# —————————————————————————————
# Troubleshooting
# —————————————————————————————
# If things go awry, the 0.0.0.0 address usually seems to be at fault, particularly if the error is "New-Item : Cannot create a file when that file already exists"
# To remove it follow these steps, then start over with the previous script again:
# View all the port 443 bindings, not just the ones matching our wilcard:
#Dir IIS:\SslBindings\!443!*
# If the 0.0.0.0 binding shows in the list then use this to drop it:
#Get-Item IIS:\SslBindings\0.0.0.0!443 | Remove-Item

References used in making this script: 用于制作此脚本的参考:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM