I was chatting with Jared Atkinson and James Habben about PowerShell today and a question emerged from the discussion: is there way to determine the version of PowerShell installed on a given machine without using the $PSVersionTable PowerShell command? We all agreed that it would be nice to have an offline source for finding this information.
Scenario
You want to determine the version of PowerShell installed on a machine, but don't have a means by which to run the $PSVersionTable PowerShell command (e.g. you are working off of a forensic image -- not a live machine).
The Solution
Right off the bat, Jared suggested that there had to be something in the registry related to this information and subsequently pointed us to the following registry key: HKLM\SOFTWARE\Microsoft\PowerShell. James noted that he found a subkey named "1" inside. Within the "1" subkey is yet another subkey named PowerShellEngine. As we can see in the screenshot below, there is a value named PowerShellVersion that will tell us the version of PowerShell installed on the machine.
Note that PowerShell version 2.0 is shown in this registry key
There was a nuance, however. While James was only seeing one subkey (with the name "1"), I was seeing another subkey in addition to "1." I also saw a subkey named "3" on my machine. I took a look to find the following:
A second subkey named "3" shows a different, more recent version of PowerShell
We wondered what this could mean. It wasn't until Jared noted that having the "1" subkey would indicate the existence of PowerShell v1 or v2 and that having the "3" subkey would indicate PowerShell v3-5 that this all started to make more sense.
James's machine was a Windows XP workstation. My machines were Windows 10 workstations. Therefore, James's SOFTWARE hive only had a single "1" subkey. It only had PowerShell v2 on it. But why did the Windows 10 workstations have both a "1" subkey and a "3" subkey? Jared, once again, suggested that a previous version of Windows being upgraded to Windows 10 may have been the reason. Sure enough, I had upgraded my Windows 7 machines to Windows 10 and had NOT done a fresh Windows 10 install. Note that this may not be the reason for seeing both subkeys; I reviewed a machine with a fresh Windows 10 install and observed that it also had both subkeys.
The bottom line is that, yes, the version of PowerShell can be found in the registry and not just by running the $PSVersionTable PowerShell command. But keep in mind that you might find more than one registry key containing PowerShell version information.
Note: Beware the PowerShell.exe Location
Do not be fooled by the default location of PowerShell.exe. The executable's path will show %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe. Unless manually changed, this path will show "v1.0" regardless of the PowerShell versions installed on the machine.
Do not be fooled by the default location of PowerShell.exe. The executable's path will show %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe. Unless manually changed, this path will show "v1.0" regardless of the PowerShell versions installed on the machine.
Extras
Great! We solved our problem. But what about some of this other stuff we see in the PowerShellEngine subkey? What's that RuntimeVersion value and why doesn't it match the PowerShellVersion value? If two PowerShell engines exist on the Windows 10 machines, how do I use the older, v2 engine instead of the v5 engine?
To answer these questions, let's first use the easiest way possible to determine the version of PowerShell installed on a machine: the $PSVersionTable PowerShell command. (I ran everything below on the Windows 10 machine).
PS C:\Users\4n6k> $PSVersionTable
Name Value
---- -----
PSVersion 5.0.10240.16384
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.42000
BuildVersion 10.0.10240.16384
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
First, I looked to see if there was an easier way to figure out what all of this output meant. And, what do you know, a quick Google search and ServerFault answer were able to point me in the right direction. Instead of looking at the help files in a PowerShell session, I just looked up what I needed online here. We come back with this:
- CLRVersion:
- The version of the common language runtime (CLR).
- BuildVersion:
- The build number of the current version.
- PSVersion:
- The Windows PowerShell version number.
- WSManStackVersion:
- The version number of the WS-Management stack.
- PSCompatibleVersions:
- Versions of Windows PowerShell that are compatible with the current version.
- SerializationVersion:
- The version of the serialization method.
- PSRemotingProtocolVersion:
- The version of the Windows PowerShell remote management protocol.
Note: CLRVersion & RuntimeVersion
Notice that when we run the $PSVersionTable command, we see a line named CLRVersion. The value associated with this name is the same as the value that we see when we look in the registry at the RuntimeVersion value. This is because both of these entries are related to the "Common Language Runtime (CLR)" used in the .NET Framework. You can read more about that here. Since I'm using Windows 10, I have .NET 4.6, which uses CLR version 4.0.30319.42000.
Notice that when we run the $PSVersionTable command, we see a line named CLRVersion. The value associated with this name is the same as the value that we see when we look in the registry at the RuntimeVersion value. This is because both of these entries are related to the "Common Language Runtime (CLR)" used in the .NET Framework. You can read more about that here. Since I'm using Windows 10, I have .NET 4.6, which uses CLR version 4.0.30319.42000.
So, what about the two PowerShell engines that exist on my Windows 10 machines? What if I want to use a different engine than v5? Well, it's as easy as running a PowerShell command. To quote this MSDN article:
"When you start Windows PowerShell, the newest version starts by default. To start Windows PowerShell with the Windows PowerShell 2.0 Engine, use the Version parameter of PowerShell.exe. You can run the command at any command prompt, including Windows PowerShell and Cmd.exe.
PowerShell.exe -Version 2
Let's give it a shot.
PS C:\Users\4n6k> $psversiontable
Name Value
---- -----
PSVersion 5.0.10240.16384
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.42000
BuildVersion 10.0.10240.16384
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
PS C:\Users\4n6k> PowerShell.exe -Version 2
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.
PS C:\Users\4n6k> $psversiontable
Name Value
---- -----
CLRVersion 2.0.50727.8669
BuildVersion 6.1.7600.16385
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1
As you can see, our PowerShell session is now using the v2 engine instead of v5. Note that when I tried PowerShell.exe -Version 3, the output I received was the same output I received for v5. This may be due to jumping from PowerShell v2 on Windows 7 to PowerShell v5 on Windows 10. This could also be because of the split between v1/v2 and v3/v4/v5 (thanks to James and Jared for this possible explanation).
A big thanks goes out to Jared Atkinson and James Habben. This post wouldn't exist without their involvement and discussion.
-4n6k
References
1. What do the contents of PowerShell's $PSVersionTable represent? (ServerFault)
2. Common Language Runtime (CLR)
3. MSDN: about_Automatic_Variables - PowerShell
4. Environment.Version Property (.NET)
5. Starting the Windows PowerShell 2.0 Engine