PayrollManagementSystem/scripts/tplus/restore_sqlserver_backup.ps1

88 lines
3.4 KiB
PowerShell

[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$BackupFileName,
[Parameter(Mandatory = $true)]
[string]$DatabaseName,
[Parameter(Mandatory = $true)]
[string]$DataLogicalName,
[Parameter(Mandatory = $true)]
[string]$LogLogicalName,
[string]$ContainerName = "ys-tplus-sqlserver-dev",
[string]$BackupRoot = "D:\work\app\tplus-sqlserver\backup",
[string]$DataRoot = "D:\work\app\tplus-sqlserver\data",
[string]$LogRoot = "D:\work\app\tplus-sqlserver\log",
[Parameter(Mandatory = $true)]
[SecureString]$SaPassword
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
. (Join-Path $PSScriptRoot "container_sql.ps1")
if ($DatabaseName -notmatch '^[A-Za-z_][A-Za-z0-9_]{0,127}$') {
throw "恢复数据库名只能使用字母、数字和下划线。"
}
if ([IO.Path]::GetFileName($BackupFileName) -ne $BackupFileName) {
throw "备份文件名不能包含目录。"
}
foreach ($path in @($BackupRoot, $DataRoot, $LogRoot)) {
if (-not [IO.Path]::GetFullPath($path).StartsWith("D:\", [StringComparison]::OrdinalIgnoreCase)) {
throw "恢复目录必须位于 D 盘。"
}
}
$mounts = docker inspect $ContainerName --format '{{json .Mounts}}' | ConvertFrom-Json
if ($LASTEXITCODE -ne 0) { throw "无法读取 SQL Server 容器挂载。" }
foreach ($pair in @(
@{ Target="/var/opt/mssql/data"; Source=$DataRoot },
@{ Target="/var/opt/mssql/log"; Source=$LogRoot },
@{ Target="/var/opt/mssql/backup"; Source=$BackupRoot }
)) {
$mount = @($mounts | Where-Object { $_.Destination -eq $pair.Target })
if ($mount.Count -ne 1 -or $mount[0].Type -ne "bind") {
throw "目标目录未明确绑定到宿主机 D 盘:$($pair.Target)"
}
if ([IO.Path]::GetFullPath($mount[0].Source) -ine [IO.Path]::GetFullPath($pair.Source)) {
throw "实际挂载与恢复目录配置不一致:$($pair.Target)"
}
}
foreach ($path in @($BackupRoot, $DataRoot, $LogRoot)) {
if (-not (Test-Path -LiteralPath $path)) {
New-Item -ItemType Directory -Path $path -Force | Out-Null
}
}
$backupPath = Join-Path $BackupRoot $BackupFileName
if (-not (Test-Path -LiteralPath $backupPath)) {
throw "找不到备份文件:$backupPath"
}
$containerBackupPath = "/var/opt/mssql/backup/$BackupFileName"
$dataPath = "/var/opt/mssql/data/$DatabaseName.mdf"
$logPath = "/var/opt/mssql/log/$DatabaseName`_log.ldf"
$safeDatabaseIdentifier = $DatabaseName.Replace("]", "]]" )
$safeDatabaseLiteral = $DatabaseName.Replace("'", "''")
$safeDataLogicalName = $DataLogicalName.Replace("'", "''")
$safeLogLogicalName = $LogLogicalName.Replace("'", "''")
$safeBackupPath = $containerBackupPath.Replace("'", "''")
$sql = @"
RESTORE VERIFYONLY FROM DISK = N'$safeBackupPath';
IF DB_ID(N'$safeDatabaseLiteral') IS NOT NULL
BEGIN
THROW 51000, 'Target database exists; refusing to overwrite.', 1;
END;
RESTORE DATABASE [$safeDatabaseIdentifier]
FROM DISK = N'$safeBackupPath'
WITH MOVE N'$safeDataLogicalName' TO N'$dataPath',
MOVE N'$safeLogLogicalName' TO N'$logPath',
RECOVERY, STATS = 5;
ALTER DATABASE [$safeDatabaseIdentifier] SET READ_ONLY;
DBCC CHECKDB (N'$safeDatabaseLiteral') WITH NO_INFOMSGS;
"@
Write-Host "正在校验并恢复备份(密码不会输出)……"
Invoke-TPlusContainerSql -ContainerName $ContainerName -Sql $sql -SaPassword $SaPassword
Write-Host "恢复完成:$DatabaseName;数据库文件位于 D 盘绑定目录。"