22

I'm trying to control bindings in an IIS app using powershell. I'd like to create a site with both a http and https binding using a script.

This is what I have thus far:

Param(
    [Parameter(Mandatory=$True,Position=1)]
    [string]$hostname,
    [Parameter(Mandatory=$True,Position=2)]
    [string]$installPath,
    [Parameter(Mandatory=$False,Position=3)]
    [string]$ip
)

Import-Module WebAdministration

$appPoolName =  $hostname + 'Pool'

$port = 80
$hostRecord = $hostname+'.example.com'

$bindings = @{protocol="http";bindingInformation=$ip + ":"+ $port + ":" + $hostRecord}

New-Item IIS:\AppPools\$appPoolName
Set-ItemProperty IIS:\AppPools\$appPoolName managedRuntimeVersion v4.0

New-Item IIS:\Sites\$hostname -Bindings $bindings -PhysicalPath $installPath
Set-ItemProperty IIS:\Sites\$hostname -Name applicationPool -Value $appPoolName

How do I add bindings to my $bindings variable / use some other mechanism to achieve my goal?

Khanzor
  • 331
  • 1
  • 2
  • 5

3 Answers3

26

You can use New-WebBinding: http://technet.microsoft.com/en-us/library/ee790567.aspx

e.g.

IIS:\>New-WebBinding -Name "Default Web Site" -IPAddress "*" -Port 80 -HostHeader TestSite
Mark Henderson
  • 68,823
  • 31
  • 180
  • 259
MatthewP
  • 413
  • 3
  • 5
  • Whilst this may theoretically answer the question, [it would be preferable](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Mark Henderson Dec 19 '13 at 00:35
  • Do you think that I'll come up with a better example than at the bottom of the technet article? – MatthewP Dec 19 '13 at 00:39
  • 16
    No, but perhaps you should take the part of the technet article that's relevant and reproduce it here in a quote block. I've edited in something that should be sufficient. – Mark Henderson Dec 19 '13 at 00:49
  • Does this require to restart IIS to take effect? – Krunal Jul 11 '19 at 13:29
13

I went through the process of trying to add an https binding to a site and it can be pretty painful. There are a lot of ways to accomplish each step and each one has pitfalls. I am leaving behind the final solution hoping that someone will find it useful.

This solution assumes that you have IIS installed and a web site defined. Call the site sample.contoso.com for the purposes of this post. Assume that you have a certificate in a sample.contoso.com.pfx file that you want to use as well.

The first step is to import the certificate from the file.

$certPwd = ConvertTo-SecureString -String "password" -Force -AsPlainText
$webServerCert = Import-PfxCertificate -FilePath c:\some\folder\sample.contoso.com.pfx -CertStoreLocation Cert:\LocalMachine\My -Password $certPwd

It would be nice if that was sufficient. And in some cases it may be. However, for me, this left the certificate without proper access to the private key. This caused a powershell error "A specified logon session does not exist. It may already have been terminated" when I went to add the certificate to the binding (see that step later). So, the next step is to fix up the ACL for the private key.

$privateKeyFilename = $webServerCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
$privateKeyFullPath = "c:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\"+$privateKeyFilename
$aclRule = "SYSTEM", "Full", "Allow"
$aclEntry = New-Object System.Security.AccessControl.FileSystemAccessRule $aclRule
$privateKeyAcl = (Get-Item $privateKeyFullPath).GetAccessControl("Access")
$privateKeyAcl.AddAccessRule($aclEntry)
Set-Acl $privateKeyFullPath $privateKeyAcl

This will allow local system to have full access to the private key if that is not inherited from the containing folder.

If you want to get a certificate that is already installed, you need the hash for it and can retrieve it with Get-Item like so:

$webServerCert = get-item Cert:\LocalMachine\My\XFX2DX02779XFD1F6F4X8435A5X26ED2X8DEFX95

The next step is to create the binding.

New-WebBinding -Name sample.contoso.com -IPAddress * -Port 443 -Protocol "https"

It is important to note that "https" is case sensitive. If you use "HTTPS" instead, you get a really different binding result.

This binding does not have a certificate attached to it yet, so the last step is to attach the certificate. If the certificate is properly trusted and the security is correct, this step should be successful. It can be finicky if there is any issue with the certificate though.

$bind = Get-WebBinding -Name $webSiteDNSName -Protocol https
$bind.AddSslCertificate($webServerCert.GetCertHashString(), "my")

If this fails with a message about a logon session does not exist, then the certificate may have some issue. Review the event viewer for more details. During my efforts, I found event 5061 in the security log. When it failed, it showed that OpenKey failed with 80090016 (The Keyset Does not Exist). And the failure was because SYSTEM did not have access to the private key.

That was sufficient for me to create the https binding. The http binding was a byproduct of using the New-WebSite cmdlet. If it does not come for free, I didn't find creating the port 80 binding with the New-WebBinding cmdlet to be a challenge.

  • 1
    I appreciated this answer, but there seems to be an easier route @ http://stackoverflow.com/questions/32390097/powershell-set-ssl-certificate-on-https-binding/32391937#32391937. – Peter Majeed Nov 19 '16 at 23:27
  • 2
    I agree that the AddSslCertificate call is more pleasing than the new-item syntax and I replaced it. The frustration I had when working through this was the error messages I got and the fact that I couldn't relate them back to a resolution using a google search. So, the remaining words are related to easing that process in the future or for someone else. – Prof Von Lemongargle Mar 15 '17 at 20:28
4

I think what you're after is the following:

$bindings = @(
   @{protocol="http";bindingInformation=$ip + ":"+ $port + ":" + $hostRecord},
   @{protocol="https";bindingInformation=$ip + ":"+ $port + ":" + $hostRecord}
)

Basically you need to pass an array of bindings in. More helpful information here - (http://blogs.iis.net/jeonghwan/iis-powershell-user-guide-comparing-representative-iis-ui-tasks)

(Edit: Fixed typo in array syntax - extraneous comma)

Taras Alenin
  • 141
  • 3