首页 > 解决方案 > 从 PowerShell 中引用 C# 定义的结构时出现管道错误

问题描述

我有以下内容struct,并且class作为 PS 脚本模块的一部分。这部分代码是用 C# 编写的,并处理在将模块导入 PowerShell 会话时运行的代码,尽管OnImport()我没有在此处包含这些位。这不是 C# 代码所做的一切,足以展示我面临的问题:

Add-Type -IgnoreWarnings @"
  using System;
  using System.Reflection;
  using System.Management.Automation;
  using System.Net;
  using System.Security.Cryptography.X509Certificates;
  using System.Runtime.Versioning;

  namespace MyPowerShell {
    public struct State {
      public readonly static ICertificatePolicy OriginalSystemCertificatePolicy = ServicePointManager.CertificatePolicy;
      public readonly static ICertificatePolicy SkipSSLCheckPolicy;
      public readonly static Version PSVersion;
      public readonly static string Framework;

      static State() {
        PSVersion = new Version(
          $($PSVersionTable.PSVersion.Major),
          $($PSVersionTable.PSVersion.Minor),
          $($PSVersionTable.PSVersion.Build),
          $($PSVersionTable.PSVersion.Revision)
        );
        OriginalSystemCertificatePolicy = ServicePointManager.CertificatePolicy;
        SkipSSLCheckPolicy = new TrustAllCertsPolicy();
      }
    }

    public class TrustAllCertsPolicy : ICertificatePolicy {
      public bool CheckValidationResult(
        ServicePoint srvPoint, X509Certificate certificate,
        WebRequest request, int certificateProblem) {
        return true;
      }
    }
  }
"@

这工作正常,一旦完成,我就可以从 PowerShell引用struct属性和罚款:classAdd-Type

# Each of these returns the information expected and I can instantiate TrustAllCertsPolicy
[MyPowerShell.State]::PSVersion
[MyPowerShell.State]::OriginalSystemCertificatePolicy
[MyPowerShell.State]::SkipSSLCheckPolicy
$policy = [MyPowerShell.TrustAllCertsPolicy]::new()

但是我尝试以不同的方式添加从不依赖于扩展$PSVersionTable.PSVersion源中属性的代码中检测当前 PowerShell 版本,稍微here string修改定义:struct

public struct State {
  public readonly static ICertificatePolicy OriginalSystemCertificatePolicy = ServicePointManager.CertificatePolicy;
  public readonly static ICertificatePolicy SkipSSLCheckPolicy;
  public readonly static Version PSVersion;
  public readonly static string Framework; # Added this line

  static State() {
    PSVersion = new Version(
      $($PSVersionTable.PSVersion.Major),
      $($PSVersionTable.PSVersion.Minor),
      $($PSVersionTable.PSVersion.Build),
      $($PSVersionTable.PSVersion.Revision)
    );
    OriginalSystemCertificatePolicy = ServicePointManager.CertificatePolicy;
    SkipSSLCheckPolicy = new TrustAllCertsPolicy();

    # Added the following 2 lines
    TargetFrameworkAttribute attribute = Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(TargetFrameworkAttribute)) as TargetFrameworkAttribute;
    Framework = attribute.FrameworkName;
  }

  // TrustAllCertsPolicy Code
}

一旦我添加代码以FrameworkName从 的静态构造函数中的条目程序集中提取属性struct,它仍然可以编译,但我不能再引用所有属性上的任何属性,struct从而导致管道错误:

[MyPowerShell.State]::PSVersion

An error occurred while creating the pipeline.
+ CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : RuntimeException

但是,我可以使用以下调用来代替 set FrameworkAssemblyProductAttribute而不是从调用程序集中使用,我没有问题:

static State() {
  PSVersion = new Version(
    $($PSVersionTable.PSVersion.Major),
    $($PSVersionTable.PSVersion.Minor),
    $($PSVersionTable.PSVersion.Build),
    $($PSVersionTable.PSVersion.Revision)
  );
  OriginalSystemCertificatePolicy = ServicePointManager.CertificatePolicy;
  SkipSSLCheckPolicy = new TrustAllCertsPolicy();

  // Replaced the next two lines with this
  AssemblyProductAttribute productAttr = Attribute.GetCustomAttribute(Assembly.GetCallingAssembly(), typeof(AssemblyProductAttribute)) as AssemblyProductAttribute;
  Framework = productAttr.Product;
}

为什么struct当我尝试从入口程序集获取时,我的 PowerShell 变得无法使用,但从调用程序集TargetFrameworkAttribute获取时却可以正常工作?AssemblyProductAttribute

标签: c#powershell

解决方案


如果您检查底层异常,您会发现原因是Attribute.GetCustomAttribute()在静态构造函数中传递了一个空引用。

PS ~> $Error[0].GetBaseException() |Format-List -Force


Message        : Value cannot be null.
                 Parameter name: element
ParamName      : element
Data           : {}
InnerException :
TargetSite     : System.Attribute[] GetCustomAttributes(System.Reflection.Assembly, System.Type,
                 Boolean)
StackTrace     :    at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType,
                 Boolean inherit)
                    at System.Attribute.GetCustomAttribute(Assembly element, Type attributeType,
                 Boolean inherit)
                    at State..cctor()
HelpLink       :
Source         : mscorlib
HResult        : -2147467261

调用Assembly.GetEntryAssembly()返回null是因为宿主应用程序实际上不是托管程序集 -powershell.exe是本机 Win32 PE。


推荐阅读