mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Transition ActionPreference.Suspend enumeration value into a non-supported, reserved state, and remove restriction on using ActionPreference.Ignore in preference variables (#10317)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace System.Management.Automation
|
||||
/// <summary>Ignore the event completely (not even logging it to the target stream)</summary>
|
||||
Ignore = 4,
|
||||
|
||||
/// <summary>Suspend the command for further diagnosis. Supported only for workflows.</summary>
|
||||
/// <summary>Reserved for future use.</summary>
|
||||
Suspend = 5,
|
||||
|
||||
/// <summary>Enter the debugger.</summary>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as GetEnumPreference, but for boolean values.
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -126,18 +126,13 @@
|
||||
<data name="RedirectedException" xml:space="preserve">
|
||||
<value>Object "{0}" is reported as an error.</value>
|
||||
</data>
|
||||
<data name="SuspendActionPreferenceErrorActionOnly" xml:space="preserve">
|
||||
<value>The action preference of "Suspend" is supported only for ErrorAction.</value>
|
||||
<comment>"Suspend" and ErrorAction should not be localized</comment>
|
||||
</data>
|
||||
<data name="SuspendActionPreferenceSupportedOnlyOnWorkflow" xml:space="preserve">
|
||||
<value>The error action preference of "Suspend" is supported only on workflows.</value>
|
||||
<comment>"Suspend" should not be localized - it is a literal.</comment>
|
||||
</data>
|
||||
<data name="UnsupportedPreferenceError" xml:space="preserve">
|
||||
<value>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."</value>
|
||||
</data>
|
||||
<data name="UnsupportedPreferenceVariable" xml:space="preserve">
|
||||
<value>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."</value>
|
||||
<data name="ActionPreferenceReservedForFutureUseError" xml:space="preserve">
|
||||
<value>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."</value>
|
||||
</data>
|
||||
<data name="ReservedActionPreferenceReplacedError" xml:space="preserve">
|
||||
<value>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."</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -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:<ActionPreferenceVariableName> 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 $<ActionPreferenceVariableName> variable does not support <DisplayValue>' -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 -<ActionPreferenceParameterName> 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 -<ActionPreferenceParameterName> 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 '<switch> 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 '<switch> 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' {
|
||||
|
||||
Reference in New Issue
Block a user