Created
July 8, 2022 13:55
-
-
Save J-Swift/524fda8672122be6f1371cf4f5534683 to your computer and use it in GitHub Desktop.
Capistrano-style IIS deployment helper
This file contains hidden or 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
| param( | |
| [switch] $Rollback | |
| ) | |
| ################################################################################ | |
| # Config | |
| ################################################################################ | |
| $WebsiteName = "FIXME: IIS WEBSITE NAME" | |
| $WaitForWebsiteTimeoutSeconds = 60 | |
| $NumReleasesToKeep = 5 | |
| $ReleasesDir = (Join-Path "." releases) | |
| ################################################################################ | |
| # Helpers | |
| ################################################################################ | |
| function WriteInfo { | |
| param([Parameter(Mandatory = $true)][string] $Msg) | |
| Write-Host $Msg | |
| } | |
| function WriteWarn { | |
| param([Parameter(Mandatory = $true)][string] $Msg) | |
| Write-Host -ForegroundColor Yellow $Msg | |
| } | |
| function WriteError { | |
| param([Parameter(Mandatory = $true)][string] $Msg) | |
| Write-Host -ForegroundColor Red $Msg | |
| } | |
| function FailWithMessage { | |
| param([Parameter(Mandatory = $true)][string] $Msg) | |
| WriteError $Msg | |
| [System.Console]::ReadKey() | |
| exit 1 | |
| } | |
| function WaitForState() { | |
| param([Parameter(Mandatory = $true)][string] $State) | |
| $Timeout = (Get-Date).AddSeconds($WaitForWebsiteTimeoutSeconds) | |
| while ($State -ne (Get-IISSite -name $WebsiteName).State) { | |
| if ((Get-Date) -gt $Timeout) { | |
| return $false | |
| } | |
| Start-Sleep -Seconds 1 | |
| } | |
| return $true | |
| } | |
| function LoadIISModule() { | |
| Import-Module IISAdministration | |
| if (-not $?) { | |
| FailWithMessage "Error while loading IISAdministration module. Exiting." | |
| } | |
| } | |
| function UpdateCurrentTo() { | |
| param([Parameter(Mandatory = $true)][string] $TargetPath) | |
| $CurrentPath = (Join-Path "." "current") | |
| if (Test-Path $CurrentPath) { | |
| Remove-Item $CurrentPath | |
| } | |
| New-Item -ItemType SymbolicLink -Path $CurrentPath -Target $TargetPath | Out-Null | |
| WriteInfo " Updated $CurrentPath to point at [$TargetPath]" | |
| } | |
| function GetRollbackTarget() { | |
| $CurrentTarget = (Get-ChildItem -Filter "current").Target | |
| $Releases = (Get-ChildItem $ReleasesDir | Sort-Object -Descending) | |
| $ReturnNext = $false | |
| foreach ($Release in $Releases) { | |
| if ($ReturnNext) { | |
| return $Release | |
| } | |
| if ($Release.ToString() -eq $CurrentTarget.ToString()) { | |
| $ReturnNext = $true | |
| } | |
| } | |
| return $null | |
| } | |
| function RemoveOldReleases() { | |
| $ReleasesToDelete = (Get-ChildItem $ReleasesDir -exclude ".revision" | Sort-Object -Descending | Select-Object -Skip $NumReleasesToKeep) | |
| $CurrentTarget = (Get-ChildItem -Filter "current").Target | |
| foreach ($Release in $ReleasesToDelete) { | |
| if ($Release.ToString() -eq $CurrentTarget.ToString()) { | |
| WriteInfo " Skipping current release [$Release]" | |
| } else { | |
| WriteInfo " Removing old release at [$Release]" | |
| Remove-Item $Release -Force -Recurse | |
| } | |
| } | |
| } | |
| function CheckIfRunningAsAdmin() { | |
| # https://megamorf.gitlab.io/2020/05/26/check-if-powershell-is-running-as-administrator/ | |
| [Security.Principal.WindowsIdentity]::GetCurrent().Groups -contains 'S-1-5-32-544' | |
| } | |
| ################################################################################ | |
| # Main | |
| ################################################################################ | |
| if (-not ("Core" -eq $PSVersionTable.PSEdition)) { | |
| FailWithMessage "This script requires Powershell Core. Exiting." | |
| } | |
| if (-not (CheckIfRunningAsAdmin)) { | |
| FailWithMessage "This script requires being run as Admin. Exiting." | |
| } | |
| if (-not (Test-Path $ReleasesDir)) { | |
| FailWithMessage "No releases found in [$ReleasesDir]. Exiting." | |
| } | |
| $NewestRelease = Get-ChildItem $ReleasesDir | Sort-Object -Descending | Select-Object -First 1 | |
| if ($null -eq $NewestRelease) { | |
| FailWithMessage "No releases found in [$ReleasesDir]. Exiting." | |
| } | |
| $NewestReleasePath = $NewestRelease | |
| function Main() { | |
| WriteInfo " > Loading IISAdministration PS module" | |
| LoadIISModule | |
| WriteInfo " > Checking if website is stopped" | |
| if ("Stopped" -ne (Get-IISSite -name $WebsiteName).State) { | |
| WriteWarn "You must stop the website named [$WebsiteName] in IIS.`n`nWaiting..." | |
| if (-not (WaitForState "Stopped")) { | |
| FailWithMessage "`nTimed out waiting for [$WebsiteName] to be stopped. Exiting." | |
| } | |
| } | |
| WriteInfo " Stopped" | |
| WriteInfo " > Updating current link" | |
| if ($Rollback) { | |
| $Target = GetRollbackTarget | |
| if ($null -eq $Target) { | |
| WriteInfo " No target for rollback" | |
| } else { | |
| WriteInfo " Rolling back to [$Target]" | |
| UpdateCurrentTo $Target | |
| } | |
| } else { | |
| UpdateCurrentTo $NewestReleasePath | |
| WriteInfo " > Checking for old releases" | |
| RemoveOldReleases | |
| } | |
| WriteWarn "Release updated. You must start the website named [$WebsiteName] in IIS.`n`nWaiting..." | |
| if ("Started" -ne (Get-IISSite -name $WebsiteName).State) { | |
| if (-not (WaitForState "Started")) { | |
| FailWithMessage "`nTimed out waiting for [$WebsiteName] to be started. Exiting." | |
| } | |
| } | |
| WriteInfo " Started" | |
| WriteInfo "`nDone!" | |
| [System.Console]::ReadKey() | |
| } | |
| Main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment