Set NoRemove NoModify NoRepair in Add Remove Programs

Even wanted to hide the [Remove] button in Programs and Features?
Or hide the [Modify] or the [Repair] buttons?

This is the function for you.

Just place it in AppDeployToolkitExtensions.ps1 file after:
# <Your custom functions go here>

#region Function Set-ARPNoRemoveNoModifyNoRepair
Function Set-ARPNoRemoveNoModifyNoRepair {
<#
.SYNOPSIS
	Sets NoRemove/NoModify/NoRepair values for ARP entry
.DESCRIPTION
	Sets NoRemove/NoModify/NoRepair values for ARP entry based on the name of the Key in the registry
	Auto-detects if key exists in 32bit or 64bit Registry ARP
	Not meant for MSIs. (Use MSI properties instead)
	NOTE: ARP = Add/Remove Programs = Programs and Features = Apps & Features
.PARAMETER ArpKeyName
	Name of Registry key (*NOT* full registry path) that we want to affect (Defaults to $InstallName)
.PARAMETER Action
	Set to ONE of the following: NoRemove NoModify NoRepair AllowRemove AllowModify AllowRepair
	CAVEAT: *CaSe SenSiTive*
.PARAMETER DeleteAction
	Controls HOW the value is removed
	set to ONE of the following: DeleteValue SetValueToZero
	Defaults to DeleteValue
.EXAMPLE
	Set-ARPNoRemoveNoModifyNoRepair -ArpKeyName "Notepad++" -Action NoRemove
	Hides [Remove] button in ARP by creating/setting the NoRemove value 1
.EXAMPLE
	Set-ARPNoRemoveNoModifyNoRepair -ArpKeyName "Notepad++" -Action AllowRemove 
	Deletes the NoRemove value to enable [Remove] button in ARP
.EXAMPLE
	Set-ARPNoRemoveNoModifyNoRepair -ArpKeyName "Notepad++" -Action AllowRemove -DeleteAction 'SetValueToZero' 
	Same as above but Sets the NoRemove value to '0' instead of deleting the NoRemove value
.EXAMPLE
	Set-ARPNoRemoveNoModifyNoRepair -Action NoRemove 	
	Hides [Remove] or [Uninstall] button in ARP for $InstallName
.EXAMPLE
	Set-ARPNoRemoveNoModifyNoRepair -ArpKeyName 'ProPlus2019Volume - en-us' -Action NoRemove
	Set-ARPNoRemoveNoModifyNoRepair -ArpKeyName 'ProPlus2019Volume - en-us' -Action AllowRemove
	Set-ARPNoRemoveNoModifyNoRepair -ArpKeyName 'ProPlus2019Volume - en-us' -Action AllowRemove -DeleteAction SetValueToZero
.NOTES

	-Tested on Windows 10 and Windows 7
#>
	[CmdletBinding()]
	Param (
	    [Parameter(Mandatory=$true,HelpMessage="Name of Registry key (Not full path)")]
		[string]$ArpKeyName,
		[Parameter(Mandatory=$true,HelpMessage="Set to ONE of the following: NoRemove NoModify NoRepair AllowRemove AllowModify AllowRepair")]
		[ValidateNotNullorEmpty()]
		[ValidateSet('NoRemove','NoModify','NoRepair','AllowRemove','AllowModify','AllowRepair',IgnoreCase = $false)]
		[string]$Action = "",
		[Parameter(Mandatory=$false,HelpMessage="Set to ONE of the following: DeleteValue SetValueToZero. DeleteValue is the default" )]
		[ValidateNotNullorEmpty()]
		[ValidateSet('DeleteValue','SetValueToZero')]
		[string]$DeleteAction = "DeleteValue"		
	)
	Begin {
        ## Get the name of this function and write header
        [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
    }
	
	Process {
		Try {
			[string]$HKLMUninstallKey64 = "HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$ArpKeyName"
			[string]$HKLMUninstallKey32 = "HKLM:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$ArpKeyName"

			#Where is the ARP key? 32 or 64 bit?
			If (Test-Path -LiteralPath $HKLMUninstallKey32) {
				If ($Action -like "No*") {
					Write-Log " Setting [$Action] for ARP entry [$ArpKeyName] Exists as a 32bit ARP entry" -Source ${CmdletName}
					Set-RegistryKey -Key $HKLMUninstallKey32 -Name $Action -Value 1 -Type DWORD
				} ElseIf ($Action -like "Allow*") {
					[String]$ActualValueName=$Action.replace("Allow","No")
					If ($DeleteAction -eq 'DeleteValue'){
						Write-Log " Deleting [$ActualValueName] for ARP entry [$ArpKeyName] Exists as a 32bit ARP entry" -Source ${CmdletName}
						Remove-RegistryKey -Key $HKLMUninstallKey32 -Name $ActualValueName
					} ElseIf ($DeleteAction -eq 'SetValueToZero'){
						Write-Log " Setting Value [$ActualValueName] to 0 for ARP entry [$ArpKeyName] Exists as a 32bit ARP entry" -Source ${CmdletName}
						Set-RegistryKey -Key $HKLMUninstallKey32 -Name $ActualValueName -Value 0 -Type DWORD
					} Else {
					Write-Log "`$DeleteAction = [$DeleteAction] is not handled by this function" -Source ${CmdletName} -Severity 2
					}
				} Else {
					Write-Log "`$Action = [$Action] is not handled by this function" -Source ${CmdletName} -Severity 2
				}
			} Else {
				Write-Log " [$ArpKeyName] is NOT a 32bit ARP entry" -Source ${CmdletName}
			}

			If (Test-Path -LiteralPath $HKLMUninstallKey64) {
				If ($Action -like "No*") {
					Write-Log " Setting [$Action] for ARP entry [$ArpKeyName] Exists as a 64bit ARP entry" -Source ${CmdletName}
					Set-RegistryKey -Key $HKLMUninstallKey64 -Name $Action -Value 1 -Type DWORD
				} ElseIf ($Action -like "Allow*") {
					[String]$ActualValueName=$Action.replace("Allow","No")
					If ($DeleteAction -eq 'DeleteValue'){
						Write-Log " Deleting [$ActualValueName] for ARP entry [$ArpKeyName] Exists as a 64bit ARP entry" -Source ${CmdletName}
						Remove-RegistryKey -Key $HKLMUninstallKey64 -Name $ActualValueName
					} ElseIf ($DeleteAction -eq 'SetValueToZero'){
						Write-Log " Setting Value [$ActualValueName] to 0 for ARP entry [$ArpKeyName] Exists as a 64bit ARP entry" -Source ${CmdletName}
						Set-RegistryKey -Key $HKLMUninstallKey64 -Name $ActualValueName -Value 0 -Type DWORD
					} Else {
						Write-Log "`$DeleteAction = [$DeleteAction] is not handled by this function" -Source ${CmdletName} -Severity 2
					}
				} Else {
					Write-Log " [$Action] is not handled by this function" -Source ${CmdletName} -Severity 2
				}
			} Else {
				Write-Log " [$ArpKeyName] is NOT a 64bit ARP entry " -Source ${CmdletName}
			}
		} Catch {
			Write-Log -Message "Failed to edit ARP Entry. `r`n$(Resolve-Error)" -Severity 3 -Source ${CmdletName}
		}
	}
    End {
        Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -Footer
    }	
}
#endregion Function Set-ARPNoRemoveNoModifyNoRepair
2 Likes

Can I just copy and paste this into AppDeployToolkitExtensions.ps1 under # or do I need to go into the script and modify some fields to get it to work?

Just place it after this line:

# <Your custom functions go here>

If you have other custom functions, the order does not matter.
You are only declaring functions.
They do not run until you call them.