Getting computer models in a domain using Powershell

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

Find the computer manufacturer and model as reported from the system (U)EFI/BIOS using PowerShell in various ways I describe in this article. This article was old crap that I've now rewritten. It was from when I was in an earlier stage of learning. Some parts are outdated still (the WSUS stuff, but you can adapt the code), but I've fixed most of it.

One approach could be using a computer with PowerShell version 3 or higher so you have the "PSComputerName" property returned from Invoke-Command, set up PSRemoting, which also works against PowerShell version 2, and run something like you see below.

Scroll down or click the table of contents to go to CIM/WMI approaches. CIM requires PSv3 (Windows Management Framework 3) on the target computers. WMI works (can work) even if the remote computer doesn't have PowerShell, but that's becoming a rarity fast.

PS C:\> Invoke-Command -ErrorVariable myerr -ErrorAction Silent -Cn (Get-ADComputer -Filter * | % Name) `
 -Script { gwmi win32_computersystem | % { "$($_.Manufacturer) $($_.Model)" } } |
 Select-Object -Property PSComputerName, @{n='ComputerModel'; e={ $_ }} |
 Format-Table -AutoSize

PSComputerName ComputerModel
-------------- -------------
2012R2         Microsoft Corporation Virtual Machine
WIN7PSV3       Microsoft Corporation Virtual Machine
WIN7           Microsoft Corporation Virtual Machine
ELITEBOOK2015  Hewlett-Packard HP EliteBook 840 G2
DELL2010       Dell Inc. Latitude E6420
STUEPC         System manufacturer System Product Name

Get-computer-model-example-modern.png




Getting Computer Model As Reported by the System BIOS

Here you will find various ways of getting the computer hardware models, as reported by the BIOS, of computers in a domain in a corporate, educational or similar environment. This is an absolute overkill, batter-to-death solution for a slightly obscure use case.

To see how to get a list of computers from Active Directory, see the following article: Getting Computer Names From AD Using PowerShell.

Here is the quick one-liner some of you might be looking for, so I will put it at the top:

PS C:\> (gwmi Win32_ComputerSystem).Model
LIFEBOOK S7010
PS C:\>

Or a slight variation, as demonstrated below.

Side note: Most vendors like HP, Dell, Fujitsu-Siemens, etc. do label their motherboards, but with home-built computers you will often find that there's a default or non-descriptive name, like in this example. It's actually an Asus motherboard.

PS C:\> Get-WmiObject Win32_ComputerSystem | Select -Expand Model
System Product Name
PS C:\>

To target a remote computer, simply add the parameter "-ComputerName server01" to gwmi/Get-WmiObject.

Pipe to Get-Member instead of Select to see all properties, or Select * - or Format-List *.

From WSUS

If you have WSUS set up against the desired target computers, this will be an easy and efficient way to get the information which has already been collected and stored in a database.

Sample Output

Below is some sample output from computers in an institution.

PS C:\powershell\wsus> .\get-wsus-models.ps1 > models.txt
PS C:\powershell\wsus> type .\models.txt | Select-Object -first 10
Found 974 computers
Found 127 unique models

Name                                    Value
----                                    -----
OptiPlex 760                            64
HP Compaq dc7600 Small Form Factor      55
OptiPlex GX620                          53
HP Compaq dc7900 Small Form Factor      49
HP Compaq 8000 Elite CMT PC             43

Script Code

Below is sample PowerShell code to be run on a WSUS server (download Get-models-wsus.ps1.txt). If you get the error "Exception calling "GetUpdateServer" with "0" argument(s): "Exception of type 'Microsoft.UpdateServices.Administration.WsusInvalidServerException' was thrown."" - please make sure you are running the script from a PowerShell console window with elevated privileges (right-click and choose "Run as administrator").

[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | Out-Null

# This function removes text between parentheses
function massageModel {
    
    param([Parameter(Mandatory=$true)][string] $private:model)
    
    $private:model = $private:model -replace '\s*\([^)]+\)\s*$', ''
    $private:model = $private:model -replace '\s+$', ''
    
    return $private:model
    
}

# Create a WSUS object
if (!$wsus) {
    
    $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()
    
}

# Create a computer scope object and set the criteria to "All" update installation states
# to target all computers in the WSUS database.
$computerScope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::All

# Get all the computer objects
$computers = $wsus.GetComputerTargets($computerScope)

'Found ' + $computers.Count + ' computers'

# Initialize hash
$models = @{}

# Store "massaged" models in a hash (keys are unique)
# and count the number of models.
$computers | Foreach-Object { $model = massageModel $_.Model; $models.$model += 1 }

'Found ' + $models.count + ' unique models'

# Output the data, sorted with the most common models
# first and then alphabetically.
$models.GetEnumerator() |
  Sort-Object -Property @{Expression='Value';Descending=$true},@{Expression='Name';Descending=$false} |
  Format-Table -AutoSize

You can of course adapt this as necessary.

Using CIM/WMI

Find a computer with PowerShell version 3 or higher and just use something like this after you've set up PSRemoting. You can actually just replace "Get-CimInstance" with "Get-WmiObject" in this example to target systems without Windows Management Framework 3. I notice the Windows 7 computer I installed PSv3 on responds to the CIM cmdlet as well.

Screenshot example:

Computer-model-get-ciminstance-example.png

As text:

PS C:\> $res = Get-CimInstance -Cn (Get-ADComputer -Filter * | % Name) `
   -Class Win32_ComputerSystem -EA Silent -ErrorVar myerr |
   Select PSComputerName, @{ Name = "ComputerModel"; Expression = {
       "$($_.Manufacturer.Trim()) $($_.Model.Trim())" } }
PS C:\> $res.Count
6
PS C:\> $res | Format-Table -AutoSize

PSComputerName ComputerModel
-------------- -------------
2012R2         Microsoft Corporation Virtual Machine
SERVER2016     Microsoft Corporation Virtual Machine
WIN7PSV3       Microsoft Corporation Virtual Machine
STUEPC         System manufacturer System Product Name
DELL2010       Dell Inc. Latitude E6420
ELITEBOOK2015  Hewlett-Packard HP EliteBook 840 G2

Using PsExec

This requires psexec.exe which you can download from Microsoft Technet - Sysinternals (http://www.sysinternals.com redirects there, because it is now Microsoft-owned) and the get-model.vbs file which you can download here or below.

PsExec isn't really a great approach, but here it is. As I mentioned at the top, this is an old article from an earlier stage of learning. I have later fixed it a bit with my Invoke-PsExec script module, but I doubt you want this. Then you can use WMI directly instead. Use Get-WmiObject instead of Invoke-Command like in the example at the top and adapt the rest.

PS C:\> # Install-Module -Name InvokePsExec # (if you have WMF 5 or WMF3 and nuget, etc.)
PS C:\> Invoke-PsExec -Cn 2012r2 -IsPS -Command 'gwmi win32_computersystem | % { "$($_.Manufacturer) $($_.Model)" }'
  -HideSummary | Format-List ComputerName, STDOUT


ComputerName : 2012r2
STDOUT       : Microsoft Corporation Virtual Machine

Get-computer-model-example-invoke-psexec-updated.png

Old Script Code

This is obsolete!