wixexeupgradeuninstallationbootstrapper

Wix not installing new exe package after old package is removed


I am trying to uninstall SqlServer 2017 and install SqlServer 2022. It is uninstalling SqlServer 2017 but never installing the 2022. Please help.

I have a class named RemoveSql2017.cs that's as follows:

 public class RemoveSQL2017
    {
        const string UNINSTALL_SQL_2017 = "/Action=Uninstall /INSTANCENAME=PHARMSPEC /FEATURES=SQL /QS /HIDECONSOLE";
        const string sqlFile = "DetachPharmSpecDB.sql";
        const string DB_INSTANCE = "PHARMSPEC";
        const int COMMAND_LINE_WAIT = 10000;
        private static WixBootstrapper _bootstrapper;
        const string registryKey = @"SOFTWARE\HIAC\PharmSpec\Database";
        const string subKeyValue = "DataPath";

        public RemoveSQL2017(WixBootstrapper bootstrapper)
        {
            _bootstrapper = bootstrapper;
        }

        public void Remove(string bootStrapFolder, string dataFilePath)
        {
            CreateDetachSQLFile();
            CopyFiles(dataFilePath);
            UninstallSQL(bootStrapFolder);
            DeleteDBRegistryPath();
        }
        public static void UninstallSQL(string bootstrapFolder)
        {
            try
            {
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Beginning UninstallSQL; bootstrapFolder=" + bootstrapFolder);
                Process process = new Process();
                ProcessStartInfo startInfo = new ProcessStartInfo(bootstrapFolder + "//SQL2017//setup.exe", UNINSTALL_SQL_2017);
                process.StartInfo = startInfo;
                process.Start();
                process.WaitForExit();
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Completing UninstallSQL; bootstrapFolder=" + bootstrapFolder);
            }
            catch (Exception e)
            {
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Error in UninstallSQL:\n " + e.ToString());
                throw (e);
            }
        }
        public static void CopyFiles(string dataFilePath)
        {
            try
            {
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Beginning CopyFiles; dataFilePath=" + dataFilePath + "  tempDBFilePath=" + Globals.tempDBFilePath);
                File.Copy(Path.Combine(dataFilePath, Globals.MDF_FILE), Path.Combine(Globals.tempDBFilePath, Globals.MDF_FILE));
                File.Copy(Path.Combine(dataFilePath, Globals.LDF_FILE), Path.Combine(Globals.tempDBFilePath, Globals.LDF_FILE));
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Completing CopyFiles; dataFilePath=" + dataFilePath + "  tempDBFilePath=" + Globals.tempDBFilePath);
            }
            catch (Exception e)
            {
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Error in CopyFiles:\n " + e.ToString());
            }
        }
        public static void DetachDB(string sqlFilePath)
        {
            try
            {
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Beginning DetachDB; sqlFilePath=" + sqlFilePath);
                string command = string.Format("-S .\\{0} -E -i \"{1}\"", DB_INSTANCE, sqlFilePath);
                ProcessStartInfo info = new ProcessStartInfo("sqlcmd", command);
                info.UseShellExecute = false;
                info.CreateNoWindow = false;
                info.WindowStyle = ProcessWindowStyle.Hidden;
                Process proc = new Process();
                proc.StartInfo = info;
                proc.StartInfo.RedirectStandardOutput = true;
                proc.Start();
                string outputD = proc.StandardOutput.ReadToEnd();
                if (proc.WaitForExit(COMMAND_LINE_WAIT))
                {
                    _bootstrapper.Engine.Log(LogLevel.Verbose, outputD);
                }
                else
                {
                    _bootstrapper.Engine.Log(LogLevel.Verbose, "Process timeout in DetachDb");
                }
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Completing DetachDB; sqlFilePath=" + sqlFilePath);
            }
            catch (Exception e)
            {
                _bootstrapper.Engine.Log(LogLevel.Verbose, "Error in DetachDB:\n " + e.ToString());
                throw (e);
            }
        }
        public static void CreateDetachSQLFile()
        {
            try
            {
                string sqlFilePath = Path.Combine(Path.GetTempPath(), sqlFile);
                var sqlScript = new StringBuilder();
                sqlScript.AppendLine("GO");
                sqlScript.AppendLine("IF EXISTS (SELECT * FROM sysdatabases WHERE name = N'PharmSpecDB')");
                sqlScript.AppendLine("use PharmSpecDB");
                sqlScript.AppendLine("DROP SCHEMA PharmSpecUsr");
                sqlScript.AppendLine("DROP USER PharmSpecUsr");
                sqlScript.AppendLine("use master");
                sqlScript.AppendLine("EXEC sp_detach_db 'PharmSpecDB'");
                sqlScript.AppendLine("GO");
                sqlScript.AppendLine("IF EXISTS (SELECT * FROM syslogins WHERE name = N'PharmSpecUsr')");
                sqlScript.AppendLine("DROP LOGIN PharmSpecUsr");
                sqlScript.AppendLine("GO");
                using (StreamWriter sw = new StreamWriter(sqlFilePath))
                {
                    sw.Write(sqlScript.ToString());
                }
                DetachDB(sqlFilePath);
            }
            catch (Exception e)
            {
                _bootstrapper.Engine.Log(LogLevel.Verbose, "error in CreateDetachSQLFile:\n " + e.ToString());
                throw (e);
            }
        }

        public static void DeleteDBRegistryPath()
        {
            try
            {
                using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
                {
                    RegistryKey subkey = key.OpenSubKey(registryKey, true);
                    if (subkey != null)
                    {
                        subkey.DeleteValue(subKeyValue);
                    }           
                }
            }
            catch (Exception e)
            {
                _bootstrapper.Engine.Log(LogLevel.Verbose, "error in DeleteDBRegistryPath:\n" + e.ToString());
            }
        }

I am calling this class as follows: I am able to see SqlServer 2017 getting uninstalled.

 if (Bootstrapper.Engine.StringVariables["PreviousVersion"].CompareTo("3.5.99") <= 0 &&
               Bootstrapper.Engine.StringVariables["SqlInstanceKeyFound64"] == "1")
                {
                    RemoveSQL2017 removeSQL = new RemoveSQL2017(Bootstrapper);
                    removeSQL.Remove(Bootstrapper.Engine.StringVariables["DB2017SETUP"], Bootstrapper.Engine.StringVariables["2017DBDataPath"]);
                    Bootstrapper.Engine.StringVariables["OLDDBDATAPATH"] = Globals.tempDBFilePath;
                    Bootstrapper.Engine.StringVariables["INSTALLSQL"] = "1";
                }

I have a SqlServer.wxi in which the registry keys and the exe file are as follows. Before removing SqlServer2017 this is what is in the registry,

Registry

SqlServer.wxi

<Variable Name="SqlInstanceKeyFound" Value="0"/>
        <Variable Name="SqlInstanceKeyFound64" Value="0"/>
<util:RegistrySearch
          Id="SqlInstanceKeyFound64"
          Root="HKLM" Key="SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL" Value="PHARMSPEC"
          Result="exists" Variable="SqlInstanceKeyFound64" Win64="yes"/>
        <util:RegistrySearch
          Id="SqlInstanceKey64"
          Root="HKLM" Key="SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL" Value="PHARMSPEC"
          Variable="SqlInstanceKey64" After="SqlInstanceKeyFound64" Condition="SqlInstanceKeyFound64" Win64="yes" />
        <util:RegistrySearch
          Id="SqlInstanceFound64"
          Root="HKLM" Key="SOFTWARE\Microsoft\Microsoft SQL Server\[SqlInstanceKey64]"
          Result="exists" Variable="SqlInstanceFound64" After="SqlInstanceKey64" Condition="SqlInstanceKeyFound64" Win64="yes" />
        <util:RegistrySearch
          Id="SqlVersion64"
          Root="HKLM" Key="SOFTWARE\Microsoft\Microsoft SQL Server\[SqlInstanceKey64]\Setup" Value="Version"
          Variable="SqlVersion64" After="SqlInstanceKey64" Condition="SqlInstanceFound64" Win64="yes" />

 <PackageGroup Id="SQL2022Express">
      <ExePackage Id="SQL2022Express"
              DisplayName="SQL Server 2022 Express"
              Cache="yes"
              Compressed="no"
              PerMachine="yes"
              Permanent="no"
              Vital="yes"
              DetectCondition="SqlInstanceFound64"
              InstallCondition="INSTALLSQL=1"
              Name="Redist\SQLEXPR_x64_!(loc.LANG).exe"
              SourceFile="$(var.DependencyFolder)\SQLEXPR_x64_!(loc.LANG).exe"
              InstallCommand="/ACTION=Install /IACCEPTSQLSERVERLICENSETERMS [SQLQUIET] /HIDECONSOLE /FEATURES=SQLEngine /UpdateEnabled=0 /INSTANCENAME=PHARMSPEC /SQLSYSADMINACCOUNTS=Builtin\Administrators /SQLSVCACCOUNT=&quot;NT AUTHORITY\NETWORK SERVICE&quot; /SECURITYMODE=SQL /SAPWD=[SAPASSWORD] /NPENABLED=1 /TCPENABLED=1 /SKIPRULES=RebootRequiredCheck"
              UninstallCommand="/Action=Uninstall /INSTANCENAME=PHARMSPEC /FEATURES=SQL /QS /HIDECONSOLE">
        <ExitCode Value ="3010" Behavior="forceReboot" />
      </ExePackage>
    </PackageGroup>

In the log its showing the following:


Solution

  • SqlInstanceFound64 variable was found, which is used in your DetectCondition to indicate that SQL Express 2022 was already installed. The bundle will not install something that already exists.

    I think you need to search for a registry key (or something) that is unique to SQL Express 2022. What you're looking at right now seems to be set by many versions of SQL Express.