param([Parameter(Mandatory=$true)] $ComputerFile, $jobCount = 50) # Initialize the models hash which will be populated while processing job output $models = @{} # This function strips stuff in parentheses and trailing whitespace from the string passed, # which in my experience is usually what you want when looking at the BIOS model string. function Massage-Model { param([Parameter(Mandatory=$true)][string] $private:model) $private:model = $private:model -replace '\s*\([^)]+\)\s*', '' $private:model = $private:model -replace '\s+$', '' return $private:model } function Process-Jobs { param($private:runningJobs) #'' 'Processing job batch...' Write-Host -NoNewLine 'Processing jobs: ' $private:jobCounter = 0 foreach ($private:jobHash in $private:runningJobs) { $private:jobCounter++ $private:computerName = $private:jobHash.Name if ($private:jobCounter -eq 8) { $private:jobCounter = 0 Write-Host $private:computerName Write-Host -NoNewLine 'Processing jobs: ' } else { Write-Host -NoNewLine "$private:computerName, " } Wait-Job $private:jobHash.Job | Out-Null $private:output = Receive-Job -ErrorAction SilentlyContinue $private:JobHash.Job if ($private:output -ieq 'No ping reply') { $private:computerName | Out-File -Append $noPingFile } elseif ($private:output -match '\S+') { $models.$private:computerName = Massage-Model $private:output } else { $models.$private:computerName = 'ERROR' } } '' Write-Host -NoNewLine 'Starting jobs: ' } # Output files, didn't bother making them parameters... $modelsFile = 'computer-models-with-computername.txt' $modelsCountFile = 'computer-models-count.txt' $noPingFile = 'computer-models-noping.txt' # Prompt before overwriting files. if ( (Test-Path $modelsFile) -or (Test-Path $modelsCountFile) -or (Test-Path $noPingFile) ) { "Output file(s) '$modelsFile', '$modelsCountFile' or '$noPingFile' exist." $private:answer = Read-Host 'Overwrite? (Y/n) [yes]' if ($private:answer -match '^n') { 'Aborting.'; exit 0 } Remove-Item $noPingFile -ErrorAction SilentlyContinue } # Get the start time and display it before starting processing. $startTime = Get-Date "Start time: $startTime" if (!(Test-Path -PathType leaf $computerFile)) { "Error: $computerFile does not exist. Exiting..." exit 0 } # Get the computers. Skip lines with only whitespace (including blank lines). $computers = Get-Content $ComputerFile | Where-Object { $_ -match '\S+' } 'Found ' + $computers.Count + ' computers.' 'Starting jobs.' 'This might take a good long while depending on the amount of computers and the hardware being used.' # Having issues with passing large arrays to GWMI -computer and many concurrent jobs, # trying batches of 50 jobs $runningJobs = @() $private:computerCounter = 0 $private:tempComputerCounter = 0 $private:jobCounter = 0 Write-Host -NoNewLine 'Starting jobs: ' foreach ($computer in $computers) { $private:computerCounter++ $private:tempComputerCounter++ if ($private:tempComputerCounter -eq 8) { $private:tempComputerCounter = 0 Write-Host $computer Write-Host -NoNewLine 'Starting jobs: ' } else { Write-Host -NoNewLine "$computer, " } #Start-Sleep -Milliseconds 500 $private:job = Start-Job -ArgumentList $computer -ScriptBlock { param($private:computer) if (Test-Connection -Quiet -Count 1 $private:computer) { (Get-WMIObject -computer $private:computer -Class Win32_ComputerSystem).Model } else { 'No ping reply' } } $runningJobs += @{ 'Name' = $computer; 'Job' = $private:job; } $private:jobCounter++ if ($private:jobCounter -eq $jobCount) { ''; "Total computer count: $private:computerCounter" Process-Jobs $runningJobs $private:jobCounter = 0 $runningJobs = @() } } '' # Process the remainder Process-Jobs $runningJobs '' $models.GetEnumerator() | Sort-Object -property @{Expression='Name';Descending=$false},@{Expression='Value';Descending=$false} | Format-Table -AutoSize | Out-File $modelsFile $modelsCount = @{} $models.Keys | Foreach { $modelsCount.$($models.$_) += 1 } 'Found ' + $modelsCount.Count + ' unique models' $modelsCount.GetEnumerator() | Sort-Object -property @{Expression='Value';Descending=$true},@{Expression='Name';Descending=$false} | Format-Table -AutoSize | Out-File $modelsCountFile @" Start time: $startTime End time: $(Get-Date) Output files: $modelsFile, $modelsCountFile, $noPingFile "@