|
|
@@ -6,11 +6,14 @@ param(
|
|
|
[Parameter(Mandatory = $true)]
|
|
|
[string]$ConfigurationPath,
|
|
|
|
|
|
- [string]$SiteName = 'Default Web Site',
|
|
|
+ [Parameter(Mandatory = $true)]
|
|
|
+ [string]$SiteName,
|
|
|
+ [ValidatePattern('^[A-Za-z0-9_-]+$')]
|
|
|
[string]$ApplicationName = 'xiaoshu-sync',
|
|
|
[string]$ApplicationPoolName = 'XiaoshuLegacySync',
|
|
|
[string]$PhysicalPath = 'C:\inetpub\xiaoshu-sync',
|
|
|
- [string]$HealthUrl = 'http://127.0.0.1/xiaoshu-sync/v1/health',
|
|
|
+ [Parameter(Mandatory = $true)]
|
|
|
+ [string]$HealthUrl,
|
|
|
[switch]$PreflightOnly
|
|
|
)
|
|
|
|
|
|
@@ -49,11 +52,32 @@ $resolvedPublishPath = (Resolve-Path -LiteralPath $PublishPath).Path
|
|
|
if (-not (Test-Path -LiteralPath (Join-Path $resolvedPublishPath 'Xiaoshu.LegacySyncBridge.dll'))) { throw '发布目录缺少 Xiaoshu.LegacySyncBridge.dll。' }
|
|
|
if (-not (Test-Path -LiteralPath (Join-Path $resolvedPublishPath 'web.config'))) { throw '发布目录缺少 web.config。' }
|
|
|
$productionConfiguration = Assert-Configuration $ConfigurationPath
|
|
|
+$configuration = $productionConfiguration | ConvertFrom-Json
|
|
|
+$configuredPathBase = [string]$configuration.XiaoshuSync.PathBase
|
|
|
+if ($configuredPathBase -ne "/$ApplicationName") { throw '配置中的 PathBase 必须与 IIS 应用路径一致。' }
|
|
|
|
|
|
if (-not (Get-WebGlobalModule -Name 'AspNetCoreModuleV2' -ErrorAction SilentlyContinue)) {
|
|
|
throw '服务器尚未安装 IIS AspNetCoreModuleV2。同步桥为 Windows x64 自包含发布,不要求服务器安装 .NET 8 Runtime,但仍需要该 IIS 模块。'
|
|
|
}
|
|
|
if (-not (Test-Path "IIS:\Sites\$SiteName")) { throw "IIS 站点不存在:$SiteName" }
|
|
|
+$healthUri = [Uri]$HealthUrl
|
|
|
+if (-not $healthUri.IsAbsoluteUri -or $healthUri.Scheme -notin @('http', 'https') -or $healthUri.AbsolutePath -ne "/$ApplicationName/v1/health" -or $healthUri.Query -or $healthUri.Fragment -or $healthUri.UserInfo) {
|
|
|
+ throw 'HealthUrl 必须是目标站点的完整 HTTP(S) 健康地址,路径为 /应用名/v1/health。'
|
|
|
+}
|
|
|
+$matchingBindings = @(Get-WebBinding -Name $SiteName | Where-Object {
|
|
|
+ $parts = ([string]$_.bindingInformation) -split ':'
|
|
|
+ $address = $null
|
|
|
+ $isIpAddress = [Net.IPAddress]::TryParse($healthUri.DnsSafeHost, [ref]$address)
|
|
|
+ $hostMatches = $parts[-1] -eq $healthUri.DnsSafeHost -or
|
|
|
+ ($isIpAddress -and [string]::IsNullOrEmpty($parts[-1]) -and ($parts[0] -eq '*' -or $parts[0] -eq $healthUri.DnsSafeHost))
|
|
|
+ $_.protocol -eq $healthUri.Scheme -and $parts[-2] -eq [string]$healthUri.Port -and
|
|
|
+ $hostMatches
|
|
|
+})
|
|
|
+if ($matchingBindings.Count -eq 0) {
|
|
|
+ throw "健康地址的域名、端口和协议没有绑定到 IIS 站点 '$SiteName'。请指定实际承载旧站域名的站点,不能默认安装到 Default Web Site。"
|
|
|
+}
|
|
|
+$rootPool = [string](Get-Item "IIS:\Sites\$SiteName").applicationPool
|
|
|
+if ($ApplicationPoolName -eq $rootPool) { throw '同步桥必须使用独立应用池,不能使用旧站根应用的应用池。' }
|
|
|
|
|
|
Write-Host '部署前检查通过:'
|
|
|
Write-Host " IIS 站点:$SiteName"
|
|
|
@@ -90,6 +114,7 @@ if ($PSCmdlet.ShouldProcess("$SiteName$applicationPath", '部署小树旧系统
|
|
|
New-WebAppPool -Name $ApplicationPoolName | Out-Null
|
|
|
}
|
|
|
Set-ItemProperty "IIS:\AppPools\$ApplicationPoolName" -Name managedRuntimeVersion -Value ''
|
|
|
+ Set-ItemProperty "IIS:\AppPools\$ApplicationPoolName" -Name enable32BitAppOnWin64 -Value $false
|
|
|
Set-ItemProperty "IIS:\AppPools\$ApplicationPoolName" -Name processModel.identityType -Value ApplicationPoolIdentity
|
|
|
Set-ItemProperty "IIS:\AppPools\$ApplicationPoolName" -Name startMode -Value AlwaysRunning
|
|
|
|
|
|
@@ -108,7 +133,7 @@ if ($PSCmdlet.ShouldProcess("$SiteName$applicationPath", '部署小树旧系统
|
|
|
foreach ($attempt in 1..12) {
|
|
|
try {
|
|
|
$health = Invoke-RestMethod -Uri $HealthUrl -Method Get -TimeoutSec 10
|
|
|
- if ($health.status -eq 'ok') { $healthy = $true; break }
|
|
|
+ if ($health.status -eq 'ok' -and $health.service -eq 'xiaoshu-legacy-sync' -and $health.version -eq 'v1') { $healthy = $true; break }
|
|
|
} catch {
|
|
|
Start-Sleep -Seconds 2
|
|
|
}
|