PowerShell 7 is finally here (woot!) and it’s time for Windows users to think seriously about migrating to pwsh 7. One obstacle in doing so in the PowerShell Core (6.x) release was limited compatibility with Windows PowerShell 5.1 modules. There are some Azure modules — my poster child is
AzureAD — that an Azure architect can’t live without and which cling stubbornly to Windows PowerShell 5.1. Over time, things will get better (I hope) but the PowerShell team decided to do something in the meantime to ease Windows users into migrating to PowerShell 7.
I think what they released will prove to be quite useful: PowerShell 7 does provide a a way to use 5.1-only modules in PowerShell 7. It works only on a Windows desktop or server (no help for us macOS and Ubuntu fans) and has some very interesting attributes you should know about.
Here’s the good news. It works and is easy to use. In this gif, you see a simple script that assigns
Get-AzureAdTenantDetail output to a variable after a
Connect-AzureAD cmdlet. This is running in pwsh 7, as you can see on the status bar lower right of the window. If you watch carefully, you’ll see how it’s done: via a remote PowerShell session to localhost. You can clearly see the remote session being set up.
To use a Windows PowerShell 5.1 module in pwsh 7, you
Import-Module using a new parameter:
UseWindowsPowerShell. The rest is automatic. Let’s start by taking a look at that remote session to localhost. Aside from its name —
WinPsCompatSession— it looks just like any remote PowerShell session. Pretty clever.
Did you notice that message about objects being deserialized in the gif as the module import proceeds? What’s that about? It turns out that the object returned from a module run in pwsh 7 with
UseWindowsPowerShell is not the same as the object returned when you run a cmdlet natively in Windows PowerShell 5.1. There are some subtle but important differences. This screenshot compares the output of
Get-Member for the same cmdlet in 5.1 and in 7 using the compatibility feature.
The pwsh 7 object is “deserialized”. I was mystified by this until I found this ten-year-old blog post by the PowerShell team which neatly details why this is happening. Bottom line — methods on an object are (usually) not available in pwsh 7 when the module was loaded with
UseWindowsPowerShell. That’s because you can’t invoke the method “there” (in the PowerShell 5.1 session started to support the legacy module) from “here” (your pwsh 7 session). This is the case even thought the remote session is on the local machine. There are some exceptions; see the blog post for details.
Practically speaking, I don’t think this matters much unless there is a specific method you need from an object you can only get from a 5.1 module. In that case, you’ll have to use PowerShell 5.1. But since most (or all) of the properties are available in the deserialized object that’s returned to pwsh 7, you can still code logic based on values and/or returned states. Personally, this will work for me for the vast majority of things that I use legacy PowerShell 5.1 modules for.
As always, there’s an About_ page you should spend some time looking over to fully understand the new compatibility functions.
Now, if the PowerShell team would just containerize the Windows PowerShell 5.1 remote session and let me 5.1 load modules on macOS… Well, I can dream, right?