diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs
index 02e6fcad67..7b22cbcddd 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/DebugRunspaceCommand.cs
@@ -101,19 +101,11 @@ namespace Microsoft.PowerShell.Commands
}
///
- /// The optional breakpoint objects to use for debugging.
+ /// Gets or sets a flag that tells PowerShell to automatically perform a BreakAll when the debugger is attached to the remote target.
///
- [Experimental("Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints", ExperimentAction.Show)]
- [Parameter(Position = 1,
- ParameterSetName = DebugRunspaceCommand.InstanceIdParameterSet)]
- [Parameter(ParameterSetName = DebugRunspaceCommand.RunspaceParameterSet)]
- [Parameter(ParameterSetName = DebugRunspaceCommand.IdParameterSet)]
- [Parameter(ParameterSetName = DebugRunspaceCommand.NameParameterSet)]
- public Breakpoint[] Breakpoint
- {
- get;
- set;
- }
+ [Experimental("Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace", ExperimentAction.Show)]
+ [Parameter]
+ public SwitchParameter BreakAll { get; set; }
#endregion
@@ -275,7 +267,7 @@ namespace Microsoft.PowerShell.Commands
_debugger.SetDebugMode(DebugModes.LocalScript | DebugModes.RemoteScript);
// Set up host script debugger to debug the runspace.
- _debugger.DebugRunspace(_runspace, disableBreakAll: Breakpoint?.Length > 0);
+ _debugger.DebugRunspace(_runspace, breakAll: BreakAll);
while (_debugging)
{
@@ -532,10 +524,6 @@ namespace Microsoft.PowerShell.Commands
{
SetLocalMode(runspace.Debugger, true);
EnableHostDebugger(runspace, false);
- if (Breakpoint?.Length > 0)
- {
- runspace.Debugger?.SetBreakpoints(Breakpoint);
- }
}
private void RestoreRunspace(Runspace runspace)
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/EnableDisableRunspaceDebugCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/EnableDisableRunspaceDebugCommand.cs
index a9192ae2da..02869619e3 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/EnableDisableRunspaceDebugCommand.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/EnableDisableRunspaceDebugCommand.cs
@@ -350,22 +350,6 @@ namespace Microsoft.PowerShell.Commands
set;
}
- ///
- /// Gets or sets the optional breakpoint objects to use for debugging.
- ///
- [Experimental("Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints", ExperimentAction.Show)]
- [Parameter(Position = 1,
- ParameterSetName = CommonRunspaceCommandBase.RunspaceParameterSet)]
- [Parameter(Position = 1,
- ParameterSetName = CommonRunspaceCommandBase.RunspaceNameParameterSet)]
- [Parameter(Position = 1,
- ParameterSetName = CommonRunspaceCommandBase.RunspaceIdParameterSet)]
- public Breakpoint[] Breakpoint
- {
- get;
- set;
- }
-
#endregion
#region Overrides
@@ -428,12 +412,6 @@ namespace Microsoft.PowerShell.Commands
debugger.SetDebuggerStepMode(false);
}
}
-
- // If any breakpoints were provided, set those in the debugger.
- if (Breakpoint?.Length > 0)
- {
- debugger.SetBreakpoints(Breakpoint);
- }
}
}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-PSBreakpoint.cs
deleted file mode 100644
index b5837cc0da..0000000000
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/New-PSBreakpoint.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.IO;
-using System.Management.Automation;
-using System.Management.Automation.Internal;
-
-namespace Microsoft.PowerShell.Commands
-{
- ///
- /// This class implements New-PSBreakpoint command.
- ///
- [Experimental("Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints", ExperimentAction.Show)]
- [Cmdlet(VerbsCommon.New, "PSBreakpoint", DefaultParameterSetName = LineParameterSetName, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113449")]
- [OutputType(typeof(VariableBreakpoint), typeof(CommandBreakpoint), typeof(LineBreakpoint))]
- public class NewPSBreakpointCommand : PSBreakpointCreationBase
- {
- ///
- /// Create a new breakpoint.
- ///
- protected override void ProcessRecord()
- {
- // If there is a script, resolve its path
- Collection scripts = ResolveScriptPaths();
-
- // If it is a command breakpoint...
- if (ParameterSetName.Equals(CommandParameterSetName, StringComparison.OrdinalIgnoreCase))
- {
- for (int i = 0; i < Command.Length; i++)
- {
- if (scripts.Count > 0)
- {
- foreach (string path in scripts)
- {
- WildcardPattern pattern = WildcardPattern.Get(Command[i], WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
- WriteObject(new CommandBreakpoint(path, pattern, Command[i], Action));
- }
- }
- else
- {
- WildcardPattern pattern = WildcardPattern.Get(Command[i], WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
- WriteObject(new CommandBreakpoint(null, pattern, Command[i], Action));
- }
- }
- }
- else if (ParameterSetName.Equals(VariableParameterSetName, StringComparison.OrdinalIgnoreCase))
- {
- // If it is a variable breakpoint...
- for (int i = 0; i < Variable.Length; i++)
- {
- if (scripts.Count > 0)
- {
- foreach (string path in scripts)
- {
- WriteObject(new VariableBreakpoint(path, Variable[i], Mode, Action));
- }
- }
- else
- {
- WriteObject(new VariableBreakpoint(null, Variable[i], Mode, Action));
- }
- }
- }
- else
- {
- // Else it is the default parameter set (Line breakpoint)...
- Debug.Assert(ParameterSetName.Equals(LineParameterSetName, StringComparison.OrdinalIgnoreCase));
-
- for (int i = 0; i < Line.Length; i++)
- {
- if (Line[i] < 1)
- {
- WriteError(
- new ErrorRecord(
- new ArgumentException(Debugger.LineLessThanOne),
- "NewPSBreakpoint:LineLessThanOne",
- ErrorCategory.InvalidArgument,
- null));
-
- continue;
- }
-
- foreach (string path in scripts)
- {
- if (Column != 0)
- {
- WriteObject(new LineBreakpoint(path, Line[i], Column, Action));
- }
- else
- {
- WriteObject(new LineBreakpoint(path, Line[i], Action));
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Set-PSBreakpoint.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Set-PSBreakpoint.cs
index 23773fd447..30e9ae7142 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Set-PSBreakpoint.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Set-PSBreakpoint.cs
@@ -75,13 +75,13 @@ namespace Microsoft.PowerShell.Commands
foreach (string path in scripts)
{
WriteObject(
- Context.Debugger.NewCommandBreakpoint(path.ToString(), Command[i], Action));
+ Context.Debugger.SetCommandBreakpoint(Command[i], Action, path));
}
}
else
{
WriteObject(
- Context.Debugger.NewCommandBreakpoint(Command[i], Action));
+ Context.Debugger.SetCommandBreakpoint(Command[i], Action));
}
}
}
@@ -97,13 +97,13 @@ namespace Microsoft.PowerShell.Commands
foreach (string path in scripts)
{
WriteObject(
- Context.Debugger.NewVariableBreakpoint(path.ToString(), Variable[i], Mode, Action));
+ Context.Debugger.SetVariableBreakpoint(Variable[i], Mode, Action, path));
}
}
else
{
WriteObject(
- Context.Debugger.NewVariableBreakpoint(Variable[i], Mode, Action));
+ Context.Debugger.SetVariableBreakpoint(Variable[i], Mode, Action));
}
}
}
@@ -130,16 +130,8 @@ namespace Microsoft.PowerShell.Commands
foreach (string path in scripts)
{
- if (Column != 0)
- {
- WriteObject(
- Context.Debugger.NewStatementBreakpoint(path, Line[i], Column, Action));
- }
- else
- {
- WriteObject(
- Context.Debugger.NewLineBreakpoint(path, Line[i], Action));
- }
+ WriteObject(
+ Context.Debugger.SetLineBreakpoint(path, Line[i], Column, Action));
}
}
}
diff --git a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
index 267ddc928d..34e7cc94ca 100644
--- a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
+++ b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
@@ -18,7 +18,7 @@ CmdletsToExport = @(
'Set-MarkdownOption', 'Add-Member', 'Get-Member', 'Compare-Object', 'Group-Object', 'Measure-Object',
'New-Object', 'Select-Object', 'Sort-Object', 'Tee-Object', 'Register-ObjectEvent', 'Write-Output',
'Import-PowerShellDataFile', 'Write-Progress', 'Disable-PSBreakpoint', 'Enable-PSBreakpoint',
- 'Get-PSBreakpoint', 'Remove-PSBreakpoint', 'Set-PSBreakpoint', 'New-PSBreakpoint', 'Get-PSCallStack', 'Export-PSSession',
+ 'Get-PSBreakpoint', 'Remove-PSBreakpoint', 'Set-PSBreakpoint', 'Get-PSCallStack', 'Export-PSSession',
'Import-PSSession', 'Get-Random', 'Invoke-RestMethod', 'Debug-Runspace', 'Get-Runspace',
'Disable-RunspaceDebug', 'Enable-RunspaceDebug', 'Get-RunspaceDebug', 'Start-Sleep', 'Join-String',
'Out-String', 'Select-String', 'ConvertFrom-StringData', 'Format-Table', 'New-TemporaryFile', 'New-TimeSpan',
@@ -35,8 +35,8 @@ PrivateData = @{
PSData = @{
ExperimentalFeatures = @(
@{
- Name = 'Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints'
- Description = "Enables the New-PSBreakpoint cmdlet and the -Breakpoint parameter on Debug-Runspace to set breakpoints in another Runspace upfront."
+ Name = 'Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace'
+ Description = 'Enables -BreakAll parameter on Debug-Runspace and Debug-Job cmdlets to allow users to decide if they want PowerShell to break immediately in the current location when they attach a debugger.'
}
)
}
diff --git a/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
index 6ef4095acf..a020aa17ea 100644
--- a/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
+++ b/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
@@ -17,7 +17,7 @@ CmdletsToExport = @(
'Show-Markdown', 'Get-MarkdownOption', 'Set-MarkdownOption', 'Add-Member', 'Get-Member', 'Compare-Object', 'Group-Object',
'Measure-Object', 'New-Object', 'Select-Object', 'Sort-Object', 'Tee-Object', 'Register-ObjectEvent', 'Write-Output',
'Import-PowerShellDataFile', 'Write-Progress', 'Disable-PSBreakpoint', 'Enable-PSBreakpoint', 'Get-PSBreakpoint',
- 'Remove-PSBreakpoint', 'Set-PSBreakpoint', 'New-PSBreakpoint', 'Get-PSCallStack', 'Export-PSSession', 'Import-PSSession', 'Get-Random',
+ 'Remove-PSBreakpoint', 'Set-PSBreakpoint', 'Get-PSCallStack', 'Export-PSSession', 'Import-PSSession', 'Get-Random',
'Invoke-RestMethod', 'Debug-Runspace', 'Get-Runspace', 'Disable-RunspaceDebug', 'Enable-RunspaceDebug',
'Get-RunspaceDebug', 'ConvertFrom-SddlString', 'Start-Sleep', 'Join-String', 'Out-String', 'Select-String',
'ConvertFrom-StringData', 'Format-Table', 'New-TemporaryFile', 'New-TimeSpan', 'Get-TraceSource', 'Set-TraceSource',
@@ -29,4 +29,14 @@ FunctionsToExport = @()
AliasesToExport = @('fhx')
NestedModules = @("Microsoft.PowerShell.Commands.Utility.dll")
HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855960'
+PrivateData = @{
+ PSData = @{
+ ExperimentalFeatures = @(
+ @{
+ Name = 'Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace'
+ Description = 'Enables -BreakAll parameter on Debug-Runspace and Debug-Job cmdlets to allow users to decide if they want PowerShell to break immediately in the current location when they attach a debugger.'
+ }
+ )
+ }
+}
}
diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs
index 0f61eb0b16..ebf1f76818 100644
--- a/src/System.Management.Automation/engine/InitialSessionState.cs
+++ b/src/System.Management.Automation/engine/InitialSessionState.cs
@@ -4545,7 +4545,6 @@ end {
new SessionStateAliasEntry("mi", "Move-Item", string.Empty, ReadOnly),
new SessionStateAliasEntry("mp", "Move-ItemProperty", string.Empty, ReadOnly),
new SessionStateAliasEntry("nal", "New-Alias", string.Empty, ReadOnly),
- new SessionStateAliasEntry("nbp", "New-PSBreakpoint", string.Empty, ReadOnly),
new SessionStateAliasEntry("ndr", "New-PSDrive", string.Empty, ReadOnly),
new SessionStateAliasEntry("ni", "New-Item", string.Empty, ReadOnly),
new SessionStateAliasEntry("nv", "New-Variable", string.Empty, ReadOnly),
diff --git a/src/System.Management.Automation/engine/PSVersionInfo.cs b/src/System.Management.Automation/engine/PSVersionInfo.cs
index ef58dafb56..7ac1c4b94b 100644
--- a/src/System.Management.Automation/engine/PSVersionInfo.cs
+++ b/src/System.Management.Automation/engine/PSVersionInfo.cs
@@ -61,6 +61,7 @@ namespace System.Management.Automation
private static readonly SemanticVersion s_psV6Version = new SemanticVersion(6, 0, 0, preReleaseLabel: null, buildLabel: null);
private static readonly SemanticVersion s_psV61Version = new SemanticVersion(6, 1, 0, preReleaseLabel: null, buildLabel: null);
private static readonly SemanticVersion s_psV62Version = new SemanticVersion(6, 2, 0, preReleaseLabel: null, buildLabel: null);
+ private static readonly SemanticVersion s_psV7Version = new SemanticVersion(7, 0, 0, preReleaseLabel: null, buildLabel: null);
private static readonly SemanticVersion s_psSemVersion;
private static readonly Version s_psVersion;
@@ -329,6 +330,11 @@ namespace System.Management.Automation
get { return s_psV6Version; }
}
+ internal static SemanticVersion PSV7Version
+ {
+ get { return s_psV7Version; }
+ }
+
internal static SemanticVersion PSCurrentVersion
{
get { return s_psSemVersion; }
diff --git a/src/System.Management.Automation/engine/debugger/Breakpoint.cs b/src/System.Management.Automation/engine/debugger/Breakpoint.cs
index 80fc66430a..30d83e5769 100644
--- a/src/System.Management.Automation/engine/debugger/Breakpoint.cs
+++ b/src/System.Management.Automation/engine/debugger/Breakpoint.cs
@@ -128,9 +128,7 @@ namespace System.Management.Automation
return BreakpointAction.Continue;
}
- internal virtual void RemoveSelf(ScriptDebugger debugger)
- {
- }
+ internal virtual bool RemoveSelf(ScriptDebugger debugger) => false;
#endregion methods
@@ -208,10 +206,8 @@ namespace System.Management.Automation
: StringUtil.Format(DebuggerStrings.CommandBreakpointString, Command);
}
- internal override void RemoveSelf(ScriptDebugger debugger)
- {
+ internal override bool RemoveSelf(ScriptDebugger debugger) =>
debugger.RemoveCommandBreakpoint(this);
- }
private bool CommandInfoMatches(CommandInfo commandInfo)
{
@@ -350,10 +346,8 @@ namespace System.Management.Automation
return false;
}
- internal override void RemoveSelf(ScriptDebugger debugger)
- {
+ internal override bool RemoveSelf(ScriptDebugger debugger) =>
debugger.RemoveVariableBreakpoint(this);
- }
}
///
@@ -589,7 +583,7 @@ namespace System.Management.Automation
this.BreakpointBitArray.Set(SequencePointIndex, true);
}
- internal override void RemoveSelf(ScriptDebugger debugger)
+ internal override bool RemoveSelf(ScriptDebugger debugger)
{
if (this.SequencePoints != null)
{
@@ -612,7 +606,7 @@ namespace System.Management.Automation
}
}
- debugger.RemoveLineBreakpoint(this);
+ return debugger.RemoveLineBreakpoint(this);
}
}
}
diff --git a/src/System.Management.Automation/engine/debugger/debugger.cs b/src/System.Management.Automation/engine/debugger/debugger.cs
index 60be22a00d..a14b2b59f4 100644
--- a/src/System.Management.Automation/engine/debugger/debugger.cs
+++ b/src/System.Management.Automation/engine/debugger/debugger.cs
@@ -618,31 +618,74 @@ namespace System.Management.Automation
return new Collection();
}
- ///
- /// Adds the provided set of breakpoints to the debugger.
- ///
- /// Breakpoints.
- public virtual void SetBreakpoints(IEnumerable breakpoints)
- {
- throw new PSNotImplementedException();
- }
-
///
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
///
/// Id of the breakpoint you want.
- public virtual Breakpoint GetBreakpoint(int id)
- {
+ public virtual Breakpoint GetBreakpoint(int id) =>
throw new PSNotImplementedException();
- }
///
/// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
///
- public virtual List GetBreakpoints()
- {
+ public virtual List GetBreakpoints() =>
+ throw new PSNotImplementedException();
+
+ ///
+ /// 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 command breakpoint that was set.
+ public virtual CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
+ throw new PSNotImplementedException();
+
+ ///
+ /// 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 line breakpoint that was set.
+ public virtual LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
+ throw new PSNotImplementedException();
+
+ ///
+ /// 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 variable breakpoint that was set.
+ public virtual VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = 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.
+ /// True if the breakpoint was removed from the debugger; false otherwise.
+ public virtual bool RemoveBreakpoint(Breakpoint breakpoint) =>
+ 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 updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public virtual Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
+ 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 updated breakpoint if it was found; null if the breakpoint was not found in the debugger.
+ public virtual Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
throw new PSNotImplementedException();
- }
///
/// Resets the command processor source information so that it is
@@ -704,13 +747,15 @@ namespace System.Management.Automation
/// Sets up debugger to debug provided job or its child jobs.
///
///
- /// Job object that is either a debuggable job or a container
- /// of debuggable child jobs.
+ /// Job object that is either a debuggable job or a container of
+ /// debuggable child jobs.
///
- internal virtual void DebugJob(Job job)
- {
+ ///
+ /// If true, the debugger automatically invokes a break all when it
+ /// attaches to the job.
+ ///
+ internal virtual void DebugJob(Job job, bool breakAll) =>
throw new PSNotImplementedException();
- }
///
/// Removes job from debugger job list and pops the its
@@ -763,21 +808,15 @@ namespace System.Management.Automation
///
/// Sets up debugger to debug provided Runspace in a nested debug session.
///
- /// Runspace to debug.
- internal virtual void DebugRunspace(Runspace runspace)
- {
+ ///
+ /// The runspace to debug.
+ ///
+ ///
+ /// If true, the debugger automatically invokes a break all when it
+ /// attaches to the runspace.
+ ///
+ internal virtual void DebugRunspace(Runspace runspace, bool breakAll) =>
throw new PSNotImplementedException();
- }
-
- ///
- /// Sets up debugger to debug provided Runspace in a nested debug session.
- ///
- /// Runspace to debug.
- ///
- internal virtual void DebugRunspace(Runspace runspace, bool disableBreakAll)
- {
- throw new PSNotImplementedException();
- }
///
/// Removes the provided Runspace from the nested "active" debugger state.
@@ -1122,7 +1161,7 @@ namespace System.Management.Automation
#endregion Call stack management
- #region adding breakpoints
+ #region setting breakpoints
internal void AddBreakpointCommon(Breakpoint breakpoint)
{
@@ -1135,30 +1174,14 @@ namespace System.Management.Automation
OnBreakpointUpdated(new BreakpointUpdatedEventArgs(breakpoint, BreakpointUpdateType.Set, _idToBreakpoint.Count));
}
- private Breakpoint AddCommandBreakpoint(CommandBreakpoint breakpoint)
+ private CommandBreakpoint AddCommandBreakpoint(CommandBreakpoint breakpoint)
{
AddBreakpointCommon(breakpoint);
_commandBreakpoints[breakpoint.Id] = breakpoint;
return breakpoint;
}
- internal Breakpoint NewCommandBreakpoint(string path, string command, ScriptBlock action)
- {
- WildcardPattern pattern = WildcardPattern.Get(command, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
-
- CheckForBreakpointSupport();
- return AddCommandBreakpoint(new CommandBreakpoint(path, pattern, command, action));
- }
-
- internal Breakpoint NewCommandBreakpoint(string command, ScriptBlock action)
- {
- WildcardPattern pattern = WildcardPattern.Get(command, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
-
- CheckForBreakpointSupport();
- return AddCommandBreakpoint(new CommandBreakpoint(null, pattern, command, action));
- }
-
- private Breakpoint AddLineBreakpoint(LineBreakpoint breakpoint)
+ private LineBreakpoint AddLineBreakpoint(LineBreakpoint breakpoint)
{
AddBreakpointCommon(breakpoint);
_pendingBreakpoints[breakpoint.Id] = breakpoint;
@@ -1188,22 +1211,6 @@ namespace System.Management.Automation
}
}
- internal Breakpoint NewLineBreakpoint(string path, int line, ScriptBlock action)
- {
- Diagnostics.Assert(path != null, "caller to verify path is not null");
-
- CheckForBreakpointSupport();
- return AddLineBreakpoint(new LineBreakpoint(path, line, action));
- }
-
- internal Breakpoint NewStatementBreakpoint(string path, int line, int column, ScriptBlock action)
- {
- Diagnostics.Assert(path != null, "caller to verify path is not null");
-
- CheckForBreakpointSupport();
- return AddLineBreakpoint(new LineBreakpoint(path, line, column, action));
- }
-
internal VariableBreakpoint AddVariableBreakpoint(VariableBreakpoint breakpoint)
{
AddBreakpointCommon(breakpoint);
@@ -1218,16 +1225,30 @@ namespace System.Management.Automation
return breakpoint;
}
- internal Breakpoint NewVariableBreakpoint(string path, string variableName, VariableAccessMode accessMode, ScriptBlock action)
+ private void UpdateBreakpoints(FunctionContext functionContext)
{
- CheckForBreakpointSupport();
- return AddVariableBreakpoint(new VariableBreakpoint(path, variableName, accessMode, action));
- }
+ if (functionContext._breakPoints == null)
+ {
+ // This should be rare - setting a breakpoint inside a script, but debugger hadn't started.
+ SetupBreakpoints(functionContext);
+ }
+ else
+ {
+ // Check pending breakpoints to see if any apply to this script.
+ if (string.IsNullOrEmpty(functionContext._file))
+ {
+ return;
+ }
- internal Breakpoint NewVariableBreakpoint(string variableName, VariableAccessMode accessMode, ScriptBlock action)
- {
- CheckForBreakpointSupport();
- return AddVariableBreakpoint(new VariableBreakpoint(null, variableName, accessMode, action));
+ foreach ((int breakpointId, LineBreakpoint item) in _pendingBreakpoints)
+ {
+ if (item.IsScriptBreakpoint && item.Script.Equals(functionContext._file, StringComparison.OrdinalIgnoreCase))
+ {
+ SetPendingBreakpoints(functionContext);
+ break;
+ }
+ }
+ }
}
///
@@ -1239,44 +1260,27 @@ namespace System.Management.Automation
RaiseBreakpointUpdatedEvent(e);
}
- #endregion adding breakpoints
+ #endregion setting breakpoints
#region removing breakpoints
- // This is the implementation of the Remove-PSBreakpoint cmdlet.
- internal void RemoveBreakpoint(Breakpoint breakpoint)
- {
- _idToBreakpoint.Remove(breakpoint.Id, out _);
-
- breakpoint.RemoveSelf(this);
-
- if (CanDisableDebugger)
- {
- SetInternalDebugMode(InternalDebugMode.Disabled);
- }
-
- OnBreakpointUpdated(new BreakpointUpdatedEventArgs(breakpoint, BreakpointUpdateType.Removed, _idToBreakpoint.Count));
- }
-
- internal void RemoveVariableBreakpoint(VariableBreakpoint breakpoint)
- {
+ internal bool RemoveVariableBreakpoint(VariableBreakpoint breakpoint) =>
_variableBreakpoints[breakpoint.Variable].Remove(breakpoint.Id, out _);
- }
- internal void RemoveCommandBreakpoint(CommandBreakpoint breakpoint)
- {
+ internal bool RemoveCommandBreakpoint(CommandBreakpoint breakpoint) =>
_commandBreakpoints.Remove(breakpoint.Id, out _);
- }
- internal void RemoveLineBreakpoint(LineBreakpoint breakpoint)
+ internal bool RemoveLineBreakpoint(LineBreakpoint breakpoint)
{
- _pendingBreakpoints.Remove(breakpoint.Id, out _);
+ bool removed = _pendingBreakpoints.Remove(breakpoint.Id, out _);
Tuple> value;
if (_boundBreakpoints.TryGetValue(breakpoint.Script, out value))
{
- value.Item2.Remove(breakpoint.Id, out _);
+ removed = value.Item2.Remove(breakpoint.Id, out _);
}
+
+ return removed;
}
#endregion removing breakpoints
@@ -1386,24 +1390,6 @@ namespace System.Management.Automation
OnDebuggerStop(invocationInfo, breakpoints.ToList());
}
- ///
- /// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
- ///
- /// Id of the breakpoint you want.
- public override Breakpoint GetBreakpoint(int id)
- {
- _idToBreakpoint.TryGetValue(id, out Breakpoint breakpoint);
- return breakpoint;
- }
-
- ///
- /// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
- ///
- public override List GetBreakpoints()
- {
- return (from bp in _idToBreakpoint.Values orderby bp.Id select bp).ToList();
- }
-
// Return the line breakpoints bound in a specific script block (used when a sequence point
// is hit, to find which breakpoints are set on that sequence point.)
internal List GetBoundBreakpoints(IScriptExtent[] sequencePoints)
@@ -1458,30 +1444,6 @@ namespace System.Management.Automation
return breaks;
}
- #endregion triggering breakpoints
-
- #region enabling/disabling breakpoints
-
- ///
- /// Implementation of Enable-PSBreakpoint cmdlet.
- ///
- internal void EnableBreakpoint(Breakpoint bp)
- {
- bp.SetEnabled(true);
- OnBreakpointUpdated(new BreakpointUpdatedEventArgs(bp, BreakpointUpdateType.Enabled, _idToBreakpoint.Count));
- }
-
- ///
- /// Implementation of Disable-PSBreakpoint cmdlet.
- ///
- internal void DisableBreakpoint(Breakpoint bp)
- {
- bp.SetEnabled(false);
- OnBreakpointUpdated(new BreakpointUpdatedEventArgs(bp, BreakpointUpdateType.Disabled, _idToBreakpoint.Count));
- }
-
- #endregion enabling/disabling breakpoints
-
internal void OnSequencePointHit(FunctionContext functionContext)
{
if (_context.ShouldTraceStatement && !_callStack.Last().IsFrameHidden && !functionContext._debuggerStepThrough)
@@ -1533,34 +1495,7 @@ namespace System.Management.Automation
}
}
- private void UpdateBreakpoints(FunctionContext functionContext)
- {
- if (functionContext._breakPoints == null)
- {
- // This should be rare - setting a breakpoint inside a script, but debugger hadn't started.
- SetupBreakpoints(functionContext);
- }
- else
- {
- // Check pending breakpoints to see if any apply to this script.
- if (string.IsNullOrEmpty(functionContext._file)) { return; }
-
- bool havePendingBreakpoint = false;
- foreach ((int breakpointId, LineBreakpoint item) in _pendingBreakpoints)
- {
- if (item.IsScriptBreakpoint && item.Script.Equals(functionContext._file, StringComparison.OrdinalIgnoreCase))
- {
- havePendingBreakpoint = true;
- break;
- }
- }
-
- if (havePendingBreakpoint)
- {
- SetPendingBreakpoints(functionContext);
- }
- }
- }
+ #endregion triggering breakpoints
#endregion internal methods
@@ -2448,39 +2383,6 @@ namespace System.Management.Automation
}
}
- ///
- /// SetBreakpoints.
- ///
- ///
- public override void SetBreakpoints(IEnumerable breakpoints)
- {
- if (breakpoints == null)
- {
- throw new PSArgumentNullException("breakpoints");
- }
-
- foreach (var breakpoint in breakpoints)
- {
- if (_idToBreakpoint.ContainsKey(breakpoint.Id)) { continue; }
-
- switch (breakpoint)
- {
- case LineBreakpoint lineBp:
- AddLineBreakpoint(lineBp);
- continue;
- case CommandBreakpoint cmdBp:
- AddCommandBreakpoint(cmdBp);
- continue;
- case VariableBreakpoint variableBp:
- AddVariableBreakpoint(variableBp);
- continue;
- default:
- // Unreachable default block
- break;
- }
- }
- }
-
///
/// True when debugger is active with breakpoints.
///
@@ -2676,16 +2578,147 @@ namespace System.Management.Automation
}
}
+ #region Breakpoints
+
+ ///
+ /// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
+ ///
+ /// Id of the breakpoint you want.
+ public override Breakpoint GetBreakpoint(int id)
+ {
+ _idToBreakpoint.TryGetValue(id, out Breakpoint breakpoint);
+ return breakpoint;
+ }
+
+ ///
+ /// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
+ ///
+ public override List GetBreakpoints()
+ {
+ return (from bp in _idToBreakpoint.Values orderby bp.Id select bp).ToList();
+ }
+
+ ///
+ /// 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.
+ ///
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null)
+ {
+ Diagnostics.Assert(!string.IsNullOrEmpty(command), "Caller to verify command is not null or empty.");
+
+ WildcardPattern pattern = WildcardPattern.Get(command, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
+
+ CheckForBreakpointSupport();
+ return AddCommandBreakpoint(new CommandBreakpoint(path, pattern, command, 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.
+ ///
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null)
+ {
+ Diagnostics.Assert(path != null, "Caller to verify path is not null.");
+ Diagnostics.Assert(line > 0, "Caller to verify line is greater than 0.");
+
+ CheckForBreakpointSupport();
+ return AddLineBreakpoint(new LineBreakpoint(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.
+ ///
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null)
+ {
+ 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)
+ {
+ Diagnostics.Assert(breakpoint != null, "Caller to verify the breakpoint is not null.");
+
+ if (_idToBreakpoint.Remove(breakpoint.Id, out _))
+ {
+ breakpoint.RemoveSelf(this);
+
+ if (CanDisableDebugger)
+ {
+ SetInternalDebugMode(InternalDebugMode.Disabled);
+ }
+
+ OnBreakpointUpdated(new BreakpointUpdatedEventArgs(breakpoint, BreakpointUpdateType.Removed, _idToBreakpoint.Count));
+
+ return true;
+ }
+
+ return false;
+ }
+
+
+ // This is the implementation of the Enable-PSBreakpoint cmdlet.
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint)
+ {
+ Diagnostics.Assert(breakpoint != null, "Caller to verify the breakpoint is not null.");
+
+ if (_idToBreakpoint.TryGetValue(breakpoint.Id, out _))
+ {
+ breakpoint.SetEnabled(true);
+ OnBreakpointUpdated(new BreakpointUpdatedEventArgs(breakpoint, BreakpointUpdateType.Enabled, _idToBreakpoint.Count));
+
+ return breakpoint;
+ }
+
+ return null;
+ }
+
+ // This is the implementation of the Disable-PSBreakpoint cmdlet.
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint)
+ {
+ Diagnostics.Assert(breakpoint != null, "Caller to verify the breakpoint is not null.");
+
+ if (_idToBreakpoint.TryGetValue(breakpoint.Id, out _))
+ {
+ breakpoint.SetEnabled(false);
+ OnBreakpointUpdated(new BreakpointUpdatedEventArgs(breakpoint, BreakpointUpdateType.Disabled, _idToBreakpoint.Count));
+
+ return breakpoint;
+ }
+
+ return null;
+ }
+
+ #endregion Breakpoints
+
#region Job Debugging
///
/// Sets up debugger to debug provided job or its child jobs.
///
///
- /// Job object that is either a debuggable job or a container
- /// of debuggable child jobs.
+ /// Job object that is either a debuggable job or a container of
+ /// debuggable child jobs.
///
- internal override void DebugJob(Job job)
+ ///
+ /// If true, the debugger automatically invokes a break all when it
+ /// attaches to the job.
+ ///
+ internal override void DebugJob(Job job, bool breakAll)
{
if (job == null) { throw new PSArgumentNullException("job"); }
@@ -2699,13 +2732,13 @@ namespace System.Management.Automation
// If a debuggable job was passed in then add it to the
// job running list.
- bool jobsAdded = TryAddDebugJob(job);
+ bool jobsAdded = TryAddDebugJob(job, breakAll);
if (!jobsAdded)
{
// Otherwise treat as parent Job and iterate over child jobs.
foreach (Job childJob in job.ChildJobs)
{
- if (TryAddDebugJob(childJob) && !jobsAdded)
+ if (TryAddDebugJob(childJob, breakAll) && !jobsAdded)
{
jobsAdded = true;
}
@@ -2718,7 +2751,7 @@ namespace System.Management.Automation
}
}
- private bool TryAddDebugJob(Job job)
+ private bool TryAddDebugJob(Job job, bool breakAll)
{
IJobDebugger debuggableJob = job as IJobDebugger;
if ((debuggableJob != null) && (debuggableJob.Debugger != null) &&
@@ -2731,7 +2764,7 @@ namespace System.Management.Automation
SetDebugJobAsync(debuggableJob, false);
AddToJobRunningList(
new PSJobStartEventArgs(job, debuggableJob.Debugger, false),
- DebuggerResumeAction.StepInto);
+ breakAll ? DebuggerResumeAction.StepInto : DebuggerResumeAction.Continue);
// Raise debug stop event if job is already in stopped state.
if (jobDebugAlreadyStopped)
@@ -2794,17 +2827,17 @@ namespace System.Management.Automation
#region Runspace Debugging
- internal override void DebugRunspace(Runspace runspace)
- {
- DebugRunspace(runspace, disableBreakAll: false);
- }
-
///
/// Sets up debugger to debug provided Runspace in a nested debug session.
///
- /// Runspace to debug.
- /// When specified, it will not turn on BreakAll.
- internal override void DebugRunspace(Runspace runspace, bool disableBreakAll)
+ ///
+ /// Runspace to debug.
+ ///
+ ///
+ /// When true, this command will invoke a BreakAll when the debugger is
+ /// first attached.
+ ///
+ internal override void DebugRunspace(Runspace runspace, bool breakAll)
{
if (runspace == null)
{
@@ -2839,7 +2872,7 @@ namespace System.Management.Automation
AddToRunningRunspaceList(new PSStandaloneMonitorRunspaceInfo(runspace));
- if (!runspace.Debugger.InBreakpoint && !disableBreakAll)
+ if (!runspace.Debugger.InBreakpoint && breakAll)
{
EnableDebuggerStepping(EnableNestedType.NestedRunspace);
}
@@ -3745,7 +3778,7 @@ namespace System.Management.Automation
{
WaitForReadyDebug();
- DebugRunspace(runspace);
+ DebugRunspace(runspace, breakAll:true);
// Block this event thread until debugging has ended.
WaitForDebugComplete();
@@ -4077,28 +4110,30 @@ namespace System.Management.Automation
return _wrappedDebugger.ProcessCommand(command, output);
}
- ///
- /// Adds the provided set of breakpoints to the debugger.
- ///
- /// Breakpoints.
- public override void SetBreakpoints(IEnumerable breakpoints)
- {
- _wrappedDebugger.SetBreakpoints(breakpoints);
- }
-
- ///
- /// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
- ///
- /// Id of the breakpoint you want.
public override Breakpoint GetBreakpoint(int id) =>
_wrappedDebugger.GetBreakpoint(id);
- ///
- /// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
- ///
public override List GetBreakpoints() =>
_wrappedDebugger.GetBreakpoints();
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
+ _wrappedDebugger.SetCommandBreakpoint(command, action, path);
+
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
+ _wrappedDebugger.SetLineBreakpoint(path, line, column, action);
+
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
+ _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path);
+
+ public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.RemoveBreakpoint(breakpoint);
+
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.EnableBreakpoint(breakpoint);
+
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.DisableBreakpoint(breakpoint);
+
///
/// SetDebuggerAction.
///
@@ -5397,12 +5432,6 @@ namespace System.Management.Automation.Internal
[SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes", Justification = "Needed Internal use only")]
public static class DebuggerUtils
{
- internal const string SetDebugModeFunctionName = "__Set-PSDebugMode";
- internal const string SetDebuggerActionFunctionName = "__Set-PSDebuggerAction";
- internal const string GetDebuggerStopArgsFunctionName = "__Get-PSDebuggerStopArgs";
- internal const string SetDebuggerStepMode = "__Set-PSDebuggerStepMode";
- internal const string SetPSUnhandledBreakpointMode = "__Set-PSUnhandledBreakpointMode";
-
private static SortedSet s_noHistoryCommandNames = new SortedSet(StringComparer.OrdinalIgnoreCase)
{
"prompt",
diff --git a/src/System.Management.Automation/engine/hostifaces/PSTask.cs b/src/System.Management.Automation/engine/hostifaces/PSTask.cs
index 6ca12b0405..59652393b1 100644
--- a/src/System.Management.Automation/engine/hostifaces/PSTask.cs
+++ b/src/System.Management.Automation/engine/hostifaces/PSTask.cs
@@ -1060,15 +1060,6 @@ namespace System.Management.Automation.PSTasks
return _wrappedDebugger.ProcessCommand(command, output);
}
- ///
- /// Adds the provided set of breakpoints to the debugger.
- ///
- /// List of breakpoints.
- public override void SetBreakpoints(IEnumerable breakpoints)
- {
- _wrappedDebugger.SetBreakpoints(breakpoints);
- }
-
///
/// Sets the debugger resume action.
///
@@ -1078,6 +1069,27 @@ namespace System.Management.Automation.PSTasks
_wrappedDebugger.SetDebuggerAction(resumeAction);
}
+ public override Breakpoint GetBreakpoint(int id) =>
+ _wrappedDebugger.GetBreakpoint(id);
+
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
+ _wrappedDebugger.SetCommandBreakpoint(command, action, path);
+
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
+ _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path);
+
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
+ _wrappedDebugger.SetLineBreakpoint(path, line, column, action);
+
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.EnableBreakpoint(breakpoint);
+
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.DisableBreakpoint(breakpoint);
+
+ public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.RemoveBreakpoint(breakpoint);
+
///
/// 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 8331f12085..18a5094228 100644
--- a/src/System.Management.Automation/engine/remoting/client/Job.cs
+++ b/src/System.Management.Automation/engine/remoting/client/Job.cs
@@ -3909,28 +3909,30 @@ namespace System.Management.Automation
return _wrappedDebugger.ProcessCommand(command, output);
}
- ///
- /// Adds the provided set of breakpoints to the debugger.
- ///
- /// Breakpoints.
- public override void SetBreakpoints(IEnumerable breakpoints)
- {
- _wrappedDebugger.SetBreakpoints(breakpoints);
- }
-
- ///
- /// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
- ///
- /// Id of the breakpoint you want.
public override Breakpoint GetBreakpoint(int id) =>
_wrappedDebugger.GetBreakpoint(id);
- ///
- /// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
- ///
public override List GetBreakpoints() =>
_wrappedDebugger.GetBreakpoints();
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
+ _wrappedDebugger.SetCommandBreakpoint(command, action, path);
+
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
+ _wrappedDebugger.SetLineBreakpoint(path, line, column, action);
+
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
+ _wrappedDebugger.SetVariableBreakpoint(variableName, accessMode, action, path);
+
+ public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.RemoveBreakpoint(breakpoint);
+
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.EnableBreakpoint(breakpoint);
+
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.DisableBreakpoint(breakpoint);
+
///
/// 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 086094fc0c..594ab4a525 100644
--- a/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs
+++ b/src/System.Management.Automation/engine/remoting/client/remoterunspace.cs
@@ -1809,7 +1809,8 @@ namespace System.Management.Automation
private bool _remoteDebugSupported;
private bool _isActive;
private int _breakpointCount;
- private Version _serverPSVersion;
+ private RemoteDebuggingCapability _remoteDebuggingCapability;
+ private bool? _remoteBreakpointManagementIsSupported;
private volatile bool _handleDebuggerStop;
private bool _isDebuggerSteppingEnabled;
private UnhandledBreakpointProcessingMode _unhandledBreakpointMode;
@@ -2005,27 +2006,165 @@ namespace System.Management.Automation
}
}
- ///
- /// Adds the provided set of breakpoints to the debugger.
- ///
- /// Breakpoints.
- public override void SetBreakpoints(IEnumerable breakpoints)
- {
- _runspace.Debugger?.SetBreakpoints(breakpoints);
- }
-
///
/// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
///
/// Id of the breakpoint you want.
- public override Breakpoint GetBreakpoint(int id) =>
- _runspace.Debugger?.GetBreakpoint(id);
+ public override Breakpoint GetBreakpoint(int id)
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.GetBreakpoint);
+
+ return InvokeRemoteBreakpointFunction(
+ RemoteDebuggingCommands.GetBreakpoint,
+ new Dictionary
+ {
+ { "Id", id },
+ });
+ }
///
/// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
///
- public override List GetBreakpoints() =>
- _runspace.Debugger?.GetBreakpoints();
+ public override List GetBreakpoints()
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.GetBreakpoint);
+
+ CheckForValidateState();
+
+ var breakpoints = new List();
+
+ using (PowerShell ps = GetNestedPowerShell())
+ {
+ ps.AddCommand(RemoteDebuggingCommands.GetBreakpoint);
+
+ Collection output = ps.Invoke();
+ foreach (var item in output)
+ {
+ if (item?.BaseObject is Breakpoint bp)
+ {
+ breakpoints.Add(bp);
+ }
+ }
+ }
+
+ return breakpoints;
+ }
+
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null)
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.SetBreakpoint);
+
+ var functionParameters = new Dictionary
+ {
+ { "Command", command },
+ };
+
+ if (action != null)
+ {
+ functionParameters.Add("Action", action);
+ }
+
+ if (path != null)
+ {
+ functionParameters.Add("Script", path);
+ }
+
+ return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
+ }
+
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null)
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.SetBreakpoint);
+
+ var functionParameters = new Dictionary
+ {
+ { "Script", path },
+ { "Line", line },
+ };
+
+ if (column != 0)
+ {
+ functionParameters.Add("Column", column);
+ }
+
+ if (action != null)
+ {
+ functionParameters.Add("Action", action);
+ }
+
+ return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
+ }
+
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null)
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.SetBreakpoint);
+
+ var functionParameters = new Dictionary
+ {
+ { "Variable", variableName },
+ };
+
+ if (accessMode != VariableAccessMode.Write)
+ {
+ functionParameters.Add("Mode", accessMode);
+ }
+
+ if (action != null)
+ {
+ functionParameters.Add("Action", action);
+ }
+
+ if (path != null)
+ {
+ functionParameters.Add("Script", path);
+ }
+
+ return InvokeRemoteBreakpointFunction(RemoteDebuggingCommands.SetBreakpoint, functionParameters);
+ }
+
+ public override bool RemoveBreakpoint(Breakpoint breakpoint)
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.RemoveBreakpoint);
+
+ return InvokeRemoteBreakpointFunction(
+ RemoteDebuggingCommands.RemoveBreakpoint,
+ new Dictionary
+ {
+ { "Id", breakpoint.Id },
+ });
+ }
+
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint)
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.EnableBreakpoint);
+
+ return InvokeRemoteBreakpointFunction(
+ RemoteDebuggingCommands.EnableBreakpoint,
+ new Dictionary
+ {
+ { "Id", breakpoint.Id },
+ });
+ }
+
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint)
+ {
+ // This is supported only for PowerShell versions >= 7.0
+ CheckRemoteBreakpointManagementSupport(RemoteDebuggingCommands.DisableBreakpoint);
+
+ return InvokeRemoteBreakpointFunction(
+ RemoteDebuggingCommands.DisableBreakpoint,
+ new Dictionary
+ {
+ { "Id", breakpoint.Id },
+ });
+ }
///
/// SetDebuggerAction.
@@ -2039,7 +2178,7 @@ namespace System.Management.Automation
using (PowerShell ps = GetNestedPowerShell())
{
- ps.AddCommand(DebuggerUtils.SetDebuggerActionFunctionName).AddParameter("ResumeAction", resumeAction);
+ ps.AddCommand(RemoteDebuggingCommands.SetDebuggerAction).AddParameter("ResumeAction", resumeAction);
ps.Invoke();
// If an error exception is returned then throw it here.
@@ -2065,7 +2204,7 @@ namespace System.Management.Automation
{
using (PowerShell ps = GetNestedPowerShell())
{
- ps.AddCommand(DebuggerUtils.GetDebuggerStopArgsFunctionName);
+ ps.AddCommand(RemoteDebuggingCommands.GetDebuggerStopArgs);
Collection output = ps.Invoke();
foreach (var item in output)
{
@@ -2102,7 +2241,7 @@ namespace System.Management.Automation
using (PowerShell ps = GetNestedPowerShell())
{
ps.SetIsNested(false);
- ps.AddCommand(DebuggerUtils.SetDebugModeFunctionName).AddParameter("Mode", mode);
+ ps.AddCommand(RemoteDebuggingCommands.SetDebugMode).AddParameter("Mode", mode);
ps.Invoke();
}
@@ -2120,8 +2259,7 @@ namespace System.Management.Automation
CheckForValidateState();
// This is supported only for PowerShell versions >= 5.0
- if ((_serverPSVersion == null) ||
- (_serverPSVersion.Major < PSVersionInfo.PSV5Version.Major))
+ if (!_remoteDebuggingCapability.IsCommandSupported(RemoteDebuggingCommands.SetDebuggerStepMode))
{
return;
}
@@ -2134,7 +2272,7 @@ namespace System.Management.Automation
// Send Enable-DebuggerStepping virtual command.
using (PowerShell ps = GetNestedPowerShell())
{
- ps.AddCommand(DebuggerUtils.SetDebuggerStepMode).AddParameter("Enabled", enabled);
+ ps.AddCommand(RemoteDebuggingCommands.SetDebuggerStepMode).AddParameter("Enabled", enabled);
ps.Invoke();
_isDebuggerSteppingEnabled = enabled;
}
@@ -2202,8 +2340,7 @@ namespace System.Management.Automation
CheckForValidateState();
// This is supported only for PowerShell versions >= 5.0
- if ((_serverPSVersion == null) ||
- (_serverPSVersion < PSVersionInfo.PSV5Version))
+ if (!_remoteDebuggingCapability.IsCommandSupported(RemoteDebuggingCommands.SetUnhandledBreakpointMode))
{
return;
}
@@ -2213,7 +2350,7 @@ namespace System.Management.Automation
// Send Set-PSUnhandledBreakpointMode virtual command.
using (PowerShell ps = GetNestedPowerShell())
{
- ps.AddCommand(DebuggerUtils.SetPSUnhandledBreakpointMode).AddParameter("UnhandledBreakpointMode", value);
+ ps.AddCommand(RemoteDebuggingCommands.SetUnhandledBreakpointMode).AddParameter("UnhandledBreakpointMode", value);
ps.Invoke();
}
@@ -2303,7 +2440,7 @@ namespace System.Management.Automation
SetRemoteDebug(true, RunspaceAvailability.RemoteDebug);
}
- _serverPSVersion = serverPSVersion;
+ _remoteDebuggingCapability = RemoteDebuggingCapability.CreateDebuggingCapability(serverPSVersion);
_breakpointCount = breakpointCount;
_isDebuggerSteppingEnabled = breakAll;
@@ -2610,6 +2747,59 @@ namespace System.Management.Automation
}
}
+ private T InvokeRemoteBreakpointFunction(string functionName, Dictionary parameters)
+ {
+ CheckForValidateState();
+
+ using (PowerShell ps = GetNestedPowerShell())
+ {
+ ps.AddCommand(functionName);
+ foreach (var parameterName in parameters.Keys)
+ {
+ ps.AddParameter(parameterName, parameters[parameterName]);
+ }
+
+ Collection output = ps.Invoke();
+
+ // If an error exception is returned then throw it here.
+ if (ps.ErrorBuffer.Count > 0)
+ {
+ Exception e = ps.ErrorBuffer[0].Exception;
+ if (e != null)
+ {
+ throw e;
+ }
+ }
+
+ // This helper is only used to return a single output item of type T.
+ foreach (var item in output)
+ {
+ if (item?.BaseObject is T)
+ {
+ return (T)item.BaseObject;
+ }
+ }
+
+ return default(T);
+ }
+ }
+
+ private void CheckRemoteBreakpointManagementSupport(string breakpointCommandNameToCheck)
+ {
+ if (_remoteBreakpointManagementIsSupported == null)
+ {
+ _remoteBreakpointManagementIsSupported = _remoteDebuggingCapability.IsCommandSupported(breakpointCommandNameToCheck);
+ }
+
+ if (!_remoteBreakpointManagementIsSupported.Value)
+ {
+ throw new PSNotSupportedException(
+ StringUtil.Format(
+ DebuggerStrings.CommandNotSupportedForRemoteUseInServerDebugger,
+ RemoteDebuggingCommands.CleanCommandName(breakpointCommandNameToCheck)));
+ }
+ }
+
#endregion
}
diff --git a/src/System.Management.Automation/engine/remoting/commands/DebugJob.cs b/src/System.Management.Automation/engine/remoting/commands/DebugJob.cs
index 954bf415f1..385182fc12 100644
--- a/src/System.Management.Automation/engine/remoting/commands/DebugJob.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/DebugJob.cs
@@ -97,6 +97,13 @@ namespace Microsoft.PowerShell.Commands
set;
}
+ ///
+ /// Gets or sets a flag that tells PowerShell to automatically perform a BreakAll when the debugger is attached to the remote target.
+ ///
+ [Experimental("Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace", ExperimentAction.Show)]
+ [Parameter]
+ public SwitchParameter BreakAll { get; set; }
+
#endregion
#region Overrides
@@ -177,7 +184,7 @@ namespace Microsoft.PowerShell.Commands
// Set up host script debugger to debug the job.
_debugger = runspace.Debugger;
- _debugger.DebugJob(_job);
+ _debugger.DebugJob(_job, breakAll: BreakAll);
// Blocking call. Send job output to host UI while debugging and wait for Job completion.
WaitAndReceiveJobOutput();
diff --git a/src/System.Management.Automation/engine/remoting/common/WireDataFormat/RemoteDebuggingCapability.cs b/src/System.Management.Automation/engine/remoting/common/WireDataFormat/RemoteDebuggingCapability.cs
new file mode 100644
index 0000000000..c093e09263
--- /dev/null
+++ b/src/System.Management.Automation/engine/remoting/common/WireDataFormat/RemoteDebuggingCapability.cs
@@ -0,0 +1,118 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Management.Automation.Remoting
+{
+ ///
+ /// This class contains information about the debugging capability of the server side of the
+ /// MS-PSRDP connection. The functionality that is supported is determined by the PowerShell
+ /// version on the server. These capabilities will be used in remote debugging sessions to
+ /// determine what is supported by the server.
+ ///
+ internal class RemoteDebuggingCapability
+ {
+ private readonly HashSet _supportedCommands = new HashSet();
+
+ internal Version PSVersion { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The version of PowerShell used on the remote server debugger.
+ ///
+ ///
+ /// This should only be invoked by the static create method.
+ ///
+ private RemoteDebuggingCapability(Version powerShellVersion)
+ {
+ PSVersion = powerShellVersion;
+
+ // Commands available in all server versions
+ _supportedCommands.Add(RemoteDebuggingCommands.GetDebuggerStopArgs);
+ _supportedCommands.Add(RemoteDebuggingCommands.SetDebuggerAction);
+ _supportedCommands.Add(RemoteDebuggingCommands.SetDebugMode);
+
+ if (PSVersion == null)
+ {
+ return;
+ }
+
+ // Commands added in v5
+ if (PSVersion.Major >= PSVersionInfo.PSV5Version.Major)
+ {
+ _supportedCommands.Add(RemoteDebuggingCommands.SetDebuggerStepMode);
+ _supportedCommands.Add(RemoteDebuggingCommands.SetUnhandledBreakpointMode);
+ }
+
+ // Commands added in v7
+ if (PSVersion.Major >= PSVersionInfo.PSV7Version.Major)
+ {
+ _supportedCommands.Add(RemoteDebuggingCommands.GetBreakpoint);
+ _supportedCommands.Add(RemoteDebuggingCommands.SetBreakpoint);
+ _supportedCommands.Add(RemoteDebuggingCommands.EnableBreakpoint);
+ _supportedCommands.Add(RemoteDebuggingCommands.DisableBreakpoint);
+ _supportedCommands.Add(RemoteDebuggingCommands.RemoveBreakpoint);
+ }
+ }
+
+ ///
+ /// Creates a instance that can be
+ /// used to identify the remoting capabilities of the server debugger.
+ ///
+ ///
+ /// The version of PowerShell used on the remote server debugger.
+ ///
+ ///
+ /// A new RemoteDebuggingCapability instance that is based on the version
+ /// of PowerShell used on the remote server debugger.
+ ///
+ internal static RemoteDebuggingCapability CreateDebuggingCapability(Version powerShellVersion) =>
+ new RemoteDebuggingCapability(powerShellVersion);
+
+ ///
+ /// Checks if a command is supported in the server version used to create
+ /// this instance.
+ ///
+ ///
+ /// The name of the command to check.
+ ///
+ ///
+ /// True if the command is supported; false otherwise.
+ ///
+ internal bool IsCommandSupported(string commandName) =>
+ _supportedCommands.Contains(commandName);
+ }
+
+ internal static class RemoteDebuggingCommands
+ {
+ #region DO NOT REMOVE OR CHANGE THE VALUES OF THESE CONSTANTS - it will break remote debugging compatibility with PowerShell
+
+ // Commands related to debugger stop events
+ internal const string GetDebuggerStopArgs = "__Get-PSDebuggerStopArgs";
+ internal const string SetDebuggerAction = "__Set-PSDebuggerAction";
+
+ // Miscellaneous debug commands
+ internal const string SetDebuggerStepMode = "__Set-PSDebuggerStepMode";
+ internal const string SetDebugMode = "__Set-PSDebugMode";
+ internal const string SetUnhandledBreakpointMode = "__Set-PSUnhandledBreakpointMode";
+
+ // Breakpoint commands
+ internal const string GetBreakpoint = "__Get-PSBreakpoint";
+ internal const string SetBreakpoint = "__Set-PSBreakpoint";
+ internal const string EnableBreakpoint = "__Enable-PSBreakpoint";
+ internal const string DisableBreakpoint = "__Disable-PSBreakpoint";
+ internal const string RemoveBreakpoint = "__Remove-PSBreakpoint";
+
+ #endregion
+
+ internal static string CleanCommandName(string commandName)
+ {
+ return commandName.TrimStart('_');
+ }
+ }
+}
diff --git a/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs b/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs
index 42005deac1..c082f0a76c 100644
--- a/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs
+++ b/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs
@@ -704,9 +704,9 @@ namespace System.Management.Automation
///
/// Handle the invocation of powershell.
///
- /// Sender of this event, unused.
+ /// Sender of this event, unused.
/// Arguments describing this event.
- private void HandleCreateAndInvokePowerShell(object sender, RemoteDataEventArgs> eventArgs)
+ private void HandleCreateAndInvokePowerShell(object _, RemoteDataEventArgs> eventArgs)
{
RemoteDataObject data = eventArgs.Data;
@@ -1194,7 +1194,8 @@ namespace System.Management.Automation
private enum PreProcessCommandResult
{
///
- /// No debugger pre-processing.
+ /// No debugger pre-processing. "Get" commands use this so that the
+ /// data they retrieve can be sent back to the caller.
///
None = 0,
@@ -1204,11 +1205,6 @@ namespace System.Management.Automation
///
ValidNotProcessed,
- ///
- /// GetDebuggerStopArgs.
- ///
- GetDebuggerStopArgs,
-
///
/// SetDebuggerAction.
///
@@ -1227,7 +1223,7 @@ namespace System.Management.Automation
///
/// SetPreserveUnhandledBreakpointMode.
///
- SetPreserveUnhandledBreakpointMode
+ SetPreserveUnhandledBreakpointMode,
};
private class DebuggerCommandArgument
@@ -1266,35 +1262,31 @@ namespace System.Management.Automation
var command = commands.Commands[0];
string commandText = command.CommandText;
- if (commandText.Equals(DebuggerUtils.GetDebuggerStopArgsFunctionName, StringComparison.OrdinalIgnoreCase))
+ if (commandText.Equals(RemoteDebuggingCommands.GetDebuggerStopArgs, StringComparison.OrdinalIgnoreCase))
{
- //
// __Get-PSDebuggerStopArgs private virtual command.
// No input parameters.
// Returns DebuggerStopEventArgs object.
- //
// Evaluate this command only if the debugger is activated.
- if (!isDebuggerActive) { return PreProcessCommandResult.ValidNotProcessed; }
+ if (!isDebuggerActive)
+ {
+ return PreProcessCommandResult.ValidNotProcessed;
+ }
- // Translate into debugger method call.
- ScriptBlock scriptBlock = ScriptBlock.Create("$host.Runspace.Debugger.GetDebuggerStopArgs()");
- scriptBlock.LanguageMode = PSLanguageMode.FullLanguage;
- commands.Clear();
- commands.AddCommand("Invoke-Command").AddParameter("ScriptBlock", scriptBlock).AddParameter("NoNewScope", true);
-
- result = PreProcessCommandResult.GetDebuggerStopArgs;
+ ReplaceVirtualCommandWithScript(commands, "$host.Runspace.Debugger.GetDebuggerStopArgs()");
}
- else if (commandText.Equals(DebuggerUtils.SetDebuggerActionFunctionName, StringComparison.OrdinalIgnoreCase))
+ else if (commandText.Equals(RemoteDebuggingCommands.SetDebuggerAction, StringComparison.OrdinalIgnoreCase))
{
- //
// __Set-PSDebuggerAction private virtual command.
// DebuggerResumeAction enum input parameter.
// Returns void.
- //
// Evaluate this command only if the debugger is activated.
- if (!isDebuggerActive) { return PreProcessCommandResult.ValidNotProcessed; }
+ if (!isDebuggerActive)
+ {
+ return PreProcessCommandResult.ValidNotProcessed;
+ }
if ((command.Parameters == null) || (command.Parameters.Count == 0) ||
(!command.Parameters[0].Name.Equals("ResumeAction", StringComparison.OrdinalIgnoreCase)))
@@ -1313,22 +1305,14 @@ namespace System.Management.Automation
catch (InvalidCastException) { }
}
- if (resumeAction == null)
- {
- throw new PSArgumentException("ResumeAction");
- }
-
- commandArgument.ResumeAction = resumeAction;
+ commandArgument.ResumeAction = resumeAction ?? throw new PSArgumentException("ResumeAction");
result = PreProcessCommandResult.SetDebuggerAction;
}
- else if (commandText.Equals(DebuggerUtils.SetDebugModeFunctionName, StringComparison.OrdinalIgnoreCase))
+ else if (commandText.Equals(RemoteDebuggingCommands.SetDebugMode, StringComparison.OrdinalIgnoreCase))
{
- //
// __Set-PSDebugMode private virtual command.
// DebugModes enum input parameter.
// Returns void.
- //
-
if ((command.Parameters == null) || (command.Parameters.Count == 0) ||
(!command.Parameters[0].Name.Equals("Mode", StringComparison.OrdinalIgnoreCase)))
{
@@ -1346,22 +1330,14 @@ namespace System.Management.Automation
catch (InvalidCastException) { }
}
- if (mode == null)
- {
- throw new PSArgumentException("Mode");
- }
-
- commandArgument.Mode = mode;
+ commandArgument.Mode = mode ?? throw new PSArgumentException("Mode");
result = PreProcessCommandResult.SetDebugMode;
}
- else if (commandText.Equals(DebuggerUtils.SetDebuggerStepMode, StringComparison.OrdinalIgnoreCase))
+ else if (commandText.Equals(RemoteDebuggingCommands.SetDebuggerStepMode, StringComparison.OrdinalIgnoreCase))
{
- //
// __Set-PSDebuggerStepMode private virtual command.
// Boolean Enabled input parameter.
// Returns void.
- //
-
if ((command.Parameters == null) || (command.Parameters.Count == 0) ||
(!command.Parameters[0].Name.Equals("Enabled", StringComparison.OrdinalIgnoreCase)))
{
@@ -1372,14 +1348,11 @@ namespace System.Management.Automation
commandArgument.DebuggerStepEnabled = enabled;
result = PreProcessCommandResult.SetDebuggerStepMode;
}
- else if (commandText.Equals(DebuggerUtils.SetPSUnhandledBreakpointMode, StringComparison.OrdinalIgnoreCase))
+ else if (commandText.Equals(RemoteDebuggingCommands.SetUnhandledBreakpointMode, StringComparison.OrdinalIgnoreCase))
{
- //
// __Set-PSUnhandledBreakpointMode private virtual command.
// UnhandledBreakpointMode input parameter.
// Returns void.
- //
-
if ((command.Parameters == null) || (command.Parameters.Count == 0) ||
(!command.Parameters[0].Name.Equals("UnhandledBreakpointMode", StringComparison.OrdinalIgnoreCase)))
{
@@ -1397,18 +1370,168 @@ namespace System.Management.Automation
catch (InvalidCastException) { }
}
- if (mode == null)
+ commandArgument.UnhandledBreakpointMode = mode ?? throw new PSArgumentException("Mode");
+ result = PreProcessCommandResult.SetPreserveUnhandledBreakpointMode;
+ }
+ else if (commandText.Equals(RemoteDebuggingCommands.GetBreakpoint, StringComparison.OrdinalIgnoreCase))
+ {
+ // __Get-PSBreakpoint private virtual command.
+ // Input parameters:
+ // [-Id ]
+ // Returns Breakpoint object(s).
+ string script = null;
+
+ if (command.Parameters?.Count > 0)
{
- throw new PSArgumentException("Mode");
+ int breakpointId = CheckBreakpointIdParameter(command);
+ script = $"$host.Runspace.Debugger.GetBreakpoint({breakpointId})";
+ }
+ else
+ {
+ script = $"$host.Runspace.Debugger.GetBreakpoints()";
}
- commandArgument.UnhandledBreakpointMode = mode;
- result = PreProcessCommandResult.SetPreserveUnhandledBreakpointMode;
+ ReplaceVirtualCommandWithScript(commands, script);
+ }
+ 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)
+ {
+ throw new PSArgumentException("You must provide at least one parameter.");
+ }
+
+ 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";
+ }
+ }
+
+ 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);
+ }
+ }
+ else if (commandText.Equals(RemoteDebuggingCommands.RemoveBreakpoint, StringComparison.OrdinalIgnoreCase))
+ {
+ // __Remove-PSBreakpoint private virtual command.
+ // Input parameters:
+ // -Id
+ // Returns bool.
+
+ int breakpointId = CheckBreakpointIdParameter(command);
+
+ string script = $"$bp = $host.Runspace.Debugger.GetBreakpoint({breakpointId}); $bp -ne $null -and $host.Runspace.Debugger.RemoveBreakpoint($bp)";
+
+ ReplaceVirtualCommandWithScript(commands, script);
+ }
+ else if (commandText.Equals(RemoteDebuggingCommands.EnableBreakpoint, StringComparison.OrdinalIgnoreCase))
+ {
+ // __Enable-PSBreakpoint private virtual command.
+ // Input parameters:
+ // -Id
+ // Returns Breakpoint.
+
+ int breakpointId = CheckBreakpointIdParameter(command);
+
+ string script = $"$bp = $host.Runspace.Debugger.GetBreakpoint({breakpointId}); if ($bp -ne $null) {{$host.Runspace.Debugger.EnableBreakpoint($bp)}}";
+
+ ReplaceVirtualCommandWithScript(commands, script);
+ }
+ else if (commandText.Equals(RemoteDebuggingCommands.DisableBreakpoint, StringComparison.OrdinalIgnoreCase))
+ {
+ // __Disable-PSBreakpoint private virtual command.
+ // Input parameters:
+ // -Id
+ // Returns Breakpoint.
+
+ int breakpointId = CheckBreakpointIdParameter(command);
+
+ string script = $"$bp = $host.Runspace.Debugger.GetBreakpoint({breakpointId}); if ($bp -ne $null) {{$host.Runspace.Debugger.DisableBreakpoint($bp)}}";
+
+ ReplaceVirtualCommandWithScript(commands, script);
}
return result;
}
+ private static void ReplaceVirtualCommandWithScript(PSCommand commands, string script)
+ {
+ ScriptBlock scriptBlock = ScriptBlock.Create(script);
+ scriptBlock.LanguageMode = PSLanguageMode.FullLanguage;
+ commands.Clear();
+ commands.AddCommand("Invoke-Command")
+ .AddParameter("ScriptBlock", scriptBlock)
+ .AddParameter("NoNewScope", true);
+ }
+
+ private static int CheckBreakpointIdParameter(Command command)
+ {
+ if (command.Parameters == null ||
+ command.Parameters.Count == 0 ||
+ !command.Parameters[0].Name.Equals("Id", StringComparison.OrdinalIgnoreCase))
+ {
+ throw new PSArgumentException("Id");
+ }
+
+ int? breakpointId = command.Parameters[0].Value as int?;
+ if (breakpointId == null)
+ {
+ throw new PSArgumentException("Id");
+ }
+
+ return breakpointId.Value;
+ }
+
#endregion
#region Private Classes
@@ -1706,28 +1829,30 @@ namespace System.Management.Automation
get { return _inDebugMode; }
}
- ///
- /// Adds the provided set of breakpoints to the debugger.
- ///
- /// Breakpoints.
- public override void SetBreakpoints(IEnumerable breakpoints)
- {
- _wrappedDebugger.Value.SetBreakpoints(breakpoints);
- }
-
- ///
- /// Get a breakpoint by id, primarily for Enable/Disable/Remove-PSBreakpoint cmdlets.
- ///
- /// Id of the breakpoint you want.
public override Breakpoint GetBreakpoint(int id) =>
_wrappedDebugger.Value.GetBreakpoint(id);
- ///
- /// Returns breakpoints primarily for the Get-PSBreakpoint cmdlet.
- ///
public override List GetBreakpoints() =>
_wrappedDebugger.Value.GetBreakpoints();
+ public override CommandBreakpoint SetCommandBreakpoint(string command, ScriptBlock action = null, string path = null) =>
+ _wrappedDebugger.Value.SetCommandBreakpoint(command, action, path);
+
+ public override LineBreakpoint SetLineBreakpoint(string path, int line, int column = 0, ScriptBlock action = null) =>
+ _wrappedDebugger.Value.SetLineBreakpoint(path, line, column, action);
+
+ public override VariableBreakpoint SetVariableBreakpoint(string variableName, VariableAccessMode accessMode = VariableAccessMode.Write, ScriptBlock action = null, string path = null) =>
+ _wrappedDebugger.Value.SetVariableBreakpoint(variableName, accessMode, action, path);
+
+ public override bool RemoveBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.Value.RemoveBreakpoint(breakpoint);
+
+ public override Breakpoint EnableBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.Value.EnableBreakpoint(breakpoint);
+
+ public override Breakpoint DisableBreakpoint(Breakpoint breakpoint) =>
+ _wrappedDebugger.Value.DisableBreakpoint(breakpoint);
+
///
/// Exits debugger mode with the provided resume action.
///
@@ -1855,13 +1980,15 @@ namespace System.Management.Automation
/// Sets up debugger to debug provided job or its child jobs.
///
///
- /// Job object that is either a debuggable job or a container
- /// of debuggable child jobs.
+ /// Job object that is either a debuggable job or a container of
+ /// debuggable child jobs.
///
- internal override void DebugJob(Job job)
- {
- _wrappedDebugger.Value.DebugJob(job);
- }
+ ///
+ /// If true, the debugger automatically invokes a break all when it
+ /// attaches to the job.
+ ///
+ internal override void DebugJob(Job job, bool breakAll) =>
+ _wrappedDebugger.Value.DebugJob(job, breakAll);
///
/// Removes job from debugger job list and pops its
@@ -1876,20 +2003,16 @@ namespace System.Management.Automation
///
/// Sets up debugger to debug provided Runspace in a nested debug session.
///
- /// Runspace to debug.
- internal override void DebugRunspace(Runspace runspace)
+ ///
+ /// Runspace to debug.
+ ///
+ ///
+ /// When true, this command will invoke a BreakAll when the debugger is
+ /// first attached.
+ ///
+ internal override void DebugRunspace(Runspace runspace, bool breakAll)
{
- _wrappedDebugger.Value.DebugRunspace(runspace);
- }
-
- ///
- /// Sets up debugger to debug provided Runspace in a nested debug session.
- ///
- /// Runspace to debug.
- ///
- internal override void DebugRunspace(Runspace runspace, bool disableBreakAll)
- {
- _wrappedDebugger.Value.DebugRunspace(runspace, disableBreakAll);
+ _wrappedDebugger.Value.DebugRunspace(runspace, breakAll);
}
///
diff --git a/src/System.Management.Automation/resources/DebuggerStrings.resx b/src/System.Management.Automation/resources/DebuggerStrings.resx
index 90cb124142..79b0cf42a4 100644
--- a/src/System.Management.Automation/resources/DebuggerStrings.resx
+++ b/src/System.Management.Automation/resources/DebuggerStrings.resx
@@ -237,6 +237,9 @@ The current session does not support debugging; operation will continue.
Cannot push a debugger object onto itself.
+
+ The {0} command is not supported for remote use in the version of PowerShell that is running in the remote runspace.
+
Process
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/EnableDisablePSBreakpoint.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/EnableDisablePSBreakpoint.Tests.ps1
deleted file mode 100644
index 155dc1b900..0000000000
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/EnableDisablePSBreakpoint.Tests.ps1
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-Describe "Enable and Disable PSBreakpoints" -Tag "CI" {
- BeforeAll {
- $path = Setup -F testbp.ps1 -content "get-command`nget-date`nget-location" -pass
- $bp = set-psbreakpoint -script $path -line 2
- disable-psbreakpoint $bp
- }
- AfterAll {
- $bp | remove-psbreakpoint
- }
- It "Enable-PSBreakpoint should enable the breakpoint" {
- $bp.Enabled | Should -BeFalse
- Enable-PSBreakpoint $bp
- $bp.Enabled | Should -BeTrue
- }
- It "Disable-PSBreakpoint should disable the breakpoint" {
- Enable-PSBreakpoint $bp
- $bp.Enabled | Should -BeTrue
- Disable-PSBreakpoint $bp
- $bp.Enabled | Should -BeFalse
- }
-}
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/New-PSBreakpoint.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/New-PSBreakpoint.Tests.ps1
deleted file mode 100644
index 544cdff290..0000000000
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/New-PSBreakpoint.Tests.ps1
+++ /dev/null
@@ -1,195 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-$FeatureEnabled = $EnabledExperimentalFeatures.Contains('Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints')
-
-Describe "New-PSBreakpoint Unit Tests - Feature-Enabled" -Tags "CI" {
-
- BeforeAll {
- if (!$FeatureEnabled) {
- Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints' to be enabled." -Verbose
- $originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
- $PSDefaultParameterValues["it:skip"] = $true
- return
- }
-
- #Set up script file 1
- $scriptFileName1 = Join-Path $TestDrive -ChildPath breakpointTestScript.ps1
-
- $contents = @"
-function Hello
-{
- `$greeting = 'Hello, world!'
- write-host `$greeting
-}
-
-function Goodbye
-{
- `$message = 'Good bye, cruel world!'
- write-host `$message
-}
-
-Hello
-Goodbye
-
-# The following 2 statements produce null tokens (needed to verify 105473)
-#
-`$table = @{}
-
-return
-"@
-
- $contents > $scriptFileName1
-
- # Set up script file 2
- $scriptFileName2 = Join-Path -Path $TestDrive -ChildPath psbreakpointtestscript.ps1
-
- "`$var = 1 " > $scriptFileName2
- }
-
- AfterAll {
- if (!$FeatureEnabled) {
- $global:PSDefaultParameterValues = $originalDefaultParameterValues
- return
- }
- }
-
- It "Should be able to set psbreakpoints for -Line" {
- $brk = New-PSBreakpoint -Line 13 -Script $scriptFileName1
- $brk.Line | Should -Be 13
- }
-
- It "Should be able to set psbreakpoints for -Line and -column" {
- $brk = New-PSBreakpoint -line 13 -column 1 -script $scriptFileName1
- $brk.Line | Should -Be 13
- $brk.Column | Should -Be 1
- }
-
- It "Should be able to set psbreakpoints for -Line and -action" {
- $brk = New-PSBreakpoint -line 13 -action {{ break; }} -script $scriptFileName1
- $brk.Line | Should -Be 13
- $brk.Action | Should -Match "break"
- }
-
- It "Should be able to set psbreakpoints for -Line, -column and -action" {
- $brk = New-PSBreakpoint -line 13 -column 1 -action {{ break; }} -script $scriptFileName1
- $brk.Line | Should -Be 13
- $brk.Column | Should -Be 1
- $brk.Action | Should -Match "break"
- }
-
- It "-script and -line can take multiple items" {
- $brk = New-PSBreakpoint -line 11,12,13 -column 1 -script $scriptFileName1,$scriptFileName1
- $brk.Line | Should -BeIn 11,12,13
- $brk.Column | Should -BeIn 1
- }
-
- It "-script and -line are positional" {
- $brk = New-PSBreakpoint $scriptFileName1 13
- $brk.Line | Should -Be 13
- }
-
- It "-script, -line and -column are positional" {
- $brk = New-PSBreakpoint $scriptFileName1 13 1
- $brk.Line | Should -Be 13
- $brk.Column | Should -Be 1
- }
-
- It "Should throw Exception when missing mandatory parameter -line" -Pending {
- $output = pwsh -noninteractive -command "nbp -column 1 -script $scriptFileName1"
- [system.string]::Join(" ", $output) | Should -Match "MissingMandatoryParameter,Microsoft.PowerShell.Commands.NewPSBreakpointCommand"
- }
-
- It "Should throw Exception when missing mandatory parameter" -Pending {
- $output = pwsh -noprofile -noninteractive -command "nbp -line 1"
- [system.string]::Join(" ", $output) | Should -Match "MissingMandatoryParameter,Microsoft.PowerShell.Commands.NewPSBreakpointCommand"
- }
-
- It "Should be able to set psbreakpoints for -command" {
- $brk = New-PSBreakpoint -command "write-host"
- $brk.Command | Should -BeExactly "write-host"
- }
-
- It "Should be able to set psbreakpoints for -command, -script" {
- $brk = New-PSBreakpoint -command "write-host" -script $scriptFileName1
- $brk.Command | Should -BeExactly "write-host"
- }
-
- It "Should be able to set psbreakpoints for -command, -action and -script" {
- $brk = New-PSBreakpoint -command "write-host" -action {{ break; }} -script $scriptFileName1
- $brk.Action | Should -Match "break"
- }
-
- It "-Command can take multiple items" {
- $brk = New-PSBreakpoint -command write-host,Hello
- $brk.Command | Should -Be write-host,Hello
- }
-
- It "-Script is positional" {
- $brk = New-PSBreakpoint -command "Hello" $scriptFileName1
- $brk.Command | Should -BeExactly "Hello"
-
- $brk = New-PSBreakpoint $scriptFileName1 -command "Hello"
- $brk.Command | Should -BeExactly "Hello"
- }
-
- It "Should be able to set breakpoints on functions" {
- $brk = New-PSBreakpoint -command Hello,Goodbye -script $scriptFileName1
- $brk.Command | Should -Be Hello,Goodbye
- }
-
- It "Should be throw Exception when Column number less than 1" {
- { New-PSBreakpoint -line 1 -column -1 -script $scriptFileName1 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.NewPSBreakpointCommand"
- }
-
- It "Should be throw Exception when Line number less than 1" {
- $ErrorActionPreference = "Stop"
- { New-PSBreakpoint -line -1 -script $scriptFileName1 } | Should -Throw -ErrorId "NewPSBreakpoint:LineLessThanOne,Microsoft.PowerShell.Commands.NewPSBreakpointCommand"
- $ErrorActionPreference = "SilentlyContinue"
- }
-
- It "Fail to set psbreakpoints when script is a file of wrong type" {
- $tempFile = [System.IO.Path]::GetTempFileName()
- $ErrorActionPreference = "Stop"
- {
- New-PSBreakpoint -Script $tempFile -Line 1
- } | Should -Throw
- $ErrorActionPreference = "SilentlyContinue"
- Remove-Item $tempFile -Force
- }
-
- It "Fail to set psbreakpoints when script file does not exist" {
- $ErrorActionPreference = "Stop"
- ${script.ps1} = 10
- {
- New-PSBreakpoint -Script variable:\script.ps1 -Line 1
- } | Should -Throw
- $ErrorActionPreference = "SilentlyContinue"
- }
-
- It "Should be able to set a psbreakpoint on a line" {
- $lineNumber = 1
- $brk = New-PSBreakpoint -Line $lineNumber -Script $scriptFileName2
- $brk.Line | Should -Be $lineNumber
- }
-
- It "Should throw when a string is entered for a line number" {
- {
- $lineNumber = "one"
- New-PSBreakpoint -Line $lineNumber -Script $scriptFileName2
-
- } | Should -Throw
- }
-
- It "Should be able to set a psbreakpoint on a Command" {
- $command = "theCommand"
- $brk = New-PSBreakpoint -Command $command -Script $scriptFileName2
- $brk.Command | Should -Be $command
- }
-
- It "Should be able to set a psbreakpoint on a variable" {
- $var = "theVariable"
- $brk = New-PSBreakpoint -Command $var -Script $scriptFileName2
- $brk.Command | Should -Be $var
- }
-}
diff --git a/test/powershell/SDK/Breakpoint.Tests.ps1 b/test/powershell/SDK/Breakpoint.Tests.ps1
new file mode 100644
index 0000000000..599b8b4561
--- /dev/null
+++ b/test/powershell/SDK/Breakpoint.Tests.ps1
@@ -0,0 +1,168 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+Describe 'Breakpoint SDK Unit Tests' -Tags 'CI' {
+
+ BeforeAll {
+ # Start a job; this will create a runspace in which we can manage breakpoints
+ $job = Start-Job -ScriptBlock {
+ Set-PSBreakpoint -Command Start-Sleep
+ 1..240 | ForEach-Object {
+ Start-Sleep -Milliseconds 250
+ $_
+ Write-Error 'boo'
+ Write-Verbose 'Verbose' -Verbose
+ $DebugPreference = 'Continue'
+ Write-Debug 'Debug'
+ Write-Warning 'Warning'
+ }
+ }
+
+ # Wait for the child job that gets created to hit the breakpoint. This is the
+ # only safe way to know that the job has actually entered a running state and
+ # that the remote runspace is listening for requests.
+ Wait-UntilTrue { $job.ChildJobs.Count -gt 0 -and $job.ChildJobs[0].State -eq 'AtBreakpoint' } -TimeoutInMilliseconds 10000 -IntervalInMilliseconds 250
+
+ # Get the runspace for the running job
+ $jobRunspace = $job.ChildJobs[0].Runspace
+ }
+
+ AfterAll {
+ # Remove the running job forcibly (whether it has finished or not)
+ Remove-Job -Job $job -Force
+ }
+
+ Context 'Managing breakpoints in the host runspace via the SDK' {
+
+ It 'Can set command breakpoints' {
+ $host.Runspace.Debugger.SetCommandBreakpoint('Test-ThisCommandDoesNotExist') | Should -BeOfType [System.Management.Automation.CommandBreakpoint]
+ }
+
+ It 'Can set variable breakpoints' {
+ $host.Runspace.Debugger.SetVariableBreakpoint('DebugPreference', 'ReadWrite', { continue }) | Should -BeOfType [System.Management.Automation.VariableBreakpoint]
+ }
+
+ It 'Can set line breakpoints' {
+ $host.Runspace.Debugger.SetLineBreakpoint($PSCommandPath, 1, 1, { continue }) | Should -BeOfType [System.Management.Automation.LineBreakpoint]
+ }
+
+ It 'Can get breakpoints' {
+ $host.Runspace.Debugger.GetBreakpoints() | Should -HaveCount 3
+ }
+
+ It 'Can disable breakpoints' {
+ foreach ($bp in $host.Runspace.Debugger.GetBreakpoints()) {
+ $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.Enabled | Should -BeTrue
+ }
+ }
+
+ It 'Can remove breakpoints' {
+ foreach ($bp in $host.Runspace.Debugger.GetBreakpoints()) {
+ $host.Runspace.Debugger.RemoveBreakpoint($bp) | Should -BeTrue
+ }
+ }
+
+ It 'Returns an empty collection when there are no breakpoints' {
+ $host.Runspace.Debugger.GetBreakpoints() | Should -HaveCount 0
+ }
+ }
+
+ Context 'Managing breakpoints in a remote runspace via the SDK' {
+
+ AfterAll {
+ # Get rid of any breakpoints that were created in the default runspace.
+ # This is necessary due to a known bug that causes breakpoints with the
+ # same id to be created or updated in the default runspace.
+ Get-PSBreakpoint | Remove-PSBreakpoint
+ }
+
+ It 'Can set command breakpoints' {
+ $jobRunspace.Debugger.SetCommandBreakpoint('Write-Verbose', { break }) | Should -BeOfType [System.Management.Automation.CommandBreakpoint]
+ }
+
+ It 'Can set variable breakpoints' {
+ $jobRunspace.Debugger.SetVariableBreakpoint('DebugPreference', 'ReadWrite', { break }) | Should -BeOfType [System.Management.Automation.VariableBreakpoint]
+ }
+
+ It 'Can set line breakpoints' {
+ $jobRunspace.Debugger.SetLineBreakpoint($PSCommandPath, 1, 1, { break }) | Should -BeOfType [System.Management.Automation.LineBreakpoint]
+ }
+
+ It 'Can get breakpoints' {
+ # This is 4, not 3, because we set a breakpoint in our job script
+ $jobRunspace.Debugger.GetBreakpoints() | Should -HaveCount 4
+ }
+
+ It 'Can disable breakpoints' {
+ foreach ($bp in $jobRunspace.Debugger.GetBreakpoints()) {
+ $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.Enabled | Should -BeTrue
+ }
+ }
+
+ It 'Can remove breakpoints' {
+ foreach ($bp in $jobRunspace.Debugger.GetBreakpoints()) {
+ $jobRunspace.Debugger.RemoveBreakpoint($bp) | Should -BeTrue
+ }
+ }
+
+ It 'Returns an empty collection when there are no breakpoints' {
+ $jobRunspace.Debugger.GetBreakpoints() | Should -HaveCount 0
+ }
+ }
+
+ 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
+ }
+
+ It 'Returns false when trying to disable a breakpoint that does not exist' {
+ $host.Runspace.Debugger.DisableBreakpoint($bp) | Should -Be $null
+ }
+
+ It 'Returns false when trying to enable a breakpoint that does not exist' {
+ $host.Runspace.Debugger.EnableBreakpoint($bp) | Should -Be $null
+ }
+
+ It 'Returns false when trying to remove a breakpoint that does not exist' {
+ $host.Runspace.Debugger.RemoveBreakpoint($bp) | Should -BeFalse
+ }
+ }
+
+ Context 'Handling errors while managing breakpoints in a remote runspace via the SDK' {
+
+ BeforeAll {
+ $bp = $jobRunspace.Debugger.SetCommandBreakpoint('Test-ThisCommandDoesNotExist')
+ $jobRunspace.Debugger.RemoveBreakpoint($bp) > $null
+ }
+
+ It 'Returns false when trying to disable a breakpoint that does not exist' {
+ $jobRunspace.Debugger.DisableBreakpoint($bp) | Should -Be $null
+ }
+
+ It 'Returns false when trying to enable a breakpoint that does not exist' {
+ $jobRunspace.Debugger.EnableBreakpoint($bp) | Should -Be $null
+ }
+
+ It 'Returns false when trying to remove a breakpoint that does not exist' {
+ $jobRunspace.Debugger.RemoveBreakpoint($bp) | Should -BeFalse
+ }
+ }
+}
diff --git a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1
index b164c116e0..f08f9dc54d 100644
--- a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1
+++ b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1
@@ -116,7 +116,6 @@ Describe "Verify approved aliases list" -Tags "CI" {
"Alias", "move", "Move-Item", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "AllScope", ""
"Alias", "mp", "Move-ItemProperty", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
"Alias", "mv", "Move-Item", $($FullCLR -or $CoreWindows ), "", "", ""
-"Alias", "nbp", "New-PSBreakpoint", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
"Alias", "nal", "New-Alias", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
"Alias", "ndr", "New-PSDrive", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
"Alias", "ni", "New-Item", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
diff --git a/test/tools/TestMetadata.json b/test/tools/TestMetadata.json
index 59c68cff18..605057a873 100644
--- a/test/tools/TestMetadata.json
+++ b/test/tools/TestMetadata.json
@@ -1,6 +1,5 @@
{
"ExperimentalFeatures": {
- "Microsoft.PowerShell.Utility.PSDebugRunspaceWithBreakpoints": ["test/powershell/Modules/Microsoft.PowerShell.Utility/New-PSBreakpoint.Tests.ps1"],
"ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ],
"PSForEachObjectParallel": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/Foreach-Object-Parallel.Tests.ps1", "test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1" ]
}
diff --git a/test/xUnit/csharp/test_Runspace.cs b/test/xUnit/csharp/test_Runspace.cs
index 38a6dfd1bf..2042ee7d6f 100644
--- a/test/xUnit/csharp/test_Runspace.cs
+++ b/test/xUnit/csharp/test_Runspace.cs
@@ -101,31 +101,5 @@ namespace PSTests.Sequential
runspace.Close();
}
}
-
- [Fact]
- public void TestRunspaceSetBreakpoints()
- {
- using (var runspace = RunspaceFactory.CreateRunspace())
- {
- var expectedBreakpoints = new Breakpoint[] {
- new LineBreakpoint(@"./path/to/some/file.ps1", 1),
- new CommandBreakpoint(@"./path/to/some/file.ps1", new WildcardPattern("Write-Host"), "Write-Host"),
- };
-
- runspace.Open();
-
- try
- {
- runspace.Debugger.SetBreakpoints(expectedBreakpoints);
- List actualBreakpoints = runspace.Debugger.GetBreakpoints();
- Assert.Equal(expectedBreakpoints.Length, actualBreakpoints.Count);
- Assert.Equal(expectedBreakpoints, actualBreakpoints);
- }
- finally
- {
- runspace.Close();
- }
- }
- }
}
}