mirror of
https://github.com/NexusOne23/noid-privacy.git
synced 2026-02-07 12:11:53 +01:00
231 lines
11 KiB
PowerShell
231 lines
11 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Restore registry policies from backup
|
|
|
|
.DESCRIPTION
|
|
Restores all registry keys/values from a backup JSON file.
|
|
Handles non-existent keys/values correctly.
|
|
|
|
.PARAMETER BackupPath
|
|
Path to backup JSON file created by Backup-RegistryPolicies
|
|
|
|
.OUTPUTS
|
|
PSCustomObject with restore status
|
|
|
|
.NOTES
|
|
Restores ORIGINAL values including deletions if keys didn't exist before
|
|
#>
|
|
|
|
function Restore-RegistryPolicies {
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$BackupPath
|
|
)
|
|
|
|
$result = [PSCustomObject]@{
|
|
Success = $false
|
|
ItemsRestored = 0
|
|
Errors = @()
|
|
}
|
|
|
|
if (-not (Test-Path $BackupPath)) {
|
|
$result.Errors += "Backup file not found: $BackupPath"
|
|
return $result
|
|
}
|
|
|
|
try {
|
|
Write-Log -Level DEBUG -Message "Loading backup from: $BackupPath" -Module "SecurityBaseline"
|
|
$backup = Get-Content -Path $BackupPath -Raw | ConvertFrom-Json
|
|
|
|
# Restore Computer policies (HKLM)
|
|
if ($backup.Computer) {
|
|
Write-Log -Level DEBUG -Message "Restoring $($backup.Computer.Count) Computer registry values..." -Module "SecurityBaseline"
|
|
|
|
foreach ($item in $backup.Computer) {
|
|
try {
|
|
# Parse key path
|
|
$keyPath = $item.KeyName -replace '^\[', '' -replace '\]$', ''
|
|
|
|
if ($keyPath -match '^(SOFTWARE|SYSTEM)\\') {
|
|
$fullPath = "HKLM:\$keyPath"
|
|
}
|
|
else {
|
|
continue
|
|
}
|
|
|
|
# Handle restoration based on original state
|
|
# CRITICAL FIX: **del* values are GPO DELETE markers - they should NOT be restored!
|
|
# These markers instruct GPO to delete a value. If we restore them, verification fails
|
|
# because verification expects these values to be DELETED (not present).
|
|
if ($item.ValueName -like "**del*" -or $item.ValueName -like "**delvals*") {
|
|
# DELETE marker - ensure value is deleted (not restored)
|
|
if (Test-Path $fullPath) {
|
|
try {
|
|
Remove-ItemProperty -Path $fullPath -Name $item.ValueName -ErrorAction SilentlyContinue
|
|
Write-Log -Level DEBUG -Message "Removed DELETE marker: $fullPath\$($item.ValueName)" -Module "SecurityBaseline"
|
|
}
|
|
catch { $null = $null }
|
|
}
|
|
}
|
|
elseif ($item.Exists -eq $false) {
|
|
# Item didn't exist before - delete it
|
|
if (Test-Path $fullPath) {
|
|
try {
|
|
Remove-ItemProperty -Path $fullPath -Name $item.ValueName -ErrorAction Stop
|
|
Write-Log -Level DEBUG -Message "Removed: $fullPath\$($item.ValueName)" -Module "SecurityBaseline"
|
|
}
|
|
catch {
|
|
# Value doesn't exist anymore - that's fine
|
|
$null = $null
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
# Item existed - restore original value
|
|
if (-not (Test-Path $fullPath)) {
|
|
New-Item -Path $fullPath -Force | Out-Null
|
|
}
|
|
|
|
# Convert type
|
|
$regType = switch ($item.Type) {
|
|
"REG_DWORD" { "DWord" }
|
|
"REG_SZ" { "String" }
|
|
"REG_EXPAND_SZ" { "ExpandString" }
|
|
"REG_BINARY" { "Binary" }
|
|
"REG_MULTI_SZ" { "MultiString" }
|
|
default { "String" }
|
|
}
|
|
|
|
# Restore value (create or update with correct type)
|
|
$existingValue = Get-ItemProperty -Path $fullPath -Name $item.ValueName -ErrorAction SilentlyContinue
|
|
|
|
if ($null -ne $existingValue) {
|
|
# Value exists - update it
|
|
Set-ItemProperty -Path $fullPath `
|
|
-Name $item.ValueName `
|
|
-Value $item.OriginalValue `
|
|
-Force `
|
|
-ErrorAction Stop
|
|
}
|
|
else {
|
|
# Value does not exist - create it with proper type
|
|
New-ItemProperty -Path $fullPath `
|
|
-Name $item.ValueName `
|
|
-Value $item.OriginalValue `
|
|
-PropertyType $regType `
|
|
-Force `
|
|
-ErrorAction Stop | Out-Null
|
|
}
|
|
|
|
Write-Log -Level DEBUG -Message "Restored: $fullPath\$($item.ValueName) = $($item.OriginalValue)" -Module "SecurityBaseline"
|
|
}
|
|
|
|
$result.ItemsRestored++
|
|
}
|
|
catch {
|
|
$result.Errors += "Failed to restore $($item.KeyName)\$($item.ValueName): $_"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Restore User policies (HKCU)
|
|
if ($backup.User) {
|
|
Write-Log -Level DEBUG -Message "Restoring $($backup.User.Count) User registry values..." -Module "SecurityBaseline"
|
|
|
|
foreach ($item in $backup.User) {
|
|
try {
|
|
# Parse key path
|
|
$keyPath = $item.KeyName -replace '^\[', '' -replace '\]$', ''
|
|
|
|
if ($keyPath -match '^SOFTWARE\\') {
|
|
$fullPath = "HKCU:\$keyPath"
|
|
}
|
|
else {
|
|
continue
|
|
}
|
|
|
|
# Handle restoration based on original state
|
|
# CRITICAL FIX: **del* values are GPO DELETE markers - they should NOT be restored!
|
|
if ($item.ValueName -like "**del*" -or $item.ValueName -like "**delvals*") {
|
|
# DELETE marker - ensure value is deleted (not restored)
|
|
if (Test-Path $fullPath) {
|
|
try {
|
|
Remove-ItemProperty -Path $fullPath -Name $item.ValueName -ErrorAction SilentlyContinue
|
|
Write-Log -Level DEBUG -Message "Removed DELETE marker: $fullPath\$($item.ValueName)" -Module "SecurityBaseline"
|
|
}
|
|
catch { $null = $null }
|
|
}
|
|
}
|
|
elseif ($item.Exists -eq $false) {
|
|
# Item didn't exist before - delete it
|
|
if (Test-Path $fullPath) {
|
|
try {
|
|
Remove-ItemProperty -Path $fullPath -Name $item.ValueName -ErrorAction Stop
|
|
Write-Log -Level DEBUG -Message "Removed: $fullPath\$($item.ValueName)" -Module "SecurityBaseline"
|
|
}
|
|
catch {
|
|
# Value doesn't exist anymore - that's fine
|
|
$null = $null
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
# Item existed - restore original value
|
|
if (-not (Test-Path $fullPath)) {
|
|
New-Item -Path $fullPath -Force | Out-Null
|
|
}
|
|
|
|
# Convert type
|
|
$regType = switch ($item.Type) {
|
|
"REG_DWORD" { "DWord" }
|
|
"REG_SZ" { "String" }
|
|
"REG_EXPAND_SZ" { "ExpandString" }
|
|
"REG_BINARY" { "Binary" }
|
|
"REG_MULTI_SZ" { "MultiString" }
|
|
default { "String" }
|
|
}
|
|
|
|
# Restore value (create or update with correct type)
|
|
$existingValue = Get-ItemProperty -Path $fullPath -Name $item.ValueName -ErrorAction SilentlyContinue
|
|
|
|
if ($null -ne $existingValue) {
|
|
# Value exists - update it
|
|
Set-ItemProperty -Path $fullPath `
|
|
-Name $item.ValueName `
|
|
-Value $item.OriginalValue `
|
|
-Force `
|
|
-ErrorAction Stop
|
|
}
|
|
else {
|
|
# Value does not exist - create it with proper type
|
|
New-ItemProperty -Path $fullPath `
|
|
-Name $item.ValueName `
|
|
-Value $item.OriginalValue `
|
|
-PropertyType $regType `
|
|
-Force `
|
|
-ErrorAction Stop | Out-Null
|
|
}
|
|
|
|
Write-Log -Level DEBUG -Message "Restored: $fullPath\$($item.ValueName) = $($item.OriginalValue)" -Module "SecurityBaseline"
|
|
}
|
|
|
|
$result.ItemsRestored++
|
|
}
|
|
catch {
|
|
$result.Errors += "Failed to restore User $($item.KeyName)\$($item.ValueName): $_"
|
|
}
|
|
}
|
|
}
|
|
|
|
$result.Success = ($result.Errors.Count -eq 0)
|
|
Write-Log -Level DEBUG -Message "Registry restore complete: $($result.ItemsRestored) items restored" -Module "SecurityBaseline"
|
|
|
|
}
|
|
catch {
|
|
$result.Errors += "Registry restore failed: $_"
|
|
Write-Error "Registry restore failed: $_"
|
|
}
|
|
|
|
return $result
|
|
}
|