0

When I upgrade / downgrade my application via a Powershell script, I want to first force the uninstallation of the currently installed version before running the new installer.

How can I do that with Powershell, using the UpgradeCode of the application?

Doing it by application name would be less robust.

Stein Åsmul
  • 34,628
  • 23
  • 78
  • 140
Axel Williot
  • 415
  • 3
  • 11
  • Can you provide what you've already tried? – thom schumacher Mar 02 '18 at 18:13
  • 1
    Any chance that you are (or will be) doing this through SCCM? – EBGreen Mar 02 '18 at 18:32
  • 1
    I thought correctly designed MSI packages do this automatically. – Bill_Stewart Mar 02 '18 at 18:42
  • You're cute.... – EBGreen Mar 02 '18 at 18:44
  • 2
    Just call msiexec.exe /x UPGRADECODE – EBGreen Mar 02 '18 at 19:02
  • @EBGreen: That's news to me to uninstall via UpgradeCode like that. I tried it, and it does bring up a prompt to uninstall a product - even if there is no product to uninstall - and clicking yes doesn't do anything (regardless if there are relevant products to uninstall or not). I added a script in my answer to uninstall by UpgradeCode using the MSI API (COM automation). It should be translatable to Powershell. – Stein Åsmul Mar 03 '18 at 12:28
  • Added an important disclaimer for my previous VBScript sample (prevent unexpected and sudden reboot without warning). And some extra information on alternative methods to use for uninstall. – Stein Åsmul Mar 04 '18 at 15:00
  • @SteinÅsmul if you get to the GUI then the uninstall is running. If nothing is actually uninstalling then that is an issue with the uninstall not MSIExec. – EBGreen Mar 05 '18 at 14:17

1 Answers1

2

Since you mention upgrade code, it must mean that you are talking about an MSI file (Windows Installer). As stated by others such an uninstall is normally performed auto-magically by a properly authored MSI package - it is referred to as a major upgrade - which is essentially an uninstall of the existing version of a product and then the install of the newest version.

The Upgrade Table of the MSI being installed will specify what existing packages on the box will be uninstalled before the new version is installed. In theory you can uninstall any number of existing installations. You can even uninstall a competitive product if you are mad as a hatter. Frankly, and astonishingly, I have never tried to uninstall multiple products during one major upgrade - it is rarely called for. In most cases you uninstall a single, existing product and then install your latest version.

  1. You can modify the Upgrade table using a transform to change how the major upgrade behaves - in other words to make it start or stop uninstalling a specific pre-existing installation.

  2. You can also enumerate all related products that share the same upgrade code by calling this MSI API function (COM - VBScript used as sample):

Set installer = CreateObject("WindowsInstaller.Installer")

' Enumerate all products related to "Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148"

' {AA783A14-A7A3-3D33-95F0-9A351D530011} is the upgrade code
Set upgrades = installer.RelatedProducts("{AA783A14-A7A3-3D33-95F0-9A351D530011}")

For Each u In upgrades
   MsgBox u, vbOKOnly, "Product Code: "
Next

Then you can uninstall the products by passing the product code(s) to the msiexec.exe command line (see below for how to do this via MSI API COM automation instead):

msiexec.exe /x {11111111-1111-1111-1111-11111111111X} /L*V "C:\msilog.log" REBOOT=ReallySuppress

Quick Parameter Explanation (since I recommend this option):

 /X = run uninstall sequence
 /QN = run completely silently
 /L*V "C:\msilog.log"= verbose logging at path specified
 {11111111-1111-1111-1111-11111111111X} = product guid of app to uninstall
 REBOOT=ReallySuppress = prevent reboot without warning (badly authored MSI packages)

If you don't want to uninstall via msiexec.exe, then you can find a myriad of ways to invoke an MSI uninstall here: Uninstalling an MSI file from the command line without using msiexec.

And you can find the product code of an installed MSI in several different ways: How can I find the product GUID of an installed MSI setup?


UPDATE: I guess I forgot the obvious, you can uninstall directly via MSI API automation. In the script below we get all products sharing the same upgrade code and then uninstall them in sequence.

Note that when run silently you should run with admin rights since the UAC may be suppressed and then the uninstall will usually fail (permission denied). Because of this the below script runs the uninstall interactively - allowing UAC prompting and elevation.

And if it isn't obvious: running this script will uninstall Orca! I use this product as a sample because it is quick to install again (hints on finding the installer quick if you need to towards bottom here - search for "orca"):

BIG DISCLAIMER:

The COM method installer.ConfigureProduct does not accept any arguments that allow us to pass in REBOOT=ReallySuppress. This means that a (very) badly authored package which triggers the ScheduleReboot action (or uses some more obscure magic to cause a reboot) - may reboot the system without warning if you run the below script with admin rights and in silent mode.

There is a newer call ConfigureProductEx which is available as a Win32 function, but it is not exposed via the COM automation interface. If you platform invoke you can use that call - there is a C++ example in section 14 here: Uninstalling an MSI file from the command line without using msiexec. Or you can use the DTF feature from the WiX toolkit (see section 6 in the same link as the C++ example).


UPDATE July 2018:

Set installer = CreateObject("WindowsInstaller.Installer")
installer.InstallProduct "product.msi", "REMOVE=ALL REBOOT=ReallySuppress"
Set installer = Nothing

Perhaps the above snippet is the best uninstall approach? This should suppress any reboots. I don't have the time or the setup to test it right now (on a Linux box), but I wanted to add it before I forget.


Original uninstall script:

Const msiUILevelNone = 2
Const msiInstallStateAbsent = 2

Set installer = CreateObject("WindowsInstaller.Installer")
'installer.UILevel = msiUILevelNone ' Disabled to prevent silent uninstall. Now the UAC prompt will show

' Uninstall Orca, replace upgrade code with yours
Set products = installer.RelatedProducts("{CFF4D510-79B2-1CCD-0061-5741A0565A76}")

For Each product In products
   ' MsgBox "Product Code: " & product ' Show the product code found, if you want

   ' The following call when run silently with admin rights may reboot the system without warning!
   ' This is due to badly authored MSI packages - most packages will not trigger this problem.
   installer.ConfigureProduct product, 0,  msiInstallStateAbsent ' Uninstall product

   ' See text above for info on the newer ConfigureProductEx method.
Next

Set installer = Nothing

MsgBox "Finished" ' Just so we know the script ran if nothing found to uninstall

Some Links:

Stein Åsmul
  • 34,628
  • 23
  • 78
  • 140