Backwards Compatibility in PowerShell
Summary: Ed Wilson, Microsoft Scripting Guy, talks about backwards compatibility in Windows PowerShell.
Hey, Scripting Guy! I wrote a script on a system with Windows PowerShell 4.0 installed. Is there an easy way to find out the earliest version of Windows PowerShell on which it will run?
Microsoft Scripting Guy, Ed Wilson, is here. This question did not come in via the email@example.com email alias. Instead, it came via Twitter to @ScriptingGuys. It doesn’t matter if the question is about Windows PowerShell 5.0, 4.0, 3.0, or even Windows PowerShell 2.0. The answer is the same.
PowerShell is forward compatible
Windows PowerShell is forward compatible. This means a script that I wrote in Windows PowerShell 1.0 will run without problems in Windows PowerShell 5.0. Well, there actually can be problems, but not with Windows PowerShell.
The reason is the ecosystem. For example, I could install Windows PowerShell 1.0 on Windows XP. There were several WMI classes and other COM objects that were available in Windows XP that did not make it to Windows Vista or Windows Server 2008. There were also WMI classes in Windows Server 2003 that were not available in Windows XP.
It is really important to keep in mind that there is a difference between the Windows PowerShell core and Windows PowerShell classes that are created by different product groups at Microsoft (and our partners) that provide the capability to manage their technologies via Windows PowerShell. This really gets confusing—especially since Windows PowerShell automatically loads a module that it finds that provides Windows PowerShell cmdlets. (It even loads various Windows PowerShell providers.)
So if I have a Windows PowerShell script that I wrote in Windows XP by using Windows PowerShell 1.0, and it calls a WMI class named NetDiagnostics, it does not matter what version of Windows PowerShell I am running, it will ONLY run on Windows XP because that was the only version of the operating system that contained that particular WMI class.
There is clearly a difference between core Windows PowerShell and the capability provided by the operating system. There were different packages of Windows PowerShell that I could have installed on Windows XP, and all of them could have used that NetDiagnostics WMI class. But it would be a mistake to believe that was a Windows PowerShell compatibility issue.
From a Windows PowerShell perspective, newer versions of Windows PowerShell add the following:
- Language statements (such as Switch, Function, and Class)
- Type accelerators (such as [wmi] and [wmiclass])
- Providers (such as the Registry provider and the Certificate provider)
- Modules (such as PSReadLine and CimCmdlets)
- Cmdlets (such as Get-Random and Get-Guid)
- Aliases (such as Dir and Ls)
- New capabilities (such as workflow, DSC, and modules)
- New features (such as the Windows PowerShell ISE)
When I am using something new from the Windows PowerShell core that was introduced in the latest version of Windows PowerShell, it will not work on a previous version of Windows PowerShell that does not include that capability or feature. This much is obvious.
But if I am using a new feature, such as Windows PowerShell modules, which was introduced in Windows PowerShell 2.0, that feature will work even in Windows PowerShell 5.0 (even though we continue to add new capabilities to the modules). This is because we maintained the essential nature of the original feature, and this is the forward compatibility nature of Windows PowerShell.
It comes down to the version of the operating system
I might be running Windows PowerShell 4.0 on Windows 8.1, and I might have Windows PowerShell 4.0 installed on Windows 7, but that does not mean that scripts I write in Windows 8.1 will work in Windows 7. The reason? Because Windows 8.1 has a lot more modules than Windows 7, such as storage modules, firewall modules, and networking modules. Beginning with Windows 8, the number of modules has exploded.
Am I going to remember what cmdlets are installed on Windows 7 and what cmdlets are installed on Windows 8.1? Not me. Am I going to remember what is part of the Windows PowerShell core and what is part of the operating system? Probably not. The best thing to do is this: If your target is Windows 7, fire up a virtual machine with Windows 7 on it and write the script there. That way you will know it will work.
It also depends on what features are installed
Depending on what features and roles you have installed, you will get a lot (sometimes way more) cmdlets available to you. This is true on the client operating systems (Windows 10 and Windows 8.1), but it is even more true on the server side (Windows 2012 R2 and Windows 2012). For example, adding the AD DS role will get you hundreds of Active Directory cmdlets.
This is also true when you install the Remote Server Administration Tools (RSAT) tools on your client workstation—the features installation adds the appropriate cmdlets for you.
Note The #Requires statement also has a #Requires –Modules parameter that permits you to specify required modules.
It is possible that when I write a script in Windows PowerShell 5.0, the script will work if I run it on a computer with Windows PowerShell 1.0 installed. Here is an example of such a script:
Get-WmiObject –class Win32_Bios
This script will work in any installation of Windows PowerShell, and on any Windows computer. In fact, I could even run it remotely against a Windows NT 4 computer, and it would probably work (depending on the settings, such as NTLM). Why? Because it uses WMI, and the Win32_Bios class has been around ever since the first version of WMI.
How do I know all this? Well, in my case, it is because I wrote a book about WMI. But the essential answer is that you don’t. Unless you happen to remember, or you have run across a particular edge case, or you have an intuition or feeling about something, you really can’t know.
I will give another example…
I was writing an article for TechNet Magazine, and I happened to have a beta build of some version of Windows PowerShell. I was not doing anything new—I was, in fact, simply working with files—it was something that Windows PowerShell had been able to do since the earliest betas. It worked fine for me, and my coworker, but the tech reviewer reported issues.
Come to find out, the build I was using had introduced an overload on one of the methods of one of the classes. It was not anything I could have anticipated or anything that I would have noticed if I hadn’t been writing the article at the time. It made an interesting sidebar. But the lesson is this:
Caution Write in the version of Windows PowerShell that you target. If you want to really be sure, use #Requires –Version 5.0 (or whatever version of Windows PowerShell you are using on your computer).
It may not be the answer you are looking for, DH, but there are too many new things added in the new versions of Windows PowerShell to take a chance on remembering esoteric details. I use Windows PowerShell every day, nearly eight hours a day, and I can’t remember when a particular thing was introduced in which version of Windows PowerShell.
You can test and try to fail gracefully. You can take the easy way out, and require a specific version of Windows PowerShell. Or you can hope for the best, and trust your luck. I have done all three, and I can tell you the best way is to use the #Requires statement.
DH, that is all there is to looking at backwards compatibility in Windows PowerShell. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy