Windows PowerShell 5.1无法用using module导入本地模块,Pwsh7可正常运行
using module导入.psm1文件失败的解决方法 问题背景
我的项目目录结构如下:
└─ScriptModuleRepositoryTemplate │ ScriptModuleRepositoryTemplate.psd1 │ ScriptModuleRepositoryTemplate.psm1 │ ScriptModuleRepositoryTemplate.Tests.ps1
在测试文件ScriptModuleRepositoryTemplate.Tests.ps1顶部,我使用以下语句导入模块:
using module './ScriptModuleRepositoryTemplate.psm1'
该语句在PowerShell 7中能正常导入模块,Pester测试运行无误,但在Windows PowerShell 5.1中抛出错误:
System.IO.FileNotFoundException: The specified module 'D:\a\PowerShell.ScriptModuleRepositoryTemplate\PowerShell.ScriptModuleRepositoryTemplate\ScriptModuleRepositoryTemplate.psm1' was not loaded because no valid module file was found in any module directory.
若改用Import-Module:
Import-Module -Name "$PSScriptRoot/ScriptModuleRepositoryTemplate.psm1"
虽然能在两个PowerShell版本中正常运行,但Import-Module无法导入模块中的类和枚举,因此必须使用using module。
注:两个PowerShell版本均使用Pester v5.5.0,本地运行Invoke-Pester .和GitHub Actions均可复现问题。
原因分析
Windows PowerShell 5.1与PowerShell 7对using module的相对路径解析逻辑存在差异:
- PowerShell 7:相对路径基于测试脚本所在目录解析
- Windows PowerShell 5.1:相对路径基于当前工作目录解析
如果运行测试时当前工作目录与测试脚本所在目录不一致,就会出现文件找不到的错误。
解决方法
方法1:通过模块清单(.psd1)导入模块
将测试文件中的using module语句改为指向模块清单文件:
using module './ScriptModuleRepositoryTemplate.psd1'
确保.psd1文件中的RootModule字段正确指向你的.psm1文件:
RootModule = 'ScriptModuleRepositoryTemplate.psm1'
这种方法能在两个PowerShell版本中正常工作,同时支持导入类和枚举,是最优解。
方法2:确保运行测试时的工作目录是脚本所在目录
调用Invoke-Pester时指定工作目录为测试脚本所在目录:
Invoke-Pester -Path .\ScriptModuleRepositoryTemplate.Tests.ps1 -WorkingDirectory $PSScriptRoot
如果是在GitHub Actions中,先切换到模块目录再执行测试:
steps: - name: 运行Pester测试 shell: pwsh run: | cd ./ScriptModuleRepositoryTemplate Invoke-Pester .
方法3:使用绝对路径导入(不推荐)
由于using module必须放在脚本最顶部,无法直接使用$PSScriptRoot变量,可通过生成临时脚本间接使用绝对路径,但该方法繁琐且维护性差,仅作为备选:
# 测试脚本最顶部 $modulePath = Join-Path -Path $PSScriptRoot -ChildPath 'ScriptModuleRepositoryTemplate.psm1' $tempScriptPath = Join-Path -Path $env:TEMP -ChildPath 'TempModuleImport.ps1' "using module '$modulePath'" | Out-File -Path $tempScriptPath -Encoding utf8 . $tempScriptPath Remove-Item -Path $tempScriptPath -Force
内容的提问来源于stack exchange,提问作者deadlydog

