@@ -43,6 +43,10 @@ public SynchronousPowerShellTask(
43
43
44
44
public override ExecutionOptions ExecutionOptions => PowerShellExecutionOptions ;
45
45
46
+ // These are PowerShell's intrinsic debugger commands that must be run via
47
+ // `ProcessDebugCommand`.
48
+ private static readonly string [ ] DebuggerCommands = { "continue" , "c" , "k" , "h" , "?" , "list" , "l" , "stepInto" , "s" , "stepOut" , "o" , "stepOver" , "v" , "quit" , "q" , "detach" , "d" } ;
49
+
46
50
public override IReadOnlyList < TResult > Run ( CancellationToken cancellationToken )
47
51
{
48
52
_pwsh = _psesHost . CurrentPowerShell ;
@@ -53,6 +57,7 @@ public override IReadOnlyList<TResult> Run(CancellationToken cancellationToken)
53
57
}
54
58
55
59
return _pwsh . Runspace . Debugger . InBreakpoint
60
+ && Array . Exists ( DebuggerCommands , c => c == _psCommand . GetInvocationText ( ) )
56
61
? ExecuteInDebugger ( cancellationToken )
57
62
: ExecuteNormally ( cancellationToken ) ;
58
63
}
@@ -87,9 +92,15 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
87
92
result = _pwsh . InvokeCommand < TResult > ( _psCommand , invocationSettings ) ;
88
93
cancellationToken . ThrowIfCancellationRequested ( ) ;
89
94
}
90
- // Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException effectively means the pipeline was stopped.
95
+ // Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException
96
+ // effectively means the pipeline was stopped.
91
97
catch ( Exception e ) when ( cancellationToken . IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException )
92
98
{
99
+ // ExecuteNormally handles user commands in a debug session. Perhaps we should clean all this up somehow.
100
+ if ( _pwsh . Runspace . Debugger . InBreakpoint )
101
+ {
102
+ StopDebuggerIfRemoteDebugSessionFailed ( ) ;
103
+ }
93
104
throw new OperationCanceledException ( ) ;
94
105
}
95
106
// We only catch RuntimeExceptions here in case writing errors to output was requested
@@ -122,6 +133,8 @@ private IReadOnlyList<TResult> ExecuteNormally(CancellationToken cancellationTok
122
133
123
134
private IReadOnlyList < TResult > ExecuteInDebugger ( CancellationToken cancellationToken )
124
135
{
136
+ // TODO: How much of this method can we remove now that it only processes PowerShell's
137
+ // intrinsic debugger commands?
125
138
cancellationToken . Register ( CancelDebugExecution ) ;
126
139
127
140
var outputCollection = new PSDataCollection < PSObject > ( ) ;
@@ -146,14 +159,22 @@ private IReadOnlyList<TResult> ExecuteInDebugger(CancellationToken cancellationT
146
159
DebuggerCommandResults debuggerResult = null ;
147
160
try
148
161
{
149
- // In the PowerShell debugger, extra debugger commands are made available, like "l", "s", "c", etc.
150
- // Executing those commands produces a result that needs to be set on the debugger stop event args.
151
- // So we use the Debugger.ProcessCommand() API to properly execute commands in the debugger
152
- // and then call DebugContext.ProcessDebuggerResult() later to handle the command appropriately
162
+ // In the PowerShell debugger, intrinsic debugger commands are made available, like
163
+ // "l", "s", "c", etc. Executing those commands produces a result that needs to be
164
+ // set on the debugger stop event args. So we use the Debugger.ProcessCommand() API
165
+ // to properly execute commands in the debugger and then call
166
+ // DebugContext.ProcessDebuggerResult() later to handle the command appropriately
167
+ //
168
+ // Unfortunately, this API does not allow us to pass in the InvocationSettings,
169
+ // which means (for instance) that we cannot instruct it to avoid adding our
170
+ // debugger implmentation's commands to the history. So instead we now only call
171
+ // `ExecuteInDebugger` for PowerShell's own intrinsic debugger commands.
153
172
debuggerResult = _pwsh . Runspace . Debugger . ProcessCommand ( _psCommand , outputCollection ) ;
154
173
cancellationToken . ThrowIfCancellationRequested ( ) ;
155
174
}
156
- // Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException effectively means the pipeline was stopped.
175
+
176
+ // Test if we've been cancelled. If we're remoting, PSRemotingDataStructureException
177
+ // effectively means the pipeline was stopped.
157
178
catch ( Exception e ) when ( cancellationToken . IsCancellationRequested || e is PipelineStoppedException || e is PSRemotingDataStructureException )
158
179
{
159
180
StopDebuggerIfRemoteDebugSessionFailed ( ) ;
0 commit comments