Решал я тут сегодня вполне простую и житейскую проблему. Стоит на компе Windows, хочется ее переустановить, только ключ никто не помнит (а Windows-то кошерный, лицензионный). Задача: вытрясти из уже установленной Windows ключ, с которым ее ставили. В принципе в Интернетах полно программулек, решающих эту проблему, но это неспортивно и не модно. А модно сейчас писать скрипты на PowerShell.

Известная тема, что Windows (да и вообще большинство продуктов Microsoft) хранит инфу о серийниках в реестре в шифрованном виде. Шифрованном – это сильно сказано, никаких особых заморочек там нет (можно взорвать свой моск здесь), нужно просто знать, где искать и как расшифровывать.

В общем, начинаем с простого скрипта:

$rpk = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\" -Name DigitalProductId).DigitalProductId
$i = 28
$rpkOffset = 52
$PossibleChars = "BCDFGHJKMPQRTVWXY2346789"
do {
    $Accumulator = 0
    $j = 14
    do {
        $Accumulator = $Accumulator * 256
        $Accumulator = $rpk[$j + $rpkOffset] + $Accumulator
        $Accumulator / 24 -match "^\d*" | Out-Null
        $rpk[$j + $rpkOffset] = $matches[0] -band 255
        $Accumulator = $Accumulator % 24
        $j--
    } while ($j -ge 0)
    $i--
    $ProductKey = $PossibleChars.Substring($Accumulator, 1) + $ProductKey
    if ((29 - $i) % 6 -eq 0 -and $i -ne -1) {
        $i--
        $ProductKey = "-" + $ProductKey
    }
} while ($i -ge 0)
$ProductKey

Скрипт тупо расшифровывает серийник из реестра и выводит его в консоль. Однако скрипт еще недостаточно модный – дополним его возможностью получать инфу с нескольких компов, а также оптимизируем алгоритм раскодирования base-24. В итоге имеем скрипт №2:

param ($targets = ".")
$hklm = 2147483650
$regPath = "Software\Microsoft\Windows NT\CurrentVersion"
$regValue = "DigitalProductId"
Foreach ($target in $targets) {
    $productKey = $null
    $win32os = $null
    $wmi = [WMIClass]"\\$target\root\default:stdRegProv"
    $data = $wmi.GetBinaryValue($hklm,$regPath,$regValue)
    $binArray = ($data.uValue)[52..66]
    $charsArray = "B","C","D","F","G","H","J","K","M","P","Q","R","T","V","W","X","Y","2","3","4","6","7","8","9"
    For ($i = 24; $i -ge 0; $i--) {
        $k = 0
        For ($j = 14; $j -ge 0; $j--) {
            $k = $k * 256 -bxor $binArray[$j]
            $binArray[$j] = [math]::truncate($k / 24)
            $k = $k % 24
        }
        $productKey = $charsArray[$k] + $productKey
        If (($i % 5 -eq 0) -and ($i -ne 0)) {
            $productKey = "-" + $productKey
        }
    }
    $win32os = Get-WmiObject Win32_OperatingSystem -computer $target
    $obj = New-Object Object
    $obj | Add-Member Noteproperty Computer -value $target
    $obj | Add-Member Noteproperty Caption -value $win32os.Caption
    $obj | Add-Member Noteproperty CSDVersion -value $win32os.CSDVersion
    $obj | Add-Member Noteproperty OSArch -value $win32os.OSArchitecture
    $obj | Add-Member Noteproperty BuildNumber -value $win32os.BuildNumber
    $obj | Add-Member Noteproperty RegisteredTo -value $win32os.RegisteredUser
    $obj | Add-Member Noteproperty ProductID -value $win32os.SerialNumber
    $obj | Add-Member Noteproperty ProductKey -value $productkey
    $obj
}

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

Сразу небольшая поправочка – данный метод не работает с ключами VA 2.0, т.е. с MAK и KMS-ключами для Windows 2008 и Windows 7 (возможно и для Windows Vista – не имею возможности проверить), т.к. при использовании VA 2.0 в нужном месте реестра лежат нули, которые раскодируются в ключ BBBBB-BBBBB-BBBBB-BBBBB-BBBBB, а инфа хранится в файле C:\Windows\ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SoftwareLicensing\tokens.dat, который пока не ясно, как расшифровывать…

Вставить свои пять копеек

Чтобы оставить комментарий, Вам нужно идентифицировать себя.