<# .SYNOPSIS Rolt een gepubliceerde versie van MijnBesluit uit op deze server. .DESCRIPTION Draai dit OP DE SERVER, in een PowerShell-venster dat je als administrator hebt geopend. Het script haalt het pad en de toepassingsgroep uit IIS, zet de site stil, bewaart de huidige versie als terugvaloptie, pakt de nieuwe versie uit, start de site en controleert of hij antwoordt. Gaat er iets mis, dan wordt de vorige versie teruggezet. De map met gegevens (sleutelbestand, kluisbestanden, appsettings.secrets.json) wordt niet aangeraakt: die staat daar bewust buiten. .EXAMPLE # De zip rechtstreeks van je eigen pc halen via de externe-bureaubladverbinding: .\Uitrollen.ps1 -Zip \\tsclient\D\publish\mijnbesluit.zip .EXAMPLE # Of vanaf een bestand dat al op de server staat: .\Uitrollen.ps1 -Zip D:\mijnbesluit.zip #> [CmdletBinding()] param( # Het zip-bestand dat Publiceren.ps1 heeft gemaakt. [Parameter(Mandatory = $true)] [string] $Zip, # De naam van de site zoals die in IIS staat. Pad en toepassingsgroep worden daaruit # opgehaald, zodat je die niet hoeft te onthouden. [string] $Site = 'mijnbesluit', # Alleen invullen als je wilt afwijken van wat er in IIS staat. [string] $Doel, [string] $Pool, # Adres om na afloop te controleren. Niet meegeven laat het script het afleiden uit de # bindingen van de site; een lege tekst slaat de controle over. [string] $Controleer, # Zoveel vorige versies blijven bewaard om op terug te kunnen vallen. [int] $BewaarVersies = 5 ) $ErrorActionPreference = 'Stop' # ---------------------------------------------------------------- vooraf controleren $beheerder = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent() ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $beheerder) { throw 'Dit script heeft beheerdersrechten nodig. Open PowerShell met "Als administrator uitvoeren".' } if (-not (Test-Path $Zip)) { throw "Het zip-bestand is niet gevonden: $Zip" } Import-Module WebAdministration -ErrorAction Stop # ---------------------------------------------------------------- gegevens uit IIS halen $website = Get-Website -Name $Site -ErrorAction SilentlyContinue if (-not $website) { $bestaande = (Get-Website | Select-Object -ExpandProperty Name) -join ', ' throw "Site '$Site' bestaat niet in IIS. Aanwezige sites: $bestaande" } if (-not $Doel) { $Doel = [Environment]::ExpandEnvironmentVariables($website.physicalPath) } if (-not $Pool) { $Pool = $website.applicationPool } if (-not (Test-Path "IIS:\AppPools\$Pool")) { throw "De toepassingsgroep '$Pool' bestaat niet in IIS." } # Een ASP.NET Core-applicatie hoort in een toepassingsgroep zonder beheerde code te draaien. # Staat dat verkeerd, dan krijg je een 500.19 of 500.21 die lastig te herleiden is. $runtime = (Get-ItemProperty "IIS:\AppPools\$Pool" -Name managedRuntimeVersion).Value if ($runtime -ne '') { Write-Host '' Write-Host "Let op: toepassingsgroep '$Pool' staat op .NET CLR-versie '$runtime'." -ForegroundColor Yellow Write-Host 'Voor ASP.NET Core hoort dat "Geen beheerde code" te zijn. Aanpassen met:' -ForegroundColor Yellow Write-Host " Set-ItemProperty 'IIS:\AppPools\$Pool' -Name managedRuntimeVersion -Value ''" Write-Host '' } # Controleadres afleiden uit de bindingen als het niet is meegegeven. if (-not $PSBoundParameters.ContainsKey('Controleer')) { $binding = $website.bindings.Collection | Where-Object { $_.protocol -eq 'https' } | Select-Object -First 1 if (-not $binding) { $binding = $website.bindings.Collection | Select-Object -First 1 } if ($binding) { # bindingInformation ziet eruit als "*:443:mijnbesluit.nl" $delen = $binding.bindingInformation -split ':' $hostnaam = if ($delen.Count -ge 3 -and $delen[2]) { $delen[2] } else { 'localhost' } $Controleer = "$($binding.protocol)://$hostnaam/inloggen" } } $BackupWortel = Join-Path (Split-Path $Doel -Parent) '_vorige-versies' $Stempel = Get-Date -Format 'yyyyMMdd-HHmmss' $BackupMap = Join-Path $BackupWortel "$(Split-Path $Doel -Leaf)-$Stempel" Write-Host '' Write-Host 'MijnBesluit uitrollen' -ForegroundColor Cyan Write-Host " Zip : $Zip" Write-Host " Site : $Site" Write-Host " Doel : $Doel" Write-Host " App-pool : $Pool" Write-Host " Controleer : $(if ($Controleer) { $Controleer } else { '(overslaan)' })" Write-Host '' # ---------------------------------------------------------------- uitpakken naar een tijdelijke map # Eerst helemaal uitpakken en controleren, en pas daarna de site stilzetten. Zo staat de site # maar een paar seconden uit, en niet de hele tijd dat het uitpakken duurt. $Tijdelijk = Join-Path $env:TEMP "mijnbesluit-$Stempel" Write-Host 'Uitpakken...' -ForegroundColor Cyan Expand-Archive -Path $Zip -DestinationPath $Tijdelijk -Force foreach ($nodig in @('MijnBesluit.Web.dll', 'web.config')) { if (-not (Test-Path (Join-Path $Tijdelijk $nodig))) { Remove-Item $Tijdelijk -Recurse -Force throw "Dit lijkt geen geldige publicatie: $nodig ontbreekt in het zip-bestand." } } # ---------------------------------------------------------------- site stilzetten $draaide = (Get-WebAppPoolState -Name $Pool).Value -eq 'Started' if ($draaide) { Write-Host 'Toepassingsgroep stoppen...' -ForegroundColor Cyan Stop-WebAppPool -Name $Pool # Wachten tot IIS de bestanden echt heeft losgelaten; anders mislukt het kopieren. $wachtTot = (Get-Date).AddSeconds(30) while ((Get-WebAppPoolState -Name $Pool).Value -ne 'Stopped' -and (Get-Date) -lt $wachtTot) { Start-Sleep -Milliseconds 500 } Start-Sleep -Seconds 2 } try { # ------------------------------------------------------------ vorige versie bewaren if (Test-Path $Doel) { Write-Host 'Vorige versie bewaren...' -ForegroundColor Cyan New-Item -ItemType Directory -Path $BackupWortel -Force | Out-Null Move-Item -Path $Doel -Destination $BackupMap -Force } # ------------------------------------------------------------ nieuwe versie neerzetten Write-Host 'Nieuwe versie plaatsen...' -ForegroundColor Cyan New-Item -ItemType Directory -Path $Doel -Force | Out-Null Copy-Item -Path (Join-Path $Tijdelijk '*') -Destination $Doel -Recurse -Force } catch { Write-Host 'Er ging iets mis; vorige versie terugzetten...' -ForegroundColor Red if ((Test-Path $BackupMap) -and -not (Test-Path (Join-Path $Doel 'MijnBesluit.Web.dll'))) { if (Test-Path $Doel) { Remove-Item $Doel -Recurse -Force } Move-Item -Path $BackupMap -Destination $Doel -Force } if ($draaide) { Start-WebAppPool -Name $Pool } throw } finally { if (Test-Path $Tijdelijk) { Remove-Item $Tijdelijk -Recurse -Force } } # ---------------------------------------------------------------- weer starten Write-Host 'Toepassingsgroep starten...' -ForegroundColor Cyan Start-WebAppPool -Name $Pool # ---------------------------------------------------------------- controleren if ($Controleer) { Write-Host "Controleren: $Controleer" -ForegroundColor Cyan $gelukt = $false # De eerste aanroep duurt langer: dan start de applicatie op. for ($poging = 1; $poging -le 10; $poging++) { try { $antwoord = Invoke-WebRequest -Uri $Controleer -UseBasicParsing -TimeoutSec 30 if ($antwoord.StatusCode -eq 200) { $gelukt = $true; break } } catch { Start-Sleep -Seconds 3 } } if ($gelukt) { Write-Host 'De site antwoordt.' -ForegroundColor Green } else { Write-Host '' Write-Host 'De site antwoordt niet.' -ForegroundColor Red Write-Host 'Kijk in Logboeken > Windows-logboeken > Toepassing, of zet in web.config' Write-Host 'stdoutLogEnabled op true en kijk daarna in de map logs.' Write-Host '' Write-Host 'Terugvallen op de vorige versie:' -ForegroundColor Yellow Write-Host " Stop-WebAppPool '$Pool'" Write-Host " Remove-Item '$Doel' -Recurse -Force" Write-Host " Move-Item '$BackupMap' '$Doel'" Write-Host " Start-WebAppPool '$Pool'" } } # ---------------------------------------------------------------- oude versies opruimen if (Test-Path $BackupWortel) { Get-ChildItem $BackupWortel -Directory | Sort-Object Name -Descending | Select-Object -Skip $BewaarVersies | ForEach-Object { Write-Host "Oude versie opruimen: $($_.Name)" Remove-Item $_.FullName -Recurse -Force } } Write-Host '' Write-Host 'Klaar.' -ForegroundColor Green Write-Host " Vorige versie staat in: $BackupMap" Write-Host ''