如何导入/加载 .dll 文件以在 PowerShell 脚本中使用而不会出现“TypeNotFound”错误?

Cam*_*ker 3 dll powershell dllimport

 [void] CreateSession() {
    try {
        # Load WinSCP .NET assembly
        Add-Type -Path (Join-Path $PSScriptRoot "\winscp\WinSCPnet.dll")
        # Setup session options
        $this.sessionOptions = New-Object WinSCP.SessionOptions -Property @{
            Protocol = [WinSCP.Protocol]::Sftp 
Run Code Online (Sandbox Code Playgroud)

在上面的代码部分中,我遇到了有关“[WinSCP.Protocol]”的“TypeNotFound”错误消息。

  14 |                  Protocol = [WinSCP.Protocol]::Sftp
     |                              ~~~~~~~~~~~~~~~
     | Unable to find type [WinSCP.Protocol].
Run Code Online (Sandbox Code Playgroud)

.dll 文件可以正确加载,我之前已经验证过这一点。我知道发生的情况是 PowerShell“解析器”抛出错误,因为它在加载时无法识别 WinSCP 库。我尝试添加模块和清单,但找不到如何正确执行此操作的简单示例。另外,我运行的是 PowerShell 5.x 还是 7.x 并不重要。我想要的只是加载这个 DLL,这样我就可以使用其中的类/函数。为什么在 PowerShell 中加载 DLL 如此困难?

我需要做什么才能让这个 WinSCP DLL 在运行时加载并且不抛出错误?

关于可能重复的注释

几年前,有人在此网站上提出了一个非常类似的问题,但没有答案。

关于建议重复的注释

我正在寻找一个关于如何将 DLL 文件加载到脚本中的真实示例。链接的问题不适当地这样做。为什么我需要创建清单模块来导入 DLL?

mkl*_*nt0 5

\n

长话短说:博士

\n
    \n
  • 该问题源于尝试通过类型文字(例如)class定义中引用刚刚加载的 WinSCP 类型,如下所述。[WinSCP.Protocol]

    \n
  • \n
  • 完全不使用es 而是使用函数可以绕过这个问题。class

    \n
  • \n
\n
\n
\n

我正在寻找一个关于如何将 DLL 文件加载到脚本中的真实示例。

\n
\n

Add-Type -Path/ -LiteralPath,如您的代码所示,就是这样做的:

\n

它加载指定的 .NET 程序集并使其公共类型在调用会话中可用,就像类似的using assembly语句一样。

\n

但是,由于您正在使用class定义\n尝试从通过类型文字(例如)从同一脚本文件加载的程序集中引用类型,因此类定义失败[WinSCP.Protocol]

\n

在脚本文件解析时,所有类型都被定义引用class类型文字(例如[WinSCP.Protocol] - 无论是作为属性类型,在方法体中,还是作为要实现的基类/接口(尽管在后一种情况下,类型文字没有外壳;例如) -\n必须已加载到会话中,从 PowerShell 7.3.6 开始。[1][...]class Foo : WinSCP.Protocol { ... }

\n
    \n
  • 删除该using assembly声明的这一违反直觉的要求已于 2017 年获得批准,但截至撰写本文时尚未实施:请参阅GitHub 问题 #3641
  • \n
\n

解决方法

\n\n
\n

并不总是需要解决方法,即如果您避免使用类型文字,例如[WinSCP.Protocol]

\n
    \n
  • 对于[WinSCP.SessionOptions],您已经通过使用而不是更现代的 (PSv5+) 来做到这一点New-Object WinSCP.SessionOptions[WinSCP.SessionOptions]::new()

    \n
  • \n
  • [WinSCP.Protocol]::Sftp您还可以通过简单地使用字符串来避免枚举值-\'Sftp\'相反 - 至少对于显示的代码片段来说这可以解决您的问题;这是一个简化的示例:

    \n
  • \n
\n
class Foo {\n  # Note: Do NOT use [WinSCP.SessionOptions] here.\n  [object] $sessionOptions \n  [void] CreateSession() {\n      # Load WinSCP .NET assembly\n      Add-Type -LiteralPath (Join-Path $PSScriptRoot "\\winscp\\WinSCPnet.dll")\n      # Set up session options\n      # Note the use of *string* \'Sftp\' in lieu of [WinSCP.Protocol]::Sftp\n      $this.sessionOptions = New-Object WinSCP.SessionOptions -Property @{\n        Protocol = \'Sftp\'  \n      }\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在您可以[Foo]像平常一样实例化 - 使用New-Object Foo或 ,最好是使用[Foo]::new()(一旦[Foo]成功定义了它本身,就可以通过类型文字、外部定义来引用)。 class

\n
\n

[1] 类是 PowerShell 语言中相对较晚的补充,不幸的是,仍然有许多问题需要解决 - 请参阅GitHub 问题 #6652中的待处理问题列表。但请注意,与 C# 类等程序的功能对等从来都不是目标。\n

\n