Tag: Automation

Creating web sites on IIS using Powershell

Basic operation

The simplest way to create an IIS website via Powershell is to use Carbon module:

Import-Module 'Carbon'

Install-IisWebsite -Name 'test site' -PhysicalPath 'c:\website'

If a website with a given name exists, the script will update it.

Host names

Suppose you need to run several versions of your software side by side, using neat host names such as “v1.localhost” or “v2.localhost”. For that, you need to manipulate the Windows hosts file, like this (again using Carbon):

Set-HostsEntry -IPAddress 127.0.0.1 -HostName v2.localhost

If such host record already exists, it will not insert a duplicate.

You can bind a website to the host in the following way:

Install-IisWebsite -Name 'test site - version 2' -PhysicalPath 'c:\v2\website' -Bindings 'http/*:80:v2.localhost'

Certificates

If you use HTTPS (as you should), you will probably need to make your website use some SSL certificate. The simplest way is to use a self-signed certificate created by IIS. You can automate it like this:

$certificate = New-SelfSignedCertificate -dnsname '*.localhost'

After you have a certificate, you need to tell the website to use it:

Install-IisWebsite -Name 'test' -PhysicalPath 'c:\website' -Bindings 'http/*:80:test.localhost', 'https/*:443:test.localhost'
$applicationId = [System.Guid]::NewGuid().ToString()
Set-IisWebsiteSslCertificate -SiteName test -Thumbprint $certificate.Thumbprint -ApplicationID $applicationId

This will create an IIS website with proper HTTPS bindings.

Note that Carbon’s function¬†Set-IisWebsiteSslCertificate requires a parameter called ApplicationId. You can supply a meaningful value here, but I just use a new guid.

Detecting if a certificate has been created

Sometimes you need a script which takes advantage of the existing data, proceeding without errors if some items already exist and just adding missing bits to them. The certificate creation described above is not suitable for this purpose, as it creates certificate unconditionally. Let’s try to¬†get the existing certificate and check if it exists

$certificate = Get-ChildItem -Path CERT:LocalMachine/My |
    Where-Object -Property DnsNameList -EQ '*.localhost' |
    Select-Object -first 1

if (!$certificate) { Write-Output 'Need to create certificate' }
else { Write-Output 'Certificate is already there' }

 

Putting everything together

Let’s combine the previous material in a couple of reusable functions to create a self-signed certificate if it does not exist, and create an HTTPS-enabled website with a corresponding host entry:

function Get-Or-Create-Certificate($certificateDns)
{
    $certificate = Get-ChildItem -Path CERT:LocalMachine/My |
        Where-Object -Property DnsNameList -EQ $certificateDns |
        Select-Object -first 1

    if (!$certificate)
    {
        Write-Output "Creating self-signed certificate for $certificateDns"

        $certificate = New-SelfSignedCertificate -dnsname $certificateDns
    }
    else
    {
        Write-Output "Self-signed certificate for $certificateDns already exists"
    }

    return $certificate
}

function Create-WebSite($hostName, $path, $siteName, $certificate)
{
    Write-Output "Adding host $hostName"
    Set-HostsEntry -IPAddress 127.0.0.1 -HostName $hostName

    Write-Output "Creating website $siteName on IIS"
    Install-IisWebsite -Name $siteName -PhysicalPath $path -Bindings "http/*:80:$hostName", "https/*:443:$hostName"

    Write-Output "Attaching certificate to the website $siteName"
    $applicationId = [System.Guid]::NewGuid().ToString()
    Set-IisWebsiteSslCertificate -SiteName $siteName -Thumbprint $certificate.Thumbprint -ApplicationID $applicationId
}

The functions above are made to be idempotent, so you can call them several times without errors. Use them as follows:

$certificate = Get-Or-Create-Certificate -certificateDns $certificateDns
Create-Dev-WebSite -hostName 'v1.localhost' -path 'c:\v1\website' -siteName v1 -certificate $certificate
Create-Dev-WebSite -hostName 'v2.localhost' -path 'c:\v2\website' -siteName v2 -certificate $certificate

Feel free to tailor those scripts to your needs.