Skip to content

CodeCompletion exposes cmdlets not available to the parent runspace #1281

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

Closed
dkattan opened this issue May 2, 2020 · 5 comments
Closed

CodeCompletion exposes cmdlets not available to the parent runspace #1281

dkattan opened this issue May 2, 2020 · 5 comments

Comments

@dkattan
Copy link
Contributor

dkattan commented May 2, 2020

Summary

When calling PSES programmatically (from C# but using the supported script) in a ConstrainedRunspace in ConstrainedLanguage mode, information about all cmdlets and the underlying filesystem is exposed via CodeCompletion.

Steps to Reproduce

StartLanguageServerViaScript()
    {
      InitialSessionState iss = InitialSessionState.Create();
      iss.LanguageMode = PSLanguageMode.ConstrainedLanguage;
      iss.ImportPSModule("Microsoft.Powershell.Utility", "Microsoft.Powershell.Core", "Microsoft.PowerShell.Security");
      iss.Commands.Add(new SessionStateCmdletEntry("Get-Command", typeof(GetCommandCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Where-Object", typeof(WhereObjectCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Select-Object", typeof(SelectObjectCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("ForEach-Object", typeof(ForEachObjectCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Format-List", typeof(FormatListCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Format-Table", typeof(FormatTableCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Set-ExecutionPolicy", typeof(SetExecutionPolicyCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Format-Hex", typeof(FormatHex), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Out-Default", typeof(OutDefaultCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Out-Host", typeof(OutHostCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Import-Module", typeof(ImportModuleCommand), null));
      iss.Commands.Add(new SessionStateCmdletEntry("Start-EditorServices", typeof(PSCommand), null));

      iss.Commands.Add(new SessionStateFunctionEntry("TabExpansion2", PowershellCommands.TabExpansion));
iss.ImportPSModule(_modulePath);
      Runspace myRunSpace = RunspaceFactory.CreateRunspace(_host, iss);
      myRunSpace.Open();
      PowerShell powershell = PowerShell.Create();
      powershell.Runspace = myRunSpace;
      powershell.AddCommand("Set-ExecutionPolicy")
                   .AddParameter("-ExecutionPolicy", "Bypass")
                   .AddParameter("-Scope", "Process")
                   .Invoke();
      PSCommand[] profileCommands = PSHostUtilities.GetProfileCommands("Microsoft.PowerShell");
      foreach (PSCommand command in profileCommands)
      {
        powershell.Commands = command;
        powershell.Invoke();
      }
      powershell.AddScript(PowershellCommands.TabExpansion);
      powershell.Runspace.SessionStateProxy.InvokeCommand.GetCommand("TabExpansion2", CommandTypes.Function);
      
      var scriptInvocation = powershell.Runspace.SessionStateProxy.InvokeCommand
                    .GetCommand(_StartEditorServicesScriptPath, CommandTypes.ExternalScript);
powershell.AddCommand(scriptInvocation)
      //"-FeatureFlags", "@()"
      .AddParameter("HostName", "monaco")
      .AddParameter("HostProfileId", "0")
      .AddParameter("HostVersion", "1.0.0")
      .AddParameter("LogPath", _logPath)
      .AddParameter("LogLevel", "Diagnostic")
      .AddParameter("BundledModulesPath", _bundledModulesPath)
      .AddParameter("SessionDetailsPath", _sessionInfoFilePath)
      .AddParameter("EnableConsoleRepl");
      
      try
      {
        foreach (var command in powershell.Commands.Commands)
       {
command.MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
          command.MergeMyResults(PipelineResultTypes.Information, PipelineResultTypes.Output);
        }
        _psInvocationResult = powershell.BeginInvoke();
}
      catch (Exception ex)
      {
Console.WriteLine(ex.Message);
      }
}

Expected Behavior

CodeCompletion should only return information about the specific set of modules I loaded into my runspace via InitialSessionState

What actually happens

All available modules are available via CodeCompletion and my custom (and likely unnecessary) TabExpansion2 function never gets called.

Possible Fixes

Instead of always creating a new runspace in PowerShellContext.Create() use the existing one.

Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.LanguageMode);

Create a new runspace but allow the user to specify a custom initialsessionstate. Perhaps do this instead of the recent change that simply passes in LanguageMode as this would give the user more granular control of the runspace. This would naturally require Start-EditorServices to be modified to accept an initiationsessionstate object.

I feel pretty confident I can implement the required changes, I’d like some feedback as to which option is most feasible or if there are perhaps intentional reasons a new runspace is being created.

@ghost ghost added the Needs: Triage Maintainer attention needed! label May 2, 2020
@TylerLeonhardt
Copy link
Member

CodeCompletion should only return information about the specific set of modules I loaded into my runspace via InitialSessionState

@dkattan I'm curious where you saw that this is the behavior of tab completion in CLM...

image

For me TabExpansion2 still completes everything in CLM.

@ghost ghost added the Needs: Maintainer Attention Maintainer attention needed! label May 2, 2020
@TylerLeonhardt TylerLeonhardt added Needs-Repro-Info and removed Needs: Maintainer Attention Maintainer attention needed! Needs: Triage Maintainer attention needed! labels May 2, 2020
@dkattan
Copy link
Contributor Author

dkattan commented May 2, 2020

I think it’s worth noting that there is be a difference between ConstrainedLanguage mode and a Constrained Runspace.

https://docs.microsoft.com/en-us/powershell/scripting/developer/hosting/creating-a-constrained-runspace?view=powershell-7

A constrained runspace essentially has no cmdlets except for the ones explicitly added. It’s created using InitialSessionState.Create() instead of InitialSessionState.CreateDefault() or CreateDefault2(). There seems to be no support for .Create(), there is however an environmental variable to use CreateDefault instead of CreateDefault2.

That being said, I think it’s a reasonable expectation for PSES to not return information about cmdlets not available in the Constrained Runspace it was spawned from.

@ghost ghost added the Needs: Maintainer Attention Maintainer attention needed! label May 2, 2020
@dkattan
Copy link
Contributor Author

dkattan commented May 2, 2020 via email

@dkattan
Copy link
Contributor Author

dkattan commented May 4, 2020

I began implementing a potential solution in #1282

I decided not to allow the end user to specify InitialSessionState as a separate parameter to Start-EditorServices, but instead infer it from Runspace.DefaultRunspace.InitialSessionState. Since InitialSessionState contains LanguageMode I simply replaced all the places @TylerLeonhardt was referencing LanguageMode and used the full InitialSessionState object instead.

@SydneyhSmith SydneyhSmith removed the Needs: Maintainer Attention Maintainer attention needed! label Jun 11, 2020
@ghost ghost closed this as completed Aug 28, 2020
@ghost
Copy link

ghost commented Aug 28, 2020

Closing due to no activity

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants