Introduction
“Uninstalling apps from Company Portal for Windows “ its finally here.
This feature allow your users to trigger an uninstall from installed apps directly from the Company Portal (given those apps are assigned as available).
This is a great feature on a few scenarios:
- An available installed application is not working as it should and a reinstall would fix it (uninstall/install).
- The applications are assigned as available to users and you would like to allow them to self uninstall when no longer required.
- Where a user (for whatever reason) might need to jump through app versions and those cannot co-exist.
This feature is great, but limited to one app uninstall at a time (depending how you are leveraging the Uninstall command field of course). If you have multiple apps or multiple versions of the same app to uninstall, you would find yourself having to create many apps to meet the requirement.
I get everyone is using third-party patching and every user has all the apps on the same version right? right?
Yeah, so not everyone has 100% of their environment under control, and some others inherited a poorly managed environment where there was no control before.
But fear not, this post will help you get back control (or at least some of it). We will be talking about how to bulk uninstall applications from all your user’s devices, and what is best, Dynamically. We can go as granular as a single version or as broad as dual architecture (yes, I found some environments where softwares likes 7-Zip were installed on 32 and 64 bits on the same device).
The script logic
ATTENTION: Before we jump into how to achieve this, please note this script should be handled carefully as a misuse could cause unintended consequences. Please test thoroughly on non-prod or a staged group until you feel confident to deploy to more devices.
The script will be leveraging the same logic implemented on my previous blog post How to patch apps with Intune where we will leverage Get-Package to gather the information necessary to uninstall apps and PowerShell wildcards to remove only desired apps.
To illustrate that, I’ve deployed 7-Zip on tree different devices. Note how different architectures or install types have different names under Programs and Features:
Computer | Version | Install Type | Architecture | Programs and Features |
---|---|---|---|---|
IT-01 | 23.01 | MSI | x64 | 7-Zip 23.01 (x64 edition) |
IT-02 | 23.01 | MSI | x86 | 7-Zip 23.01 |
IT-03 | 19.00 | EXE | x64 | 7-Zip 19.00 (x64) |
IT-03 | 23.01 | EXE | x86 | 7-Zip 23.01 |
Confused enough? I know right. You can install 2 different versions on the same device if one is x64 and the other x86. And also the detection is the same for MSI and EXE on 32 bits.
Now lets have a look at a generic version of the JSON we will be using later.
{
"LastUpdate": "2023-08-20 00:00:00Z",
"Application": [{
"Name": "Software1",
"Version": "*",
"Type": "msi"
}, {
"Name": "Software2",
"Version": "23.0.2",
"Type": "msi"
}, {
"Name": "Software *",
"Version": "*",
"Type": "programs"
}]
}
The first property “LastUpdate” its there to be used as a detection method by Intune Management Extension in case we want to run this script from time to time. In the same post mentioned above I explain how Intune detects an app, so if we use the “LastUpdate” as an anchor we can make sure the app only runs when the dates are newer than the current device local date. As an example, if we change the date to “2023-08-20 00:00:00Z” that means the script will keep running and coming back with an undetected status until the 20th of August, when it will then say detected and won’t try to remove any software from that list again.
The application property is where the action happens.
Name is the full or partial identifier (using wildcards) of how the software Name displays on Programs and Features.
Version is the version you are looking to remove (or “*” if any version of that software)
Type is the installer type, if not sure you can always run Get-Package and capture the ProviderName of the software.
SilentArg is only used for program uninstallers (given an MSI can always be uninstalled calling msiexec.exe with fairly static parameters). By default, the uninstaller tries to use the UninstallString from registry combining with the silent argument. If no silent argument is passed and a QuietUninstallString exists, that will be used instead.
Example
Folliwng the example above, on a test environment we only make available 7-Zip x64 with an MSI installer, so we would like to remove all the exe versions (x64 or x86) installed and also the x86 msi version from all devices.
The JSON file should look like this.
{
"LastUpdate": "2023-08-20 15:35:50Z",
"Application": [{
"Name": "7-Zip *",
"Version": "*",
"Type": "programs",
"SilentArg": "/S"
}, {
"Name": "7-Zip ??.??",
"Version": "*",
"Type": "msi"
}]
}
The first JSON Application object will only look for Programs type, which means only executable installers and remove any version of any architecture (thanks to the wildcards on version and name) The second JSON Application object will only look for msi type, but will also limit the name to 4 digits (that is the difference between ? and ) and remove any versions of it. That would leave our *7-Zip ??.?? (x64 edition) alone.
This logic can be used with almost any app. Even for apps that install multiple components or prerequisites like C++ Redistributables, all you need is to add more objects to the Applications JSON and be as wide or granular as you need.
Also, take into consideration that apps have similar names. If you use something like “Git*” on your, search you are looking at possibly a dozen apps like Git, Github Desktop and Git Extensions to name a few.
The script
The script can be copied from my Github repo BulkUninstallApps. To facilitate, I’ve created detection and remediation scripts, which can be used on both Remediations or Win32App (depending on which license you have).
Thanks for reading and I hope this post helps you to remove some unwanted apps from your environment. If something is not clear or you would like some help with the scripts please reach out via twitter.
Comments