为什么通过模块清单ScriptsToProcess运行脚本会取消定义$LASTEXITCODE?
我有如下在模块清单文件中使用ScriptsToProcess指令的PowerShell模块:
test-lstExtCode.psd1文件内容:
@{ RootModule = 'test-lstExtCod.psm1' ModuleVersion = '0.1' FunctionsToExport = @( 'get-importDate' ) ScriptsToProcess = @( 'write-import-date.ps1' ) }
模块主体test-lstExtCod.psm1的内容如下:
set-strictMode -version 3 function get-importDate { get-content $psScriptRoot/import-date }
write-import-date.ps1的内容如下:
set-strictMode -version 3 get-date > $psScriptRoot/import-date
导入该模块或者调用get-importDate会出现全局变量$LASTEXITCODE未定义的报错,测试现象如下:
PS> $LASTEXITCODE -eq $null True PS> get-importDate Thursday, July 29, 2021 9:55:16 PM PS> $LASTEXITCODE -eq $null The variable '$LASTEXITCODE' cannot be retrieved because it has not been set. At line:1 char:1 + $LASTEXITCODE -eq $null + ~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (LASTEXITCODE:String) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : VariableIsUndefined
我不清楚是什么原因导致$LASTEXITCODE被取消定义。如果我注释掉ScriptsToProcess指令,该现象就会消失,导入模块后$LASTEXITCODE仍为已定义状态。
根因说明
这个现象不是$LASTEXITCODE被取消定义,而是全局严格模式被意外修改导致的表现差异:
- PowerShell默认关闭严格模式,此时访问未定义的变量会直接返回
$null,不会抛出错误。测试初始阶段$LASTEXITCODE本身就不存在(只有运行过外部可执行程序后这个变量才会被自动赋值),此时访问返回$null,所以$LASTEXITCODE -eq $null结果为True。 - 模块清单中
ScriptsToProcess指定的脚本会在导入模块的会话的全局作用域直接执行,不会被模块私有作用域隔离。write-import-date.ps1中执行的Set-StrictMode -Version 3会直接修改全局会话的严格模式配置。 - 严格模式V3及以上要求所有变量必须先定义才能访问,此时再访问本身就不存在的
$LASTEXITCODE,就会抛出变量未定义的错误,看起来就像该变量被删除了一样。 - 注释
ScriptsToProcess后问题消失的原因是:模块主.psm1文件中的Set-StrictMode运行在模块隔离作用域内,不会污染全局会话的严格模式配置,全局仍然保持严格模式关闭的默认状态,访问未定义变量不会报错。
修复方案
- 移除
write-import-date.ps1中的Set-StrictMode语句,若确实需要在该脚本中使用严格模式,可在脚本执行末尾显式恢复全局严格模式为之前的状态。 - 将写入导入时间的逻辑直接迁移到
.psm1文件的顶层执行,模块内部的严格模式配置不会影响全局会话。 - 若需要保留全局严格模式,后续访问
$LASTEXITCODE前先通过Test-Path variable:LASTEXITCODE判断变量是否存在,避免直接访问未定义变量报错。
内容的提问来源于stack exchange,提问作者René Nyffenegger
相关产品推荐
相关产品推荐

