@samitouri / QOSAMI-WSL / commits / e0c6196c

Create a persistent install log file to help root cause package upgrade issues (#13500)

* Create a persistent install log file to help root cause package upgrade issues * Update src/windows/common/wslutil.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Collect log file in diagnostic script --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

Blue committed Oct 1, 2025 at 15:40 UTC e0c6196cd5185f253040701a375c27959e5b091e
7 files changed +99 -5
diagnostics/collect-wsl-logs.ps1
+2
@@ -56,6 +56,8 @@ if (Test-Path $wslconfig)
56 Copy-Item $wslconfig $folder | Out-Null
57 }
58
59 +Copy-Item "C:\Windows\temp\wsl-install-log.txt" $folder -ErrorAction ignore
60 +
61 get-appxpackage MicrosoftCorporationII.WindowsSubsystemforLinux -ErrorAction Ignore > $folder/appxpackage.txt
62 get-acl "C:\ProgramData\Microsoft\Windows\WindowsApps" -ErrorAction Ignore | Format-List > $folder/acl.txt
63 Get-WindowsOptionalFeature -Online > $folder/optional-components.txt
msipackage/package.wix.in
+10
@@ -397,6 +397,14 @@
397 Execute="deferred"
398 />
399
400 + <CustomAction Id="FinalizeInstall"
401 + Impersonate="no"
402 + BinaryRef="wslinstall.dll"
403 + DllEntry="WslFinalizeInstallation"
404 + Return="check"
405 + Execute="deferred"
406 + />
407 +
408 <CustomAction Id="DeprovisionMsix"
409 Impersonate="no"
410 BinaryRef="wslinstall.dll"
@@ -533,6 +541,8 @@
541 <Custom Action="CalculateWslSettingsProtocolIds" Before="WriteRegistryValues" Condition='(not REMOVE~="ALL")' />
542 <?endif?>
543
544 + <Custom Action="FinalizeInstall" After="PublishFeatures"/>
545 +
546 </InstallExecuteSequence>
547
548 <!-- Don't show a 'Modify' button in settings since there is nothing to modify -->
src/windows/common/wslutil.cpp
+55 -1
@@ -135,6 +135,7 @@ static const std::map<HRESULT, LPCWSTR> g_commonErrors{
135 X_WIN32(ERROR_INVALID_SECURITY_DESCR),
136 X(VM_E_INVALID_STATE),
137 X_WIN32(STATUS_SHUTDOWN_IN_PROGRESS),
138 + X_WIN32(ERROR_BAD_PATHNAME),
139 X(WININET_E_TIMEOUT)};
140
141 #undef X
@@ -1344,10 +1345,17 @@ int WINAPI InstallRecordHandler(void* context, UINT messageType, LPCWSTR message
1345 try
1346 {
1347 WSL_LOG("MSIMessage", TraceLoggingValue(messageType, "type"), TraceLoggingValue(message, "message"));
1348 + auto type = (INSTALLMESSAGE)(0xFF000000 & (UINT)messageType);
1349 +
1350 + if (type == INSTALLMESSAGE_ERROR || type == INSTALLMESSAGE_FATALEXIT || type == INSTALLMESSAGE_WARNING)
1351 + {
1352 + WriteInstallLog(std::format("MSI message: {}", message));
1353 + }
1354 +
1355 auto* callback = reinterpret_cast<const std::function<void(UINT, LPCWSTR)>*>(context);
1356 if (callback != nullptr)
1357 {
1350 - (*callback)((INSTALLMESSAGE)(0xFF000000 & (UINT)messageType), message);
1358 + (*callback)(type, message);
1359 }
1360 }
1361 CATCH_LOG();
@@ -1401,6 +1409,8 @@ int wsl::windows::common::wslutil::UpdatePackage(bool PreRelease, bool Repair)
1409 UINT wsl::windows::common::wslutil::UpgradeViaMsi(
1410 _In_ LPCWSTR PackageLocation, _In_opt_ LPCWSTR ExtraArgs, _In_opt_ LPCWSTR LogFile, _In_ const std::function<void(INSTALLMESSAGE, LPCWSTR)>& Callback)
1411 {
1412 + WriteInstallLog(std::format("Upgrading via MSI package: {}. Args: {}", PackageLocation, ExtraArgs != nullptr ? ExtraArgs : L""));
1413 +
1414 ConfigureMsiLogging(LogFile, Callback);
1415
1416 auto result = MsiInstallProduct(PackageLocation, ExtraArgs);
@@ -1409,6 +1419,8 @@ UINT wsl::windows::common::wslutil::UpgradeViaMsi(
1419 TraceLoggingValue(result, "result"),
1420 TraceLoggingValue(ExtraArgs != nullptr ? ExtraArgs : L"", "ExtraArgs"));
1421
1422 + WriteInstallLog(std::format("MSI upgrade result: {}", result));
1423 +
1424 return result;
1425 }
1426
@@ -1417,10 +1429,15 @@ UINT wsl::windows::common::wslutil::UninstallViaMsi(_In_opt_ LPCWSTR LogFile, _I
1429 const auto key = OpenLxssMachineKey(KEY_READ);
1430 const auto productCode = ReadString(key.get(), L"Msi", L"ProductCode", nullptr);
1431
1432 + WriteInstallLog(std::format("Uninstalling MSI package: {}", productCode));
1433 +
1434 ConfigureMsiLogging(LogFile, Callback);
1435
1436 auto result = MsiConfigureProduct(productCode.c_str(), 0, INSTALLSTATE_ABSENT);
1437 WSL_LOG("MsiUninstallResult", TraceLoggingValue(result, "result"));
1438 +
1439 + WriteInstallLog(std::format("MSI package uninstall result: {}", result));
1440 +
1441 return result;
1442 }
1443
@@ -1451,6 +1468,43 @@ wil::unique_hfile wsl::windows::common::wslutil::ValidateFileSignature(LPCWSTR P
1468 return fileHandle;
1469 }
1470
1471 +void wsl::windows::common::wslutil::WriteInstallLog(const std::string& Content)
1472 +try
1473 +{
1474 + static std::wstring path = wil::GetWindowsDirectoryW<std::wstring>() + L"\\temp\\wsl-install-log.txt";
1475 +
1476 + // Wait up to 10 seconds for the log file mutex
1477 + wil::unique_handle mutex{CreateMutex(nullptr, true, L"Global\\WslInstallLog")};
1478 + THROW_LAST_ERROR_IF(!mutex);
1479 +
1480 + THROW_LAST_ERROR_IF(WaitForSingleObject(mutex.get(), 10 * 1000) != WAIT_OBJECT_0);
1481 +
1482 + wil::unique_handle file{CreateFile(
1483 + path.c_str(), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_ALWAYS, 0, nullptr)};
1484 +
1485 + THROW_LAST_ERROR_IF(!file);
1486 +
1487 + LARGE_INTEGER size{};
1488 + THROW_IF_WIN32_BOOL_FALSE(GetFileSizeEx(file.get(), &size));
1489 +
1490 + // Append to the file if its size is below 10MB, otherwise truncate.
1491 + if (size.QuadPart < 10 * _1MB)
1492 + {
1493 + THROW_LAST_ERROR_IF(SetFilePointer(file.get(), 0, nullptr, FILE_END) == INVALID_SET_FILE_POINTER);
1494 + }
1495 + else
1496 + {
1497 + THROW_IF_WIN32_BOOL_FALSE(SetEndOfFile(file.get()));
1498 + }
1499 +
1500 + static auto processName = wil::GetModuleFileNameW<std::wstring>();
1501 + auto logLine = std::format("{:%FT%TZ} {}[{}]: {}\n", std::chrono::system_clock::now(), processName, WSL_PACKAGE_VERSION, Content);
1502 +
1503 + DWORD bytesWritten{};
1504 + THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), logLine.c_str(), static_cast<DWORD>(logLine.size()), &bytesWritten, nullptr));
1505 +}
1506 +CATCH_LOG();
1507 +
1508 winrt::Windows::Management::Deployment::PackageVolume wsl::windows::common::wslutil::GetSystemVolume()
1509 try
1510 {
src/windows/common/wslutil.h
+2
@@ -181,6 +181,8 @@ UINT UpgradeViaMsi(_In_ LPCWSTR PackageLocation, _In_opt_ LPCWSTR ExtraArgs, _In
181
182 UINT UninstallViaMsi(_In_opt_ LPCWSTR LogFile, _In_ const std::function<void(INSTALLMESSAGE, LPCWSTR)>& callback);
183
184 +void WriteInstallLog(const std::string& Content);
185 +
186 winrt::Windows::Management::Deployment::PackageVolume GetSystemVolume();
187
188 } // namespace wsl::windows::common::wslutil
src/windows/wslinstall/DllMain.cpp
+20
@@ -23,6 +23,7 @@ Abstract:
23 using unique_msi_handle = wil::unique_any<MSIHANDLE, decltype(MsiCloseHandle), &MsiCloseHandle>;
24
25 using namespace wsl::windows::common::registry;
26 +using namespace wsl::windows::common::wslutil;
27
28 static constexpr auto c_progIdPrefix{L"App."};
29 static constexpr auto c_protocolProgIdSuffix{L".Protocol"};
@@ -519,6 +520,7 @@ extern "C" UINT __stdcall DeprovisionMsix(MSIHANDLE install)
520 try
521 {
522 WSL_LOG("DeprovisionMsix");
523 + WriteInstallLog("MSI install: DeprovisionMsix");
524
525 const winrt::Windows::Management::Deployment::PackageManager packageManager;
526 const auto result = packageManager.DeprovisionPackageForAllUsersAsync(wsl::windows::common::wslutil::c_msixPackageFamilyName).get();
@@ -542,6 +544,7 @@ extern "C" UINT __stdcall RemoveMsixAsSystem(MSIHANDLE install)
544 try
545 {
546 WSL_LOG("RemoveMsixAsSystem");
547 + WriteInstallLog("MSI install: RemoveMsixAsSystem");
548
549 const winrt::Windows::Management::Deployment::PackageManager packageManager;
550
@@ -571,6 +574,7 @@ extern "C" UINT __stdcall RemoveMsixAsUser(MSIHANDLE install)
574 try
575 {
576 WSL_LOG("RemoveMsixAsUser");
577 + WriteInstallLog("MSI install: RemoveMsixAsUser");
578
579 const winrt::Windows::Management::Deployment::PackageManager packageManager;
580
@@ -640,6 +644,7 @@ extern "C" UINT __stdcall InstallMsixAsUser(MSIHANDLE install)
644 try
645 {
646 WSL_LOG("InstallMsixAsUser");
647 + WriteInstallLog("MSI install: InstallMsixAsUser");
648
649 // RegisterPackageByFamilyNameAsync() cannot be run as SYSTEM.
650 // If this thread runs as SYSTEM, simply skip this step.
@@ -683,6 +688,7 @@ try
688 msixFile.Handle.reset();
689
690 WSL_LOG("InstallMsix", TraceLoggingValue(msixFile.Path.c_str(), "Path"));
691 + WriteInstallLog("MSI install: InstallMsix");
692
693 winrt::Windows::Management::Deployment::PackageManager packageManager;
694
@@ -780,11 +786,25 @@ catch (...)
786 return ERROR_INSTALL_FAILURE;
787 }
788
789 +extern "C" UINT __stdcall WslFinalizeInstallation(MSIHANDLE install)
790 +{
791 + try
792 + {
793 + WSL_LOG("WslFinalizeInstallation");
794 + WriteInstallLog(std::format("MSI install: WslFinalizeInstallation"));
795 + }
796 + CATCH_LOG();
797 +
798 + return NOERROR;
799 +}
800 +
801 extern "C" UINT __stdcall WslValidateInstallation(MSIHANDLE install)
802 try
803 {
804 WSL_LOG("WslValidateInstallation");
805
806 + WriteInstallLog(std::format("MSI install: WslValidateInstallation"));
807 +
808 // TODO: Use a more precise version check so we don't install if the Windows build doesn't support lifted.
809
810 if (wsl::windows::common::helpers::GetWindowsVersion().BuildNumber < wsl::windows::common::helpers::Vibranium)
src/windows/wslinstall/wslinstall.def
+1
@@ -5,6 +5,7 @@ EXPORTS
5 CleanMsixState
6 DeprovisionMsix
7 WslValidateInstallation
8 + WslFinalizeInstallation
9 InstallMsix
10 InstallMsixAsUser
11 RegisterLspCategories
src/windows/wslinstaller/exe/WslInstaller.cpp
+9 -4
@@ -102,7 +102,7 @@ DWORD WINAPI InstallMsiPackage(LPVOID Context)
102 return 0;
103 }
104
105 -bool IsUpdateNeeded()
105 +std::pair<bool, std::wstring> IsUpdateNeeded()
106 {
107 try
108 {
@@ -115,13 +115,15 @@ bool IsUpdateNeeded()
115 TraceLoggingLevel(WINEVENT_LEVEL_INFO),
116 TraceLoggingValue(installedVersion.c_str(), "InstalledVersion"));
117
118 - return installedVersion.empty() || wsl::windows::common::wslutil::ParseWslPackageVersion(installedVersion) < wsl::shared::PackageVersion;
118 + return std::make_pair(
119 + installedVersion.empty() || wsl::windows::common::wslutil::ParseWslPackageVersion(installedVersion) < wsl::shared::PackageVersion,
120 + installedVersion);
121 }
122 catch (...)
123 {
124 LOG_CAUGHT_EXCEPTION();
125
124 - return false;
126 + return std::make_pair(false, L"");
127 }
128 }
129
@@ -132,11 +134,14 @@ std::shared_ptr<InstallContext> LaunchInstall()
134
135 auto lock = mutex.lock_exclusive();
136
135 - if (!IsUpdateNeeded())
137 + auto [updateNeeded, existingVersion] = IsUpdateNeeded();
138 + if (!updateNeeded)
139 {
140 return {};
141 }
142
143 + wsl::windows::common::wslutil::WriteInstallLog(std::format("Starting upgrade via WslInstaller. Previous version: {}", existingVersion));
144 +
145 // Return an existing install if any
146 if (auto ptr = weak_context.lock(); ptr != nullptr)
147 {