我遇到了powershell代码中最奇怪的问题。
我有两个文件,A.ps1和B.ps1。B包含非常简单的代码,它将环境映射到一周中的几天,然后使用当前环境来获得正确的几天:
$LocationA.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包含:
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 }
}
}
由于我当前的env是[CurrentEnv]::LOCAL
,所以$activatedWeekdayNums
应该是列表@(0, 1, 2, 3, 4, 5, 6)
。但事实并非如此!是$null
。经过大量挖掘,我发现了原因。
当我在文件中定义并调用Detect-Environment
时,代码运行良好。但是,当我在另一个名为A.ps1
的文件中定义Detect-Environment
,然后用. $LocationA.ps1
导入它时,它不起作用,即使$currentEnv
说它等于[CurrentEnv]::LOCAL
。事实上,如果我比较通过将$currentEnv1
(局部函数(与$currentEnv2
(导入函数(相等而获得的变量,则$currentEnv2 -eq $currentEnv
返回True。但与CCD_ 14的结果不同。完全困惑。
感谢您的帮助!很乐意提供更多上下文/代码。
编辑:$currentEnv1.GetType()
等于:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True CurrentEnv System.Enum
$currentEnv2.GetType()
等于相同的东西:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True CurrentEnv System.Enum
第2版:为了添加更多信息,即使我使用$activatedEnvsAndWeekdays[[CurrentCinchyEnv]::LOCAL]
(因此我根本不使用$currentEnv
(,在导入Detect-Environment
和enum CurrentCinchyEnv
时也不会返回任何信息。
按照评论中的要求发布此答案。对于想知道如何重现这个错误(?(的人来说,这里有一个可重现的最小示例。
-
script1.ps1
enum TestEnum {
Test
}
$key = . .script2.ps1
$map = @{ [TestEnum]::Test = 'hello' }
$map[$key]
script2.ps1
[TestEnum]::Test
如果我们试图在干净的PS会话中运行script1.ps1
,我们应该得到正确的值hello
。但是,任何后续对script1.ps1
的更新(必须是定义enum
的.ps1
(都将导致PowerShell发出一个同名的新类型:
PS /> [AppDomain]::CurrentDomain.GetAssemblies().GetTypes() |
Where-Object Name -EQ TestEnum
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True TestEnum System.Enum
True True TestEnum System.Enum
还有一个更新的组装版本:
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
值得注意的是,这只会在处理代码时影响我们,但错误不应在干净的会话中重现,换句话说,如果您希望在hashtable
上使用引用类型密钥,并且可以忍受每次更新代码时都必须重新启动PowerShell会话,那么在运行时应该可以。
作为个人建议,我会使用字符串作为哈希表键来避免这种情况
作为解决方法,转换类型应在不需要重新启动会话的情况下解决问题:
$map[[TestEnum] $keyEnum]