powershelliishttpsssl-certificate

Setting certificate information after creating an IIS website with https binding via Microsoft.Web.Administration.ServerManager


I'm writing a PowerShell script to set up several websites on developers' machines in IIS (not IIS Express).

I understand that the current recommendation (as at 2025) is to create IIS websites using the IISAdministration module, rather than the old WebAdministration module, and Microsoft.Web.Administration.ServerManager via the Get-ServerManager cmdlet.

There are several overloads of ServerManager.Sites.Add(). I would prefer to use one of the overloads which doesn't include certificate information, so I can reuse the code to set up multiple sites, some of which do not have HTTPS bindings. I would like to add the certificate information as a separate optional step for those sites which do have HTTPS bindings.

However, I find that if I do add certificate information to a binding after the site is added, when I call ServerManager.CommitChanges() the certificate information disappears.

Is there any way to add a site as a two step process via ServerManager, adding the site first, then the certificate information to the binding if required?

Here is my proof of concept code:

#Requires -RunAsAdministrator
#Requires -Version 5.1
#Requires -Modules @{ ModuleName='IISAdministration'; ModuleVersion='1.1.0.0' }

$physicalPath = 'C:\Working\Test'
$websiteName = 'Test'
# ASSUMPTION: App pool already exists.
$appPoolName = 'Test'
$bindingInfo = @{ Protocol = 'https'; BindingInformation = '*:4000:' }
[byte[]]$certificateHash = 204,219,71,236,31,111,36,12,228,97,184,227,116,172,225,48,123,184,38,197
$certificateInfo = @{ 
    Name = 'IIS Express Development Certificate'
    StoreName = 'My'
    Hash = $certificateHash
    Thumbprint = 'CCDB47EC1F6F240CE461B8E374ACE1307BB826C5'
}

$addCertificateWithSite = $true

$iisServerManager = Get-IISServerManager

if ($addCertificateWithSite) 
{
    # Works.
    $webSite = $iisServerManager.Sites.Add(
        $websiteName, 
        $bindingInfo.BindingInformation, 
        $physicalPath,
        $certificateInfo.Hash,
        $certificateInfo.StoreName)
}
else
{
    # Doesn't work.
    $webSite = $iisServerManager.Sites.Add(
        $websiteName, 
        $bindingInfo.Protocol, 
        $bindingInfo.BindingInformation, 
        $physicalPath)

    $configuredBinding = $webSite.Bindings[0]
    $configuredBinding.CertificateHash = $certificateInfo.Hash
    $configuredBinding.CertificateStoreName = $certificateInfo.StoreName
}

$rootWebApp = $website.Applications['/']
$rootWebApp.ApplicationPoolName = $appPoolName

$iisServerManager.CommitChanges()

Write-Host 'End'

If I supply the certificate information in the Sites.Add(...) method the certificate is set up correctly. See the above code when $addCertificateWithSite = $true. However, if I add the certificate information after the site is added, the certificate information disappears when $iisServerManager.CommitChanges() is called. See the above code when $addCertificateWithSite = $false.

When $addCertificateWithSite = $false here is the binding information before CommitChanges() is called:

enter image description here

And here is the binding information after CommitChanges() is called:

enter image description here


Solution

  • The API/cmdlets were designed along with IIS Manager, so you should use it in the same way as you use IIS Manager to create sites.

    That is, when creating a site, you must start with either an HTTP binding, or an HTTPS binding. You can add or update bindings after creation. The sample code from the other answer shows the exact approach.