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:
And here is the binding information after CommitChanges()
is called:
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.