diff --git a/src/System.Management.Automation/engine/ArgumentTypeConverterAttribute.cs b/src/System.Management.Automation/engine/ArgumentTypeConverterAttribute.cs
index 19c383e6cd..746d2f82df 100644
--- a/src/System.Management.Automation/engine/ArgumentTypeConverterAttribute.cs
+++ b/src/System.Management.Automation/engine/ArgumentTypeConverterAttribute.cs
@@ -147,15 +147,14 @@ namespace System.Management.Automation
// Note - this is duplicated in ExecutionContext.cs as parameter binding for script cmdlets can avoid this code path.
if ((!bindingScriptCmdlet) && (!bindingParameters))
{
- // ActionPreference of Suspend is not supported as a preference variable. We can only block "Suspend"
- // during variable assignment (here) - "Ignore" is blocked during variable retrieval.
+ // ActionPreference.Suspend is reserved for future use and is not supported as a preference variable.
if (_convertTypes[i] == typeof(ActionPreference))
{
ActionPreference resultPreference = (ActionPreference)result;
if (resultPreference == ActionPreference.Suspend)
{
- throw new PSInvalidCastException("InvalidActionPreference", null, ErrorPackage.UnsupportedPreferenceVariable, resultPreference);
+ throw new PSInvalidCastException("InvalidActionPreference", null, ErrorPackage.ActionPreferenceReservedForFutureUseError, resultPreference);
}
}
}
diff --git a/src/System.Management.Automation/engine/CommandBase.cs b/src/System.Management.Automation/engine/CommandBase.cs
index 8848d86f3d..b2351059cc 100644
--- a/src/System.Management.Automation/engine/CommandBase.cs
+++ b/src/System.Management.Automation/engine/CommandBase.cs
@@ -291,7 +291,7 @@ namespace System.Management.Automation
/// Ignore the event completely (not even logging it to the target stream)
Ignore = 4,
- /// Suspend the command for further diagnosis. Supported only for workflows.
+ /// Reserved for future use.
Suspend = 5,
/// Enter the debugger.
diff --git a/src/System.Management.Automation/engine/ExecutionContext.cs b/src/System.Management.Automation/engine/ExecutionContext.cs
index 45cb3bd7fa..ac6fea07a0 100644
--- a/src/System.Management.Automation/engine/ExecutionContext.cs
+++ b/src/System.Management.Automation/engine/ExecutionContext.cs
@@ -573,18 +573,9 @@ namespace System.Management.Automation
object val = EngineSessionState.GetVariableValue(preferenceVariablePath, out _, out _);
if (val is T)
{
- // We don't want to support "Ignore" as action preferences, as it leads to bad
- // scripting habits. They are only supported as cmdlet overrides.
- if (val is ActionPreference)
+ if (val is ActionPreference actionPreferenceValue)
{
- ActionPreference preference = (ActionPreference)val;
- if ((preference == ActionPreference.Ignore) || (preference == ActionPreference.Suspend))
- {
- // Reset the variable value
- EngineSessionState.SetVariableValue(preferenceVariablePath.UserPath, defaultPref);
- string message = StringUtil.Format(ErrorPackage.UnsupportedPreferenceError, preference);
- throw new NotSupportedException(message);
- }
+ CheckActionPreference(preferenceVariablePath, actionPreferenceValue, defaultPref);
}
T convertedResult = (T)val;
@@ -611,6 +602,11 @@ namespace System.Management.Automation
result = (T)PSObject.Base(val);
defaultUsed = false;
}
+
+ if (result is ActionPreference actionPreferenceValue)
+ {
+ CheckActionPreference(preferenceVariablePath, actionPreferenceValue, defaultPref);
+ }
}
catch (InvalidCastException)
{
@@ -625,6 +621,18 @@ namespace System.Management.Automation
return result;
}
+ private void CheckActionPreference(VariablePath preferenceVariablePath, ActionPreference preference, object defaultValue)
+ {
+ if (preference == ActionPreference.Suspend)
+ {
+ // ActionPreference.Suspend is reserved for future use. When it is used, reset
+ // the variable to its default.
+ string message = StringUtil.Format(ErrorPackage.ReservedActionPreferenceReplacedError, preference, preferenceVariablePath.UserPath, defaultValue);
+ EngineSessionState.SetVariable(preferenceVariablePath, defaultValue, true, CommandOrigin.Internal);
+ throw new NotSupportedException(message);
+ }
+ }
+
///
/// Same as GetEnumPreference, but for boolean values.
///
diff --git a/src/System.Management.Automation/engine/MshCommandRuntime.cs b/src/System.Management.Automation/engine/MshCommandRuntime.cs
index 07208dc343..f9e4b6bae6 100644
--- a/src/System.Management.Automation/engine/MshCommandRuntime.cs
+++ b/src/System.Management.Automation/engine/MshCommandRuntime.cs
@@ -3009,6 +3009,11 @@ namespace System.Management.Automation
set
{
+ if (value == ActionPreference.Suspend)
+ {
+ throw PSTraceSource.NewNotSupportedException(ErrorPackage.ActionPreferenceReservedForFutureUseError, value);
+ }
+
_debugPreference = value;
_isDebugPreferenceSet = true;
}
@@ -3098,7 +3103,7 @@ namespace System.Management.Automation
{
if (value == ActionPreference.Suspend)
{
- throw PSTraceSource.NewNotSupportedException(ErrorPackage.SuspendActionPreferenceErrorActionOnly);
+ throw PSTraceSource.NewNotSupportedException(ErrorPackage.ActionPreferenceReservedForFutureUseError, value);
}
_warningPreference = value;
@@ -3268,7 +3273,7 @@ namespace System.Management.Automation
{
if (value == ActionPreference.Suspend)
{
- throw PSTraceSource.NewNotSupportedException(ErrorPackage.SuspendActionPreferenceSupportedOnlyOnWorkflow);
+ throw PSTraceSource.NewNotSupportedException(ErrorPackage.ActionPreferenceReservedForFutureUseError, value);
}
_errorAction = value;
@@ -3301,6 +3306,11 @@ namespace System.Management.Automation
set
{
+ if (value == ActionPreference.Suspend)
+ {
+ throw PSTraceSource.NewNotSupportedException(ErrorPackage.ActionPreferenceReservedForFutureUseError, value);
+ }
+
_progressPreference = value;
_isProgressPreferenceSet = true;
}
@@ -3335,7 +3345,7 @@ namespace System.Management.Automation
{
if (value == ActionPreference.Suspend)
{
- throw PSTraceSource.NewNotSupportedException(ErrorPackage.SuspendActionPreferenceErrorActionOnly);
+ throw PSTraceSource.NewNotSupportedException(ErrorPackage.ActionPreferenceReservedForFutureUseError, value);
}
_informationPreference = value;
diff --git a/src/System.Management.Automation/resources/ErrorPackage.resx b/src/System.Management.Automation/resources/ErrorPackage.resx
index 49d1e8c2fc..04c0467ba7 100644
--- a/src/System.Management.Automation/resources/ErrorPackage.resx
+++ b/src/System.Management.Automation/resources/ErrorPackage.resx
@@ -126,18 +126,13 @@
Object "{0}" is reported as an error.
-
- The action preference of "Suspend" is supported only for ErrorAction.
- "Suspend" and ErrorAction should not be localized
-
-
- The error action preference of "Suspend" is supported only on workflows.
- "Suspend" should not be localized - it is a literal.
-
The value {0} is not supported for an ActionPreference variable. The provided value should be used only as a value for a preference parameter, and has been replaced by the default value. For more information, see the Help topic, "about_Preference_Variables."
-
- The value {0} is not supported for an ActionPreference variable. The provided value should be used only as a value for a preference parameter. For more information, see the Help topic, "about_Preference_Variables."
+
+ The {0} ActionPreference value is reserved for future use and is not supported at this time. For more information about preference variables, see the Help topic, "about_Preference_Variables."
+
+
+ The {0} ActionPreference value is reserved for future use and is not supported at this time. It has been replaced in your {1} variable by the default value of {2}. For more information about preference variables, see the Help topic, "about_Preference_Variables."
diff --git a/test/powershell/Language/Scripting/ActionPreference.Tests.ps1 b/test/powershell/Language/Scripting/ActionPreference.Tests.ps1
index 3cc2e0337c..3b8fb8e9ac 100644
--- a/test/powershell/Language/Scripting/ActionPreference.Tests.ps1
+++ b/test/powershell/Language/Scripting/ActionPreference.Tests.ps1
@@ -2,119 +2,190 @@
# Licensed under the MIT License.
Describe "Tests for (error, warning, etc) action preference" -Tags "CI" {
- BeforeAll {
- $orgin = $GLOBAL:errorActionPreference
+ $commonActionPreferenceParameterTestCases = foreach ($commonParameterName in [System.Management.Automation.Cmdlet]::CommonParameters | Select-String Action) {
+ @{
+ ActionPreferenceParameterName = $commonParameterName
}
+ }
- AfterAll {
- if ($GLOBAL:errorActionPreference -ne $orgin)
- {
- $GLOBAL:errorActionPreference = $orgin
+ $actionPreferenceVariableTestCases = foreach ($variable in Get-Variable -Name *Preference -Scope Global | Where-Object Value -Is [System.Management.Automation.ActionPreference]) {
+ @{
+ ActionPreferenceVariableName = $variable.Name
+ StreamName = $variable.Name -replace '(Action)?Preference$'
+ }
+ }
+
+ $actionPreferenceVariableValueTestCases = @(
+ @{
+ Value = [System.Management.Automation.ActionPreference]::Suspend
+ DisplayValue = '[System.Management.Automation.ActionPreference]::Suspend'
+ }
+ @{
+ Value = 'Suspend'
+ DisplayValue = '''Suspend'''
+ }
+ )
+
+ BeforeAll {
+ $orgin = $GLOBAL:errorActionPreference
+
+ function Join-TestCase {
+ [OutputType([Hashtable[]])]
+ [CmdletBinding()]
+ param(
+ [Hashtable[]]$Set1,
+ [Hashtable[]]$Set2
+ )
+ foreach ($ht1 in $Set1) {
+ foreach ($ht2 in $Set2) {
+ $ht1 + $ht2
+ }
}
}
- Context 'Setting ErrorActionPreference to stop prevents user from getting the error exception' {
- $err = $null
- try
- {
- get-childitem nosuchfile.nosuchextension -ErrorAction stop -ErrorVariable err
+
+ function Test-ActionPreferenceVariableSuspendValue {
+ [CmdletBinding()]
+ param(
+ $Value
+ )
+ if ($DebugPreference -eq $Value) {
+ Write-Debug -Message 'A debug message'
+ } elseif ($ErrorActionPreference -eq $Value) {
+ Write-Error -Message 'An error message'
+ } elseif ($InformationPreference -eq $Value) {
+ Write-Information -MessageData 'Some information'
+ } elseif ($ProgressPreference -eq $Value) {
+ Write-Progress -Activity 'Some progress'
+ } elseif ($VerbosePreference -eq $Value) {
+ Write-Verbose -Message 'A verbose message'
+ } elseif ($WarningPreference -eq $Value) {
+ Write-Warning -Message 'A warning message'
}
- catch {}
-
- It '$err.Count' { $err.Count | Should -Be 1 }
- It '$err[0] should not be $null' { $err[0] | Should -Not -BeNullOrEmpty }
- It '$err[0].GetType().Name' { $err[0] | Should -BeOfType "System.Management.Automation.ActionPreferenceStopException" }
- It '$err[0].ErrorRecord' { $err[0].ErrorRecord | Should -Not -BeNullOrEmpty }
- It '$err[0].ErrorRecord.Exception.GetType().Name' { $err[0].ErrorRecord.Exception | Should -BeOfType "System.Management.Automation.ItemNotFoundException" }
}
+ }
- It 'ActionPreference Ignore Works' {
- $errorCount = $error.Count
- Get-Process -Name asdfasdfsadfsadf -ErrorAction Ignore
-
- $error.Count | Should -BeExactly $errorCount
- }
-
- It 'action preference of Ignore cannot be set as a preference variable' {
- $e = {
- $GLOBAL:errorActionPreference = "Ignore"
- Get-Process -Name asdfasdfasdf
- } | Should -Throw -ErrorId 'System.NotSupportedException' -PassThru
- $e.CategoryInfo.Reason | Should -BeExactly 'NotSupportedException'
-
+ AfterAll {
+ if ($GLOBAL:errorActionPreference -ne $orgin) {
$GLOBAL:errorActionPreference = $orgin
}
+ }
- It 'action preference of Suspend cannot be set as a preference variable' {
- $e = {
- $GLOBAL:errorActionPreference = "Suspend"
- Get-Process -Name asdfasdfasdf
- } | Should -Throw -ErrorId 'RuntimeException' -PassThru
- $e.CategoryInfo.Reason | Should -BeExactly 'ArgumentTransformationMetadataException'
+ Context 'Setting ErrorActionPreference to stop prevents user from getting the error exception' {
+ $err = $null
+ try {
+ Get-ChildItem nosuchfile.nosuchextension -ErrorAction stop -ErrorVariable err
+ } catch { }
- $GLOBAL:errorActionPreference = $orgin
- }
+ It '$err.Count' { $err.Count | Should -Be 1 }
+ It '$err[0] should not be $null' { $err[0] | Should -Not -BeNullOrEmpty }
+ It '$err[0].GetType().Name' { $err[0] | Should -BeOfType "System.Management.Automation.ActionPreferenceStopException" }
+ It '$err[0].ErrorRecord' { $err[0].ErrorRecord | Should -Not -BeNullOrEmpty }
+ It '$err[0].ErrorRecord.Exception.GetType().Name' { $err[0].ErrorRecord.Exception | Should -BeOfType "System.Management.Automation.ItemNotFoundException" }
+ }
- It 'enum disambiguation works' {
+ It 'Action preference of Ignore can be set as a preference variable using a string value' {
+ try {
+ Remove-Variable -Name ErrorActionPreference -Scope Global -Force
+ $GLOBAL:ErrorActionPreference = 'Ignore'
$errorCount = $error.Count
- Get-Process -Name asdfasdfsadfsadf -ErrorAction Ig
-
+ Get-Process -Name asdfasdfasdf
$error.Count | Should -BeExactly $errorCount
+ } finally {
+ Remove-Variable -Name ErrorActionPreference -Scope Global
+ # Re-create the action preference variable as a strongly typed variable like it was before
+ [System.Management.Automation.ActionPreference]$GLOBAL:ErrorActionPreference = $orgin
+ }
+ }
+
+ It 'Action preference of Ignore can be set as a preference variable using an enumerated value' {
+ try {
+ $GLOBAL:ErrorActionPreference = [System.Management.Automation.ActionPreference]::Ignore
+ $errorCount = $error.Count
+ Get-Process -Name asdfasdfasdf
+ $error.Count | Should -BeExactly $errorCount
+ } finally {
+ $GLOBAL:ErrorActionPreference = $orgin
+ }
+ }
+
+ It 'The $global: variable does not support Suspend' -TestCases $actionPreferenceVariableTestCases {
+ param($ActionPreferenceVariableName)
+
+ $e = {
+ Set-Variable -Name $ActionPreferenceVariableName -Scope Global -Value ([System.Management.Automation.ActionPreference]::Suspend)
+ } | Should -Throw -ErrorId RuntimeException -PassThru
+
+ $e.CategoryInfo.Reason | Should -BeExactly 'ArgumentTransformationMetadataException'
+ }
+
+ It 'A local $ variable does not support ' -TestCases (Join-TestCase -Set1 $actionPreferenceVariableTestCases -Set2 $actionPreferenceVariableValueTestCases) {
+ param(
+ $ActionPreferenceVariableName,
+ $StreamName,
+ $Value,
+ $DisplayValue
+ )
+
+ $e = {
+ Set-Variable -Name $ActionPreferenceVariableName -Value $Value
+ Test-ActionPreferenceVariableSuspendValue -Value $Value
+ } | Should -Throw -ErrorId "System.NotSupportedException$(if ($StreamName -ne 'Error') {",Microsoft.PowerShell.Commands.Write${StreamName}Command"})" -PassThru
+
+ $e.CategoryInfo.Reason | Should -BeExactly 'NotSupportedException'
+ }
+
+ It 'enum disambiguation works' {
+ $errorCount = $error.Count
+ Get-Process -Name asdfasdfsadfsadf -ErrorAction Ig
+
+ $error.Count | Should -BeExactly $errorCount
+ }
+
+ #issue 2076
+ It 'The - common parameter does not support Suspend on cmdlets' -TestCases $commonActionPreferenceParameterTestCases {
+ param($ActionPreferenceParameterName)
+
+ $commonParameters = @{
+ "${ActionPreferenceParameterName}" = [System.Management.Automation.ActionPreference]::Suspend
}
- It 'ErrorAction = Suspend works on Workflow' -Skip:$IsCoreCLR {
- . .\TestsOnWinFullOnly.ps1
- Run-TestOnWinFull "ActionPreference:ErrorAction=SuspendOnWorkflow"
+ { Write-Output -InputObject Test @commonParameters } | Should -Throw -ErrorId "ParameterBindingFailed,Microsoft.PowerShell.Commands.WriteOutputCommand"
+ }
+
+ It 'The - common parameter does not support Suspend on functions' -TestCases $commonActionPreferenceParameterTestCases {
+ param($ActionPreferenceParameterName)
+
+ function MyHelperFunction {
+ [CmdletBinding()]
+ param()
+ "Hello"
}
- It 'ErrorAction = Suspend does not work on functions' {
- function MyHelperFunction {
- [CmdletBinding()]
- param()
- "Hello"
- }
-
- { MyHelperFunction -ErrorAction Suspend } | Should -Throw -ErrorId "ParameterBindingFailed,MyHelperFunction"
+ $commonParameters = @{
+ "${ActionPreferenceParameterName}" = [System.Management.Automation.ActionPreference]::Suspend
}
- It 'ErrorAction = Suspend does not work on cmdlets' {
- { Get-Process -ErrorAction Suspend } | Should -Throw -ErrorId "ParameterBindingFailed,Microsoft.PowerShell.Commands.GetProcessCommand"
- }
-
- It 'WarningAction = Suspend does not work' {
- { Get-Process -WarningAction Suspend } | Should -Throw -ErrorId "ParameterBindingFailed,Microsoft.PowerShell.Commands.GetProcessCommand"
- }
-
- #issue 2076
- It 'ErrorAction and WarningAction are the only action preferences do not support suspend' -Pending{
- $params = [System.Management.Automation.Internal.CommonParameters].GetProperties().Name | Select-String Action
-
- $suspendErrors = $null
- $num=0
-
- $params | ForEach-Object {
- $input=@{'InputObject' = 'Test';$_='Suspend'}
- { Write-Output @input } | Should -Throw -ErrorId "ParameterBindingFailed,Microsoft.PowerShell.Commands.WriteOutputCommand"
- }
- }
-
- It ' does not take precedence over $ErrorActionPreference' -TestCases @(
- @{switch="Verbose"},
- @{switch="Debug"}
- ) {
- param($switch)
- $ErrorActionPreference = "SilentlyContinue"
- $params = @{
- ItemType = "File";
- Path = "$testdrive\test.txt";
- Confirm = $false
- }
- New-Item @params > $null
- $params += @{$switch=$true}
- { New-Item @params } | Should -Not -Throw
- $ErrorActionPreference = "Stop"
- { New-Item @params } | Should -Throw -ErrorId "NewItemIOError,Microsoft.PowerShell.Commands.NewItemCommand"
- Remove-Item "$testdrive\test.txt" -Force
+ { MyHelperFunction -ErrorAction Suspend } | Should -Throw -ErrorId "ParameterBindingFailed,MyHelperFunction"
+ }
+
+ It ' does not take precedence over $ErrorActionPreference' -TestCases @(
+ @{switch = "Verbose" },
+ @{switch = "Debug" }
+ ) {
+ param($switch)
+ $ErrorActionPreference = "SilentlyContinue"
+ $params = @{
+ ItemType = "File";
+ Path = "$testdrive\test.txt";
+ Confirm = $false
}
+ New-Item @params > $null
+ $params += @{$switch = $true }
+ { New-Item @params } | Should -Not -Throw
+ $ErrorActionPreference = "Stop"
+ { New-Item @params } | Should -Throw -ErrorId "NewItemIOError,Microsoft.PowerShell.Commands.NewItemCommand"
+ Remove-Item "$testdrive\test.txt" -Force
+ }
}
Describe 'ActionPreference.Break tests' -tag 'CI' {