private void DebugService_DebuggerStopped(object sender, DebuggerStoppedEventArgs e) { // Provide the reason for why the debugger has stopped script execution. // See https://github.com/Microsoft/vscode/issues/3648 // The reason is displayed in the breakpoints viewlet. Some recommended reasons are: // "step", "breakpoint", "function breakpoint", "exception" and "pause". // We don't support exception breakpoints and for "pause", we can't distinguish // between stepping and the user pressing the pause/break button in the debug toolbar. string debuggerStoppedReason = "step"; if (e.OriginalEvent.Breakpoints.Count > 0) { debuggerStoppedReason = e.OriginalEvent.Breakpoints[0] is CommandBreakpoint ? "function breakpoint" : "breakpoint"; } _jsonRpcServer.SendNotification(EventNames.Stopped, new StoppedEvent { ThreadId = 1, Reason = debuggerStoppedReason }); }
private async Task LaunchScriptAsync(string scriptToLaunch) { // Is this an untitled script? if (ScriptFile.IsUntitledPath(scriptToLaunch)) { ScriptFile untitledScript = _workspaceService.GetFile(scriptToLaunch); await _powerShellContextService .ExecuteScriptStringAsync(untitledScript.Contents, true, true); } else { await _powerShellContextService .ExecuteScriptWithArgsAsync(scriptToLaunch, _debugStateService.Arguments, writeInputToHost : true); } _jsonRpcServer.SendNotification(EventNames.Terminated); }
private async Task OnExecutionCompletedAsync(Task executeTask) { try { await executeTask.ConfigureAwait(false); } catch (Exception e) { _logger.LogError( "Exception occurred while awaiting debug launch task.\n\n" + e.ToString()); } _logger.LogTrace("Execution completed, terminating..."); //_debugStateService.ExecutionCompleted = true; //_debugEventHandlerService.UnregisterEventHandlers(); //if (_debugStateService.IsAttachSession) //{ // // Pop the sessions // if (_powerShellContextService.CurrentRunspace.Context == RunspaceContext.EnteredProcess) // { // try // { // await _powerShellContextService.ExecuteScriptStringAsync("Exit-PSHostProcess"); // if (_debugStateService.IsRemoteAttach && // _powerShellContextService.CurrentRunspace.Location == RunspaceLocation.Remote) // { // await _powerShellContextService.ExecuteScriptStringAsync("Exit-PSSession"); // } // } // catch (Exception e) // { // _logger.LogException("Caught exception while popping attached process after debugging", e); // } // } //} //_debugService.IsClientAttached = false; _jsonRpcServer.SendNotification(EventNames.Terminated); }
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."); } // 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) { IEnumerable <int?> ids = await _powerShellContextService.ExecuteCommandAsync <int?>(new PSCommand() .AddCommand("Microsoft.PowerShell.Utility\\Get-Runspace") .AddParameter("Name", request.RunspaceName) .AddCommand("Microsoft.PowerShell.Utility\\Select-Object") .AddParameter("ExpandProperty", "Id")); foreach (var id in ids) { _debugStateService.RunspaceId = id; break; } 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."); } _debugStateService.RunspaceId = runspaceId; debugRunspaceCmd = $"\nDebug-Runspace -Id {runspaceId}"; } else { _debugStateService.RunspaceId = 1; debugRunspaceCmd = "\nDebug-Runspace -Id 1"; } // Clear any existing breakpoints before proceeding await _breakpointService.RemoveAllBreakpointsAsync().ConfigureAwait(continueOnCapturedContext: false); _debugStateService.WaitingForAttach = true; Task nonAwaitedTask = _powerShellContextService .ExecuteScriptStringAsync(debugRunspaceCmd) .ContinueWith(OnExecutionCompletedAsync); if (runspaceVersion.Version.Major >= 7) { _jsonRpcServer.SendNotification(EventNames.Initialized); } return(Unit.Value); }
public async Task <Unit> Handle(PsesLaunchRequestArguments request, CancellationToken cancellationToken) { _debugEventHandlerService.RegisterEventHandlers(); // Determine whether or not the working directory should be set in the PowerShellContext. if ((_powerShellContextService.CurrentRunspace.Location == RunspaceLocation.Local) && !_debugService.IsDebuggerStopped) { // Get the working directory that was passed via the debug config // (either via launch.json or generated via no-config debug). string workingDir = request.Cwd; // Assuming we have a non-empty/null working dir, unescape the path and verify // the path exists and is a directory. if (!string.IsNullOrEmpty(workingDir)) { try { if ((File.GetAttributes(workingDir) & FileAttributes.Directory) != FileAttributes.Directory) { workingDir = Path.GetDirectoryName(workingDir); } } catch (Exception ex) { workingDir = null; _logger.LogError( $"The specified 'cwd' path is invalid: '{request.Cwd}'. Error: {ex.Message}"); } } // If we have no working dir by this point and we are running in a temp console, // pick some reasonable default. if (string.IsNullOrEmpty(workingDir) && request.CreateTemporaryIntegratedConsole) { workingDir = Environment.CurrentDirectory; } // At this point, we will either have a working dir that should be set to cwd in // the PowerShellContext or the user has requested (via an empty/null cwd) that // the working dir should not be changed. if (!string.IsNullOrEmpty(workingDir)) { await _powerShellContextService.SetWorkingDirectoryAsync(workingDir, isPathAlreadyEscaped : false).ConfigureAwait(false); } _logger.LogTrace($"Working dir " + (string.IsNullOrEmpty(workingDir) ? "not set." : $"set to '{workingDir}'")); } // Prepare arguments to the script - if specified string arguments = null; if ((request.Args != null) && (request.Args.Length > 0)) { arguments = string.Join(" ", request.Args); _logger.LogTrace("Script arguments are: " + arguments); } // Store the launch parameters so that they can be used later _debugStateService.NoDebug = request.NoDebug; _debugStateService.ScriptToLaunch = request.Script; _debugStateService.Arguments = arguments; _debugStateService.IsUsingTempIntegratedConsole = request.CreateTemporaryIntegratedConsole; if (request.CreateTemporaryIntegratedConsole && !string.IsNullOrEmpty(request.Script) && ScriptFile.IsUntitledPath(request.Script)) { throw new RpcErrorException(0, "Running an Untitled file in a temporary integrated console is currently not supported."); } // If the current session is remote, map the script path to the remote // machine if necessary if (_debugStateService.ScriptToLaunch != null && _powerShellContextService.CurrentRunspace.Location == RunspaceLocation.Remote) { _debugStateService.ScriptToLaunch = _remoteFileManagerService.GetMappedPath( _debugStateService.ScriptToLaunch, _powerShellContextService.CurrentRunspace); } // If no script is being launched, mark this as an interactive // debugging session _debugStateService.IsInteractiveDebugSession = string.IsNullOrEmpty(_debugStateService.ScriptToLaunch); // Send the InitializedEvent so that the debugger will continue // sending configuration requests _jsonRpcServer.SendNotification(EventNames.Initialized); return(Unit.Value); }