Решал я тут сегодня вполне простую и житейскую проблему. Стоит на компе 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
, который пока не ясно, как расшифровывать…