@@ -23,6 +23,8 @@ namespace Microsoft.PowerShell.EditorServices.Protocol.Server
2323{
2424 public class DebugAdapter
2525 {
26+ private static readonly Version _minVersionForCustomPipeName = new Version ( 6 , 2 ) ;
27+
2628 private EditorSession _editorSession ;
2729
2830 private bool _noDebug ;
@@ -350,11 +352,17 @@ protected async Task HandleAttachRequestAsync(
350352
351353 RegisterEventHandlers ( ) ;
352354
355+ bool processIdIsSet = ! string . IsNullOrEmpty ( attachParams . ProcessId ) && attachParams . ProcessId != "undefined" ;
356+ bool customPipeNameIsSet = ! string . IsNullOrEmpty ( attachParams . CustomPipeName ) && attachParams . CustomPipeName != "undefined" ;
357+
358+ PowerShellVersionDetails runspaceVersion =
359+ _editorSession . PowerShellContext . CurrentRunspace . PowerShellVersion ;
360+
353361 // If there are no host processes to attach to or the user cancels selection, we get a null for the process id.
354362 // This is not an error, just a request to stop the original "attach to" request.
355363 // Testing against "undefined" is a HACK because I don't know how to make "Cancel" on quick pick loading
356364 // to cancel on the VSCode side without sending an attachRequest with processId set to "undefined".
357- if ( string . IsNullOrEmpty ( attachParams . ProcessId ) || ( attachParams . ProcessId == "undefined" ) )
365+ if ( ! processIdIsSet && ! customPipeNameIsSet )
358366 {
359367 Logger . Write (
360368 LogLevel . Normal ,
@@ -370,9 +378,6 @@ await requestContext.SendErrorAsync(
370378
371379 if ( attachParams . ComputerName != null )
372380 {
373- PowerShellVersionDetails runspaceVersion =
374- _editorSession . PowerShellContext . CurrentRunspace . PowerShellVersion ;
375-
376381 if ( runspaceVersion . Version . Major < 4 )
377382 {
378383 await requestContext . SendErrorAsync (
@@ -403,16 +408,12 @@ await requestContext.SendErrorAsync(
403408 _isRemoteAttach = true ;
404409 }
405410
406- if ( int . TryParse ( attachParams . ProcessId , out int processId ) && ( processId > 0 ) )
411+ if ( processIdIsSet && int . TryParse ( attachParams . ProcessId , out int processId ) && ( processId > 0 ) )
407412 {
408- PowerShellVersionDetails runspaceVersion =
409- _editorSession . PowerShellContext . CurrentRunspace . PowerShellVersion ;
410-
411413 if ( runspaceVersion . Version . Major < 5 )
412414 {
413415 await requestContext . SendErrorAsync (
414416 $ "Attaching to a process is only available with PowerShell 5 and higher (current session is { runspaceVersion . Version } ).") ;
415-
416417 return ;
417418 }
418419
@@ -427,20 +428,27 @@ await requestContext.SendErrorAsync(
427428
428429 return ;
429430 }
431+ }
432+ else if ( customPipeNameIsSet )
433+ {
434+ if ( runspaceVersion . Version < _minVersionForCustomPipeName )
435+ {
436+ await requestContext . SendErrorAsync (
437+ $ "Attaching to a process with CustomPipeName is only available with PowerShell 6.2 and higher (current session is { runspaceVersion . Version } ).") ;
438+ return ;
439+ }
430440
431- // Clear any existing breakpoints before proceeding
432- await ClearSessionBreakpointsAsync ( ) ;
433-
434- // Execute the Debug-Runspace command but don't await it because it
435- // will block the debug adapter initialization process. The
436- // InitializedEvent will be sent as soon as the RunspaceChanged
437- // event gets fired with the attached runspace.
438- int runspaceId = attachParams . RunspaceId > 0 ? attachParams . RunspaceId : 1 ;
439- _waitingForAttach = true ;
440- Task nonAwaitedTask =
441- _editorSession . PowerShellContext
442- . ExecuteScriptStringAsync ( $ "\n Debug-Runspace -Id { runspaceId } ")
443- . ContinueWith ( OnExecutionCompletedAsync ) ;
441+ await _editorSession . PowerShellContext . ExecuteScriptStringAsync (
442+ $ "Enter-PSHostProcess -CustomPipeName { attachParams . CustomPipeName } ",
443+ errorMessages ) ;
444+
445+ if ( errorMessages . Length > 0 )
446+ {
447+ await requestContext . SendErrorAsync (
448+ $ "Could not attach to process with CustomPipeName: '{ attachParams . CustomPipeName } '") ;
449+
450+ return ;
451+ }
444452 }
445453 else
446454 {
@@ -454,6 +462,19 @@ await requestContext.SendErrorAsync(
454462 return ;
455463 }
456464
465+ // Clear any existing breakpoints before proceeding
466+ await ClearSessionBreakpointsAsync ( ) . ConfigureAwait ( continueOnCapturedContext : false ) ;
467+
468+ // Execute the Debug-Runspace command but don't await it because it
469+ // will block the debug adapter initialization process. The
470+ // InitializedEvent will be sent as soon as the RunspaceChanged
471+ // event gets fired with the attached runspace.
472+ int runspaceId = attachParams . RunspaceId > 0 ? attachParams . RunspaceId : 1 ;
473+ _waitingForAttach = true ;
474+ Task nonAwaitedTask = _editorSession . PowerShellContext
475+ . ExecuteScriptStringAsync ( $ "\n Debug-Runspace -Id { runspaceId } ")
476+ . ContinueWith ( OnExecutionCompletedAsync ) ;
477+
457478 await requestContext . SendResultAsync ( null ) ;
458479 }
459480
0 commit comments