Photo in the public domain, courtesy of Pixabay

Down the Uninstalls Rabbit Hole: Installment 1, Basic Uninstalls

Recently I got a request from Daniel Hurtubise at RPBW, to look into automating the uninstall of ALL installed flavors of Dynamo. That led me to digging into the nasty details of Dynamo uninstalls, and uninstalls in general. I thought it would be worth sharing what I discovered. But that’s going to be a long post, even for me, so I am going to break it up a bit.

In this first installment we’ll look at the basics of Windows Uninstalls, both manual and automated, and how to gather the data needed for the latter. The second installment we will look at Windows AppStore uninstalls. Then in the third installment we will get to the Dynamo uninstalls that started my explorations. And finally the fourth installment will discuss how all this is influencing Px Tools 4.0 development, for those who are interested.

I started researching this topic, after working with Uninstalls pretty extensively for a decade and a half, and discovered that there was a LOT I didn’t understand. I Googled (actually I DuckDuckGo’d, or is that DuckDuckWent?) lots of things, and found all sorts of contradictory or incomplete info. I searched Microsoft’s own developer resources and found painfully limited resources. I searched the help resources for the various vendors to get specific information on their software. And finally I asked on stackoverflow and got a great response from Stein-Inge Åsmul, who is a bit of an expert at this stuff. I mean, check out his website, it’s DEEP. What did he have to say?

“Windows is a hodge-podge of different technologies that sort of meet in this registry location (Windows Installer, Legacy Installers, Windows Updates perhaps, etc…). I wouldn’t waste my time trying to make sense of it all.”

And, after a few weeks of digging around I knew he was right, I was never going to UNDERSTAND what was going on, especially not every nuance. The closest I can get is some guidelines for gathering info and putting it to use productively.

And with that, lets go down the rabbit hole.

When you manually Uninstall, by clicking the Uninstall button in Add & Remove Programs (AKA Apps & features in Windows 10)…
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]
… some program or command line is triggered. But what exactly?

We can find this command line in the registry, in the Uninstall key found here:

Start by looking in the GUID named Keys at the top of the list. These will contain some Properties with pertinent values.

DisplayName which identifies the product.
DisplayVersion which shows the current build number. This is revised as updates are installed, while the GUID key name remains the same.
InstallLocation which shows the folder in which the program is installed. The property is not always provided with a value, but when it is it’s useful to note as there is a good chance this folder will be orphaned at uninstall and you will need to delete it separately.
UninstallString which provides the command line that is run when you choose Uninstall from Add & Remove Programs.

We’ll look at some examples now, to explore (some of) the many variations you’ll run into.

Bluebeam Revu 2019
Bluebeam provides a fairly simple first example. A single GUID key and a number of properties that provide details about the installed program.

[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

UninstallString MsiExec.exe /X{74A435D8-FE24-498A-9809-76541D74182A}

This command line runs MsiExec.exe, with the /X argument for a delete, and the GUID. This is a “direct” use of msiexec, in that it uninstalls the product when the Remove button is clicked, after the UAC dialog of course.


Preview Image Generator (P.I.G.)
Parley Burnett’s Preview Image Generator takes a different approach.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

UninstallString MsiExec.exe /I{3E2F7A34-01A7-475C-9363-22D3EC223C7A}

The argument for MsiExec.exe is /I, which is normally an Install. And yet, the Uninstall is what runs. I think Microsoft is actually intercepting the argument and changing it, as using the /I argument outside of Add & Remove Programs does NOT uninstall. But we’ll get to that a bit later.


eTransmit for Revit 2019
eTransmit throws in another variation, and this is one that Autodesk really seems to love.

You get a GUID Primary Key just like the previous examples.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

And you get a Secondary Key that doesn’t have a GUID based name
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

UninstallPath C:\Program Files\Autodesk\eTransmit for Revit 2019\Setup\Setup.exe /P {4477F08B-1901-0010-0000-9A09D834DFF5} /M REVIT /LANG en-US
UninstallString MsiExec.exe /X{4477F08B-1901-0010-0000-9A09D834DFF5}

In the Primary Key you get a now familiar UninstallString, but right above it you also have a new UninstallPath, with a VERY different command line. And if you look closely at the Secondary key, you have the same two properties there as well, but now the UninstallString is the same as the UninstallPath in both. So which is triggered?
It definitely isn’t the MsiExec of UninstallString in the Primary Key, because you get this when you manually Uninstall.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]
As it turns out, it’s the Secondary Key UninstallString that is triggered, because if you rename that, the Uninstall button will be unavailable in Add & Remove programs. Rename all three of the other Properties instead and the Uninstall button is unaffected. And that makes sense, since this Property launches Setup.exe, referencing the Product by GUID /P {4477F08B-1901-0010-0000-9A09D834DFF5} and in Modify mode /M. Which is exactly what we see in the dialog that comes up.


Revit 2019
Revit, and all the Autodesk “Main Line” programs I think, are a variation of this. With a Primary Key.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

A Secondary Key.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

And a Tertiary Key.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]
The Uninstall properties and behaviors are the same as with eTransmit, but now you also have that Tertiary Key, with information that has no bearing on Uninstalls at all.

Notepad++ gives us a new wrinkle.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

The Primary (and only) Key is not GUID named.

UninstallString C:\Program Files\Notepad++\uninstall.exe

And the the UninstallString references neither MsiExec.exe nor a Setup.exe, but rather an Uninstall.exe.


And lest you think you can at least expect predictability within a particular product…

Enscape 2.5 (and earlier)
Earlier Enscapes are similar to Notepad++
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

A non GUID Primary Key.

UninstallString “C:\Program Files\Enscape\Uninstall.exe” /allusers

And an Uninstall.exe that takes an argument.


Enscape 2.6
But Enscape 2.6 is more like Preview Image Generator.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

At least Enscape is moving to GUID named Primary Keys and MsiExec.exe based Uninstalls. You’ll find some programs doing the opposite.

That’s a lot to take in, but we have another issue to consider. Should you have a machine with an older build of Dynamo, you’ll find that there is no Key for it in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall. Similarly, most of the main Autodesk products have components that need to be Uninstalled separately, be it manually or with Automation. You may have noticed above that along with Revit 2019 there is a Secondary Key for Autodesk Workflows 2019, and if you dig through the GUID Primary Keys you will find {F9857F69-9B57-4DF2-8930-7A4D5F8D5635} is the one you need for Workflows 2019. But there are other, seemingly missing Components, like all the Material Libraries. You will find them in Add & Remove Programs, but not the the Registry location we have been exploring. The reason for this has to do with how Microsoft implemented 64 bit Windows, specifically the ability to install 32 bit and 64 bit versions of the same software “side by side”.
The Registry location we have been working with is the “Native” Registry location. On 64 bit Windows 64 bit programs can be found here. On 32 bit Windows 32 bit programs can be found here. And 32 bit Windows CAN’T have 64 bit programs installed. But 64 bit Windows CAN have 32 bit programs installed. And the 32 bit version needs to be totally independent of the 64 bit version. At the same time, when a 32 bit version is installed on 32 bit Windows, it needs to act exactly like a 64 bit version installed on 64 bit Windows. The solution is Registry Redirection. On 64 bit Windows, when a 32 bit process asks for a Registry path, Windows intercepts that request and redirects to another location, transparent to the program making the request. Installers behave the same way. So we need to look in this alternative location for our missing Uninstalls, and that location is:

There are some differences in how some things get handled here (explore the x86 C++ redistributable Knowledge Base updates, for example), but for our purposes with normal programs, things are pretty familiar, just in a new place and with some nuances.

Autodesk Material Library 2019
Material Libraries have the Primary key we expect.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

But lack the Secondary Key that confuses the UninstallString question, instead only having a Tertiary Key we can ignore.
[wp_lightbox_fancybox_image link=”” width=”840″ height=”640″ source=””]

I won’t go into dealing with software installed for a single user here, but if there is an interest in going down that rabbit hole too let me know in the comments. In the meantime…

What does all this mean from a practical level? Thankfully it’s not actually as bad as it might look at first glance. Let’s consider the three broad categories of Uninstall data one at a time.

GUID Primary Key, MsiExec.exe Uninstall
There are two different variations in our examples here, using /X and /I arguments, but once you move out of manual Uninstalls there’s really only one answer, /X. You’ll remember that I said for Preview Image Generator it seemed like Add & Remove Programs was actually remapping the /I to /X? I “verified” that by running the command line I found in the UninstallString Property using PowerShell, and the /I argument did nothing. Or, more correctly it returned a 0 as one would expect when trying to install something that is already there. But using the /X argument works, for all those programs that have /I in UninstallString. But, it’s not quite a simple as just running the command line.
First, we need to use the Start-Process commandlet, which requires that we separate out the executable (MsiExec.exe) from the arguments (the /X and the GUID).

For our first example, Bluebeam Revu 2019, that looks like this…
Start-Process msiexec.exe '/x {74A435D8-FE24-498A-9809-76541D74182A}'

Alternatively, if you like to see the name of the parameters, you can use this approach, where PowerShell parameters get a prefix.
Start-Process -filePath msiexec.exe -argumentList '/x {74A435D8-FE24-498A-9809-76541D74182A}'

Or, if you are like me and what the parameter and value more discreetly associated with each other, you are allowed to use a : between them like this:
Start-Process -filePath:msiexec.exe -argumentList:'/x {74A435D8-FE24-498A-9809-76541D74182A}'

Just be aware that not EVERYTHING supports this. But I do think it helps to understand the relationships so I’ll keep using that approach here. Also note that while all Installers seem to put the GUID right after the /X argument, a space will actually work as well, which I think helps with readability. You also aren’t limited to capitalizing the /X, /x works also. Do what is most readable to you. I’m obviously a lower case kinda guy.

Now, that’s all well and good, but if you actually use this in a PowerShell script you will get a verification dialog like this

Which kind of defeats the purpose of automation. To address the issue we need to add a silent “flag” or Command Line Option, and my preference here is /qn. At which point our example looks like this
Start-Process -filePath:msiexec.exe -argumentList:'/x {74A435D8-FE24-498A-9809-76541D74182A} /qn'

So, that’s progress, and it will work grand for a single Uninstall, but more often than not we do a bunch in sequence, but only one at a time can run. And that’s why we needed to use the Start-Process cmdlet, because it has a Wait option, so each Uninstall will complete before the next one starts.

Start-Process -filePath:msiexec.exe -argumentList:'/x {74A435D8-FE24-498A-9809-76541D74182A} /qn' -wait

The thing to understand here is that -argumentList is arguments for MsiExec.exe, while -wait is an argument for Start-Process. There are other arguments, related to getting back result codes and such, as well as using the cmdlet for MANY other things. Details here.

Autodesk Main Line Programs
This is enough to address simple programs, and in the case of Autodesk stuff, we can expand on it just a bit to address more complicated programs. Because, while a manual Uninstall of, for examp0le Revit, triggers Setup.exe, we can just string together a bunch of MsiExec.exe based uninstalls and ignore Setup.exe entirely. So this gives you a sense of how you might start constructing a more complex Uninstall, and shows you how PowerShell comments work, though the line breaks are unfortunate and suggest I have some work to do on the web site CSS. 😉

Start-Process -filePath:msiexec.exe -argumentList:'/x {7346B4A0-1900-0510-0000-705C0D862004} /qn' -wait # Revit 2019
Start-Process -filePath:msiexec.exe -argumentList:'/x {F9857F69-9B57-4DF2-8930-7A4D5F8D5635} /qn' -wait # Autodesk Workflows 2019
Start-Process -filePath:msiexec.exe -argumentList:'/x {8F69EE2C-DC34-4746-9B47-7511147BD4B0} /qn' -wait # Autodesk Material Library 2019

Uninstall.exe based programs
Here things get interesting, because sometimes the Uninstall.exe is silent, and you don’t need to do anything. But often you need a silent flag. Unfortunately we usually don’t get those in the UninstallString, and different Uninstallers will need different flags. Here Google or DuckDuck Go is your friend, especially if your software vendor doesn’t provide documentation on the topic. So here we see what Notepad++ would look like.

Start-Process -filePath:"C:\Program Files\Notepad++\uninstall.exe" -argumentList:'/S' -wait # Notepad++

And notice two things.
1: The quotes around the file path, which are needed when there is a space in the path, and
2: The silent flag is capitalized, and must be.
Yeah, a “hodge-podge”, remember?

So, that about wraps us up for this introduction to gathering uninstall data and automating uninstalls with that data. It hasn’t been comprehensive, I have very intentionally avoided some of the nastier programs (I’m looking at YOU Microsoft Office!). But hopefully it is enough to get you started gathering data and testing your own uninstalls.

In the next installment we look at the Windows App Store and some new cmdlets to address both Uninstalls and Deprovisioning.

Also, one last item. Along with all the Uninstall info, I have been playing with a lot of site CSS on this post, creating and testing things in preparation for the big site renovation that coincides with the Px Tools 4.0 release. If you have any issue with this post, in specific browsers or especially on non PC devices, please Contact me and let me know, so I can try to get that sorted too.