Skip to content

Commit e033118

Browse files
backport PowerShell#881 in a different way
1 parent 257d26c commit e033118

File tree

1 file changed

+52
-27
lines changed

1 file changed

+52
-27
lines changed

src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs

+52-27
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
using System.Diagnostics;
1717
using System.IO;
1818
using System.Linq;
19-
using System.Management.Automation;
2019
using System.Management.Automation.Language;
2120
using System.Management.Automation.Runspaces;
21+
using System.Reflection;
2222
using System.Text;
2323
using System.Text.RegularExpressions;
2424
using System.Threading;
@@ -28,6 +28,8 @@
2828

2929
namespace Microsoft.PowerShell.EditorServices.Protocol.Server
3030
{
31+
using System.Management.Automation;
32+
3133
public class LanguageServer
3234
{
3335
private static CancellationTokenSource s_existingRequestCancellation;
@@ -1234,48 +1236,71 @@ protected async Task HandleCommentHelpRequest(
12341236
await requestContext.SendResult(result);
12351237
}
12361238

1239+
// Since the NamedPipeConnectionInfo type is only available in 5.1+
1240+
// we have to use reflection to support older version of PS.
1241+
// This code only lives in the v1.X of the extension.
1242+
// The 2.x version of the code can be found here:
1243+
// https://github.com/PowerShell/PowerShellEditorServices/pull/881
1244+
private static Type _namedPipeConnectionInfoType = Type.GetType("System.Management.Automation.Runspaces.NamedPipeConnectionInfo, System.Management.Automation");
1245+
private static MethodInfo _runspaceFactoryCreateRunspaceMethod = typeof(RunspaceFactory)
1246+
.GetMethod("CreateRunspace", new Type[] { _namedPipeConnectionInfoType });
1247+
private Runspace GetRemoteRunspace(int pid)
1248+
{
1249+
var namedPipeConnectionInfoInstance = Activator.CreateInstance(
1250+
_namedPipeConnectionInfoType,
1251+
pid);
1252+
return _runspaceFactoryCreateRunspaceMethod.Invoke(null, new [] { namedPipeConnectionInfoInstance }) as Runspace;
1253+
}
1254+
12371255
protected async Task HandleGetRunspaceRequestAsync(
12381256
string processId,
12391257
RequestContext<GetRunspaceResponse[]> requestContext)
12401258
{
1241-
var runspaceResponses = new List<GetRunspaceResponse>();
1259+
IEnumerable<PSObject> runspaces = null;
12421260

12431261
if (this.editorSession.PowerShellContext.LocalPowerShellVersion.Version.Major >= 5)
12441262
{
12451263
if (processId == null) {
12461264
processId = "current";
12471265
}
12481266

1249-
var isNotCurrentProcess = processId != null && processId != "current";
1250-
1251-
var psCommand = new PSCommand();
1252-
1253-
if (isNotCurrentProcess) {
1254-
psCommand.AddCommand("Enter-PSHostProcess").AddParameter("Id", processId).AddStatement();
1255-
}
1256-
1257-
psCommand.AddCommand("Get-Runspace");
1258-
1259-
StringBuilder sb = new StringBuilder();
1260-
IEnumerable<Runspace> runspaces = await editorSession.PowerShellContext.ExecuteCommand<Runspace>(psCommand, sb);
1261-
if (runspaces != null)
1267+
// If the processId is a valid int, we need to run Get-Runspace within that process
1268+
// otherwise just use the current runspace.
1269+
if (int.TryParse(processId, out int pid))
12621270
{
1263-
foreach (var p in runspaces)
1271+
1272+
// Create a remote runspace that we will invoke Get-Runspace in.
1273+
using(var rs = GetRemoteRunspace(pid))
1274+
using(var ps = PowerShell.Create())
12641275
{
1265-
runspaceResponses.Add(
1266-
new GetRunspaceResponse
1267-
{
1268-
Id = p.Id,
1269-
Name = p.Name,
1270-
Availability = p.RunspaceAvailability.ToString()
1271-
});
1276+
rs.Open();
1277+
ps.Runspace = rs;
1278+
// Returns deserialized Runspaces. For simpler code, we use PSObject and rely on dynamic later.
1279+
runspaces = ps.AddCommand("Microsoft.PowerShell.Utility\\Get-Runspace").Invoke<PSObject>();
12721280
}
12731281
}
1282+
else
1283+
{
1284+
var psCommand = new PSCommand().AddCommand("Microsoft.PowerShell.Utility\\Get-Runspace");
1285+
var sb = new StringBuilder();
1286+
// returns (not deserialized) Runspaces. For simpler code, we use PSObject and rely on dynamic later.
1287+
runspaces = await editorSession.PowerShellContext.ExecuteCommand<PSObject>(psCommand, sb);
1288+
}
1289+
}
12741290

1275-
if (isNotCurrentProcess) {
1276-
var exitCommand = new PSCommand();
1277-
exitCommand.AddCommand("Exit-PSHostProcess");
1278-
await editorSession.PowerShellContext.ExecuteCommand(exitCommand);
1291+
var runspaceResponses = new List<GetRunspaceResponse>();
1292+
1293+
if (runspaces != null)
1294+
{
1295+
foreach (dynamic runspace in runspaces)
1296+
{
1297+
runspaceResponses.Add(
1298+
new GetRunspaceResponse
1299+
{
1300+
Id = runspace.Id,
1301+
Name = runspace.Name,
1302+
Availability = runspace.RunspaceAvailability.ToString()
1303+
});
12791304
}
12801305
}
12811306

0 commit comments

Comments
 (0)