<# finish-elevated.ps1 — финал декоммишена windows-recovery-host. ЗАПУСКАТЬ В ELEVATED PowerShell (Run as Administrator). Требует: рабочий `pass` (gpg-agent) для VDS sa-пароля. Что делает (с safety-гейтом): F1. Чинит orphaned-user `snolla` в БД `stostayer` на mssql.kzntsv.site. F2. Репойнтит stostayer.old web.config localhost -> mssql.kzntsv.site (+ backup). F3. Рестартит пул stostayer.old, smoke :8091. Если 5xx -> STOP, MSSQL не трогаем. E. Сносит IIS-сайт snolla + C:\sites\snolla + dead traefik CMS-routes. M. Сносит локальный MSSQL (docker) + volume + data dir (~30 ГБ). Идемпотентно, можно прогонять повторно. #> $ErrorActionPreference = 'Stop' if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) { Write-Error "Нужен elevated shell (Run as Administrator)."; return } Import-Module WebAdministration # ---------- F1: orphan fix on VDS ---------- Write-Host "`n=== F1. orphan-fix snolla@stostayer на VDS ===" -ForegroundColor Cyan $sa = (& bash -lc "pass show mssql-vds/sa-password" 2>$null | Select-Object -First 1) if (-not $sa) { $sa = Read-Host "VDS sa password (pass show mssql-vds/sa-password)" } $saConn = "Data Source=mssql.kzntsv.site,1433;Initial Catalog=master;User ID=sa;Password=$sa;TrustServerCertificate=True;Encrypt=True" $cn = New-Object System.Data.SqlClient.SqlConnection $saConn; $cn.Open() $c = $cn.CreateCommand() $c.CommandText = @" USE stostayer; IF EXISTS (SELECT 1 FROM sys.database_principals WHERE name='snolla') ALTER USER snolla WITH LOGIN = snolla; ELSE BEGIN CREATE USER snolla FOR LOGIN snolla; ALTER ROLE db_owner ADD MEMBER snolla; END "@ [void]$c.ExecuteNonQuery(); $cn.Close() Write-Host " orphan-fix applied" -ForegroundColor Green # verify snolla can open stostayer $wcPath = "C:\sites\stostayer.old\web.config" $src = ([xml](Get-Content $wcPath)).configuration.connectionStrings.add.connectionString $verify = ($src -replace '(?i)Data Source=localhost(,1433)?','Data Source=mssql.kzntsv.site,1433') if ($verify -notmatch 'TrustServerCertificate') { $verify = $verify.TrimEnd(';') + ';TrustServerCertificate=True' } $cn = New-Object System.Data.SqlClient.SqlConnection $verify; $cn.Open() $c = $cn.CreateCommand(); $c.CommandText = "SELECT DB_NAME()"; $db = $c.ExecuteScalar(); $cn.Close() Write-Host " verify snolla->VDS stostayer OK (db=$db)" -ForegroundColor Green # ---------- F2: repoint web.config ---------- Write-Host "`n=== F2. repoint stostayer.old web.config ===" -ForegroundColor Cyan Copy-Item $wcPath "$wcPath.bak-pre-vds-$(Get-Date -Format yyyyMMdd)" -Force $xml = [xml](Get-Content $wcPath) $node = $xml.configuration.connectionStrings.add | Where-Object { $_.name -eq 'MoreThenCmsEntities' } $new = ($node.connectionString -replace '(?i)Data Source=localhost(,1433)?','Data Source=mssql.kzntsv.site,1433') if ($new -notmatch 'TrustServerCertificate') { $new = $new.TrimEnd(';') + ';TrustServerCertificate=True' } $node.connectionString = $new $xml.Save($wcPath) Write-Host " web.config -> mssql.kzntsv.site (backup рядом)" -ForegroundColor Green # ---------- F3: restart pool + smoke ---------- Write-Host "`n=== F3. restart pool stostayer.old + smoke :8091 ===" -ForegroundColor Cyan Restart-WebAppPool -Name 'stostayer.old' Start-Sleep -Seconds 5 $code = try { (Invoke-WebRequest "http://localhost:8091/" -UseBasicParsing -TimeoutSec 30).StatusCode } catch { $_.Exception.Response.StatusCode.value__ } Write-Host " :8091 -> HTTP $code" if ($code -ge 500 -or -not $code) { Write-Error "stostayer.old отдаёт $code — репойнт НЕ удался. MSSQL НЕ трогаю. Откат: вернуть web.config.bak-pre-vds-*." return } Write-Host " stostayer.old жив на VDS-БД" -ForegroundColor Green # ---------- E: snolla source IIS teardown ---------- Write-Host "`n=== E. снос IIS-сайта snolla + контента ===" -ForegroundColor Cyan if (Get-Website -Name snolla -ErrorAction SilentlyContinue) { Stop-Website -Name snolla -ErrorAction SilentlyContinue Remove-Website -Name snolla Write-Host " IIS site snolla удалён" } if (Get-WebAppPoolState -Name snolla -ErrorAction SilentlyContinue) { Remove-WebAppPool -Name snolla; Write-Host " app pool snolla удалён" } # dead traefik CMS routes $cust = "C:\Users\vitya\projects\docker\diskstation\traefik\data\custom" $dead = @("snolla.yml","kupimknigi.yml","emspb.yml","pilorama98.yml","labtools.yml","labtoolspro.yml","maljarka.yml","tandemmebel.yml","rimiz.yml","disk.yml","dsm.yml","minio.yml","imgproxy.yml","elasticsearch.yml") foreach ($f in $dead) { $p = Join-Path $cust $f; if (Test-Path $p) { Remove-Item $p -Force; Write-Host " traefik route removed: $f" } } docker restart traefik | Out-Null # delete content (site остановлен -> локи сняты) if (Test-Path "C:\sites\snolla") { Remove-Item "C:\sites\snolla" -Recurse -Force; Write-Host " C:\sites\snolla удалён (8.66 ГБ)" -ForegroundColor Green } # ---------- M: local MSSQL teardown ---------- Write-Host "`n=== M. снос локального MSSQL ===" -ForegroundColor Cyan docker stop mssql 2>$null | Out-Null docker rm mssql 2>$null | Out-Null docker volume rm mssql_mssql_data 2>$null | Out-Null $mssqlDir = "C:\Users\vitya\projects\docker\diskstation\mssql" if (Test-Path $mssqlDir) { Remove-Item $mssqlDir -Recurse -Force; Write-Host " diskstation/mssql удалён (~28 ГБ)" -ForegroundColor Green } Write-Host "`n=== DONE. Free C: ===" -ForegroundColor Cyan Get-PSDrive C | ForEach-Object { "Free={0:N0}GB" -f ($_.Free/1GB) } Write-Host "`nОтдельно (когда удобно) — компактировать docker WSL vhdx, чтобы вернуть ~176 ГБ на C::" Write-Host ' wsl --shutdown; Optimize-VHD -Path "$env:LOCALAPPDATA\Docker\wsl\disk\docker_data.vhdx" -Mode Full' Write-Host ' (путь vhdx уточни: Get-ChildItem $env:LOCALAPPDATA\Docker\wsl -Recurse -Filter *.vhdx)'