The Windows Compatibility module (WindowsCompatibility
) is a PowerShell module that lets PowerShell Core 6 scripts access Windows PowerShell modules that are not yet natively available on PowerShell Core. (Note: the list of unavailable commands is getting smaller with each new release of PowerShell Core. This module is just for things aren’t natively supported yet.)
You can install the module from the PowerShell Gallery using the command
Install-Module WindowsCompatibility
and the source code is available on GitHub. (This is where you should open issues or make suggestions.)
Once you have WindowsCompatibility
installed, you can start using it. The first thing you might want to run is Get-WinModule
which will show you the list of available modules. From that list, choose a module, say PKI
and and load it. To do this, run the following command:
Import-WinModule PKI
and you’ll have the commands exported by the PKI
module in your local session. You can run them just like any other command. For example:
New-SelfSignedCertificate -DnsName localhost
As always, you can see what a module exported by doing:
Get-Command -module PKI
just like any other module.
These are the most important commands but the WindowsCompatibility
module provides some others:
Invoke-WinCommand
allows you to invokes a one-time command in the compatibility session.Add-WinFunction
allows you to define new functions that operate implicitly in the compatibility session.Compare-WinModule
lets you compare what you have against what’s available.Copy-WinModule
will let you copy Window PowerShell modules that are known to work in PowerShell 6 to the PowerShell 6 command path.Initialize-WinSession
gives you more control on where and how the compatibility session is created. For example. it will allow you to place the compatibility session on another machine.
(See the module’s command help for more details and examples on how to use the WindowsCompatibility
functions.)
How It Works
The WindowsCompatibility
module takes advantage of the ‘Implicit Remoting‘ feature that has been available in PowerShell since version 2. Implicit remoting works by retrieving command metadata from a remote session and synthesizing proxy functions in the local session. When you call one of these proxy function, it takes all of the parameters passed to it and forwards them to the real command in the “remote” session. Wait a minute you may be thinking – what does remoting have to do with the WindowsCompatibility
module? WindowsCompatibility
automatically creates and manages a ‘local remote’ session, called the ‘compatibility session’ that runs with Windows PowerShell on the local machine. It imports the specified module and then creates local proxy functions for all of commands defined in that module.
OK – what about modules that exist in both Windows PowerShell and PowerShell core? Yes – you can import them. After all, there are still a fair number of base cmdlets that aren’t available in PowerShell core yet.
So how does this work? WindowsCompatibility
is very careful to not overwrite native PowerShell core commands. It only imports the ones that are available with Windows PowerShell but not with PowerShell Core. For example, the following will import the PowerShell default management module
Import-WinModule Microsoft.PowerShell.Management
which contains, among others, the Get-EventLog
cmdlet. None of the native PowerShell Core cmdlets get overwritten but now you have Get-EventLog
available in your session.
At this point, if you call Get-Module
, you will see something a bit strange:
Get-Module | ForEach-Object Name
results in output that looks like:
Microsoft.PowerShell.Management
Microsoft.PowerShell.Management.WinModule
Microsoft.PowerShell.Utility
NetTCPIP
Import-WinModule
renames the compatibility module at load time to prevent collisions with identically named modules. This is so the module qualified commands will resolve against the current module. In fact, if you want to see what additional commands were imported, you can run:
Get-Command -Module Microsoft.PowerShell.Management.WinModule
Limitations
Because WindowsCompatibility
is based on implicit remoting, there are a number of significant limitations on the cmdlets imported by the module. First, because everything is done using the remoting protocol, the imported cmdlets will return deserialized objects that only contain properties. Much of the time, this won’t matter because the parameter binder binds by property name rather than by object type. As long as the required properties are present on the object, it doesn’t matter what type the object actually is. There are, however, cases where the cmdlet actually requires that the object be of a specific type or that it have methods. WindowsCompatibility
won’t work for these cmdlets.
Windows Forms and other graphical tools
The remoting session is considered non-interactive so graphical tools such as notepad or Winforms scripts will either fail, or worse hang.
Linux and Mac support
This module depends on WinRM and the client libraries on these platforms are known to be unstable and limited. So for this release, only PowerShell Core running on Windows is supported. (This may change in the future. But you’ll still need a Windows machine with Windows PowerShell to host the compatibility session.)
PowerShell 6.1 Dependency
WindowsCompatibility
depends on a feature introduced in PowerShell Core 6.1 for keeping the current working directory in both the local and compatibility sessions synchronized. Earlier versions of PowerShell will work with WindowsCompatibility
but won’t have this directory synchronization feature. So if you’re running PowerShell Core 6.0, import a command that writes to files, do Set-Location
to a new directory, then use that command to write to a file with an unqualified path; it will use the original path from when the module was imported rather than your sessions current working directory. On PowerShell Core 6.1, it will correctly use the current working directory.
Summary
To sum it all up, the WindowsCompatibility
module provides a set of commands that allow you to access Window PowerShell modules from PowerShell Core 6. There are however, some limitations that make it unsuitable for all scenarios. Over time, as more and more modules are ported to .NET Core/PowerShell 6 natively there will be less need for this module.
Cheers!
Bruce Payette,
PowerShell Team.