Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save PaulStovell/9522828 to your computer and use it in GitHub Desktop.
Save PaulStovell/9522828 to your computer and use it in GitHub Desktop.
## --------------------------------------------------------------------------------------
## Configuration
## --------------------------------------------------------------------------------------
$ConfirmPreference = "None"
$isEnabled = $OctopusParameters["Octopus.Action.IISWebSite.CreateOrUpdateWebSite"]
if (!$isEnabled -or ![Bool]::Parse($isEnabled))
{
exit 0
}
$WebSiteName = $OctopusParameters["Octopus.Action.IISWebSite.WebSiteName"]
$ApplicationPoolName = $OctopusParameters["Octopus.Action.IISWebSite.ApplicationPoolName"]
$bindingString = $OctopusParameters["Octopus.Action.IISWebSite.Bindings"]
$appPoolFrameworkVersion = $OctopusParameters["Octopus.Action.IISWebSite.ApplicationPoolFrameworkVersion"]
$webRoot = $OctopusParameters["Octopus.Action.IISWebSite.WebRoot"]
$enableWindows = $OctopusParameters["Octopus.Action.IISWebSite.EnableWindowsAuthentication"]
$enableBasic = $OctopusParameters["Octopus.Action.IISWebSite.EnableBasicAuthentication"]
$enableAnonymous = $OctopusParameters["Octopus.Action.IISWebSite.EnableAnonymousAuthentication"]
$applicationPoolIdentityType = $OctopusParameters["Octopus.Action.IISWebSite.ApplicationPoolIdentityType"]
$applicationPoolUsername = $OctopusParameters["Octopus.Action.IISWebSite.ApplicationPoolUsername"]
$applicationPoolPassword = $OctopusParameters["Octopus.Action.IISWebSite.ApplicationPoolPassword"]
if (! $webRoot) {
$webRoot = "."
}
$maxFailures = $OctopusParameters["Octopus.Action.IISWebSite.MaxRetryFailures"]
if ($maxFailures -Match "^\d+$") {
$maxFailures = [int]$maxFailures
} else {
$maxFailures = 5
}
$sleepBetweenFailures = $OctopusParameters["Octopus.Action.IISWebSite.SleepBetweenRetryFailuresInSeconds"]
if ($sleepBetweenFailures -Match "^\d+$") {
$sleepBetweenFailures = [int]$sleepBetweenFailures
} else {
$sleepBetweenFailures = Get-Random -minimum 1 -maximum 4
}
if ($sleepBetweenFailures -gt 60) {
Write-Host "Invalid Sleep time between failures. Setting to max of 60 seconds"
$sleepBetweenFailures = 60
}
# Helper to run a block with a retry if things go wrong
function Execute-WithRetry([ScriptBlock] $command) {
$attemptCount = 0
$operationIncomplete = $true
while ($operationIncomplete -and $attemptCount -lt $maxFailures) {
$attemptCount = ($attemptCount + 1)
if ($attemptCount -ge 2) {
Write-Output "Waiting for $sleepBetweenFailures seconds before retrying..."
Start-Sleep -s $sleepBetweenFailures
Write-Output "Retrying..."
}
try {
& $command
$operationIncomplete = $false
} catch [System.Exception] {
if ($attemptCount -lt ($maxFailures)) {
Write-Output ("Attempt $attemptCount of $maxFailures failed: " + $_.Exception.Message)
} else {
throw
}
}
}
}
$webRoot = (resolve-path $webRoot)
$wsbindings = new-object System.Collections.ArrayList
# Each binding string consists of a protocol/binding information (IP, port, hostname)/SSL thumbprint/enabled
# Binding strings are pipe (|) separated to allow multiple to be specified
$bindingString.Split("|") | foreach-object {
$bindingParts = $_.split("/")
$skip = $false
if ($bindingParts.Length -ge 4) {
if (![String]::IsNullOrEmpty($bindingParts[3]) -and [Bool]::Parse($bindingParts[3]) -eq $false) {
$skip = $true
}
}
if ($skip -eq $false) {
$wsbindings.Add(@{ protocol=$bindingParts[0];bindingInformation=$bindingParts[1];thumbprint=$bindingParts[2] }) | Out-Null
} else {
Write-Host "Ignore binding: $_"
}
}
Import-Module WebAdministration
# For any HTTPS bindings, ensure the certificate is configured for the IP/port combination
$wsbindings | where-object { $_.protocol -eq "https" } | foreach-object {
$sslCertificateThumbprint = $_.thumbprint.Trim()
Write-Host "Finding SSL certificate with thumbprint $sslCertificateThumbprint"
$certificate = Get-ChildItem Cert:\LocalMachine -Recurse | Where-Object { $_.Thumbprint -eq $sslCertificateThumbprint -and $_.HasPrivateKey -eq $true } | Select-Object -first 1
if (! $certificate)
{
throw "Could not find certificate under Cert:\LocalMachine with thumbprint $sslCertificateThumbprint. Make sure that the certificate is installed to the Local Machine context and that the private key is available."
}
Write-Host ("Found certificate: " + $certificate.Subject)
$bindingInfo = $_.bindingInformation
$bindingParts = $bindingInfo.split(':')
$ipAddress = $bindingParts[0]
if ((! $ipAddress) -or ($ipAddress -eq '*')) {
$ipAddress = "0.0.0.0"
}
$port = $bindingParts[1]
$sslBindingsPath = ("IIS:\SslBindings\" + $ipAddress + "!" + $port)
Execute-WithRetry {
$sslBinding = get-item $sslBindingsPath -ErrorAction SilentlyContinue
if (! $sslBinding) {
New-Item $sslBindingsPath -Value $certificate | Out-Null
} else {
Set-Item $sslBindingsPath -Value $certificate | Out-Null
}
}
}
## --------------------------------------------------------------------------------------
## Run
## --------------------------------------------------------------------------------------
pushd IIS:\
$appPoolPath = ("IIS:\AppPools\" + $ApplicationPoolName)
Execute-WithRetry {
$pool = Get-Item $appPoolPath -ErrorAction SilentlyContinue
if (!$pool) {
Write-Host "Application pool `"$ApplicationPoolName`" does not exist, creating..."
new-item $appPoolPath -confirm:$false
$pool = Get-Item $appPoolPath
} else {
Write-Host "Application pool `"$ApplicationPoolName`" already exists"
}
}
Execute-WithRetry {
Write-Host "Set application pool identity: $applicationPoolIdentityType"
if ($applicationPoolIdentityType -eq "SpecificUser") {
Set-ItemProperty $appPoolPath -name processModel -value @{identitytype="SpecificUser"; username="$applicationPoolUsername"; password="$applicationPoolPassword"}
} else {
Set-ItemProperty $appPoolPath -name processModel -value @{identitytype="$applicationPoolIdentityType"}
}
}
Execute-WithRetry {
Write-Host "Set .NET framework version: $appPoolFrameworkVersion"
Set-ItemProperty $appPoolPath managedRuntimeVersion $appPoolFrameworkVersion
}
$sitePath = ("IIS:\Sites\" + $webSiteName)
Execute-WithRetry {
$site = Get-Item $sitePath -ErrorAction SilentlyContinue
if (!$site) {
Write-Host "Site `"$WebSiteName`" does not exist, creating..."
$id = (dir iis:\sites | foreach {$_.id} | sort -Descending | select -first 1) + 1
new-item $sitePath -bindings @{protocol="http";bindingInformation=":81:od-temp.example.com"} -id $id -physicalPath $webRoot -confirm:$false
} else {
Write-Host "Site `"$WebSiteName`" already exists"
}
}
$cmd = {
Write-Host "Assigning website to application pool..."
Set-ItemProperty $sitePath -name applicationPool -value $ApplicationPoolName
}
Execute-WithRetry -Command $cmd
Execute-WithRetry {
Write-Host ("Home directory: " + $webRoot)
Set-ItemProperty $sitePath -name physicalPath -value "$webRoot"
}
Execute-WithRetry {
Write-Host "Assigning bindings to website..."
Clear-ItemProperty $sitePath -name bindings
for ($i = 0; $i -lt $wsbindings.Count; $i = $i+1) {
Write-Host ("Binding: " + ($wsbindings[$i].protocol + " " + $wsbindings[$i].bindingInformation + " " + $wsbindings[$i].thumbprint))
New-ItemProperty $sitePath -name bindings -value ($wsbindings[$i])
}
}
try {
Execute-WithRetry {
Write-Host "Anonymous authentication enabled: $enableAnonymous"
Set-WebConfigurationProperty -filter /system.webServer/security/authentication/anonymousAuthentication -name enabled -value "$enableAnonymous" -location $WebSiteName -PSPath "IIS:\"
}
Execute-WithRetry {
Write-Host "Basic authentication enabled: $enableBasic"
Set-WebConfigurationProperty -filter /system.webServer/security/authentication/basicAuthentication -name enabled -value "$enableBasic" -location $WebSiteName -PSPath "IIS:\"
}
Execute-WithRetry {
Write-Host "Windows authentication enabled: $enableWindows"
Set-WebConfigurationProperty -filter /system.webServer/security/authentication/windowsAuthentication -name enabled -value "$enableWindows" -location $WebSiteName -PSPath "IIS:\"
}
} catch [System.Exception] {
Write-Output "Authentication options could not be set. This can happen when there is a problem with your application's web.config. For example, you might be using a section that requires an extension that is not installed on this web server (such as URL Rewrtiting). It can also happen when you have selected an authentication option and the appropriate IIS module is not installed (for example, for Windows authentication, you need to enable the Windows Authentication module in IIS/Windows first)"
throw
}
# It can take a while for the App Pool to come to life (#490)
Start-Sleep -s 1
Execute-WithRetry {
$state = Get-WebAppPoolState $ApplicationPoolName
if ($state.Value -eq "Stopped") {
Write-Host "Application pool is stopped. Attempting to start..."
Start-WebAppPool $ApplicationPoolName
}
}
Execute-WithRetry {
$state = Get-WebsiteState $WebSiteName
if ($state.Value -eq "Stopped") {
Write-Host "Web site is stopped. Attempting to start..."
Start-Website $WebSiteName
}
}
popd
Write-Host "IIS configuration complete"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment