[wix-users] Programmatically removing a bundle
Dan Parker
Daniel.Parker at microsoft.com
Wed Feb 17 09:22:22 PST 2016
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
More information about the wix-users
mailing list