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
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:
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-WinCommandallows you to invokes a one-time command in the compatibility session.
Add-WinFunctionallows you to define new functions that operate implicitly in the compatibility session.
Compare-WinModulelets you compare what you have against what’s available.
Copy-WinModulewill let you copy Window PowerShell modules that are known to work in PowerShell 6 to the PowerShell 6 command path.
Initialize-WinSessiongives 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 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 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
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
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.
The remoting session is considered non-interactive so graphical tools such as notepad or Winforms scripts will either fail, or worse hang.
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.)
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.
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.