@@ -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 ;
@@ -344,11 +346,17 @@ protected async Task HandleAttachRequest(
344346
345347 RegisterEventHandlers ( ) ;
346348
349+ bool processIdIsSet = ! string . IsNullOrEmpty ( attachParams . ProcessId ) && attachParams . ProcessId != "undefined" ;
350+ bool customPipeNameIsSet = ! string . IsNullOrEmpty ( attachParams . CustomPipeName ) && attachParams . CustomPipeName != "undefined" ;
351+
352+ PowerShellVersionDetails runspaceVersion =
353+ _editorSession . PowerShellContext . CurrentRunspace . PowerShellVersion ;
354+
347355 // If there are no host processes to attach to or the user cancels selection, we get a null for the process id.
348356 // This is not an error, just a request to stop the original "attach to" request.
349357 // Testing against "undefined" is a HACK because I don't know how to make "Cancel" on quick pick loading
350358 // to cancel on the VSCode side without sending an attachRequest with processId set to "undefined".
351- if ( string . IsNullOrEmpty ( attachParams . ProcessId ) || ( attachParams . ProcessId == "undefined" ) )
359+ if ( ! processIdIsSet && ! customPipeNameIsSet )
352360 {
353361 Logger . Write (
354362 LogLevel . Normal ,
@@ -364,9 +372,6 @@ await requestContext.SendError(
364372
365373 if ( attachParams . ComputerName != null )
366374 {
367- PowerShellVersionDetails runspaceVersion =
368- _editorSession . PowerShellContext . CurrentRunspace . PowerShellVersion ;
369-
370375 if ( runspaceVersion . Version . Major < 4 )
371376 {
372377 await requestContext . SendError (
@@ -397,16 +402,12 @@ await requestContext.SendError(
397402 _isRemoteAttach = true ;
398403 }
399404
400- if ( int . TryParse ( attachParams . ProcessId , out int processId ) && ( processId > 0 ) )
405+ if ( processIdIsSet && int . TryParse ( attachParams . ProcessId , out int processId ) && ( processId > 0 ) )
401406 {
402- PowerShellVersionDetails runspaceVersion =
403- _editorSession . PowerShellContext . CurrentRunspace . PowerShellVersion ;
404-
405407 if ( runspaceVersion . Version . Major < 5 )
406408 {
407409 await requestContext . SendError (
408410 $ "Attaching to a process is only available with PowerShell 5 and higher (current session is { runspaceVersion . Version } ).") ;
409-
410411 return ;
411412 }
412413
@@ -421,20 +422,27 @@ await requestContext.SendError(
421422
422423 return ;
423424 }
425+ }
426+ else if ( customPipeNameIsSet )
427+ {
428+ if ( runspaceVersion . Version < _minVersionForCustomPipeName )
429+ {
430+ await requestContext . SendError (
431+ $ "Attaching to a process with CustomPipeName is only available with PowerShell 6.2 and higher (current session is { runspaceVersion . Version } ).") ;
432+ return ;
433+ }
424434
425- // Clear any existing breakpoints before proceeding
426- await ClearSessionBreakpoints ( ) ;
427-
428- // Execute the Debug-Runspace command but don't await it because it
429- // will block the debug adapter initialization process. The
430- // InitializedEvent will be sent as soon as the RunspaceChanged
431- // event gets fired with the attached runspace.
432- int runspaceId = attachParams . RunspaceId > 0 ? attachParams . RunspaceId : 1 ;
433- _waitingForAttach = true ;
434- Task nonAwaitedTask =
435- _editorSession . PowerShellContext
436- . ExecuteScriptString ( $ "\n Debug-Runspace -Id { runspaceId } ")
437- . ContinueWith ( OnExecutionCompleted ) ;
435+ await _editorSession . PowerShellContext . ExecuteScriptString (
436+ $ "Enter-PSHostProcess -CustomPipeName { attachParams . CustomPipeName } ",
437+ errorMessages ) ;
438+
439+ if ( errorMessages . Length > 0 )
440+ {
441+ await requestContext . SendError (
442+ $ "Could not attach to process with CustomPipeName: '{ attachParams . CustomPipeName } '") ;
443+
444+ return ;
445+ }
438446 }
439447 else
440448 {
@@ -448,6 +456,19 @@ await requestContext.SendError(
448456 return ;
449457 }
450458
459+ // Clear any existing breakpoints before proceeding
460+ await ClearSessionBreakpoints ( ) . ConfigureAwait ( continueOnCapturedContext : false ) ;
461+
462+ // Execute the Debug-Runspace command but don't await it because it
463+ // will block the debug adapter initialization process. The
464+ // InitializedEvent will be sent as soon as the RunspaceChanged
465+ // event gets fired with the attached runspace.
466+ int runspaceId = attachParams . RunspaceId > 0 ? attachParams . RunspaceId : 1 ;
467+ _waitingForAttach = true ;
468+ Task nonAwaitedTask = _editorSession . PowerShellContext
469+ . ExecuteScriptString ( $ "\n Debug-Runspace -Id { runspaceId } ")
470+ . ContinueWith ( OnExecutionCompleted ) ;
471+
451472 await requestContext . SendResult ( null ) ;
452473 }
453474
0 commit comments