#Requires -Version 5.1 # Pack existing backup scripts into a double-click exe. Does not change backup logic. $ErrorActionPreference = "Stop" $Root = Split-Path -Parent $MyInvocation.MyCommand.Path Set-Location $Root $cscCandidates = @( "$env:WINDIR\Microsoft.NET\Framework64\v4.0.30319\csc.exe", "$env:WINDIR\Microsoft.NET\Framework\v4.0.30319\csc.exe" ) $csc = $cscCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 if (-not $csc) { throw "csc.exe not found (.NET Framework 4.x)." } $src = Join-Path $Root "MesDbBackup.cs" if (-not (Test-Path $src)) { throw "MesDbBackup.cs not found" } $readme = Get-ChildItem -Path $Root -Filter "*.txt" | Select-Object -First 1 if (-not $readme) { throw "readme txt not found" } $required = @( "backup-ui-server.ps1", "backup-db.ps1", "db-config.ps1", "backup-ui.html", "restore-db.ps1", "install-backup-task.bat", $readme.Name ) foreach ($f in $required) { if (-not (Test-Path (Join-Path $Root $f))) { throw "missing pack file: $f" } } # PS 5.1 parses no-BOM files as ANSI; add UTF-8 BOM to .ps1 so Chinese stays valid $utf8Bom = New-Object System.Text.UTF8Encoding $true $utf8NoBom = New-Object System.Text.UTF8Encoding $false Get-ChildItem -Path $Root -Filter "*.ps1" | ForEach-Object { $raw = [System.IO.File]::ReadAllBytes($_.FullName) if ($raw.Length -ge 3 -and $raw[0] -eq 0xEF -and $raw[1] -eq 0xBB -and $raw[2] -eq 0xBF) { return } $text = [System.IO.File]::ReadAllText($_.FullName, $utf8NoBom) [System.IO.File]::WriteAllText($_.FullName, $text, $utf8Bom) } # csc misreads UTF-8 without BOM; write a BOM copy of the C# source $tmpSrc = Join-Path $env:TEMP "MesDbBackup_build.cs" $utf8Bom = New-Object System.Text.UTF8Encoding $true [System.IO.File]::WriteAllText($tmpSrc, [System.IO.File]::ReadAllText($src, [System.Text.Encoding]::UTF8), $utf8Bom) $outExe = Join-Path $Root "MesDbBackup.exe" $fwDir = Split-Path $csc $winforms = Join-Path $fwDir "System.Windows.Forms.dll" $drawing = Join-Path $fwDir "System.Drawing.dll" $resArgs = @() foreach ($f in $required) { $resArgs += ('/resource:"{0}",{1}' -f (Join-Path $Root $f), $f) } $argList = @( "/nologo", "/target:winexe", "/optimize+", "/platform:anycpu", ('/out:"{0}"' -f $outExe), ('/reference:"{0}"' -f $winforms), ('/reference:"{0}"' -f $drawing) ) + $resArgs + @(('"{0}"' -f $tmpSrc)) Write-Host ("Compiling: {0}" -f $outExe) $p = Start-Process -FilePath $csc -ArgumentList $argList -Wait -PassThru -NoNewWindow if ($p.ExitCode -ne 0) { throw ("compile failed, exit {0}" -f $p.ExitCode) } Remove-Item $tmpSrc -Force -ErrorAction SilentlyContinue if (-not (Test-Path $outExe)) { throw "exe not created" } $sizeKb = [math]::Round((Get-Item $outExe).Length / 1KB, 1) Write-Host ("OK: {0} ({1} KB)" -f $outExe, $sizeKb) Write-Host "Copy the exe to the server and double-click. Config is saved as db-config.json beside the exe."