Using Powershell Reflection.Assembly to interact with mRemoteNG
Hi All,
I've been using powershell [System.Reflection.Assembly]::LoadFile to create connection files in previous versions.
Similar to : https://github.com/realslacker/PSmRemoteNG
In the latest 1.77 versions of mRemoteNG, this no longer works.
I'm attempting to run this within the latest version of VS Code, on an upto date Windows 10 PC.
Expected Behavior
In Previous versions I've been able to create mRemoteNG objects in powershell by doing:
[void][System.Reflection.Assembly]::LoadFile( "1.76\mRemoteNG.exe" )
[void][System.Reflection.Assembly]::LoadFile( "1.76\BouncyCastle.Crypto.dll" )
$RootNode = [mRemoteNG.Tree.Root.RootNodeInfo]::new($RootNodeType)
Current Behavior
[void][System.Reflection.Assembly]::LoadFile( "1.77.2\mRemoteNG.dll" )
[void][System.Reflection.Assembly]::LoadFile( "1.77.2\BouncyCastle.Crypto.dll" )
$RootNode = [mRemoteNG.Tree.Root.RootNodeInfo]::new('Connection')
In version 1.77.2, I get the following error
Could not load type 'System.Runtime.Versioning.TargetPlatformAttribute' from assembly
'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
At C:\repos\mremoteng-tree\createfile.ps1:13 char:1
+ $RootNode = [mRemoteNG.Tree.Root.RootNodeInfo]::new('Connection')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], TypeLoadException
+ FullyQualifiedErrorId : System.TypeLoadException
hello, need to check but we move to new .net 6 so just guessing you may not have it installed, try to install .NET Desktop Runtime 6.0.7 perhaps
Unfortunately, that didn't help. .NET SDK 6 is already installed.
Strangely I can interact with parts of the assembly, for example, I can do:
[mRemoteNG.Connection.ConnectionInfo].GetProperties()
But not:
$RootNode = [mRemoteNG.Tree.Root.RootNodeInfo]::new('Connection')
I receive the error noted in the original post.
Hey all,
the major issue is described here: https://learn.microsoft.com/de-de/powershell/scripting/install/powershell-support-lifecycle?view=powershell-7.3
After updating to the .NET 6 Desktop environment, Powershell 2, 3, and 5 are no longer supported for loading mRemoteNG assemblies. I have verified this with Powershell 5 and the portable versions Stable (v1.76.20) and Preview (v1.77.1) run fine with Powershell 5.1, which is the default and latest version of Microsoft's OS-built Powershell for Windows 10/11.
If you want to use Powershell with the latest Nightly version, you need to use Powershell 7. PS7 supports .NET 6.0/7 or 8 in previous versions. You can check this with the following simple PS cmd:
[System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription
Additionally, you need to load assemblies like this:
[void][System.Reflection.Assembly]::LoadFile("$mRemoteNGPath\mRemoteNG.dll")
[void][System.Reflection.Assembly]::LoadFile("$mRemoteNGPath\BouncyCastle.Crypto.dll")`
instead of this
[void][System.Reflection.Assembly]::LoadFile("$mRemoteNGPath\mRemoteNG.exe")
[void][System.Reflection.Assembly]::LoadFile("$mRemoteNGPath\BouncyCastle.Crypto.dll")
and be sure, you unblocked all files:
gci $PathTomRemoteNG -Recurse | ForEach-Object {$_ | Unblock-File}
I tested it with your example; therefore, I didn't check each other functionality:
$RootNode = [mRemoteNG.Tree.Root.RootNodeInfo]::new('Connection')
$RootNode
It seems like an issue when using the wrong PowerShell versions. Download and install PowerShell 7 from here: https://learn.microsoft.com/de-de/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.3
Please test it, and if successful, you can happily use the latest Nightly build with PowerShell 7! If, however, downgrading the .NET environment is not a feasible option, please consider keeping an eye on any updates or alternative solutions that may arise.
King reguarts!
P.S.: My full script i have tested with. Its only functinal and a fast check:
$mRemoteNGPath = "Your Path to mRemoteNG"
gci $mRemoteNGPath -Recurse | ForEach-Object {$_ | Unblock-File}
# Get the FrameworkDescription string
$frameworkDescription = [System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription
# Parse the version from the string
$versionMatch = $frameworkDescription -match '\d+\.\d+\.\d+'
if ($versionMatch)
{
$versionString = $matches[0]
}
else {
$versionString = $frameworkDescription -replace '[^\d.]'
}
try {
$dotNetVersion = [version]$versionString
}
catch {
throw $_
}
$MRNGVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo( "$mRemoteNGPath\mRemoteNG.exe" ).FileVersionRaw
Write-Host mRemoteNG:
$MRNGVersion
Write-Host
Write-Host PSVersion:
$PSVersionTable.PSVersion
Write-Host
Write-Host .NetVersion
$dotNetVersion
try {
if ( $MRNGVersion.ToString() -eq "1.76.20.24669" -or $version -eq "1.77.1.27713") {
[void][System.Reflection.Assembly]::LoadFile( "$mRemoteNGPath\mRemoteNG.exe" )
[void][System.Reflection.Assembly]::LoadFile( "$mRemoteNGPath\BouncyCastle.Crypto.dll" )
}
elseif ($MRNGVersion.ToString() -match "1.77.3.*" ){
# Check if the version is less than 6
if ($dotNetVersion -lt [version]'6.0.0.0') {
throw ".Net build in Version of PS to low"
}
[void][System.Reflection.Assembly]::LoadFile( "$mRemoteNGPath\mRemoteNG.dll")
[void][System.Reflection.Assembly]::LoadFile( "$mRemoteNGPath\BouncyCastle.Crypto.dll" )
}
$RootNode = [mRemoteNG.Tree.Root.RootNodeInfo]::new('Connection')
$RootNode
}
catch {
# Display detailed error information
Write-Host "Failed to load the assembly. Error details:"
Write-Host "Exception Type: $($_.Exception.GetType().FullName)"
Write-Host "Message: $($_.Exception.Message)"
Write-Host "StackTrace: $($_.Exception.StackTrace)"
Write-Host "InnerException: $($_.Exception.InnerException)"
}