CLI: Unify session resolution, add WSLC_E_SESSION_NOT_FOUND, and refactor session service (#40832)

David Bennett committed Jun 19, 2026 at 13:58 UTC 14b78c929050f49b42b415011c930dd0d7bb2ef6
58 files changed +229 -232
localization/strings/en-US/Resources.resw
+4 -3
@@ -2066,6 +2066,10 @@ Usage:
2066 <value>OpenSessionByName('{}') failed</value>
2067 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2068 </data>
2069 + <data name="MessageWslcSessionOptionNotSupported" xml:space="preserve">
2070 + <value>The --session option cannot be used with this command.</value>
2071 + <comment>{Locked="--session "}Command line arguments, file names and string inserts should not be translated</comment>
2072 + </data>
2073 <data name="MessageWslcFailedToLaunchCommand" xml:space="preserve">
2074 <value>Failed to launch command {}. Errno = {}</value>
2075 <comment>{FixedPlaceholder="{}"}{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
@@ -2903,9 +2907,6 @@ On first run, creates the file with all settings commented out at their defaults
2907 <value>Size of /dev/shm (e.g. 64M, 1G)</value>
2908 <comment>{Locked="/dev/shm"}Command line arguments should not be translated</comment>
2909 </data>
2906 - <data name="WSLCCLI_SessionIdPositionalArgDescription" xml:space="preserve">
2907 - <value>Session ID</value>
2908 - </data>
2910 <data name="WSLCCLI_SessionStoragePositionalArgDescription" xml:space="preserve">
2911 <value>Session storage path</value>
2912 </data>
src/windows/WslcSDK/wslcsdk.h
+1
@@ -41,6 +41,7 @@ EXTERN_C_START
41 #define WSLC_E_CONTAINER_DISABLED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 12) /* 0x8004060C */
42 #define WSLC_E_REGISTRY_BLOCKED_BY_POLICY MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 13) /* 0x8004060D */
43 #define WSLC_E_VOLUME_NOT_AVAILABLE MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 14) /* 0x8004060E */
44 +#define WSLC_E_SESSION_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 15) /* 0x8004060F */
45
46 // Session values
47 #define WSLC_SESSION_OPTIONS_SIZE 72
src/windows/common/wslutil.cpp
+1
@@ -160,6 +160,7 @@ static const std::map<HRESULT, LPCWSTR> g_commonErrors{
160 X(WSLC_E_SESSION_RESERVED),
161 X(WSLC_E_INVALID_SESSION_NAME),
162 X(WSLC_E_NETWORK_NOT_FOUND),
163 + X(WSLC_E_SESSION_NOT_FOUND),
164 X(WSLC_E_WU_SEARCH_FAILED),
165 X_WIN32(RPC_S_SERVER_UNAVAILABLE),
166 X_WIN32(ERROR_ELEVATION_REQUIRED)};
src/windows/service/exe/WSLCSessionManager.cpp
+7 -3
@@ -38,6 +38,7 @@ Abstract:
38 #include "wslutil.h"
39 #include "filesystem.hpp"
40 #include "APICompat.h"
41 +#include "Localization.h"
42
43 extern wsl::windows::service::PluginManager g_pluginManager;
44
@@ -361,7 +362,7 @@ void WSLCSessionManagerImpl::OpenSession(ULONG Id, IWSLCSession** Session)
362 return S_OK;
363 });
364
364 - THROW_IF_FAILED_MSG(result.value_or(HRESULT_FROM_WIN32(ERROR_NOT_FOUND)), "Session '%lu' not found", Id);
365 + THROW_IF_FAILED_MSG(result.value_or(WSLC_E_SESSION_NOT_FOUND), "Session '%lu' not found", Id);
366 }
367
368 void WSLCSessionManagerImpl::OpenSessionByName(LPCWSTR DisplayName, IWSLCSession** Session)
@@ -391,7 +392,10 @@ void WSLCSessionManagerImpl::OpenSessionByName(LPCWSTR DisplayName, IWSLCSession
392 return S_OK;
393 });
394
394 - THROW_IF_FAILED_MSG(result.value_or(HRESULT_FROM_WIN32(ERROR_NOT_FOUND)), "Session '%ls' not found", DisplayName);
395 + THROW_HR_WITH_USER_ERROR_IF(
396 + WSLC_E_SESSION_NOT_FOUND, wsl::shared::Localization::MessageWslcSessionNotFound(DisplayName), !result.has_value());
397 +
398 + THROW_IF_FAILED_MSG(result.value(), "Failed to open session '%ls'", DisplayName);
399 }
400
401 void WSLCSessionManagerImpl::ListSessions(_Out_ WSLCSessionListEntry** Sessions, _Out_ ULONG* SessionsCount)
@@ -663,7 +667,7 @@ wil::com_ptr<IWSLCSession> WSLCSessionManagerImpl::FindSession(ULONG Id)
667 return S_OK;
668 });
669
666 - THROW_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), !result, "WSLC session %lu not found", Id);
670 + THROW_HR_IF_MSG(WSLC_E_SESSION_NOT_FOUND, !result, "WSLC session %lu not found", Id);
671 return result;
672 }
673
src/windows/service/inc/wslc.idl
+1
@@ -725,3 +725,4 @@ cpp_quote("#define WSLC_E_SDK_UPDATE_NEEDED MAKE_HRESULT(SEVERITY_ERROR, FACILIT
725 cpp_quote("#define WSLC_E_CONTAINER_DISABLED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 12) /* 0x8004060C */")
726 cpp_quote("#define WSLC_E_REGISTRY_BLOCKED_BY_POLICY MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 13) /* 0x8004060D */")
727 cpp_quote("#define WSLC_E_VOLUME_NOT_AVAILABLE MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 14) /* 0x8004060E */")
728 +cpp_quote("#define WSLC_E_SESSION_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 15) /* 0x8004060F */")
src/windows/wslc/arguments/ArgumentDefinitions.h
-1
@@ -98,7 +98,6 @@ _(Remove, "rm", NO_ALIAS, Kind::Flag, L
98 /*_(Scheme, "scheme", NO_ALIAS, Kind::Value, Localization::WSLCCLI_SchemeArgDescription())*/ \
99 _(Server, "server", NO_ALIAS, Kind::Positional, Localization::WSLCCLI_LoginServerArgDescription()) \
100 _(Session, "session", NO_ALIAS, Kind::Value, Localization::WSLCCLI_SessionIdArgDescription()) \
101 -_(SessionId, "session-id", NO_ALIAS, Kind::Positional, Localization::WSLCCLI_SessionIdPositionalArgDescription()) \
101 _(ShmSize, "shm-size", NO_ALIAS, Kind::Value, Localization::WSLCCLI_ShmSizeArgDescription()) \
102 _(StoragePath, "storage-path", NO_ALIAS, Kind::Positional, L"Path to the session storage directory") \
103 _(Signal, "signal", L"s", Kind::Value, Localization::WSLCCLI_SignalArgDescription()) \
src/windows/wslc/commands/ContainerAttachCommand.cpp
+2 -2
@@ -43,8 +43,8 @@ std::wstring ContainerAttachCommand::LongDescription() const
43
44 void ContainerAttachCommand::ExecuteInternal(CLIExecutionContext& context) const
45 {
46 - context //
47 - << CreateSession //
46 + context //
47 + << ResolveSession //
48 << AttachContainer(context.Args.Get<ArgType::ContainerId>());
49 }
50 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ContainerCreateCommand.cpp
+1 -1
@@ -83,7 +83,7 @@ std::wstring ContainerCreateCommand::LongDescription() const
83 void ContainerCreateCommand::ExecuteInternal(CLIExecutionContext& context) const
84 {
85 context
86 - << CreateSession
86 + << ResolveSession
87 << SetContainerOptionsFromArgs
88 << CreateContainer;
89 }
src/windows/wslc/commands/ContainerExecCommand.cpp
+1 -1
@@ -53,7 +53,7 @@ std::wstring ContainerExecCommand::LongDescription() const
53 void ContainerExecCommand::ExecuteInternal(CLIExecutionContext& context) const
54 {
55 context
56 - << CreateSession
56 + << ResolveSession
57 << SetContainerOptionsFromArgs
58 << ExecContainer;
59 }
src/windows/wslc/commands/ContainerExportCommand.cpp
+2 -2
@@ -44,8 +44,8 @@ std::wstring ContainerExportCommand::LongDescription() const
44
45 void ContainerExportCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context //
48 - << CreateSession //
47 + context //
48 + << ResolveSession //
49 << ExportContainer;
50 }
51 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ContainerInspectCommand.cpp
+1 -1
@@ -45,7 +45,7 @@ std::wstring ContainerInspectCommand::LongDescription() const
45 void ContainerInspectCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 context
48 - << CreateSession
48 + << ResolveSession
49 << InspectContainers;
50 }
51 // clang-format on
src/windows/wslc/commands/ContainerKillCommand.cpp
+1 -1
@@ -46,7 +46,7 @@ std::wstring ContainerKillCommand::LongDescription() const
46 void ContainerKillCommand::ExecuteInternal(CLIExecutionContext& context) const
47 {
48 context
49 - << CreateSession
49 + << ResolveSession
50 << KillContainers;
51 }
52 // clang-format on
src/windows/wslc/commands/ContainerListCommand.cpp
+1 -1
@@ -52,7 +52,7 @@ std::wstring ContainerListCommand::LongDescription() const
52 void ContainerListCommand::ExecuteInternal(CLIExecutionContext& context) const
53 {
54 context
55 - << CreateSession
55 + << ResolveSession
56 << GetContainers
57 << ListContainers;
58 }
src/windows/wslc/commands/ContainerLogsCommand.cpp
+2 -2
@@ -48,8 +48,8 @@ std::wstring ContainerLogsCommand::LongDescription() const
48
49 void ContainerLogsCommand::ExecuteInternal(CLIExecutionContext& context) const
50 {
51 - context //
52 - << CreateSession //
51 + context //
52 + << ResolveSession //
53 << ViewContainerLogs;
54 }
55 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/ContainerPruneCommand.cpp
+2 -2
@@ -41,8 +41,8 @@ std::wstring ContainerPruneCommand::LongDescription() const
41
42 void ContainerPruneCommand::ExecuteInternal(CLIExecutionContext& context) const
43 {
44 - context //
45 - << CreateSession //
44 + context //
45 + << ResolveSession //
46 << PruneContainers;
47 }
48 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ContainerRemoveCommand.cpp
+2 -2
@@ -44,8 +44,8 @@ std::wstring ContainerRemoveCommand::LongDescription() const
44
45 void ContainerRemoveCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context //
48 - << CreateSession //
47 + context //
48 + << ResolveSession //
49 << RemoveContainers;
50 }
51 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/ContainerRunCommand.cpp
+1 -1
@@ -84,7 +84,7 @@ std::wstring ContainerRunCommand::LongDescription() const
84 void ContainerRunCommand::ExecuteInternal(CLIExecutionContext& context) const
85 {
86 context
87 - << CreateSession
87 + << ResolveSession
88 << SetContainerOptionsFromArgs
89 << RunContainer;
90 }
src/windows/wslc/commands/ContainerStartCommand.cpp
+1 -1
@@ -45,6 +45,6 @@ std::wstring ContainerStartCommand::LongDescription() const
45
46 void ContainerStartCommand::ExecuteInternal(CLIExecutionContext& context) const
47 {
48 - context << CreateSession << StartContainer;
48 + context << ResolveSession << StartContainer;
49 }
50 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ContainerStatsCommand.cpp
+2 -2
@@ -58,8 +58,8 @@ void ContainerStatsCommand::ValidateArgumentsInternal(const ArgMap& execArgs) co
58
59 void ContainerStatsCommand::ExecuteInternal(CLIExecutionContext& context) const
60 {
61 - context //
62 - << CreateSession //
61 + context //
62 + << ResolveSession //
63 << ShowContainerStats;
64 }
65 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ContainerStopCommand.cpp
+1 -1
@@ -47,7 +47,7 @@ std::wstring ContainerStopCommand::LongDescription() const
47 void ContainerStopCommand::ExecuteInternal(CLIExecutionContext& context) const
48 {
49 context
50 - << CreateSession
50 + << ResolveSession
51 << StopContainers;
52 }
53 // clang-format on
src/windows/wslc/commands/ImageBuildCommand.cpp
+2 -2
@@ -50,8 +50,8 @@ std::wstring ImageBuildCommand::LongDescription() const
50
51 void ImageBuildCommand::ExecuteInternal(CLIExecutionContext& context) const
52 {
53 - context //
54 - << CreateSession //
53 + context //
54 + << ResolveSession //
55 << BuildImage;
56 }
57 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/ImageImportCommand.cpp
+2 -2
@@ -44,8 +44,8 @@ std::wstring ImageImportCommand::LongDescription() const
44
45 void ImageImportCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context //
48 - << CreateSession //
47 + context //
48 + << ResolveSession //
49 << ImportImage;
50 }
51 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ImageInspectCommand.cpp
+2 -2
@@ -44,8 +44,8 @@ std::wstring ImageInspectCommand::LongDescription() const
44
45 void ImageInspectCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context //
48 - << CreateSession //
47 + context //
48 + << ResolveSession //
49 << InspectImages;
50 }
51 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/ImageListCommand.cpp
+3 -3
@@ -47,9 +47,9 @@ std::wstring ImageListCommand::LongDescription() const
47
48 void ImageListCommand::ExecuteInternal(CLIExecutionContext& context) const
49 {
50 - context //
51 - << CreateSession //
52 - << GetImages //
50 + context //
51 + << ResolveSession //
52 + << GetImages //
53 << ListImages;
54 }
55 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/ImageLoadCommand.cpp
+2 -2
@@ -43,8 +43,8 @@ std::wstring ImageLoadCommand::LongDescription() const
43
44 void ImageLoadCommand::ExecuteInternal(CLIExecutionContext& context) const
45 {
46 - context //
47 - << CreateSession //
46 + context //
47 + << ResolveSession //
48 << LoadImage;
49 }
50 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/ImagePruneCommand.cpp
+2 -2
@@ -45,8 +45,8 @@ std::wstring ImagePruneCommand::LongDescription() const
45
46 void ImagePruneCommand::ExecuteInternal(CLIExecutionContext& context) const
47 {
48 - context //
49 - << CreateSession //
48 + context //
49 + << ResolveSession //
50 << PruneImages;
51 }
52 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ImagePullCommand.cpp
+2 -2
@@ -45,8 +45,8 @@ std::wstring ImagePullCommand::LongDescription() const
45
46 void ImagePullCommand::ExecuteInternal(CLIExecutionContext& context) const
47 {
48 - context //
49 - << CreateSession //
48 + context //
49 + << ResolveSession //
50 << PullImage;
51 }
52 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/ImagePushCommand.cpp
+2 -2
@@ -43,8 +43,8 @@ std::wstring ImagePushCommand::LongDescription() const
43
44 void ImagePushCommand::ExecuteInternal(CLIExecutionContext& context) const
45 {
46 - context //
47 - << CreateSession //
46 + context //
47 + << ResolveSession //
48 << PushImage;
49 }
50 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ImageRemoveCommand.cpp
+2 -2
@@ -46,8 +46,8 @@ std::wstring ImageRemoveCommand::LongDescription() const
46
47 void ImageRemoveCommand::ExecuteInternal(CLIExecutionContext& context) const
48 {
49 - context //
50 - << CreateSession //
49 + context //
50 + << ResolveSession //
51 << DeleteImage;
52 }
53 } // namespace wsl::windows::wslc
src/windows/wslc/commands/ImageSaveCommand.cpp
+2 -2
@@ -44,8 +44,8 @@ std::wstring ImageSaveCommand::LongDescription() const
44
45 void ImageSaveCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context //
48 - << CreateSession //
47 + context //
48 + << ResolveSession //
49 << SaveImage;
50 }
51 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/ImageTagCommand.cpp
+2 -2
@@ -44,8 +44,8 @@ std::wstring ImageTagCommand::LongDescription() const
44
45 void ImageTagCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context //
48 - << CreateSession //
47 + context //
48 + << ResolveSession //
49 << TagImage;
50 }
51 } // namespace wsl::windows::wslc
src/windows/wslc/commands/InspectCommand.cpp
+1 -1
@@ -39,7 +39,7 @@ std::wstring InspectCommand::LongDescription() const
39
40 void InspectCommand::ExecuteInternal(CLIExecutionContext& context) const
41 {
42 - context << CreateSession //
42 + context << ResolveSession //
43 << Inspect;
44 }
45 } // namespace wsl::windows::wslc
src/windows/wslc/commands/NetworkCreateCommand.cpp
+1 -1
@@ -46,7 +46,7 @@ std::wstring NetworkCreateCommand::LongDescription() const
46
47 void NetworkCreateCommand::ExecuteInternal(CLIExecutionContext& context) const
48 {
49 - context << CreateSession //
49 + context << ResolveSession //
50 << CreateNetwork;
51 }
52 } // namespace wsl::windows::wslc
src/windows/wslc/commands/NetworkInspectCommand.cpp
+1 -1
@@ -43,7 +43,7 @@ std::wstring NetworkInspectCommand::LongDescription() const
43
44 void NetworkInspectCommand::ExecuteInternal(CLIExecutionContext& context) const
45 {
46 - context << CreateSession //
46 + context << ResolveSession //
47 << InspectNetworks;
48 }
49 } // namespace wsl::windows::wslc
src/windows/wslc/commands/NetworkListCommand.cpp
+2 -2
@@ -57,8 +57,8 @@ void NetworkListCommand::ValidateArgumentsInternal(const ArgMap& execArgs) const
57
58 void NetworkListCommand::ExecuteInternal(CLIExecutionContext& context) const
59 {
60 - context << CreateSession //
61 - << GetNetworks //
60 + context << ResolveSession //
61 + << GetNetworks //
62 << ListNetworks;
63 }
64 } // namespace wsl::windows::wslc
src/windows/wslc/commands/NetworkPruneCommand.cpp
+2 -3
@@ -28,7 +28,6 @@ std::vector<Argument> NetworkPruneCommand::GetArguments() const
28 {
29 return {
30 Argument::Create(ArgType::Filter, false, NO_LIMIT),
31 - Argument::Create(ArgType::Session),
31 };
32 }
33
@@ -44,8 +43,8 @@ std::wstring NetworkPruneCommand::LongDescription() const
43
44 void NetworkPruneCommand::ExecuteInternal(CLIExecutionContext& context) const
45 {
47 - context //
48 - << CreateSession //
46 + context //
47 + << ResolveSession //
48 << PruneNetworks;
49 }
50 } // namespace wsl::windows::wslc
src/windows/wslc/commands/NetworkRemoveCommand.cpp
+1 -1
@@ -44,7 +44,7 @@ std::wstring NetworkRemoveCommand::LongDescription() const
44
45 void NetworkRemoveCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context << CreateSession //
47 + context << ResolveSession //
48 << DeleteNetworks;
49 }
50 } // namespace wsl::windows::wslc
src/windows/wslc/commands/RegistryCommand.cpp
+1 -1
@@ -151,7 +151,7 @@ void RegistryLoginCommand::ExecuteInternal(CLIExecutionContext& context) const
151 }
152
153 context //
154 - << CreateSession << Login;
154 + << ResolveSession << Login;
155 }
156
157 // Registry Logout Command
src/windows/wslc/commands/SessionEnterCommand.cpp
+5
@@ -43,6 +43,11 @@ std::wstring SessionEnterCommand::LongDescription() const
43
44 void SessionEnterCommand::ExecuteInternal(CLIExecutionContext& context) const
45 {
46 + if (context.GlobalArgs.Contains(ArgType::Session))
47 + {
48 + throw CommandException(Localization::MessageWslcSessionOptionNotSupported());
49 + }
50 +
51 context << EnterSession;
52 }
53 } // namespace wsl::windows::wslc
src/windows/wslc/commands/SessionRunCommand.cpp
+1 -1
@@ -42,6 +42,6 @@ std::wstring SessionRunCommand::LongDescription() const
42
43 void SessionRunCommand::ExecuteInternal(CLIExecutionContext& context) const
44 {
45 - context << RunInSession;
45 + context << ResolveSession << RunInSession;
46 }
47 } // namespace wsl::windows::wslc
src/windows/wslc/commands/SessionShellCommand.cpp
+2 -4
@@ -24,9 +24,7 @@ namespace wsl::windows::wslc {
24 // Session Shell Command
25 std::vector<Argument> SessionShellCommand::GetArguments() const
26 {
27 - return {
28 - Argument::Create(ArgType::SessionId),
29 - };
27 + return {};
28 }
29
30 std::wstring SessionShellCommand::ShortDescription() const
@@ -41,6 +39,6 @@ std::wstring SessionShellCommand::LongDescription() const
39
40 void SessionShellCommand::ExecuteInternal(CLIExecutionContext& context) const
41 {
44 - context << AttachToSession;
42 + context << ResolveSession << AttachToSession;
43 }
44 } // namespace wsl::windows::wslc
src/windows/wslc/commands/SessionTerminateCommand.cpp
+5 -4
@@ -24,9 +24,7 @@ namespace wsl::windows::wslc {
24 // Session Terminate Command
25 std::vector<Argument> SessionTerminateCommand::GetArguments() const
26 {
27 - return {
28 - Argument::Create(ArgType::SessionId),
29 - };
27 + return {};
28 }
29
30 std::wstring SessionTerminateCommand::ShortDescription() const
@@ -41,6 +39,9 @@ std::wstring SessionTerminateCommand::LongDescription() const
39
40 void SessionTerminateCommand::ExecuteInternal(CLIExecutionContext& context) const
41 {
44 - context << TerminateSession;
42 + context //
43 + << OpenSessionIfSpecified //
44 + << OpenDefaultSession //
45 + << TerminateSession;
46 }
47 } // namespace wsl::windows::wslc
\ No newline at end of file
src/windows/wslc/commands/VolumeCreateCommand.cpp
+1 -1
@@ -46,7 +46,7 @@ std::wstring VolumeCreateCommand::LongDescription() const
46
47 void VolumeCreateCommand::ExecuteInternal(CLIExecutionContext& context) const
48 {
49 - context << CreateSession //
49 + context << ResolveSession //
50 << CreateVolume;
51 }
52 } // namespace wsl::windows::wslc
src/windows/wslc/commands/VolumeInspectCommand.cpp
+1 -1
@@ -43,7 +43,7 @@ std::wstring VolumeInspectCommand::LongDescription() const
43
44 void VolumeInspectCommand::ExecuteInternal(CLIExecutionContext& context) const
45 {
46 - context << CreateSession //
46 + context << ResolveSession //
47 << InspectVolumes;
48 }
49 } // namespace wsl::windows::wslc
src/windows/wslc/commands/VolumeListCommand.cpp
+2 -2
@@ -57,8 +57,8 @@ void VolumeListCommand::ValidateArgumentsInternal(const ArgMap& execArgs) const
57
58 void VolumeListCommand::ExecuteInternal(CLIExecutionContext& context) const
59 {
60 - context << CreateSession //
61 - << GetVolumes //
60 + context << ResolveSession //
61 + << GetVolumes //
62 << ListVolumes;
63 }
64 } // namespace wsl::windows::wslc
src/windows/wslc/commands/VolumePruneCommand.cpp
+2 -2
@@ -44,8 +44,8 @@ std::wstring VolumePruneCommand::LongDescription() const
44
45 void VolumePruneCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context //
48 - << CreateSession //
47 + context //
48 + << ResolveSession //
49 << PruneVolumes;
50 }
51 } // namespace wsl::windows::wslc
src/windows/wslc/commands/VolumeRemoveCommand.cpp
+1 -1
@@ -44,7 +44,7 @@ std::wstring VolumeRemoveCommand::LongDescription() const
44
45 void VolumeRemoveCommand::ExecuteInternal(CLIExecutionContext& context) const
46 {
47 - context << CreateSession //
47 + context << ResolveSession //
48 << DeleteVolumes;
49 }
50 } // namespace wsl::windows::wslc
src/windows/wslc/services/SessionModel.h
+15
@@ -19,16 +19,31 @@ namespace wsl::windows::wslc::models {
19
20 struct Session
21 {
22 + NON_COPYABLE(Session);
23 + DEFAULT_MOVABLE(Session);
24 +
25 explicit Session(wil::com_ptr<IWSLCSession> session) : m_session(std::move(session))
26 {
27 }
28 +
29 IWSLCSession* Get() const noexcept
30 {
31 return m_session.get();
32 }
33
34 + const std::optional<std::wstring>& DisplayName() const noexcept
35 + {
36 + return m_displayName;
37 + }
38 +
39 + void SetDisplayName(std::wstring name)
40 + {
41 + m_displayName = std::move(name);
42 + }
43 +
44 private:
45 wil::com_ptr<IWSLCSession> m_session;
46 + std::optional<std::wstring> m_displayName;
47 };
48
49 } // namespace wsl::windows::wslc::models
\ No newline at end of file
src/windows/wslc/services/SessionService.cpp
+53 -95
@@ -24,44 +24,53 @@ using namespace wsl::shared;
24 using namespace wsl::windows::wslc::models;
25 namespace wslutil = wsl::windows::common::wslutil;
26
27 -namespace {
28 -
29 - wil::com_ptr<IWSLCSession> OpenOrCreateSession(const std::wstring& sessionName)
30 - {
31 - wil::com_ptr<IWSLCSessionManager> manager;
32 - THROW_IF_FAILED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&manager)));
33 - wsl::windows::common::security::ConfigureForCOMImpersonation(manager.get());
27 +static wil::com_ptr<IWSLCSessionManager> CreateSessionManager()
28 +{
29 + wil::com_ptr<IWSLCSessionManager> manager;
30 + THROW_IF_FAILED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&manager)));
31 + wsl::windows::common::security::ConfigureForCOMImpersonation(manager.get());
32 + return manager;
33 +}
34
35 - wil::com_ptr<IWSLCSession> session;
36 - if (sessionName.empty())
37 - {
38 - // Default session: open it if it exists, otherwise create it.
39 - auto warningCallback = Microsoft::WRL::Make<WarningCallback>();
40 - THROW_IF_FAILED(manager->CreateSession(nullptr, WSLCSessionFlagsNone, warningCallback.Get(), &session));
41 - wsl::windows::common::security::ConfigureForCOMImpersonation(session.get());
42 - return session;
43 - }
35 +Session SessionService::OpenSessionByName(const wil::com_ptr<IWSLCSessionManager>& manager, LPCWSTR displayName)
36 +{
37 + wil::com_ptr<IWSLCSession> session;
38 + THROW_IF_FAILED(manager->OpenSessionByName(displayName, &session));
39
45 - HRESULT hr = manager->OpenSessionByName(sessionName.c_str(), &session);
46 - if (FAILED(hr))
47 - {
48 - THROW_HR_WITH_USER_ERROR_IF(
49 - hr, Localization::MessageWslcSessionNotFound(sessionName.c_str()), hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
40 + wsl::windows::common::security::ConfigureForCOMImpersonation(session.get());
41 + Session result(std::move(session));
42 + if (displayName)
43 + {
44 + result.SetDisplayName(displayName);
45 + }
46 + return result;
47 +}
48
51 - THROW_HR_WITH_USER_ERROR(hr, Localization::MessageWslcOpenSessionFailed(sessionName.c_str()));
52 - }
49 +Session SessionService::OpenSession(const std::wstring& sessionName)
50 +{
51 + return OpenSessionByName(CreateSessionManager(), sessionName.c_str());
52 +}
53
54 - wsl::windows::common::security::ConfigureForCOMImpersonation(session.get());
54 +Session SessionService::OpenDefaultSession()
55 +{
56 + // Null DisplayName = default session, resolved from caller's token by the server.
57 + return OpenSessionByName(CreateSessionManager(), nullptr);
58 +}
59
56 - return session;
57 - }
60 +Session SessionService::OpenOrCreateDefaultSession()
61 +{
62 + auto manager = CreateSessionManager();
63
59 -} // namespace
64 + // Null Settings = default session with server-determined name and settings.
65 + wil::com_ptr<IWSLCSession> session;
66 + auto warningCallback = Microsoft::WRL::Make<WarningCallback>();
67 + THROW_IF_FAILED(manager->CreateSession(nullptr, WSLCSessionFlagsNone, warningCallback.Get(), &session));
68 + wsl::windows::common::security::ConfigureForCOMImpersonation(session.get());
69 + return Session(std::move(session));
70 +}
71
61 -int SessionService::Attach(const std::wstring& sessionName)
72 +int SessionService::Attach(const Session& session)
73 {
63 - auto session = OpenOrCreateSession(sessionName);
64 -
74 // Configure console for interactive usage.
75 wsl::windows::common::ConsoleState console{};
76 console.SetInteractiveMode();
@@ -72,7 +81,7 @@ int SessionService::Attach(const std::wstring& sessionName)
81 // Launch with terminal fds (PTY).
82 wsl::windows::common::WSLCProcessLauncher launcher{shell, {shell, "--login"}, {"TERM=xterm-256color"}, WSLCProcessFlagsTty | WSLCProcessFlagsStdin};
83 launcher.SetTtySize(windowSize.Y, windowSize.X);
75 - auto process = launcher.Launch(*session);
84 + auto process = launcher.Launch(*session.Get());
85 auto tty = process.GetStdHandle(WSLCFDTty);
86 auto updateTerminalSize = [&]() {
87 const auto windowSize = console.GetWindowSize();
@@ -114,28 +123,12 @@ int SessionService::Attach(const std::wstring& sessionName)
123 return static_cast<int>(exitCode);
124 }
125
117 -Session SessionService::CreateDefaultSession()
118 -{
119 - wil::com_ptr<IWSLCSessionManager> sessionManager;
120 - THROW_IF_FAILED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager)));
121 - wsl::windows::common::security::ConfigureForCOMImpersonation(sessionManager.get());
122 -
123 - // Null Settings = default session with server-determined name and settings.
124 - wil::com_ptr<IWSLCSession> session;
125 - auto warningCallback = Microsoft::WRL::Make<WarningCallback>();
126 - THROW_IF_FAILED(sessionManager->CreateSession(nullptr, WSLCSessionFlagsNone, warningCallback.Get(), &session));
127 - wsl::windows::common::security::ConfigureForCOMImpersonation(session.get());
128 - return Session(std::move(session));
129 -}
130 -
126 int SessionService::Enter(const std::wstring& storagePath, const std::wstring& displayName)
127 {
128 THROW_HR_IF(E_INVALIDARG, storagePath.empty());
129 THROW_HR_IF(E_INVALIDARG, displayName.empty());
130
136 - wil::com_ptr<IWSLCSessionManager> sessionManager;
137 - THROW_IF_FAILED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager)));
138 - wsl::windows::common::security::ConfigureForCOMImpersonation(sessionManager.get());
131 + auto sessionManager = CreateSessionManager();
132
133 wil::com_ptr<IWSLCSession> session;
134 auto warningCallback = Microsoft::WRL::Make<WarningCallback>();
@@ -156,9 +149,7 @@ int SessionService::Enter(const std::wstring& storagePath, const std::wstring& d
149 std::vector<SessionInformation> SessionService::List()
150 {
151 std::vector<SessionInformation> result;
159 - wil::com_ptr<IWSLCSessionManager> sessionManager;
160 - THROW_IF_FAILED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager)));
161 - wsl::windows::common::security::ConfigureForCOMImpersonation(sessionManager.get());
152 + auto sessionManager = CreateSessionManager();
153
154 wil::unique_cotaskmem_array_ptr<WSLCSessionListEntry> sessions;
155 THROW_IF_FAILED(sessionManager->ListSessions(&sessions, sessions.size_address<ULONG>()));
@@ -175,29 +166,15 @@ std::vector<SessionInformation> SessionService::List()
166 return result;
167 }
168
178 -Session SessionService::OpenSession(const std::wstring& displayName)
179 -{
180 - wil::com_ptr<IWSLCSessionManager> sessionManager;
181 - THROW_IF_FAILED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager)));
182 - wsl::windows::common::security::ConfigureForCOMImpersonation(sessionManager.get());
183 -
184 - wil::com_ptr<IWSLCSession> session;
185 - THROW_IF_FAILED(sessionManager->OpenSessionByName(displayName.c_str(), &session));
186 - wsl::windows::common::security::ConfigureForCOMImpersonation(session.get());
187 - return Session(std::move(session));
188 -}
189 -
190 -int SessionService::Run(const std::wstring& sessionName, const std::vector<std::string>& arguments)
169 +int SessionService::Run(const Session& session, const std::vector<std::string>& arguments)
170 {
171 WI_ASSERT(!arguments.empty());
172
194 - auto session = OpenOrCreateSession(sessionName);
195 -
173 // Pass a default $PATH environment for convenience.
174 const std::vector<std::string> environment{"PATH=/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin"};
175 wsl::windows::common::WSLCProcessLauncher launcher{arguments.front(), arguments, environment, WSLCProcessFlagsStdin};
176
200 - auto [result, process, error] = launcher.LaunchNoThrow(*session);
177 + auto [result, process, error] = launcher.LaunchNoThrow(*session.Get());
178 THROW_HR_WITH_USER_ERROR_IF(result, Localization::MessageWslcFailedToLaunchCommand(arguments.front(), error), FAILED(result) && error != 0);
179
180 THROW_IF_FAILED(result);
@@ -206,40 +183,21 @@ int SessionService::Run(const std::wstring& sessionName, const std::vector<std::
183 return ConsoleService::AttachToCurrentConsole(console, std::move(process.value()));
184 }
185
209 -int SessionService::TerminateSession(const std::wstring& displayName)
186 +int SessionService::TerminateSession(const Session& session)
187 {
211 - wil::com_ptr<IWSLCSessionManager> sessionManager;
212 - THROW_IF_FAILED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager)));
213 - wsl::windows::common::security::ConfigureForCOMImpersonation(sessionManager.get());
214 -
215 - wil::com_ptr<IWSLCSession> session;
216 - HRESULT hr = sessionManager->OpenSessionByName(displayName.empty() ? nullptr : displayName.c_str(), &session);
188 + HRESULT hr = session.Get()->Terminate();
189 if (FAILED(hr))
190 {
219 - if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
191 + auto errorString = wsl::windows::common::wslutil::ErrorCodeToString(hr);
192 + if (session.DisplayName().has_value())
193 {
194 wslutil::PrintMessage(
222 - displayName.empty() ? Localization::MessageWslcDefaultSessionNotFound()
223 - : Localization::MessageWslcSessionNotFound(displayName.c_str()),
224 - stderr);
225 - return 1;
195 + Localization::MessageErrorCode(Localization::MessageWslcTerminateSessionFailed(session.DisplayName().value()), errorString), stderr);
196 + }
197 + else
198 + {
199 + wslutil::PrintMessage(Localization::MessageErrorCode(Localization::MessageWslcTerminateDefaultSessionFailed(), errorString), stderr);
200 }
227 -
228 - THROW_HR(hr);
229 - }
230 -
231 - wsl::windows::common::security::ConfigureForCOMImpersonation(session.get());
232 -
233 - hr = session->Terminate();
234 - if (FAILED(hr))
235 - {
236 - auto errorString = wsl::windows::common::wslutil::ErrorCodeToString(hr);
237 - wslutil::PrintMessage(
238 - Localization::MessageErrorCode(
239 - displayName.empty() ? Localization::MessageWslcTerminateDefaultSessionFailed()
240 - : Localization::MessageWslcTerminateSessionFailed(displayName.c_str()),
241 - errorString),
242 - stderr);
201 return 1;
202 }
203
src/windows/wslc/services/SessionService.h
+13 -6
@@ -26,14 +26,21 @@ struct SessionInformation
26
27 struct SessionService
28 {
29 - static int Attach(const std::wstring& name);
30 - // Creates a default session with server-determined name and settings.
31 - static wsl::windows::wslc::models::Session CreateDefaultSession();
29 + static int Attach(const wsl::windows::wslc::models::Session& session);
30 static int Enter(const std::wstring& storagePath, const std::wstring& displayName);
31 static std::vector<SessionInformation> List();
34 - static wsl::windows::wslc::models::Session OpenSession(const std::wstring& displayName);
32 + // Opens an existing session by name. Throws if not found.
33 + static wsl::windows::wslc::models::Session OpenSession(const std::wstring& name);
34 + // Opens the default session. Throws WSLC_E_SESSION_NOT_FOUND if no default session exists.
35 + static wsl::windows::wslc::models::Session OpenDefaultSession();
36 + // Opens or creates the default session.
37 + static wsl::windows::wslc::models::Session OpenOrCreateDefaultSession();
38 // Runs the given command and arguments in a session without a TTY, resolving the executable from PATH.
36 - static int Run(const std::wstring& name, const std::vector<std::string>& arguments);
37 - static int TerminateSession(const std::wstring& displayName);
39 + static int Run(const wsl::windows::wslc::models::Session& session, const std::vector<std::string>& arguments);
40 + static int TerminateSession(const wsl::windows::wslc::models::Session& session);
41 +
42 +private:
43 + // Common open-only session lookup with unified error handling.
44 + static wsl::windows::wslc::models::Session OpenSessionByName(const wil::com_ptr<IWSLCSessionManager>& manager, LPCWSTR displayName);
45 };
46 } // namespace wsl::windows::wslc::services
src/windows/wslc/tasks/SessionTasks.cpp
+28 -25
@@ -29,27 +29,39 @@ namespace wsl::windows::wslc::task {
29
30 void AttachToSession(CLIExecutionContext& context)
31 {
32 - std::wstring sessionId;
33 - if (context.Args.Contains(ArgType::SessionId))
34 - {
35 - sessionId = context.Args.Get<ArgType::SessionId>();
36 - }
37 -
38 - context.ExitCode = SessionService::Attach(sessionId);
32 + auto& session = context.Data.Get<Data::Session>();
33 + context.ExitCode = SessionService::Attach(session);
34 }
35
41 -void CreateSession(CLIExecutionContext& context)
36 +void OpenSessionIfSpecified(CLIExecutionContext& context)
37 {
38 if (context.GlobalArgs.Contains(ArgType::Session))
39 {
45 - // User specified a session name — open only, don't create.
40 const auto& sessionName = context.GlobalArgs.Get<ArgType::Session>();
41 context.Data.Add<Data::Session>(SessionService::OpenSession(sessionName));
48 - return;
42 }
43 +}
44 +
45 +void OpenOrCreateDefaultSession(CLIExecutionContext& context)
46 +{
47 + if (!context.Data.Contains(Data::Session))
48 + {
49 + context.Data.Add<Data::Session>(SessionService::OpenOrCreateDefaultSession());
50 + }
51 +}
52 +
53 +void OpenDefaultSession(CLIExecutionContext& context)
54 +{
55 + if (!context.Data.Contains(Data::Session))
56 + {
57 + context.Data.Add<Data::Session>(SessionService::OpenDefaultSession());
58 + }
59 +}
60
51 - // Create/open the default session.
52 - context.Data.Add<Data::Session>(SessionService::CreateDefaultSession());
61 +void ResolveSession(CLIExecutionContext& context)
62 +{
63 + OpenSessionIfSpecified(context);
64 + OpenOrCreateDefaultSession(context);
65 }
66
67 void ListSessions(CLIExecutionContext& context)
@@ -78,22 +90,13 @@ void ListSessions(CLIExecutionContext& context)
90
91 void TerminateSession(CLIExecutionContext& context)
92 {
81 - std::wstring sessionId;
82 - if (context.Args.Contains(ArgType::SessionId))
83 - {
84 - sessionId = context.Args.Get<ArgType::SessionId>();
85 - }
86 -
87 - context.ExitCode = SessionService::TerminateSession(sessionId);
93 + auto& session = context.Data.Get<Data::Session>();
94 + context.ExitCode = SessionService::TerminateSession(session);
95 }
96
97 void RunInSession(CLIExecutionContext& context)
98 {
92 - std::wstring sessionName;
93 - if (context.GlobalArgs.Contains(ArgType::Session))
94 - {
95 - sessionName = context.GlobalArgs.Get<ArgType::Session>();
96 - }
99 + auto& session = context.Data.Get<Data::Session>();
100
101 std::vector<std::string> arguments;
102 arguments.emplace_back(wsl::windows::common::string::WideToMultiByte(context.Args.Get<ArgType::Command>()));
@@ -105,7 +108,7 @@ void RunInSession(CLIExecutionContext& context)
108 }
109 }
110
108 - context.ExitCode = SessionService::Run(sessionName, arguments);
111 + context.ExitCode = SessionService::Run(session, arguments);
112 }
113
114 void EnterSession(CLIExecutionContext& context)
src/windows/wslc/tasks/SessionTasks.h
+3 -1
@@ -18,9 +18,11 @@ using wsl::windows::wslc::execution::CLIExecutionContext;
18
19 namespace wsl::windows::wslc::task {
20 void AttachToSession(CLIExecutionContext& context);
21 -void CreateSession(CLIExecutionContext& context);
21 void EnterSession(CLIExecutionContext& context);
22 void ListSessions(CLIExecutionContext& context);
23 +void OpenDefaultSession(CLIExecutionContext& context);
24 +void OpenSessionIfSpecified(CLIExecutionContext& context);
25 +void ResolveSession(CLIExecutionContext& context);
26 void RunInSession(CLIExecutionContext& context);
27 void TerminateSession(CLIExecutionContext& context);
28 } // namespace wsl::windows::wslc::task
test/windows/WSLCTests.cpp
+2 -2
@@ -403,10 +403,10 @@ class WSLCTests
403 VERIFY_SUCCEEDED(sessionManager->OpenSessionByName(c_testSessionName, &opened));
404 VERIFY_IS_NOT_NULL(opened.get());
405
406 - // And verify we get ERROR_NOT_FOUND for a nonexistent name
406 + // And verify we get WSLC_E_SESSION_NOT_FOUND for a nonexistent name
407 wil::com_ptr<IWSLCSession> notFound;
408 auto hr = sessionManager->OpenSessionByName(L"this-name-does-not-exist", &notFound);
409 - VERIFY_ARE_EQUAL(hr, HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
409 + VERIFY_ARE_EQUAL(hr, WSLC_E_SESSION_NOT_FOUND);
410 }
411
412 WSLC_TEST_METHOD(CreateSessionValidation)
test/windows/wslc/CommandLineTestCases.h
+2 -2
@@ -41,7 +41,7 @@ COMMAND_LINE_TEST_CASE(L"system session list --verbose", L"list", true)
41 COMMAND_LINE_TEST_CASE(L"system session list --verbose --help", L"list", true)
42 COMMAND_LINE_TEST_CASE(L"system session list --notanarg", L"list", false)
43 COMMAND_LINE_TEST_CASE(L"system session list extraarg", L"list", false)
44 -COMMAND_LINE_TEST_CASE(L"system session shell session1", L"shell", true)
44 +COMMAND_LINE_TEST_CASE(L"--session session1 system session shell", L"shell", true)
45 COMMAND_LINE_TEST_CASE(L"system session shell", L"shell", true)
46 COMMAND_LINE_TEST_CASE(L"system session run ls", L"run", true)
47 COMMAND_LINE_TEST_CASE(L"system session run echo foo", L"run", true) // Command with trailing arguments
@@ -52,7 +52,7 @@ COMMAND_LINE_TEST_CASE(L"system session run \"ls -la /tmp\"", L"run", true)
52 COMMAND_LINE_TEST_CASE(L"system session run", L"run", false) // Missing required command positional
53 COMMAND_LINE_TEST_CASE(L"--session session1 system session run", L"run", false) // Missing required command positional
54 COMMAND_LINE_TEST_CASE(L"system session run --notanarg ls", L"run", false) // Invalid flag before command
55 -COMMAND_LINE_TEST_CASE(L"system session terminate session1", L"terminate", true)
55 +COMMAND_LINE_TEST_CASE(L"--session session1 system session terminate", L"terminate", true)
56 COMMAND_LINE_TEST_CASE(L"system session terminate", L"terminate", true)
57 COMMAND_LINE_TEST_CASE(L"system session enter C:\\storage", L"enter", true)
58 COMMAND_LINE_TEST_CASE(L"system session enter C:\\storage --name my-session", L"enter", true)
test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp
+19 -18
@@ -116,7 +116,7 @@ class WSLCE2EGlobalTests
116
117 // Try to explicitly target the admin session from non-elevated process
118 auto adminName = GetExpectedDefaultSessionName(true);
119 - result = RunWslc(std::format(L"--session {} container list", adminName), ElevationType::NonElevated);
119 + result = RunWslc(std::format(L"--session \"{}\" container list", adminName), ElevationType::NonElevated);
120
121 // Should fail with access denied.
122 result.Verify({.Stderr = L"The requested operation requires elevation. \r\nError code: ERROR_ELEVATION_REQUIRED\r\n", .ExitCode = 1});
@@ -130,7 +130,7 @@ class WSLCE2EGlobalTests
130
131 // Elevated user should be able to explicitly target the non-admin session
132 auto nonAdminName = GetExpectedDefaultSessionName(false);
133 - result = RunWslc(std::format(L"--session {} container list", nonAdminName), ElevationType::Elevated);
133 + result = RunWslc(std::format(L"--session \"{}\" container list", nonAdminName), ElevationType::Elevated);
134
135 // This should work - elevated users can access non-elevated sessions
136 result.Verify({.Stderr = L"", .ExitCode = 0});
@@ -144,12 +144,12 @@ class WSLCE2EGlobalTests
144 // Ensure elevated cannot create the non-elevated session.
145 auto nonAdminName = GetExpectedDefaultSessionName(false);
146 auto adminName = GetExpectedDefaultSessionName(true);
147 - auto result = RunWslc(std::format(L"--session {} container list", nonAdminName), ElevationType::Elevated);
148 - result.Verify({.Stderr = L"Element not found. \r\nError code: ERROR_NOT_FOUND\r\n", .ExitCode = 1});
147 + auto result = RunWslc(std::format(L"--session \"{}\" container list", nonAdminName), ElevationType::Elevated);
148 + result.Verify({.Stderr = std::format(L"Session not found: '{}'\r\nError code: WSLC_E_SESSION_NOT_FOUND\r\n", nonAdminName), .ExitCode = 1});
149
150 // Ensure non-elevated cannot create the elevated session.
151 - result = RunWslc(std::format(L"--session {} container list", adminName), ElevationType::NonElevated);
152 - result.Verify({.Stderr = L"Element not found. \r\nError code: ERROR_NOT_FOUND\r\n", .ExitCode = 1});
151 + result = RunWslc(std::format(L"--session \"{}\" container list", adminName), ElevationType::NonElevated);
152 + result.Verify({.Stderr = std::format(L"Session not found: '{}'\r\nError code: WSLC_E_SESSION_NOT_FOUND\r\n", adminName), .ExitCode = 1});
153 }
154
155 // Regression test for session name squatting vulnerability.
@@ -298,7 +298,7 @@ class WSLCE2EGlobalTests
298 VERIFY_IS_TRUE(result.Stdout->find(adminName) != std::wstring::npos);
299
300 // Terminate the session
301 - result = RunWslc(std::format(L"system session terminate {}", adminName));
301 + result = RunWslc(std::format(L"--session \"{}\" system session terminate", adminName));
302 result.Verify({.Stderr = L"", .ExitCode = 0});
303
304 // Verify session no longer shows up
@@ -320,7 +320,7 @@ class WSLCE2EGlobalTests
320 VERIFY_IS_TRUE(result.Stdout->find(nonAdminName + L"\r\n") != std::wstring::npos);
321
322 // Terminate the session
323 - result = RunWslc(std::format(L"system session terminate {}", nonAdminName), ElevationType::NonElevated);
323 + result = RunWslc(std::format(L"--session \"{}\" system session terminate", nonAdminName), ElevationType::NonElevated);
324 result.Verify({.Stderr = L"", .ExitCode = 0});
325
326 // Verify session no longer shows up
@@ -349,11 +349,11 @@ class WSLCE2EGlobalTests
349 VERIFY_IS_TRUE(result.Stdout->find(nonAdminName + L"\r\n") != std::wstring::npos);
350
351 // Attempt to terminate the admin session from the non-elevated process and fail.
352 - result = RunWslc(std::format(L"system session terminate {}", adminName), ElevationType::NonElevated);
352 + result = RunWslc(std::format(L"--session \"{}\" system session terminate", adminName), ElevationType::NonElevated);
353 result.Verify({.Stderr = L"The requested operation requires elevation. \r\nError code: ERROR_ELEVATION_REQUIRED\r\n", .ExitCode = 1});
354
355 // Terminate the non-elevated session from the elevated process.
356 - result = RunWslc(std::format(L"system session terminate {}", nonAdminName), ElevationType::Elevated);
356 + result = RunWslc(std::format(L"--session \"{}\" system session terminate", nonAdminName), ElevationType::Elevated);
357 result.Verify({.Stderr = L"", .ExitCode = 0});
358
359 // Verify non-elevated session no longer shows up
@@ -379,7 +379,8 @@ class WSLCE2EGlobalTests
379
380 // Verify targeting a non-existent session fails.
381 auto result = RunWslc(L"--session INVALID_SESSION_NAME container list");
382 - result.Verify({.Stdout = L"", .Stderr = L"Element not found. \r\nError code: ERROR_NOT_FOUND\r\n", .ExitCode = 1});
382 + result.Verify(
383 + {.Stdout = L"", .Stderr = L"Session not found: 'INVALID_SESSION_NAME'\r\nError code: WSLC_E_SESSION_NOT_FOUND\r\n", .ExitCode = 1});
384
385 // Verify session list
386 result = RunWslc(L"system session list");
@@ -391,12 +392,12 @@ class WSLCE2EGlobalTests
392 VERIFY_ARE_NOT_EQUAL(findResult, std::wstring::npos);
393
394 // Run container list in the test session, which should succeed if the session is valid.
394 - result = RunWslc(std::format(L"--session {} container list", session.Name()));
395 + result = RunWslc(std::format(L"--session \"{}\" container list", session.Name()));
396 result.Verify({.Stderr = L"", .ExitCode = 0});
397
398 // Add a container to the new session.
398 - result = RunWslc(
399 - std::format(L"--session {} container create --name {} {}", session.Name(), L"test-cont", DebianTestImage().NameAndTag()));
399 + result = RunWslc(std::format(
400 + L"--session \"{}\" container create --name {} {}", session.Name(), L"test-cont", DebianTestImage().NameAndTag()));
401 result.Dump(); // Dump so it is easier to find any potential issues with the pull in the test output.
402 result.Verify({.ExitCode = 0});
403
@@ -444,7 +445,7 @@ class WSLCE2EGlobalTests
445 Log::Comment(L"Testing non-elevated interactive session with explicit session name");
446 // Non-Elevated session shell should attach to the wslc by name also.
447 auto nonAdminName = GetExpectedDefaultSessionName(false);
447 - auto session = RunWslcInteractive(std::format(L"system session shell {}", nonAdminName), ElevationType::NonElevated);
448 + auto session = RunWslcInteractive(std::format(L"--session \"{}\" system session shell", nonAdminName), ElevationType::NonElevated);
449 VERIFY_IS_TRUE(session.IsRunning(), L"Session should be running");
450
451 session.ExpectStdout(VT::SESSION_PROMPT);
@@ -469,7 +470,7 @@ class WSLCE2EGlobalTests
470 Log::Comment(L"Testing elevated interactive session with explicit admin session name");
471 // Elevated session shell should attach to the wslc by name also.
472 auto adminName = GetExpectedDefaultSessionName(true);
472 - auto session = RunWslcInteractive(std::format(L"system session shell {}", adminName), ElevationType::Elevated);
473 + auto session = RunWslcInteractive(std::format(L"--session \"{}\" system session shell", adminName), ElevationType::Elevated);
474 VERIFY_IS_TRUE(session.IsRunning(), L"Session should be running");
475
476 session.ExpectStdout(VT::SESSION_PROMPT);
@@ -500,13 +501,13 @@ class WSLCE2EGlobalTests
501 }
502
503 {
503 - auto result = RunWslc(std::format(L"--session {} system session run echo OK", GetExpectedDefaultSessionName(true)));
504 + auto result = RunWslc(std::format(L"--session \"{}\" system session run echo OK", GetExpectedDefaultSessionName(true)));
505 result.Verify({.Stdout = L"OK\n", .Stderr = L"", .ExitCode = 0});
506 }
507
508 {
509 auto result = RunWslc(L"--session not-found system session run echo OK");
509 - result.Verify({.Stdout = L"", .Stderr = L"Session not found: 'not-found'\r\nError code: ERROR_NOT_FOUND\r\n", .ExitCode = 1});
510 + result.Verify({.Stderr = L"Session not found: 'not-found'\r\nError code: WSLC_E_SESSION_NOT_FOUND\r\n", .ExitCode = 1});
511 }
512
513 {
test/windows/wslc/e2e/WSLCE2EHelpers.cpp
+2 -2
@@ -145,7 +145,7 @@ void VerifyContainerIsListed(const std::wstring& containerNameOrId, const std::w
145 std::wstring command = L"container list --no-trunc --all";
146 if (!sessionName.empty())
147 {
148 - command = std::format(L"--session {} container list --no-trunc --all", sessionName);
148 + command = std::format(L"--session \"{}\" container list --no-trunc --all", sessionName);
149 }
150
151 auto result = RunWslc(command);
@@ -429,7 +429,7 @@ void EnsureSessionIsTerminated(const std::wstring& sessionName)
429 // Check if the line ends with the target session name
430 if (line.size() >= targetSession.size() && line.compare(line.size() - targetSession.size(), targetSession.size(), targetSession) == 0)
431 {
432 - auto result = RunWslc(std::format(L"system session terminate \"{}\"", targetSession));
432 + auto result = RunWslc(std::format(L"--session \"{}\" system session terminate", targetSession));
433 result.Verify({.Stdout = L"", .Stderr = L"", .ExitCode = 0});
434 break;
435 }
test/windows/wslc/e2e/WSLCE2ENetworkPruneTests.cpp
-1
@@ -244,7 +244,6 @@ private:
244 std::wstringstream options;
245 options << L"The following options are available:\r\n"
246 << L" -f,--filter " << Localization::WSLCCLI_FilterArgDescription() << L"\r\n"
247 - << L" --session " << Localization::WSLCCLI_SessionIdArgDescription() << L"\r\n"
247 << L" -?,--help " << Localization::WSLCCLI_HelpArgDescription() << L"\r\n"
248 << L"\r\n";
249 return options.str();
test/windows/wslc/e2e/WSLCE2ETlsRegistryTests.cpp
+6 -4
@@ -227,9 +227,10 @@ class WSLCE2ETlsRegistryTests
227 auto [registry, address] = StartLocalRegistry(session.Session(), "", "", c_registryPort, certDir.wstring());
228 VERIFY_ARE_EQUAL(std::format("{}:{}", c_registryIp, c_registryPort), address);
229
230 - RunWslcAndVerify(std::format(L"--session {} image tag {} {}", session.Name(), image.NameAndTag(), registryImage), {.ExitCode = 0});
230 + RunWslcAndVerify(
231 + std::format(L"--session \"{}\" image tag {} {}", session.Name(), image.NameAndTag(), registryImage), {.ExitCode = 0});
232
232 - auto result = RunWslc(std::format(L"--session {} push {}", session.Name(), registryImage));
233 + auto result = RunWslc(std::format(L"--session \"{}\" push {}", session.Name(), registryImage));
234 VERIFY_ARE_EQUAL(1u, result.ExitCode.value_or(0), L"Push should fail while the CA is not trusted");
235 VERIFY_IS_TRUE(result.Stderr.has_value());
236 VERIFY_IS_TRUE(
@@ -251,9 +252,10 @@ class WSLCE2ETlsRegistryTests
252 auto [registry, address] = StartLocalRegistry(session.Session(), "", "", c_registryPort, certDir.wstring());
253 VERIFY_ARE_EQUAL(std::format("{}:{}", c_registryIp, c_registryPort), address);
254
254 - RunWslcAndVerify(std::format(L"--session {} image tag {} {}", session.Name(), image.NameAndTag(), registryImage), {.ExitCode = 0});
255 + RunWslcAndVerify(
256 + std::format(L"--session \"{}\" image tag {} {}", session.Name(), image.NameAndTag(), registryImage), {.ExitCode = 0});
257
256 - auto result = RunWslc(std::format(L"--session {} push {}", session.Name(), registryImage));
258 + auto result = RunWslc(std::format(L"--session \"{}\" push {}", session.Name(), registryImage));
259 VERIFY_ARE_EQUAL(0u, result.ExitCode.value_or(1), L"Push should succeed once the CA is trusted");
260 }
261 }