Заметки о 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, запускаем и получаем результат. Готовый скрипт getproductkey.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

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

Алексей

ни как не получается, пробовал перенести содержимое скрипта себе на ПК, пишет об ошибках. Возможно выложить в статье готовый и проверенный скрипт?
P.S. как в одном cmd файле разрешить запуск двух строк
-ExecutionPolicy Bypass -File d:\getmsofficekey.ps1
Import-Module d:\getmsofficekey.ps1 ; Get-MSOfficeProductKey >> c:\t.txt
Благодарю

Добавил ссылку на готовый скрипт. По поводу второго вопроса: что требуется получить в результате? Если вывод в файл, то это можно реализовать внутри скрипта. Ну или добавить в cmd строку:
-ExecutionPolicy Bypass -Command «Import-Module d:\getmsofficekey.ps1; Get-MSOfficeProductKey >> c:\t.txt»

Алексей

Кирилл, благодарю за ваш ответ.
Не получилось запустить ваш скрипт-
1 вариант запуска
PS C:\Users\root> d:\getproductkey.ps1
Не удается загрузить файл D:\getproductkey.ps1. Файл D:\getproductkey.ps1 не имеет цифровой подписи. Скрипт не будет вы
полнен в данной системе. Введите «get-help about_signing» для получения дополнительных сведений..
строка:1 знак:21
+ d:\getproductkey.ps1 <<< PowerShell.exe -ExecutionPolicy Bypass -File d:\getproductkey.ps1
Необходимо предоставить выражение для значения справа от оператора «-«.
D:\getproductkey.ps1:17 знак:49
+ $containsN = ($digitalProductId[$decodeLength] — <<<< shr 3) -bAnd 1;
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpectedValueExpression

3 вариант запуска и вашего в том числе задания хотелось оформить в виде cmd , но при выполнении по предложенному вами варианту формируется файл не текстовый, а со скобкой в конце c:\t.txt»

команду в cmd подавал такую powershell -ExecutionPolicy Bypass -Command > c:\t.txt>

Алексей

содержимое файла c:\t.txt>

Имя «<Import-Module" не распознано как имя командлета, функции, файла скрипта или выполняемой программы. Проверьте правильность написания имени, а также наличие и п
равильность пути, после чего повторите попытку.
строка:1 знак:15
+ <Import-Module <<<< d:\getmsofficekey.ps1; Get-MSOfficeProductKey
+ CategoryInfo : ObjectNotFound: (<Import-Module:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException

Имя "Get-MSOfficeProductKey" не распознано как имя командлета, функции, файла скрипта или выполняемой программы. Проверьте правильность написания имени, а также нал
ичие и правильность пути, после чего повторите попытку.
строка:1 знак:61
+ <Import-Module d:\getmsofficekey.ps1; Get-MSOfficeProductKey <<<<
+ CategoryInfo : ObjectNotFound: (Get-MSOfficeProductKey:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException

Алексей

Кирилл, оказывается вот такой способ выдернуть ключи MS офиса сработал в cmd -файле
%SystemRoot%\syswow64\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -command «Import-Module d:\getmsofficekey.ps1 ; Get-MSOfficeProductKey» >>c:\result.txt
а ваш скрипт по прежнему не отрабатывается из готового файла

Скрипт 100% рабочий, специально проверил. У меня вот такая команда отработала: powershell.exe -file «C:\Scripts\getproductkey.ps1» -executionpolicy Bypass
С кавычками вечная проблема — браузер их коверкает, вместо нормальных кавычек подставляются литературные. Вот как сейчас 🙂 Надо проверять каждый раз.

Алексей

А у меня по прежнему результат
PS C:\Users\root> d:\getproductkey.ps1
Необходимо предоставить выражение для значения справа от оператора «-«.
D:\getproductkey.ps1:17 знак:49
+ $containsN = ($digitalProductId[$decodeLength] — <<< powershell.exe -file «d:\getproductkey.ps1» -executionpolicy Bypass
Необходимо предоставить выражение для значения справа от оператора «-«.
D:\getproductkey.ps1:17 знак:49
+ $containsN = ($digitalProductId[$decodeLength] — <<<< shr 3) -bAnd 1;
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpectedValueExpression