public async Task <InitializeResponse> Handle(InitializeRequestArguments request, CancellationToken cancellationToken) { // Clear any existing breakpoints before proceeding await _debugService.ClearAllBreakpointsAsync().ConfigureAwait(false); // Now send the Initialize response to continue setup return(new InitializeResponse { SupportsConfigurationDoneRequest = true, SupportsFunctionBreakpoints = true, SupportsConditionalBreakpoints = true, SupportsHitConditionalBreakpoints = true, SupportsSetVariable = true }); }
public async Task <Unit> Handle(PsesAttachRequestArguments request, CancellationToken cancellationToken) { _debugStateService.IsAttachSession = true; _debugEventHandlerService.RegisterEventHandlers(); bool processIdIsSet = !string.IsNullOrEmpty(request.ProcessId) && request.ProcessId != "undefined"; bool customPipeNameIsSet = !string.IsNullOrEmpty(request.CustomPipeName) && request.CustomPipeName != "undefined"; PowerShellVersionDetails runspaceVersion = _powerShellContextService.CurrentRunspace.PowerShellVersion; // If there are no host processes to attach to or the user cancels selection, we get a null for the process id. // This is not an error, just a request to stop the original "attach to" request. // Testing against "undefined" is a HACK because I don't know how to make "Cancel" on quick pick loading // to cancel on the VSCode side without sending an attachRequest with processId set to "undefined". if (!processIdIsSet && !customPipeNameIsSet) { _logger.LogInformation( $"Attach request aborted, received {request.ProcessId} for processId."); throw new RpcErrorException(0, "User aborted attach to PowerShell host process."); } StringBuilder errorMessages = new StringBuilder(); if (request.ComputerName != null) { if (runspaceVersion.Version.Major < 4) { throw new RpcErrorException(0, $"Remote sessions are only available with PowerShell 4 and higher (current session is {runspaceVersion.Version})."); } else if (_powerShellContextService.CurrentRunspace.Location == RunspaceLocation.Remote) { throw new RpcErrorException(0, $"Cannot attach to a process in a remote session when already in a remote session."); } await _powerShellContextService.ExecuteScriptStringAsync( $"Enter-PSSession -ComputerName \"{request.ComputerName}\"", errorMessages).ConfigureAwait(false); if (errorMessages.Length > 0) { throw new RpcErrorException(0, $"Could not establish remote session to computer '{request.ComputerName}'"); } _debugStateService.IsRemoteAttach = true; } if (processIdIsSet && int.TryParse(request.ProcessId, out int processId) && (processId > 0)) { if (runspaceVersion.Version.Major < 5) { throw new RpcErrorException(0, $"Attaching to a process is only available with PowerShell 5 and higher (current session is {runspaceVersion.Version})."); } await _powerShellContextService.ExecuteScriptStringAsync( $"Enter-PSHostProcess -Id {processId}", errorMessages).ConfigureAwait(false); if (errorMessages.Length > 0) { throw new RpcErrorException(0, $"Could not attach to process '{processId}'"); } } else if (customPipeNameIsSet) { if (runspaceVersion.Version < s_minVersionForCustomPipeName) { throw new RpcErrorException(0, $"Attaching to a process with CustomPipeName is only available with PowerShell 6.2 and higher (current session is {runspaceVersion.Version})."); } await _powerShellContextService.ExecuteScriptStringAsync( $"Enter-PSHostProcess -CustomPipeName {request.CustomPipeName}", errorMessages).ConfigureAwait(false); if (errorMessages.Length > 0) { throw new RpcErrorException(0, $"Could not attach to process with CustomPipeName: '{request.CustomPipeName}'"); } } else if (request.ProcessId != "current") { _logger.LogError( $"Attach request failed, '{request.ProcessId}' is an invalid value for the processId."); throw new RpcErrorException(0, "A positive integer must be specified for the processId field."); } // Clear any existing breakpoints before proceeding await _debugService.ClearAllBreakpointsAsync().ConfigureAwait(continueOnCapturedContext: false); // Execute the Debug-Runspace command but don't await it because it // will block the debug adapter initialization process. The // InitializedEvent will be sent as soon as the RunspaceChanged // event gets fired with the attached runspace. string debugRunspaceCmd; if (request.RunspaceName != null) { debugRunspaceCmd = $"\nDebug-Runspace -Name '{request.RunspaceName}'"; } else if (request.RunspaceId != null) { if (!int.TryParse(request.RunspaceId, out int runspaceId) || runspaceId <= 0) { _logger.LogError( $"Attach request failed, '{request.RunspaceId}' is an invalid value for the processId."); throw new RpcErrorException(0, "A positive integer must be specified for the RunspaceId field."); } debugRunspaceCmd = $"\nDebug-Runspace -Id {runspaceId}"; } else { debugRunspaceCmd = "\nDebug-Runspace -Id 1"; } _debugStateService.WaitingForAttach = true; Task nonAwaitedTask = _powerShellContextService .ExecuteScriptStringAsync(debugRunspaceCmd) .ContinueWith(OnExecutionCompletedAsync); return(Unit.Value); }