Powershell: Modifying AllScope variable in "global" SessionState affects module but not vice versa

Created on 13 Mar 2018  路  4Comments  路  Source: PowerShell/PowerShell

This behavior is surprising to me. I'm not sure if it is as intended, as neither the documentation for ScopedItemOptions nor about_Scopes seem to contemplate the behavior of AllScope variables in the context of multiple SessionStates.

Steps to reproduce

$m = New-Module {}
Set-Variable v -Value 'v.1' -Option AllScope

& $m { $v }
& $m { $v = 'v.2'; $v }
$v
& {
    $v = 'v.3'
}
$v
& $m { $v }

Expected behavior

I expected that

either there really is only one $v and the output is

v.1
v.2
v.2
v.3
v.3

or, there are two $v that are really unrelated and the output is

v.1
v.2
v.1
v.3
v.2

Actual behavior

The actual behavior seems to be consistent with two $v that are sort-of related.

v.1
v.2
v.1
v.3
v.3

Environment data

> $PSVersionTable

Name                           Value                                            
----                           -----                                            
PSVersion                      6.0.0                                            
PSEdition                      Core                                             
GitCommitId                    v6.0.0                                           
OS                             Microsoft Windows 6.3.9600                       
Platform                       Win32NT                                          
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                          
PSRemotingProtocolVersion      2.3                                              
SerializationVersion           1.1.0.1                                          
WSManStackVersion              3.0                                              
Issue-Bug WG-Engine

All 4 comments

The expected behaviour is that an AllScope variable be the same PSVariable object in all child scopes, module or not. The current behaviour is a bug.

Ideally, the rollout of this fix would occur after Pester/Pester#1007 is fixed. I _think_ fixing this without fixing Pester/Pester#1007 would break all Pester tests involving mocks of commands whose parameters conflict with AllScope variables that are Constant or ReadOnly. Get-Module is the most obvious affected command. Currently, mocking Get-Module inside a module using Pester works because of this bug.

@BrucePay

The expected behaviour is that an AllScope variable be the same PSVariable object in all child scopes, module or not. The current behaviour is a bug.

Does that applied to scopes which existed before AllScope variables was created in some parent to them scope?

& {
    & {
        sv a 1 -Scope 1 -Option AllScope
        $a = 2
        gv a -Scope 1 -ValueOnly
        $a
        [object]::ReferenceEquals((gv a),(gv a -Scope 1))
    }
    & {
        $a = 3
        gv a -Scope 1 -ValueOnly
        $a
        [object]::ReferenceEquals((gv a), (gv a -Scope 1))
    }
}

Current behavior is that only new created scopes inherit AllScope variable from its parent scope.

I have experienced a similar, related bug when putting the call to Invoke-Pester into a function of a psm1 module broke PSSA tests. Examples were:

  • $error[0] was not defined any more in the local scope (I replaced it with $_ to fix it):
    powershell try { CmdletThatThrows-NonTerminatingError -ErrorAction stop } catch { $Error[0].FullyQualifiedErrorId | Should -Match $expectedFullyQualfiedErrorId }
  • Then I had tests that were testing that Set-Variable of a read-only automatic variable is throwing a non-terminating error. This did not work for some automatic variables such as e.g. PSVersionTable, therfore I had to change it to use global scope when setting the variable.
Was this page helpful?
0 / 5 - 0 ratings