[wix-users] Programmatically removing a bundle

Phill Hogland phill.hogland at rimage.com
Wed Feb 17 09:47:21 PST 2016


I also support scenarios where non-wix applications need to locate and launch my bundle.  The approach that I developed back in the wix3.7 era before Jacob did his work with the dutil.dll also relies on setting the Bundle/@ProviderKey to a known GUID, and fishing the BundleId out of the BootstrapperData.xml, to pass to a MSI to write to a common location for the external app to later lookup and build the ARP registry key for the bundle.  (Others have taken a different approach that involves compiling code from the wix source dutil.dll project and using the UpgradeCode with that code.)

For scenarios where an external app is not involved and it is just a newer version of the wix bundle trying to remove an older version of a wix bundle with the same upgradecode, the above approach (particularly setting the Bundle/@ProviderKey are not needed as Rob indicated.  But for all of my bundles I always define a ProviderKey, UpgradeCode, and RelatedBundle detect code which remains stable between builds of that bundle (product suite).  This has worked well for me.

-----Original Message-----
From: wix-users [mailto:wix-users-bounces at lists.wixtoolset.org] On Behalf Of Dan Parker
Sent: Wednesday, February 17, 2016 11:22 AM
To: WiX Toolset Users Mailing List <wix-users at lists.wixtoolset.org>
Subject: Re: [wix-users] Programmatically removing a bundle

I have a similar issue where I had to automatically deploy a bootstrapper to N PCs first by uninstalling the old one, without any user interactivity. Here's what I had to do to get this to happen:

First in the bundle WXS, set a dep:ProviderKey on the Bundle element. This is important, because you have a stable bundle bundle provider key to look up the installed bundle in the ARP registry key.

Second in my code, I wrote these two methods to look up something in the ARP by bundle provider key and run the uninstall script associated with it (sorry, it's C#):

        static int RunUninstallBootstrapper(string testSuiteName)
        {
            string[] uninstallLocations = new string[]
            {
                @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
                @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
            };
            string logFileName = GetCustomLogPath(testSuiteName, "uninstall.txt");
            int rc = 0;

            Console.Out.WriteLine("Uninstalling test suite. Log={0}", logFileName);

            using (StreamWriter sw = new StreamWriter(logFileName, true))
            {
                sw.AutoFlush = true;

                foreach (string productId in Properties.Settings.Default.TestSuiteProductIds)
                {
                    sw.WriteLine("Looking for '{0}'", productId);
                    Installer type;
                    string productCode = GetProductId(productId, out type);
                    sw.Write("Type: {0}  code: {1}", type, productCode);

                    if (type == Installer.Bundle || type == Installer.Exe)
                    {
                        foreach (string uninstallLocation in uninstallLocations)
                        {
                            using (RegistryKey uninstallKey = Registry.LocalMachine.OpenSubKey(uninstallLocation))
                            {
                                if (uninstallKey != null)
                                {
                                    sw.WriteLine("In key '{0}'", uninstallLocation);
                                    if (!ArpUninstall(sw, logFileName, productCode, type, uninstallKey, ref rc))
                                    {
                                        sw.WriteLine("Uninstaller failed. rc={0}", rc);
                                        return rc;
                                    }
                                }
                            }
                        }
                    }
                    else if (type == Installer.Msi)
                    {
                        MsiUninstall(sw, logFileName, productCode);
                    }
                    else
                    {
                        throw new InvalidOperationException();
                    }
                }
            }

            return rc;
        }

        static bool ArpUninstall(StreamWriter sw, string logFileName, string productCode, Installer installerType, RegistryKey uninstallKey, ref int rc)
        {
            foreach (string subKeyName in uninstallKey.GetSubKeyNames())
            {
                using (RegistryKey productKey = uninstallKey.OpenSubKey(subKeyName))
                {
                    if (productKey != null)
                    {
                        string compareString;
                        if (installerType == Installer.Bundle)
                        {
                            compareString = (string)productKey.GetValue("BundleProviderKey", String.Empty);
                        }
                        else if (installerType == Installer.Exe || installerType == Installer.Msi)
                        {
                            compareString = uninstallKey.Name;
                        }
                        else
                        {
                            throw new InvalidOperationException();
                        }
                        compareString = compareString.Trim();
                        string uninstallString = GetUninstallString(logFileName, productKey, installerType);

                        if (String.Compare(productCode, compareString, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            sw.WriteLine("Uninstalling product '{0}'", productCode);
                            sw.WriteLine("Uninstall string: '{0}'", uninstallString);
                            if (String.IsNullOrEmpty(uninstallString))
                            {
                                sw.WriteLine("Product does not specify an uninstall string. Skipping.");
                                if (rc == 0)
                                {
                                    rc = -1;
                                }
                                continue;
                            }

                            using (Process p = new Process())
                            {
                                string cmdExe = Path.Combine(Environment.SystemDirectory, @"cmd.exe");
                                uninstallString = @"/c """ + uninstallString + @"""";
                                sw.WriteLine(@"Running command: ""{0}"" {1}", cmdExe, uninstallString);
                                p.StartInfo.FileName = cmdExe;
                                p.StartInfo.CreateNoWindow = true;
                                p.StartInfo.Arguments = uninstallString;
                                p.StartInfo.UseShellExecute = false;
                                if (!p.Start())
                                {
                                    sw.WriteLine("Failed to start uninstaller.");
                                    if (rc == 0)
                                    {
                                        rc = -1;
                                    }
                                    return false;
                                }
                                p.WaitForExit();
                                sw.WriteLine("Exit Code: '{0}'", p.ExitCode);
                                rc = p.ExitCode;
                                break;
                            }
                        }
                    }
                }
            }
            return true;
        }

It worked for my bundle, but you may have to tweak it for yours.

-----Original Message-----
From: wix-users [mailto:wix-users-bounces at lists.wixtoolset.org] On Behalf Of Tomer Kimia
Sent: Wednesday, February 17, 2016 9:14 AM
To: wix-users at lists.wixtoolset.org
Subject: [wix-users] Programmatically removing a bundle

Hello all,

We have a Bootstrapper installing two MSIs, let's call them PROD1 and PROD2. We'd like to uninstall the Bootstrapper programmatically, via PowerShell.

We currently use get-wmi and retrieve Win32_Product, but that lists entries for PROD1 and PROD2 rather than the Bootstrapper.

Does anyone know how to programmatically uninstall your Bootstrapper without knowing its location?

Tomer K Software Engineer tkimia at factset.com<mailto:tkimia at factset.com>



____________________________________________________________________
WiX Toolset Users Mailing List provided by FireGiant https://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2fwww.firegiant.com%2f&data=01%7c01%7cDaniel.Parker%40microsoft.com%7cba956b40e3c94a57b3be08d337bdb9c3%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=kloOrKT5CDLz5FMegk%2bVPd6E0iNFDAT5u0Zg9zSf4Uc%3d

____________________________________________________________________
WiX Toolset Users Mailing List provided by FireGiant http://www.firegiant.com/


More information about the wix-users mailing list