PowerShell Hardware Inventory Script
Scenario:
PowerShell hardware Inventory Script.
Have you ever wanted to have an inventory without the hassle of going to each finding the information needed to fill the information for your inventory? It is important to keep your inventory up to date. Every time there is a change you will need to update also your inventory. As much information you have in your inventory the easiest will be when you will need this information. I came up with the below script just for a basic inventory with information to be taken automatically. In general the script will connect to all computers in the network and gather the information needed.
Lets see in more detail
The first part of the script is only the description and help information of the script that can be retrieved by using Get-Help command. Then, the script starts doing the actual work. An empty array list is created that we will fill it through the process. After the array will be created the script will connect to Active Directory and get all computer names to create the list that will be used to retrieve the information for each one. When we will have the list then we will go through a loop to gather the information. The first step is to check if there is a connection to the computer. If the connection is OK the script with will connect to the computer for the information. Before connecting to the computer, we are creating an object to keep the information and then we will add the values to the array list.
Operating System and Service Pack, are retrieved from Active Directory so there is no problem whether we have a connection to the computer or not. So before we start the process and after the creation of the object we get the information for Operating System and Service Pack. We keep them in variables to be used later and the moving forwarding to get the rest of the information if the connection test was successful.
Loop through the list
As you can see on the first command the we will get the manufacturer of the computer, model, number of processors and RAM. Ad you will noticed for RAM we have a small expression. This expression will get process the information of RAM as it is retried in Bytes and converts it in GB. Using the second command we will get the information about CPU. Actually we keep the CPU ID, manufacturer of CPU, name of CPU, number of cores and number of logical processors. The third command will retrieve the information about disks. We will save their Drive Letter, Name (if it exists) and size. As you can see again, an expression is used to convert the size of the drive in GB. Now we have finished with the collection of the information we need for this computer and we will proceed to add those values in our object that we have created before.
Before we will add the information to the object, we save each property on a different variable so it will be easier for to be used on the next commands. So as you will see a block of commands is only about saving the property values to variables. After that we use those variables and we fill the object with those properties. When the object is ready, the object is added in the array list so we will be able to continue with the next computer. As you can see also, after adding the object to the array, we set three variable to null. The reason we are doing this is to be ready for the next computer. If the next computer is not reachable, or we are not able to connect due to issue with WMI, then we do not want the property values of the previous computer to be added in this one. With this way we ensure that the variables are always empty.
Reporting
After the loop has been completed and processed all computer names in the list, we array list is filled with the values / properties of each one. Then we are exporting this array list to a csv file. As this a basic script with basic functionality, there are some minor things that you need to know for the values. We aim is to create a basic inventory and not a fully functional inventory. There are some values that you might consider to edit, so our inventory will be more readable. One of the values are the drive letters, if there are more that one drive in the computer. All drive letters are under the same cell in Microsoft Excel. There are some of you that you might want to add more columns and separate them. The second value that you need notice is RAM. You will see that RAM value has a lot of decimal places. You need to change the format of this column, so the numbers will not have any decimal places.
The last value that you need to check is the size of the drive. We have a combination of the 2 previous cases. All sizes appear in the same cell in Microsoft Excel but in the same order as the drive letters. The numbers have a lot of decimal places again so you will need to removed change the format of the cells so that they will not contain any decimal places. In the case that the are 2 size values in the same cell, then you have to separate the 2 values, so the removal of decimal places will work.
Permissions
Last thing that I have to mention so this script will work. The user that will run the script, needs to have at least read permission on Computer Objects in Active Directory for the Name, OperatingSystem, OperatingSystemServicePack attributes. Now in relation to the permissions needed for computers, the user needs WMI permissions on each computer so it will run smoothly. If the user does not have permission for Active Directory then the script will not be able to retrieve the computer names. If the user does not have WMI permissions on a computer then the script will throw errors for each computer that the users does not have permissions.
You can download the script here or copy it from below.
Hope you like it. If you have any questions or anything else please let me know in the comments below.
Related Links:
- PowerShell script to get computer information
- How to get remote system information – Part 3
- PowerShell Hardware Inventory Script – Part 2
- New-Object – Microsoft Docs
- Test-Connection – Microsoft Docs
- Get-ADComputer – Microsoft Docs
- Add-Member – Microsoft Docs
- Get-WmiObject – Microsoft Docs
- Out-Null – Microsoft Docs
- Export-Csv – Microsoft Docs
- Get-Help – Microsoft Docs
Solution / Script:
<#
.SYNOPSIS
Name: Get-Inventory.ps1
The purpose of this script is to create a simple inventory.
.DESCRIPTION
This is a simple script to retrieve all computer objects in Active Directory and then connect
to each one and gather basic hardware information using WMI. The information includes Manufacturer,
Model, CPU, RAM, Disks and Operating System.
.RELATED LINKS
Home
.NOTES
Release Date: 10-02-2018
Author: Stephanos Constantinou
.EXAMPLE
Get-Inventory.ps1
Find the output under C:\Scripts_Output
#>
$Inventory = New-Object System.Collections.ArrayList
$AllComputers = Get-ADComputer -Filter * -Properties Name
$AllComputersNames = $AllComputers.Name
Foreach ($ComputerName in $AllComputersNames) {
$Connection = Test-Connection $ComputerName -Count 1 -Quiet
$ComputerInfo = New-Object System.Object
$ComputerOS = Get-ADComputer $ComputerName -Properties OperatingSystem,OperatingSystemServicePack
$ComputerInfoOperatingSystem = $ComputerOS.OperatingSystem
$ComputerInfoOperatingSystemServicePack = $ComputerOS.OperatingSystemServicePack
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "Name" -Value "$ComputerName" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $ComputerInfoOperatingSystem
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "ServicePack" -Value $ComputerInfoOperatingSystemServicePack
if ($Connection -eq "True"){
$ComputerHW = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ComputerName | select Manufacturer,Model,NumberOfProcessors,@{Expression={$_.TotalPhysicalMemory / 1GB};Label="TotalPhysicalMemoryGB"}
$ComputerCPU = Get-WmiObject win32_processor -ComputerName $ComputerName | select DeviceID,Name,Manufacturer,NumberOfCores,NumberOfLogicalProcessors
$ComputerDisks = Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -ComputerName $ComputerName | select DeviceID,VolumeName,@{Expression={$_.Size / 1GB};Label="SizeGB"}
$ComputerInfoManufacturer = $ComputerHW.Manufacturer
$ComputerInfoModel = $ComputerHW.Model
$ComputerInfoNumberOfProcessors = $ComputerHW.NumberOfProcessors
$ComputerInfoProcessorID = $ComputerCPU.DeviceID
$ComputerInfoProcessorManufacturer = $ComputerCPU.Manufacturer
$ComputerInfoProcessorName = $ComputerCPU.Name
$ComputerInfoNumberOfCores = $ComputerCPU.NumberOfCores
$ComputerInfoNumberOfLogicalProcessors = $ComputerCPU.NumberOfLogicalProcessors
$ComputerInfoRAM = $ComputerHW.TotalPhysicalMemoryGB
$ComputerInfoDiskDrive = $ComputerDisks.DeviceID
$ComputerInfoDriveName = $ComputerDisks.VolumeName
$ComputerInfoSize = $ComputerDisks.SizeGB
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "Manufacturer" -Value "$ComputerInfoManufacturer" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "Model" -Value "$ComputerInfoModel" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "NumberOfProcessors" -Value "$ComputerInfoNumberOfProcessors" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "ProcessorID" -Value "$ComputerInfoProcessorID" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "ProcessorManufacturer" -Value "$ComputerInfoProcessorManufacturer" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "ProcessorName" -Value "$ComputerInfoProcessorName" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "NumberOfCores" -Value "$ComputerInfoNumberOfCores" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "NumberOfLogicalProcessors" -Value "$ComputerInfoNumberOfLogicalProcessors" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "RAM" -Value "$ComputerInfoRAM" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "DiskDrive" -Value "$ComputerInfoDiskDrive" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "DriveName" -Value "$ComputerInfoDriveName" -Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "Size" -Value "$ComputerInfoSize"-Force
}
$Inventory.Add($ComputerInfo) | Out-Null
$ComputerHW = ""
$ComputerCPU = ""
$ComputerDisks = ""
}
$Inventory | Export-Csv C:\Scripts_Output\Inventory.csv
Thanks for posting PS, will get a good use out of it.
I’d probably add below to also grab bios info which is mostly useless but contains the serial number of the machine which can be good for lease tracking etc.
$ComputerBios = get-ciminstance win32_bios -ComputerName $ComputerName | select SMBIOSBIOSVersion,Manufacturer,Name,SerialNumber,Version,PSComputerName
$ComputerInfo | Add-Member -MemberType NoteProperty -Name “SMBios Version” -Value “$ComputerInfoBiosSMBIOSBIOSVersion”-Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name “Bios Manufacturer” -Value “$ComputerInfoBiosManufacturer”-Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name “Bios Name” -Value “$ComputerInfoBiosName”-Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name “Bios Version” -Value “$ComputerInfoBiosVersion”-Force
$ComputerInfo | Add-Member -MemberType NoteProperty -Name “Bios PSComputerName” -Value “$ComputerInfoBiosPSComputerName”-Force
Dear Maciej,
Thank you for your comments. I am looking into this script to add more features and information. I will post accordingly.
Thanks
Stephanos
Hi Stephanos,
I really appreciate your work, well done!
Just a question: I ran the script on my domain controller running Windows Server 2012 64 bit but for every PC (15 Windows 7 Professional 64 bit and 3 Windows 10 Professional 64 bit) I got same 3 errors
Get-WmiObject : Server RPC non disponibile. (Eccezione da HRESULT: 0x800706BA)
In C:\demo\Get-Inventory.ps1:46 car:21
+ $ComputerHW = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $Com …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Get-WmiObject : Server RPC non disponibile. (Eccezione da HRESULT: 0x800706BA)
In C:\demo\Get-Inventory.ps1:47 car:22
+ $ComputerCPU = Get-WmiObject win32_processor -ComputerName $ComputerName | …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Get-WmiObject : Server RPC non disponibile. (Eccezione da HRESULT: 0x800706BA)
In C:\demo\Get-Inventory.ps1:48 car:24
+ $ComputerDisks = Get-WmiObject -Class Win32_LogicalDisk -Filter “DriveType …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Could be so kind to help me solving this issue?
Thank you in advance
Roberto
Hi Roberto,
Have you checked WMI is enabled on every PC? In order to establish a connection with the remote PCs you need to enable WinRM. You can run the below command to see if the service is running and if not enable it and try again.
Thanks
Stephanos
Hi Stephanos,
Great script and thanks very much for posting it.
A question though. When trying it out I keep getting an error on getting the computer name in $Connection = Test-Connection $ComputerName -Count 1 -Quiet because the argument is null or empty
and thus also in $ComputerOS = Get-ADComputer $ComputerName -Properties OperatingSystem,OperatingSystemServicePack because the argument is null.
Running from the DC, and trying each line as stand alone, I get a result.
Any ideas?
Thanks!
Hi Yair,
Have you tried to get the list of computers from AD on the PC that you have the problem?
Thanks
Stephanos
Hi Stephanos,
It’s great script, helps a lot.
I was wondering if this could query two domains ?