From e033118a81a1974defa30534d0ecb8f6f4c7e063 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Wed, 20 Mar 2019 11:18:36 -0700 Subject: [PATCH 1/6] backport #881 in a different way --- .../Server/LanguageServer.cs | 79 ++++++++++++------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index de4fc99eb..ed6136fc7 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -16,9 +16,9 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Management.Automation; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -28,6 +28,8 @@ namespace Microsoft.PowerShell.EditorServices.Protocol.Server { + using System.Management.Automation; + public class LanguageServer { private static CancellationTokenSource s_existingRequestCancellation; @@ -1234,11 +1236,27 @@ protected async Task HandleCommentHelpRequest( await requestContext.SendResult(result); } + // Since the NamedPipeConnectionInfo type is only available in 5.1+ + // we have to use reflection to support older version of PS. + // This code only lives in the v1.X of the extension. + // The 2.x version of the code can be found here: + // https://github.com/PowerShell/PowerShellEditorServices/pull/881 + private static Type _namedPipeConnectionInfoType = Type.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo, System.Management.Automation"); + private static MethodInfo _runspaceFactoryCreateRunspaceMethod = typeof(RunspaceFactory) + .GetMethod("CreateRunspace", new Type[] { _namedPipeConnectionInfoType }); + private Runspace GetRemoteRunspace(int pid) + { + var namedPipeConnectionInfoInstance = Activator.CreateInstance( + _namedPipeConnectionInfoType, + pid); + return _runspaceFactoryCreateRunspaceMethod.Invoke(null, new [] { namedPipeConnectionInfoInstance }) as Runspace; + } + protected async Task HandleGetRunspaceRequestAsync( string processId, RequestContext requestContext) { - var runspaceResponses = new List(); + IEnumerable runspaces = null; if (this.editorSession.PowerShellContext.LocalPowerShellVersion.Version.Major >= 5) { @@ -1246,36 +1264,43 @@ protected async Task HandleGetRunspaceRequestAsync( processId = "current"; } - var isNotCurrentProcess = processId != null && processId != "current"; - - var psCommand = new PSCommand(); - - if (isNotCurrentProcess) { - psCommand.AddCommand("Enter-PSHostProcess").AddParameter("Id", processId).AddStatement(); - } - - psCommand.AddCommand("Get-Runspace"); - - StringBuilder sb = new StringBuilder(); - IEnumerable runspaces = await editorSession.PowerShellContext.ExecuteCommand(psCommand, sb); - if (runspaces != null) + // If the processId is a valid int, we need to run Get-Runspace within that process + // otherwise just use the current runspace. + if (int.TryParse(processId, out int pid)) { - foreach (var p in runspaces) + + // Create a remote runspace that we will invoke Get-Runspace in. + using(var rs = GetRemoteRunspace(pid)) + using(var ps = PowerShell.Create()) { - runspaceResponses.Add( - new GetRunspaceResponse - { - Id = p.Id, - Name = p.Name, - Availability = p.RunspaceAvailability.ToString() - }); + rs.Open(); + ps.Runspace = rs; + // Returns deserialized Runspaces. For simpler code, we use PSObject and rely on dynamic later. + runspaces = ps.AddCommand("Microsoft.PowerShell.Utility\\Get-Runspace").Invoke(); } } + else + { + var psCommand = new PSCommand().AddCommand("Microsoft.PowerShell.Utility\\Get-Runspace"); + var sb = new StringBuilder(); + // returns (not deserialized) Runspaces. For simpler code, we use PSObject and rely on dynamic later. + runspaces = await editorSession.PowerShellContext.ExecuteCommand(psCommand, sb); + } + } - if (isNotCurrentProcess) { - var exitCommand = new PSCommand(); - exitCommand.AddCommand("Exit-PSHostProcess"); - await editorSession.PowerShellContext.ExecuteCommand(exitCommand); + var runspaceResponses = new List(); + + if (runspaces != null) + { + foreach (dynamic runspace in runspaces) + { + runspaceResponses.Add( + new GetRunspaceResponse + { + Id = runspace.Id, + Name = runspace.Name, + Availability = runspace.RunspaceAvailability.ToString() + }); } } From 0486deab5a390ef8582ea9364f90161152c20a8f Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Wed, 20 Mar 2019 14:05:12 -0700 Subject: [PATCH 2/6] simpler --- .../Server/LanguageServer.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index ed6136fc7..65a26cdc6 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -18,7 +18,6 @@ using System.Linq; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; -using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -1237,19 +1236,19 @@ protected async Task HandleCommentHelpRequest( } // Since the NamedPipeConnectionInfo type is only available in 5.1+ - // we have to use reflection to support older version of PS. + // we have to use Activator to support older version of PS. // This code only lives in the v1.X of the extension. // The 2.x version of the code can be found here: // https://github.com/PowerShell/PowerShellEditorServices/pull/881 private static Type _namedPipeConnectionInfoType = Type.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo, System.Management.Automation"); - private static MethodInfo _runspaceFactoryCreateRunspaceMethod = typeof(RunspaceFactory) - .GetMethod("CreateRunspace", new Type[] { _namedPipeConnectionInfoType }); - private Runspace GetRemoteRunspace(int pid) + + private static Runspace GetRemoteRunspace(int pid) { var namedPipeConnectionInfoInstance = Activator.CreateInstance( _namedPipeConnectionInfoType, pid); - return _runspaceFactoryCreateRunspaceMethod.Invoke(null, new [] { namedPipeConnectionInfoInstance }) as Runspace; + + return RunspaceFactory.CreateRunspace(namedPipeConnectionInfoInstance as RunspaceConnectionInfo); } protected async Task HandleGetRunspaceRequestAsync( From 65dcf3534f8b2f14536ca490e90117f5198cecd3 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Wed, 20 Mar 2019 16:28:19 -0700 Subject: [PATCH 3/6] switch back to reflecting --- .../Server/LanguageServer.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 65a26cdc6..71733aa4c 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -18,6 +18,7 @@ using System.Linq; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -1241,13 +1242,10 @@ protected async Task HandleCommentHelpRequest( // The 2.x version of the code can be found here: // https://github.com/PowerShell/PowerShellEditorServices/pull/881 private static Type _namedPipeConnectionInfoType = Type.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo, System.Management.Automation"); - + private static ConstructorInfo _namedPipeConnectionInfoCtor = _namedPipeConnectionInfoType.GetConstructor(new [] { typeof(int) }); private static Runspace GetRemoteRunspace(int pid) { - var namedPipeConnectionInfoInstance = Activator.CreateInstance( - _namedPipeConnectionInfoType, - pid); - + var namedPipeConnectionInfoInstance = _namedPipeConnectionInfoCtor.Invoke(new object[] { pid }); return RunspaceFactory.CreateRunspace(namedPipeConnectionInfoInstance as RunspaceConnectionInfo); } From db3e0987ef84365b30c5202d8ba567b8cfe6bf3c Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Thu, 21 Mar 2019 12:44:52 -0700 Subject: [PATCH 4/6] address feedback --- .../Server/LanguageServer.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 71733aa4c..e231e6c3e 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -44,6 +44,14 @@ public class LanguageServer private static readonly SymbolInformation[] s_emptySymbolResult = new SymbolInformation[0]; + // Since the NamedPipeConnectionInfo type is only available in 5.1+ + // we have to use Activator to support older version of PS. + // This code only lives in the v1.X of the extension. + // The 2.x version of the code can be found here: + // https://github.com/PowerShell/PowerShellEditorServices/pull/881 + private static readonly Type s_namedPipeConnectionInfoType = Type.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo, System.Management.Automation"); + private static readonly ConstructorInfo s_namedPipeConnectionInfoCtor = s_namedPipeConnectionInfoType.GetConstructor(new [] { typeof(int) }); + private ILogger Logger; private bool profilesLoaded; private bool consoleReplStarted; @@ -1236,16 +1244,9 @@ protected async Task HandleCommentHelpRequest( await requestContext.SendResult(result); } - // Since the NamedPipeConnectionInfo type is only available in 5.1+ - // we have to use Activator to support older version of PS. - // This code only lives in the v1.X of the extension. - // The 2.x version of the code can be found here: - // https://github.com/PowerShell/PowerShellEditorServices/pull/881 - private static Type _namedPipeConnectionInfoType = Type.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo, System.Management.Automation"); - private static ConstructorInfo _namedPipeConnectionInfoCtor = _namedPipeConnectionInfoType.GetConstructor(new [] { typeof(int) }); private static Runspace GetRemoteRunspace(int pid) { - var namedPipeConnectionInfoInstance = _namedPipeConnectionInfoCtor.Invoke(new object[] { pid }); + var namedPipeConnectionInfoInstance = s_namedPipeConnectionInfoCtor.Invoke(new object[] { pid }); return RunspaceFactory.CreateRunspace(namedPipeConnectionInfoInstance as RunspaceConnectionInfo); } @@ -1267,7 +1268,7 @@ protected async Task HandleGetRunspaceRequestAsync( { // Create a remote runspace that we will invoke Get-Runspace in. - using(var rs = GetRemoteRunspace(pid)) + using(Runspace rs = GetRemoteRunspace(pid)) using(var ps = PowerShell.Create()) { rs.Open(); From 2d00d9e57ce5224cc7c549db12fedcab7c2be91a Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Thu, 21 Mar 2019 14:20:40 -0700 Subject: [PATCH 5/6] more feedback --- src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index e231e6c3e..a443c5866 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -49,7 +49,7 @@ public class LanguageServer // This code only lives in the v1.X of the extension. // The 2.x version of the code can be found here: // https://github.com/PowerShell/PowerShellEditorServices/pull/881 - private static readonly Type s_namedPipeConnectionInfoType = Type.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo, System.Management.Automation"); + private static readonly Type s_namedPipeConnectionInfoType = typeof(PSObject).GetTypeInfo().Assembly.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo"); private static readonly ConstructorInfo s_namedPipeConnectionInfoCtor = s_namedPipeConnectionInfoType.GetConstructor(new [] { typeof(int) }); private ILogger Logger; From 1bff5cf346f8c884bbe1b62d364ea476297d280e Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Thu, 21 Mar 2019 14:39:10 -0700 Subject: [PATCH 6/6] safe check --- .../Server/LanguageServer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index a443c5866..43cae0ab0 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -49,8 +49,9 @@ public class LanguageServer // This code only lives in the v1.X of the extension. // The 2.x version of the code can be found here: // https://github.com/PowerShell/PowerShellEditorServices/pull/881 - private static readonly Type s_namedPipeConnectionInfoType = typeof(PSObject).GetTypeInfo().Assembly.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo"); - private static readonly ConstructorInfo s_namedPipeConnectionInfoCtor = s_namedPipeConnectionInfoType.GetConstructor(new [] { typeof(int) }); + private static readonly ConstructorInfo s_namedPipeConnectionInfoCtor = typeof(PSObject).GetTypeInfo().Assembly + .GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo") + ?.GetConstructor(new [] { typeof(int) }); private ILogger Logger; private bool profilesLoaded;