I'm encountering the strangest issue with powershell code.
I have 2 files, A.ps1 and B.ps1. B contains very simple code that maps environment to days of the week, and then uses the current environment to get the correct days:
$Location\A.ps1 # import Detect-Environment
$currentEnv = Detect-Environment
# 0 as Sunday, 6 as Saturday
$activatedEnvsAndWeekdays = @{
[CurrentEnv]::LOCAL = @(0, 1, 2, 3, 4, 5, 6)
[CurrentEnv]::DEV = @(0, 1, 2, 3, 4, 5, 6)
[CurrentEnv]::UAT = @()
[CurrentEnv]::PROD = @(1)
}
$activatedWeekdayNums = $activatedEnvsAndWeekdays[$currentEnv]
A.ps1 contains:
enum CurrentEnv {
LOCAL
DEV
UAT
PROD
}
function Detect-CinchyEnvironment {
$hostName = [System.Net.Dns]::GetHostName()
switch -Wildcard ($hostName) {
'*CINCHYPRD*' { [CurrentEnv]::PROD }
'*CINCHYUAT*' { [CurrentEnv]::UAT }
'*CINCHYDEV*' { [CurrentEnv]::DEV }
Default { [CurrentEnv]::LOCAL }
}
}
Since my current env is [CurrentEnv]::LOCAL
, $activatedWeekdayNums
should be the list @(0, 1, 2, 3, 4, 5, 6)
. But it's not! It's $null
. After much digging, I discovered why.
When I define and call Detect-Environment
from within my file, the code works fine. But when I define Detect-Environment
in another file called A.ps1
and then import it with . $Location\A.ps1
, it doesn't work, even though $currentEnv
says it's equal to [CurrentEnv]::LOCAL
. Indeed if I compare the variables obtained by equating$currentEnv1
(local function) to $currentEnv2
(imported function), $currentEnv2 -eq $currentEnv
return True. But the result with $activatedEnvsAndWeekdays
is different. Totally confused.
Any help is appreciated! Happy to provide more context/code.
EDIT:
$currentEnv1.GetType()
is equal to:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True CurrentEnv System.Enum
$currentEnv2.GetType()
is equal to the same thing:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True CurrentEnv System.Enum
EDIT2:
To add more info, even if I do $activatedEnvsAndWeekdays[[CurrentCinchyEnv]::LOCAL]
so I'm not using $currentEnv
at all, it doesn't return anything when Detect-Environment
and enum CurrentCinchyEnv
are imported.
CodePudding user response:
Posting this answer as was requested in comments. For anyone wondering how to reproduce this bug (?), here is a minimal reproducible example.
script1.ps1
enum TestEnum {
Test
}
$key = . .\script2.ps1
$map = @{ [TestEnum]::Test = 'hello' }
$map[$key]
script2.ps1
[TestEnum]::Test
If we attempt to run script1.ps1
in a clean PS session we should get the right value hello
, however, any subsequent update to script1.ps1
(has to be the .ps1
defining the enum
) will result in PowerShell emitting a new type with the same name:
PS /> [AppDomain]::CurrentDomain.GetAssemblies().GetTypes() |
Where-Object Name -EQ TestEnum
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True TestEnum System.Enum
True True TestEnum System.Enum
And a newer assembly version:
PS /> [AppDomain]::CurrentDomain.GetAssemblies().GetTypes() |
Where-Object Name -EQ TestEnum | ForEach-Object AssemblyQualifiedName
TestEnum, PowerShell Class Assembly, Version=1.0.0.2, Culture=neutral, PublicKeyToken=null
TestEnum, PowerShell Class Assembly, Version=1.0.0.3, Culture=neutral, PublicKeyToken=null
It's worth noting that this would only affect us while working on our code but the bug should not be reproducible on a clean session, in other words, if you wish to use reference type keys on your hashtable
and can bear with having to restart your PowerShell session on each update of your code then it should be fine during runtime.
As a personal recommendation, I would use strings as the hashtable keys to avoid this.
As workaround, casting the type should fix the issue without a need to restart the session:
$map[[TestEnum] $keyEnum]