diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw
index 1a9b8cbd8..6def84997 100644
--- a/localization/strings/en-US/Resources.resw
+++ b/localization/strings/en-US/Resources.resw
@@ -744,6 +744,11 @@ For information please visit https://aka.ms/wslinstall
Running the debug shell requires running wsl.exe as Administrator.
+
+ Administrator protection is enabled, and your distributions might be registered with a different account.
+Sign in with the account that registered them, and try again. To learn more, go to aka.ms/apdevguide.
+ {Locked="Administrator protection"}{Locked="https://aka.ms/apdevguide"}Command line arguments, file names and string inserts should not be translated
+
The installation process for distribution '{}' failed with exit code: {}.
{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated
diff --git a/src/windows/common/wslutil.cpp b/src/windows/common/wslutil.cpp
index 24d21733e..4a808f9ef 100644
--- a/src/windows/common/wslutil.cpp
+++ b/src/windows/common/wslutil.cpp
@@ -522,10 +522,40 @@ wsl::windows::common::wslutil::GetDefaultVersion(void)
return version;
}
+namespace {
+
+// Returns true if the current process is running as a shadow admin under
+// Windows Admin Protection. Caches the DLL lookup on first call.
+bool IsAdminProtectionEnabled()
+{
+ const auto token = wil::open_current_access_token();
+ if (!wsl::windows::common::security::IsTokenElevated(token.get()))
+ {
+ return false;
+ }
+
+ using ShadowAdminEnabledFn = BOOL(WINAPI)();
+ static std::optional> s_fn;
+ static std::once_flag s_initFlag;
+
+ std::call_once(s_initFlag, []() {
+ LxssDynamicFunction fn{DynamicFunctionErrorLogs::None};
+ if (SUCCEEDED(fn.load(L"SecurityHealthUdk.dll", "Shield_LUAIsShadowAdminEnabled")))
+ {
+ s_fn.emplace(std::move(fn));
+ }
+ });
+
+ return s_fn.has_value() && (*s_fn)();
+}
+
+} // anonymous namespace
+
std::wstring wsl::windows::common::wslutil::GetErrorString(HRESULT result)
{
ULONG buildNumber = 0;
std::wstring kbUrl;
+ std::wstring errorString;
switch (result)
{
@@ -545,14 +575,16 @@ std::wstring wsl::windows::common::wslutil::GetErrorString(HRESULT result)
return Localization::MessageHigherIntegrity();
case WSL_E_DEFAULT_DISTRO_NOT_FOUND:
- return Localization::MessageNoDefaultDistro();
+ errorString = Localization::MessageNoDefaultDistro();
+ break;
case HRESULT_FROM_WIN32(WSAECONNABORTED):
case HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS):
return Localization::MessageInstanceTerminated();
case WSL_E_DISTRO_NOT_FOUND:
- return Localization::MessageDistroNotFound();
+ errorString = Localization::MessageDistroNotFound();
+ break;
case HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS):
return Localization::MessageDistroNameAlreadyExists();
@@ -695,7 +727,26 @@ std::wstring wsl::windows::common::wslutil::GetErrorString(HRESULT result)
}
}
- return GetSystemErrorString(result);
+ if (errorString.empty())
+ {
+ return GetSystemErrorString(result);
+ }
+
+ // If Admin Protection is enabled, prepend an informational message for
+ // errors that may be caused by the shadow admin's separate registry hive.
+ try
+ {
+ if (IsAdminProtectionEnabled())
+ {
+ auto message = Localization::MessageAdminProtectionEnabled();
+ message += L"\n\n";
+ message += errorString;
+ return message;
+ }
+ }
+ CATCH_LOG()
+
+ return errorString;
}
std::optional> wsl::windows::common::wslutil::GetGitHubAssetFromRelease(const GitHubRelease& Release)