How to Effectively Remove Microsoft Bloatware Using a PowerShell Script

In the IT landscape, bloatware often poses a significant challenge for both individual users and IT professionals managing multiple systems. Bloatware refers to unwanted software pre-installed on a new computer, which can slow down performance and clutter the system.

Addressing this issue effectively is crucial, and PowerShell scripts offer a powerful solution. This blog post will delve into a specific PowerShell script designed to remove common bloatware, providing a detailed breakdown, use cases, comparisons, FAQs, and best practices.

Background

Bloatware, also known as pre-installed software, often includes trial versions of software, promotional tools, and other unnecessary applications that consume valuable resources.

For Managed Service Providers (MSPs) and IT professionals, removing these applications across numerous devices can be time-consuming and tedious. This PowerShell script automates the removal of common bloatware, streamlining the process and ensuring a cleaner, more efficient system.

The Script:

#Requires -Version 5.1

<#
.SYNOPSIS
    Removes common bloatware that is often pre-installed on a PC.
.DESCRIPTION
    Removes common bloatware that is often pre-installed on a PC.
.EXAMPLE
    -AppsToRemove "Amazon.com.Amazon, AmazonVideo.PrimeVideo, Clipchamp.Clipchamp, Disney.37853FC22B2CE, DropboxInc.Dropbox, Facebook.Facebook, Facebook.InstagramBeta, king.com.BubbleWitch3Saga, king.com.CandyCrushSaga, king.com.CandyCrushSodaSaga, 5A894077.McAfeeSecurity, 4DF9E0F8.Netflix, SpotifyAB.SpotifyMusic, BytedancePte.Ltd.TikTok, 5319275A.WhatsAppDesktop"
    
    [Warn] Amazon.com.Amazon is not installed!
    Attempting to remove AmazonVideo.PrimeVideo...
    Successfully removed AmazonVideo.PrimeVideo.
    Attempting to remove Clipchamp.Clipchamp...
    Successfully removed Clipchamp.Clipchamp.
    Attempting to remove Disney.37853FC22B2CE...
    Successfully removed Disney.37853FC22B2CE.
    Attempting to remove DropboxInc.Dropbox...
    Successfully removed DropboxInc.Dropbox.
    Attempting to remove FACEBOOK.FACEBOOK...
    Successfully removed FACEBOOK.FACEBOOK.
    Attempting to remove Facebook.InstagramBeta...
    Successfully removed Facebook.InstagramBeta.
    [Warn] king.com.BubbleWitch3Saga is not installed!
    [Warn] king.com.CandyCrushSaga is not installed!
    [Warn] king.com.CandyCrushSodaSaga is not installed!
    Attempting to remove 5A894077.McAfeeSecurity...
    Successfully removed 5A894077.McAfeeSecurity.
    Attempting to remove 4DF9E0F8.Netflix...
    Successfully removed 4DF9E0F8.Netflix.
    Attempting to remove SpotifyAB.SpotifyMusic...
    Successfully removed SpotifyAB.SpotifyMusic.
    Attempting to remove BytedancePte.Ltd.TikTok...
    Successfully removed BytedancePte.Ltd.TikTok.
    Attempting to remove 5319275A.WhatsAppDesktop...
    Successfully removed 5319275A.WhatsAppDesktop.

PARAMETER: -AppsToRemove "AmazonVideo.PrimeVideo"
    A comma-separated list of Appx package names you would like to remove.

PARAMETER: -OverrideWithCustomField "ReplaceMeWithAmultilineCustomFieldName"
    Name of a multiline custom field to retrieve the 'Apps To Remove' list.

.NOTES
    Minimum OS Architecture Supported: Windows 10, Windows Server 2016
    Release Notes: Initial Release
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#>

[CmdletBinding()]
param (
    [Parameter()]
    [String]$AppsToRemove = "Amazon.com.Amazon, AmazonVideo.PrimeVideo, Clipchamp.Clipchamp, Disney.37853FC22B2CE, DropboxInc.Dropbox, Facebook.Facebook, Facebook.InstagramBeta, king.com.BubbleWitch3Saga, king.com.CandyCrushSaga, king.com.CandyCrushSodaSaga, 5A894077.McAfeeSecurity, 4DF9E0F8.Netflix, SpotifyAB.SpotifyMusic, BytedancePte.Ltd.TikTok, 5319275A.WhatsAppDesktop",
    [Parameter()]
    [String]$OverrideWithCustomField
)

begin {
    # Replace parameters with dynamic script variables.
    if ($env:appsToRemove -and $env:appsToRemove -notlike "null") { $AppsToRemove = $env:appsToRemove }
    if ($env:overrideWithCustomFieldName -and $env:overrideWithCustomFieldName -notlike "null") { $OverrideWithCustomField = $env:overrideWithCustomFieldName }

    $AppList = New-Object System.Collections.Generic.List[string]

    function Get-NinjaProperty {
        [CmdletBinding()]
        Param(
            [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
            [String]$Name
        )
    
        # We'll redirect error output to the success stream to make it easier to error out if nothing was found or something else went wrong.
        $NinjaPropertyValue = Ninja-Property-Get -Name $Name 2>&1
    
        # If we received some sort of error it should have an exception property and we'll exit the function with that error information.
        if ($NinjaPropertyValue.Exception) { throw $NinjaPropertyValue }
    
        if (-not $NinjaPropertyValue) {
            throw [System.NullReferenceException]::New("The Custom Field '$Name' is empty!")
        }
    
        $NinjaPropertyValue
    }

    if ($OverrideWithCustomField) {
        Write-Host "Attempting to retrieve uninstall list from '$OverrideWithCustomField'."
        try {
            $AppsToRemove = Get-NinjaProperty -Name $OverrideWithCustomField -ErrorAction Stop
        }
        catch {
            # If we ran into some sort of error we'll output it here.
            Write-Host "[Error] $($_.Exception.Message)"
            exit 1
        }
    }

    # Check if apps to remove are specified; otherwise, list all Appx packages and exit
    if (!$AppsToRemove) {
        Write-Host "[Error] Nothing given to remove? Please specify one of the below packages."
        Get-AppxPackage -AllUsers | Select-Object Name | Sort-Object Name | Out-String | Write-Host
        exit 1
    }

    # Regex to detect invalid characters in Appx package names
    $InvalidCharacters = "[#!@&$)(<>?|:;\/{}^%`"']+"

    # Process each app name after splitting the input string
    if ($AppsToRemove -match ",") {
        $AppsToRemove -split ',' | ForEach-Object {
            $App = $_.Trim()
            if ($App -match '^[-.]' -or $App -match '\.\.|--' -or $App -match '[-.]$' -or $App -match "\s" -or $App -match $InvalidCharacters) {
                Write-Host "[Error] Invalid character in '$App'. Appx package names cannot contain '#!@&$)(<>?|:;\/{}^%`"'', start with '.-', contain a space, or have consecutive '.' or '-' characters."
                $ExitCode = 1
                return
            }

            if ($App.Length -ge 50) {
                Write-Host "[Error] Appx package name of '$App' is invalid Appx package names must be less than 50 characters."
                $ExitCode = 1
                return
            }

            $AppList.Add($App)
        }
    }
    else {
        $AppsToRemove = $AppsToRemove.Trim()
        if ($AppsToRemove -match '^[-.]' -or $AppsToRemove -match '\.\.|--' -or $AppsToRemove -match '[-.]$' -or $AppsToRemove -match "\s" -or $AppsToRemove -match $InvalidCharacters) {
            Write-Host "[Error] Invalid character in '$AppsToRemove'. AppxPackage names cannot contain '#!@&$)(<>?|:;\/{}^%`"'', start with '.-', contain a space, or have consecutive '.' or '-' characters."
            Get-AppxPackage -AllUsers | Select-Object Name | Sort-Object Name | Out-String | Write-Host
            exit 1
        }

        if ($AppsToRemove.Length -ge 50) {
            Write-Host "[Error] Appx package name of '$AppsToRemove' is invalid Appx package names must be less than 50 characters."
            Get-AppxPackage -AllUsers | Select-Object Name | Sort-Object Name | Out-String | Write-Host
            exit 1
        }

        $AppList.Add($AppsToRemove)
    }

    # Exit if no valid apps to remove
    if ($AppList.Count -eq 0) {
        Write-Host "[Error] No valid apps to remove!"
        Get-AppxPackage -AllUsers | Select-Object Name | Sort-Object Name | Out-String | Write-Host
        exit 1
    }

    # Function to check if the script is running with Administrator privileges
    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
    }

    if (!$ExitCode) {
        $ExitCode = 0
    }
}
process {
    # Check for Administrator privileges before attempting to remove any packages
    if (!(Test-IsElevated)) {
        Write-Host -Object "[Error] Access Denied. Please run with Administrator privileges."
        exit 1
    }

    # Attempt to remove each specified app
    foreach ($App in $AppList) {
        $AppxPackage = Get-AppxPackage -AllUsers | Where-Object { $_.Name -Like "*$App*" } | Sort-Object Name -Unique
        $ProvisionedPackage = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like "*$App*" } | Sort-Object DisplayName -Unique
        
        # Warn if the app is not installed
        if (!$AppxPackage -and !$ProvisionedPackage) {
            Write-Host "`n[Warn] $App is not installed!"
            continue
        }

        # Output an error if too many apps were selected for uninstall
        if ($AppxPackage.Count -gt 1) {
            Write-Host "[Error] Too many Apps were found with the name '$App'. Please re-run with a more specific name."
            Write-Host ($AppxPackage | Select-Object Name | Sort-Object Name | Out-String)
            $ExitCode = 1
            continue
        }
        if ($ProvisionedPackage.Count -gt 1) {
            Write-Host "[Error] Too many Apps were found with the name '$App'. Please re-run with a more specific name."
            Write-Host ($ProvisionedPackage | Select-Object DisplayName | Sort-Object DisplayName | Out-String)
            ExitCode = 1
            continue
        }

        # Output an error if two different packages got selected.
        if ($ProvisionedPackage -and $AppxPackage -and $AppxPackage.Name -ne $ProvisionedPackage.DisplayName) {
            Write-Host "[Error] Too many Apps were found with the name '$App'. Please re-run with a more specific name."
            Write-Host ($ProvisionedPackage | Select-Object DisplayName | Sort-Object DisplayName | Out-String)
            ExitCode = 1
            continue
        }

        try {
            # Remove the provisioning package first.
            if ($ProvisionedPackage) {
                Write-Host "`nAttempting to remove provisioning package $($ProvisionedPackage.DisplayName)..."
                Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like "*$App*" } | Remove-AppxProvisionedPackage -Online -AllUsers | Out-Null
                Write-Host "Successfully removed provisioning package $($ProvisionedPackage.DisplayName)."
            }

            # Remove the installed instances.
            if ($AppxPackage) {
                Write-Host "`nAttempting to remove $($AppxPackage.Name)..."
                Get-AppxPackage -AllUsers | Where-Object { $_.Name -Like "*$App*" } | Remove-AppxPackage -AllUsers
                Write-Host "Successfully removed $($AppxPackage.Name)."
            }
        }
        catch {
            Write-Host "[Error] $($_.Exception.Message)"
            $ExitCode = 1
        }
    }

    exit $ExitCode
}
end {
    
    
    
}

 

Access over 300+ scripts in the NinjaOne Dojo

Get Access

Detailed Breakdown

This PowerShell script is designed to remove a list of common bloatware applications often found on new Windows PCs. Here’s a step-by-step explanation of how the script works:

1. Script Initialization and Parameter Definition:

The script starts by defining two parameters: $AppsToRemove and $OverrideWithCustomField. $AppsToRemove holds a comma-separated list of app package names to be removed, while $OverrideWithCustomField can be used to specify a custom field name containing the list of apps to remove.

2. Dynamic Parameter Handling:

The script checks for environment variables that might override the initial parameters, ensuring flexibility in various deployment scenarios.

3. Custom Field Retrieval:

If a custom field is specified, the script attempts to retrieve the app list from it using the Get-NinjaPropertyfunction. This ensures that IT professionals can dynamically adjust the list of apps to remove.

4. Validation and List Preparation:

The script validates the app names, checking for invalid characters, length, and formatting. Valid app names are added to the $AppList.

5. Administrator Privileges Check:

Before proceeding with the removal, the script ensures it is running with Administrator privileges using the Test-IsElevated function.

6. App Removal Process:

The script iterates through each app in the list, attempting to remove both the provisioned and installed instances of the app.

Potential Use Cases

Hypothetical Case Study

Imagine an IT professional managing a fleet of new laptops for a corporate client. Each laptop is pre-installed with various bloatware applications that the client does not need. Using this PowerShell script, the IT professional can quickly remove these unwanted applications from all laptops in a fraction of the time it would take to do manually. This results in a cleaner, faster system ready for deployment.

Comparisons

Manual Removal vs. PowerShell Script:

  • Manual Removal: Time-consuming and tedious, especially across multiple devices.
  • PowerShell Script: Automated, efficient, and can handle bulk operations seamlessly.

Third-Party Software vs. PowerShell Script:

  • Third-Party Software: Often requires installation, licensing, and might introduce additional overhead.
  • PowerShell Script: Lightweight, no additional installation required, and fully customizable.

FAQs

Q: Can this script remove any application?

A: The script is designed to remove common bloatware, but it can be customized to remove any application by adjusting the $AppsToRemove parameter.

Q: What happens if the script encounters an app that is not installed?

A: The script will output a warning message indicating that the app is not installed and continue with the next app.

Q: Do I need Administrator privileges to run this script?

A: Yes, the script checks for Administrator privileges and will not proceed without them.

Implications

Removing bloatware improves system performance, frees up resources, and enhances the user experience. For IT security, removing unnecessary applications reduces potential vulnerabilities, making systems more secure.

Recommendations

  • Test in a Controlled Environment: Before deploying the script across multiple devices, test it in a controlled environment to ensure it behaves as expected.
  • Keep a Backup: Always keep a backup of important data before running the script to prevent any accidental data loss.
  • Regular Updates: Periodically update the list of apps to remove, as new bloatware may be introduced with system updates or new device models.

Final Thoughts

Managing bloatware is a crucial aspect of maintaining clean, efficient, and secure systems. This PowerShell script offers a powerful, automated solution for IT professionals and MSPs. By integrating such tools into your workflow, you can streamline system preparation, reduce manual effort, and enhance overall system performance. For comprehensive IT management solutions, consider tools like NinjaOne that offer robust features for system maintenance and management.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service deliver tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).