Last active
April 17, 2017 11:38
-
-
Save PaulStovell/9522828 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## -------------------------------------------------------------------------------------- | |
## 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