powershellexport-to-csvsystem-information

powershell - get System Info from file containing list of computers


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)

Solution

  • 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