在 PS 类 中引用程序集导致 "Unable to find type" 错误

Referencing assemblies inside PS classes causes "Unable to find type" error

我在 Windows 7 box 上使用 PowerShell 5.1,并试图从 PowerShell class 中引用 .NET 程序集中的类型,并得到一个 "Unable to find type"错误。

我的 "main" 程序是 FooProg。ps1,我正在其中创建 FooMod 的新实例 class

#Requires -Version 5.1
using module .\FooMod\FooMod.psm1
[FooMod]::new() | out-null

FooMod class 位于 FooMod 子文件夹的 PowerShell 模块 (FooMod.psm1) 中

#Requires -Version 5.1

using assembly .\Foo.dll
using namespace Foo

class FooMod {
   FooMod() {
      Write-Host "Start - Assembly access"
      [Bar] $bar = [Bar]::new()
      Write-Host $bar.Name
      Write-Host $bar.Greeting()
      Write-Host "Finish - Assembly access"
   }
}

我的 Foo.dll 是根据以下 Bar.cs 构建的,与模块文件 (FooMod.psm1) 和模块清单文件 (FooMod.psd1) 一起位于 FooMod 子文件夹中

namespace Foo {
   public class Bar {
      public string Name;

      public Bar(string name) => this.Name = name;

      public Bar() : this("Bar") {
      }

      public string Greeting() {
         return System.String.Format("Hello! My name is {0}", Name);
      }
   }
}

我在名为 FooMod.psd1 的 FooMod 子文件夹中还有一个模块清单,其中包含这些相关条目

RootModule = 'FooMod.psm1'
RequiredAssemblies = 'Foo.dll'

还有什么我想念的吗?在 class 之外使用程序集工作正常,实例化 PowerShell class(不引用程序集/外部类型)工作正常 - 但结合 PowerShell classes 和程序集类型是不行的!

想通了!事实证明,在主脚本 FooProg.ps1 中,using 语句需要引用 Module Manifest 并且 NOT Module Script.

所以不用

#Requires -Version 5.1
using module .\FooMod\FooMod.psm1
[FooMod]::new() | out-null

我改成了

#Requires -Version 5.1
using module .\FooMod\FooManifest.psd1
[FooModule]::new() | out-null

因此,我也将我的模块清单文件从 .\FooMod\FooMod.psd1 重命名为 .\FooMod\FooManifest.psd1

此外,在模块清单文件中,我将条目 RootModule = 'FooMod.psm1' 更改为 RootModule = 'FooModule.psm1'.这不是必需的更改,但有助于理解不同文件的结构。

这显然导致将模块脚本从 FooMod.psm1 重命名为 FooModule.psm1 并且还更改了 class 模块脚本中的名称从 FooModFooModule。同样不是必需的更改,但它与命名一致 classes 与包含它们的文件名相同。

整个练习让我相信在主脚本中命名的模块清单文件需要首先处理,以便在 RequiredAssemblies 中命名的程序集在在 RootModule 中命名的模块被解析。这使得外部 .NET 程序集中的类型在分析模块时可用,并防止出现 "Unable to find type" 错误。

现在配备了新的 FooModule.psm1 文件

#Requires -Version 5.1

using assembly .\Foo.dll
using namespace Foo

class FooModule {
   FooModule() {
      Write-Host "Start - Assembly access"
      Write-Host

      [Bar] $bar1 = [Bar]::new("Romeo")

      Write-Host $bar1.Name
      Write-Host $bar1.Greeting()

      Write-Host

      [Bar] $bar2 = [Bar]::new("Juliet")

      Write-Host $bar2.Name
      Write-Host $bar2.Greeting()

      Write-Host
      Write-Host "Finish - Assembly access"
   }
}

我得到的输出如下

Start - Assembly access

Romeo
Hello! My name is Romeo

Juliet
Hello! My name is Juliet

Finish - Assembly access

关键是使用模块清单,正确设置 RequiredAssemblies 键并在主脚本中引用模块清单而不是模块脚本本身。