Skip to content

Support ConstrainedLanguage mode #1269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//

using System.Collections.Generic;
using System.Management.Automation;
using System.Management.Automation.Host;

namespace Microsoft.PowerShell.EditorServices.Hosting
Expand Down Expand Up @@ -111,6 +112,12 @@ public EditorServicesConfig(
/// </summary>
public ProfilePathConfig ProfilePaths { get; set; }

/// <summary>
/// The language mode inherited from the orginal PowerShell process.
/// This will be used when creating runspaces so that we honor the same language mode.
/// </summary>
public PSLanguageMode LanguageMode { get; internal set; }

public string StartupBanner { get; set; } = @"

=====> PowerShell Integrated Console <=====
Expand Down
17 changes: 1 addition & 16 deletions src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -250,19 +248,6 @@ private void CheckNetFxVersion()
}
#endif

/// <summary>
/// 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.
/// </summary>
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))
Expand Down Expand Up @@ -332,7 +317,7 @@ private string GetPSOutputEncoding()
{
using (var pwsh = SMA.PowerShell.Create())
{
return pwsh.AddScript("$OutputEncoding.EncodingName").Invoke<string>()[0];
return pwsh.AddScript("$OutputEncoding.EncodingName", useLocalScope: true).Invoke<string>()[0];
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ private HostStartupInfo CreateHostStartupInfo()
profilePaths,
_config.FeatureFlags,
_config.AdditionalModules,
_config.LanguageMode,
_config.LogPath,
(int)_config.LogLevel,
consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None,
Expand Down
10 changes: 10 additions & 0 deletions src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Management.Automation.Host;

namespace Microsoft.PowerShell.EditorServices.Hosting
Expand Down Expand Up @@ -89,6 +90,12 @@ public sealed class HostStartupInfo
/// </summary>
public string LogPath { get; }

/// <summary>
/// The language mode inherited from the orginal PowerShell process.
/// This will be used when creating runspaces so that we honor the same language mode.
/// </summary>
public PSLanguageMode LanguageMode { get; }

/// <summary>
/// The minimum log level of log events to be logged.
/// </summary>
Expand Down Expand Up @@ -117,6 +124,7 @@ public sealed class HostStartupInfo
/// <param name="currentUsersProfilePath">The path to the user specific profile.</param>
/// <param name="featureFlags">Flags of features to enable.</param>
/// <param name="additionalModules">Names or paths of additional modules to import.</param>
/// <param name="languageMode">The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same language mode.</param>
/// <param name="logPath">The path to log to.</param>
/// <param name="logLevel">The minimum log event level.</param>
/// <param name="consoleReplEnabled">Enable console if true.</param>
Expand All @@ -129,6 +137,7 @@ public HostStartupInfo(
ProfilePathInfo profilePaths,
IReadOnlyList<string> featureFlags,
IReadOnlyList<string> additionalModules,
PSLanguageMode languageMode,
string logPath,
int logLevel,
bool consoleReplEnabled,
Expand All @@ -141,6 +150,7 @@ public HostStartupInfo(
ProfilePaths = profilePaths;
FeatureFlags = featureFlags ?? Array.Empty<string>();
AdditionalModules = additionalModules ?? Array.Empty<string>();
LanguageMode = languageMode;
LogPath = logPath;
LogLevel = logLevel;
ConsoleReplEnabled = consoleReplEnabled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -244,9 +244,7 @@ public static PowerShellContextService Create(
/// </summary>
/// <param name="hostDetails"></param>
/// <param name="powerShellContext"></param>
/// <param name="hostUserInterface">
/// The EditorServicesPSHostUserInterface to use for this instance.
/// </param>
/// <param name="hostUserInterface">The EditorServicesPSHostUserInterface to use for this instance.</param>
/// <param name="logger">An ILogger implementation to use for this instance.</param>
/// <returns></returns>
public static Runspace CreateRunspace(
Expand All @@ -260,15 +258,16 @@ 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);
}

/// <summary>
///
/// </summary>
/// <param name="psHost"></param>
/// <param name="psHost">The PSHost that will be used for this Runspace.</param>
/// <param name="languageMode">The language mode inherited from the orginal PowerShell process. This will be used when creating runspaces so that we honor the same language mode.</param>
/// <returns></returns>
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") {
Expand All @@ -277,6 +276,11 @@ public static Runspace CreateRunspace(PSHost psHost)
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;

Runspace runspace = RunspaceFactory.CreateRunspace(psHost, initialSessionState);

// Windows PowerShell must be hosted in STA mode
Expand Down Expand Up @@ -410,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(
Expand Down Expand Up @@ -597,7 +603,7 @@ public async Task<IEnumerable<TResult>> ExecuteCommandAsync<TResult>(
// 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;
Expand Down Expand Up @@ -686,7 +692,7 @@ public async Task<IEnumerable<TResult>> ExecuteCommandAsync<TResult>(
if (executionOptions.WriteInputToHost)
{
this.WriteOutput(
psCommand.Commands[0].CommandText,
executionOptions.InputString ?? psCommand.Commands[0].CommandText,
includeNewLine: true);
}

Expand Down Expand Up @@ -1161,7 +1167,7 @@ internal static TResult ExecuteScriptAndGetItem<TResult>(string scriptToExecute,
using (PowerShell pwsh = PowerShell.Create())
{
pwsh.Runspace = runspace;
IEnumerable<TResult> results = pwsh.AddScript(scriptToExecute).Invoke<TResult>();
IEnumerable<TResult> results = pwsh.AddScript(scriptToExecute, useLocalScope: true).Invoke<TResult>();
return results.DefaultIfEmpty(defaultValue).First();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<PSObject> resourcePaths = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ internal class ExecutionOptions
/// </summary>
public bool WriteInputToHost { get; set; }

/// <summary>
/// If this is set, we will use this string for history and writing to the host
/// instead of grabbing the command from the PSCommand.
/// </summary>
public string InputString { get; set; }

/// <summary>
/// If this is set, we will use this string for history and writing to the host
/// instead of grabbing the command from the PSCommand.
/// </summary>
public bool UseNewScope { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the command to
/// be executed is a console input prompt, such as the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ internal static bool TryGetPSReadLineProxy(
{
pwsh.Runspace = runspace;
var psReadLineType = pwsh
.AddScript(ReadLineInitScript)
.AddScript(ReadLineInitScript, useLocalScope: true)
.Invoke<Type>()
.FirstOrDefault();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -45,6 +46,7 @@ public static PowerShellContextService Create(ILogger logger)
TestProfilePaths,
new List<string>(),
new List<string>(),
PSLanguageMode.FullLanguage,
null,
0,
consoleReplEnabled: false,
Expand Down