diff --git a/.editorconfig b/.editorconfig
index 7f900f267..e0f9bbf3f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,7 +11,7 @@ insert_final_newline = true
indent_size = 4
trim_trailing_whitespace = true
csharp_space_before_open_square_brackets = true
-csharp_space_after_keywords_in_control_flow_statements = false
+csharp_space_after_keywords_in_control_flow_statements = true
[*.{json}]
indent_size = 2
diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
index 0e698f812..2a2ae3527 100644
--- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
+++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
@@ -349,7 +349,16 @@ private EditorServicesConfig CreateConfigObject()
var profile = (PSObject)GetVariableValue("profile");
var hostInfo = new HostInfo(HostName, HostProfileId, HostVersion);
- var editorServicesConfig = new EditorServicesConfig(hostInfo, Host, SessionDetailsPath, bundledModulesPath, LogPath)
+
+ var initialSessionState = Runspace.DefaultRunspace.InitialSessionState;
+ initialSessionState.LanguageMode = Runspace.DefaultRunspace.SessionStateProxy.LanguageMode;
+
+ var editorServicesConfig = new EditorServicesConfig(
+ hostInfo,
+ Host,
+ SessionDetailsPath,
+ bundledModulesPath,
+ LogPath)
{
FeatureFlags = FeatureFlags,
LogLevel = LogLevel,
@@ -357,7 +366,7 @@ private EditorServicesConfig CreateConfigObject()
AdditionalModules = AdditionalModules,
LanguageServiceTransport = GetLanguageServiceTransport(),
DebugServiceTransport = GetDebugServiceTransport(),
- LanguageMode = Runspace.DefaultRunspace.SessionStateProxy.LanguageMode,
+ InitialSessionState = initialSessionState,
ProfilePaths = new ProfilePathConfig
{
AllUsersAllHosts = GetProfilePathFromProfileObject(profile, ProfileUserKind.AllUsers, ProfileHostKind.AllHosts),
diff --git a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
index 5228ceced..2347ac4a1 100644
--- a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
+++ b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
@@ -2,8 +2,8 @@
// Licensed under the MIT License.
using System.Collections.Generic;
-using System.Management.Automation;
using System.Management.Automation.Host;
+using System.Management.Automation.Runspaces;
namespace Microsoft.PowerShell.EditorServices.Hosting
{
@@ -111,10 +111,9 @@ public EditorServicesConfig(
public ProfilePathConfig ProfilePaths { get; set; }
///
- /// The language mode inherited from the orginal PowerShell process.
- /// This will be used when creating runspaces so that we honor the same language mode.
+ /// The InitialSessionState to use when creating runspaces. LanguageMode can be set here.
///
- public PSLanguageMode LanguageMode { get; internal set; }
+ public InitialSessionState InitialSessionState { get; internal set; }
public string StartupBanner { get; set; } = @"
diff --git a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
index e49da8527..a68842876 100644
--- a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
+++ b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
@@ -288,7 +288,7 @@ private HostStartupInfo CreateHostStartupInfo()
profilePaths,
_config.FeatureFlags,
_config.AdditionalModules,
- _config.LanguageMode,
+ _config.InitialSessionState,
_config.LogPath,
(int)_config.LogLevel,
consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None,
diff --git a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
index 9fc788e0d..ed6fb3e11 100644
--- a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
+++ b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
@@ -3,8 +3,8 @@
using System;
using System.Collections.Generic;
-using System.Management.Automation;
using System.Management.Automation.Host;
+using System.Management.Automation.Runspaces;
namespace Microsoft.PowerShell.EditorServices.Hosting
{
@@ -92,10 +92,10 @@ public sealed class HostStartupInfo
public string LogPath { get; }
///
- /// The language mode inherited from the orginal PowerShell process.
- /// This will be used when creating runspaces so that we honor the same language mode.
+ /// The InitialSessionState will be inherited from the orginal PowerShell process. This will
+ /// be used when creating runspaces so that we honor the same InitialSessionState.
///
- public PSLanguageMode LanguageMode { get; }
+ public InitialSessionState InitialSessionState { get; }
///
/// The minimum log level of log events to be logged.
@@ -135,7 +135,7 @@ public sealed class HostStartupInfo
/// The path to the user specific profile.
/// Flags of features to enable.
/// Names or paths of additional modules to import.
- /// The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same language mode.
+ /// The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same initialSessionState including allowed modules, cmdlets and language mode.
/// The path to log to.
/// The minimum log event level.
/// Enable console if true.
@@ -149,7 +149,7 @@ public HostStartupInfo(
ProfilePathInfo profilePaths,
IReadOnlyList featureFlags,
IReadOnlyList additionalModules,
- PSLanguageMode languageMode,
+ InitialSessionState initialSessionState,
string logPath,
int logLevel,
bool consoleReplEnabled,
@@ -163,7 +163,7 @@ public HostStartupInfo(
ProfilePaths = profilePaths;
FeatureFlags = featureFlags ?? Array.Empty();
AdditionalModules = additionalModules ?? Array.Empty();
- LanguageMode = languageMode;
+ InitialSessionState = initialSessionState;
LogPath = logPath;
LogLevel = logLevel;
ConsoleReplEnabled = consoleReplEnabled;
diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs
index 198cd26d9..c2194a9bd 100644
--- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs
+++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs
@@ -11,7 +11,6 @@
using System.Management.Automation.Remoting;
using System.Management.Automation.Runspaces;
using System.Reflection;
-using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -230,7 +229,7 @@ public static PowerShellContextService Create(
logger);
logger.LogTrace("Creating initial PowerShell runspace");
- Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.LanguageMode);
+ Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.InitialSessionState);
powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface);
powerShellContext.ImportCommandsModuleAsync();
@@ -256,14 +255,17 @@ public static PowerShellContextService Create(
}
///
- ///
+ /// Only used in testing. Creates a Runspace given HostStartupInfo instead of a PSHost.
///
+ ///
+ /// TODO: We should use `CreateRunspace` in testing instead of this, if possible.
+ ///
///
///
/// The EditorServicesPSHostUserInterface to use for this instance.
/// An ILogger implementation to use for this instance.
///
- public static Runspace CreateRunspace(
+ public static Runspace CreateTestRunspace(
HostStartupInfo hostDetails,
PowerShellContextService powerShellContext,
EditorServicesPSHostUserInterface hostUserInterface,
@@ -274,38 +276,17 @@ public static Runspace CreateRunspace(
var psHost = new EditorServicesPSHost(powerShellContext, hostDetails, hostUserInterface, logger);
powerShellContext.ConsoleWriter = hostUserInterface;
powerShellContext.ConsoleReader = hostUserInterface;
- return CreateRunspace(psHost, hostDetails.LanguageMode);
+ return CreateRunspace(psHost, hostDetails.InitialSessionState);
}
///
///
///
/// The PSHost that will be used for this Runspace.
- /// The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same language mode.
+ /// This will be used when creating runspaces so that we honor the same InitialSessionState.
///
- public static Runspace CreateRunspace(PSHost psHost, PSLanguageMode languageMode)
+ public static Runspace CreateRunspace(PSHost psHost, InitialSessionState initialSessionState)
{
- InitialSessionState initialSessionState;
- if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") {
- initialSessionState = InitialSessionState.CreateDefault();
- } else {
- initialSessionState = InitialSessionState.CreateDefault2();
- }
-
- // Create and initialize a new Runspace while honoring the LanguageMode of the original runspace
- // that started PowerShell Editor Services. This is because the PowerShell Integrated Console
- // should have the same LanguageMode of whatever is set by the system.
- initialSessionState.LanguageMode = languageMode;
-
- // We set the process scope's execution policy (which is really the runspace's scope) to
- // Bypass so we can import our bundled modules. This is equivalent in scope to the CLI
- // argument `-Bypass`, which (for instance) the extension passes. Thus we emulate this
- // behavior for consistency such that unit tests can pass in a similar environment.
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- initialSessionState.ExecutionPolicy = ExecutionPolicy.Bypass;
- }
-
Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState);
// Windows PowerShell must be hosted in STA mode
@@ -434,10 +415,9 @@ public void Initialize(
this.PromptContext = new LegacyReadLineContext(this);
}
- if (VersionUtils.IsWindows)
- {
- this.SetExecutionPolicy();
- }
+ // Finally, restore the runspace's execution policy to the user's policy instead of
+ // Bypass.
+ this.RestoreExecutionPolicy();
}
///
@@ -2152,9 +2132,20 @@ private static string GetStringForPSCommand(PSCommand psCommand)
return stringBuilder.ToString();
}
- private void SetExecutionPolicy()
+ ///
+ /// This function restores the execution policy for the process by examining the user's
+ /// execution policy hierarchy. We do this because the process policy will always be set to
+ /// Bypass when initializing our runspaces.
+ ///
+ internal void RestoreExecutionPolicy()
{
- this.logger.LogTrace("Setting execution policy...");
+ // Execution policy is a Windows-only feature.
+ if (!VersionUtils.IsWindows)
+ {
+ return;
+ }
+
+ this.logger.LogTrace("Restoring execution policy...");
// We want to get the list hierarchy of execution policies
// Calling the cmdlet is the simplest way to do that
diff --git a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs
index 41c3e4730..422cc58a0 100644
--- a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs
+++ b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Management.Automation;
+using System.Management.Automation.Runspaces;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -13,6 +13,7 @@
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.PowerShellContext;
using Microsoft.PowerShell.EditorServices.Test.Shared;
+using Microsoft.PowerShell.EditorServices.Utility;
namespace Microsoft.PowerShell.EditorServices.Test
{
@@ -40,6 +41,16 @@ internal static class PowerShellContextFactory
public static PowerShellContextService Create(ILogger logger)
{
PowerShellContextService powerShellContext = new PowerShellContextService(logger, null, isPSReadLineEnabled: false);
+ var initialSessionState = InitialSessionState.CreateDefault();
+ // We set the process scope's execution policy (which is really the runspace's scope) to
+ // `Bypass` so we can import our bundled modules. This is equivalent in scope to the CLI
+ // argument `-ExecutionPolicy Bypass`, which (for instance) the extension passes. Thus
+ // we emulate this behavior for consistency such that unit tests can pass in a similar
+ // environment.
+ if (VersionUtils.IsWindows)
+ {
+ initialSessionState.ExecutionPolicy = ExecutionPolicy.Bypass;
+ }
HostStartupInfo testHostDetails = new HostStartupInfo(
"PowerShell Editor Services Test Host",
@@ -49,16 +60,14 @@ public static PowerShellContextService Create(ILogger logger)
TestProfilePaths,
new List(),
new List(),
- // TODO: We want to replace this property with an entire initial session state,
- // which would then also control the process-scoped execution policy.
- PSLanguageMode.FullLanguage,
+ initialSessionState,
null,
0,
consoleReplEnabled: false,
usesLegacyReadLine: false,
bundledModulePath: BundledModulePath);
- InitialRunspace = PowerShellContextService.CreateRunspace(
+ InitialRunspace = PowerShellContextService.CreateTestRunspace(
testHostDetails,
powerShellContext,
new TestPSHostUserInterface(powerShellContext, logger),