Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,8 @@ private void SetVariable(string[] varNames, object varValue)
if (ShouldProcess(target, action))
{
object result = null;
bool wasReadOnly = Force &&
(matchingVariable.Options & ScopedItemOptions.ReadOnly) != 0;

try
{
Expand All @@ -983,12 +985,9 @@ private void SetVariable(string[] varNames, object varValue)
// If we want to force setting over a readonly variable
// we have to temporarily mark the variable writable.

bool wasReadOnly = false;
if (Force &&
(matchingVariable.Options & ScopedItemOptions.ReadOnly) != 0)
if (wasReadOnly)
{
matchingVariable.SetOptions(matchingVariable.Options & ~ScopedItemOptions.ReadOnly, true);
wasReadOnly = true;
}

// Now change the value, options, or description
Expand Down Expand Up @@ -1036,6 +1035,11 @@ private void SetVariable(string[] varNames, object varValue)
}
catch (SessionStateException sessionStateException)
{
if (wasReadOnly)
{
matchingVariable.SetOptions(matchingVariable.Options | ScopedItemOptions.ReadOnly, true);
}

WriteError(
new ErrorRecord(
sessionStateException.ErrorRecord,
Expand All @@ -1044,6 +1048,11 @@ private void SetVariable(string[] varNames, object varValue)
}
catch (PSArgumentException argException)
{
if (wasReadOnly)
{
matchingVariable.SetOptions(matchingVariable.Options | ScopedItemOptions.ReadOnly, true);
}

WriteError(
new ErrorRecord(
argException.ErrorRecord,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,113 @@ Describe "Set-Variable DRT Unit Tests" -Tags "CI" {
{ Set-Variable abcaVar -Option None -Scope 1 -ErrorAction Stop } | Should -Throw -ErrorId "VariableNotWritable,Microsoft.PowerShell.Commands.SetVariableCommand"
}

# Issue #27679 cases 1 and 2 intentionally retain value mutation for backward compatibility.
It "Set-Variable preserves value mutation when setting Constant on an existing writable variable fails"{
$name = "SetVariableIssue27679Case1"

try
{
Set-Variable -Name $name -Value 1

$exception = $null
try
{
Set-Variable -Name $name -Value 2 -Option Constant -ErrorAction Stop
}
catch
{
$exception = $_
}

$exception | Should -Not -BeNullOrEmpty
$exception.FullyQualifiedErrorId | Should -BeExactly "VariableCannotBeMadeConstant,Microsoft.PowerShell.Commands.SetVariableCommand"

$var1 = Get-Variable -Name $name
$var1.Value | Should -Be 2
$var1.Options | Should -BeExactly "None"
}
finally
{
Remove-Variable -Name $name -Force -ErrorAction SilentlyContinue
}
}

It "Set-Variable preserves value mutation and restores ReadOnly when setting Constant fails with force"{
$name = "SetVariableIssue27679Case2"

try
{
Set-Variable -Name $name -Value 1 -Option ReadOnly

$exception = $null
try
{
Set-Variable -Name $name -Value 2 -Force -Option Constant -ErrorAction Stop
}
catch
{
$exception = $_
}

$exception | Should -Not -BeNullOrEmpty
$exception.FullyQualifiedErrorId | Should -BeExactly "VariableCannotBeMadeConstant,Microsoft.PowerShell.Commands.SetVariableCommand"

$var1 = Get-Variable -Name $name
$var1.Value | Should -Be 2
$var1.Options | Should -BeExactly "ReadOnly"
}
finally
{
Remove-Variable -Name $name -Force -ErrorAction SilentlyContinue
}
}

It "Set-Variable of ReadOnly variable with force preserves expected options when option update fails for <ExpectedOptions>" -TestCases @(
@{
Name = "SetVariableIssue27679Case3ReadOnly"
Options = [System.Management.Automation.ScopedItemOptions]::ReadOnly
ExpectedOptions = "ReadOnly"
}
@{
Name = "SetVariableIssue27679Case3ReadOnlyPrivate"
Options = [System.Management.Automation.ScopedItemOptions]::ReadOnly -bor [System.Management.Automation.ScopedItemOptions]::Private
ExpectedOptions = "ReadOnly, Private"
}
@{
Name = "SetVariableIssue27679Case3ReadOnlyAllScope"
Options = [System.Management.Automation.ScopedItemOptions]::ReadOnly -bor [System.Management.Automation.ScopedItemOptions]::AllScope
ExpectedOptions = "ReadOnly, AllScope"
}
) {
param($Name, $Options, $ExpectedOptions)

try
{
Set-Variable -Name $Name -Value 1 -Option $Options

$exception = $null
try
{
Set-Variable -Name $Name -Force -Option Constant -ErrorAction Stop
}
catch
{
$exception = $_
}

$exception | Should -Not -BeNullOrEmpty
$exception.FullyQualifiedErrorId | Should -BeExactly "VariableCannotBeMadeConstant,Microsoft.PowerShell.Commands.SetVariableCommand"

$var1 = Get-Variable -Name $Name
$var1.Value | Should -Be 1
$var1.Options.ToString() | Should -BeExactly $ExpectedOptions
}
finally
{
Remove-Variable -Name $Name -Force -ErrorAction SilentlyContinue
}
}

It "Set-Variable of ReadOnly variable with private scope should work"{
Set-Variable foo bar -Description "new description" -Option ReadOnly -Scope "private"
$var1=Get-Variable -Name foo
Expand Down