Search code examples
powershellvbscriptcmdwsh

Windows Product Key - Different answers from different techniques


Following on from this question (which asks how to retrieve a Windows Product Key), there seems to be conflicting information obtained from the various methods. This question asks why is there a difference when they should all return the same value?

These two methods ...

POWERSHELL

(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey

CMD

wmic path softwarelicensingservice get OA3xOriginalProductKey

return a different result to this VBS script ...

Set WshShell = CreateObject("WScript.Shell")
MsgBox ConvertToKey(WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId"))

Function ConvertToKey(Key)
    Const KeyOffset = 52
    i = 28
    Chars = "BCDFGHJKMPQRTVWXY2346789"
    Do
        Cur = 0
        x = 14
        Do
            Cur = Cur * 256
            Cur = Key(x + KeyOffset) + Cur
            Key(x + KeyOffset) = (Cur \ 24) And 255
            Cur = Cur Mod 24
            x = x - 1
        Loop While x >= 0
        i = i - 1
        KeyOutput = Mid(Chars, Cur + 1, 1) & KeyOutput
        If (((29 - i) Mod 6) = 0) And (i <> -1) Then
            i = i - 1
            KeyOutput = "-" & KeyOutput
        End If
    Loop While i >= 0
    ConvertToKey = KeyOutput
End Function

POWERSHELL and CMD agree with each other, but the VBS script shows a different value.

Any ideas why this might be?


UPDATE - Nearly there!!

The following PowerShell script gets the same product key as the PowerShell and Cmd commands. It appears that something has changed in the way the values are encoded (I've not had time to ascertain what that change is yet)

function Get-ProductKey {
     <#
    .SYNOPSIS
        Retrieves the product key and OS information from a local or remote system/s.

    .Description
        Retrieves the product key and OS information from a local or remote system/s. Queries of 64bit OS from a 32bit OS will result in
        inaccurate data being returned for the Product Key. You must query a 64bit OS from a system running a 64bit OS.

    .Parameter ComputerName
        Name of the local or remote system/s.

    .Notes
Author:             Boe Prox
        Version: 1.1
            -Update of function from http://powershell.com/cs/blogs/tips/archive/2012/04/30/getting-windows-product-key.aspx
            -Added capability to query more than one system
            -Supports remote system query
            -Supports querying 64bit OSes
            -Shows OS description and Version in output object
            -Error Handling

    .EXAMPLE
     Get-ProductKey -Computername Server1

    OSDescription                                           Computername OSVersion ProductKey
    -------------                                           ------------ --------- ----------
    Microsoft(R) Windows(R) Server 2003, Enterprise Edition Server1       5.2.3790  bcdfg-hjklm-pqrtt-vwxyy-12345

        Description
        -----------
        Retrieves the product key information from 'Server1'
    #>
    [cmdletbinding()]
    Param (
        [parameter(ValueFromPipeLine=$True,ValueFromPipeLineByPropertyName=$True)]
        [Alias("CN","__Server","IPAddress","Server")]
        [string[]]$Computername = $Env:Computername
    )
    Begin {
        $map="BCDFGHJKMPQRTVWXY2346789"
    }
    Process {
        ForEach ($Computer in $Computername) {
            Write-Verbose ("{0}: Checking network availability" -f $Computer)
            If (Test-Connection -ComputerName $Computer -Count 1 -Quiet) {
                Try {
                    Write-Verbose ("{0}: Retrieving WMI OS information" -f $Computer)
                    $OS = Get-WmiObject -ComputerName $Computer Win32_OperatingSystem -ErrorAction Stop
                } Catch {
                    $OS = New-Object PSObject -Property @{
                        Caption = $_.Exception.Message
                        Version = $_.Exception.Message
                    }
                }
                Try {
            Write-Verbose ("{0}: Attempting remote registry access" -f $Computer)
            $remoteReg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$Computer)
            $value = $remoteReg.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue('DigitalProductId')[0x34..0x42]
            $isWin8OrNewer = [math]::Floor(($value[14] / 6)) -band 1
            $value[14] = ($value[14] -band 0xF7) -bor (($isWin8OrNewer -band 2) * 4)
            $ProductKey = ""
            Write-Verbose ("{0}: Translating data into product key" -f $Computer)
            for ($i = 24; $i -ge 0; $i--) {
              $r = 0
              for ($j = 14; $j -ge 0; $j--) {
                $r = ($r * 256) -bxor $value[$j]
                $value[$j] = [math]::Floor([double]($r/24))
                $r = $r % 24
              }
              $ProductKey = $map[$r] + $ProductKey
            }
        } Catch {
            $ProductKey = $_.Exception.Message
        }

        if ($isWin8OrNewer){
            $ProductKey = $ProductKey.Remove(0, 1)
            $ProductKey = $ProductKey.Insert($r, 'N')
        }

        #insert dashes to make key more readable
        for($i = 5; $i -lt 29; $i = $i + 6){
            $ProductKey = $ProductKey.Insert($i, '-')
        }
                $object = New-Object PSObject -Property @{
                    Computername = $Computer
                    ProductKey = $ProductKey
                    OSDescription = $os.Caption
                    OSVersion = $os.Version
                }
                $object.pstypenames.insert(0,'ProductKey.Info')
                $object
            } Else {
                $object = New-Object PSObject -Property @{
                    Computername = $Computer
                    ProductKey = 'Unreachable'
                    OSDescription = 'Unreachable'
                    OSVersion = 'Unreachable'
                }
                $object.pstypenames.insert(0,'ProductKey.Info')
                $object
            }
        }
    }
}

The above script was taken from here, but takes into account the change suggested by TJ in the comments at the bottom, dated Feb 5th 2016. That guy is a legend! Well, the original author too, clearly!

I will post the VB version when I have created it, assuming this question doesn't get closed (only 3 more votes required so act quickly people) /sarcasm.


Solution

  • On the Windows 7 and Windows 10 systems that I tested, this key does not exist: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId
    But the vbscript will still output a value rather than throw an error.

    You might be looking for this value instead on Windows 7:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey\DigitalProductId
    (Note: it doesn't exist on Windows 10)