Verifying PowerShell versions...let me count the ways

There are numerous posts out there on how to check which version(s) of PowerShell are installed on a machine.

An easy, common way is to check the PSVersion property of the $PSVersionTable variable. This will tell you the version of the currently running engine.

But what if you have multiple engines installed on the machine? It's possible (today) to have up to three versions of PowerShell installed, side-by-side. Version 2, 3-5, and 6 (core).

[caption id="attachment_255" align="aligncenter" width="1024"] Three versions of PS, v2, v4, v6, running side-by-side on the same machine.[/caption]

 

Contrary to some posts out there online, I have found that registry keys such as HKLM:\Software\Microsoft\Windows\PowerShell\1\PowerShellEngine do not validate the existence of PowerShell 2.0. In this screenshot, I show a machine which shows that regkey yet I cannot launch the v2 engine.

[caption id="attachment_265" align="aligncenter" width="1185"] Existence of PS v2 regkey but PS v2 engine unavailable.[/caption]

 

I've written a script to launch a job in the v2 engine, and using that to verify if v2 is actually available. I use this script to verify the existence of versions on my machines. I then use the other regkeys to verify if higher versions are available. This is just a sample script and could use a lot more testing. But it's been accurate for my small lab and has detected versions 2 through 6.

 

 # See what version(s) of PowerShell are installed, if any
# v2, v3+, and Core can all exist side-by-side

$originalErrorActionPref = $ErrorActionPreference
$ErrorActionPreference = "SilentlyContinue"

#Reg Installation path for v1 and v2 - does NOT mean it's actually available though
$regPathV1or2 = "hklm:\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine\"

# Reg path for v3 and above
$regPathV3plus = "hklm:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine\"

# Reg path for Core
$regPathVCore = "hklm:\SOFTWARE\Microsoft\PowerShellCore\InstalledVersions"

$vOutput = @{ name="";
    v1="";
    v2="";
    v3="";
    v4="";
    v5="";
    v6="";
}

# test for v1 or v2
if (test-path $regPathV1or2)
{
    [string]$versionA = (Get-ItemProperty -path $regPathV1or2).powershellversion

    if ($PSVersionTable.PSVersion.Major -le $versionA)
    { # running v1 or v2 only
        if ($PSVersionTable.PSVersion.Major -eq 1) {
            $vOutput.v1 = $PSVersionTable.PSVersion.ToString()
        } else {
            $vOutput.v2 = $PSVersionTable.PSVersion.ToString()
        }
    } else {
        # machines with v2 only don't have -psversion parameter
        $job = Start-Job {Get-DateTime} -PSVersion 2.0
        if($?) {
             $vOutput.v2 = $versionA
        } else {# no v2 installed
           remove-job $job.id
        }
    }
}

# test for v3 or above
if (test-path $regPathV3plus) 
{
    [string]$versionB = (Get-ItemProperty -path $regPathV3plus).powershellversion

    if($PSVersionTable.PSVersion.Major -eq 3) {
        $vOutput.v3 = $versionB
    } elseif($PSVersionTable.PSVersion.Major -eq 4) {
        $vOutput.v4 = $versionB
    } elseif($PSVersionTable.PSVersion.Major -eq 5) {
        $vOutput.v5 = $versionB
    }
}

# test for Core ----------test-------------------
if (test-path $regPathVCore)
{
    $vOutput.v6 = "Core"
}


$vOutput.name = "$(hostname).$((Get-WmiObject win32_computersystem).Domain)"

#Write-Output $vOutput
write-output "$($vOutput.name);$($vOutput.v1);$($vOutput.v2);$($vOutput.v3);$($vOutput.v4);$($vOutput.v5);$($vOutput.v6)"

$ErrorActionPreference = $originalErrorActionPref