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