Improvements in breakpoint APIs for remote scenarios (#11312)

This commit is contained in:
Tyler James Leonhardt
2019-12-12 17:23:12 -08:00
committed by Aditya Patwardhan
parent bcc5acb0bd
commit ca202da643
9 changed files with 902 additions and 292 deletions
@@ -622,20 +622,23 @@ namespace System.Management.Automation
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
/// </summary>
/// <param name="id">Id of the breakpoint you want.</param>
public virtual Breakpoint GetBreakpoint(int id) =>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public virtual Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
throw new PSNotImplementedException();
/// <summary>
/// Adds the provided set of breakpoints to the debugger.
/// </summary>
/// <param name="breakpoints">Breakpoints.</param>
public virtual void SetBreakpoints(IEnumerable<Breakpoint> breakpoints) =>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public virtual void SetBreakpoints(IEnumerable<Breakpoint> breakpoints, int? runspaceId = null) =>
throw new PSNotImplementedException();
/// <summary>
/// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
/// </summary>
public virtual List<Breakpoint> GetBreakpoints() =>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public virtual List<Breakpoint> GetBreakpoints(int? runspaceId = null) =>
throw new PSNotImplementedException();
/// <summary>
@@ -644,8 +647,9 @@ namespace System.Management.Automation
/// <param name="command">The name of the command that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The command breakpoint that was set.</returns>
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();
/// <summary>
@@ -655,8 +659,9 @@ namespace System.Management.Automation
/// <param name="line">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.</param>
/// <param name="column">The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The line breakpoint that was set.</returns>
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();
/// <summary>
@@ -666,32 +671,36 @@ namespace System.Management.Automation
/// <param name="accessMode">The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">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.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The variable breakpoint that was set.</returns>
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();
/// <summary>
/// Removes a breakpoint from the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to remove from the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>True if the breakpoint was removed from the debugger; false otherwise.</returns>
public virtual bool RemoveBreakpoint(Breakpoint breakpoint) =>
public virtual bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
throw new PSNotImplementedException();
/// <summary>
/// Enables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public virtual Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
public virtual Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
throw new PSNotImplementedException();
/// <summary>
/// Disables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public virtual Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
public virtual Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
throw new PSNotImplementedException();
/// <summary>
@@ -2590,9 +2599,16 @@ namespace System.Management.Automation
/// <summary>
/// Adds the provided set of breakpoints to the debugger.
/// </summary>
/// <param name="breakpoints"></param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints)
/// <param name="breakpoints">The breakpoints to set.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> 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.
/// </summary>
/// <param name="id">Id of the breakpoint you want.</param>
public override Breakpoint GetBreakpoint(int id)
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
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
/// <summary>
/// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
/// </summary>
public override List<Breakpoint> GetBreakpoints()
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public override List<Breakpoint> 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
/// <param name="command">The name of the command that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns></returns>
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
/// <param name="line">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.</param>
/// <param name="column">The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <returns></returns>
public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null)
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>A LineBreakpoint</returns>
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
/// <param name="accessMode">The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">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.</param>
/// <returns></returns>
public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null)
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>A VariableBreakpoint that was set.</returns>
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)
/// <summary>
/// This is the implementation of the Remove-PSBreakpoint cmdlet.
/// </summary>
/// <param name="breakpoint">Id of the breakpoint you want.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
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)
/// <summary>
/// This is the implementation of the Enable-PSBreakpoint cmdlet.
/// </summary>
/// <param name="breakpoint">Id of the breakpoint you want.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
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)
/// <summary>
/// This is the implementation of the Disable-PSBreakpoint cmdlet.
/// </summary>
/// <param name="breakpoint">Id of the breakpoint you want.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
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<Runspace> 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.
/// </summary>
/// <param name="breakpoints">Breakpoints.</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints) =>
_wrappedDebugger.SetBreakpoints(breakpoints);
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints, int? runspaceId = null) =>
_wrappedDebugger.SetBreakpoints(breakpoints, runspaceId);
/// <summary>
/// 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);
/// <summary>
/// Get a breakpoint by id.
/// </summary>
/// <param name="id">Id of the breakpoint you want.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public override Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
_wrappedDebugger.GetBreakpoint(id, runspaceId);
public override List<Breakpoint> GetBreakpoints() =>
_wrappedDebugger.GetBreakpoints();
/// <summary>
/// Returns breakpoints on a runspace.
/// </summary>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>A list of breakpoints in a runspace.</returns>
public override List<Breakpoint> GetBreakpoints(int? runspaceId = null) =>
_wrappedDebugger.GetBreakpoints(runspaceId);
public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
_wrappedDebugger.SetCommandBreakpoint(command, action, path);
/// <summary>
/// Sets a command breakpoint in the debugger.
/// </summary>
/// <param name="command">The name of the command that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The command breakpoint that was set.</returns>
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);
/// <summary>
/// Sets a line breakpoint in the debugger.
/// </summary>
/// <param name="path">The path to the script file where the breakpoint may be hit. This value is required and may not be null.</param>
/// <param name="line">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.</param>
/// <param name="column">The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The line breakpoint that was set.</returns>
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);
/// <summary>
/// Sets a variable breakpoint in the debugger.
/// </summary>
/// <param name="variableName">The name of the variable that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="accessMode">The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">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.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The variable breakpoint that was set.</returns>
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);
/// <summary>
/// Removes a breakpoint from the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to remove from the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>True if the breakpoint was removed from the debugger; false otherwise.</returns>
public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.RemoveBreakpoint(breakpoint, runspaceId);
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
_wrappedDebugger.EnableBreakpoint(breakpoint);
/// <summary>
/// Enables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.EnableBreakpoint(breakpoint, runspaceId);
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
_wrappedDebugger.DisableBreakpoint(breakpoint);
/// <summary>
/// Disables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.DisableBreakpoint(breakpoint, runspaceId);
/// <summary>
/// SetDebuggerAction.
@@ -1091,8 +1091,9 @@ namespace System.Management.Automation.PSTasks
/// Adds the provided set of breakpoints to the debugger.
/// </summary>
/// <param name="breakpoints">List of breakpoints.</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints) =>
_wrappedDebugger.SetBreakpoints(breakpoints);
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints, int? runspaceId = null) =>
_wrappedDebugger.SetBreakpoints(breakpoints, runspaceId);
/// <summary>
/// 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);
/// <summary>
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
/// </summary>
/// <param name="id">Id of the breakpoint you want.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The breakpoint with the specified id.</returns>
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);
/// <summary>
/// Returns breakpoints on a runspace.
/// </summary>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>A list of breakpoints in a runspace.</returns>
public override List<Breakpoint> 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);
/// <summary>
/// Sets a command breakpoint in the debugger.
/// </summary>
/// <param name="command">The name of the command that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The command breakpoint that was set.</returns>
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);
/// <summary>
/// Sets a variable breakpoint in the debugger.
/// </summary>
/// <param name="variableName">The name of the variable that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="accessMode">The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">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.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The variable breakpoint that was set.</returns>
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);
/// <summary>
/// Sets a line breakpoint in the debugger.
/// </summary>
/// <param name="path">The path to the script file where the breakpoint may be hit. This value is required and may not be null.</param>
/// <param name="line">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.</param>
/// <param name="column">The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The line breakpoint that was set.</returns>
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);
/// <summary>
/// Enables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.EnableBreakpoint(breakpoint, runspaceId);
public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
_wrappedDebugger.RemoveBreakpoint(breakpoint);
/// <summary>
/// Disables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.DisableBreakpoint(breakpoint, runspaceId);
/// <summary>
/// Removes a breakpoint from the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to remove from the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>True if the breakpoint was removed from the debugger; false otherwise.</returns>
public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.RemoveBreakpoint(breakpoint, runspaceId);
/// <summary>
/// Stops a running command.
@@ -3913,32 +3913,88 @@ namespace System.Management.Automation
/// Adds the provided set of breakpoints to the debugger.
/// </summary>
/// <param name="breakpoints">Breakpoints to set.</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints) =>
_wrappedDebugger.SetBreakpoints(breakpoints);
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints, int? runspaceId = null) =>
_wrappedDebugger.SetBreakpoints(breakpoints, runspaceId);
public override Breakpoint GetBreakpoint(int id) =>
_wrappedDebugger.GetBreakpoint(id);
/// <summary>
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
/// </summary>
/// <param name="id">Id of the breakpoint you want.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>A a breakpoint with the specified id.</returns>
public override Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
_wrappedDebugger.GetBreakpoint(id, runspaceId);
public override List<Breakpoint> GetBreakpoints() =>
_wrappedDebugger.GetBreakpoints();
/// <summary>
/// Returns breakpoints on a runspace.
/// </summary>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>A list of breakpoints in a runspace.</returns>
public override List<Breakpoint> GetBreakpoints(int? runspaceId = null) =>
_wrappedDebugger.GetBreakpoints(runspaceId);
public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
_wrappedDebugger.SetCommandBreakpoint(command, action, path);
/// <summary>
/// Sets a command breakpoint in the debugger.
/// </summary>
/// <param name="command">The name of the command that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The command breakpoint that was set.</returns>
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);
/// <summary>
/// Sets a line breakpoint in the debugger.
/// </summary>
/// <param name="path">The path to the script file where the breakpoint may be hit. This value is required and may not be null.</param>
/// <param name="line">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.</param>
/// <param name="column">The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The line breakpoint that was set.</returns>
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);
/// <summary>
/// Sets a variable breakpoint in the debugger.
/// </summary>
/// <param name="variableName">The name of the variable that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="accessMode">The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">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.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The variable breakpoint that was set.</returns>
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);
/// <summary>
/// Removes a breakpoint from the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to remove from the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>True if the breakpoint was removed from the debugger; false otherwise.</returns>
public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.RemoveBreakpoint(breakpoint, runspaceId);
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
_wrappedDebugger.EnableBreakpoint(breakpoint);
/// <summary>
/// Enables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.EnableBreakpoint(breakpoint, runspaceId);
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
_wrappedDebugger.DisableBreakpoint(breakpoint);
/// <summary>
/// Disables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.DisableBreakpoint(breakpoint, runspaceId);
/// <summary>
/// Sets the debugger resume action.
@@ -2010,30 +2010,55 @@ namespace System.Management.Automation
/// Adds the provided set of breakpoints to the debugger.
/// </summary>
/// <param name="breakpoints">Breakpoints to set.</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints) =>
_runspace.Debugger?.SetBreakpoints(breakpoints);
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.SetBreakpoint);
var functionParameters = new Dictionary<string, object>
{
{ "BreakpointList", breakpoints },
};
if (runspaceId.HasValue)
{
functionParameters.Add("RunspaceId", runspaceId.Value);
}
InvokeRemoteBreakpointFunction<CommandBreakpoint>(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
}
/// <summary>
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
/// </summary>
/// <param name="id">Id of the breakpoint you want.</param>
public override Breakpoint GetBreakpoint(int id)
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The breakpoint with the specified id.</returns>
public override Breakpoint GetBreakpoint(int id, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.GetBreakpoint);
return InvokeRemoteBreakpointFunction<Breakpoint>(
RemoteDebuggingCommands.GetBreakpoint,
new Dictionary<string, object>
{
{ "Id", id },
});
var functionParameters = new Dictionary<string, object>
{
{ "Id", id },
};
if (runspaceId.HasValue)
{
functionParameters.Add("RunspaceId", runspaceId.Value);
}
return InvokeRemoteBreakpointFunction<Breakpoint>(RemoteDebuggingCommands.GetBreakpoint, functionParameters);
}
/// <summary>
/// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
/// </summary>
public override List<Breakpoint> GetBreakpoints()
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>A list of breakpoints in a runspace.</returns>
public override List<Breakpoint> 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<PSObject> output = ps.Invoke<PSObject>();
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)
/// <summary>
/// Sets a command breakpoint in the debugger.
/// </summary>
/// <param name="command">The name of the command that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The command breakpoint that was set.</returns>
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<string, object>
{
{ "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<CommandBreakpoint>(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
}
public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null)
/// <summary>
/// Sets a line breakpoint in the debugger.
/// </summary>
/// <param name="path">The path to the script file where the breakpoint may be hit. This value is required and may not be null.</param>
/// <param name="line">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.</param>
/// <param name="column">The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The line breakpoint that was set.</returns>
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<string, object>
{
{ "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<LineBreakpoint>(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
}
public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null)
/// <summary>
/// Sets a variable breakpoint in the debugger.
/// </summary>
/// <param name="variableName">The name of the variable that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="accessMode">The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">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.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The variable breakpoint that was set.</returns>
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<string, object>
{
{ "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<VariableBreakpoint>(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
}
public override bool RemoveBreakpoint(Breakpoint breakpoint)
/// <summary>
/// Removes a breakpoint from the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to remove from the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>True if the breakpoint was removed from the debugger; false otherwise.</returns>
public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.RemoveBreakpoint);
return InvokeRemoteBreakpointFunction<bool>(
RemoteDebuggingCommands.RemoveBreakpoint,
new Dictionary<string, object>
{
{ "Id", breakpoint.Id },
});
if (breakpoint == null)
{
return false;
}
var functionParameters = new Dictionary<string, object>
{
{ "Id", breakpoint.Id },
};
if (runspaceId.HasValue)
{
functionParameters.Add("RunspaceId", runspaceId.Value);
}
return InvokeRemoteBreakpointFunction<bool>(RemoteDebuggingCommands.RemoveBreakpoint, functionParameters);
}
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint)
/// <summary>
/// Enables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.EnableBreakpoint);
return InvokeRemoteBreakpointFunction<Breakpoint>(
RemoteDebuggingCommands.EnableBreakpoint,
new Dictionary<string, object>
{
{ "Id", breakpoint.Id },
});
if (breakpoint == null)
{
return null;
}
var functionParameters = new Dictionary<string, object>
{
{ "Id", breakpoint.Id },
};
if (runspaceId.HasValue)
{
functionParameters.Add("RunspaceId", runspaceId.Value);
}
return InvokeRemoteBreakpointFunction<Breakpoint>(RemoteDebuggingCommands.EnableBreakpoint, functionParameters);
}
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint)
/// <summary>
/// Disables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null)
{
// This is supported only for PowerShell versions >= 7.0
CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.DisableBreakpoint);
return InvokeRemoteBreakpointFunction<Breakpoint>(
RemoteDebuggingCommands.DisableBreakpoint,
new Dictionary<string, object>
{
{ "Id", breakpoint.Id },
});
if (breakpoint == null)
{
return null;
}
var functionParameters = new Dictionary<string, object>
{
{ "Id", breakpoint.Id },
};
if (runspaceId.HasValue)
{
functionParameters.Add("RunspaceId", runspaceId.Value);
}
return InvokeRemoteBreakpointFunction<Breakpoint>(RemoteDebuggingCommands.DisableBreakpoint, functionParameters);
}
/// <summary>
@@ -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);
@@ -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.
/// </summary>
internal void RunNoOpCommand()
/// <param name="output">The output from preprocessing that we want to send to the client.</param>
internal void RunNoOpCommand(IReadOnlyCollection<object> output)
{
if (LocalPowerShell != null)
{
@@ -300,6 +302,14 @@ namespace System.Management.Automation
new PSInvocationStateInfo(
PSInvocationState.Running, null));
foreach (var item in output)
{
if (item != null)
{
_localPowerShellOutput.Add(PSObject.AsPSObject(item));
}
}
LocalPowerShell.SetStateChanged(
new PSInvocationStateInfo(
PSInvocationState.Completed, null));
@@ -4,6 +4,7 @@
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@@ -747,36 +748,52 @@ namespace System.Management.Automation
{
DebuggerCommandArgument commandArgument;
bool terminateImmediate = false;
var result = PreProcessDebuggerCommand(powershell.Commands, _serverRemoteDebugger.IsActive, _serverRemoteDebugger.IsRemote, out commandArgument);
Collection<object> preProcessOutput = new Collection<object>();
switch (result)
try
{
case PreProcessCommandResult.SetDebuggerAction:
// Run this directly on the debugger and terminate the remote command.
_serverRemoteDebugger.SetDebuggerAction(commandArgument.ResumeAction.Value);
terminateImmediate = true;
break;
var result = PreProcessDebuggerCommand(powershell.Commands, _serverRemoteDebugger, preProcessOutput, out commandArgument);
case PreProcessCommandResult.SetDebugMode:
// Set debug mode directly and terminate remote command.
_serverRemoteDebugger.SetDebugMode(commandArgument.Mode.Value);
terminateImmediate = true;
break;
switch (result)
{
case PreProcessCommandResult.SetDebuggerAction:
// Run this directly on the debugger and terminate the remote command.
_serverRemoteDebugger.SetDebuggerAction(commandArgument.ResumeAction.Value);
terminateImmediate = true;
break;
case PreProcessCommandResult.SetDebuggerStepMode:
// Enable debugger and set to step action, then terminate remote command.
_serverRemoteDebugger.SetDebuggerStepMode(commandArgument.DebuggerStepEnabled.Value);
terminateImmediate = true;
break;
case PreProcessCommandResult.SetDebugMode:
// Set debug mode directly and terminate remote command.
_serverRemoteDebugger.SetDebugMode(commandArgument.Mode.Value);
terminateImmediate = true;
break;
case PreProcessCommandResult.SetPreserveUnhandledBreakpointMode:
_serverRemoteDebugger.UnhandledBreakpointMode = commandArgument.UnhandledBreakpointMode.Value;
terminateImmediate = true;
break;
case PreProcessCommandResult.SetDebuggerStepMode:
// Enable debugger and set to step action, then terminate remote command.
_serverRemoteDebugger.SetDebuggerStepMode(commandArgument.DebuggerStepEnabled.Value);
terminateImmediate = true;
break;
case PreProcessCommandResult.ValidNotProcessed:
terminateImmediate = true;
break;
case PreProcessCommandResult.SetPreserveUnhandledBreakpointMode:
_serverRemoteDebugger.UnhandledBreakpointMode = commandArgument.UnhandledBreakpointMode.Value;
terminateImmediate = true;
break;
case PreProcessCommandResult.ValidNotProcessed:
terminateImmediate = true;
break;
case PreProcessCommandResult.BreakpointManagement:
terminateImmediate = true;
break;
}
}
catch (Exception ex)
{
terminateImmediate = true;
preProcessOutput.Add(
PSObject.AsPSObject(ex));
}
// If we don't want to run or queue a command to run in the server session then
@@ -796,7 +813,7 @@ namespace System.Management.Automation
addToHistory,
null);
noOpDriver.RunNoOpCommand();
noOpDriver.RunNoOpCommand(preProcessOutput);
return;
}
}
@@ -1237,6 +1254,11 @@ namespace System.Management.Automation
/// SetPreserveUnhandledBreakpointMode.
/// </summary>
SetPreserveUnhandledBreakpointMode,
/// <summary>
/// The PreProcessCommandResult used for managing breakpoints.
/// </summary>
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.
/// </summary>
/// <param name="commands">PSCommand.</param>
/// <param name="isDebuggerActive">True if debugger is active.</param>
/// <param name="isDebuggerRemote">True if active debugger is pushed and is a remote debugger.</param>
/// <param name="commands">The PSCommand.</param>
/// <param name="serverRemoteDebugger">The debugger that can be used to invoke debug operations via API.</param>
/// <param name="preProcessOutput">A Collection that can be used to send output to the client.</param>
/// <param name="commandArgument">Command argument.</param>
/// <returns>PreProcessCommandResult type if preprocessing occurred.</returns>
private static PreProcessCommandResult PreProcessDebuggerCommand(
PSCommand commands,
bool isDebuggerActive,
bool isDebuggerRemote,
ServerRemoteDebugger serverRemoteDebugger,
Collection<object> 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 <int>]
// Returns Breakpoint object(s).
string script = null;
if (command.Parameters?.Count > 0)
TryGetParameter<int?>(command, "RunspaceId", out int? runspaceId);
if (TryGetParameter<int>(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] <string[]> [-Line] <int[]> [[-Column] <int>] [-Action <scriptblock>]
// [[-Script] <string[]>] -Command <string[]> [-Action <scriptblock>]
// [[-Script] <string[]>] -Variable <string[]> [-Action <scriptblock>] [-Mode <VariableAccessMode>]
// Returns Breakpoint object.
if (command.Parameters == null || command.Parameters.Count == 0)
// -Breakpoint <Breakpoint> or -BreakpointList <IEnumerable<Breakpoint>>
// [-RunspaceId <int?>]
// Returns Breakpoint object(s).
TryGetParameter<Breakpoint>(command, "Breakpoint", out Breakpoint breakpoint);
TryGetParameter<ArrayList>(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<int?>(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<Breakpoint>();
if (breakpoints != null)
{
foreach (object obj in breakpoints)
{
if (!LanguagePrimitives.TryConvertTo<Breakpoint>(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 <int>
// [-RunspaceId <int?>]
// Returns bool.
int breakpointId = GetParameter<int>(command, "Id");
TryGetParameter<int?>(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 <int>
// Returns Breakpoint.
// [-RunspaceId <int?>]
// Returns Breakpoint object.
int breakpointId = GetParameter<int>(command, "Id");
TryGetParameter<int?>(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 <int>
// Returns Breakpoint.
// [-RunspaceId <int?>]
// Returns Breakpoint object.
int breakpointId = GetParameter<int>(command, "Id");
TryGetParameter<int?>(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<T>(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<T>(param.Value);
}
}
return breakpointId.Value;
throw new PSArgumentException(parameterName);
}
private static bool TryGetParameter<T>(Command command, string parameterName, out T value)
{
try
{
value = GetParameter<T>(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.
/// </summary>
/// <param name="breakpoints">List of breakpoints.</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints) =>
_wrappedDebugger.Value.SetBreakpoints(breakpoints);
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
public override void SetBreakpoints(IEnumerable<Breakpoint> breakpoints, int? runspaceId = null) =>
_wrappedDebugger.Value.SetBreakpoints(breakpoints, runspaceId);
public override Breakpoint GetBreakpoint(int id) =>
_wrappedDebugger.Value.GetBreakpoint(id);
/// <summary>
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
/// </summary>
/// <param name="id">Id of the breakpoint you want.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The breakpoint with the specified id.</returns>
public override Breakpoint GetBreakpoint(int id, int? runspaceId = null) =>
_wrappedDebugger.Value.GetBreakpoint(id, runspaceId);
public override List<Breakpoint> GetBreakpoints() =>
_wrappedDebugger.Value.GetBreakpoints();
/// <summary>
/// Returns breakpoints on a runspace.
/// </summary>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>A list of breakpoints in a runspace.</returns>
public override List<Breakpoint> 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);
/// <summary>
/// Sets a command breakpoint in the debugger.
/// </summary>
/// <param name="command">The name of the command that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">The path to the script file where the breakpoint may be hit. If null, the breakpoint may be hit anywhere the command is invoked.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The command breakpoint that was set.</returns>
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);
/// <summary>
/// Sets a line breakpoint in the debugger.
/// </summary>
/// <param name="path">The path to the script file where the breakpoint may be hit. This value is required and may not be null.</param>
/// <param name="line">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.</param>
/// <param name="column">The column in the script file where the breakpoint may be hit. If 0, the breakpoint will trigger on any statement on the line.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The line breakpoint that was set.</returns>
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);
/// <summary>
/// Sets a variable breakpoint in the debugger.
/// </summary>
/// <param name="variableName">The name of the variable that will trigger the breakpoint. This value is required and may not be null.</param>
/// <param name="accessMode">The variable access mode that will trigger the breakpoint. By default variable breakpoints will trigger only when the variable is updated.</param>
/// <param name="action">The action to take when the breakpoint is hit. If null, PowerShell will break into the debugger when the breakpoint is hit.</param>
/// <param name="path">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.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The variable breakpoint that was set.</returns>
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);
/// <summary>
/// Removes a breakpoint from the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to remove from the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>True if the breakpoint was removed from the debugger; false otherwise.</returns>
public override bool RemoveBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.Value.RemoveBreakpoint(breakpoint, runspaceId);
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
_wrappedDebugger.Value.EnableBreakpoint(breakpoint);
/// <summary>
/// Enables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint EnableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.Value.EnableBreakpoint(breakpoint, runspaceId);
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
_wrappedDebugger.Value.DisableBreakpoint(breakpoint);
/// <summary>
/// Disables a breakpoint in the debugger.
/// </summary>
/// <param name="breakpoint">The breakpoint to enable in the debugger. This value is required and may not be null.</param>
/// <param name="runspaceId">The runspace id of the runspace you want to interact with. Defaults to null (current runspace).</param>
/// <returns>The updated breakpoint if it was found; null if the breakpoint was not found in the debugger.</returns>
public override Breakpoint DisableBreakpoint(Breakpoint breakpoint, int? runspaceId = null) =>
_wrappedDebugger.Value.DisableBreakpoint(breakpoint, runspaceId);
/// <summary>
/// Exits debugger mode with the provided resume action.
@@ -249,4 +249,16 @@ The current session does not support debugging; operation will continue.
<data name="InvalidDetachCommand" xml:space="preserve">
<value>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.</value>
</data>
<data name="InvalidRunspaceId" xml:space="preserve">
<value>Invalid runspace id: {0}</value>
</data>
<data name="UnableToGetRunspace" xml:space="preserve">
<value>Unable to get Runspace.</value>
</data>
<data name="BreakpointOrBreakpointListNotSpecified" xml:space="preserve">
<value>Breakpoint or BreakpointList must be specified.</value>
</data>
<data name="BreakpointListContainedANonBreakpoint" xml:space="preserve">
<value>The BreakpointList contained an item that was not a breakpoint.</value>
</data>
</root>
@@ -1693,4 +1693,7 @@ All WinRM sessions connected to PowerShell session configurations, such as Micro
<data name="EnterPSHostProcessCmdletDisabled" xml:space="preserve">
<value>Enter-PSHostProcess cmdlet is disabled because an application control policy such as 'AppLocker' or 'Windows Defender Application Control' is in enforcement.</value>
</data>
<data name="RemoteDebuggerError" xml:space="preserve">
<value>Remote debugger exception: {0}, error message: {1}</value>
</data>
</root>
+107 -7
View File
@@ -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
}
}
}