如何在 powershell 模块中正确设置功能范围?
How to properly set function scope within a powershell module?
背景
我希望我所有的脚本和模块都基于一个模板脚本,该脚本负责一些常见的 "housekeeping" 任务。
我的一些模块是相互依赖的,所以我可能会在另一个模块中加载一个模块,即使是暂时的。
但是,由于代码是模板化的,所以基本的初始化函数具有相同的名称。
在我看来,只要我适当地确定范围,这就应该不是问题,但事实证明这是一个问题。
演示问题
下面的演示将有 1 个脚本,它加载一个模块,然后加载另一个模块。
每个模块都有加载模块时运行的初始化代码。
- 更新:更新了代码以更好地展示其结构的原因,尽管答案已被接受。
module.level2.psm1
# module.level2.psm1
# list of modules loaded by template code
$script:LoadModule = $null
# module housekeeping code - called from template code
function ModuleSpecificInitCode {
Write-Host "Level 2 Code"
}
function Level2ModuleFunction {
Write-Host "This is why I imported Level 2 module"
}
# module housekeeping code - template code
function TemplateInitCode {
Write-Host "Level 2 Init"
$LoadModule | % { Import-Module ".$_.psm1" }
}
TemplateInitCode
try {
ModuleSpecificInitCode
} catch {
# Error handling
}
module.level1.psm1
# module.level1.psm1
# list of modules loaded by template code
$script:LoadModule = "module.level2"
# module housekeeping code - called from template code
function ModuleSpecificInitCode {
Write-Host "Level 1 Code"
}
function Level1ModuleFunction {
Write-Host "This is why I imported Level 1 module"
}
# module housekeeping code - template code
function TemplateInitCode {
Write-Host "Level 1 Init"
$LoadModule | % { Import-Module ".$_.psm1" }
}
TemplateInitCode
try {
ModuleSpecificInitCode
} catch {
# Error handling
}
测试.ps1
# test.ps1
Remove-Module module.level*
Import-Module .\module.level1.psm1
当运行 test.ps1时,我收到的输出是:
PS>.\test.ps1
Level 1 Init
Level 2 Init
Level 2 Code
Level 2 Code
问题/我的问题
问题是最后一行。 2 级代码是 运行 而不是 1 级代码。
我已经尝试 local
、private
和 script
作为 <scope>:
,但无论我做什么,Level 1 Code
都无法运行。
我在这里遗漏了什么,为什么所有模块似乎都在同一个命名空间中 运行?
如果您没有显式地从模块中导出任何内容,则会全部导出。
如果您希望某个函数仅在模块内可用(将其视为私有函数,尽管它实际上与 PowerShell 中的 Private:
作用域无关),则只需导出除内部的。
Export-ModuleMember
是您定义要导出的内容的方式。它接受通配符,因此如果您可以用模式描述什么是 public,您可以在一次调用中完成,但可以根据需要多次调用它。
一旦函数不再被导出,它们就不能用于模块外的代码。
你的例子对我来说有点奇怪,因为你似乎想要访问模块外部的一些模块代码,但希望它们是同名的,但我不确定。
在那种情况下,例如,如果 Level1 init 应该调用 Level2 模块中的代码,您可能会考虑将 -Scope Local
添加到 Import-Module
调用本身,但我不确定这是否会帮助你的情况。
背景
我希望我所有的脚本和模块都基于一个模板脚本,该脚本负责一些常见的 "housekeeping" 任务。
我的一些模块是相互依赖的,所以我可能会在另一个模块中加载一个模块,即使是暂时的。
但是,由于代码是模板化的,所以基本的初始化函数具有相同的名称。 在我看来,只要我适当地确定范围,这就应该不是问题,但事实证明这是一个问题。
演示问题
下面的演示将有 1 个脚本,它加载一个模块,然后加载另一个模块。 每个模块都有加载模块时运行的初始化代码。
- 更新:更新了代码以更好地展示其结构的原因,尽管答案已被接受。
module.level2.psm1
# module.level2.psm1
# list of modules loaded by template code
$script:LoadModule = $null
# module housekeeping code - called from template code
function ModuleSpecificInitCode {
Write-Host "Level 2 Code"
}
function Level2ModuleFunction {
Write-Host "This is why I imported Level 2 module"
}
# module housekeeping code - template code
function TemplateInitCode {
Write-Host "Level 2 Init"
$LoadModule | % { Import-Module ".$_.psm1" }
}
TemplateInitCode
try {
ModuleSpecificInitCode
} catch {
# Error handling
}
module.level1.psm1
# module.level1.psm1
# list of modules loaded by template code
$script:LoadModule = "module.level2"
# module housekeeping code - called from template code
function ModuleSpecificInitCode {
Write-Host "Level 1 Code"
}
function Level1ModuleFunction {
Write-Host "This is why I imported Level 1 module"
}
# module housekeeping code - template code
function TemplateInitCode {
Write-Host "Level 1 Init"
$LoadModule | % { Import-Module ".$_.psm1" }
}
TemplateInitCode
try {
ModuleSpecificInitCode
} catch {
# Error handling
}
测试.ps1
# test.ps1
Remove-Module module.level*
Import-Module .\module.level1.psm1
当运行 test.ps1时,我收到的输出是:
PS>.\test.ps1
Level 1 Init
Level 2 Init
Level 2 Code
Level 2 Code
问题/我的问题
问题是最后一行。 2 级代码是 运行 而不是 1 级代码。
我已经尝试 local
、private
和 script
作为 <scope>:
,但无论我做什么,Level 1 Code
都无法运行。
我在这里遗漏了什么,为什么所有模块似乎都在同一个命名空间中 运行?
如果您没有显式地从模块中导出任何内容,则会全部导出。
如果您希望某个函数仅在模块内可用(将其视为私有函数,尽管它实际上与 PowerShell 中的 Private:
作用域无关),则只需导出除内部的。
Export-ModuleMember
是您定义要导出的内容的方式。它接受通配符,因此如果您可以用模式描述什么是 public,您可以在一次调用中完成,但可以根据需要多次调用它。
一旦函数不再被导出,它们就不能用于模块外的代码。
你的例子对我来说有点奇怪,因为你似乎想要访问模块外部的一些模块代码,但希望它们是同名的,但我不确定。
在那种情况下,例如,如果 Level1 init 应该调用 Level2 模块中的代码,您可能会考虑将 -Scope Local
添加到 Import-Module
调用本身,但我不确定这是否会帮助你的情况。