win: fix system app removal affecting updates #287
This commit fixes an issue where removing systems apps could disrupt Windows Cumulative updates as reported in #287. The fix involves removing the `EndOfLife` registry key after the app is removed. Keeping the key at `HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\EndOfLife` was identified as the cause for update failures in #287. This commit also refactors the registry key creation/removal logic to be owned by separate functions for easier readability and reusability.
This commit is contained in:
@@ -12003,50 +12003,29 @@ functions:
|
|||||||
recurse: 'true'
|
recurse: 'true'
|
||||||
-
|
-
|
||||||
# -- ❗️ This script must be executed before `UninstallStoreApp` as it enables it for system app removal ---
|
# -- ❗️ This script must be executed before `UninstallStoreApp` as it enables it for system app removal ---
|
||||||
function: RunPowerShell
|
function: CreateRegistryKey
|
||||||
parameters:
|
parameters:
|
||||||
|
codeComment: Enable removal of system app '{{ $packageName }}' by marking it as "EndOfLife"
|
||||||
# This script modifies the system registry to enable the uninstallation of a specified app.
|
# This script modifies the system registry to enable the uninstallation of a specified app.
|
||||||
# Some apps (including system apps) are marked as non-removable, which prevents uninstallation and results in error 0x80070032 if an uninstall is attempted.
|
# Some apps (including system apps) are marked as non-removable, which prevents uninstallation and results in error 0x80070032 if an uninstall is attempted.
|
||||||
# To bypass this, the script marks the app as 'EndOfLife' in the registry, tricking the system into allowing the uninstallation.
|
# To bypass this, the script marks the app as 'EndOfLife' in the registry, tricking the system into allowing the uninstallation
|
||||||
codeComment: Enable removal of system app '{{ $packageName }}' by marking it as "EndOfLife" in the system registry
|
keyName: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\EndOfLife\$CURRENT_USER_SID\{{ $packageName }}_{{ $publisherId }}
|
||||||
code: |-
|
replaceSid: 'true'
|
||||||
$packageName='{{ $packageName }}'
|
|
||||||
$publisherId='{{ $publisherId }}'
|
|
||||||
$packageFamilyName = "$($packageName)_$($publisherId)"
|
|
||||||
$sid = (New-Object System.Security.Principal.NTAccount($env:USERNAME)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
||||||
$path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\EndOfLife\$($sid)\$($packageFamilyName)"
|
|
||||||
if (Test-Path $path) {
|
|
||||||
Write-Host "Skipping, no action needed, path `"$path`" already exists."
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
New-Item -Path $path -Force -ErrorAction Stop | Out-Null
|
|
||||||
Write-Host "Successfully created the registry key at path `"$path`"."
|
|
||||||
} catch {
|
|
||||||
Write-Error "Failed to create the registry key at path `"$path`": $($_.Exception.Message)"
|
|
||||||
}
|
|
||||||
revertCodeComment: Disable removal of system app '{{ $packageName }}' by removing the "EndOfLife" mark from the registry.
|
|
||||||
revertCode: |-
|
|
||||||
$packageName='{{ $packageName }}'
|
|
||||||
$publisherId='{{ $publisherId }}'
|
|
||||||
$packageFamilyName = "$($packageName)_$($publisherId)"
|
|
||||||
$sid = (New-Object System.Security.Principal.NTAccount($env:USERNAME)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
||||||
$path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\EndOfLife\$($sid)\$($packageFamilyName)"
|
|
||||||
if (-not (Test-Path $path)) {
|
|
||||||
Write-Host "Skipping, no action needed, path `"$path`" does not exist."
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Remove-Item -Path $path -Force -ErrorAction Stop | Out-Null
|
|
||||||
Write-Host "Successfully removed the registry key at path `"$path`"."
|
|
||||||
} catch {
|
|
||||||
Write-Error "Failed to remove the registry key at path `"$path`": $($_.Exception.Message)"
|
|
||||||
}
|
|
||||||
-
|
-
|
||||||
function: UninstallStoreApp
|
function: UninstallStoreApp
|
||||||
parameters:
|
parameters:
|
||||||
packageName: '{{ $packageName }}'
|
packageName: '{{ $packageName }}'
|
||||||
publisherId: '{{ $publisherId }}'
|
publisherId: '{{ $publisherId }}'
|
||||||
|
-
|
||||||
|
# -- ❗️ This script must be executed after `UninstallStoreApp` as it disables it for system app removal ---
|
||||||
|
function: DeleteRegistryKey
|
||||||
|
parameters:
|
||||||
|
codeComment: Revert '{{ $packageName }}' to its default, non-removable state.
|
||||||
|
# This script reverses the previous modification made to the Windows registry to enable its uninstallation.
|
||||||
|
# By removing the 'EndOfLife' status from the registry entry, the app is restored to its default, non-removable state.
|
||||||
|
# Restoring (removing) this key is important for maintaining the stability of Windows Updates (for details: https://github.com/undergroundwires/privacy.sexy/issues/287).
|
||||||
|
keyName: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\EndOfLife\$CURRENT_USER_SID\{{ $packageName }}_{{ $publisherId }}
|
||||||
|
replaceSid: 'true'
|
||||||
-
|
-
|
||||||
# Clear: User-specific data
|
# Clear: User-specific data
|
||||||
# - Folder : %LOCALAPPDATA%\Packages\{PackageFamilyName}
|
# - Folder : %LOCALAPPDATA%\Packages\{PackageFamilyName}
|
||||||
@@ -12404,11 +12383,15 @@ functions:
|
|||||||
name: RunPowerShellWithSameCodeAndRevertCode
|
name: RunPowerShellWithSameCodeAndRevertCode
|
||||||
parameters:
|
parameters:
|
||||||
- name: code
|
- name: code
|
||||||
|
- name: codeComment
|
||||||
|
optional: true
|
||||||
call:
|
call:
|
||||||
function: RunPowerShell
|
function: RunPowerShell
|
||||||
parameters:
|
parameters:
|
||||||
code: '{{ $code }}'
|
code: '{{ $code }}'
|
||||||
revertCode: '{{ $code }}'
|
revertCode: '{{ $code }}'
|
||||||
|
codeComment: '{{ with $codeComment }}{{ . }}{{ end }}'
|
||||||
|
revertCodeComment: '{{ with $codeComment }}{{ . }}{{ end }}'
|
||||||
-
|
-
|
||||||
name: RunInlineCodeAsTrustedInstaller
|
name: RunInlineCodeAsTrustedInstaller
|
||||||
parameters:
|
parameters:
|
||||||
@@ -13648,3 +13631,75 @@ functions:
|
|||||||
Write-Output 'Failed to restore some tasks. Check error messages above.'
|
Write-Output 'Failed to restore some tasks. Check error messages above.'
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
-
|
||||||
|
name: CreateRegistryKey
|
||||||
|
parameters:
|
||||||
|
- name: keyName # Full path of the subkey or entry to be added.
|
||||||
|
- name: replaceSid # Replaces "$CURRENT_USER_SID" string in registry key with user SID.
|
||||||
|
optional: true
|
||||||
|
- name: codeComment
|
||||||
|
optional: true
|
||||||
|
- name: revertCodeComment
|
||||||
|
optional: true
|
||||||
|
call:
|
||||||
|
# Marked: refactor-with-variables
|
||||||
|
# Replacing SID is same as `DeleteRegistryKey`
|
||||||
|
function: RunPowerShell
|
||||||
|
parameters:
|
||||||
|
code: |-
|
||||||
|
$keyName='{{ $keyName }}'
|
||||||
|
$replaceSid={{ with $replaceSid }} $true # {{ end }} $false
|
||||||
|
$registryHive = $keyName.Split('\')[0]
|
||||||
|
$registryPath = "$($registryHive):$($keyName.Substring($registryHive.Length))"
|
||||||
|
{{ with $replaceSid }}
|
||||||
|
$userSid = (New-Object System.Security.Principal.NTAccount($env:USERNAME)).Translate([Security.Principal.SecurityIdentifier]).Value
|
||||||
|
$registryPath = $registryPath.Replace('$CURRENT_USER_SID', $userSid)
|
||||||
|
{{ end }}
|
||||||
|
if (Test-Path $registryPath) {
|
||||||
|
Write-Host "Skipping, no action needed, registry path `"$registryPath`" already exists."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
New-Item -Path $registryPath -Force -ErrorAction Stop | Out-Null
|
||||||
|
Write-Host "Successfully created the registry key at path `"$registryPath`"."
|
||||||
|
} catch {
|
||||||
|
Write-Error "Failed to create the registry key at path `"$registryPath`": $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
codeComment: '{{ with $codeComment }}{{ . }}{{ end }}'
|
||||||
|
revertCodeComment: '{{ with $revertCodeComment }}{{ . }}{{ end }}'
|
||||||
|
-
|
||||||
|
name: DeleteRegistryKey
|
||||||
|
parameters:
|
||||||
|
- name: keyName # Full path of the subkey or entry to be added.
|
||||||
|
- name: replaceSid # Replaces "$CURRENT_USER_SID" string in registry key with user SID.
|
||||||
|
optional: true
|
||||||
|
- name: codeComment
|
||||||
|
optional: true
|
||||||
|
- name: revertCodeComment
|
||||||
|
optional: true
|
||||||
|
call:
|
||||||
|
# Marked: refactor-with-variables
|
||||||
|
# Replacing SID is same as `CreateRegistryKey`
|
||||||
|
function: RunPowerShell
|
||||||
|
parameters:
|
||||||
|
code: |-
|
||||||
|
$keyName='{{ $keyName }}'
|
||||||
|
$replaceSid={{ with $replaceSid }} $true # {{ end }} $false
|
||||||
|
$registryHive = $keyName.Split('\')[0]
|
||||||
|
$registryPath = "$($registryHive):$($keyName.Substring($registryHive.Length))"
|
||||||
|
{{ with $replaceSid }}
|
||||||
|
$userSid = (New-Object System.Security.Principal.NTAccount($env:USERNAME)).Translate([Security.Principal.SecurityIdentifier]).Value
|
||||||
|
$registryPath = $registryPath.Replace('$CURRENT_USER_SID', $userSid)
|
||||||
|
{{ end }}
|
||||||
|
if (-not (Test-Path $registryPath)) {
|
||||||
|
Write-Host "Skipping, no action needed, registry path `"$registryPath`" does not exist."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Remove-Item -Path $registryPath -Force -ErrorAction Stop | Out-Null
|
||||||
|
Write-Host "Successfully removed the registry key at path `"$registryPath`"."
|
||||||
|
} catch {
|
||||||
|
Write-Error "Failed to remove the registry key at path `"$registryPath`": $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
codeComment: '{{ with $codeComment }}{{ . }}{{ end }}'
|
||||||
|
revertCodeComment: '{{ with $revertCodeComment }}{{ . }}{{ end }}'
|
||||||
|
|||||||
Reference in New Issue
Block a user