Down the Uninstalls Rabbit Hole: Installment 2, Microsoft Store Uninstalls

In the last installment we looked at normal uninstalls, the stuff we have dealt with going back to Windows XP and even earlier. And while there is a lot of variation in the HOW of Uninstalls, and the Install that comes first, the underlying situation is pretty simple. Programs get installed when WE trigger the install, and they get uninstalled when WE trigger the uninstall. The only subtlety is installing for just a single user, rather than all users. Because of how AEC firms manage machines over time, and sometimes jump from machine to machine, programs should always be installed for all users, so that is a subtlety we shouldn’t be dealing with that often, though autodesk needs to get a clue there with their addins architecture, but that’s another post.

In this installment we look at the new kid on the block, Microsoft Store, which introduces a number of new wrinkles.
Microsoft introduced the Windows Store in Windows 8, as a delivery mechanism for UWP (Universal Windows Platform) programs. Basically programs that would run on Windows or Windows Phone. Thankfully most of us have moved on from Windows 8, so here we will just be looking at the Windows 10 Store. That said, Microsoft Marketing did what they always do, and changed the name to Microsoft store in 2017, so that’s what we’ll be calling it from here on.

The first thing we need to do is look at what is installed on a machine, and that’s very different from traditional installs. Here our only option is PowerShell, and we’ll need to get into some of the nuances of that tool, so let’s dig in.
First off, you will need to be running the PowerShell ISE “elevated”. Even if you are logged in as a local admin user, Windows security still requires you to intentionally elevate PowerShell by choosing Run as Administrator to enable certain actions via automation.

Uninstalls

From an elevated ISE (or console) you can use the Get-AppxPackage cmdlet to get a list of installed programs, but the results are pretty verbose.
Get-AppxPackage

The two most important pieces of information are:

Name The short name of the installed program.
PackageFullName The long name, which changes as updates are installed.

Also important are the three boolean parameters:

IsFramework
IsResourcePackage
IsBundle

There are four “types” of store based install…

Main A regular program, potentially no more than a single executable.
Bundle Also a regular program, but “bundled” with other assets beyond a simple executable.
Resource Usually a regular program, with included resources, but I guess could also be a standalone resource for something else.
Framework OS stuff like .NET or C++. Not usually something you want to uninstalls.

We can usefully limit the returned list by using the -packageTypeFilter to only get Main programs. And we can also use the Select-Object cmdlet, which is a bit of a misnomer, it actually selects properties of the provided object, and we use it by “piping” the results of Get-AppxPackage to Select-Object using the pipe operator, |. This is a defining characteristic of PowerShell. It allows the results of one cmdlet to be piped to the next, just like Unix shell, but what is passed is an object, not just a string. As you dig deeper into PowerShell you realize just how profound a difference this is. That said, our revised code looks like this
Get-AppxPackage -packageTypeFilter:main | Select-Object -property: name, packageFullName
and produces a much more useful list of programs.

Now this list still includes some things you don’t want to uninstall, or that in fact are not possible to uninstall, and as a rule we want to be pretty specific with uninstalls anyway. But the list does give us the information we need, and we now have enough PowerShell knowledge, to move on to actual uninstalls with the Remove-AppxPackage cmdlet. Here we want to use the -allUsers parameter to uninstall for, well, all users.
Another thing to be aware of is just how these “names” work. The first item in the name is the publisher, and it can be something recognizable like Microsoft, or a seemingly random string that represents a particular vendor, such as 89006A2E.AutodeskSketchBook where 89006A2E is Autodesk’s code, or CAF9E577.Plex where CAF9E577 is an unknown (to me) company code. We can use this to our advantage, along with wild cards, to filter Get-AppxPackage on names.
So, to get rid of the “Get Office” marketingware we use
Get-AppxPackage -name:"Microsoft.MicrosoftOfficeHub*" | Remove-AppxPackage -allUsers

And here, the wildcard gets both the audio and the video Zune stuff in one go.
Get-AppxPackage -name:"Microsoft.Zune*" | Remove-AppxPackage -allUsers

One nuance to mention here. If you explore the Remove-AppxPackage link you’ll find that you CAN use Remove-AppxPackage alone, if you pass it the PackageFullName you want to remove. But that will be different on different machines, depending on which build of Windows is installed. And as you will find on that page, -Package doesn’t accept a wild card. You either pass the actual object, or the complete PackageFullName. But, check out the Microsoft info on Get-AppXPackage, and while it still says it doesn’t accept while cards for Name in the table, above that it says wildcards ARE supported. So we NEED to use Get-AppXPackage to get the wildcard based filtering needed to control what’s uninstalled in a granular way.

De-Provisioning
At this point, you might expect that we are done. We’ve uninstalled a program, for all users, so it’s gone, right? No, not really. You see, with the Microsoft Store Microsoft is making the OS more of an advertising platform for the Store itself, and to further that end they want to make sure that every new user on the machine get’s the pleasure of seeing all the new shiny they copied from Apple. So, a new user after the work we have done will get all sorts of provisioned apps installed automatically at first logon, and the process will need to be repeated to uninstall them again. But there is a solution.
Much like with “installed” programs and the Get-AppxPackage cmdlet, we have the Get-AppXProvisionedPackage cmdlet to see what is provisioned on the machine. And be aware, you can “provision” the current image of Windows on a machine, but IT can also use offline images on the network to facilitate OS installs, and these images can be provisioned and de-provisioned too. So we need to let AppXProvisionedPackage know we want to look at the the “online” image, meaning the installed image on this machine.
Get-AppXProvisionedPackage -online

And again we can use Select-Object to constrain our output.
Get-AppXProvisionedPackage -online | Select-Object -property:DisplayName

As you can see, lots of things are still lurking there in the shadows, waiting to pounce.

Another difference with Get-AppXProvisionedPackage is that it offers no built in ability to filter the results, not by DisplayName and not by PackageName. So how do we ensure we only get the specific package we want? Another PowerShell cmdlet, Where-Object, and the pipeline!

Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "Microsoft.Zune*"}

Here every single provisioned package is passed by Get-AppXProvisionedPackage to Where-Object , which processes the code block {$_.PackageName -like “Microsoft.Zune*”} , which acts a bit like an If statement. $_ is an automatic variable, which contains the package object being passed, .PackageName is dot referencing the Property we want, -like is the similarity operator (which accepts wildcards) and “Microsoft.Zune*” is once again the string we want to filter by. It’s a bit slow, since every possible package is compared each time you want to filter just one package, but computers are fast and it’s not an issue. End result, we get the same behavior as before, only the package or packages we want are passed further. Which brings us to the last cmdlet we need in our pipeline, Remove-AppxProvisionedPackage to do the actual remove, and again we need to specify that this is for the -online OS image.
Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "Microsoft.Zune*"} | Get-AppxProvisionedPackage -online

Combined, we get this to both uninstall the two Zune components for all users and deprovision them so new users on the machine don’t get them installed either. Winning!
Get-AppxPackage -name:"Microsoft.Zune*" | Remove-AppxPackage -allUsers
Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "Microsoft.Zune*"} | Get-AppxProvisionedPackage -online
And, thanks to the filtering, if Zune isn’t installed or provisioned on the machine, the code runs without errors. Nice

One thing to be aware of here is that some things are part of the OS and can’t be uninstalled. Things that really SHOULDN’T be, but Microsoft Marketing doesn’t care. Xbox is an example. You might think that using wildcards like this would be to your advantage.
Get-AppxPackage -name:"Microsoft.Xbox*" | Remove-AppxPackage -allUsers
But that’s going to throw an error when certain xBox items can’t be uninstalled. Instead you’ll need to be rather specific, with something like this to address the Xbox stuff that CAN be uninstalled, while ignoring the stuff that can’t, like Xbox.TCUI.
Get-AppxPackage -name:"Microsoft.XboxApp*" | Remove-AppxPackage -allUsers
Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "Microsoft.XboxApp*"} | Get-AppxProvisionedPackage -online
Get-AppxPackage -name:"Microsoft.XboxGameOverlay*" | Remove-AppxPackage -allUsers
Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "Microsoft.XboxGameOverlay*"} | Get-AppxProvisionedPackage -online
Get-AppxPackage -name:"Microsoft.XboxGamingOverlay*" | Remove-AppxPackage -allUsers
Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "Microsoft.XboxGamingOverlay*"} | Get-AppxProvisionedPackage -online
Get-AppxPackage -name:"Microsoft.XboxIdentityProvider*" | Remove-AppxPackage -allUsers
Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "Microsoft.XboxIdentityProvider*"} | Get-AppxProvisionedPackage -online
Get-AppxPackage -name:"Microsoft.XboxSpeechToTextOverlay*" | Remove-AppxPackage -allUsers
Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "Microsoft.XboxSpeechToTextOverlay*"} | Get-AppxProvisionedPackage -online

Promoted Apps
Now there is one last nuance to be aware of, and we already have the tools to deal with it, for the most part. As I mentioned before, Microsoft has decided that post install, the OS is still more their advertising platform than your work platform, and to that end, there is another category of program that may get forced on you, the dreaded “promoted app”. This is usually crap like Candy Crush Cesspool or whatever, but also some less offensive apps in a professional environment, like Drawboard PDF or the recent WinZip stuff.

The list is different with every new build of Windows, and these apps only get installed for the logged in user when the update happens. Controlled timing of the update, triggered intentionally while logged in as a dedicated “install” user account, can mitigate the problem (and many others), whereas users as local admins and windows updates on Microsoft’s schedule leads to polluted production user accounts. Windows 10 Enterprise offers a way to suppress this shit behavior (branded Microsoft Consumer Experience by the tools at Microsoft Marketing), but Microsoft removed that capability from Windows 10 Pro in the 2016 Anniversary Update. To make matters worse, they also are adding “promoted” tiles for software that isn’t even installed, but clicking installs it.
So, go ahead and use the skills you now have to remove the crapware you already have, and then reconsider the way you install Windows Updates to minimize the pain later. And here again, give some thought to how you use wild cards. For example, here I am removing everything by crapware vendor King.

Get-AppxPackage -name:"king.com*" | Remove-AppxPackage -allUsers
Get-AppXProvisionedPackage -online | Where-Object {$_.PackageName -like "king.com*"} | Get-AppxProvisionedPackage -online

Caveats
All of this has been tested on multiple versions of Windows, with… mixed results. I have an old 1703 VM where Promoted Apps like the Candy Crush stuff will not uninstall. But I have a fresh 1703 VM where it uninstalls fine. I have an old 1803 VM where all the Remove-AppxProvisionedPackage stuff throws errors, but after I let it upgrade to 1903 it works fine. The fresh 1909 VM I just built works like a champ. So at this point I don’t know if some builds have issues, or something happens over time as other updates get installed, or my older VMs have settings at fault. I would love to test this more thoroughly, but I only have Windows ISOs for 1607, 1703, 1803, 1903 & 1909. If anyone has other ISOs I can use with my license, please let me know! I am hoping to do some very thorough testing with all builds since 1607 and all flavors from Windows 10 Home through Enterprise. Any help on the ISO front, or issues you have run into yourself, is greatly appreciated.

And, one last caveat. You might be tempted to uninstall the Microsoft Store itself, but everything I have read suggests NOT to do that. Too much of the basic Windows functionally is now managed via the store, and updates will be broken if the store is removed. that said, I intend to rebuild my primary test VM for work on Px Tools 4.0, and uninstall the store, then see what happens. Stay tuned for an update as I dogfood that process with a VM that will see action on a daily basis.

And on that note, time to start putting the finishing touches on the third installment, where we FINALLY get to look at the Dynamo issues that started all of this. Till then!

Comments