Remove PUA
Summary
This script manages the removal of predefined bloatware packages or lists installed bloatware based on a centrally maintained list. It offers three primary operations: bulk removal, selective removal, and bloatware listing. The remove parameter allows bypassing the PUA List to remove any installed AppxPackage.
PUA List: https://content.provaltech.com/attachments/potentially-unwanted-applications.json
Sample Run

To get the list of installed Bloatware:

To remove all installed Bloatware installed on the computer from the PUA List:

To remove all installed Bloatware except any of WindowsStoreApps category apps and Microsoft.BingNews, and Microsoft.MSPaint:

To remove individual AppxPackages installed on the machine like Microsoft.MicrosoftOfficeHub, Microsoft.XboxApp, Microsoft.Messaging, and Microsoft.People:


Dependencies
User Parameters
| Name | Example | Required | Type | Description |
|---|---|---|---|---|
| ListBloatware | Yes | False | Flag | Select Yes to list installed bloatwares without making changes. |
| Remove | Microsoft.MicrosoftOfficeHub,Microsoft.XboxApp | False | Text | Specify name(s) of the bloatwares to uninstall. |
| RemoveAll | Yes | False | Flag | Set it to Yes to remove all bloatware by category or all found bloatware with or without exceptions |
| Category | XboxFeaturesApps | False | Text | Used with RemoveAll to filter bloatware to a certain category, allowing you to select just a specific category of bloatware. Accepted Values includes - MsftBloatApps - ThirdPartyBloatApps - WindowsStoreApps - XboxFeaturesApps - NonAppxApps |
| Except | xboxGameOverlay | False | Text | Used with RemoveAll or Category to remove all except some item(s) from a category or all together |
Implementation
Script Details
Step 1
Navigate to Automation ➞ Tasks

Step 2
Create a new Script Editor style task by choosing the Script Editor option from the Add dropdown menu
The New Script page will appear on clicking the Script Editor button:

Step 3
Fill in the following details in the Description section:
Name: Remove - PUA
Description:
This script manages the removal of predefined bloatware packages or lists installed bloatware based on a centrally maintained list. It offers three primary operations: bulk removal, selective removal, and bloatware listing. The remove parameter allows bypassing the PUA List to remove any installed AppxPackage.
PUA List: https://content.provaltech.com/attachments/potentially-unwanted-applications.json
Category: Application

Parameters
ListBloatware
Add a new parameter by clicking the Add Parameter button present at the top-right corner of the screen.
This screen will appear.

- Set
ListBloatwarein theParameter Namefield. - Select
Flagfrom theParameter Typedropdown menu. - Click the
Savebutton.

Remove
Add a new parameter by clicking the Add Parameter button present at the top-right corner of the screen.
This screen will appear.

- Set
Removein theParameter Namefield. - Select
Text Stringfrom theParameter Typedropdown menu. - Click the
Savebutton.

RemoveAll
Add a new parameter by clicking the Add Parameter button present at the top-right corner of the screen.
This screen will appear.

- Set
RemoveAllin theParameter Namefield. - Select
Flagfrom theParameter Typedropdown menu. - Click the
Savebutton.

Category
Add a new parameter by clicking the Add Parameter button present at the top-right corner of the screen.
This screen will appear.

- Set
Categoryin theParameter Namefield. - Select
Text Stringfrom theParameter Typedropdown menu. - Click the
Savebutton.

Except
Add a new parameter by clicking the Add Parameter button present at the top-right corner of the screen.
This screen will appear.

- Set
Exceptin theParameter Namefield. - Select
Text Stringfrom theParameter Typedropdown menu. - Click the
Savebutton.

Script Editor
Click the Add Row button in the Script Editor section to start creating the script
A blank function will appear.
Row 1: Function: PowerShell Script
Search and select the PowerShell Script function.
The following function will pop up on the screen:
Paste in the following PowerShell script and set the Expected time of script execution in seconds to 3600 seconds. Click the Save button.
<#
.SYNOPSIS
Wrapper script that prepares parameters, downloads, and runs the Remove-PUA automation script.
.DESCRIPTION
This script is an automation wrapper for Remove-PUA operations.
It reads runtime placeholders from an RMM tool, validates and normalizes user input,
builds the correct parameter set, prepares a local working directory, ensures TLS support,
downloads the latest Remove-PUA script from the content repository, executes it with the
selected parameters, and validates generated logs.
Main workflow blocks:
1. Globals and user parameters:
Reads placeholders such as ListBloatware, Remove, RemoveAll, Category, and Except,
then converts them into boolean/array values as needed.
2. Parameter hash table:
Creates one valid parameter set for the downstream script and rejects invalid input.
3. Variables and working directory setup:
Builds file paths under ProgramData and creates the working folder if needed.
4. Permissions:
Ensures the working directory has an Everyone FullControl ACL rule for automation access.
5. TLS policy:
Forces TLS 1.2/1.3 where available so secure download calls can succeed.
6. Script download and execution:
Downloads Remove-PUA.ps1 from the repository and runs it with splatted parameters.
7. Log verification:
Confirms expected log output exists and throws with error log content when failures are detected.
#>
#region globals
$ProgressPreference = 'SilentlyContinue'
$WarningPreference = 'SilentlyContinue'
#endRegion
#region user parameters
$ListBloatware = '@ListBloatware@'
$Remove = '@Remove@'
$RemoveAll = '@RemoveAll@'
$Category = '@Category@'
$Except = '@Except@'
if ($ListBloatware -match '1|True|Yes') {
$ListBloatware = $true
} else {
$ListBloatware = $false
}
if ($Remove -and $Remove -notmatch 'Remove' -and $Remove -match '[A-z]') {
$Remove = $Remove -replace ', ', ',' -replace ' ,', ','
$Remove = $Remove.Trim()
$Remove = $Remove.Split(',')
} else {
$Remove =$false
}
if ($RemoveAll -match '1|True|Yes') {
$RemoveAll = $true
} else {
$RemoveAll = $false
}
if ($RemoveAll -and $Category -and $Category -notmatch 'Category' -and $Category -match '[A-z]') {
if (!(('MsftBloatApps', 'ThirdPartyBloatApps') -contains $Category)) {
throw 'Invalid category. Supported categories are: MsftBloatApps, and ThirdPartyBloatApps'
} else {
$Category = $Category
}
} else {
$Category = $false
}
if ($RemoveAll -and $Except -and $Except -notmatch 'Except' -and $Except -match '[A-z]') {
$Except = $Except -replace ', ', ',' -replace ' ,', ','
$Except = $Except.Trim()
$Except = $Except.Split(',')
} else {
$Except = $false
}
#endregion
#region parameters hash table
$Parameters = @{}
if ( $ListBloatware ) {
$Parameters.Add('ListBloatware', $true)
} elseif ( $Remove ) {
$Parameters.Add('Remove', $Remove)
} elseif ( $RemoveAll ) {
$Parameters.Add('RemoveAll', $true)
if ( $Category ) {
$Parameters.Add('Category', $Category)
}
if ( $Except ) {
$Parameters.Add('Except', $Except)
}
} else {
throw 'Invalid parameter set.'
}
#endregion
#region variables
$projectName = 'Remove-PUA'
$workingDirectory = '{0}\_Automation\Script\{1}' -f $env:ProgramData, $projectName
$scriptPath = '{0}\{1}.ps1' -f $workingDirectory, $projectName
$logPath = '{0}\{1}-log.txt' -f $workingDirectory, $projectName
$errorLogPath = '{0}\{1}-error.txt' -f $workingDirectory, $projectName
$baseUrl = 'https://contentrepo.net/repo'
$scriptUrl = '{0}/script/{1}.ps1' -f $baseUrl, $projectName
#endRegion
#region working Directory
if (!(Test-Path -Path $workingDirectory)) {
try {
New-Item -Path $workingDirectory -ItemType Directory -Force -ErrorAction Stop | Out-Null
} catch {
throw ('Failed to Create working directory {0}. Reason: {1}' -f $workingDirectory, $($Error[0].Exception.Message))
}
}
$acl = Get-Acl -Path $workingDirectory
$hasFullControl = $acl.Access | Where-Object {
$_.IdentityReference -match 'Everyone' -and $_.FileSystemRights -match 'FullControl'
}
if (-not $hasFullControl) {
$accessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule(
'Everyone', 'FullControl', 'ContainerInherit, ObjectInherit', 'None', 'Allow'
)
$acl.AddAccessRule($accessRule)
Set-Acl -Path $workingDirectory -AclObject $acl -ErrorAction SilentlyContinue
}
#endRegion
#region set tls policy
$supportedTLSversions = [enum]::GetValues('Net.SecurityProtocolType')
if (($supportedTLSversions -contains 'Tls13') -and ($supportedTLSversions -contains 'Tls12')) {
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol::Tls13 -bor [System.Net.SecurityProtocolType]::Tls12
} elseif ($supportedTLSversions -contains 'Tls12') {
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
} else {
Write-Information 'TLS 1.2 and/or TLS 1.3 are not supported on this system. This download may fail!' -InformationAction Continue
if ($PSVersionTable.PSVersion.Major -lt 3) {
Write-Information 'PowerShell 2 / .NET 2.0 doesn''t support TLS 1.2.' -InformationAction Continue
}
}
#endRegion
#region download script
try {
Invoke-WebRequest -Uri $scriptUrl -OutFile $scriptPath -UseBasicParsing -ErrorAction Stop
} catch {
if (!(Test-Path -Path $scriptPath)) {
throw ('Failed to download the script from ''{0}'', and no local copy of the script exists on the machine. Reason: {1}' -f $scriptUrl, $($Error[0].Exception.Message))
}
}
#endRegion
#region execute script
if ($parameters) {
& $scriptPath @parameters
} else {
& $scriptPath
}
#endRegion
#region log verification
if (!(Test-Path -Path $logPath )) {
throw ('Failed to run the agnostic script ''{0}''. A security application seems to have interrupted the script.' -f $scriptPath)
} else {
$content = Get-Content -Path $logPath
$logContent = $content[ $($($content.IndexOf($($content -match "$($projectName)$")[-1])) + 1)..$($content.length - 1) ]
Write-Information ('Log Content: {0}' -f ($logContent | Out-String)) -InformationAction Continue
}
if ((Test-Path -Path $errorLogPath)) {
$errorLogContent = Get-Content -Path $errorLogPath -ErrorAction SilentlyContinue
throw ('Error log Content: {0}' -f ($errorLogContent | Out-String -ErrorAction SilentlyContinue))
}
#endRegion

Row 2: Function: Script Log
Add a new row by clicking the Add Row button.
A blank function will appear.
Search and select the Script Log function.
The following function will pop up on the screen:
In the script log message, simply type %output% and click the Save button
Click the Save button at the top-right corner of the screen to save the script.
Completed Script
Output
- Script log
Changelog
2026-04-02
- Updated the PowerShell used in the script as per our new standards.
2025-05-02
- Fixed the bug where the script contained several outdated and potentially incorrect AppxPackage IDs in the bloatware removal arrays. Some Microsoft apps have changed their package identifiers in newer Windows versions, and some third-party apps may have incorrect publisher IDs.
2025-04-01
- Initial version of the document