13

我想从文件中导入外部函数,而不是将其转换为模块(我们每个函数有数百个文件,所以将它们都视为模块是多余的)。

这里是代码解释。请注意,我在 Import-Function 中有一些额外的逻辑,例如添加脚本根文件夹并检查文件是否存在并抛出特殊错误,以避免在需要这种导入的每个脚本中出现这种代码重复。

C:\存储库\Foo.ps1:

Function Foo {
    Write-Host 'Hello world!'
}

C:\InvocationTest.ps1:

# Wrapper func
Function Import-Function ($Name) {
    # Checks and exception throwing are omitted
    . "C:\Repository\$name.ps1"

    # Foo function can be invoked in this scope
}

# Wrapped import
Import-Function -Name 'Foo'
Foo          # Exception: The term 'Foo' is not recognized

# Direct import
. "C:\Repository\Foo.ps1"
Foo          # 'Hello world!'

有什么技巧可以将源点点到全局范围吗?

4

4 回答 4

6

您不能使脚本在父范围内运行,但您可以通过显式确定范围来在全局范围内创建函数。

像这样的东西对你有用吗?

# Wrapper func
Function Import-Function ($Path) {
    # Checks and exception throwing are omitted
    $script = Get-Content $Path
    $Script -replace '^function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)', 'function Global:$1'
    .([scriptblock]::Create($script))

}

上面的正则表达式仅针对根函数(左对齐的函数;单词左侧没有空格function)。为了定位所有功能,无论间距如何(包括子功能),将$Script -replace行更改为:

$Script -replace '^\s*function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)','function Global:$1'
于 2013-03-03T16:44:56.897 回答
4

您可以更改点源文件中定义的函数,以便在全局范围内定义它们:

function Global:Get-SomeThing {
    # ...
}

当您从函数中点源时,点源文件中定义的函数将是全局的。不是说这是最好的主意,只是另一种可能性。

于 2016-01-26T20:41:14.157 回答
1

只需点源函数:

. Import-Function -Name 'Foo'
Foo # Hello world!
于 2021-12-07T08:47:39.253 回答
0

我现在不记得在全局范围内运行函数的方法。你可以这样做:

$name = "myscript"

$myimportcode= {
    # Checks and exception throwing are omitted
    . .\$name.ps1
    # Foo function can be invoked in this scope
}

Invoke-Expression -Command $myimportcode.ToString()

当您将 scriptblock 转换为 string.ToString()时,该变量将展开。

于 2013-03-03T16:31:18.420 回答