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 ;
@@ -42,6 +44,15 @@ public class LanguageServer
42
44
43
45
private static readonly SymbolInformation [ ] s_emptySymbolResult = new SymbolInformation [ 0 ] ;
44
46
47
+ // Since the NamedPipeConnectionInfo type is only available in 5.1+
48
+ // we have to use Activator to support older version of PS.
49
+ // This code only lives in the v1.X of the extension.
50
+ // The 2.x version of the code can be found here:
51
+ // https://github.com/PowerShell/PowerShellEditorServices/pull/881
52
+ private static readonly ConstructorInfo s_namedPipeConnectionInfoCtor = typeof ( PSObject ) . GetTypeInfo ( ) . Assembly
53
+ . GetType ( "System.Management.Automation.Runspaces.NamedPipeConnectionInfo" )
54
+ ? . GetConstructor ( new [ ] { typeof ( int ) } ) ;
55
+
45
56
private ILogger Logger ;
46
57
private bool profilesLoaded ;
47
58
private bool consoleReplStarted ;
@@ -1234,48 +1245,61 @@ protected async Task HandleCommentHelpRequest(
1234
1245
await requestContext . SendResult ( result ) ;
1235
1246
}
1236
1247
1248
+ private static Runspace GetRemoteRunspace ( int pid )
1249
+ {
1250
+ var namedPipeConnectionInfoInstance = s_namedPipeConnectionInfoCtor . Invoke ( new object [ ] { pid } ) ;
1251
+ return RunspaceFactory . CreateRunspace ( namedPipeConnectionInfoInstance as RunspaceConnectionInfo ) ;
1252
+ }
1253
+
1237
1254
protected async Task HandleGetRunspaceRequestAsync (
1238
1255
string processId ,
1239
1256
RequestContext < GetRunspaceResponse [ ] > requestContext )
1240
1257
{
1241
- var runspaceResponses = new List < GetRunspaceResponse > ( ) ;
1258
+ IEnumerable < PSObject > runspaces = null ;
1242
1259
1243
1260
if ( this . editorSession . PowerShellContext . LocalPowerShellVersion . Version . Major >= 5 )
1244
1261
{
1245
1262
if ( processId == null ) {
1246
1263
processId = "current" ;
1247
1264
}
1248
1265
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 )
1266
+ // If the processId is a valid int, we need to run Get-Runspace within that process
1267
+ // otherwise just use the current runspace.
1268
+ if ( int . TryParse ( processId , out int pid ) )
1262
1269
{
1263
- foreach ( var p in runspaces )
1270
+
1271
+ // Create a remote runspace that we will invoke Get-Runspace in.
1272
+ using ( Runspace rs = GetRemoteRunspace ( pid ) )
1273
+ using ( var ps = PowerShell . Create ( ) )
1264
1274
{
1265
- runspaceResponses . Add (
1266
- new GetRunspaceResponse
1267
- {
1268
- Id = p . Id ,
1269
- Name = p . Name ,
1270
- Availability = p . RunspaceAvailability . ToString ( )
1271
- } ) ;
1275
+ rs . Open ( ) ;
1276
+ ps . Runspace = rs ;
1277
+ // Returns deserialized Runspaces. For simpler code, we use PSObject and rely on dynamic later.
1278
+ runspaces = ps . AddCommand ( "Microsoft.PowerShell.Utility\\ Get-Runspace" ) . Invoke < PSObject > ( ) ;
1272
1279
}
1273
1280
}
1281
+ else
1282
+ {
1283
+ var psCommand = new PSCommand ( ) . AddCommand ( "Microsoft.PowerShell.Utility\\ Get-Runspace" ) ;
1284
+ var sb = new StringBuilder ( ) ;
1285
+ // returns (not deserialized) Runspaces. For simpler code, we use PSObject and rely on dynamic later.
1286
+ runspaces = await editorSession . PowerShellContext . ExecuteCommand < PSObject > ( psCommand , sb ) ;
1287
+ }
1288
+ }
1274
1289
1275
- if ( isNotCurrentProcess ) {
1276
- var exitCommand = new PSCommand ( ) ;
1277
- exitCommand . AddCommand ( "Exit-PSHostProcess" ) ;
1278
- await editorSession . PowerShellContext . ExecuteCommand ( exitCommand ) ;
1290
+ var runspaceResponses = new List < GetRunspaceResponse > ( ) ;
1291
+
1292
+ if ( runspaces != null )
1293
+ {
1294
+ foreach ( dynamic runspace in runspaces )
1295
+ {
1296
+ runspaceResponses . Add (
1297
+ new GetRunspaceResponse
1298
+ {
1299
+ Id = runspace . Id ,
1300
+ Name = runspace . Name ,
1301
+ Availability = runspace . RunspaceAvailability . ToString ( )
1302
+ } ) ;
1279
1303
}
1280
1304
}
1281
1305
0 commit comments