首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在脚本模块导入期间,从PowerShell类评估当前的C#会话版本

在脚本模块导入期间,从PowerShell类评估当前的C#会话版本
EN

Stack Overflow用户
提问于 2020-09-10 15:22:31
回答 2查看 425关注 0票数 0

首先,介绍一下我想做的事情的背景。我正在编写一个PowerShell脚本模块,它需要设置一些变量,并在导入模块时运行一些代码。最终需要发生的是依赖于将模块导入到的PowerShell版本。例如,这需要支持5.1及更高版本,但是Invoke-RestMethod不支持

-SkipCertificateCheck参数直到PowerShell 6,这意味着我需要检查版本,创建一个在验证时始终返回true虚拟ICertificatePolicy,并将其存储在全局位置,如果用户要求在调用某些cmdlet时跳过安全检查,则可以引用该参数并设置该策略。到目前为止,我有以下代码:

代码语言:javascript
复制
Add-Type @"
  using System.Management.Automation;
  using System.Net;
  using System.Security.Cryptography.X509Certificates;

  namespace MyModuleNamespace {
    public struct State {
      public static ICertificatePolicy SystemCertificatePolicy;
      public static ICertificatePolicy SkipSSLCheckPolicy;
    }

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

  namespace MyModuleNamespace.SubNamespace {
    public class ModuleAssemblyInitializer : IModuleAssemblyInitializer {
      public void OnImport() {
        // pseudocode of what I'm struggling to define in C#
        if( CurrentPSSession.PSVersion.Major -lt 6 ) {
          MyModuleNamespace.State.SystemCertificatePolicy = ServicePointManager.CertificatePolicy;
          MyModuleNamespace.State.SkipSSLCheckPolicy = new MyModuleNamespace.TrustAllCertsPolicy();
        }
        // end pseudocode
      }
    }
  }
"@

然而..。我很难评估来自当前PowerShell会话的信息,比如评估$PSVersionTable.PSVersion。我知道如何检查安装了哪些版本的PowerShell,但我需要能够评估这个类添加到的当前运行的PowerShell版本。此外,我不希望整个模块都是用C#编写的,尽管从技术上讲,这是一个选项。我团队中的其他人将被期望维护这个模块,虽然他们非常了解PowerShell,但C#超出了他们的技能范围。

如果在导入模块时有一种PowerShell本机方法来处理运行代码的情况,那么我将全神贯注。这是我的第一个PowerShell模块,如果我用错误的解决方案来处理这个问题,也不会感到惊讶。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-10 20:10:01

总的来说,我强烈建议__上不要这样做。盲目跳过证书信任验证是个坏主意。

当我试图在注释中解释时,如果您解决了调用程序集(即。( System.Management.Automation.dll),您可能可以使用反射在初始化程序中发现版本信息:

代码语言:javascript
复制
using System;
using System.Management.Automation;
using System.Reflection;

namespace CrossVersionModule
{
    public class ModuleAssemblyInitializer : IModuleAssemblyInitializer
    {
        public void OnImport()
        {
            // obtain reference to calling assembly
            var caller = Assembly.GetCallingAssembly();

            // locate the PSVersionInfo type
            var psversionType = caller.GetType("System.Management.Automation.PSVersionInfo");
            if (null != psversionType)
            {
                // locate the PSVersion property
                PropertyInfo versionProp = psversionType.GetProperty("PSVersion");
                if (null == versionProp) {
                    // In .NET framework (ie. Windows PowerShell 5.1) we have to explicitly pass binding flags for non-public members
                    versionProp = psversionType.GetProperty("PSVersion", BindingFlags.NonPublic | BindingFlags.Static);
                }

                // Invoke the getter to get the value
                var getter = versionProp.GetGetMethod(true);
                var version = getter.Invoke(null, new object[] { });
                Console.WriteLine(version); // here's where you'd do your version check
            }
        }
    }
}

如果我使用PowerShell标准编译上述代码,则在分别导入5.1版和7版时得到正确的PowerShell版本

票数 2
EN

Stack Overflow用户

发布于 2020-09-10 22:16:01

除了Mathias的.NET 有用的答案之外,我还找到了几种确定有用的答案版本的方法。

一种方法是展开字符串中的表达式,并将以下代码添加到我的struct State中,将来自$PSVersionTable.PSVersion的值插入到C#代码中,然后在模块代码的其他地方可以读取:

代码语言:javascript
复制
public struct State {
  public static ICertificatePolicy SystemCertificatePolicy = ServicePointManager.CertificatePolicy;
  public static ICertificatePolicy SkipSSLCheckPolicy;
  
  // Lines below were added
  public readonly static System.Version PSVersion;

  static State() {
    PSVersion = new Version(
      $($PSVersionTable.PSVersion.Major),
      $($PSVersionTable.PSVersion.Minor),
      $($PSVersionTable.PSVersion.Build),
      $($PSVersionTable.PSVersion.Revision)
    );
  }
}

另一种工作方式是检查调用程序集的product的值,该属性可以在调用程序集上为AssemblyProductAttribute返回少数几个内容之一:

  • 如果直接从PowerShell调用
    • Microsoft® .NET Framework如果使用PowerShell
    • Microsoft® .NET Core如果使用PowerShell核

  • 如果从C#调用,则使用Add-Type 在PowerShell脚本中编译
    • Microsoft (R) Windows (R) Operating System if在.NET框架中的应用
    • PowerShell如果使用.NET核

  • 不确定在使用C# Core编译时,正确编译的.NET项目返回了什么

在我的例子中,我可以检查属性是否等于PowerShell,看看这是否是.NET核心:

代码语言:javascript
复制
// New using directives
using System;
using System.Reflection;

// Check if .NET Core
AssemblyProductAttribute attribute = Attribute.GetCustomAttribute(Assembly.GetCallingAssembly(), typeof(AssemblyProductAttribute)) as AssemblyProductAttribute;
if(attribute.Product == "PowerShell")) {
  // do .NET Core things
}

似乎第三种方法在运行时有一些问题,我已经从这个答案中删除了它,直到我能够弄清楚正在发生什么。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63832847

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档