Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions diagnostics/collect-wsl-logs.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,12 @@ if (Test-Path $wslconfig)
Copy-Item $wslconfig $folder | Out-Null
}

# Collect high-level WSL install log (written by WriteInstallLog() in install.cpp)
Copy-Item "C:\Windows\temp\wsl-install-log.txt" $folder -ErrorAction ignore

# Collect MSI verbose install log (preserved on failure by wsl --update or WslInstaller service).
Copy-Item "$env:TEMP\wsl-install-logs.txt" $folder -ErrorAction ignore

get-appxpackage MicrosoftCorporationII.WindowsSubsystemforLinux -ErrorAction Ignore > $folder/appxpackage.txt
get-acl "C:\ProgramData\Microsoft\Windows\WindowsApps" -ErrorAction Ignore | Format-List > $folder/acl.txt
Get-WindowsOptionalFeature -Online > $folder/optional-components.txt
Expand Down
31 changes: 27 additions & 4 deletions src/windows/wslinstaller/exe/WslInstaller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,26 @@ std::wstring GetMsiPackagePath()
return (wsl::windows::common::wslutil::GetBasePath() / L"wsl.msi").wstring();
}

std::optional<std::wstring> GetUpgradeLogFileLocation()
struct UpgradeLogInfo
{
std::wstring path;
bool fromRegistry; // true when the path was explicitly configured via UpgradeLogFile registry value
};

std::optional<UpgradeLogInfo> GetUpgradeLogFileLocation()
try
{
const auto key = wsl::windows::common::registry::OpenLxssMachineKey();
const auto path = wsl::windows::common::registry::ReadString(key.get(), L"MSI", L"UpgradeLogFile", L"");
if (path.empty())
{
return {};
// Default to the same path used by wsl --update so all MSI logs
// are collected from one location by the diagnostic script.
return UpgradeLogInfo{(std::filesystem::temp_directory_path() / L"wsl-install-logs.txt").wstring(), false};
}

// A canonical path is required because msiexec doesn't like symlinks.
return std::filesystem::weakly_canonical(path);
return UpgradeLogInfo{std::filesystem::weakly_canonical(path), true};
Comment thread
benhillis marked this conversation as resolved.
}
catch (...)
{
Expand All @@ -54,6 +62,16 @@ std::pair<UINT, std::wstring> InstallMsipackageImpl()
{
const auto logFile = GetUpgradeLogFileLocation();

// Delete MSI log on success, preserve on failure for diagnostics (same as wsl --update).
// When the UpgradeLogFile registry value is set, always keep the log — the registry key
// is explicitly designed to retain MSI logs across installs.
auto clearLogs = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&logFile]() {
Comment thread
yeelam-gordon marked this conversation as resolved.
if (logFile.has_value() && !logFile->fromRegistry)
{
LOG_IF_WIN32_BOOL_FALSE(DeleteFile(logFile->path.c_str()));
}
});

std::wstring errors;
auto messageCallback = [&errors](INSTALLMESSAGE type, LPCWSTR message) {
switch (type)
Expand All @@ -77,10 +95,15 @@ std::pair<UINT, std::wstring> InstallMsipackageImpl()
};

auto result = wsl::windows::common::install::UpgradeViaMsi(
GetMsiPackagePath().c_str(), L"SKIPMSIX=1", logFile.has_value() ? logFile->c_str() : nullptr, messageCallback);
GetMsiPackagePath().c_str(), L"SKIPMSIX=1", logFile.has_value() ? logFile->path.c_str() : nullptr, messageCallback);

WSL_LOG("MSIUpgradeResult", TraceLoggingValue(result, "result"), TraceLoggingValue(errors.c_str(), "errorMessage"));

if (result != ERROR_SUCCESS && result != ERROR_SUCCESS_REBOOT_REQUIRED)
{
clearLogs.release();
}

return {result, errors};
}

Expand Down
Loading