|
16 | 16 | using System.Diagnostics;
|
17 | 17 | using System.IO;
|
18 | 18 | using System.Linq;
|
19 |
| -using System.Management.Automation; |
20 | 19 | using System.Management.Automation.Language;
|
21 | 20 | using System.Management.Automation.Runspaces;
|
| 21 | +using System.Reflection; |
22 | 22 | using System.Text;
|
23 | 23 | using System.Text.RegularExpressions;
|
24 | 24 | using System.Threading;
|
|
28 | 28 |
|
29 | 29 | namespace Microsoft.PowerShell.EditorServices.Protocol.Server
|
30 | 30 | {
|
| 31 | + using System.Management.Automation; |
| 32 | + |
31 | 33 | public class LanguageServer
|
32 | 34 | {
|
33 | 35 | private static CancellationTokenSource s_existingRequestCancellation;
|
@@ -1234,48 +1236,71 @@ protected async Task HandleCommentHelpRequest(
|
1234 | 1236 | await requestContext.SendResult(result);
|
1235 | 1237 | }
|
1236 | 1238 |
|
| 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 | + |
1237 | 1255 | protected async Task HandleGetRunspaceRequestAsync(
|
1238 | 1256 | string processId,
|
1239 | 1257 | RequestContext<GetRunspaceResponse[]> requestContext)
|
1240 | 1258 | {
|
1241 |
| - var runspaceResponses = new List<GetRunspaceResponse>(); |
| 1259 | + IEnumerable<PSObject> runspaces = null; |
1242 | 1260 |
|
1243 | 1261 | if (this.editorSession.PowerShellContext.LocalPowerShellVersion.Version.Major >= 5)
|
1244 | 1262 | {
|
1245 | 1263 | if (processId == null) {
|
1246 | 1264 | processId = "current";
|
1247 | 1265 | }
|
1248 | 1266 |
|
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)) |
1262 | 1270 | {
|
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()) |
1264 | 1275 | {
|
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>(); |
1272 | 1280 | }
|
1273 | 1281 | }
|
| 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 | + } |
1274 | 1290 |
|
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 | + }); |
1279 | 1304 | }
|
1280 | 1305 | }
|
1281 | 1306 |
|
|
0 commit comments