restore-db.ps1 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #Requires -Version 5.1
  2. <#
  3. .SYNOPSIS
  4. 还原 MES Cloud 全量备份(gzip)
  5. .EXAMPLE
  6. powershell -ExecutionPolicy Bypass -File .\restore-db.ps1
  7. powershell -ExecutionPolicy Bypass -File .\restore-db.ps1 -BackupFile "E:\MES_DB_Backup\mes_cloud_20260821.sql.gz"
  8. #>
  9. param(
  10. [string]$BackupFile,
  11. [switch]$Force
  12. )
  13. $ErrorActionPreference = "Stop"
  14. . (Join-Path $PSScriptRoot "db-config.ps1")
  15. $dbCfg = Read-MesDbConfig
  16. $DbHost = [string]$dbCfg.host
  17. $DbPort = [int]$dbCfg.port
  18. $DbName = [string]$dbCfg.database
  19. $DbUser = [string]$dbCfg.user
  20. $DbPassword = [string]$dbCfg.password
  21. $BackupRoot = "E:\MES_DB_Backup"
  22. $CnfFile = Join-Path $env:TEMP ("mes_restore_{0}.cnf" -f $PID)
  23. function Find-MysqlTool {
  24. param([string]$Name)
  25. $cmd = Get-Command $Name -ErrorAction SilentlyContinue
  26. if ($cmd -and $cmd.Source) { return $cmd.Source }
  27. $binRoots = @(
  28. "C:\Program Files\MySQL",
  29. "C:\Program Files (x86)\MySQL",
  30. "C:\mysql",
  31. "D:\MySQL",
  32. "E:\MySQL",
  33. "C:\Program Files\MariaDB"
  34. )
  35. foreach ($root in $binRoots) {
  36. if (-not (Test-Path $root)) { continue }
  37. $hit = Get-ChildItem -Path $root -Filter ($Name + ".exe") -Recurse -ErrorAction SilentlyContinue |
  38. Where-Object { $_.Directory.Name -eq "bin" } |
  39. Select-Object -First 1
  40. if ($hit) { return $hit.FullName }
  41. }
  42. return $null
  43. }
  44. try {
  45. if (-not $BackupFile) {
  46. $latest = Get-ChildItem -Path $BackupRoot -File -Filter "mes_cloud_*.sql.gz" -ErrorAction SilentlyContinue |
  47. Sort-Object LastWriteTime -Descending |
  48. Select-Object -First 1
  49. if (-not $latest) { throw "找不到备份文件,目录: $BackupRoot" }
  50. $BackupFile = $latest.FullName
  51. }
  52. if (-not (Test-Path $BackupFile)) {
  53. throw "找不到备份文件: $BackupFile"
  54. }
  55. if (-not $Force) {
  56. Write-Host "即将把备份还原到 ${DbHost}:${DbPort} / $DbName"
  57. Write-Host "备份文件: $BackupFile"
  58. Write-Host "现有数据会被覆盖。"
  59. $ans = Read-Host "确认还原请输入 YES"
  60. if ($ans -ne "YES") {
  61. Write-Host "已取消"
  62. exit 0
  63. }
  64. }
  65. $mysql = Find-MysqlTool "mysql"
  66. if (-not $mysql) { throw "找不到 mysql.exe,请安装 MySQL 客户端并把 bin 目录加入 PATH" }
  67. Write-MesMysqlCnf -Config $dbCfg -CnfPath $CnfFile
  68. $isGzip = $false
  69. $fsHead = [System.IO.File]::OpenRead($BackupFile)
  70. try {
  71. $b0 = $fsHead.ReadByte()
  72. $b1 = $fsHead.ReadByte()
  73. $isGzip = ($b0 -eq 0x1F -and $b1 -eq 0x8B)
  74. } finally {
  75. $fsHead.Dispose()
  76. }
  77. Write-Host $(if ($isGzip) { "正在还原(gzip 压缩包)..." } else { "正在还原(SQL 文本,文件较大时请耐心等待)..." })
  78. $psi = New-Object System.Diagnostics.ProcessStartInfo
  79. $psi.FileName = $mysql
  80. $psi.Arguments = ('"--defaults-extra-file={0}" "--max-allowed-packet=1G" "--default-character-set=utf8mb4"' -f $CnfFile)
  81. $psi.UseShellExecute = $false
  82. $psi.RedirectStandardInput = $true
  83. $psi.RedirectStandardError = $true
  84. $psi.CreateNoWindow = $true
  85. $proc = New-Object System.Diagnostics.Process
  86. $proc.StartInfo = $psi
  87. if (-not $proc.Start()) { throw "无法启动 mysql" }
  88. $fs = [System.IO.File]::OpenRead($BackupFile)
  89. $gz = $null
  90. try {
  91. $inStream = $fs
  92. if ($isGzip) {
  93. $gz = New-Object System.IO.Compression.GZipStream($fs, [System.IO.Compression.CompressionMode]::Decompress)
  94. $inStream = $gz
  95. }
  96. $inStream.CopyTo($proc.StandardInput.BaseStream)
  97. $proc.StandardInput.Close()
  98. } finally {
  99. if ($gz) { $gz.Dispose() }
  100. $fs.Dispose()
  101. }
  102. $err = $proc.StandardError.ReadToEnd()
  103. $proc.WaitForExit()
  104. if ($proc.ExitCode -ne 0) {
  105. throw ("还原失败: {0}" -f $err)
  106. }
  107. Write-Host "还原完成"
  108. exit 0
  109. } catch {
  110. Write-Host ("还原失败: {0}" -f $_.Exception.Message) -ForegroundColor Red
  111. exit 1
  112. } finally {
  113. if (Test-Path $CnfFile) { Remove-Item $CnfFile -Force -ErrorAction SilentlyContinue }
  114. }