Find the Full Windows Build Number with PowerShell

Much to my surprise I discovered that the full build number for a Windows OS is not stored in WMI in the usual Win32_OperatingSystem class.

In Windows 10 at least, the full build number containing the “UBR”, or essentially the CU patch level of the build, is a useful piece of information.

Open Settings > System > About on a Windows 10 box, and you’ll find the OS Build value, in my case 15063.183

W10

If I run the usual WMI query to get the build number I just get 15063:

WMI

Same if I query the environment:

DotNet

To find the full number I have to query the registry in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion branch.

So I put together a PowerShell script that can be used to get the Windows version for a local or remote computer (or group of computers) which includes the Edition, Version and full OS Build values.

Query the local system like this:


Get-WindowsVersion

Or query remote computers:


Get-WindowsVersion -ComputerName PC001


Get-WindowsVersion -ComputerName @("PC001","PC002","SRV001","SRV002")

Result:

result

The script


[CmdletBinding()]
Param
(
[Parameter(Mandatory=$false,
ValueFromPipelineByPropertyName=$true,
ValueFromPipeline=$true
)]
[string[]]$ComputerName = $env:COMPUTERNAME
)
Begin
{
$Table = New-Object System.Data.DataTable
$Table.Columns.AddRange(@("ComputerName","Windows Edition","Version","OS Build"))
}
Process
{
Foreach ($Computer in $ComputerName)
{
$Code = {
$ProductName = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ProductName).ProductName
Try
{
$Version = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ReleaseID -ErrorAction Stop).ReleaseID
}
Catch
{
$Version = "N/A"
}
$CurrentBuild = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name CurrentBuild).CurrentBuild
$UBR = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name UBR).UBR
$OSVersion = $CurrentBuild + "." + $UBR
$TempTable = New-Object System.Data.DataTable
$TempTable.Columns.AddRange(@("ComputerName","Windows Edition","Version","OS Build"))
[void]$TempTable.Rows.Add($env:COMPUTERNAME,$ProductName,$Version,$OSVersion)
Return $TempTable
}
If ($Computer -eq $env:COMPUTERNAME)
{
$Result = Invoke-Command -ScriptBlock $Code
[void]$Table.Rows.Add($Result.Computername,$Result.'Windows Edition',$Result.Version,$Result.'OS Build')
}
Else
{
Try
{
$Result = Invoke-Command -ComputerName $Computer -ScriptBlock $Code -ErrorAction Stop
[void]$Table.Rows.Add($Result.Computername,$Result.'Windows Edition',$Result.Version,$Result.'OS Build')
}
Catch
{
$_
}
}
}
}
End
{
Return $Table
}

23 thoughts on “Find the Full Windows Build Number with PowerShell

  1. Wauw, beside your nice script, this must be the coolest .net class I’ve ever seen System.Data.DataTable Many Thanks for that, nice and easy way to create objects..I guess better than the hashtables everyone knows about to create PCCustomobjects…or which one is in your opinion more a favorite?

    1. Thanks, hashtables are perfectly cool too 🙂 I often query SQL data so I’m in the habit of using the datatable format, but it works quite well for general use too.

  2. What am I missing here? I can run the script and return the local computers value. But, I can’t seem to figure out how to return remote system values and groups of remote system values.

  3. function Get-WindowsVersion {

    ^ required on line one for the script to work properly with the command indicated.

    Maybe this was implied? I had to ask IRC to get this information. I hope this helps anyone else trying to use the script.

    1. You can also call this like: ‘.\Get Computer Build Number.ps1’ -ComputerName ‘Name’ | Export-csv ‘path’

      or: ‘.\Get Computer Build Number.ps1’ -ComputerName @(‘Name’, ‘Name1’) | Export-csv ‘path’

    2. Hey Paul. I’m trying the same thing you are, but cant seem to figure out what you mean above. Can you post the modified script for remote users?

      Thanks.

  4. Excellent script that saved me a lot of work. Thank you Trevor for sharing.
    And thank you Paul R. for your notice

  5. OK, I can get the script to work on my local machine, but how do you make this script get the info for 500 machines? I have a txt file with the PC names, how can I make it read each name in the txt file and display the Windows Version?

    Thanks,

    1. If your file is just computer names: Get-Content .\Yourfile.txt | .\NameOfTheScript.ps1
      If your file is a CSV, name column header “ComputerName” then: Import-Csv .\YourFile.csv | .\NameOfTheScript.ps1

      Either of those should work since the has “ValueFromPipelineByPropertyName = $true” which handles the CSV with proper column name and “ValueFromPipeline = $true” takes any string input from pipeline.

  6. I’m going to go ahead and put my ignorance on full display here, but since I am only barely familiar with Powershell, I absolutely cannot fill in the blanks between the script as originally written and the modifications offered or changing the way the script is initiated. Are lines being added? Is the script being run in the ISE version or just straight powershell? Does it matter? If lines are being added, where? The solutions for modifying the script above might work wonderfully for those who know how to integrate them, but following *any* of them at face value consistently produces error messages that indicate that the term used is not recognized. Or in the case of trying to run the script by typing “scriptname.ps1” returns with the term is not recognized as the name of a cmdlet, function, script file, or operable program. I am completely unable to get any of the modifications to actually work.

    Paul R gives us: function Get-WindowsVersion {
    Importantly, he adds that this be added in line 1, but when I do, this only breaks the script and I continue to see that Get-WindowsVersion is not recognized.

    Chase R gives us: Get-Content .\Yourfile.txt | .\NameOfTheScript.ps1. Subbing in my own files in place of the sample names offered, I get the message that Get-Content is not recognized. Running Get-Content by itself, works, but the result is simply to print out what I typed into my CSV file and the script, which is not at all the result I am looking for. How do I get the script to refer to the CSV file for computer names to address? Screen shots will probably work better than description alone.

    1. just execute Get-Content .\servers.txt | .\Get-WindowsVersion.ps1. it works
      exemple content of servers.txt :
      server1
      server2

  7. When trying to run this script, it works fine on my local machine however when I pass it a computer name using -computername, it returns an error saying it couldn’t connect to the destination specified in the request. When I try to use a cmdlet such as get-service -computername ‘Name’ it returns the information just fine. If I try adding the function line to line 1, it does not return anything at all. Any ideas what I am doing wrong?

      1. How do you replace the Invoke-Command with something so it can reach the remote computers from the list.txt?

    1. Enable PSRemoting and use it as intended. Otherwise, you’d have a bunch of redo to enable remote registry, WMI, and firewall rules for both. Off the top of my head those are just the least that would probably need to be done. Instead just enable the more secure PSRemoting and you’re good.

  8. Hi,
    I’m trying to get the Windows Versions of computers in our AD environnement.
    For some reason i can’t find, when i use the Get-WindowsVersion function in a foreach loop, it always ends up telling me the computer name is not valid.
    $a = Get-ADComputer ….filters…. | select Name
    foreach($b in $a)
    Get-WindowsVersion -Computername $b.Name
    Is not working. Can anyone point me to my mistake please ? Its probably pretty obvious but im a real newbie in PS…

    1. Looks like my post didn’t go through, so hopefully this does not duplicate. I just use the following one liner to get info for server01, server02, server03, server04, server05, etc.:

      Get-ADComputer -Filter { Name -like ‘server0*’ } | select -ExpandProperty Name | Get-WindowsVersion

      or similar to your way but in a one-liner:

      Get-ADComputer -Filter { Name -like ‘server0*’ } | foreach { Get-WindowsVersion -ComputerName $_.Name }

      Explanation: The script/function accepts pipeline input via property and raw pipeline. Since “ComputerName” is not part of the results of “Get-ADComputer” AD object the pipeline via property does not work. So you need to give it raw piple data by expanding the property with “select -ExpandProperty Name” which sends just a list of names down the pipeline which the script/function can read. Similaryl using the foreach in the pipeline you can specify the “$_.Name” to get the same result.

      To use your method you’re missing the curly braces and you can keep or do without the “select Name”:

      $a = Get-ADComputer -Filter { Name -like ‘server0*’ }
      foreach ($b in $a)
      {
      Get-WindowsVersion -ComputerName $b.Name
      }

      Also you could just loop through the Name using the slightly different foreach:

      $a = Get-ADComputer -Filter { Name -like ‘server0*’ }
      foreach ($b in $a.Name)
      {
      Get-WindowsVersion -ComputerName $b
      }

  9. Thanks very much for the script, I can run it all good. But what I found is that the Version number is not correct.
    For example: it shows: ” Windows 10 Enterprise 2009 19044.2846 ” , but actually it is 21H2 instead of 2009 . ( the build number is correct)
    On the other hand, if build number 19044 related version number is 21H2, then I can simply run CMD-> “systeminfo /s [computer name] ” to get the build number , then convert it to version number. Is it?

Leave a reply to praphulk02@gmail.com Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.