簡體   English   中英

在腳本模塊導入期間從 C# 類評估當前的 PowerShell 會話版本

[英]Evaluate current PowerShell session version from C# class during script module import

首先,我正在嘗試做的一些背景。 我正在編寫一個 PowerShell 腳本模塊,該模塊需要在導入模塊時設置一些變量並運行一些代碼。 最終需要發生的事情取決於導入模塊的 PowerShell 版本。 比如這個需要支持5.1及以后,但是Invoke-RestMethod不支持
-SkipCertificateCheck參數直到 PowerShell 6,這意味着我需要檢查版本,創建一個虛擬的 ICertificatePolicy ,它在驗證時基本上總是返回true ,並將其存儲在一個全局位置,我可以引用它並設置該策略,如果用戶要求他們想要調用某些 cmdlet 時跳過安全檢查。 到目前為止,我有以下代碼:

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 模塊,如果我使用錯誤的解決方案來解決這個問題,我不會感到驚訝。

一般來說,我強烈建議根本不要這樣做 盲目跳過證書信任驗證是一個壞主意。


正如我(不好)試圖在評論中解釋的那樣,如果您解析調用程序集(即System.Management.Automation.dll ),您可以使用它來使用反射發現初始化程序中的版本信息:

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 Standard編譯上述內容,則分別在 5.1 和 7 中導入時會獲得正確的 PowerShell 版本

除了 Mathias 的有用答案之外,我還找到了一些方法來確定 .NET 版本。

一種是擴展字符串中的表達式,並將以下代碼添加到我的struct State以將$PSVersionTable.PSVersion的值插入到 C# 代碼中,然后可以在模塊代碼的其他地方讀取這些值:

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如果使用 Windows PowerShell)
    • Microsoft® .NET Core如果使用 PowerShell Core
  • 如果從使用Add-Type在 PowerShell 腳本中編譯的 C# 調用
    • Microsoft (R) Windows (R) Operating System如果在 .NET Framework 上)
    • 如果使用 .NET Core,則為PowerShell
  • 不確定在針對 .NET Core SDK 編譯時從正確編譯的 C# 項目返回什么

在我的情況下,我可以檢查屬性是否等於PowerShell以查看這是否是 .NET Core:

// 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
}

似乎第三種方法在運行時有一些問題,我已經從這個答案中刪除了它,直到我弄清楚發生了什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM