假设我在模块中有以下代码(名为MyModule.psm1,位于模块的适当位置):
-option Allscope
导入模块并运行new-function后,我可以成功调用write-greeting函数(由new-function创建)。
当我尝试在新函数调用范围之外调用write-greeting函数时,它会失败,因为该函数不存在。
我尝试过点源代理新功能,但这没有用。我提供了Import-module MyModule
New-Function
write-greeting
,但显然只包含在子范围内。
我还尝试使用export-modulemember write-greeting显式跟随new-item调用,该问题不会产生错误,但也不会创建函数。
我希望能够从模块内部的函数动态创建一个函数(即通过new-item,因为函数的内容和名称将根据输入而变化),并且可以使用新创建的函数来调用模块。
具体来说,我希望能够做到这一点:
where 1=1; drop database;
并将“hello world”视为输出
有什么想法吗?
答案 0 :(得分:4)
使函数可见非常简单:只需在New-Item中更改函数的名称即可拥有global:
范围修饰符:
new-item -path function:\ -name global:write-greeting -value {write-output $greeting} #-Options AllScope
但是,您的示例会遇到新问题,因为$greeting
只存在于new-function
范围内,当您致电write-greeting
时,该范围将不存在。您正在使用未绑定的scriptblock定义模块,这意味着它将在其范围内查找$greeting
(它不会找到它),然后它将查找任何父作用域。它不会看到来自new-function
的那个,所以你获得任何输出的唯一方法是模块或全局范围是否包含$greeting
变量。
我不确定你的真实动态函数会是什么样子,但解决新问题的最简单方法是在脚本块周围创建一个新的闭包,如下所示:
new-item -path function:\ -name global:write-greeting -value {write-output $greeting}.GetNewClosure()
这将创建一个新的动态模块,其中包含当时可用状态的副本。当然,这会产生一个新问题,因为如果你拨打Remove-Module MyModule
,这个功能就不会消失。如果没有更多信息,我不确定这对您是否有问题......
答案 1 :(得分:3)
您需要点源,但您缺少Export-ModuleMember。这是一个完整的例子:
function new-function
{
$greeting='hello world'
Invoke-Expression "function write-greeting { write-output '$greeting' }"
write-greeting
}
. new-function
Export-ModuleMember -Function write-greeting
您也不需要或想要-Scope AllScope。
使用global:scope限定符似乎可行,但不是理想的解决方案。首先,您的函数可以踩踏全局范围中的另一个函数,这些函数通常不应该这样做。其次,如果删除模块,则不会删除全局函数。最后 - 您的全局函数不会在模块的范围内定义,因此如果需要访问模块中的非导出函数或变量,则无法(轻松)获取它们。
答案 2 :(得分:0)
借助其他解决方案,我能够提供一个小帮手,使我可以将纯脚本文件添加为函数,并一步一步将其导出到模块中。 我在.psm1
中添加了以下功能function AddModuleFileAsFunction {
param (
[string] $Name,
[switch] $Export
)
$content = Get-Content (Join-Path $PSScriptRoot "$Name.ps1") -Raw
# Write-Host $content
$expression = @"
function $Name {
$content
}
"@
Invoke-Expression $expression
if ($Export) {
Export-ModuleMember -Function $Name
}
}
这允许我将脚本加载为函数:
. AddModuleFileAsFunction "Get-WonderfulThings" -Export
(加载Get-WonderfulThings.ps1主体并将其导出为功能:Get-WonderfulThings)