1616using System . Diagnostics ;
1717using System . IO ;
1818using System . Linq ;
19- using System . Management . Automation ;
2019using System . Management . Automation . Language ;
2120using System . Management . Automation . Runspaces ;
21+ using System . Reflection ;
2222using System . Text ;
2323using System . Text . RegularExpressions ;
2424using System . Threading ;
2828
2929namespace Microsoft . PowerShell . EditorServices . Protocol . Server
3030{
31+ using System . Management . Automation ;
32+
3133 public class LanguageServer
3234 {
3335 private static CancellationTokenSource s_existingRequestCancellation ;
@@ -42,6 +44,15 @@ public class LanguageServer
4244
4345 private static readonly SymbolInformation [ ] s_emptySymbolResult = new SymbolInformation [ 0 ] ;
4446
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+
4556 private ILogger Logger ;
4657 private bool profilesLoaded ;
4758 private bool consoleReplStarted ;
@@ -1234,48 +1245,61 @@ protected async Task HandleCommentHelpRequest(
12341245 await requestContext . SendResult ( result ) ;
12351246 }
12361247
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+
12371254 protected async Task HandleGetRunspaceRequestAsync (
12381255 string processId ,
12391256 RequestContext < GetRunspaceResponse [ ] > requestContext )
12401257 {
1241- var runspaceResponses = new List < GetRunspaceResponse > ( ) ;
1258+ IEnumerable < PSObject > runspaces = null ;
12421259
12431260 if ( this . editorSession . PowerShellContext . LocalPowerShellVersion . Version . Major >= 5 )
12441261 {
12451262 if ( processId == null ) {
12461263 processId = "current" ;
12471264 }
12481265
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 ) )
12621269 {
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 ( ) )
12641274 {
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 > ( ) ;
12721279 }
12731280 }
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+ }
12741289
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+ } ) ;
12791303 }
12801304 }
12811305
0 commit comments