I am using the following code to pull system info from a list of computers in a txt file. The info seems to be pulling correctly for the most part, & the write-host command displays the correct returned values, but in my results file, I am getting duplicated computer names even though the list does not contain dupe entries & the progress shown in the terminal host shows all different info for the list of names. Anyone have any ideas why this might be writing to the csv file this way?
Thanks!
set-location "c:\myfolder"
$ErrorActionPreference = 'SilentlyContinue'
$exportFile = 'c:\myfolder\system-info.csv'
$TstConnect = test-connection $Computer
$t = 0
$i = 0
$tab_char = [char]9
#Clear screen & old file
Clear-Host
try {
# Attempt to open the file exclusively for read access
$file = [System.IO.File]::Open($exportfile, 'Open', 'Read', 'None')
$file.Close() # Close the file if successful
Write-Host "File $exportfile is not open. Deleting old results file... $exportfile" -BackgroundColor DarkCyan
remove-item $exportFile
} catch {
Write-Host "File is open or in use by another process. Ending the task." -BackgroundColor DarkRed
break
}
# Get Totals
foreach ($Computer in Get-Content c:\myfolder\computers.txt)
{
$t++
}
write-Host "$t total computers " -BackgroundColor DarkCyan
foreach ($Computer in Get-Content c:\myfolder\computers.txt) {
$i++
$p = "{0:N1}" -f ($i * 100 / $t)
if ($TstConnect.IPV4Address.IPAddressToString[0]) {
$computerSystem = get-wmiobject Win32_ComputerSystem -Computer $Computer
write-Host $computerSystem.name "is online, checking $tab_char $i of $t $tab_char $p% complete " -BackgroundColor DarkCyan
$computerBIOS = get-wmiobject Win32_BIOS -Computer $Computer
$AssetTag = Get-WmiObject -Class Win32_SystemEnclosure -Computer $Computer | Select-Object SMBiosAssetTag
$computerOS = get-wmiobject Win32_OperatingSystem -Computer $Computer
$computerCPU = get-wmiobject Win32_Processor -Computer $Computer
$computerNET = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $Computer | Where-Object { $_.IPAddress -ne $null -and $_.Description -like "*Ethernet*" }
$computerIP = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName $computer | Select-Object -Property ipaddress
$computerHDD = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter drivetype=3
$csvObject = New-Object PSObject -property @{
'PCName' = $computerSystem.Name
'MACAddress' = $computerNET.MACAddress
'IPAddress' = ($computerIP.ipaddress)[0]
'Manuf' = $computerSystem.Manufacturer
'Model' = $computerSystem.Model
'AssetTag' = $AssetTag.SMBiosAssetTag
'SerialNumber' = $computerBIOS.SerialNumber
'RAM' = "{0:N2}" -f ($computerSystem.TotalPhysicalMemory/1GB)
'HDDSize' = "{0:N2}" -f ($computerHDD.Size/1GB)
'HDDFree' = "{0:P2}" -f ($computerHDD.FreeSpace/$computerHDD.Size)
'CPU' = $computerCPU.Name
'OS' = $computerOS.caption
'Version' = $computerOS.Version
'SP' = $computerOS.ServicePackMajorVersion
'User' = $computerSystem.UserName
'BootTime' = $computerOS.ConvertToDateTime($computerOS.LastBootUpTime)
}
}
else{
write-Host "$Computer is not online... $p% complete" -BackgroundColor DarkRed
$csvObject = New-Object PSObject -property @{
'PCName' = $Computer
'Manuf' = "xxxxx"
'Model' = "xxx Offline xxx"
'SerialNumber' = "xxxxx"
'AssetTag' = "xxxxx"
'RAM' = "xxxxx"
'HDDSize' = "xxxxx"
'HDDFree' = "xxxxx"
'CPU' = "xxxxx"
'OS' = "xxxxx"
'Version' = "xxxxx"
'SP' = "xxxxx"
'User' = "xxxxx"
'BootTime' = "xxxxx"
'MACAddress' = "xxxxx"
'IPAddress' = "xxxxx"
}
}
$csvObject | Select PCName, HDDFree, Manuf, Model, OS, Version, SP, User, BootTime, MACAddress, IPAddress, AssetTag | Export-Csv $exportfile -NoTypeInformation -Append
}
Write-host "All computers processed. File created at $exportfile"
do {
$response = Read-Host -Prompt "Do you want to open the file to view it? (Y/N)"
if ($response -eq "Y") {
Write-Host "Opening $exportfile..."
Start-Process -FilePath $exportfile
break
} elseif ($response -eq "N") {
Write-Host "Exiting..."
break
} else {
Write-Host "Invalid input. Please enter Y or N."
}
} while ($true)
Nowadays, you should use Get-CimInstance
in favour of Get-WmiObject
.
Then, beware of the fact that you may have (or in the future will have) computers with multiple harddisks.
$sourceFile = 'D:\Test\computers.txt'
$exportFile = 'D:\Test\system-info.csv'
# from https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-systemenclosure
$chassisTypes = 'Unknown','Other','Unknown','Desktop','Low Profile Desktop','Pizza Box','Mini Tower',
'Tower','Portable','Laptop','Notebook','Hand Held','Docking Station','All in One',
'Sub Notebook','Space-Saving','Lunch Box','Main System Chassis','Expansion Chassis',
'SubChassis','Bus Expansion Chassis','Peripheral Chassis','Storage Chassis',
'Rack Mount Chassis','Sealed-Case PC','Tablet','Convertible','Detachable'
# get the list of computernames, ignore empty lines and remove duplicates where present
$allComputers = @(Get-Content -Path $sourceFile | Where-Object { $_ -match '\S+' } | Sort-Object -Unique)
Write-Host "$($allComputers.Count) total computers" -BackgroundColor DarkCyan
# loop over the list of computers and capture the info in variable $result
$result = foreach ($Computer in $allComputers) {
if (Test-Connection -ComputerName $Computer -Count 1 -Quiet) {
Write-Host "Getting information for computer '$Computer'"
$system = Get-CimInstance -ClassName Win32_ComputerSystem -Computer $Computer
$bios = Get-CimInstance -ClassName Win32_BIOS -Computer $Computer
$chassis = Get-CimInstance -ClassName Win32_SystemEnclosure -Computer $Computer
$os = Get-CimInstance -ClassName Win32_OperatingSystem -Computer $Computer
$cpu = Get-CimInstance -ClassName Win32_Processor -Computer $Computer | Select-Object -First 1
$disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType=3' -ComputerName $Computer
$net = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object { $_.IPAddress -match '\S+' }
foreach ($hdd in @($disks)) {
# output the computer info (one row for each found harddisk)
[PSCustomObject]@{
PCName = $system.Name
MACAddress = $net.MACAddress
IPAddress = $net.IPAddress[0]
Manuf = $system.Manufacturer
Model = $system.Model
AssetTag = $chassis.SMBiosAssetTag
PCType = $chassisTypes[$chassis.ChassisTypes[0]]
SerialNumber = $bios.SerialNumber
RAM = '{0:N2}' -f ($system.TotalPhysicalMemory/1GB)
HDDDrive = $hdd.DeviceID
HDDVolume = $hdd.VolumeName
HDDSize = '{0:N2}' -f ($hdd.Size/1GB)
HDDFree = '{0:P2}' -f ($hdd.FreeSpace/$hdd.Size)
CPU = $cpu.Name
OS = $os.Caption
Version = $os.Version
Build = $os.BuildNumber
SP = '{0}.{1}' -f $os.ServicePackMajorVersion, $os.ServicePackMinorVersion
BootTime = $os.LastBootUpTime # Get-CimInstance returns a DateTime object
User = $system.UserName
}
}
}
else {
Write-Warning "$Computer is not online..."
# output an almost empty object for the computer that cannot be reached
# use the same properties as for the objects that do have info
'' | Select-Object @{Name = 'PCName'; Expression = {"OFFLINE: $Computer"}},
MACAddress, IPAddress, Manuf, Model, AssetTag, PCType, SerialNumber, RAM,
HDDDrive, HDDVolume, HDDSize, HDDFree, CPU, OS, Version, Build, SP, BootTime, User
}
}
# save the result to CSV
$result | Export-Csv -Path $exportfile -NoTypeInformation
In response to your comment on restricting the maximum number of info for available disks, you could rewrite the code like so:
(I kept the Get-CimInstance in favour of Get-WmiObject here hoping you can some day fix the firewall issue)
$sourceFile = 'D:\Test\computers.txt'
$exportFile = 'D:\Test\system-info.csv'
# from https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-systemenclosure
$chassisTypes = 'Unknown','Other','Unknown','Desktop','Low Profile Desktop','Pizza Box','Mini Tower',
'Tower','Portable','Laptop','Notebook','Hand Held','Docking Station','All in One',
'Sub Notebook','Space-Saving','Lunch Box','Main System Chassis','Expansion Chassis',
'SubChassis','Bus Expansion Chassis','Peripheral Chassis','Storage Chassis',
'Rack Mount Chassis','Sealed-Case PC','Tablet','Convertible','Detachable'
# get the list of computernames, ignore empty lines and remove duplicates where present
$allComputers = @(Get-Content -Path $sourceFile | Where-Object { $_ -match '\S+' } | Sort-Object -Unique)
Write-Host "$($allComputers.Count) total computers" -BackgroundColor DarkCyan
# loop over the list of computers and capture the info in variable $result
$result = foreach ($Computer in $allComputers) {
if (Test-Connection -ComputerName $Computer -Count 1 -Quiet) {
Write-Host "Getting information for computer '$Computer'"
$system = Get-CimInstance -ClassName Win32_ComputerSystem -Computer $Computer
$bios = Get-CimInstance -ClassName Win32_BIOS -Computer $Computer
$chassis = Get-CimInstance -ClassName Win32_SystemEnclosure -Computer $Computer
$os = Get-CimInstance -ClassName Win32_OperatingSystem -Computer $Computer
$cpu = Get-CimInstance -ClassName Win32_Processor -Computer $Computer | Select-Object -First 1
$disks = @(Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType=3' -ComputerName $Computer)
$net = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object { $_.IPAddress -match '\S+' }
# maximize number of columns to 2 harddisks
$hdd1 = $disks[0]
$hdd2 = if ($disks.Count -gt 1) { $disks[1] } else { $null }
# output the computer info
[PSCustomObject]@{
PCName = $system.Name
MACAddress = $net.MACAddress
IPAddress = $net.IPAddress[0]
Manuf = $system.Manufacturer
Model = $system.Model
AssetTag = $chassis.SMBiosAssetTag
PCType = $chassisTypes[$chassis.ChassisTypes[0]]
SerialNumber = $bios.SerialNumber
RAM = '{0:N2}' -f ($system.TotalPhysicalMemory/1GB)
HDD1_Drive = $hdd1.DeviceID
HDD1_Volume = $hdd1.VolumeName
HDD1_Size = '{0:N2}' -f ($hdd1.Size/1GB)
HDD1_Free = '{0:P2}' -f ($hdd1.FreeSpace/$hdd1.Size)
# add columns for possible second harddisk
HDD2_Drive = if ($hdd2) {$hdd2.DeviceID} else { 'N/A' }
HDD2_Volume = if ($hdd2) {$hdd2.VolumeName} else { '' }
HDD2_Size = if ($hdd2) {'{0:N2}' -f ($hdd2.Size/1GB)} else { '' }
HDD2_Free = if ($hdd2) {'{0:P2}' -f ($hdd2.FreeSpace/$hdd2.Size)} else { '' }
CPU = $cpu.Name
OS = $os.Caption
Version = $os.Version
Build = $os.BuildNumber
SP = '{0}.{1}' -f $os.ServicePackMajorVersion, $os.ServicePackMinorVersion
BootTime = $os.LastBootUpTime # Get-CimInstance returns a DateTime object
User = $system.UserName
}
}
else {
Write-Warning "$Computer is not online..."
# output an almost empty object for the computer that cannot be reached
# use the same properties as for the objects that do have info
'' | Select-Object @{Name = 'PCName'; Expression = {"OFFLINE: $Computer"}},
MACAddress, IPAddress, Manuf, Model, AssetTag, PCType, SerialNumber, RAM,
HDD1_Drive, HDD1_Volume, HDD1_Size, HDD1_Free,
HDD2_Drive, HDD2_Volume, HDD2_Size, HDD2_Free,
CPU, OS, Version, Build, SP, BootTime, User
}
}
# save the result to CSV
$result | Export-Csv -Path $exportfile -NoTypeInformation