Windows 产品密钥 - 不同技术的不同答案
Windows Product Key - Different answers from different techniques
从 this question 开始(询问如何检索 Windows 产品密钥),似乎从各种方法获得的信息相互矛盾。这个问题问为什么当他们都应该 return 相同的值时会有差异?
这两种方法...
POWERSHELL
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey
命令
wmic path softwarelicensingservice get OA3xOriginalProductKey
return 与此 VBS 脚本不同的结果 ...
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 和 CMD 相互一致,但 VBS 脚本显示不同的值。
知道为什么会这样吗?
更新 - 快到了!!
以下 PowerShell 脚本获取与 PowerShell 和 Cmd 命令相同的产品密钥。值的编码方式似乎发生了变化(我还没有时间确定变化是什么)
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
}
}
}
}
以上脚本摘自 here,但考虑到了 TJ 在底部评论中建议的更改,日期为 2016 年 2 月 5 日。那家伙是个传奇!嗯,原作者也是,清楚!
我会 post 创建它时的 VB 版本,假设这个问题没有结束(只需要再投票 3 票所以行动迅速的人)/sarcasm.
在我测试的 Windows 7 和 Windows 10 系统上,此密钥不存在:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId
但是 vbscript 仍然会输出一个值而不是抛出错误。
您可能在 Windows 7:
上查找此值
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey\DigitalProductId
(注意:Windows10 上不存在)
根据 this article,WMI 查询将 return 制造商存储在 BIOS 或 UEFI 固件中的 OEM 密钥。从注册表读取的 VBScript 方法将 return 用户在设置期间(或之后)输入的零售产品密钥。
从 this question 开始(询问如何检索 Windows 产品密钥),似乎从各种方法获得的信息相互矛盾。这个问题问为什么当他们都应该 return 相同的值时会有差异?
这两种方法...
POWERSHELL
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey
命令
wmic path softwarelicensingservice get OA3xOriginalProductKey
return 与此 VBS 脚本不同的结果 ...
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 和 CMD 相互一致,但 VBS 脚本显示不同的值。
知道为什么会这样吗?
更新 - 快到了!!
以下 PowerShell 脚本获取与 PowerShell 和 Cmd 命令相同的产品密钥。值的编码方式似乎发生了变化(我还没有时间确定变化是什么)
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
}
}
}
}
以上脚本摘自 here,但考虑到了 TJ 在底部评论中建议的更改,日期为 2016 年 2 月 5 日。那家伙是个传奇!嗯,原作者也是,清楚!
我会 post 创建它时的 VB 版本,假设这个问题没有结束(只需要再投票 3 票所以行动迅速的人)/sarcasm.
在我测试的 Windows 7 和 Windows 10 系统上,此密钥不存在:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId
但是 vbscript 仍然会输出一个值而不是抛出错误。
您可能在 Windows 7:
上查找此值
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey\DigitalProductId
(注意:Windows10 上不存在)
根据 this article,WMI 查询将 return 制造商存储在 BIOS 或 UEFI 固件中的 OEM 密钥。从注册表读取的 VBScript 方法将 return 用户在设置期间(或之后)输入的零售产品密钥。