Public/Restore-GamConfig.ps1
|
function Restore-GamConfig { <# .SYNOPSIS Restores a GAM7 config folder from an AES-encrypted backup artifact. .DESCRIPTION Decrypts the backup artifact, decompresses the zip archive, and writes the config folder contents to the specified output directory. .EXAMPLE Restore-GamConfig -KeyFile ./gam-encryption.key .OUTPUTS Restored GAM config directory at the specified path. #> [CmdletBinding()] param( [Parameter()] [string]$InputPath = (Join-Path (Get-Location) 'gam-config-backup.encrypted'), [Parameter()] [string]$KeyFile = (Join-Path (Get-Location) 'gam-encryption.key'), [Parameter()] [string]$OutputDir = (Join-Path (Get-Location) 'gam-restored'), [Parameter()] [switch]$RestoreToGamDir, [Parameter()] [switch]$Force ) $activity = 'Restore-GamConfig' if (-not (Test-Path $KeyFile)) { Write-Warning "Encryption key not found: $KeyFile" return } Write-Progress -Activity $activity -Status 'Loading encryption key...' -PercentComplete 10 $keyBase64 = [System.IO.File]::ReadAllText($KeyFile).Trim() [byte[]]$key = [Convert]::FromBase64String($keyBase64) if ($key.Length -notin @(16, 24, 32)) { Write-Warning "Invalid key length: $($key.Length) bytes. Must be 16, 24, or 32." return } if ($RestoreToGamDir) { $OutputDir = $env:GAMCFGDIR if (-not $OutputDir) { $OutputDir = Join-Path $HOME '.gam' } Write-Warning "Restoring directly to GAM config directory: $OutputDir" } Write-Verbose "$activity : $InputPath -> $OutputDir" if (-not (Test-Path $InputPath)) { Write-Warning "Backup file not found: $InputPath" return } if ((Test-Path $OutputDir) -and (Get-ChildItem $OutputDir -Force | Select-Object -First 1) -and -not $Force) { Write-Warning "Output directory is not empty: $OutputDir. Use -Force to overwrite." return } Write-Progress -Activity $activity -Status 'Decrypting backup...' -PercentComplete 30 $encryptedBytes = [System.IO.File]::ReadAllBytes($InputPath) $zipBytes = Unprotect-GamData -CipherBytes $encryptedBytes -AesKey $key $tempZip = Join-Path ([System.IO.Path]::GetTempPath()) "gam-restore-$(Get-Date -Format 'yyyyMMddHHmmss').zip" try { [System.IO.File]::WriteAllBytes($tempZip, $zipBytes) if (-not (Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null } Write-Progress -Activity $activity -Status 'Extracting to output directory...' -PercentComplete 70 Expand-Archive -Path $tempZip -DestinationPath $OutputDir -Force Write-Progress -Activity $activity -Completed $itemCount = (Get-ChildItem $OutputDir -Recurse -File).Count [PSCustomObject]@{ InputPath = $InputPath OutputDir = $OutputDir FilesCount = $itemCount Restored = 'Yes' } | Format-List } finally { if (Test-Path $tempZip) { Remove-Item $tempZip -Force } } } |