From cf9f46402d3793acedd602742a24a50f44f05452 Mon Sep 17 00:00:00 2001 From: Matej Kafka Date: Mon, 8 Apr 2024 20:30:12 +0200 Subject: [PATCH] InitialSessionState: Add support for configuring initial working directory (#17603) --- .../engine/InitialSessionState.cs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index c30e199b2b1b..f2bf811fa302 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -1678,6 +1678,7 @@ public InitialSessionState Clone() ss.ThreadOptions = this.ThreadOptions; ss.ThrowOnRunspaceOpenError = this.ThrowOnRunspaceOpenError; ss.ApartmentState = this.ApartmentState; + ss.DefaultLocation = this.DefaultLocation; foreach (ModuleSpecification modSpec in this.ModuleSpecificationsToImport) { @@ -1831,6 +1832,12 @@ public Microsoft.PowerShell.ExecutionPolicy ExecutionPolicy /// public bool ThrowOnRunspaceOpenError { get; set; } = false; + /// + /// If not null, the working location of the runspace is set to this path. If null, + /// the process working directory is used as a default. + /// + public string DefaultLocation { get; set; } = null; + /// /// This property will be set only if we are refreshing the Type/Format settings by calling UpdateTypes/UpdateFormats directly. /// In this case, we should wait until all type/format entries get processed. After that, if there were errors @@ -2231,7 +2238,7 @@ internal void Bind(ExecutionContext context, bool updateOnly, PSModuleInfo modul } } - SetSessionStateDrive(context, setLocation: setLocation); + SetSessionStateDrive(context, setLocation, DefaultLocation); } private void Bind_SetVariables(SessionStateInternal ss) @@ -3370,7 +3377,7 @@ internal void ResetRunspaceState(ExecutionContext context) InitialSessionState.CreateQuestionVariable(context); // Reset the path for this runspace. - SetSessionStateDrive(context, true); + SetSessionStateDrive(context, true, DefaultLocation); // Reset the event, transaction and debug managers. context.ResetManagers(); @@ -3408,13 +3415,11 @@ private static bool TryInitSessionStateCurrentDrive(ExecutionContext context) } else { - ItemNotFoundException itemNotFound = new(Environment.CurrentDirectory, "PathNotFound", SessionStateStrings.PathNotFound); - context.ReportEngineStartupError(itemNotFound); return false; } } - internal static void SetSessionStateDrive(ExecutionContext context, bool setLocation) + internal static void SetSessionStateDrive(ExecutionContext context, bool setLocation, string location) { if (context.EngineSessionState.ProviderCount == 0) { @@ -3426,6 +3431,9 @@ internal static void SetSessionStateDrive(ExecutionContext context, bool setLoca // UNC paths if (context.EngineSessionState.CurrentDrive == null && !TryInitSessionStateCurrentDrive(context)) { + // FIXME: this is a wrong exception to throw, we don't yet know that the path was not found + ItemNotFoundException itemNotFound = new(location ?? Environment.CurrentDirectory, "PathNotFound", SessionStateStrings.PathNotFound); + context.ReportEngineStartupError(itemNotFound); return; } @@ -3436,7 +3444,16 @@ internal static void SetSessionStateDrive(ExecutionContext context, bool setLoca var providerContext = new CmdletProviderContext(context) { SuppressWildcardExpansion = true }; - // Set the starting location to the current process working directory + // User set a custom initial working directory. + if (location != null) + { + // If the location is invalid or does not exist, let the exception bubble up; since the user explicitly + // configured the working directory, he probably wants to get notified on failure. + context.EngineSessionState.SetLocation(location, providerContext); + return; + } + + // As a fallback, set the starting location to the current process working directory. // Ignore any errors as the file system provider may not be loaded or // a drive with the same name as the real file system drive may not have // been mounted.