A couple of days ago I received my daily PowerTips email from PowerShell.com talking about how to get the Windows Product key via PowerShell from your local system.
The code is simple and to the point to look for and translate the data into a readable product key:
function Get-ProductKey { $map="BCDFGHJKMPQRTVWXY2346789" $value = (get-itemproperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").digitalproductid[0x34..0x42] $ProductKey = "" 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 if (($i % 5) -eq 0 -and $i -ne 0) { $ProductKey = "-" + $ProductKey } } $ProductKey }
However, being that I had a little free time and really like this code, I wanted to enhance it to make it more robust by adding a few extra things here and there. By doing this, you can see just how easy it is to take some existing code and modify it to meet your own specific requirements.
The list of items I wanted to add to the existing code are:
- Run against multiple systems.
- Allow this function to query remote systems; not just locally
- Output an object instead of just text
- In the object, show the following properties
- Computername, ProductKey,OSDescription,OSVersion
- Allow to query against 64bit systems
- Error handling
- Comment Based Help
First off, lets add some comment based help to this code:
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' #>
I also add some parameters to the existing code with a default parameter value for the Computername to point to the local machine. I also add some aliases to support the ValueFromPipeLineByPropertyName which allows extra pipeline support. You will also notice that I set the type for Computername to [string[]] which means that it will take a collection of strings for that parameter.
[cmdletbinding()] Param ( [parameter(ValueFromPipeLine=$True,ValueFromPipeLineByPropertyName=$True)] [Alias("CN","__Server","IPAddress","Server")] [string[]]$Computername = $Env:Computername )
I start off with a quick check to see if the system is reachable on the network and then perform a WMI query for some pieces of information regarding the Caption (Operating System name), Version and also the Architecture which will tell me if the OS is 64bit or 32bit which will be vital in determining what to do next for the product key.
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 } }
The rest of the code deals with the actual operations to query the specified system’s registry key based on whether it is a 64bit system or 32bit. This is important because if the system is 64bit, the DigitalProductId4 key value must be used instead of DigitalProductId, otherwise you will not receive the accurate data for the product key. The other part of the code performs the translation of the value of the registry key to find the product key and also using a .Net class ([Microsoft.Win32.RegistryKey]) which will allow me to perform a remote query of the registry.
Try { Write-Verbose ("{0}: Attempting remote registry access" -f $Computer) $remoteReg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$Computer) If ($OS.OSArchitecture -eq '64-bit') { $value = $remoteReg.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue('DigitalProductId4')[0x34..0x42] } Else { $value = $remoteReg.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue('DigitalProductId')[0x34..0x42] } $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 if (($i % 5) -eq 0 -and $i -ne 0) { $ProductKey = "-" + $ProductKey } } } Catch { $ProductKey = $_.Exception.Message }
Lastly we need to make this into an object because this is PowerShell, after all. I use the New-Object cmdlet and supply a hash table of data that is saved to a variable. After the object is created, I opt to create a custom type name for this object to make it more unique which is then displayed to the user running the code.
$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 } } } }
Code in Action
Ok, lets run this against a local and remote system and see it in action.
Get-ProductKey -Computername Boe-PC,DC1
Whoops! Forgot to power on the server… Lets try this one more time!
Ok, that looks better. As you can see, not only is the product key displayed, but the computername as well as the Operating System and version are also displayed as well. This allows for better use of the code to see not only what the product key is, but what it also applies to as well.
Download This Function
Hope you enjoy my updated take on this already great function! This also shows how you can take some existing code and modify it to your own requirements to accomplish a goal.
Hi, Boe!
Great script, thnx, but we have some issues with it
30-40 2012R2 servers
You script gives us exact one ProductKey for all servers.
But! If we run slmgr /dlv on servers – this command gives us very different Partial Product Keys
And if we run some 3rd-party software to get these full keys – they are different than in step 2
How can it be?? Two different objects called “Product Key” ??? How we can resolve this issue??
This script doesn’t work
edwinjor is the man. Had to Google Translate his message though 🙂
Open Windows PowerShell as Administrator.
Copy and paste the Script into the console.
Then press the enter key repeatedly until PS C: …
Now type Get-ProductKey and press enter.
Note:
Otherwise the script executes: Set-ExecutionPolicy Unrestricted
To export the result use: Get-ProductKey | Out-File c: \ productkey.txt
Otra manera de ejecutarlo es:
Abre Windows PowerShell como Administrador.
Copia y pega el Script en la consola.
Luego presiona varias veces la tecla enter hasta que muestre PS C:...
Ahora escribe Get-ProductKey y presiona enter.
Nota:
Sino ejecuta el script utiliza: Set-ExecutionPolicy Unrestricted
Para exportar el resultado utiliza: Get-ProductKey | Out-File c:\productkey.txt
The way this script is currently written it will not work on anything newer than Windows 7 and or 64bit. You can correct the script by replacing the try catch block that is actually doing the decoding with the following:
I have tested this on Windows Server 2012 R2 (and was actually able to install Windows Server 2012 R2 as a VM with the key that was returned), and I have tested this on Windows 10 which will return VK7JG-NPHTM-C97JM-9MPGT-3V66T which is a generic key that anybody who has Windows 10 will get when running a key finder on their machine, see http://www.maximumpc.com/microsoft-changes-rules-for-windows-10-activation-for-the-better/ for more information on that.
Thank you for providing the working try catch block. I attempted several of the other scripts I could find and I ended up with as many different and incorrect product keys. I was seriously considering a product key extractor third party tool until I modified the script with your try catch block. I have successfully tested the new script on two different systems Windows 8.1 Pro 64-bit and Windows 8.1 32-bit. Inside a VM I was able validate the modified script is getting the same results as iSunshare Product Key Finder.
What’s going on here again?
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 = $r % 24
}
$ProductKey = $map[$r] + $ProductKey
if (($i % 5) -eq 0 -and $i -ne 0) {
$ProductKey = “-” + $ProductKey
}
}
Hi,
We have a server in the cloud that is giving us a licensing error. When I run your script it returns the following. Does this mean I do not have a Productkey installed?
PS C:> Get-ProductKey -Computername Boe-PC,DC1
OSDescription Computername OSVersion ProductKey
————- ———— ——— ———-
Unreachable Boe-PC Unreachable Unreachable
Unreachable DC1 Unreachable Unreachable
I got the script to run by using the following in Powershell.
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
I can not run, error occurs:CategoryInfo : SecurityError: (:) [], ParentContainsErrorRecordException
Hi, my problem is I don’t get the full product key. I get X-Y-Z… where X, Y and Z are a 5 digit set of alphanumerics
Pipe it to an output grid. “script | Out-Gridview”
Pingback: How to find the Product Key on any version of Windows - fixedByVonnie
Bei mir wurde ebenfalls immer der gleiche Code angeziegt, dank deiner Arbeit habe musste ich aber nicht viel Zeit investieren, Danke!
CODE:
function Get-Productkey ($ComputerName) {
invoke-command -computername $ComputerName -scriptblock {
$map=”BCDFGHJKMPQRTVWXY2346789″
$value = (get-itemproperty “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion”).digitalproductid[0x34..0x42]
$ProductKey = “”
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 = $r % 24
}
$ProductKey = $map[$r] + $ProductKey
if (($i % 5) -eq 0 -and $i -ne 0) {
$ProductKey = “-” + $ProductKey
}
}
$ProductKey
}
}
Pingback: PowerShell获取Windows系统序列号 - PowerShell 中文博客
first script gives me different key
your script gives me something totally different.
I run ‘produkey’ software and it’s gives me something else.
I’m totally confuse. 🙂
Your script turns up the SAME product key for multiple machines that I run it against. What is up with that brother!
I don’t understand what you mean by “Dot Sourcing” normally with these scripts I download them run them and then get my report. But with the product key script it just doesn’t return any data or reports when I run it.
Where did you get this?:
” This is important because if the system is 64bit, the DigitalProductId4 key value must be used instead of DigitalProductId, otherwise you will not receive the accurate data for the product key.”
Based on my tests this is not correct.
Using DigitalProductId4 always derive an icorrect Product Key
Go to PowerShell, checkyour ExecPolicy setting with: #Get-ExecutionPolicy
If result is Restricted set to RemoteSigned with: #Set-ExecutionPolicy RemoteSigned
re-check your Policy …
then Load PS-Script with: #. .\Get-ProductKey.ps1
there is a [:space:] between the dots ._.\Get-ProductKey.ps1
i think that space is all poeples problem who are new to PS
then run function of that script with: Get-ProductKey
working fine
This is great and worked once I saw the note about ..\thescriptname. Thanks!
I know this is a pretty old post, but I’m confused. I enter a product key to activate windows, and it works. Then I run this script, and it returns a different value for the product key. What’s going on here?
Hi, i tryed your code and it worked great. I am kind of new to Powershell and I have a question? How can i get this script to check if the productkey is active and return a TRUE/FALSE response?
Thanks.
When i run your script, the first one, i get no output. I am only trying to retrieve info off the local computer. I have tried . .\get-productkey, . .\get-productkey mycomputername, . .\get-productkey mycomputername, . .\get-productkey -computername mycomputername. I have also tried it without the dot sourcing. Please Advise.
You’re close. First dot source the script and then run the function.
. ./Get-ProductKey.ps1
Get-ProductKey
Boe Prox, I’ve already come to see the Client UI but after I put in username and serve IP It can’t connect to the server, then the server-side PowerShell had the remind tips said BOB has disconnected from the server
Same here, when I run the script, I get no output at all (no errors either).
OK, dot sourcing the script resolved this problem. You basically have to put a dot and then a space before the name of the script before you can run it successfully (. Get-ProductKey.ps1 and then run Get-ProductKey)
Now I am getting the wrong key though. I queried 3 different systems and they all came up with the same product key. Two of the systems were Windows 2008 R2 servers and one is a Windows 7 box.
I’m having some issues getting results from this. I have it running seemingly fine, and am passing it a list of computers from a file. It gets parsed ok, and since some of the names aren’t on the network currently, they come up ‘unreachable’ , which is to be expected. However, none of the other names that should be returning results actually are returning a key.
I get “Exception Callin…” in the Product Key column, and that’s it. Seems like it’s catching and truncating the exception to fit in my PS window, even when I output to a file via “| Out-File keys.txt”.
This is on remote machines. If I run it with just the local name it seems to get a key, however that is truncated as well.
Being rather new to the PS world, I’m not really sure how to prevent such truncating, nor what the exception might be likely to say. Any advice on this, or the Exception Calling problem?
Executing it bit by bit on a few different names yields the ‘Exception Callin..’ is likely ‘Exception calling “OpenRemoteBaseKey” with “2” argument(s): “The network path was not found”, which is a bit more descriptive of an error.
Figured it out. The Remote Registry service was not running.
Cool! Glad you were able to figure it out!
Having some issues running this. I have it running just fine, and am passing it a list of computers from a file. It gets parsed ok, and since some of the names aren’t on the network currently, they come up ‘unreachable’ , which is to be expected. However, none of the other names that should be returning results actually are returning a key.
I get “Exception Callin…” in the Product Key column, and that’s it. Seems like it’s catching and truncating the exception to fit in my PS window, which even when I output to a file via “| Out-File keys.txt”.
This is on remote machines. If I run it with just the local name it seems to get a key, however that is truncated as well.
Being rather new to the PS world, I’m not really sure how to prevent such truncating. Any advice on this, or the Exception Calling problem?
Hi Boe, thank you for all your hard work. I got this to work today in a domain environment but I am not sure why the Product Key is actually different than the license key on the box. Now, a product key finder will return the key on the box versus the Product Key that Get-ProductKey finds. Maybe I am missing something simple here, but are they supposed to be different?
Works fine:
function Get-ProductKey {
script code
}
Get-ProductKey
or
Get-ProductKey -Computer
how can i provide a list of computers from a “computers.txt: and export the result to “result.txt”
I’m not sure where I’m going wrong. I run:
.\get-productkey
get-productkey -computername (servername)
Result:
…
+ FullyQualifiedErrorId : CommandNotFoundException
I run:
.\Get-ProductKeydownloaded.ps1 Get-productkey -computername (servername)
Result: Nothing
Even if I output it to a txt file:
.\Get-ProductKeydownloaded.ps1 Get-productkey -computername (servername) >> C:\Tmp\test.txt
The result is an empty txt file.
Running this as a script will not work. You have to dot source the function into the session.
. .\Get-ProductKey.ps1
Then run the function to get it to work.
Boa Noite!
Executei o script de forma correta, o resultado não está correto.
A Chave Serial que retorna não é a mesma utilizada para instalar o windows, tentei em diversas plataformas. Foi realizada alguma correção? Grato, Fabrício Paim
When I am executing i am getting below error
File E:\Get-ProductKey.ps1 cannot be loaded. The file E:\Get-ProductKey.ps1 is not digitally signed. The script will no
t execute on the system. Please see “get-help about_signing” for more details..
At line:1 char:22
+ ..\Get-ProductKey.ps1 <<<<
+ CategoryInfo : NotSpecified: (:) [], PSSecurityException
+ FullyQualifiedErrorId : RuntimeException
You will need to unblock the file,either via the properties of the script or using Unblock-File in PowerShell V3.
Good night!
I ran the script correctly, the result is not correct.
Serial Key that returns is not the same one used to install the windows, tried on several platforms. A correction was made? Grateful, Fabricio Paim
I run the script on window 7 but no result after running the script ( no error as well)
Why doesnt the script work for me? I set set-exec pol unrestricted run the ps1 file and get the warning to allow Run once and returns nothing…..
There is a function in the .ps1 file that needs to be dot sourced before it will work.
ex. . .\get-productkey.ps1
Get-ProductKey -Computername
When I run this on some PC’s I get this “Exception calling “OpenRemoteBaseKey” with “2” argument(s): “The network path was not found….” where the product key is supposed to be. Any Ideas?
In case anyone else wants to follow along, this discussion was taken to powershell.org. http://powershell.org/discuss/viewtopic.php?f=29&t=238
When I run the script it asks me if I want to run. Then I run once and it doesn’t output anything. Just puts me right back in the directory I started.
Hi, I have run your script on windows 7 64bit as “PS C:\Scripting> .\Get-ProductKey.ps1” and I get no report back. Tried it with -Computername… and still got no results. I have also tried it on other windows 7 32bit comps and did not receive any results.
This is actually a function that resides in the script, so you need to dot-source the script before using the function.
. .\Get-ProductKeys.ps1
Get-ProductKeys
Hi, I tried executing this on several systems which consists of combinations of 32 & 64bits systems. On the output, on the license key column show “Cannot index into a null array.”
Hmmm… When running against 64 bit systems, you need to make sure that you are running it from a 64 bit system. Also, while I don’t think it should matter, are you also running it from an Administrator prompt (run as administrator)?
Hi, sorry but download of your script is not possible 😦 http://gallery.technet.microsoft.com/scriptcenter/Get-product-keys-of-local-83b4ce97
Weird, I can download it just fine. What problems are you seeing with the download?
It does nothing on my system – reports nothing back either – bummer
Can you provide the syntax that you are using to run the code? Also can you let me know how you are running it (elevated prompt, OS, etc…)?
Hi, I do not understand this – at 8 July I not download script – after accept licence agreement at MS Script Repository is nothing happen (not action for file download). but today is working…
thanks for you script I test …