From d9fef9cb6dfba279c1e9d758b3491ed65b05d4bf Mon Sep 17 00:00:00 2001 From: "Tyler Leonhardt (POWERSHELL)" Date: Tue, 21 Apr 2020 17:20:58 -0700 Subject: [PATCH 1/5] change some to AddScript useLocalScope --- .../EditorServicesLoader.cs | 2 +- .../PowerShellContext/PowerShellContextService.cs | 6 +++--- .../Session/Capabilities/DscBreakpointCapability.cs | 13 ++++++++----- .../PowerShellContext/Session/ExecutionOptions.cs | 12 ++++++++++++ .../Session/PSReadLinePromptContext.cs | 2 +- .../PowerShellContext/Session/SessionDetails.cs | 3 ++- 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs index 7690070a0..466f3c638 100644 --- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs +++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs @@ -332,7 +332,7 @@ private string GetPSOutputEncoding() { using (var pwsh = SMA.PowerShell.Create()) { - return pwsh.AddScript("$OutputEncoding.EncodingName").Invoke()[0]; + return pwsh.AddScript("$OutputEncoding.EncodingName", useLocalScope: true).Invoke()[0]; } } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 4f9639209..1be3aa7eb 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -597,7 +597,7 @@ public async Task> ExecuteCommandAsync( // cancelled prompt when it's called again. if (executionOptions.AddToHistory) { - this.PromptContext.AddToHistory(psCommand.Commands[0].CommandText); + this.PromptContext.AddToHistory(executionOptions.InputString ?? psCommand.Commands[0].CommandText); } bool hadErrors = false; @@ -686,7 +686,7 @@ public async Task> ExecuteCommandAsync( if (executionOptions.WriteInputToHost) { this.WriteOutput( - psCommand.Commands[0].CommandText, + executionOptions.InputString ?? psCommand.Commands[0].CommandText, includeNewLine: true); } @@ -1161,7 +1161,7 @@ internal static TResult ExecuteScriptAndGetItem(string scriptToExecute, using (PowerShell pwsh = PowerShell.Create()) { pwsh.Runspace = runspace; - IEnumerable results = pwsh.AddScript(scriptToExecute).Invoke(); + IEnumerable results = pwsh.AddScript(scriptToExecute, useLocalScope: true).Invoke(); return results.DefaultIfEmpty(defaultValue).First(); } } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/Capabilities/DscBreakpointCapability.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/Capabilities/DscBreakpointCapability.cs index 247c1d13e..4c9c87d92 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/Capabilities/DscBreakpointCapability.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/Capabilities/DscBreakpointCapability.cs @@ -121,14 +121,17 @@ public static DscBreakpointCapability CheckForCapability( runspaceDetails.AddCapability(capability); powerShell.Commands.Clear(); - powerShell.AddScript("Write-Host \"Gathering DSC resource paths, this may take a while...\""); - powerShell.Invoke(); + powerShell + .AddCommand("Microsoft.PowerShell.Utility\\Write-Host") + .AddArgument("Gathering DSC resource paths, this may take a while...") + .Invoke(); // Get the list of DSC resource paths powerShell.Commands.Clear(); - powerShell.AddCommand("Get-DscResource"); - powerShell.AddCommand("Select-Object"); - powerShell.AddParameter("ExpandProperty", "ParentPath"); + powerShell + .AddCommand("Get-DscResource") + .AddCommand("Select-Object") + .AddParameter("ExpandProperty", "ParentPath"); Collection resourcePaths = null; diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/ExecutionOptions.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/ExecutionOptions.cs index 31e0ab1de..df585ca79 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/ExecutionOptions.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/ExecutionOptions.cs @@ -46,6 +46,18 @@ internal class ExecutionOptions /// public bool WriteInputToHost { get; set; } + /// + /// If this is set, we will use this string for history and writing to the host + /// instead of grabbing the command from the PSCommand. + /// + public string InputString { get; set; } + + /// + /// If this is set, we will use this string for history and writing to the host + /// instead of grabbing the command from the PSCommand. + /// + public bool UseNewScope { get; set; } + /// /// Gets or sets a value indicating whether the command to /// be executed is a console input prompt, such as the diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs index 93a098f2e..7a14d8e7a 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs @@ -91,7 +91,7 @@ internal static bool TryGetPSReadLineProxy( { pwsh.Runspace = runspace; var psReadLineType = pwsh - .AddScript(ReadLineInitScript) + .AddScript(ReadLineInitScript, useLocalScope: true) .Invoke() .FirstOrDefault(); diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/SessionDetails.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/SessionDetails.cs index 9054e5784..39f12fdae 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/SessionDetails.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/SessionDetails.cs @@ -56,7 +56,8 @@ public static PSCommand GetDetailsCommand() { PSCommand infoCommand = new PSCommand(); infoCommand.AddScript( - "@{ 'computerName' = if ([Environment]::MachineName) {[Environment]::MachineName} else {'localhost'}; 'processId' = $PID; 'instanceId' = $host.InstanceId }"); + "@{ 'computerName' = if ([Environment]::MachineName) {[Environment]::MachineName} else {'localhost'}; 'processId' = $PID; 'instanceId' = $host.InstanceId }", + useLocalScope: true); return infoCommand; } From 3bf1bacb862b743c965a5f7bfe12103e9cc7dc3b Mon Sep 17 00:00:00 2001 From: "Tyler Leonhardt (POWERSHELL)" Date: Wed, 22 Apr 2020 16:16:28 -0700 Subject: [PATCH 2/5] initial support of constrainedlanguage mode --- .../Commands/StartEditorServicesCommand.cs | 2 ++ .../Configuration/EditorServicesConfig.cs | 6 ++++++ .../EditorServicesLoader.cs | 15 --------------- .../Internal/EditorServicesRunner.cs | 1 + .../Hosting/HostStartupInfo.cs | 8 ++++++++ .../PowerShellContext/PowerShellContextService.cs | 10 +++++++--- .../PowerShellContextFactory.cs | 2 ++ 7 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs index 3eebe047c..9c24da69f 100644 --- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs +++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs @@ -11,6 +11,7 @@ using System.Management.Automation; using System.Reflection; using SMA = System.Management.Automation; +using System.Management.Automation.Runspaces; using Microsoft.PowerShell.EditorServices.Hosting; using System.Globalization; using System.Collections; @@ -358,6 +359,7 @@ private EditorServicesConfig CreateConfigObject() AdditionalModules = AdditionalModules, LanguageServiceTransport = GetLanguageServiceTransport(), DebugServiceTransport = GetDebugServiceTransport(), + LanguageMode = Runspace.DefaultRunspace.SessionStateProxy.LanguageMode, 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 e56f4d27b..d9d70ce81 100644 --- a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs +++ b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs @@ -4,6 +4,7 @@ // using System.Collections.Generic; +using System.Management.Automation; using System.Management.Automation.Host; namespace Microsoft.PowerShell.EditorServices.Hosting @@ -111,6 +112,11 @@ public EditorServicesConfig( /// public ProfilePathConfig ProfilePaths { get; set; } + /// + /// The language mode of the original runspace that we will inherit from. + /// + public PSLanguageMode LanguageMode { get; internal set; } + public string StartupBanner { get; set; } = @" =====> PowerShell Integrated Console <===== diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs index 466f3c638..f387063e5 100644 --- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs +++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs @@ -190,8 +190,6 @@ public Task LoadAndRunEditorServicesAsync() // Make sure the .NET Framework version supports .NET Standard 2.0 CheckNetFxVersion(); #endif - // Ensure the language mode allows us to run - CheckLanguageMode(); // Add the bundled modules to the PSModulePath UpdatePSModulePath(); @@ -250,19 +248,6 @@ private void CheckNetFxVersion() } #endif - /// - /// PSES currently does not work in Constrained Language Mode, because PSReadLine script invocations won't work in it. - /// Ideally we can find a better way so that PSES will work in CLM. - /// - private void CheckLanguageMode() - { - _logger.Log(PsesLogLevel.Diagnostic, "Checking that PSES is running in FullLanguage mode"); - if (Runspace.DefaultRunspace.SessionStateProxy.LanguageMode != PSLanguageMode.FullLanguage) - { - throw new InvalidOperationException("Cannot start PowerShell Editor Services in Constrained Language Mode"); - } - } - private void UpdatePSModulePath() { if (string.IsNullOrEmpty(_hostConfig.BundledModulePath)) diff --git a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs index cd8ae8013..e153f76a2 100644 --- a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs +++ b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs @@ -238,6 +238,7 @@ private HostStartupInfo CreateHostStartupInfo() _config.FeatureFlags, _config.AdditionalModules, _config.LogPath, + _config.LanguageMode, (int)_config.LogLevel, consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None, usesLegacyReadLine: _config.ConsoleRepl == ConsoleReplKind.LegacyReadLine); diff --git a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs index b6ff618a3..0ba043587 100644 --- a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs +++ b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Management.Automation; using System.Management.Automation.Host; namespace Microsoft.PowerShell.EditorServices.Hosting @@ -89,6 +90,11 @@ public sealed class HostStartupInfo /// public string LogPath { get; } + /// + /// The language mode of the original runspace that we will inherit from. + /// + public PSLanguageMode LanguageMode { get; } + /// /// The minimum log level of log events to be logged. /// @@ -130,6 +136,7 @@ public HostStartupInfo( IReadOnlyList featureFlags, IReadOnlyList additionalModules, string logPath, + PSLanguageMode languageMode, int logLevel, bool consoleReplEnabled, bool usesLegacyReadLine) @@ -142,6 +149,7 @@ public HostStartupInfo( FeatureFlags = featureFlags ?? Array.Empty(); AdditionalModules = additionalModules ?? Array.Empty(); LogPath = logPath; + LanguageMode = languageMode; LogLevel = logLevel; ConsoleReplEnabled = consoleReplEnabled; UsesLegacyReadLine = usesLegacyReadLine; diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 1be3aa7eb..e87f735fb 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -213,7 +213,7 @@ public static PowerShellContextService Create( hostUserInterface, logger); - Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost); + Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.LanguageMode); powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); powerShellContext.ImportCommandsModuleAsync(); @@ -260,7 +260,7 @@ public static Runspace CreateRunspace( var psHost = new EditorServicesPSHost(powerShellContext, hostDetails, hostUserInterface, logger); powerShellContext.ConsoleWriter = hostUserInterface; powerShellContext.ConsoleReader = hostUserInterface; - return CreateRunspace(psHost); + return CreateRunspace(psHost, hostDetails.LanguageMode); } /// @@ -268,7 +268,7 @@ public static Runspace CreateRunspace( /// /// /// - public static Runspace CreateRunspace(PSHost psHost) + public static Runspace CreateRunspace(PSHost psHost, PSLanguageMode languageMode) { InitialSessionState initialSessionState; if (Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1") { @@ -277,6 +277,10 @@ public static Runspace CreateRunspace(PSHost psHost) initialSessionState = InitialSessionState.CreateDefault2(); } + // Create and initialize a new Runspace while honoring the LanguageMode. + Console.WriteLine(languageMode); + initialSessionState.LanguageMode = languageMode; + Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); // Windows PowerShell must be hosted in STA mode diff --git a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs index 17d02c5ed..ae50c9acf 100644 --- a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs +++ b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Management.Automation; using System.Threading; using System.Threading.Tasks; @@ -46,6 +47,7 @@ public static PowerShellContextService Create(ILogger logger) new List(), new List(), null, + PSLanguageMode.FullLanguage, 0, consoleReplEnabled: false, usesLegacyReadLine: false); From c82c4627e45eb1a43ea3670c99f804226b497c99 Mon Sep 17 00:00:00 2001 From: "Tyler Leonhardt (POWERSHELL)" Date: Thu, 23 Apr 2020 11:53:02 -0700 Subject: [PATCH 3/5] polish ConstrainedLanguage mode --- .../Commands/Public/Clear-Host.ps1 | 4 +++- .../Configuration/EditorServicesConfig.cs | 3 ++- .../Internal/EditorServicesRunner.cs | 2 +- .../Hosting/HostStartupInfo.cs | 8 +++++--- .../PowerShellContext/PowerShellContextService.cs | 14 ++++++++------ .../PowerShellContextFactory.cs | 2 +- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/module/PowerShellEditorServices/Commands/Public/Clear-Host.ps1 b/module/PowerShellEditorServices/Commands/Public/Clear-Host.ps1 index 50e9d4503..373f19d69 100644 --- a/module/PowerShellEditorServices/Commands/Public/Clear-Host.ps1 +++ b/module/PowerShellEditorServices/Commands/Public/Clear-Host.ps1 @@ -10,7 +10,9 @@ function Clear-Host { param() __clearhost - $psEditor.Window.Terminal.Clear() + if ($host.Runspace.LanguageMode -eq [System.Management.Automation.PSLanguageMode]::FullLanguage) { + $psEditor.Window.Terminal.Clear() + } } if (!$IsMacOS -or $IsLinux) { diff --git a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs index d9d70ce81..7650a522b 100644 --- a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs +++ b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs @@ -113,7 +113,8 @@ public EditorServicesConfig( public ProfilePathConfig ProfilePaths { get; set; } /// - /// The language mode of the original runspace that we will inherit from. + /// The language mode inherited from the orginal PowerShell process. + /// This will be used when creating runspaces so that we honor the same language mode. /// public PSLanguageMode LanguageMode { get; internal set; } diff --git a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs index e153f76a2..730964127 100644 --- a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs +++ b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs @@ -237,8 +237,8 @@ private HostStartupInfo CreateHostStartupInfo() profilePaths, _config.FeatureFlags, _config.AdditionalModules, - _config.LogPath, _config.LanguageMode, + _config.LogPath, (int)_config.LogLevel, consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None, usesLegacyReadLine: _config.ConsoleRepl == ConsoleReplKind.LegacyReadLine); diff --git a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs index 0ba043587..5cd5232f9 100644 --- a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs +++ b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs @@ -91,7 +91,8 @@ public sealed class HostStartupInfo public string LogPath { get; } /// - /// The language mode of the original runspace that we will inherit from. + /// The language mode inherited from the orginal PowerShell process. + /// This will be used when creating runspaces so that we honor the same language mode. /// public PSLanguageMode LanguageMode { get; } @@ -123,6 +124,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 path to log to. /// The minimum log event level. /// Enable console if true. @@ -135,8 +137,8 @@ public HostStartupInfo( ProfilePathInfo profilePaths, IReadOnlyList featureFlags, IReadOnlyList additionalModules, - string logPath, PSLanguageMode languageMode, + string logPath, int logLevel, bool consoleReplEnabled, bool usesLegacyReadLine) @@ -148,8 +150,8 @@ public HostStartupInfo( ProfilePaths = profilePaths; FeatureFlags = featureFlags ?? Array.Empty(); AdditionalModules = additionalModules ?? Array.Empty(); - LogPath = logPath; LanguageMode = languageMode; + LogPath = logPath; LogLevel = logLevel; ConsoleReplEnabled = consoleReplEnabled; UsesLegacyReadLine = usesLegacyReadLine; diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index e87f735fb..03ad232d0 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -244,9 +244,7 @@ public static PowerShellContextService Create( /// /// /// - /// - /// The EditorServicesPSHostUserInterface to use for this instance. - /// + /// The EditorServicesPSHostUserInterface to use for this instance. /// An ILogger implementation to use for this instance. /// public static Runspace CreateRunspace( @@ -266,7 +264,8 @@ public static Runspace CreateRunspace( /// /// /// - /// + /// 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. /// public static Runspace CreateRunspace(PSHost psHost, PSLanguageMode languageMode) { @@ -277,8 +276,9 @@ public static Runspace CreateRunspace(PSHost psHost, PSLanguageMode languageMode initialSessionState = InitialSessionState.CreateDefault2(); } - // Create and initialize a new Runspace while honoring the LanguageMode. - Console.WriteLine(languageMode); + // 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; Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState); @@ -414,6 +414,8 @@ public void Initialize( if (powerShellVersion.Major >= 5 && this.isPSReadLineEnabled && + // TODO: Figure out why PSReadLine isn't working in ConstrainedLanguage mode. + initialRunspace.SessionStateProxy.LanguageMode == PSLanguageMode.FullLanguage && PSReadLinePromptContext.TryGetPSReadLineProxy(logger, initialRunspace, out PSReadLineProxy proxy)) { this.PromptContext = new PSReadLinePromptContext( diff --git a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs index ae50c9acf..7b5cb229c 100644 --- a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs +++ b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs @@ -46,8 +46,8 @@ public static PowerShellContextService Create(ILogger logger) TestProfilePaths, new List(), new List(), - null, PSLanguageMode.FullLanguage, + null, 0, consoleReplEnabled: false, usesLegacyReadLine: false); From 73511fd85e231a3780ba68ef21ef0062f96f9be0 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Fri, 24 Apr 2020 09:37:29 -0700 Subject: [PATCH 4/5] useLocalScope --- .../PowerShellContext/PowerShellContextService.cs | 8 ++++++-- .../PowerShellContext/Session/PowerShellVersionDetails.cs | 4 ++-- .../Services/PowerShellContext/Session/RunspaceDetails.cs | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 03ad232d0..f79cbc4c2 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -1162,12 +1162,16 @@ internal async Task InvokeReadLineAsync(bool isCommandLine, Cancellation cancellationToken).ConfigureAwait(false); } - internal static TResult ExecuteScriptAndGetItem(string scriptToExecute, Runspace runspace, TResult defaultValue = default) + internal static TResult ExecuteScriptAndGetItem( + string scriptToExecute, + Runspace runspace, + TResult defaultValue = default, + bool useLocalScope = false) { using (PowerShell pwsh = PowerShell.Create()) { pwsh.Runspace = runspace; - IEnumerable results = pwsh.AddScript(scriptToExecute, useLocalScope: true).Invoke(); + IEnumerable results = pwsh.AddScript(scriptToExecute, useLocalScope).Invoke(); return results.DefaultIfEmpty(defaultValue).First(); } } diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PowerShellVersionDetails.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PowerShellVersionDetails.cs index 72b8dc5be..71d56f234 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/PowerShellVersionDetails.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/PowerShellVersionDetails.cs @@ -101,7 +101,7 @@ public static PowerShellVersionDetails GetVersionDetails(Runspace runspace, ILog try { - var psVersionTable = PowerShellContextService.ExecuteScriptAndGetItem("$PSVersionTable", runspace); + var psVersionTable = PowerShellContextService.ExecuteScriptAndGetItem("$PSVersionTable", runspace, useLocalScope: true); if (psVersionTable != null) { var edition = psVersionTable["PSEdition"] as string; @@ -134,7 +134,7 @@ public static PowerShellVersionDetails GetVersionDetails(Runspace runspace, ILog versionString = powerShellVersion.ToString(); } - var arch = PowerShellContextService.ExecuteScriptAndGetItem("$env:PROCESSOR_ARCHITECTURE", runspace); + var arch = PowerShellContextService.ExecuteScriptAndGetItem("$env:PROCESSOR_ARCHITECTURE", runspace, useLocalScope: true); if (arch != null) { if (string.Equals(arch, "AMD64", StringComparison.CurrentCultureIgnoreCase)) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/RunspaceDetails.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/RunspaceDetails.cs index d5013c9f9..be5aea9cf 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/RunspaceDetails.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/RunspaceDetails.cs @@ -223,7 +223,8 @@ internal static RunspaceDetails CreateFromRunspace( PowerShellContextService.ExecuteScriptAndGetItem( "$Host.Name", runspace, - defaultValue: string.Empty); + defaultValue: string.Empty, + useLocalScope: true); // hostname is 'ServerRemoteHost' when the user enters a session. // ex. Enter-PSSession From b476c6a5afcf64bd14796d517a240857a5552f4c Mon Sep 17 00:00:00 2001 From: "Tyler Leonhardt (POWERSHELL)" Date: Mon, 27 Apr 2020 15:21:42 -0700 Subject: [PATCH 5/5] have e2e tests also run in CLM --- PowerShellEditorServices.build.ps1 | 10 ++++ .../LanguageServerProtocolMessageTests.cs | 52 +++++++++++++++---- .../PowerShellEditorServices.Test.E2E.csproj | 1 + .../TestsFixture.cs | 7 +-- 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index af68856eb..66a17c569 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -274,6 +274,16 @@ task TestE2E { $env:PWSH_EXE_NAME = if ($IsCoreCLR) { "pwsh" } else { "powershell" } exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Core (DotNetTestFilter) } + + # Run E2E tests in ConstrainedLanguage mode. + if (!$script:IsUnix) { + try { + [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", [System.EnvironmentVariableTarget]::Machine); + exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Core (DotNetTestFilter) } + } finally { + [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", $null, [System.EnvironmentVariableTarget]::Machine); + } + } } task LayoutModule -After Build { diff --git a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs index 4640ab723..6999f158b 100644 --- a/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs +++ b/test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs @@ -135,9 +135,13 @@ function CanSendWorkspaceSymbolRequest { Assert.Equal("CanSendWorkspaceSymbolRequest { }", symbol.Name); } - [Fact] + [SkippableFact] public async Task CanReceiveDiagnosticsFromFileOpen() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + NewTestFile("$a = 4"); await WaitForDiagnostics(); @@ -154,9 +158,13 @@ public async Task WontReceiveDiagnosticsFromFileOpenThatIsNotPowerShell() Assert.Empty(Diagnostics); } - [Fact] + [SkippableFact] public async Task CanReceiveDiagnosticsFromFileChanged() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string filePath = NewTestFile("$a = 4"); await WaitForDiagnostics(); Diagnostics.Clear(); @@ -191,9 +199,13 @@ public async Task CanReceiveDiagnosticsFromFileChanged() Assert.Equal("PSUseDeclaredVarsMoreThanAssignments", diagnostic.Code); } - [Fact] + [SkippableFact] public async Task CanReceiveDiagnosticsFromConfigurationChange() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + NewTestFile("gci | % { $_ }"); await WaitForDiagnostics(); @@ -275,9 +287,13 @@ await LanguageClient.SendRequest>( }); } - [Fact] + [SkippableFact] public async Task CanSendFormattingRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string scriptPath = NewTestFile(@" gci | % { Get-Process @@ -306,9 +322,13 @@ public async Task CanSendFormattingRequest() Assert.Contains("\t", textEdit.NewText); } - [Fact] + [SkippableFact] public async Task CanSendRangeFormattingRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string scriptPath = NewTestFile(@" gci | % { Get-Process @@ -756,9 +776,13 @@ function CanSendReferencesCodeLensRequest { Assert.Equal("1 reference", codeLensResolveResult.Command.Title); } - [Fact] + [SkippableFact] public async Task CanSendCodeActionRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string filePath = NewTestFile("gci"); await WaitForDiagnostics(); @@ -929,9 +953,11 @@ await LanguageClient.SendRequest( Assert.Equal(33, locationOrLocationLink.Location.Range.End.Character); } - [Fact] + [SkippableFact] public async Task CanSendGetProjectTemplatesRequest() { + Skip.If(TestsFixture.RunningInConstainedLanguageMode, "Plaster doesn't work in ConstrainedLanguage mode."); + GetProjectTemplatesResponse getProjectTemplatesResponse = await LanguageClient.SendRequest( "powerShell/getProjectTemplates", @@ -951,9 +977,13 @@ await LanguageClient.SendRequest( }); } - [Fact] + [SkippableFact] public async Task CanSendGetCommentHelpRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode && TestsFixture.IsWindowsPowerShell, + "Windows PowerShell doesn't trust PSScriptAnalyzer by default so it won't load."); + string scriptPath = NewTestFile(@" function CanSendGetCommentHelpRequest { param( @@ -1012,9 +1042,13 @@ public async Task CanSendGetCommandRequest() Assert.True(pSCommandMessages.Count > 20); } - [Fact] + [SkippableFact] public async Task CanSendExpandAliasRequest() { + Skip.If( + TestsFixture.RunningInConstainedLanguageMode, + "This feature currently doesn't support ConstrainedLanguage Mode."); + ExpandAliasResult expandAliasResult = await LanguageClient.SendRequest( "powerShell/expandAlias", diff --git a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj index 58da8923b..5e9dc7ecd 100644 --- a/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj +++ b/test/PowerShellEditorServices.Test.E2E/PowerShellEditorServices.Test.E2E.csproj @@ -13,6 +13,7 @@ + diff --git a/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs b/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs index e56d4668f..b0eca7af9 100644 --- a/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs +++ b/test/PowerShellEditorServices.Test.E2E/TestsFixture.cs @@ -5,10 +5,7 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Linq; -using OmniSharp.Extensions.LanguageServer.Client; using OmniSharp.Extensions.LanguageServer.Client.Processes; -using OmniSharp.Extensions.LanguageServer.Protocol.Models; using Xunit; namespace PowerShellEditorServices.Test.E2E @@ -42,6 +39,10 @@ public abstract class TestsFixture : IAsyncLifetime public static string PwshExe { get; } = Environment.GetEnvironmentVariable("PWSH_EXE_NAME") ?? "pwsh"; + public static bool IsWindowsPowerShell { get; } = PwshExe.Contains("powershell"); + public static bool RunningInConstainedLanguageMode { get; } = + Environment.GetEnvironmentVariable("__PSLockdownPolicy", EnvironmentVariableTarget.Machine) != null; + public virtual bool IsDebugAdapterTests { get; set; } public async Task InitializeAsync()