diff --git a/src/System.Management.Automation/engine/debugger/debugger.cs b/src/System.Management.Automation/engine/debugger/debugger.cs
index 77992fcf86..2da8856222 100644
--- a/src/System.Management.Automation/engine/debugger/debugger.cs
+++ b/src/System.Management.Automation/engine/debugger/debugger.cs
@@ -622,20 +622,23 @@ namespace System.Management.Automation
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
///
/// Id of the breakpoint you want.
- public virtual Breakpoint GetBreakpoint(int id) =>
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public virtual Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
throw new PSNotImplementedException();
///
/// Adds the provided set of breakpoints to the debugger.
///
/// Breakpoints.
- public virtual void SetBreakpoints(IEnumerable breakpoints) =>
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public virtual void SetBreakpoints(IEnumerable breakpoints, int? runspaceId = null) =>
throw new PSNotImplementedException();
///
/// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
///
- public virtual List GetBreakpoints() =>
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public virtual List GetBreakpoints(int? runspaceId = null) =>
throw new PSNotImplementedException();
///
@@ -644,8 +647,9 @@ namespace System.Management.Automation
/// The name of the command that will trigger the breakpoint. This value is required and may not be null.
/// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
/// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
/// The command breakpoint that was set.
- public virtual CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
+ public virtual CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
throw new PSNotImplementedException();
///
@@ -655,8 +659,9 @@ namespace System.Management.Automation
/// The line in the script file where the breakpoint may be hit. This value is required and must be greater than or equal to 1.
/// The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.
/// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
/// The line breakpoint that was set.
- public virtual LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
+ public virtual LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null, int? runspaceId = null) =>
throw new PSNotImplementedException();
///
@@ -666,32 +671,36 @@ namespace System.Management.Automation
/// The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.
/// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
/// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the variable is accessed using the specified access mode.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
/// The variable breakpoint that was set.
- public virtual VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
+ public virtual VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
throw new PSNotImplementedException();
///
/// Removes a breakpoint from the debugger.
///
/// The breakpoint to remove from the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
/// True if the breakpoint was removed from the debugger; false otherwise.
- public virtual bool RemoveBreakpoint(Breakpoint breakpoint) =>
+ public virtual bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
throw new PSNotImplementedException();
///
/// Enables a breakpoint in the debugger.
///
/// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
/// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
- public virtual Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
+ public virtual Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
throw new PSNotImplementedException();
///
/// Disables a breakpoint in the debugger.
///
/// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
/// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
- public virtual Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
+ public virtual Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
throw new PSNotImplementedException();
///
@@ -2590,9 +2599,16 @@ namespace System.Management.Automation
///
/// Adds the provided set of breakpoints to the debugger.
///
- ///
- public override void SetBreakpoints(IEnumerable breakpoints)
+ /// The breakpoints to set.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override void SetBreakpoints(IEnumerable breakpoints, int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ GetRunspaceDebugger(runspaceId.Value).SetBreakpoints(breakpoints);
+ return;
+ }
+
foreach (Breakpoint bp in breakpoints)
{
switch (bp)
@@ -2616,8 +2632,14 @@ namespace System.Management.Automation
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
///
/// Id of the breakpoint you want.
- public override Breakpoint GetBreakpoint(int id)
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override Breakpoint GetBreakpoint(int id, int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ return GetRunspaceDebugger(runspaceId.Value).GetBreakpoint(id);
+ }
+
_idToBreakpoint.TryGetValue(id, out Breakpoint breakpoint);
return breakpoint;
}
@@ -2625,8 +2647,14 @@ namespace System.Management.Automation
///
/// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
///
- public override List GetBreakpoints()
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override List GetBreakpoints(int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ return GetRunspaceDebugger(runspaceId.Value).GetBreakpoints();
+ }
+
return (from bp in _idToBreakpoint.Values orderby bp.Id select bp).ToList();
}
@@ -2636,9 +2664,15 @@ namespace System.Management.Automation
/// The name of the command that will trigger the breakpoint. This value is required and may not be null.
/// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
/// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
///
- public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null)
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null, int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ return GetRunspaceDebugger(runspaceId.Value).SetCommandBreakpoint(command, action, path);
+ }
+
Diagnostics.Assert(!string.IsNullOrEmpty(command), "Caller to verify command is not null or empty.");
WildcardPattern pattern = WildcardPattern.Get(command, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
@@ -2654,9 +2688,15 @@ namespace System.Management.Automation
/// The line in the script file where the breakpoint may be hit. This value is required and must be greater than or equal to 1.
/// The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.
/// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
- ///
- public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null)
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// A LineBreakpoint
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null, int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ return GetRunspaceDebugger(runspaceId.Value).SetLineBreakpoint(path, line, column, action);
+ }
+
Diagnostics.Assert(path != null, "Caller to verify path is not null.");
Diagnostics.Assert(line > 0, "Caller to verify line is greater than 0.");
@@ -2671,18 +2711,33 @@ namespace System.Management.Automation
/// The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.
/// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
/// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the variable is accessed using the specified access mode.
- ///
- public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null)
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// A VariableBreakpoint that was set.
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null, int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ return GetRunspaceDebugger(runspaceId.Value).SetVariableBreakpoint(variableName, accessMode, action, path);
+ }
+
Diagnostics.Assert(!string.IsNullOrEmpty(variableName), "Caller to verify variableName is not null or empty.");
CheckForBreakpointSupport();
return AddVariableBreakpoint(new VariableBreakpoint(path, variableName, accessMode, action));
}
- // This is the implementation of the Remove-PSBreakpoint cmdlet.
- public override bool RemoveBreakpoint(Breakpoint breakpoint)
+ ///
+ /// This is the implementation of the Remove-PSBreakpoint cmdlet.
+ ///
+ /// Id of the breakpoint you want.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ return GetRunspaceDebugger(runspaceId.Value).RemoveBreakpoint(breakpoint);
+ }
+
Diagnostics.Assert(breakpoint != null, "Caller to verify the breakpoint is not null.");
if (_idToBreakpoint.Remove(breakpoint.Id, out _))
@@ -2702,10 +2757,18 @@ namespace System.Management.Automation
return false;
}
-
- // This is the implementation of the Enable-PSBreakpoint cmdlet.
- public override Breakpoint EnableBreakpoint(Breakpoint breakpoint)
+ ///
+ /// This is the implementation of the Enable-PSBreakpoint cmdlet.
+ ///
+ /// Id of the breakpoint you want.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ return GetRunspaceDebugger(runspaceId.Value).EnableBreakpoint(breakpoint);
+ }
+
Diagnostics.Assert(breakpoint != null, "Caller to verify the breakpoint is not null.");
if (_idToBreakpoint.TryGetValue(breakpoint.Id, out _))
@@ -2719,9 +2782,18 @@ namespace System.Management.Automation
return null;
}
- // This is the implementation of the Disable-PSBreakpoint cmdlet.
- public override Breakpoint DisableBreakpoint(Breakpoint breakpoint)
+ ///
+ /// This is the implementation of the Disable-PSBreakpoint cmdlet.
+ ///
+ /// Id of the breakpoint you want.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
+ if (runspaceId.HasValue)
+ {
+ return GetRunspaceDebugger(runspaceId.Value).DisableBreakpoint(breakpoint);
+ }
+
Diagnostics.Assert(breakpoint != null, "Caller to verify the breakpoint is not null.");
if (_idToBreakpoint.TryGetValue(breakpoint.Id, out _))
@@ -2735,6 +2807,21 @@ namespace System.Management.Automation
return null;
}
+ private Debugger GetRunspaceDebugger(int runspaceId)
+ {
+ if (!Runspace.RunspaceDictionary.TryGetValue(runspaceId, out WeakReference wr))
+ {
+ throw new PSArgumentException(string.Format(DebuggerStrings.InvalidRunspaceId, runspaceId));
+ }
+
+ if (!wr.TryGetTarget(out Runspace rs))
+ {
+ throw new PSArgumentException(DebuggerStrings.UnableToGetRunspace);
+ }
+
+ return rs.Debugger;
+ }
+
#endregion Breakpoints
#region Job Debugging
@@ -4084,8 +4171,9 @@ namespace System.Management.Automation
/// Adds the provided set of breakpoints to the debugger.
///
/// Breakpoints.
- public override void SetBreakpoints(IEnumerable breakpoints) =>
- _wrappedDebugger.SetBreakpoints(breakpoints);
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override void SetBreakpoints(IEnumerable breakpoints, int? runspaceId = null) =>
+ _wrappedDebugger.SetBreakpoints(breakpoints, runspaceId);
///
/// Process debugger or PowerShell command/script.
@@ -4123,29 +4211,83 @@ namespace System.Management.Automation
return _wrappedDebugger.ProcessCommand(command, output);
}
- public override Breakpoint GetBreakpoint(int id) =>
- _wrappedDebugger.GetBreakpoint(id);
+ ///
+ /// Get a breakpoint by id.
+ ///
+ /// Id of the breakpoint you want.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
+ _wrappedDebugger.GetBreakpoint(id, runspaceId);
- public override List GetBreakpoints() =>
- _wrappedDebugger.GetBreakpoints();
+ ///
+ /// Returns breakpoints on a runspace.
+ ///
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// A list of breakpoints in a runspace.
+ public override List GetBreakpoints(int? runspaceId = null) =>
+ _wrappedDebugger.GetBreakpoints(runspaceId);
- public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
- _wrappedDebugger.SetCommandBreakpoint(command, action, path);
+ ///
+ /// Sets a command breakpoint in the debugger.
+ ///
+ /// The name of the command that will trigger the breakpoint. This value is required and may not be null.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The command breakpoint that was set.
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetCommandBreakpoint(command, action, path, runspaceId);
- public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
- _wrappedDebugger.SetLineBreakpoint(path, line, column, action);
+ ///
+ /// Sets a line breakpoint in the debugger.
+ ///
+ /// The path to the script file where the breakpoint may be hit. This value is required and may not be null.
+ /// The line in the script file where the breakpoint may be hit. This value is required and must be greater than or equal to 1.
+ /// The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The line breakpoint that was set.
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetLineBreakpoint(path, line, column, action, runspaceId);
- public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
- _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path);
+ ///
+ /// Sets a variable breakpoint in the debugger.
+ ///
+ /// The name of the variable that will trigger the breakpoint. This value is required and may not be null.
+ /// The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the variable is accessed using the specified access mode.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The variable breakpoint that was set.
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path, runspaceId);
- public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.RemoveBreakpoint(breakpoint);
+ ///
+ /// Removes a breakpoint from the debugger.
+ ///
+ /// The breakpoint to remove from the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// True if the breakpoint was removed from the debugger; false otherwise.
+ public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.RemoveBreakpoint(breakpoint, runspaceId);
- public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.EnableBreakpoint(breakpoint);
+ ///
+ /// Enables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.EnableBreakpoint(breakpoint, runspaceId);
- public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.DisableBreakpoint(breakpoint);
+ ///
+ /// Disables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.DisableBreakpoint(breakpoint, runspaceId);
///
/// SetDebuggerAction.
diff --git a/src/System.Management.Automation/engine/hostifaces/PSTask.cs b/src/System.Management.Automation/engine/hostifaces/PSTask.cs
index 9a17e20252..c68a84a9d0 100644
--- a/src/System.Management.Automation/engine/hostifaces/PSTask.cs
+++ b/src/System.Management.Automation/engine/hostifaces/PSTask.cs
@@ -1091,8 +1091,9 @@ namespace System.Management.Automation.PSTasks
/// Adds the provided set of breakpoints to the debugger.
///
/// List of breakpoints.
- public override void SetBreakpoints(IEnumerable breakpoints) =>
- _wrappedDebugger.SetBreakpoints(breakpoints);
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override void SetBreakpoints(IEnumerable breakpoints, int? runspaceId = null) =>
+ _wrappedDebugger.SetBreakpoints(breakpoints, runspaceId);
///
/// Sets the debugger resume action.
@@ -1103,26 +1104,84 @@ namespace System.Management.Automation.PSTasks
_wrappedDebugger.SetDebuggerAction(resumeAction);
}
- public override Breakpoint GetBreakpoint(int id) =>
- _wrappedDebugger.GetBreakpoint(id);
+ ///
+ /// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
+ ///
+ /// Id of the breakpoint you want.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The breakpoint with the specified id.
+ public override Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
+ _wrappedDebugger.GetBreakpoint(id, runspaceId);
- public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
- _wrappedDebugger.SetCommandBreakpoint(command, action, path);
+ ///
+ /// Returns breakpoints on a runspace.
+ ///
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// A list of breakpoints in a runspace.
+ public override List GetBreakpoints(int? runspaceId = null) =>
+ _wrappedDebugger.GetBreakpoints(runspaceId);
- public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
- _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path);
+ ///
+ /// Sets a command breakpoint in the debugger.
+ ///
+ /// The name of the command that will trigger the breakpoint. This value is required and may not be null.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The command breakpoint that was set.
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetCommandBreakpoint(command, action, path, runspaceId);
- public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
- _wrappedDebugger.SetLineBreakpoint(path, line, column, action);
+ ///
+ /// Sets a variable breakpoint in the debugger.
+ ///
+ /// The name of the variable that will trigger the breakpoint. This value is required and may not be null.
+ /// The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the variable is accessed using the specified access mode.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The variable breakpoint that was set.
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path, runspaceId);
- public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.EnableBreakpoint(breakpoint);
+ ///
+ /// Sets a line breakpoint in the debugger.
+ ///
+ /// The path to the script file where the breakpoint may be hit. This value is required and may not be null.
+ /// The line in the script file where the breakpoint may be hit. This value is required and must be greater than or equal to 1.
+ /// The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The line breakpoint that was set.
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetLineBreakpoint(path, line, column, action, runspaceId);
- public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.DisableBreakpoint(breakpoint);
+ ///
+ /// Enables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.EnableBreakpoint(breakpoint, runspaceId);
- public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.RemoveBreakpoint(breakpoint);
+ ///
+ /// Disables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.DisableBreakpoint(breakpoint, runspaceId);
+
+ ///
+ /// Removes a breakpoint from the debugger.
+ ///
+ /// The breakpoint to remove from the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// True if the breakpoint was removed from the debugger; false otherwise.
+ public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.RemoveBreakpoint(breakpoint, runspaceId);
///
/// Stops a running command.
diff --git a/src/System.Management.Automation/engine/remoting/client/Job.cs b/src/System.Management.Automation/engine/remoting/client/Job.cs
index 93061df4a8..d01e555d71 100644
--- a/src/System.Management.Automation/engine/remoting/client/Job.cs
+++ b/src/System.Management.Automation/engine/remoting/client/Job.cs
@@ -3913,32 +3913,88 @@ namespace System.Management.Automation
/// Adds the provided set of breakpoints to the debugger.
///
/// Breakpoints to set.
- public override void SetBreakpoints(IEnumerable breakpoints) =>
- _wrappedDebugger.SetBreakpoints(breakpoints);
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override void SetBreakpoints(IEnumerable breakpoints, int? runspaceId = null) =>
+ _wrappedDebugger.SetBreakpoints(breakpoints, runspaceId);
- public override Breakpoint GetBreakpoint(int id) =>
- _wrappedDebugger.GetBreakpoint(id);
+ ///
+ /// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
+ ///
+ /// Id of the breakpoint you want.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// A a breakpoint with the specified id.
+ public override Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
+ _wrappedDebugger.GetBreakpoint(id, runspaceId);
- public override List GetBreakpoints() =>
- _wrappedDebugger.GetBreakpoints();
+ ///
+ /// Returns breakpoints on a runspace.
+ ///
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// A list of breakpoints in a runspace.
+ public override List GetBreakpoints(int? runspaceId = null) =>
+ _wrappedDebugger.GetBreakpoints(runspaceId);
- public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
- _wrappedDebugger.SetCommandBreakpoint(command, action, path);
+ ///
+ /// Sets a command breakpoint in the debugger.
+ ///
+ /// The name of the command that will trigger the breakpoint. This value is required and may not be null.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The command breakpoint that was set.
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetCommandBreakpoint(command, action, path, runspaceId);
- public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
- _wrappedDebugger.SetLineBreakpoint(path, line, column, action);
+ ///
+ /// Sets a line breakpoint in the debugger.
+ ///
+ /// The path to the script file where the breakpoint may be hit. This value is required and may not be null.
+ /// The line in the script file where the breakpoint may be hit. This value is required and must be greater than or equal to 1.
+ /// The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The line breakpoint that was set.
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetLineBreakpoint(path, line, column, action, runspaceId);
- public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
- _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path);
+ ///
+ /// Sets a variable breakpoint in the debugger.
+ ///
+ /// The name of the variable that will trigger the breakpoint. This value is required and may not be null.
+ /// The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the variable is accessed using the specified access mode.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The variable breakpoint that was set.
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
+ _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path, runspaceId);
- public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.RemoveBreakpoint(breakpoint);
+ ///
+ /// Removes a breakpoint from the debugger.
+ ///
+ /// The breakpoint to remove from the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// True if the breakpoint was removed from the debugger; false otherwise.
+ public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.RemoveBreakpoint(breakpoint, runspaceId);
- public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.EnableBreakpoint(breakpoint);
+ ///
+ /// Enables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.EnableBreakpoint(breakpoint, runspaceId);
- public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.DisableBreakpoint(breakpoint);
+ ///
+ /// Disables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.DisableBreakpoint(breakpoint, runspaceId);
///
/// Sets the debugger resume action.
diff --git a/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs b/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs
index dc9b2bab40..ce7abd0749 100644
--- a/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs
+++ b/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs
@@ -2010,30 +2010,55 @@ namespace System.Management.Automation
/// Adds the provided set of breakpoints to the debugger.
///
/// Breakpoints to set.
- public override void SetBreakpoints(IEnumerable breakpoints) =>
- _runspace.Debugger?.SetBreakpoints(breakpoints);
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override void SetBreakpoints(IEnumerable breakpoints, int? runspaceId = null)
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.SetBreakpoint);
+
+ var functionParameters = new Dictionary
+ {
+ { "BreakpointList", breakpoints },
+ };
+
+ if (runspaceId.HasValue)
+ {
+ functionParameters.Add("RunspaceId", runspaceId.Value);
+ }
+
+ InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
+ }
///
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
///
/// Id of the breakpoint you want.
- public override Breakpoint GetBreakpoint(int id)
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The breakpoint with the specified id.
+ public override Breakpoint GetBreakpoint(int id, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.GetBreakpoint);
- return InvokeRemoteBreakpointFunction(
- RemoteDebuggingCommands.GetBreakpoint,
- new Dictionary
- {
- { "Id", id },
- });
+ var functionParameters = new Dictionary
+ {
+ { "Id", id },
+ };
+
+ if (runspaceId.HasValue)
+ {
+ functionParameters.Add("RunspaceId", runspaceId.Value);
+ }
+
+ return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.GetBreakpoint, functionParameters);
}
///
/// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
///
- public override List GetBreakpoints()
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// A list of breakpoints in a runspace.
+ public override List GetBreakpoints(int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.GetBreakpoint);
@@ -2046,6 +2071,11 @@ namespace System.Management.Automation
{
ps.AddCommand(RemoteDebuggingCommands.GetBreakpoint);
+ if (runspaceId.HasValue)
+ {
+ ps.AddParameter("RunspaceId", runspaceId.Value);
+ }
+
Collection output = ps.Invoke();
foreach (var item in output)
{
@@ -2053,124 +2083,186 @@ namespace System.Management.Automation
{
breakpoints.Add(bp);
}
+ else if (TryGetRemoteDebuggerException(item, out Exception ex))
+ {
+ throw ex;
+ }
}
}
return breakpoints;
}
- public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null)
+ ///
+ /// Sets a command breakpoint in the debugger.
+ ///
+ /// The name of the command that will trigger the breakpoint. This value is required and may not be null.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The command breakpoint that was set.
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.SetBreakpoint);
-
+
+ Breakpoint breakpoint = new CommandBreakpoint(path, null, command, action);
var functionParameters = new Dictionary
{
- { "Command", command },
+ { "Breakpoint", breakpoint },
};
- if (action != null)
+ if (runspaceId.HasValue)
{
- functionParameters.Add("Action", action);
- }
-
- if (path != null)
- {
- functionParameters.Add("Script", path);
+ functionParameters.Add("RunspaceId", runspaceId.Value);
}
return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
}
- public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null)
+ ///
+ /// Sets a line breakpoint in the debugger.
+ ///
+ /// The path to the script file where the breakpoint may be hit. This value is required and may not be null.
+ /// The line in the script file where the breakpoint may be hit. This value is required and must be greater than or equal to 1.
+ /// The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The line breakpoint that was set.
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.SetBreakpoint);
+ Breakpoint breakpoint = new LineBreakpoint(path, line, column, action);
+
var functionParameters = new Dictionary
{
- { "Script", path },
- { "Line", line },
+ { "Breakpoint", breakpoint },
};
- if (column != 0)
+ if (runspaceId.HasValue)
{
- functionParameters.Add("Column", column);
- }
-
- if (action != null)
- {
- functionParameters.Add("Action", action);
+ functionParameters.Add("RunspaceId", runspaceId.Value);
}
return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
}
- public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null)
+ ///
+ /// Sets a variable breakpoint in the debugger.
+ ///
+ /// The name of the variable that will trigger the breakpoint. This value is required and may not be null.
+ /// The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the variable is accessed using the specified access mode.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The variable breakpoint that was set.
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.SetBreakpoint);
+ Breakpoint breakpoint = new VariableBreakpoint(path, variableName, accessMode, action);
+
var functionParameters = new Dictionary
{
- { "Variable", variableName },
+ { "Breakpoint", breakpoint },
};
- if (accessMode != VariableAccessMode.Write)
+ if (runspaceId.HasValue)
{
- functionParameters.Add("Mode", accessMode);
- }
-
- if (action != null)
- {
- functionParameters.Add("Action", action);
- }
-
- if (path != null)
- {
- functionParameters.Add("Script", path);
+ functionParameters.Add("RunspaceId", runspaceId.Value);
}
return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
}
- public override bool RemoveBreakpoint(Breakpoint breakpoint)
+ ///
+ /// Removes a breakpoint from the debugger.
+ ///
+ /// The breakpoint to remove from the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// True if the breakpoint was removed from the debugger; false otherwise.
+ public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.RemoveBreakpoint);
- return InvokeRemoteBreakpointFunction(
- RemoteDebuggingCommands.RemoveBreakpoint,
- new Dictionary
- {
- { "Id", breakpoint.Id },
- });
+ if (breakpoint == null)
+ {
+ return false;
+ }
+
+ var functionParameters = new Dictionary
+ {
+ { "Id", breakpoint.Id },
+ };
+
+ if (runspaceId.HasValue)
+ {
+ functionParameters.Add("RunspaceId", runspaceId.Value);
+ }
+
+ return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.RemoveBreakpoint, functionParameters);
}
- public override Breakpoint EnableBreakpoint(Breakpoint breakpoint)
+ ///
+ /// Enables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.EnableBreakpoint);
- return InvokeRemoteBreakpointFunction(
- RemoteDebuggingCommands.EnableBreakpoint,
- new Dictionary
- {
- { "Id", breakpoint.Id },
- });
+ if (breakpoint == null)
+ {
+ return null;
+ }
+
+ var functionParameters = new Dictionary
+ {
+ { "Id", breakpoint.Id },
+ };
+
+ if (runspaceId.HasValue)
+ {
+ functionParameters.Add("RunspaceId", runspaceId.Value);
+ }
+
+ return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.EnableBreakpoint, functionParameters);
}
- public override Breakpoint DisableBreakpoint(Breakpoint breakpoint)
+ ///
+ /// Disables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.DisableBreakpoint);
- return InvokeRemoteBreakpointFunction(
- RemoteDebuggingCommands.DisableBreakpoint,
- new Dictionary
- {
- { "Id", breakpoint.Id },
- });
+ if (breakpoint == null)
+ {
+ return null;
+ }
+
+ var functionParameters = new Dictionary
+ {
+ { "Id", breakpoint.Id },
+ };
+
+ if (runspaceId.HasValue)
+ {
+ functionParameters.Add("RunspaceId", runspaceId.Value);
+ }
+
+ return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.DisableBreakpoint, functionParameters);
}
///
@@ -2518,6 +2610,38 @@ namespace System.Management.Automation
#region Private Methods
+ private static bool TryGetRemoteDebuggerException(
+ PSObject item,
+ out Exception exception)
+ {
+ exception = null;
+ if (item == null)
+ {
+ return false;
+ }
+
+ bool haveExceptionType = false;
+ foreach (var typeName in item.TypeNames)
+ {
+ if (typeName.Equals("Deserialized.System.Exception"))
+ {
+ haveExceptionType = true;
+ break;
+ }
+ }
+
+ if (haveExceptionType)
+ {
+ var errorMessage = item.Properties["Message"]?.Value ?? string.Empty;
+ exception = new RemoteException(
+ StringUtil.Format(
+ RemotingErrorIdStrings.RemoteDebuggerError, item.TypeNames[0], errorMessage));
+ return true;
+ }
+
+ return false;
+ }
+
//
// Event handlers
//
@@ -2785,6 +2909,11 @@ namespace System.Management.Automation
{
return (T)item.BaseObject;
}
+
+ if (TryGetRemoteDebuggerException(item, out Exception ex))
+ {
+ throw ex;
+ }
}
return default(T);
diff --git a/src/System.Management.Automation/engine/remoting/server/ServerPowerShellDriver.cs b/src/System.Management.Automation/engine/remoting/server/ServerPowerShellDriver.cs
index 8096a0e3f6..ce5f69ee6a 100644
--- a/src/System.Management.Automation/engine/remoting/server/ServerPowerShellDriver.cs
+++ b/src/System.Management.Automation/engine/remoting/server/ServerPowerShellDriver.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
+using System.Collections.Generic;
using System.Management.Automation.Internal;
using System.Management.Automation.Remoting;
using System.Management.Automation.Runspaces;
@@ -289,7 +290,8 @@ namespace System.Management.Automation
/// commands that sets debugger state but doesn't run any command
/// on the server runspace.
///
- internal void RunNoOpCommand()
+ /// The output from preprocessing that we want to send to the client.
+ internal void RunNoOpCommand(IReadOnlyCollection
SetPreserveUnhandledBreakpointMode,
+
+ ///
+ /// The PreProcessCommandResult used for managing breakpoints.
+ ///
+ BreakpointManagement,
};
private class DebuggerCommandArgument
@@ -1254,21 +1276,21 @@ namespace System.Management.Automation
/// Pre-processor for debugger commands.
/// Parses special debugger commands and converts to equivalent script for remote execution as needed.
///
- /// PSCommand.
- /// True if debugger is active.
- /// True if active debugger is pushed and is a remote debugger.
+ /// The PSCommand.
+ /// The debugger that can be used to invoke debug operations via API.
+ /// A Collection that can be used to send output to the client.
/// Command argument.
/// PreProcessCommandResult type if preprocessing occurred.
private static PreProcessCommandResult PreProcessDebuggerCommand(
PSCommand commands,
- bool isDebuggerActive,
- bool isDebuggerRemote,
+ ServerRemoteDebugger serverRemoteDebugger,
+ Collection preProcessOutput,
out DebuggerCommandArgument commandArgument)
{
commandArgument = new DebuggerCommandArgument();
PreProcessCommandResult result = PreProcessCommandResult.None;
- if ((commands.Commands.Count == 0) || (commands.Commands[0].IsScript))
+ if (commands.Commands.Count == 0 || commands.Commands[0].IsScript)
{
return result;
}
@@ -1282,7 +1304,7 @@ namespace System.Management.Automation
// Returns DebuggerStopEventArgs object.
// Evaluate this command only if the debugger is activated.
- if (!isDebuggerActive)
+ if (!serverRemoteDebugger.IsActive)
{
return PreProcessCommandResult.ValidNotProcessed;
}
@@ -1296,7 +1318,7 @@ namespace System.Management.Automation
// Returns void.
// Evaluate this command only if the debugger is activated.
- if (!isDebuggerActive)
+ if (!serverRemoteDebugger.IsActive)
{
return PreProcessCommandResult.ValidNotProcessed;
}
@@ -1315,7 +1337,10 @@ namespace System.Management.Automation
{
resumeAction = (DebuggerResumeAction)resumeObject.BaseObject;
}
- catch (InvalidCastException) { }
+ catch (InvalidCastException)
+ {
+ // Do nothing.
+ }
}
commandArgument.ResumeAction = resumeAction ?? throw new PSArgumentException("ResumeAction");
@@ -1340,7 +1365,10 @@ namespace System.Management.Automation
{
mode = (DebugModes)modeObject.BaseObject;
}
- catch (InvalidCastException) { }
+ catch (InvalidCastException)
+ {
+ // Do nothing.
+ }
}
commandArgument.Mode = mode ?? throw new PSArgumentException("Mode");
@@ -1380,7 +1408,10 @@ namespace System.Management.Automation
{
mode = (UnhandledBreakpointProcessingMode)modeObject.BaseObject;
}
- catch (InvalidCastException) { }
+ catch (InvalidCastException)
+ {
+ // Do nothing.
+ }
}
commandArgument.UnhandledBreakpointMode = mode ?? throw new PSArgumentException("Mode");
@@ -1392,126 +1423,121 @@ namespace System.Management.Automation
// Input parameters:
// [-Id ]
// Returns Breakpoint object(s).
- string script = null;
-
- if (command.Parameters?.Count > 0)
+ TryGetParameter(command, "RunspaceId", out int? runspaceId);
+ if (TryGetParameter(command, "Id", out int breakpointId))
{
- int breakpointId = CheckBreakpointIdParameter(command);
- script = $"$host.Runspace.Debugger.GetBreakpoint({breakpointId})";
+ preProcessOutput.Add(serverRemoteDebugger.GetBreakpoint(breakpointId, runspaceId));
}
else
{
- script = $"$host.Runspace.Debugger.GetBreakpoints()";
+ foreach (Breakpoint breakpoint in serverRemoteDebugger.GetBreakpoints(runspaceId))
+ {
+ preProcessOutput.Add(breakpoint);
+ }
}
- ReplaceVirtualCommandWithScript(commands, script);
+ result = PreProcessCommandResult.BreakpointManagement;
}
else if (commandText.Equals(RemoteDebuggingCommands.SetBreakpoint, StringComparison.OrdinalIgnoreCase))
{
// __Set-PSBreakpoint private virtual command.
// Input parameters:
- // [-Script] [-Line] [[-Column] ] [-Action ]
- // [[-Script] ] -Command [-Action ]
- // [[-Script] ] -Variable [-Action ] [-Mode ]
- // Returns Breakpoint object.
- if (command.Parameters == null || command.Parameters.Count == 0)
+ // -Breakpoint or -BreakpointList >
+ // [-RunspaceId ]
+ // Returns Breakpoint object(s).
+ TryGetParameter(command, "Breakpoint", out Breakpoint breakpoint);
+ TryGetParameter(command, "BreakpointList", out ArrayList breakpoints);
+ if (breakpoint == null && breakpoints == null)
{
- throw new PSArgumentException("You must provide at least one parameter.");
+ throw new PSArgumentException(DebuggerStrings.BreakpointOrBreakpointListNotSpecified);
}
- string breakpointType = null;
- foreach (var commandParameter in command.Parameters)
- {
- if (!commandParameter.Name.Equals("Script", StringComparison.OrdinalIgnoreCase) &&
- !commandParameter.Name.Equals("Line", StringComparison.OrdinalIgnoreCase) &&
- !commandParameter.Name.Equals("Column", StringComparison.OrdinalIgnoreCase) &&
- !commandParameter.Name.Equals("Action", StringComparison.OrdinalIgnoreCase) &&
- !commandParameter.Name.Equals("Command", StringComparison.OrdinalIgnoreCase) &&
- !commandParameter.Name.Equals("Variable", StringComparison.OrdinalIgnoreCase) &&
- !commandParameter.Name.Equals("Mode", StringComparison.OrdinalIgnoreCase))
- {
- throw new PSArgumentException(commandParameter.Name);
- }
-
- if (commandParameter.Name.Equals("Line", StringComparison.OrdinalIgnoreCase) ||
- commandParameter.Name.Equals("Column", StringComparison.OrdinalIgnoreCase))
- {
- if (breakpointType != null && breakpointType != "Line")
- {
- throw new PSArgumentException(commandParameter.Name);
- }
-
- breakpointType = "Line";
- }
- else if (commandParameter.Name.Equals("Command", StringComparison.OrdinalIgnoreCase))
- {
- if (breakpointType != null)
- {
- throw new PSArgumentException(commandParameter.Name);
- }
-
- breakpointType = "Command";
- }
- else if (commandParameter.Name.Equals("Variable", StringComparison.OrdinalIgnoreCase))
- {
- if (breakpointType != null)
- {
- throw new PSArgumentException(commandParameter.Name);
- }
-
- breakpointType = "Variable";
- }
- }
+ TryGetParameter(command, "RunspaceId", out int? runspaceId);
commands.Clear();
- commands.AddCommand("Set-PSBreakpoint");
- foreach (var commandParameter in command.Parameters)
- {
- var parameterValue = commandParameter.Name.Equals("Action", StringComparison.OrdinalIgnoreCase)
- ? ScriptBlock.Create(commandParameter.Value as string)
- : commandParameter.Value;
- commands.AddParameter(commandParameter.Name, parameterValue);
+ // Any collection comes through remoting as an ArrayList of Objects so we convert each object
+ // into a breakpoint and add it to the list.
+ var bps = new List();
+ if (breakpoints != null)
+ {
+ foreach (object obj in breakpoints)
+ {
+ if (!LanguagePrimitives.TryConvertTo(obj, out Breakpoint bp))
+ {
+ throw new PSArgumentException(DebuggerStrings.BreakpointListContainedANonBreakpoint);
+ }
+
+ bps.Add(bp);
+ }
}
+ else
+ {
+ bps.Add(breakpoint);
+ }
+
+ serverRemoteDebugger.SetBreakpoints(bps, runspaceId);
+
+ foreach (var bp in bps)
+ {
+ preProcessOutput.Add(bp);
+ }
+
+ result = PreProcessCommandResult.BreakpointManagement;
}
else if (commandText.Equals(RemoteDebuggingCommands.RemoveBreakpoint, StringComparison.OrdinalIgnoreCase))
{
// __Remove-PSBreakpoint private virtual command.
// Input parameters:
// -Id
+ // [-RunspaceId ]
// Returns bool.
+ int breakpointId = GetParameter(command, "Id");
+ TryGetParameter(command, "RunspaceId", out int? runspaceId);
- int breakpointId = CheckBreakpointIdParameter(command);
+ Breakpoint breakpoint = serverRemoteDebugger.GetBreakpoint(breakpointId, runspaceId);
+ preProcessOutput.Add(
+ breakpoint == null
+ ? false
+ : serverRemoteDebugger.RemoveBreakpoint(breakpoint, runspaceId));
- string script = $"$bp = $host.Runspace.Debugger.GetBreakpoint({breakpointId}); $bp -ne $null -and $host.Runspace.Debugger.RemoveBreakpoint($bp)";
-
- ReplaceVirtualCommandWithScript(commands, script);
+ result = PreProcessCommandResult.BreakpointManagement;
}
else if (commandText.Equals(RemoteDebuggingCommands.EnableBreakpoint, StringComparison.OrdinalIgnoreCase))
{
// __Enable-PSBreakpoint private virtual command.
// Input parameters:
// -Id
- // Returns Breakpoint.
+ // [-RunspaceId ]
+ // Returns Breakpoint object.
+ int breakpointId = GetParameter(command, "Id");
+ TryGetParameter(command, "RunspaceId", out int? runspaceId);
- int breakpointId = CheckBreakpointIdParameter(command);
-
- string script = $"$bp = $host.Runspace.Debugger.GetBreakpoint({breakpointId}); if ($bp -ne $null) {{$host.Runspace.Debugger.EnableBreakpoint($bp)}}";
-
- ReplaceVirtualCommandWithScript(commands, script);
+ Breakpoint bp = serverRemoteDebugger.GetBreakpoint(breakpointId, runspaceId);
+ if (bp != null)
+ {
+ preProcessOutput.Add(serverRemoteDebugger.EnableBreakpoint(bp, runspaceId));
+ }
+
+ result = PreProcessCommandResult.BreakpointManagement;
}
else if (commandText.Equals(RemoteDebuggingCommands.DisableBreakpoint, StringComparison.OrdinalIgnoreCase))
{
// __Disable-PSBreakpoint private virtual command.
// Input parameters:
// -Id
- // Returns Breakpoint.
+ // [-RunspaceId ]
+ // Returns Breakpoint object.
+ int breakpointId = GetParameter(command, "Id");
+ TryGetParameter(command, "RunspaceId", out int? runspaceId);
- int breakpointId = CheckBreakpointIdParameter(command);
-
- string script = $"$bp = $host.Runspace.Debugger.GetBreakpoint({breakpointId}); if ($bp -ne $null) {{$host.Runspace.Debugger.DisableBreakpoint($bp)}}";
-
- ReplaceVirtualCommandWithScript(commands, script);
+ Breakpoint bp = serverRemoteDebugger.GetBreakpoint(breakpointId, runspaceId);
+ if (bp != null)
+ {
+ preProcessOutput.Add(serverRemoteDebugger.DisableBreakpoint(bp, runspaceId));
+ }
+
+ result = PreProcessCommandResult.BreakpointManagement;
}
return result;
@@ -1527,22 +1553,39 @@ namespace System.Management.Automation
.AddParameter("NoNewScope", true);
}
- private static int CheckBreakpointIdParameter(Command command)
+ private static T GetParameter(Command command, string parameterName)
{
- if (command.Parameters == null ||
- command.Parameters.Count == 0 ||
- !command.Parameters[0].Name.Equals("Id", StringComparison.OrdinalIgnoreCase))
+ if (command.Parameters?.Count == 0)
{
- throw new PSArgumentException("Id");
+ throw new PSArgumentException(parameterName);
}
- int? breakpointId = command.Parameters[0].Value as int?;
- if (breakpointId == null)
+ foreach (CommandParameter param in command.Parameters)
{
- throw new PSArgumentException("Id");
+ if (string.Equals(param.Name, parameterName, StringComparison.OrdinalIgnoreCase))
+ {
+ return LanguagePrimitives.ConvertTo(param.Value);
+ }
}
- return breakpointId.Value;
+ throw new PSArgumentException(parameterName);
+ }
+
+ private static bool TryGetParameter(Command command, string parameterName, out T value)
+ {
+ try
+ {
+ value = GetParameter(command, parameterName);
+ return true;
+ }
+ catch (Exception ex) when(
+ ex is PSArgumentException ||
+ ex is InvalidCastException ||
+ ex is PSInvalidCastException)
+ {
+ value = default(T);
+ return false;
+ }
}
#endregion
@@ -1846,32 +1889,88 @@ namespace System.Management.Automation
/// Adds the provided set of breakpoints to the debugger.
///
/// List of breakpoints.
- public override void SetBreakpoints(IEnumerable breakpoints) =>
- _wrappedDebugger.Value.SetBreakpoints(breakpoints);
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ public override void SetBreakpoints(IEnumerable breakpoints, int? runspaceId = null) =>
+ _wrappedDebugger.Value.SetBreakpoints(breakpoints, runspaceId);
- public override Breakpoint GetBreakpoint(int id) =>
- _wrappedDebugger.Value.GetBreakpoint(id);
+ ///
+ /// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
+ ///
+ /// Id of the breakpoint you want.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The breakpoint with the specified id.
+ public override Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
+ _wrappedDebugger.Value.GetBreakpoint(id, runspaceId);
- public override List GetBreakpoints() =>
- _wrappedDebugger.Value.GetBreakpoints();
+ ///
+ /// Returns breakpoints on a runspace.
+ ///
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// A list of breakpoints in a runspace.
+ public override List GetBreakpoints(int? runspaceId = null) =>
+ _wrappedDebugger.Value.GetBreakpoints(runspaceId);
- public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
- _wrappedDebugger.Value.SetCommandBreakpoint(command, action, path);
+ ///
+ /// Sets a command breakpoint in the debugger.
+ ///
+ /// The name of the command that will trigger the breakpoint. This value is required and may not be null.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The command breakpoint that was set.
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
+ _wrappedDebugger.Value.SetCommandBreakpoint(command, action, path, runspaceId);
- public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
- _wrappedDebugger.Value.SetLineBreakpoint(path, line, column, action);
+ ///
+ /// Sets a line breakpoint in the debugger.
+ ///
+ /// The path to the script file where the breakpoint may be hit. This value is required and may not be null.
+ /// The line in the script file where the breakpoint may be hit. This value is required and must be greater than or equal to 1.
+ /// The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The line breakpoint that was set.
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null, int? runspaceId = null) =>
+ _wrappedDebugger.Value.SetLineBreakpoint(path, line, column, action, runspaceId);
- public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
- _wrappedDebugger.Value.SetVariableBreakpoint(variableName, accessMode, action, path);
+ ///
+ /// Sets a variable breakpoint in the debugger.
+ ///
+ /// The name of the variable that will trigger the breakpoint. This value is required and may not be null.
+ /// The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.
+ /// The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.
+ /// The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the variable is accessed using the specified access mode.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The variable breakpoint that was set.
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null, int? runspaceId = null) =>
+ _wrappedDebugger.Value.SetVariableBreakpoint(variableName, accessMode, action, path, runspaceId);
- public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.Value.RemoveBreakpoint(breakpoint);
+ ///
+ /// Removes a breakpoint from the debugger.
+ ///
+ /// The breakpoint to remove from the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// True if the breakpoint was removed from the debugger; false otherwise.
+ public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.Value.RemoveBreakpoint(breakpoint, runspaceId);
- public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.Value.EnableBreakpoint(breakpoint);
+ ///
+ /// Enables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.Value.EnableBreakpoint(breakpoint, runspaceId);
- public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
- _wrappedDebugger.Value.DisableBreakpoint(breakpoint);
+ ///
+ /// Disables a breakpoint in the debugger.
+ ///
+ /// The breakpoint to enable in the debugger. This value is required and may not be null.
+ /// The runspace id of the runspace you want to interact with. Defaults to null (current runspace).
+ /// The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
+ _wrappedDebugger.Value.DisableBreakpoint(breakpoint, runspaceId);
///
/// Exits debugger mode with the provided resume action.
diff --git a/src/System.Management.Automation/resources/DebuggerStrings.resx b/src/System.Management.Automation/resources/DebuggerStrings.resx
index 79b0cf42a4..466ee067ce 100644
--- a/src/System.Management.Automation/resources/DebuggerStrings.resx
+++ b/src/System.Management.Automation/resources/DebuggerStrings.resx
@@ -249,4 +249,16 @@ The current session does not support debugging; operation will continue.
The debugger detach command is not applicable. The detach command only applies when debugging jobs and runspaces with the Debug-Job or Debug-Runspace cmdlets.
+
+ Invalid runspace id: {0}
+
+
+ Unable to get Runspace.
+
+
+ Breakpoint or BreakpointList must be specified.
+
+
+ The BreakpointList contained an item that was not a breakpoint.
+
diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
index 4cfd7203f6..3f9e9ad118 100644
--- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
+++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
@@ -1693,4 +1693,7 @@ All WinRM sessions connected to PowerShell session configurations, such as Micro
Enter-PSHostProcess cmdlet is disabled because an application control policy such as 'AppLocker' or 'Windows Defender Application Control' is in enforcement.
+
+ Remote debugger exception: {0}, error message: {1}
+
diff --git a/test/powershell/SDK/Breakpoint.Tests.ps1 b/test/powershell/SDK/Breakpoint.Tests.ps1
index b81148d8fa..7c3b886866 100644
--- a/test/powershell/SDK/Breakpoint.Tests.ps1
+++ b/test/powershell/SDK/Breakpoint.Tests.ps1
@@ -34,6 +34,12 @@ Describe 'Breakpoint SDK Unit Tests' -Tags 'CI' {
Context 'Managing breakpoints in the host runspace via the SDK' {
+ AfterAll {
+ foreach ($bp in $host.Runspace.Debugger.GetBreakpoints()) {
+ $host.Runspace.Debugger.RemoveBreakpoint($bp) | Should -BeTrue
+ }
+ }
+
It 'Can set command breakpoints' {
$host.Runspace.Debugger.SetCommandBreakpoint('Test-ThisCommandDoesNotExist') | Should -BeOfType [System.Management.Automation.CommandBreakpoint]
}
@@ -52,14 +58,14 @@ Describe 'Breakpoint SDK Unit Tests' -Tags 'CI' {
It 'Can disable breakpoints' {
foreach ($bp in $host.Runspace.Debugger.GetBreakpoints()) {
- $bp = $host.Runspace.Debugger.DisableBreakpoint($bp)
+ $bp = $host.Runspace.Debugger.DisableBreakpoint($bp)
$bp.Enabled | Should -BeFalse
}
}
It 'Can enable breakpoints' {
foreach ($bp in $host.Runspace.Debugger.GetBreakpoints()) {
- $bp = $host.Runspace.Debugger.EnableBreakpoint($bp)
+ $bp = $host.Runspace.Debugger.EnableBreakpoint($bp)
$bp.Enabled | Should -BeTrue
}
}
@@ -73,10 +79,27 @@ Describe 'Breakpoint SDK Unit Tests' -Tags 'CI' {
It 'Returns an empty collection when there are no breakpoints' {
$host.Runspace.Debugger.GetBreakpoints() | Should -HaveCount 0
}
+
+ It 'Can set multiple breakpoints' {
+ $breakpoints = [System.Collections.Generic.List[System.Management.Automation.Breakpoint]] @(
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 1)
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 2)
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 3)
+ )
+
+ $host.Runspace.Debugger.SetBreakpoints($breakpoints)
+ $host.Runspace.Debugger.GetBreakpoints() | Should -HaveCount 3
+ }
}
Context 'Managing breakpoints in a remote runspace via the SDK' {
+ AfterAll {
+ foreach ($bp in $jobRunspace.Debugger.GetBreakpoints()) {
+ $jobRunspace.Debugger.RemoveBreakpoint($bp) | Should -BeTrue
+ }
+ }
+
It 'Can set command breakpoints' {
$jobRunspace.Debugger.SetCommandBreakpoint('Write-Verbose', { break }) | Should -BeOfType [System.Management.Automation.CommandBreakpoint]
}
@@ -96,14 +119,14 @@ Describe 'Breakpoint SDK Unit Tests' -Tags 'CI' {
It 'Can disable breakpoints' {
foreach ($bp in $jobRunspace.Debugger.GetBreakpoints()) {
- $bp = $jobRunspace.Debugger.DisableBreakpoint($bp)
+ $bp = $jobRunspace.Debugger.DisableBreakpoint($bp)
$bp.Enabled | Should -BeFalse
}
}
It 'Can enable breakpoints' {
foreach ($bp in $jobRunspace.Debugger.GetBreakpoints()) {
- $bp = $jobRunspace.Debugger.EnableBreakpoint($bp)
+ $bp = $jobRunspace.Debugger.EnableBreakpoint($bp)
$bp.Enabled | Should -BeTrue
}
}
@@ -125,13 +148,23 @@ Describe 'Breakpoint SDK Unit Tests' -Tags 'CI' {
It 'Returns an empty collection when there are no breakpoints' {
$jobRunspace.Debugger.GetBreakpoints() | Should -HaveCount 0
}
+
+ It 'Can set multiple breakpoints' {
+ $breakpoints = [System.Collections.Generic.List[System.Management.Automation.Breakpoint]] @(
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 1)
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 2)
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 3)
+ )
+
+ $jobRunspace.Debugger.SetBreakpoints($breakpoints)
+ $jobRunspace.Debugger.GetBreakpoints() | Should -HaveCount 3
+ }
}
- Context 'Handling empty collections and errors while managing breakpoints in the host runspace via the SDK' {
+ Context 'Handling empty collections and errors while managing breakpoints in the host runspace via the SDK' {
BeforeAll {
- $bp = $host.Runspace.Debugger.SetCommandBreakpoint('Test-ThisCommandDoesNotExist')
- $host.Runspace.Debugger.RemoveBreakpoint($bp) > $null
+ $bp = [System.Management.Automation.CommandBreakpoint]::new($TestDrive, $null, 'Test-ThisCommandDoesNotExist')
}
It 'Returns false when trying to disable a breakpoint that does not exist' {
@@ -166,4 +199,71 @@ Describe 'Breakpoint SDK Unit Tests' -Tags 'CI' {
$jobRunspace.Debugger.RemoveBreakpoint($bp) | Should -BeFalse
}
}
+
+ Context 'Manage breakpoints in another runspace' {
+ BeforeAll {
+ $runspace = [runspacefactory]::CreateRunspace()
+ $runspace.Open()
+ }
+
+ AfterAll {
+ $runspace.Close()
+ $runspace.Dispose()
+ }
+
+ It 'Can set command breakpoints' {
+ $host.Runspace.Debugger.SetCommandBreakpoint('Test-ThisCommandDoesNotExist', $null, $null, $runspace.Id) | Should -BeOfType [System.Management.Automation.CommandBreakpoint]
+ }
+
+ It 'Can set variable breakpoints' {
+ $host.Runspace.Debugger.SetVariableBreakpoint('DebugPreference', 'ReadWrite', { continue }, $null, $runspace.Id) | Should -BeOfType [System.Management.Automation.VariableBreakpoint]
+ }
+
+ It 'Can set line breakpoints' {
+ $host.Runspace.Debugger.SetLineBreakpoint($PSCommandPath, 1, 1, { continue }, $runspace.Id) | Should -BeOfType [System.Management.Automation.LineBreakpoint]
+ }
+
+ It 'Can get breakpoints' {
+ $host.Runspace.Debugger.GetBreakpoints($runspace.Id) | Should -HaveCount 3
+ }
+
+ It 'Can disable breakpoints' {
+ foreach ($bp in $host.Runspace.Debugger.GetBreakpoints($runspace.Id)) {
+ $bp = $host.Runspace.Debugger.DisableBreakpoint($bp, $runspace.Id)
+ $bp.Enabled | Should -BeFalse
+ }
+ }
+
+ It 'Can enable breakpoints' {
+ foreach ($bp in $host.Runspace.Debugger.GetBreakpoints($runspace.Id)) {
+ $bp = $host.Runspace.Debugger.EnableBreakpoint($bp, $runspace.Id)
+ $bp.Enabled | Should -BeTrue
+ }
+ }
+
+ It 'Doesn''t manipulate any breakpoints in the default runspace' {
+ $host.Runspace.Debugger.GetBreakpoints() | Should -BeNullOrEmpty
+ }
+
+ It 'Can remove breakpoints' {
+ foreach ($bp in $host.Runspace.Debugger.GetBreakpoints($runspace.Id)) {
+ $host.Runspace.Debugger.RemoveBreakpoint($bp, $runspace.Id) | Should -BeTrue
+ }
+ }
+
+ It 'Returns an empty collection when there are no breakpoints' {
+ $host.Runspace.Debugger.GetBreakpoints($runspace.Id) | Should -HaveCount 0
+ }
+
+ It 'Can set multiple breakpoints' {
+ $breakpoints = [System.Collections.Generic.List[System.Management.Automation.Breakpoint]] @(
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 1)
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 2)
+ [System.Management.Automation.LineBreakpoint]::new("/Path/to/foo.ps1", 3)
+ )
+
+ $host.Runspace.Debugger.SetBreakpoints($breakpoints, $runspace.Id)
+ $host.Runspace.Debugger.GetBreakpoints($runspace.Id) | Should -HaveCount 3
+ }
+ }
}