Skip to content

Commit 7ee07db

Browse files
benhillisBen HillisCopilot
authored
Suppress MSI-initiated reboots during Store updates (#40079)
When the WSL MSIX package is updated via the Microsoft Store, the WslInstaller service automatically upgrades the MSI package by calling MsiInstallProduct. This call was made with INSTALLUILEVEL_NONE (silent install) but without setting the REBOOT=ReallySuppress property. Per Windows Installer documentation, when a silent install encounters files in use and REBOOT is not suppressed, the system reboots automatically without any user prompt. This could cause unexpected machine restarts after a Store update when WSL binaries (e.g. wslservice.exe) were in use during the upgrade. Every deployment script in the repo already passes /norestart to msiexec (deploy-to-host.ps1, deploy-to-vm.ps1, install-latest-wsl.ps1, test-setup.ps1), but the programmatic MsiInstallProduct path used by the WslInstaller service lacked the equivalent property. This change: - Always appends REBOOT=ReallySuppress to MsiInstallProduct arguments in UpgradeViaMsi, preventing Windows Installer from ever initiating a system restart during install/upgrade. - Switches UninstallViaMsi from MsiConfigureProduct to MsiConfigureProductEx so we can pass REBOOT=ReallySuppress during uninstall as well. - Propagates ERROR_SUCCESS_REBOOT_REQUIRED (3010) to callers instead of swallowing it. User-facing paths (wsl --update, wsl --uninstall) print a reboot-needed message to stderr. The background WslInstaller service silently treats 3010 as success since it has no console. Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 11ae8b2 commit 7ee07db

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

src/windows/common/WslClient.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,11 @@ int Uninstall()
12771277

12781278
const auto exitCode = wsl::windows::common::install::UninstallViaMsi(logFile.c_str(), &wsl::windows::common::install::MsiMessageCallback);
12791279

1280-
if (exitCode != 0)
1280+
if (exitCode == ERROR_SUCCESS_REBOOT_REQUIRED)
1281+
{
1282+
wsl::windows::common::wslutil::PrintSystemError(ERROR_SUCCESS_REBOOT_REQUIRED);
1283+
}
1284+
else if (exitCode != 0)
12811285
{
12821286
clearLogs.release();
12831287
THROW_HR_WITH_USER_ERROR(

src/windows/common/install.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,11 @@ int UpdatePackageImpl(bool preRelease, bool repair)
104104

105105
const auto exitCode = UpgradeViaMsi(downloadPath.c_str(), L"", logFile.c_str(), &MsiMessageCallback);
106106

107-
if (exitCode != 0)
107+
if (exitCode == ERROR_SUCCESS_REBOOT_REQUIRED)
108+
{
109+
PrintSystemError(ERROR_SUCCESS_REBOOT_REQUIRED);
110+
}
111+
else if (exitCode != 0)
108112
{
109113
clearLogs.release();
110114
THROW_HR_WITH_USER_ERROR(
@@ -358,15 +362,20 @@ int wsl::windows::common::install::UpdatePackage(bool PreRelease, bool Repair)
358362
UINT wsl::windows::common::install::UpgradeViaMsi(
359363
_In_ LPCWSTR PackageLocation, _In_opt_ LPCWSTR ExtraArgs, _In_opt_ LPCWSTR LogFile, _In_ const std::function<void(INSTALLMESSAGE, LPCWSTR)>& Callback)
360364
{
361-
WriteInstallLog(std::format("Upgrading via MSI package: {}. Args: {}", PackageLocation, ExtraArgs != nullptr ? ExtraArgs : L""));
365+
// Always suppress MSI-initiated reboots. With INSTALLUILEVEL_NONE, Windows Installer
366+
// will silently reboot the machine if files are in use and REBOOT is not suppressed.
367+
std::wstring args = L"REBOOT=ReallySuppress";
368+
if (ExtraArgs != nullptr && *ExtraArgs != L'\0')
369+
{
370+
args = std::wstring(ExtraArgs) + L" " + args;
371+
}
372+
373+
WriteInstallLog(std::format("Upgrading via MSI package: {}. Args: {}", PackageLocation, args));
362374

363375
ConfigureMsiLogging(LogFile, Callback);
364376

365-
auto result = MsiInstallProduct(PackageLocation, ExtraArgs);
366-
WSL_LOG(
367-
"MsiInstallResult",
368-
TraceLoggingValue(result, "result"),
369-
TraceLoggingValue(ExtraArgs != nullptr ? ExtraArgs : L"", "ExtraArgs"));
377+
auto result = MsiInstallProduct(PackageLocation, args.c_str());
378+
WSL_LOG("MsiInstallResult", TraceLoggingValue(result, "result"), TraceLoggingValue(args.c_str(), "ExtraArgs"));
370379

371380
WriteInstallLog(std::format("MSI upgrade result: {}", result));
372381

@@ -382,7 +391,7 @@ UINT wsl::windows::common::install::UninstallViaMsi(_In_opt_ LPCWSTR LogFile, _I
382391

383392
ConfigureMsiLogging(LogFile, Callback);
384393

385-
auto result = MsiConfigureProduct(productCode.c_str(), 0, INSTALLSTATE_ABSENT);
394+
auto result = MsiConfigureProductEx(productCode.c_str(), 0, INSTALLSTATE_ABSENT, L"REBOOT=ReallySuppress");
386395
WSL_LOG("MsiUninstallResult", TraceLoggingValue(result, "result"));
387396

388397
WriteInstallLog(std::format("MSI package uninstall result: {}", result));

src/windows/wslinstaller/exe/WslInstaller.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,20 @@ std::pair<UINT, std::wstring> InstallMsipackageImpl()
7979
auto result = wsl::windows::common::install::UpgradeViaMsi(
8080
GetMsiPackagePath().c_str(), L"SKIPMSIX=1", logFile.has_value() ? logFile->c_str() : nullptr, messageCallback);
8181

82-
WSL_LOG("MSIUpgradeResult", TraceLoggingValue(result, "result"), TraceLoggingValue(errors.c_str(), "errorMessage"));
82+
// ERROR_SUCCESS_REBOOT_REQUIRED (3010) means the install succeeded but some files
83+
// will be replaced on the next reboot. Treat as success since the service runs
84+
// silently with no user-facing console.
85+
const bool rebootRequired = (result == ERROR_SUCCESS_REBOOT_REQUIRED);
86+
if (rebootRequired)
87+
{
88+
result = ERROR_SUCCESS;
89+
}
90+
91+
WSL_LOG(
92+
"MSIUpgradeResult",
93+
TraceLoggingValue(result, "result"),
94+
TraceLoggingValue(rebootRequired, "rebootRequired"),
95+
TraceLoggingValue(errors.c_str(), "errorMessage"));
8396

8497
return {result, errors};
8598
}

0 commit comments

Comments
 (0)