Public/Remove-MSIXVirtualRegistryKey.ps1
|
function Remove-MSIXVirtualRegistryKey { <# .SYNOPSIS Removes a key from an MSIX registry hive file (Registry.dat / User.dat). .DESCRIPTION Loads the hive file given by -HiveFilePath with RegLoadAppKey and deletes -KeyPath (relative to the hive root: 'REGISTRY\MACHINE\SOFTWARE\...' in Registry.dat, 'Software\...' in User.dat whose root is HKCU). Without -Recurse only a key without subkeys can be removed (RegDeleteKeyEx); with -Recurse the key and all its subkeys are deleted (RegDeleteTree). A missing key is not an error - the call is idempotent. .EXAMPLE Remove-MSIXVirtualRegistryKey -HiveFilePath "$pkg\Registry.dat" -KeyPath 'REGISTRY\MACHINE\SOFTWARE\Microsoft\.NETFramework' -Recurse .NOTES RegLoadAppKey works on the hive file directly (no reg load). The keys in package hives usually allow writing only from an elevated PowerShell; reading - and a removal with nothing to remove - works without. https://www.nick-it.de Andreas Nick, 2024 #> [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory = $true)] [string]$HiveFilePath, [Parameter(Mandatory = $true)] [string]$KeyPath, [switch]$Recurse ) # Check read-only first: a missing key needs no write access, so the idempotent case also works # without elevation (package hives usually allow writing only from an elevated PowerShell). $hKey = [IntPtr]::Zero $result = [Win32Apis]::RegLoadAppKey($HiveFilePath, [ref]$hKey, 0x20019, 0, 0) # KEY_READ if ($result -ne 0) { throw "Failed to load hive '$HiveFilePath' (Win32 error $(Format-MSIXWin32Error $result))." } try { $subKeyHandle = [IntPtr]::Zero $result = [Win32Apis]::RegOpenKeyEx($hKey, $KeyPath, 0, 0x20019, [ref]$subKeyHandle) if ($result -eq 0) { $null = [Win32Apis]::RegCloseKey($subKeyHandle) } } finally { $null = [Win32Apis]::RegCloseKey($hKey) } if ($result -eq 2) { Write-Verbose "Key '$KeyPath' not present in '$HiveFilePath' - nothing to remove." return } if (-not $PSCmdlet.ShouldProcess("$HiveFilePath : $KeyPath", 'Remove key')) { return } $hKey = [IntPtr]::Zero $result = [Win32Apis]::RegLoadAppKey($HiveFilePath, [ref]$hKey, 0xF003F, 0, 0) # KEY_ALL_ACCESS if ($result -ne 0) { $hint = '' if ($result -eq 5) { $hint = ' Writing to package hives usually requires an elevated PowerShell.' } throw "Failed to load hive '$HiveFilePath' (Win32 error $(Format-MSIXWin32Error $result)).$hint" } try { if ($Recurse) { $result = [Win32Apis]::RegDeleteTree($hKey, $KeyPath) } else { # samDesired only selects the WOW64 view (KEY_WOW64_32KEY/64KEY) - not used for app hives. $result = [Win32Apis]::RegDeleteKeyEx($hKey, $KeyPath, 0, 0) } if ($result -eq 2) { Write-Verbose "Key '$KeyPath' not present in '$HiveFilePath' - nothing to remove." } elseif ($result -ne 0) { $hint = '' if ($result -eq 5 -and -not $Recurse) { $hint = ' Use -Recurse if the key has subkeys.' } throw "Failed to delete key '$KeyPath' in hive '$HiveFilePath' (Win32 error $(Format-MSIXWin32Error $result)).$hint" } else { Write-Verbose "Removed key '$KeyPath' from '$HiveFilePath'." } } finally { $null = [Win32Apis]::RegCloseKey($hKey) } } |