PowerShell 5.1与7的证书操作差异及脚本兼容问题咨询
PowerShell 5.1与7的差异及脚本运行失败原因分析
我编写了一段脚本,可在PowerShell 7中正常运行,但需要适配PowerShell 5.1。我已安装System.IdentityModel.Tokens.Jwt 7.0.3包,并将脚本依赖的DLL复制到了脚本目录。在PowerShell 7中执行new-object Microsoft.IdentityModel.Tokens.X509SigningCredentials($x509cert)能正常输出,但在PowerShell 5.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)
想请教两个问题:
- 除底层依赖的.NET版本不同外,PowerShell 5.1和7还有哪些关键差异?
- 这段脚本无法在PowerShell 5.1运行的具体原因是什么?
脚本示例
$CertPassWord = "password" # 证书密码 $CertificatePath_Pfx = "C:\Temp\Certs\test.pfx" # 证书保存路径 [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)
一、PowerShell 5.1与7的核心差异(除.NET版本外)
- 程序集加载机制:PowerShell 5.1基于.NET Framework,依赖全局程序集缓存(GAC)或本地目录,对.NET Core/.NET 5+程序集兼容性极差;PowerShell 7基于.NET(Core),采用现代化依赖解析,支持NuGet包依赖链自动加载。
- API兼容性边界:PowerShell 7支持大量.NET Core专属新API,而5.1仅能调用.NET Framework兼容的API,部分.NET Core类型/方法在5.1中无法直接使用。
- 程序集隔离性:PowerShell 7的程序集加载更独立,能避免版本冲突;5.1的加载逻辑易受GAC中旧版本程序集干扰。
- 语法与功能扩展:PowerShell 7新增
foreach-object -parallel、三元运算符?:等语法,但这不是当前问题的诱因。
二、脚本无法在PowerShell 5.1运行的原因
从错误信息看,核心问题是缺少依赖程序集System.Runtime.CompilerServices.Unsafe(版本4.0.4.1),具体诱因如下:
- 包版本兼容性不匹配:你使用的
System.IdentityModel.Tokens.Jwt 7.0.3是针对.NET 6+编译的,它依赖的System.Runtime.CompilerServices.Unsafe是.NET Core专属程序集,而PowerShell 5.1底层的.NET Framework默认不包含该程序集,也无法直接加载。 - 依赖集复制不完整:你仅复制了
Microsoft.IdentityModel.Tokens.dll,但该DLL依赖的其他.NET Core程序集(如System.Memory、System.Security.Cryptography.Xml等)未一并复制到脚本目录,PowerShell 5.1无法自动解析这些依赖链。 - API实现差异导致初始化失败:
X509SigningCredentials的构造函数在.NET Core实现中使用了.NET Framework不支持的Span<T>相关API,而Span<T>必须依赖System.Runtime.CompilerServices.Unsafe,最终引发类型初始化异常。
解决建议
- 降级NuGet包版本:改用针对.NET Framework编译的旧版本
System.IdentityModel.Tokens.Jwt(如5.x系列,同时支持.NET Framework 4.6.1+和.NET Core),其依赖的程序集均与.NET Framework兼容。 - 完整复制依赖程序集(不推荐):若坚持使用7.0.3版本,需将所有依赖的.NET Core程序集全部复制到脚本目录,还需通过
app.config配置程序集绑定重定向,但这种方法稳定性极差,容易出现其他兼容问题。 - 改用.NET Framework原生API:直接使用.NET Framework自带的JWT相关API,避免依赖.NET Core专属程序集。
内容的提问来源于stack exchange,提问作者Danny
相关产品推荐
相关产品推荐

