Following are the bits having to do with the installation and update of SQL Server express 2019. I effectively slipstream the update onto the RTM install, though this "finishing before finishing" problem was happening without the update.
#define PLATFORM "x64"
#define SQL_SERVER_EXPRESS_2019_EXE_NAME "SQLEXPR_x64_ENU.exe"
#define SQL_SERVER_CU_EXE_NAME "SQLServer2019-KB5007182-x64.exe"
[Setup]
AlwaysShowDirOnReadyPage=yes
AlwaysShowGroupOnReadyPage=yes
AppMutex=Global\{{063C236C-5096-45AA-AAAD-2604ADC08C7A}
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
DisableDirPage=yes
DisableProgramGroupPage=yes
DisableReadyMemo=yes
DisableReadyPage=yes
LZMANumBlockThreads=6
LZMAUseSeparateProcess=yes
MinVersion=10.0
SetupLogging=yes
SolidCompression=yes
TimeStampsInUTC=True
WizardResizable=no
WizardStyle=modern
[Code]
function InstallPrerequisite(const prerequisiteName, executableName, executableCommandArgs: String;
const isInstalled: Boolean): Boolean;
var
message: String;
begin
if isInstalled then
begin
LogPrerequisiteInstallStatus(prerequisiteName, isInstalled);
ClearWizardPreparingLabel;
UpdateProgressText(FmtMessage(CustomMessage('PrerequisiteInstalledCaption'), [prerequisiteName]));
Result := True;
Exit;
end;
message := FmtMessage(CustomMessage('PrerequisiteInstallingCaption'), [prerequisiteName]);
UpdateProgressText(message);
WizardForm.PreparingLabel.Caption := message;
WizardForm.PreparingLabel.Visible := True;
Log(Format('Extracting %s to %s.', [executableName, ExpandConstant('{tmp}')]));
ExtractTemporaryFile(executableName);
Log(Format('Installing %s...', [prerequisiteName]));
Result := True;
try
if not Exec(AddBackslash(ExpandConstant('{tmp}')) + executableName, executableCommandArgs, '', SW_HIDE, ewWaitUntilTerminated, ExitCode) then
begin
if ExitCode = 3010 then // This indicates that a reboot is required (at least for SQL Server installs)
begin
Log('Restart required');
NeedsRestart := True;
end
else
if ExitCode <> 0 then
begin
ShowErrorSeeLogsMessage(FmtMessage(CustomMessage('PrerequisiteInstallationFailedWithCodeMessage'), [prerequisiteName, IntToStr(ExitCode)]),
Format('%s install failed with error code %s', [prerequisiteName, IntToStr(ExitCode)]));
Result := False;
end;
end;
except
begin
ShowErrorSeeLogsMessage(GetExceptionMessage,
Format('Exception while installing %s: %s', [prerequisiteName, GetExceptionMessage]));
Result := False;
end;
finally
ClearWizardPreparingLabel;
end;
Log(Format('Exit code: %d (%s)', [ExitCode, SysErrorMessage(ExitCode)]));
if Result
and
(ExitCode = 0) then
Log(Format('%s installation successful.', [prerequisiteName]))
else
// SQL Server Cumulative Update was returning True but had an error code and hadn't completed.
// Thus, this.
begin
Log(Format('%s installation encountered errors.', [prerequisiteName]));
Result := False;
end;
end;
function DetectAndInstallSqlServerExpressInstance(const displayName: String; version: TVersion;
const executableName, configurationFile, instanceName: String): Boolean;
var
executableCommand: String;
isSqlServerVersionInstalled: Boolean;
begin
Log('Installing SQL Server...');
// Even though ACTION (and HIDECONSOLE and UPDATEENABLED) is set in the configuration file, it was getting ignored and has to be set explicitly here.
// SKIPRULES is undocumented (so could become non-functional)
// Include update with regular install
// (per
https://docs.microsoft.com/en-us/sql/database-engine/install-windows/installing-updates-from-the-command-prompt?view=sql-server-ver15)
executableCommand := '/Q /X:"' + AddBackslash(ExpandConstant('{tmp}')) + '{#PRODUCT_DIRECTORY_TREE_FRAGMENT}' + '"'
+ ' /ACTION="INSTALL" /INSTANCENAME="' + instanceName + '" /INSTANCEID="' + instanceName + '"'
+ ' /IAcceptSQLServerLicenseTerms="True"'
+ ' /UpdateEnabled=True /UpdateSource="'+ ExpandConstant('{tmp}') + '"'
+ ' /SQLTELSVCACCT="NT Service\SQLTELEMETRY$' + instanceName + '"'
+ ' /HIDECONSOLE /SKIPRULES=RebootRequiredCheck'
+ ' /ConfigurationFile="'+ AddBackslash(ExpandConstant('{tmp}')) + configurationFile + '"';
isSqlServerVersionInstalled := SqlServerExpressVersionIsInstalled(version, instanceName);
if not isSqlServerVersionInstalled then
begin
ExtractTemporaryFile(configurationFile);
ExtractTemporaryFile('{#SQL_SERVER_CU_EXE_NAME}');
end;
Result := InstallPrerequisite(displayName, executableName, executableCommand, isSqlServerVersionInstalled);
Log('Completed SQL Server prerequisite.');
end;
[Files]
; Prerequisite files
Source: "Prerequisites\SqlServerExpress2019\{#SQL_SERVER_INSTALLATION_CONFIGURATION_FILENAME}"; Flags: dontcopy noencryption
Source: "Prerequisites\SqlServerExpress2019\{#SQL_SERVER_EXPRESS_2019_EXE_NAME}"; Flags: dontcopy noencryption
Source: "Prerequisites\SqlServer2019CumulativeUpdate\{#SQL_SERVER_CU_EXE_NAME}"; Flags: dontcopy noencryption