在PowerShell中的模块中动态创建函数

时间:2016-01-24 21:23:01

标签: powershell module new-item

假设我在模块中有以下代码(名为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”视为输出

有什么想法吗?

3 个答案:

答案 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)