Difference between PowerShell 5.1 and 7 when working with certificates

1.2k views Asked by At

Below is a small sample of the script that I am making. I need it to work in PowerShell 5.1 At the moment it only works in PS7. I installed the package "System.IdentityModel.Tokens.Jwt 7.0.3" and copied the dll's I am referencing in the script folder. When I run this script in PS7 I get ouput from "new-object Microsoft.IdentityModel.Tokens.X509SigningCredentials($x509cert)" On PS5.1 I get the error:

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)

Can someone explain to me what the difference is between 5.1 and 7 other than .NET version? And why this piece of code won't run on 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)
2

There are 2 answers

0
Danny On BEST ANSWER

I found the problem why it wasn't running in PS 5.1. I updated my question with the detailed exception. The dll "System.Runtime.CompilerServices.Unsafe.dll" wasn't loaded in PowerShell session causing the script to fail. In PS 7 this dll is loaded by default. I only had a newer version then was expected so I needed a binding redirect in PowerShell 5.1. I got the way to do that from this question: Powershell config assembly redirect

This is my example script that is working in 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
}
3
Zach Perlmutter On

Platform Compatibility...

PowerShell 5.1:

It is the version of PowerShell that is built into Windows and is available on all Windows systems (starting from Windows 7). It primarily targets Windows environments.

PowerShell 7:

This is cross-platform and can run on Windows, Linux, and macOS. It extends PowerShell's reach beyond just Windows systems, making it more versatile for cross-platform scripting and automation.

.NET Version...

PowerShell 5.1:

It relies on the .NET Framework, which is a Windows-only technology. It uses the .NET Framework 4.5.

PowerShell 7:

This is built on the .NET Core (now known as .NET 5+), which is cross-platform. It benefits from the improved performance and cross-platform compatibility of .NET Core.

Compatibility with Modules...

PowerShell 5.1:

It supports a wide range of Windows-specific modules and cmdlets. Some modules and cmdlets may not work in cross-platform scenarios.

PowerShell 7:

While it maintains compatibility with many modules designed for PowerShell 5.1, it also offers new features and improvements. It's more compatible with cross-platform modules and cmdlets, making it suitable for multi-platform scripting.

Language Features and Improvements...

PowerShell 5.1:

It has the features and improvements available up to that version, but development and enhancements are primarily focused on Windows.

PowerShell 7:

It introduces new language features and improvements, as well as bug fixes. While maintaining backward compatibility, it also adds support for modern scripting practices and cross-platform capabilities.

PowerShell Gallery...

PowerShell 5.1:

It uses the PowerShell Gallery to distribute modules and scripts primarily for Windows environments.

PowerShell 7:

It continues to use the PowerShell Gallery but provides a broader range of modules and scripts that can be used across different platforms.

Community and Open Source...

PowerShell 5.1:

Developed and maintained by Microsoft, it follows a traditional closed-source development model.

PowerShell 7:

It is an open-source project hosted on GitHub. The community actively contributes to its development, and it benefits from input and contributions from a wider range of users.

So... PowerShell 5.1 is the traditional Windows-centric version, while PowerShell 7 is the cross-platform, open-source successor that brings many improvements and the ability to work on multiple operating systems.

I hope this helps.