gpt4 book ai didi

powershell - 在 psm1 模块内的导入模块上使用 'hiding' 时绕过 PowerShell 模块 '-Force'

转载 作者:行者123 更新时间:2023-12-04 17:21:22 25 4
gpt4 key购买 nike

上下文/设置

我正在开发一个相当大的构建自动化工具,它由 90% 的 PowerShell 代码组成。

许多功能都分组在 .psm1 文件中,这些文件通过使用相互加载

导入模块“$PSScriptRoot/AnotherModule.psm1”-Force

这似乎是开发目的/测试代码等的好主意,但我最近偶然发现这种方法存在问题。

发现/问题

每当加载的模块强制导入之前已加载到父/外部作用域中的另一个模块时,它不再可在此父/外部作用域中访问

现在我遇到了一个问题,在脚本开头导入所需的模块并不能保证导入的模块在脚本执行期间实际可用,因为其中一个导入的模块可能会“隐藏”另一个先前加载的模块:-/

例子

假设我们有三个模块:ModA、ModB、ModC:

模组:

$ErrorActionPreference = "Stop"
Import-Module "$PSScriptRoot\ModB.psm1" -Force
// module A entrails

调制解调器:

$ErrorActionPreference = "Stop"
// module B entrails

国防部:

$ErrorActionPreference = "Stop"
Import-Module "$PSScriptRoot\ModA.psm1" -Force
// module C entrails

以下纠缠测试证明了这种“模块隐藏”行为:

Describe 'powershell module system tests' {

# ModA -> Import ModB -Force
# ModC -> Import ModA -Force
$mod_path = Join-Path $PSScriptRoot "testmod"
$mods = @("ModA", "ModB", "ModC")

It "cleanup leftovers from previous tests" {
Remove-Module $mods -ErrorAction SilentlyContinue
}

It 'is able to import ModA, which internally loads module B' {
Import-Module "$mod_path\ModA.psm1" -Force
Get-Module ModA | Should -Not -BeNullOrEmpty
Get-Module ModB | Should -BeNullOrEmpty
}

It 'is able to import a second module already imported by the first one' {
Get-Module ModA | Should -Not -BeNullOrEmpty
Import-Module "$mod_path\ModB.psm1" -Force
Get-Module ModB | Should -Not -BeNullOrEmpty
}

It 'still knows the first module' {
Get-Module ModA | Should -Not -BeNullOrEmpty
}

It 'is able to import a thid module that also imports the first one' {
Get-Module ModC | Should -BeNullOrEmpty
Import-Module "$mod_path\ModC.psm1" -Force
Get-Module ModC | Should -Not -BeNullOrEmpty
}

It 'does not know A or B any longer, as it has been hidden by C' {
Get-Module ModA | Should -BeNullOrEmpty
Get-Module ModB | Should -BeNullOrEmpty
}

It 'still knows C' {
Get-Module ModC | Should -Not -BeNullOrEmpty
}

It 'cleanup leftovers from this test' {
Remove-Module $mods
}
}

追踪错误

为了查明问题,我试图提出另一个测试代码库,并验证在导入另一个模块时没有从全局模块表中删除“已加载”模块:

Describe 'verify tool module system hierachy' {
$tool_modules = Get-ChildItem $script:engine_path -Filter "*.psm1"

function UNLoadAllToolModules {
Remove-Module 'Tool-*'
}
function LoadAllToolModules {
$tool_modules | Foreach-Object { Import-Module $_.FullName }
}

It "cleanup leftovers from previous tests" {
UNLoadAllToolModules
}

It "loading of a module does not hide an already loaded module" {
$errMods = $()
$tool_modules | ForEach-Object {
LoadAllToolModules
$pre = Get-Module
$mod = $_
Import-Module $mod.FullName -Force
$post = Get-Module
$mods = Compare-Object $post $pre | Select-Object -Expand InputObject | Select-Object -Expand Name
$mods | Foreach-Object {
"import of '$mod' hides '$_'" | Write-Host
}
if ($mods) {
$errMods += $mod.Name
}
}
$errMods | Should -BeNullOrEmpty
}
}

问题

有没有办法打印/调试全局模块表,如图所示here ,所以我可以弄清楚哪个模块被多次加载/模块树在导入后如何修改?

解决方案?

目前,解决这个“问题”的唯一方法(除此之外,在其他模块中强制导入模块可能是一个糟糕的设计选择)是放弃 -force 或使用 -global 每当在此构建自动化套件/工具中包含的模块上调用 Import-Module -Force 时。

最佳答案

我对此的回答很简单,但可能不适用于您的情况。

PowerShell 中的作用域相当简单。但是,当您开始尝试做这样的事情时,我只是建议您将所有内容加载到全局范围内并完成它。否则,你最终会经常追尾。

在最终用户机器上,使用全局范围是 Not Acceptable (无论如何对我来说)。在构建自动化系统上,使用全局范围可能是可以接受的,具体取决于您的情况,因为这就是它的全部用途。

如果您查看Import-Module cmdlet 的帮助,您会在-Global 参数下看到:

> [!TIP] > You should avoid calling `Import-Module` from within a module.
> Instead, declare the target module as a nested module in the parent module's manifest.
> Declaring nested modules improves the discoverability of dependencies.

The Global parameter is equivalent to the Scope parameter with a value of Global.

(我修正了格式,所以它在这里工作)。

此建议/提示也可能对您有用。

关于powershell - 在 psm1 模块内的导入模块上使用 'hiding' 时绕过 PowerShell 模块 '-Force',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66005926/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com