mirror of
https://github.com/Raphire/Win11Debloat.git
synced 2026-08-21 23:26:42 +00:00
148 lines
7.2 KiB
PowerShell
148 lines
7.2 KiB
PowerShell
BeforeAll {
|
|
function Test-RunningAsSystem { $false }
|
|
. (Join-Path $PSScriptRoot '..\Scripts\Helpers\Registry-PathHelpers.ps1')
|
|
. (Join-Path $PSScriptRoot '..\Scripts\Helpers\Get-FriendlyRegistryBackupTarget.ps1')
|
|
. (Join-Path $PSScriptRoot '..\Scripts\Helpers\Resolve-UserProfilePath.ps1')
|
|
. (Join-Path $PSScriptRoot '..\Scripts\Helpers\Test-TargetUserName.ps1')
|
|
. (Join-Path $PSScriptRoot '..\Scripts\Features\Registry-BackupValidation.ps1')
|
|
. (Join-Path $PSScriptRoot '..\Scripts\Features\Restore-RegistryApplyState.ps1')
|
|
. (Join-Path $PSScriptRoot '..\Scripts\Features\Restore-RegistryBackup.ps1')
|
|
$script:JsonFixturePath = Join-Path $PSScriptRoot 'TestData\JsonFileLoading'
|
|
}
|
|
|
|
Describe 'Import-RegistryBackup' {
|
|
It 'loads JSON and passes the parsed backup to normalization' {
|
|
Mock ConvertTo-NormalizedRegistryBackup { [PSCustomObject]@{ Target = 'DefaultUserProfile' } }
|
|
|
|
$result = Import-RegistryBackup -FilePath (Join-Path $script:JsonFixturePath 'RegistryBackup.Valid.json')
|
|
|
|
$result.Target | Should -Be 'DefaultUserProfile'
|
|
Should -Invoke ConvertTo-NormalizedRegistryBackup -Times 1 -Exactly
|
|
}
|
|
|
|
It 'parses and normalizes registry snapshots from a real backup structure' {
|
|
Mock Test-UserNameMatch { $true }
|
|
Mock Test-RegistryBackupMatchesSelectedFeatures { @() }
|
|
|
|
$result = Import-RegistryBackup -FilePath (Join-Path $script:JsonFixturePath 'RegistryBackup.RealStructure.json')
|
|
|
|
$result.Target | Should -Be 'CurrentUser:fixture-user'
|
|
$result.SelectedFeatures | Should -Be @('RemoveApps', 'DisableStickyKeys')
|
|
$result.SelectedUndoFeatures | Should -Be 'DisableTransparency'
|
|
$result.RegistryKeys | Should -HaveCount 2
|
|
$result.RegistryKeys[0].Path | Should -Be 'HKEY_CURRENT_USER\Control Panel\Accessibility\StickyKeys'
|
|
$result.RegistryKeys[0].Values[0].Name | Should -Be 'Flags'
|
|
$result.RegistryKeys[0].Values[0].Kind | Should -Be 'String'
|
|
$result.RegistryKeys[0].Values[0].Data | Should -Be '510'
|
|
$result.RegistryKeys[1].Path | Should -Be 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize'
|
|
$result.RegistryKeys[1].Values[0].Name | Should -Be 'EnableTransparency'
|
|
$result.RegistryKeys[1].Values[0].Kind | Should -Be 'DWord'
|
|
$result.RegistryKeys[1].Values[0].Data | Should -Be 0
|
|
Should -Invoke Test-RegistryBackupMatchesSelectedFeatures -Times 1 -Exactly
|
|
}
|
|
|
|
It 'rejects <Case>' -ForEach @(
|
|
@{ Case = 'a missing backup file'; FileName = 'missing.json'; ExpectedError = 'Backup file was not found:*' }
|
|
@{ Case = 'an invalid JSON backup file'; FileName = 'RegistryBackup.Invalid.json'; ExpectedError = $null }
|
|
) {
|
|
$path = Join-Path $script:JsonFixturePath $FileName
|
|
$errorPattern = if ($null -ne $ExpectedError) { $ExpectedError } else { "Failed to read backup file '$path'. The file is not valid JSON." }
|
|
|
|
{ Import-RegistryBackup -FilePath $path } | Should -Throw $errorPattern
|
|
}
|
|
}
|
|
|
|
Describe 'ConvertTo-NormalizedRegistryBackup' {
|
|
BeforeEach {
|
|
$script:Features = @{ Example = [PSCustomObject]@{ FeatureId = 'Example'; RegistryKey = 'Example.reg' } }
|
|
Mock Test-RegistryBackupMatchesSelectedFeatures { @() }
|
|
Mock Write-Error {}
|
|
}
|
|
|
|
It 'normalizes a valid legacy backup without undo selections' {
|
|
$backup = [PSCustomObject]@{
|
|
Version = '1.0'; BackupType = 'RegistryState'; Target = 'DefaultUserProfile'
|
|
CreatedAt = '2026-01-01T00:00:00.0000000Z'; CreatedBy = 'Win11Debloat'; ComputerName = 'PC'
|
|
SelectedFeatures = @('Example', 'example'); RegistryKeys = @()
|
|
}
|
|
|
|
$result = ConvertTo-NormalizedRegistryBackup -Backup $backup
|
|
|
|
$result.Target | Should -Be 'DefaultUserProfile'
|
|
$result.SelectedFeatures -is [array] | Should -BeTrue
|
|
$result.SelectedFeatures | Should -Be 'Example'
|
|
$result.SelectedUndoFeatures | Should -BeNullOrEmpty
|
|
Should -Invoke Test-RegistryBackupMatchesSelectedFeatures -Times 1 -Exactly
|
|
}
|
|
|
|
It 'aggregates invalid metadata and does not attempt allow-list validation without feature IDs' {
|
|
$backup = [PSCustomObject]@{ Version = '2.0'; BackupType = 'Other'; Target = 'Unknown'; RegistryKeys = @() }
|
|
|
|
{ ConvertTo-NormalizedRegistryBackup -Backup $backup } | Should -Throw 'Validation failed with * errors. See console output for details.'
|
|
|
|
Should -Invoke Write-Error -Times 1 -Exactly
|
|
Should -Invoke Test-RegistryBackupMatchesSelectedFeatures -Times 0 -Exactly
|
|
}
|
|
|
|
It 'reports an invalid user target as a validation failure' {
|
|
Mock Test-TargetUserName { [PSCustomObject]@{ IsValid = $false } }
|
|
$backup = [PSCustomObject]@{
|
|
Version = '1.0'; BackupType = 'RegistryState'; Target = 'User:bad/user'
|
|
SelectedFeatures = @('Example'); RegistryKeys = @()
|
|
}
|
|
|
|
{ ConvertTo-NormalizedRegistryBackup -Backup $backup } | Should -Throw "Validation failed: Invalid user 'User:bad/user'"
|
|
}
|
|
|
|
It 'does not allow current-user backup restore when running as SYSTEM' {
|
|
Mock Test-RunningAsSystem { $true }
|
|
$backup = [PSCustomObject]@{
|
|
Version = '1.0'; BackupType = 'RegistryState'; Target = 'CurrentUser:Alice'
|
|
SelectedFeatures = @('Example'); RegistryKeys = @()
|
|
}
|
|
|
|
{ ConvertTo-NormalizedRegistryBackup -Backup $backup } |
|
|
Should -Throw "Validation failed: Backup was made for 'Alice' and is user-scoped*"
|
|
}
|
|
}
|
|
|
|
Describe 'Restore-RegistryBackupState' {
|
|
BeforeEach {
|
|
$script:Params = @{}
|
|
Mock Get-FriendlyRegistryBackupTarget { 'friendly target' }
|
|
Mock Restore-RegistryKeySnapshot {}
|
|
Mock Invoke-WithLoadedRestoreHive {}
|
|
Mock Write-Host {}
|
|
$script:backup = [PSCustomObject]@{ Target = 'CurrentUser:Tester'; RegistryKeys = @([PSCustomObject]@{ Path = 'HKEY_CURRENT_USER\Software\One' }, [PSCustomObject]@{ Path = 'HKEY_CURRENT_USER\Software\Two' }) }
|
|
}
|
|
|
|
It 'restores every root snapshot directly for the current user' {
|
|
(Restore-RegistryBackupState -Backup $script:backup).Result | Should -BeTrue
|
|
|
|
Should -Invoke Restore-RegistryKeySnapshot -Times 2 -Exactly
|
|
Should -Invoke Invoke-WithLoadedRestoreHive -Times 0 -Exactly
|
|
}
|
|
|
|
It 'delegates default-profile restores through the loaded hive wrapper' {
|
|
$script:backup.Target = 'DefaultUserProfile'
|
|
Mock Invoke-WithLoadedRestoreHive {
|
|
param($Target, $ScriptBlock, $ArgumentObject)
|
|
& $ScriptBlock $ArgumentObject
|
|
}
|
|
|
|
(Restore-RegistryBackupState -Backup $script:backup).Result | Should -BeTrue
|
|
|
|
Should -Invoke Invoke-WithLoadedRestoreHive -Times 1 -Exactly -ParameterFilter { $Target -eq 'DefaultUserProfile' }
|
|
Should -Invoke Restore-RegistryKeySnapshot -Times 2 -Exactly
|
|
}
|
|
|
|
It 'honors WhatIf without restoring snapshots or loading a hive' {
|
|
$script:Params = @{ WhatIf = $true }
|
|
|
|
(Restore-RegistryBackupState -Backup $script:backup).Result | Should -BeTrue
|
|
|
|
Should -Invoke Restore-RegistryKeySnapshot -Times 0 -Exactly
|
|
Should -Invoke Invoke-WithLoadedRestoreHive -Times 0 -Exactly
|
|
}
|
|
}
|