Files
Win11Debloat/Scripts/Features/BackupRegistryState.ps1

147 lines
5.2 KiB
PowerShell

<#
.SYNOPSIS
Creates a timestamped JSON backup of registry state for selected features.
.DESCRIPTION
Resolves selected and undo features from the provided keys, captures their
registry state, and saves the result as a JSON file in the Backups/ folder.
Returns the file path on success, $null if no registry-backed features exist.
.PARAMETER ActionableKeys
Param keys from $script:Params to resolve into apply features.
.PARAMETER ExtraFeatures
Additional synthetic feature objects (e.g. undo features) to include.
#>
function New-RegistrySettingsBackup {
param(
[string[]]$ActionableKeys,
[object[]]$ExtraFeatures = @()
)
$ActionableKeys = @($ActionableKeys)
$selectedFeatures = @(Get-SelectedFeatures -ActionableKeys $ActionableKeys)
$undoFeatures = @($ExtraFeatures | Where-Object { $_ -ne $null })
$allFeatures = @($selectedFeatures) + @($undoFeatures)
if (@($allFeatures | Where-Object { -not [string]::IsNullOrWhiteSpace([string]$_.RegistryKey) }).Count -eq 0) {
return $null
}
$timestamp = Get-Date
$backupDirectory = $script:RegistryBackupsPath
if (-not (Test-Path $backupDirectory)) {
New-Item -ItemType Directory -Path $backupDirectory -Force | Out-Null
}
$backupFileName = 'Win11Debloat-RegistryBackup-{0}.json' -f $timestamp.ToString('yyyyMMdd_HHmmss')
$backupFilePath = Join-Path $backupDirectory $backupFileName
$backupConfig = Get-RegistryBackupPayload -SelectedFeatures $selectedFeatures -UndoFeatures $undoFeatures -CreatedAt $timestamp
if (-not (SaveToFile -Config $backupConfig -FilePath $backupFilePath -MaxDepth 25)) {
throw "Failed to save registry backup to '$backupFilePath'"
}
Write-Host "Backup successfully created: $backupFilePath"
Write-Host ""
return $backupFilePath
}
<#
.SYNOPSIS
Resolves param keys into deduplicated feature objects from the catalog.
.PARAMETER ActionableKeys
Param keys to look up in $script:Features.
#>
function Get-SelectedFeatures {
param(
[string[]]$ActionableKeys
)
$selectedFeatures = New-Object System.Collections.Generic.List[object]
$selectedFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase)
foreach ($paramKey in $ActionableKeys) {
if (-not $script:Features.ContainsKey($paramKey)) { continue }
$feature = $script:Features[$paramKey]
if (-not $feature) { continue }
$featureId = [string]$feature.FeatureId
if ($selectedFeatureIds.Add($featureId)) {
$selectedFeatures.Add($feature)
}
}
return @($selectedFeatures.ToArray())
}
<#
.SYNOPSIS
Builds the full backup payload object from selected and undo features.
.DESCRIPTION
Deduplicates feature IDs, resolves registry capture plans, snapshots all
registry keys, and assembles the final backup hashtable with metadata.
.PARAMETER SelectedFeatures
Feature objects from the apply side.
.PARAMETER UndoFeatures
Synthetic feature objects from the undo side.
.PARAMETER CreatedAt
Timestamp recorded in the backup metadata.
#>
function Get-RegistryBackupPayload {
param(
[object[]]$SelectedFeatures = @(),
[object[]]$UndoFeatures = @(),
[Parameter(Mandatory)]
[datetime]$CreatedAt
)
$selectedFeatureIds = New-Object System.Collections.Generic.List[string]
$seenSelectedFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase)
foreach ($feature in $SelectedFeatures) {
$featureId = [string]$feature.FeatureId
if ($seenSelectedFeatureIds.Add($featureId)) {
$selectedFeatureIds.Add($featureId)
}
}
$selectedUndoFeatureIds = New-Object System.Collections.Generic.List[string]
$seenUndoFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase)
foreach ($feature in $UndoFeatures) {
$featureId = [string]$feature.FeatureId
if ($seenUndoFeatureIds.Add($featureId)) {
$selectedUndoFeatureIds.Add($featureId)
}
}
$selectedRegistryFeatures = @(Get-RegistryBackedFeatures -Features $SelectedFeatures)
$undoRegistryFeatures = @($UndoFeatures | Where-Object {
-not [string]::IsNullOrWhiteSpace([string]$_.RegistryUndoKey) -or -not [string]::IsNullOrWhiteSpace([string]$_.RegistryKey)
})
$capturePlans = @(Get-RegistryBackupCapturePlans -SelectedRegistryFeatures $selectedRegistryFeatures -UndoRegistryFeatures $undoRegistryFeatures)
$registryKeys = @(Get-RegistrySnapshotsForBackup -CapturePlans $capturePlans)
$backupPayload = @{
Version = '1.0'
BackupType = 'RegistryState'
CreatedAt = $CreatedAt.ToString('o')
CreatedBy = 'Win11Debloat'
Target = (Get-RegistryBackupTargetDescription)
ComputerName = $env:COMPUTERNAME
SelectedFeatures = @($selectedFeatureIds)
RegistryKeys = @($registryKeys)
}
if ($selectedUndoFeatureIds.Count -gt 0) {
$backupPayload['SelectedUndoFeatures'] = @($selectedUndoFeatureIds)
}
return $backupPayload
}