有没有办法让模块在第一个 运行 时创建其所需的程序集?

Is there a way for a module to create its required assemblies when it is first run?

我正在尝试编写一个依赖于小型程序集的 PowerShell 模块。该程序集是从 C# 文件 (add-type -typeDefinition (get-content -raw xyz.cs) -outputAssembly xyz.dll -outputType library) 创建的。因为模块需要这个程序集,所以我必须在安装模块时手动创建程序集。我现在想知道是否可以让 PowerShell 在首次使用时自动执行此 add-type ... 步骤(或任何其他模块初始化步骤)

注:

  • 正如 Mathias R. Jessen 指出的那样,没有严格的必要将辅助程序集 写入磁盘 - 在 中创建它memory 足以满足您的用例(省略 -OutputType-OutputAssembly 参数,并跳过下面代码中的 Add-Type -LiteralPath 调用)。

    • 这就足够了,因为在函数被定义(和导出)时,用于在函数中声明参数的类型的存在并没有被强制执行,但是而不是在 调用 时(或调用其帮助或将其名称传递给 Get-Command -Syntax)。
  • 但是,您可能仍想使用基于磁盘的方法,如下所示,这样会导致编译仅 一次 的性能损失每台机器,第一次导入模块时。

    • 同时考虑实施版本控制机制,以便需要更新类型定义的模块更新在需要时重新创建助手程序集。

以下概念验证使用独立脚本模块 (./foo.psm1),其顶层代码测试是否存在与模块相同位置的辅助程序集 foo.dll,并且,如果找不到,则使用 Add-Type.

创建它

程序集定义了示例类型[demo.Foo],模块导出的Use-Foo模块函数将其用作参数类型。

在实际使用中,对于基于 目录 的模块,您只需指向模块清单(*.psd1 文件的)RootModule 条目相当于 foo.psm1 文件。

# Create demo module ./foo.psm1
@'

    # Deactivate this to silence the verbose messages.
    $VerbosePreference = 'Continue'

    $dllPath = "$PSScriptRoot/foo.dll"
    if (-not (Test-Path $dllPath)) {
      Write-Verbose "Creating assembly $dllPath..."
      Add-Type -ErrorAction Stop -OutputType Library -OutputAssembly $dllPath '
        namespace demo {
          public class Foo {
            public string Bar { get { return "I am a Foo instance."; } }
          }
        }
    '  
    }
    else {
      Write-Verbose "Using preexisting $dllPath assembly."
    }

    Write-Verbose "Loading assembly $dllPath..."
    Add-Type -ErrorAction Stop -LiteralPath $dllPath

    # Define the function to be exported, whose parameter
    # uses the type defined by the helper assembly.
    function Use-Foo {
      param(
        [demo.Foo] $foo
      )
      $foo.Bar
    }

'@ > ./foo.psm1

# Import the module, at which point the top-level code runs,
# which either creates the helper assembly or loads a previously
# created copy.
Import-Module -Force -Verbose ./foo.psm1

Write-Verbose -vb 'Calling Use-Foo...'
Use-Foo ([demo.Foo]::new())

运行 上面第一次得到如下结果,证明程序集是按需创建,加载,并且使用程序集定义的类型作为导出的参数类型Use-Foo 函数成功:

VERBOSE: Loading module from path '/Users/jdoe/demo/foo.psm1'.
VERBOSE: Creating assembly /Users/jdoe/demo/foo.dll...
VERBOSE: Loading assembly /Users/jdoe/demo/foo.dll...
VERBOSE: Exporting function 'Use-Foo'.
VERBOSE: Importing function 'Use-Foo'.
VERBOSE: Calling Use-Foo...
I am a Foo instance.