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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }