使用证书时 PowerShell 5.1 和 7 之间的区别

Difference between PowerShell 5.1 and 7 when working with certificates

提问人:Danny 提问时间:11/7/2023 最后编辑:Danny 更新时间:11/8/2023 访问量:88

问:

下面是我正在制作的脚本的一小部分。我需要它在 PowerShell 5.1 中工作 目前它仅适用于 PS7。我安装了软件包“System.IdentityModel.Tokens.Jwt 7.0.3”,并在脚本文件夹中复制了我正在引用的dll。 当我在 PS7 中运行此脚本时,我从“new-object Microsoft.IdentityModel.Tokens.X509SigningCredentials($x 509cert)”中输出 在 PS5.1 上,我收到错误:

System.Management.Automation.MethodInvocationException: Exception calling ".ctor" with "1" argument(s): "The type initializer for 'PerTypeValues`1' threw an exception." ---> System.TypeInitializationException: The type initializer for 'PerTypeValues`1' threw an exception. ---> System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
   at System.SpanHelpers.PerTypeValues`1.MeasureArrayAdjustment()
   at System.SpanHelpers.PerTypeValues`1..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.IdentityModel.Tokens.Base64UrlEncoder.Encode(Byte[] inArray, Int32 offset, Int32 length)
   at Microsoft.IdentityModel.Tokens.X509SecurityKey..ctor(X509Certificate2 certificate)
   at Microsoft.IdentityModel.Tokens.SigningCredentials..ctor(X509Certificate2 certificate)
   at Microsoft.IdentityModel.Tokens.X509SigningCredentials..ctor(X509Certificate2 certificate)
   --- End of inner exception stack trace ---
   at System.Management.Automation.DotNetAdapter.AuxiliaryConstructorInvoke(MethodInformation methodInformation, Object[] arguments, Object[] originalArguments)
   at System.Management.Automation.DotNetAdapter.ConstructorInvokeDotNet(Type type, ConstructorInfo[] constructors, Object[] arguments)
   at Microsoft.PowerShell.Commands.NewObjectCommand.CallConstructor(Type type, ConstructorInfo[] constructors, Object[] args)

有人可以向我解释 5.1 和 7 除了 .NET 版本之外有什么区别吗?为什么这段代码不能在 5.1 上运行?

$CertPassWord       = "password" # Password used for creating the certificate
$CertificatePath_Pfx = "C:\Temp\Certs\test.pfx" # Path where the certificate is saved 
 

[System.Reflection.Assembly]::LoadFrom("C:\Temp\Certs\Microsoft.IdentityModel.Tokens.dll")


$x509cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath_Pfx, $CertPassWord)
new-object Microsoft.IdentityModel.Tokens.X509SigningCredentials($x509cert)
.NET PowerShell .net-core 程序集 powershell-core

评论

1赞 Bacon Bits 11/7/2023
安装在 C:\Temp\Certs\ 中的库适用于哪个版本的 .Net?如果您选择 .Net Standard 2.0 库,您可能会有最好的运气。但是,.Net 6+ 和 .Net Framework 之间的 JSON 解析器有很大不同。在 .Net 6 之前,每个人都使用 Newtonsoft.Json 是有原因的。
0赞 Danny 11/7/2023
这些是 .NET Framework 4.8 dll,用于创建 SignedCredential 对象。此示例不需要所有 dll。我删除了示例不需要的 dll
0赞 mklement0 11/7/2023
我不知道这意味着什么,但请注意,Microsoft.IdentityModel NuGet 包仅适用于 .NET Framework,而 System.IdentityModel.Tokens.Jwt 是跨版本包。

答:

3赞 Zach Perlmutter 11/7/2023 #1

平台兼容性...

PowerShell 5.1:

它是内置于 Windows 中的 PowerShell 版本,可在所有 Windows 系统(从 Windows 7 开始)上使用。它主要面向 Windows 环境。

PowerShell 7:

这是跨平台的,可以在 Windows、Linux 和 macOS 上运行。它将 PowerShell 的范围扩展到 Windows 系统之外,使其在跨平台脚本和自动化方面更加通用。

.NET 版本...

PowerShell 5.1:

它依赖于 .NET Framework,这是一种仅限 Windows 的技术。它使用 .NET Framework 4.5。

PowerShell 7:

这是基于跨平台的 .NET Core(现在称为 .NET 5+)构建的。它受益于 .NET Core 的改进性能和跨平台兼容性。

与模块的兼容性...

PowerShell 5.1:

它支持各种特定于 Windows 的模块和 cmdlet。某些模块和 cmdlet 在跨平台方案中可能不起作用。

PowerShell 7:

虽然它保持与为 PowerShell 5.1 设计的许多模块的兼容性,但它也提供了新功能和改进。它与跨平台模块和 cmdlet 更兼容,使其适用于多平台脚本。

语言功能和改进...

PowerShell 5.1:

它具有该版本可用的功能和改进,但开发和增强主要集中在 Windows 上。

PowerShell 7:

它引入了新的语言功能和改进,以及错误修复。在保持向后兼容性的同时,它还增加了对现代脚本实践和跨平台功能的支持。

PowerShell 库...

PowerShell 5.1:

它使用 PowerShell 库主要为 Windows 环境分发模块和脚本。

PowerShell 7:

它继续使用 PowerShell 库,但提供了更广泛的模块和脚本,可以跨不同平台使用。

社区和开源...

PowerShell 5.1:

它由 Microsoft 开发和维护,遵循传统的闭源开发模型。

PowerShell 7:

它是托管在 GitHub 上的开源项目。社区积极为其发展做出贡献,并从更广泛的用户的投入和贡献中受益。

所以。。。PowerShell 5.1 是传统的以 Windows 为中心的版本,而 PowerShell 7 是跨平台的开源继任者,带来了许多改进和在多个操作系统上工作的能力。

我希望这会有所帮助。

评论

2赞 Danny 11/7/2023
谢谢。这解释了很多。你知道为什么这段代码在 7 上运行而不在 5.1 上运行吗?
0赞 Zach Perlmutter 11/8/2023
您提供的代码使用的是 Microsoft.IdentityModel.Tokens 程序集,该程序集与 .NET Core (PowerShell 7) 的兼容性可能优于与 .NET Framework (PowerShell 5.1) 的兼容性。这可以解释为什么代码在 PowerShell 7 中成功运行,但在 PowerShell 5.1 中无法成功运行。
0赞 Zach Perlmutter 11/8/2023
如果需要在 PowerShell 5.1 中运行此代码并遇到问题,可以考虑检查是否需要安装或加载更新或其他库或程序集,以使其在该环境中正常工作。此外,升级到 PowerShell 7 或更新版本的 .NET Framework 可能会为此类代码提供更好的兼容性。
2赞 Danny 11/8/2023 #2

我发现了为什么它没有在 PS 5.1 中运行的问题。我用详细的例外更新了我的问题。DLL“System.Runtime.CompilerServices.Unsafe.dll”未在 PowerShell 会话中加载,导致脚本失败。在 PS 7 中,默认情况下会加载此 dll。我当时只有一个更新的版本,所以我需要在 PowerShell 5.1 中进行绑定重定向。我从这个问题中得到了做到这一点的方法:Powershell 配置程序集重定向

这是我在 PS 5.1 中工作的示例脚本

$CertPassWord       = "password" # Password used for creating the certificate
$CertificatePath_Pfx = "C:\Temp\Certs\test.pfx" # Path where the certificate is saved 
 

[System.Reflection.Assembly]::LoadFrom("C:\Temp\Certs\Microsoft.IdentityModel.Tokens.dll")
[System.Reflection.Assembly]::LoadFrom("C:\Temp\Certs\System.Runtime.CompilerServices.Unsafe.dll")



$OnAssemblyResolve = [System.ResolveEventHandler] {
    param($sender, $e)

    $searchFor = $null
    if ($e.Name -match "(.*?), .*") {
        $searchFor = $matches[1]
    }
    foreach ($a in [System.AppDomain]::CurrentDomain.GetAssemblies()) {
        Write-Host $a
        $foundItem = $null
        if ($a.FullName -match "(.*?), .*") {
            $foundItem = $matches[1]
        }
    
        if ($foundItem -eq $searchFor) {
            return $a
        }
    }
    return $null
}
[System.AppDomain]::CurrentDomain.add_AssemblyResolve($OnAssemblyResolve)

try {
$x509cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath_Pfx, $CertPassWord)
new-object Microsoft.IdentityModel.Tokens.X509SigningCredentials($x509cert)
}

catch {
     Write-Host "An error occurred:"
  Write-Host $_.Exception
}