Remove Appx Packages with Intune Remediation

Introduction

In this article, I will explain a remediation I created to remove specific Appx packages from Windows devices using Intune. The purpose of this remediation is to ensure that certain unwanted or unnecessary Appx packages are not present on managed devices. This helps in maintaining a clean and streamlined environment for users.

Objective :

The main goal of this remediation is to check if specific Appx packages are installed or provisioned on a system and, if they are, remove them.

Implementation in Intune :

To set up this remediation in Intune, follow these steps:

  1. Download the Scripts: You can find the detection and remediation scripts on GitHub.
  2. Create a New Remediation: In the Intune portal, navigate to Devices > Remediation > Add and create a new remediation with the downloaded scripts.
  3. Upload and Assign: Upload the detection and remediation scripts, configure the run settings, and assign them to the desired device groups.

Technical Explanation

In this section, I will explain the main parts of both the detection and remediation scripts.

Detection Script :

The detection script checks if specific Appx packages are present on the system. Here’s a detailed explanation of the main script:

# Function for logging
Function LogWrite {
    Param ([string]$logstring)
    $logstring = (Get-Date -Format "MM-dd-yyyy - HH:mm:ss.fff") + " | $logstring"
    Add-Content $Logfile -Value $logstring
}

########################################################
# Main Script

$logDir = "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs"
$Logfile = "$logDir\RemoveAppx_Detection.log"

LogWrite "Script starting..."

# Appx list
$Appx = @(
    'Clipchamp.Clipchamp'
    'Microsoft.549981C3F5F10'
    'Microsoft.BingNews'
    'Microsoft.BingWeather'
    'Microsoft.GamingApp'
)

# Get Windows version
$Winver = Get-ComputerInfo | Select-Object OSName,OSDisplayVersion
LogWrite "Current OS : $($Winver.OsName) $($Winver.OSDisplayVersion)"

# Get all installed and provisioned Appx packages
$InstalledPackages = Get-AppxPackage -AllUsers | Select-Object -ExpandProperty Name
$ProvisionedPackages = Get-AppxProvisionedPackage -Online | Select-Object -ExpandProperty DisplayName

# Combine all packages to check
$AllPackages = $InstalledPackages + $ProvisionedPackages

# Find matching packages
$MatchingPackages = $Appx | Where-Object { $AllPackages -contains $_ }

# Log matching packages
if ($MatchingPackages) {
    LogWrite "Matching Appx packages found:"
    $MatchingPackages | ForEach-Object { LogWrite "- $_" }
    LogWrite "Exiting with code 1."
    exit 1
}

LogWrite "No matching Appx packages found. Exiting with code 0."
exit 0

How It Works :

  • Appx List:
# Appx list
$Appx = @(
    'Clipchamp.Clipchamp'
    'Microsoft.549981C3F5F10'
    'Microsoft.BingNews'
    'Microsoft.BingWeather'
    'Microsoft.GamingApp'
)

This array contains the names of the Appx packages we want to check for. For the sake of this example, only five packages are listed, but the full list is available in the script on GitHub.

  • Get Installed and Provisioned Appx Packages:
$InstalledPackages = Get-AppxPackage -AllUsers | Select-Object -ExpandProperty Name
$ProvisionedPackages = Get-AppxProvisionedPackage -Online | Select-Object -ExpandProperty DisplayName

These commands retrieve the names of all installed and provisioned Appx packages on the system. Get-AppxPackage lists installed packages for all users, and Get-AppxProvisionedPackage lists packages that are provisioned (available for installation) on the system.

  • Combine and Compare Packages:
$AllPackages = $InstalledPackages + $ProvisionedPackages
$MatchingPackages = $Appx | Where-Object { $AllPackages -contains $_ }

The script combines the installed and provisioned packages into one list and then checks if any of the packages in the $Appx list are present in this combined list.

  • Log and Exit Based on Findings:
if ($MatchingPackages) {
    LogWrite "Matching Appx packages found:"
    $MatchingPackages | ForEach-Object { LogWrite "- $_" }
    LogWrite "Exiting with code 1."
    exit 1
}

LogWrite "No matching Appx packages found. Exiting with code 0."
exit 0

If any matching packages are found, the script logs them and exits with code 1, indicating that action is needed. If no matches are found, it logs that no matches were found and exits with code 0, indicating no action is needed.


Remediation Script :

The remediation script removes the specified Appx packages from all users and removes provisioned packages. Here’s a detailed explanation of the main script:

# Function for logging
Function LogWrite {
    Param ([string]$logstring)
    $logstring = (Get-Date -Format "MM-dd-yyyy - HH:mm:ss.fff") + " | $logstring"
    Add-Content $Logfile -Value $logstring
}

########################################################
# Main Script

$logDir = "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs"
$Logfile = "$logDir\RemoveAppx_Remediation.log"

LogWrite "Script starting..."

# Appx list
$Appx = @(
    'Clipchamp.Clipchamp'
    'Microsoft.549981C3F5F10'
    'Microsoft.BingNews'
    'Microsoft.BingWeather'
    'Microsoft.GamingApp'
)

# Get Windows version
$Winver = Get-ComputerInfo | Select-Object OSName,OSDisplayVersion
LogWrite "Current OS : $($Winver.OsName) $($Winver.OSDisplayVersion)"

# Get installed and provisioned packages to remove
$InstalledPackages = Get-AppxPackage -AllUsers | Where-Object { $Appx -contains $_.Name }
$ProvisionedPackages = Get-AppxProvisionedPackage -Online | Where-Object { $Appx -contains $_.DisplayName }

# Remove all Appx packages from the list
$InstalledPackages | ForEach-Object {
    try {
        LogWrite "Removing Appx package: $($_.Name)"
        Remove-AppxPackage -Package $_.PackageFullName -AllUsers -ErrorAction Stop
        LogWrite "Successfully removed package: $($_.Name)"
    } catch {
        LogWrite "Failed to remove package: $($_.Name). Error: $($_.Exception.Message)"
    }
}

# Remove all provisioned Appx packages from the list
$ProvisionedPackages | ForEach-Object {
    try {
        LogWrite "Removing provisioned Appx package: $($_.DisplayName)"
        Remove-AppxProvisionedPackage -Online -PackageName $_.PackageName -ErrorAction Stop
        LogWrite "Successfully removed provisioned package: $($_.DisplayName)"
    } catch {
        LogWrite "Failed to remove provisioned package: $($_.DisplayName). Error: $($_.Exception.Message)"
    }
}

LogWrite "Script ending..."

How It Works :

  • Appx List:
# Appx list
$Appx = @(
    'Clipchamp.Clipchamp'
    'Microsoft.549981C3F5F10'
    'Microsoft.BingNews'
    'Microsoft.BingWeather'
    'Microsoft.GamingApp'
)

This array contains the names of the Appx packages we want to remove. For the sake of this example, only five packages are listed, but the full list is available in the script on GitHub.

  • Get Installed and Provisioned Packages to Remove:
$InstalledPackages = Get-AppxPackage -AllUsers | Where-Object { $Appx -contains $_.Name }
$ProvisionedPackages = Get-AppxProvisionedPackage -Online | Where-Object { $Appx -contains $_.DisplayName }

These commands retrieve the installed and provisioned packages that match the names in the $Appx list. Only the packages in the $Appx list are considered for removal.

  • Remove Installed Packages:
$InstalledPackages | ForEach-Object {
    try {
        LogWrite "Removing Appx package: $($_.Name)"
        Remove-AppxPackage -Package $_.PackageFullName -AllUsers -ErrorAction Stop
        LogWrite "Successfully removed package: $($_.Name)"
    } catch {
        LogWrite "Failed to remove package: $($_.Name). Error: $($_.Exception.Message)"
    }
}

The script iterates through each installed package and attempts to remove it. Successful removals and errors are logged for each package.

  • Remove Provisioned Packages:
$ProvisionedPackages | ForEach-Object {
    try {
        LogWrite "Removing provisioned Appx package: $($_.DisplayName)"
        Remove-AppxProvisionedPackage -Online -PackageName $_.PackageName -ErrorAction Stop
        LogWrite "Successfully removed provisioned package: $($_.DisplayName)"
    } catch {
        LogWrite "Failed to remove provisioned package: $($_.DisplayName). Error: $($_.Exception.Message)"
    }
}

Similarly, the script iterates through each provisioned package and attempts to remove it, logging the outcome.

For clarity and simplicity, I have only listed five Appx packages in the examples above. The complete list is available in the scripts on GitHub.

By using these scripts in Intune, you can ensure that unwanted Appx packages are identified and removed from your managed devices, keeping the environment clean and efficient.

Leave a Comment