5

假设我在模块中有以下代码(称为 MyModule.psm1,位于模块的适当位置):

function new-function{

    $greeting='hello world'
    new-item -path function:\ -name write-greeting -value {write-output $greeting} -Options AllScope
    write-greeting
}

导入模块并运行 new-function 后,我可以成功调用 write-greeting 函数(由 new-function 创建)。

当我尝试在 new-function 调用范围之外调用 write-greeting 函数时,它会失败,因为该函数不存在。

我试过点源新功能,但这没有帮助。我已经提供了-option Allscope, 但显然它只包含在子范围中。

我还尝试使用 export-modulemember write-greeting 明确地遵循 new-item 调用,它不会给出错误,但也不会创建函数。

我希望能够从模块内的函数动态地创建一个函数(即通过 new-item,因为函数的内容和名称将根据输入而有所不同),并且新创建的函数可用于在模块外调用。

具体来说,我希望能够做到这一点:

Import-module MyModule
New-Function
write-greeting

并将“hello world”视为输出

有任何想法吗?

4

3 回答 3

7

使函数可见非常简单:只需在 New-Item 中更改函数的名称以具有global:范围修饰符:

new-item -path function:\ -name global:write-greeting -value {write-output $greeting} #-Options AllScope

但是,您的示例将遇到一个新问题,因为$greeting只会存在于new-function范围内,而当您调用write-greeting. 您正在使用未绑定的脚本块定义模块,这意味着它将$greeting在其范围内查找(它不会找到它),然后它将在任何父范围内查找。它不会看到 from new-function,因此获得任何输出的唯一方法是模块或全局范围是否包含$greeting变量。

我不确定你真正的动态函数会是什么样子,但解决这个新问题的最简单方法是在你的脚本块周围创建一个新的闭包,如下所示:

new-item -path function:\ -name global:write-greeting -value {write-output $greeting}.GetNewClosure()

这将创建一个新的动态模块,其中包含当时可用的状态副本。当然,这会产生一个新问题,即如果您调用Remove-Module MyModule. 没有更多信息,我不确定这对您是否有问题...

于 2016-01-24T23:30:31.217 回答
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 限定符似乎可行,但不是理想的解决方案。首先,您的函数可能会踩踏全局范围内的另一个函数,而这些模块通常不应该这样做。其次,如果您删除模块,您的全局函数将不会被删除。最后 - 您的全局函数不会在模块的范围内定义,因此如果它需要访问模块中的非导出函数或变量,您无法(轻松)获得它们。

于 2016-01-25T14:08:50.987 回答
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)

于 2020-10-22T13:35:36.687 回答