gpt4 book ai didi

Powershell:使用 PS 5 类时无法找到类型

转载 作者:行者123 更新时间:2023-12-02 22:10:16 24 4
gpt4 key购买 nike

我在 PS 中使用 WinSCP Powershell 程序集类。在其中一种方法中,我使用了 WinSCP 中的各种类型。

只要我已经添加了程序集,这就可以正常工作 - 但是,由于 Powershell 在使用类时读取脚本的方式(我假设?),在加载程序集之前会引发错误。

其实就算我放了Write-Host在顶部,它不会加载。

在解析文件的其余部分之前,是否有任何方法可以强制运行某些内容?

Transfer() {
$this.Logger = [Logger]::new()
try {

Add-Type -Path $this.Paths.WinSCP
$ConnectionType = $this.FtpSettings.Protocol.ToString()
$SessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::$ConnectionType
HostName = $this.FtpSettings.Server
UserName = $this.FtpSettings.Username
Password = $this.FtpSettings.Password
}

结果是这样的错误:

Protocol = [WinSCP.Protocol]::$ConnectionType
Unable to find type [WinSCP.Protocol].

最佳答案

正如您所发现的, PowerShell 拒绝运行包含引用当时不可用(尚未加载)类型的类定义的脚本 - 脚本解析阶段失败。

  • 从 PSv5.1 开始,即使是 using assembly在这种情况下,脚本顶部的语句没有帮助,因为在您的情况下,类型是在 PS 类定义的上下文中引用的 - 这个 may get fixed in PowerShell Core, however ;所需的工作正在this GitHub issue 中进行跟踪.

  • 正确的解决方法是 创建一个脚本模块 ( *.psm1 ),其关联的 list ( *.psd1 ) 将包含引用类型的程序集声明为先决条件 ,通过 RequiredAssemblies key 。

    如果不能选择使用模块,请参阅底部的替代解决方案。

    这是一个 简化演练 :

    创建测试模块 tm如下 :
  • 创建模块文件夹 ./tm并在其中显示( *.psd1 ):
    # Create module folder
    mkdir ./tm

    # Create manifest file that declares the WinSCP assembly a prerequisite.
    # Modify the path to the assembly as needed; you may specify a relative path, but
    # note that the path must not contain variable references (e.g., $HOME).
    New-ModuleManifest ./tm/tm.psd1 -RootModule tm.psm1 `
    -RequiredAssemblies C:\path\to\WinSCPnet.dll
  • 在模块文件夹中创建脚本模块文件 ( *.psm1 ):

    创建文件 ./tm/tm.psm1使用您的类定义;例如。:
    class Foo {
    # Simply return the full name of the WinSCP type.
    [string] Bar() {
    return [WinSCP.Protocol].FullName
    }
    }

    注意:在现实世界中,模块通常放置在 $env:PSMODULEPATH 中定义的标准位置之一。 ,以便模块可以仅通过名称引用,而无需指定(相对)路径。

  • 使用模块 :
    PS> using module ./tm; (New-Object Foo).Bar()
    WinSCP.Protocol
    using module语句导入模块并且 - 不像 Import-Module ——
    还使模块中定义的类可用于当前 session 。

    由于 RequiredAssemblies,导入模块隐式加载了 WinSCP 程序集模块 list 中的键,实例化类 Foo ,它引用了程序集的类型,成功了。

    如果您的用例不允许使用模块 ,您可以使用 Invoke-Expression在紧要关头,但请注意,通常最好避免 Invoke-Expression为了健壮性和避免安全风险[1]
    .
    # Adjust this path as needed.
    Add-Type -LiteralPath C:\path\to\WinSCPnet.dll

    # By placing the class definition in a string that is invoked at *runtime*
    # via Invoke-Expression, *after* the WinSCP assembly has been loaded, the
    # class definition succeeds.
    Invoke-Expression @'
    class Foo {
    # Simply return the full name of the WinSCP type.
    [string] Bar() {
    return [WinSCP.Protocol].FullName
    }
    }
    '@

    (New-Object Foo).Bar()

    [1] 在这种情况下,这不是问题,但一般来说,鉴于 Invoke-Expression可以调用存储在字符串中的任何命令,将其应用于不受您完全控制的字符串可能会导致执行恶意命令。
    这个警告类似地适用于其他语言,例如 Bash 的内置 eval命令。

    关于Powershell:使用 PS 5 类时无法找到类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42837447/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com