首页 > 解决方案 > 有没有办法让模块在首次运行时创建其所需的程序集?

问题描述

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

标签: powershellmodule

解决方案


笔记:

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

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

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

下面的概念证明使用了一个独立的脚本./foo.psm1模块(foo.dllAdd-Type

程序集定义了 sample 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.

推荐阅读