Заметки о Windows и других программных продуктах Microsoft...

Как узнать ключ продукта Windows с помощью PowerShell

Как узнать ключ продукта Windows с помощью PowerShell

Как узнать ключ продукта установленной операционной системы Windows? Конечно проще всего воспользоваться специализированными программами (ProduKey, ShowKeyPlus и т.п.), но мы не ищем легких путей 🙂 В поисках ключа нам поможет PowerShell.

Ключ продукта Windows хранится в системном реестре, в разделе HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion, в параметре DigitalProductID.

Примечание. На самом деле у Windows есть два ключа продукта. Кроме ключа активации есть еще ключ установки (generic), находящийся в разделе HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey. С этим ключом можно установить систему, но нельзя ее активировать.

раздел реестра

 

Но просто так ключ посмотреть не удастся. Данные в DigitalProductID хранятся в двоичном виде, сам ключ занимает байты с 52 по 66. Кроме того данные зашифрованы в кодировке base 24.

параметр реестра

 

Для того, чтобы узнать ключ, надо извлечь его из реестра и расшифровать. Для расшифровки используем следующий PowerShell скрипт. Сознаюсь, скрипт не мой 🙂  Я нашел его на просторах интернета и немного подправил, а также добавил комментарии. Кстати, в скрипте активно используются побитовые операторы.

# 24 символа, использующиеся в ключах продукта Microsoft
$base24 = ‘BCDFGHJKMPQRTVWXY2346789’;
# длина ключа продукта в символах
$decodeStringLength = 24;
# длина ключа продукта в байтах
$decodeLength = 14;
# строка с расшифрованным ключом
$decodedKey = ″ ″;

#Извлекаем зашифрованный ключ из реестра и сохраняем его в массив

$digitalProductId = (Get-Item ‘HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion’).GetValue(‘DigitalProductId’)[52..66]

#Проверяем наличие в ключе буквы ‘N’ (для Windows 8 и старше)

#Если третий бит младшего байта массива равен 1, то в номере присутствует буква ‘N’
$containsN = ($digitalProductId[$decodeLength] -shr 3) -bAnd 1;

#Для корректной расшифровки номера этот бит необходимо сбросить
$digitalProductId[$decodeLength] = $digitalProductId[$decodeLength] -band 0xF7;

<# Расшифровка ключа. Заключается в том, что полученное из реестра значение $digitalProductId переводится в систему счисления с основанием 24, затем каждая цифра заменяется на символ из $base24, индексом которого является эта цифра #>

for ($i = $decodeStringLength; $i -ge 0; $i−−) {

# Переменная для хранения индекса текущего символа, перед началом вычисления обнуляем
$digitMapIndex = 0;

for ($j = $decodeLength; $j -ge 0; $j−−) {

<# Размерность в байтах, поэтому исходное основание 256. Умножаем на него остаток от предыдущей итерации и добавляем цифру из следующего разряда #>
$digitMapIndex = ($digitMapIndex -shl 8) -bXor $digitalProductId[$j];

<# Делим $digitMapIndex на количество символов в $base24. Частное попадает в $digitalProductId[$j],
а остаток от деления в $digitMapIndex #>
$digitalProductId[$j] = [System.Math]::DivRem($digitMapIndex, $base24.Length, [ref]$digitMapIndex);

}

# Находим в $base24 символ с полученным индексом и добавляем его в $decodedKey
$decodedKey = $decodedKey.Insert(0, $base24[$digitMapIndex]);

}

<# Если в ключе присутвует символ ′N′, то добавляем его. Для этого находим в расшифрованной строке первый символ и запоминаем его индекс в $base24. Затем удаляем первый символ, а в оставшуюся строку вставляем ′N′ в позицию с номером индекса удалённого символа #>

if ($containsN -eq 1) {

$index = $base24.IndexOf($decodedKey[0]);
$decodedKey = $decodedKey.Substring(1).Insert($index, ‘N’);

}

# Вставляем тире через каждые пять символов

for ($n = 20; $n -ge 5; $n -= 5){$decodedKey = $decodedKey.Insert($n, ‘-‘)}

# Формируем вывод, добавляем в него дополнительную информацию об операционной системе

$Target = [System.Net.Dns]::GetHostName();
$win32os = Get-WmiObject -Class ‘Win32_OperatingSystem’ -ComputerName $target;
$product = New-Object -TypeName System.Object;

$product | Add-Member -MemberType ‘NoteProperty’ -Name ‘Computer’ -Value $target;
$product | Add-Member -MemberType ‘NoteProperty’ -Name ‘Caption’ -Value $win32os.Caption;
$product | Add-Member -MemberType ‘NoteProperty’ -Name ‘OSArch’ -Value $win32os.OSArchitecture;
$product | Add-Member -MemberType ‘NoteProperty’ -Name ‘BuildNumber’ -Value $win32os.BuildNumber;
$product | Add-Member -MemberType ‘NoteProperty’ -Name ‘ProductID’ -Value $win32os.SerialNumber;
$product | Add-Member -MemberType ‘NoteProperty’ -Name ‘ProductKey’ -Value $decodedKey;

Write-Output $product;

Сохраняем код в файлик с расширением .ps1, запускаем и получаем результат.

вывод скрипта

 

Ну и чтобы убедиться в том, что скрипт работает правильно, проверим полученный результат с помощью программы ProduKey. Как видите, она выдает такой же ключ.

вывод программы ProduKey

 

И еще. Если система была активирована корпоративным ключом (MAK) либо с помощью цифровой лицензии, то ключ не сохраняется в системе. В этом случае и скрипт выдаст что то вроде этого BBBBB-BBBBB-BBBBB-BBBBB-BBBBB.

 
 
Комментарии
Анатолий

В скрипте ( скорее всего при перенесении на сайт) допущены 2 ошибки. Каким-то образом команды декримента ( два знака минус) «превратились» в «длинное тире».
Таким образом, вместо for ($i = $decodeStringLength; $i -ge 0; $i-) Здесь на сайте последний минус — «длинное тире»
должно быть for ($i = $decodeStringLength; $i -ge 0; $i- -) (Два минуса специально разделил пробелами.)
Ну и аналогично для цикла по $j:
for ($j = $decodeLength; $j -ge 0; $j- -)

После корректировки скрипт заработал:

Computer : WIN7_64_MAX
Caption : Microsoft Windows 7 Максимальная
OSArch : 64-bit
BuildNumber : 7601
ProductID : 00426-068-2492092-86602
ProductKey : XXXX-XXXX-XXXX-XXX-JB3D2

Спасибо, поправил.