Make PSWSMan
module the only source of libmi
and libpsrpclient
binaries for PowerShell remoting over WSMan on Linux and macOS?
#15310
Replies: 7 comments 22 replies
-
This is something that I have investigated when someone tried to get this working in Azure Cloud Shell where you don't have root access jborean93/omi#24 (comment)
While this does work and allows you to use the fork without root access and the restart there is one catch with
Right now there is no custom import resolver for the S.M.A assembly but I have no idea if that assumption will be true in the future. It also means that any 3rd party code that does this themselves for some reason will not be usable with this module and vice versa. I don't know whether this is really something to be concerned about but I have mostly avoided going that route because I didn't want to paint myself into a corner. I see in your comment you are talking about setting this for the
This is definitely possible but there are 2 wrinkles that make this complicated. The linkage between
I'm not against the idea, I do have some concerns about My only other qualm is how this works from a support perspective, While I'm happy to help out when I can I cannot give any guarantees that any bugs or feature requests will be addressed at all. This is fine if this is a fork and people opt into that knowing the "risks" involved but when something comes with the "official" status that may change the expectation of the users. While I don't wish to cause any offense to anybody who works on this part of PowerShell the builtin implementation is a bit lacking and the fork should provide a better experience it's still not a 1 for 1 comparison with what Windows provides. I see 4 potential options that are available
I know 4 is a pipe dream and I personally don't have time to work on it and the same probably also applies to anybody on the PowerShell team. TLDR: I'm happy to investigate this further but have some concerns around limtations of |
Beta Was this translation helpful? Give feedback.
-
Regarding MMI, it's still needed on Windows for CimCmdlets, but is out of scope for this discussion. The only other thing MMI was used for on Linux/macOS was DSC configuration compilation to a mof file. Since we are no longer using MOF for DSC going forward, it is ok to break this dependency. I would think |
Beta Was this translation helpful? Give feedback.
-
Even though we won't use PowerShell needs some additional changes besides removing those 2 libs -- the code path that creates a new |
Beta Was this translation helpful? Give feedback.
-
I'd like to know when it comes to Enterprises that are still paying for overdue Windows PowerShell. It looks ridiculous to put a patch on another patch. :-) We didn't get WSMan in OOB before and never will. Same with SSH. With this suggestion, we stay in the same place again, or even take a step back (well, to a side :-) ).
|
Beta Was this translation helpful? Give feedback.
-
Here we are not talking about Windows PowerShell. Nothing is changed to Windows PowerShell. What do you mean by "a patch on another patch"?
It's not very clear what you mean here, could you please elaborate some more? |
Beta Was this translation helpful? Give feedback.
-
@daxian-dbw I've had a play with this today and feel like this should work going forward Add-Type -TypeDefinition @'
using System;
using System.Management.Automation;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
namespace PSWSMan
{
public class Resolver : IDisposable
{
private static readonly string PSRP_LIB_NAME = "libpsrpclient";
private string libPath = null;
private IntPtr libHandle = IntPtr.Zero;
public Resolver(string libPath, bool setPwshResolver)
{
this.libPath = libPath;
AssemblyLoadContext.Default.ResolvingUnmanagedDll += ResolvePSRPClient;
if (setPwshResolver)
{
try
{
NativeLibrary.SetDllImportResolver(typeof(PSObject).Assembly, ImportResolver);
}
catch (InvalidOperationException) {} // Only 1 resolver allowed per assembly
}
}
private IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
if (libraryName == PSRP_LIB_NAME)
return GetPSRPClientLibrary(assembly, searchPath);
return NativeLibrary.Load(libraryName, assembly, searchPath);
}
private IntPtr ResolvePSRPClient(Assembly assembly, string libraryName)
{
if (libraryName != PSRP_LIB_NAME)
return IntPtr.Zero;
return GetPSRPClientLibrary(assembly, null);
}
private IntPtr GetPSRPClientLibrary(Assembly assembly, DllImportSearchPath? searchPath)
{
if (libHandle == IntPtr.Zero)
libHandle = NativeLibrary.Load(libPath, assembly, searchPath);
return libHandle;
}
public void Dispose()
{
if (libHandle != IntPtr.Zero)
{
NativeLibrary.Free(libHandle);
libHandle = IntPtr.Zero;
}
AssemblyLoadContext.Default.ResolvingUnmanagedDll -= ResolvePSRPClient;
GC.SuppressFinalize(this);
}
~Resolver() { this.Dispose(); }
}
}
'@
# Will be selected at runtime based on the host environment - just used for testing here
$libPath = "/home/jborean/dev/omi/PSWSMan/lib/glibc-1.1/libpsrpclient.so"
# Will check if pwsh still ships libpsrpclient, if so it's going to call SetDllImportResolver to ensure
# pwsh no longer uses the shipped copy. If not present then SetDllImportResolver is not called
# so that in case pwsh adds it's own resolver won't impact this module
$pwshDir = Split-Path -Path ([PSObject].Assembly.Location) -Parent
$libPresent = Test-Path -LiteralPath (Join-Path $pwshDir libpsrpclient.so)
# Will live for the scope of the module - disposes itself on unload
[PSWSMan.Resolver]::new($libPath, $libPresent) Do you see any glaring problems with this approach? It should work today where the builtin libs are present and in the future where they are no longer present with PowerShell. Things are a bit more complicated on macOS as it needs to set up some symlinks for the OpenSSL libs at runtime but I think I have a separate solution for that which I don't hate too much. The only downside I can see with this approach over the current just copy into the pwsh dir is that someone needs to import this module. If any WSMan commands are run then the existing |
Beta Was this translation helpful? Give feedback.
-
I wonder we are trying to resolve the fundamental problem with PowerShell remoting based on the principle of minimal change. |
Beta Was this translation helpful? Give feedback.
-
Background
The PowerShell remoting over WSMan on Linux and macOS depends on the WSMan client libraries
libmi.so/libmi.dylib
andlibpsrpclient.so/libpsrpclient.dylib
, which were from the microsoft/omi repository. The OMI project is in maintenance mode and its team has decided to not support PowerShell anymore. Therefore, the PowerShell WSMan remoting is becoming more and more broken on Linux and macOS.Proposal
How about making the
PSWSMan
module the only source oflibmi
andlibpsrpclient
binaries for PowerShell remoting over WSMan on Linux and macOS?The PSWSMan module is created by @jborean93 to install and manage the WSMan client libraries
libmi
andlibpsrpclient
produced from his forked omi repository for Linux and macOS.The
libmi/libpsrpclient
shipped by PowerShell are not going to be updated. They may still work on some old Linux distros, but very likely not on newer ones. @jborean93, what if PowerShell doesn't shiplibmi/libpsrpclient
at all, but instead tell users to leveragePSWSMan
module to enable WSMan remoting support on Linux/macOS?Today, to use
PSWSMan
, one has to replace the WSMan client libraries shipped by PowerShell with the ones contained inPSWSMan
withInstall-WSMan
. The user needs to have root privilege and needs to restart PowerShell for that.If PowerShell doesn't ship those libs, then allPSWSMan
needs to do is to set aDllImportResolver
callback for theMicrosoft.Management.Infrastructure
assembly upon module loading, which will then be used by the runtime to resolve the P/Invoke's from MMI tolibmi/libpsrpclient
.[edit] I missed that
System.Management.Automation
also referenceslibpsrpclient
in PInvoke's.NativeLibrary.SetDllImportResolver
only allows one callback per assembly, when it comes toS.M.A
, the risk of collision would be too high to be ignored. So, instead of usingDllImportResolver
, we can useAssemblyLoadContext.ResolvingUnmanagedDll
instead, which is a multi-cast event. See the algorithm for loading unmanaged lib.I saw in
PSWSMan.psm1
that you have a set of steps to resolve which libs to be used based on the runtime/environment. That logic can be put in theResolvingUnmanagedDll
handler. You register the handler toAssemblyLoadContext.Default
when thePSWSMan
module is being loaded, and then unregister it upon module unloading.@jborean93, what do you think about this proposal? This will essentially make your forked omi repository the
advertised "official"recommended repo for WSMan client support in PowerShell./cc @TravisEz13 @SteveL-MSFT @PaulHigin @JamesWTruher
Beta Was this translation helpful? Give feedback.
All reactions