PowerShell tool-building is an essential part of learning to go from a copy/paste scripter to someone that can build real, reusable scripts. As an example of a tool-building methodology, let’s build a simple computer inventory report tool that will walk you through the process of building a simple yet effective tool using PowerShell.
We'll start with reading data from a CSV file, then query computer details using CIM, and finally output the results into a structured format. Let’s get started!
Step 1: Reading and Processing a CSV File
First, we need to set up our environment. We'll create a sample CSV file containing a computer name and deparment that computer may be in. I’ll also create a blank script called Start-ComputerInventoryReport.ps1.
# Sample CSV content
@'
ComputerName,Department
PC1,HR
PC2,Finance
'@ | Set-Content -Path C:computers.csv
Set-Content -Path C:Start-ComputerInventoryReport.ps1 -Value ''
Next, open up C:Start-ComputerInventoryReport.ps1 in your favorite editor and let’s get scripting!
First, read the computers into a CSV file. You should see each CSV row.
$computers = Import-Csv -Path C:computers.csv
$computers
This will import our CSV file and store the data in the $computers
variable.
Step 2: Adding a Connection Check
I always recommend starting small; start with a single object and then build upon that. So start working with a single computer and get all of the code down.
Since our script will query remote computers, it’s a good practice to check if the computer is online before proceeding:
Test-Connection -ComputerName $computers[0].ComputerName -Count 1 -Quiet
This command will return True
if the machine is online and False
otherwise.
Step 3: Processing Each Computer
To handle multiple computers, we'll use a foreach
loop:
foreach ($computer in $computers) {
Write-Host "Processing the [$($computer.ComputerName)] computer."
}
For now, let's focus on a single computer by temporarily adjusting our loop:
foreach ($computer in $computers[0]) {
Write-Host "Processing the [$($computer.ComputerName)] computer."
}
Step 4: Creating the Output Object
We want to gather the ComputerName
, Department
, and IsOnline
properties. Let’s create a hashtable and convert it to a custom object:
foreach ($computer in $computers[0]) {
$output = @{
ComputerName = $computer.ComputerName
Department = $computer.Department
IsOnline = $null
}
[pscustomobject]$output
}
Now, populate the IsOnline
property using the Test-Connection
command:
foreach ($computer in $computers[0]) {
$output = @{
ComputerName = $computer.ComputerName
Department = $computer.Department
IsOnline = $null
}
$isOnline = Test-Connection -ComputerName $computer.ComputerName -Count 1 -Quiet
$output.IsOnline = $isOnline
[pscustomobject]$output
}
Step 5: Processing All Computers
Finally, remove the temporary single computer focus and process all computers:
foreach ($computer in $computers) {
$output = @{
ComputerName = $computer.ComputerName
Department = $computer.Department
IsOnline = $null
}
$isOnline = Test-Connection -ComputerName $computer.ComputerName -Count 1 -Quiet
$output.IsOnline = $isOnline
[pscustomobject]$output
}
Step 6: Adding CIM Query
Let's extend our tool to gather additional information such as the manufacturer, model, CPU count, and total RAM from each computer using the CIM class Win32_ComputerSystem
:
foreach ($computer in $computers) {
$output = @{
ComputerName = $computer.ComputerName
Department = $computer.Department
IsOnline = $null
Manufacturer = $null
Model = $null
CPUCount = $null
TotalRAM = $null
}
$isOnline = Test-Connection -ComputerName $computer.ComputerName -Count 1 -Quiet
$output.IsOnline = $isOnline
if ($isOnline) {
$systemInfo = Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $computer.ComputerName
$output.Manufacturer = $systemInfo.Manufacturer
$output.Model = $systemInfo.Model
$output.CPUCount = $systemInfo.NumberOfProcessors
$output.TotalRAM = $systemInfo.TotalPhysicalMemory
}
[pscustomobject]$output
}
Step 7: Refactoring Using the Pipeline
To make our tool more flexible, let's refactor it to accept input from the pipeline. This allows us to use various data sources, not just CSV files:
[CmdletBinding()]
param(
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string]$ComputerName
)
process {
$output = @{
ComputerName = $ComputerName
IsOnline = $null
Manufacturer = $null
Model = $null
CPUCount = $null
TotalRAM = $null
}
$isOnline = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet
$output.IsOnline = $isOnline
if ($isOnline) {
$systemInfo = Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $ComputerName
$output.Manufacturer = $systemInfo.Manufacturer
$output.Model = $systemInfo.Model
$output.CPUCount = $systemInfo.NumberOfProcessors
$output.TotalRAM = $systemInfo.TotalPhysicalMemory
}
[pscustomobject]$output
}
You can now pipe data from various sources:
Get-ADComputer -Filter * -SearchBase "OU=IT, DC=contoso, DC=com" |
Select-Object -Property *,@{n='ComputerName';e={$_.Name}} -ExcludeProperty Name |
C:Start-ComputerInventoryReportv4.ps1
Step 8: Saving Output to CSV
Let's add functionality to save the output to a CSV file:
[CmdletBinding()]
param(
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string]$ComputerName,
[Parameter()]
[string]$OutputFilePath
)
process {
$output = @{
ComputerName = $ComputerName
IsOnline = $null
Manufacturer = $null
Model = $null
CPUCount = $null
TotalRAM = $null
}
$isOnline = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet
$output.IsOnline = $isOnline
if ($isOnline) {
$systemInfo = Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $ComputerName
$output.Manufacturer = $systemInfo.Manufacturer
$output.Model = $systemInfo.Model
$output.CPUCount = $systemInfo.NumberOfProcessors
$output.TotalRAM = $systemInfo.TotalPhysicalMemory
}
$out = [pscustomobject]$output
if ($PSBoundParameters.ContainsKey('OutputFilePath')) {
$out | Export-Csv -Path $OutputFilePath -Append
}
$out
}
Step 9: Adding Error Handling
Finally, let's add error handling to make our script more robust:
[CmdletBinding()]
param(
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string]$ComputerName,
[Parameter()]
[string]$OutputFilePath
)
begin {
$ErrorActionPreference = 'Stop'
}
process {
try {
$output = @{
ComputerName = $ComputerName
IsOnline = $null
Manufacturer = $null
Model = $null
CPUCount = $null
TotalRAM = $null
Error = $null
}
$isOnline = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet
$output.IsOnline = $isOnline
if ($isOnline) {
$systemInfo = Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $ComputerName
$output.Manufacturer = $systemInfo.Manufacturer
$output.Model = $systemInfo.Model
$output.CPUCount = $systemInfo.NumberOfProcessors
$output.TotalRAM = $systemInfo.TotalPhysicalMemory
}
$out = [pscustomobject]$output
}
catch {
$output.Error = $_.Exception.Message
$out = [pscustomobject]$output
}
finally {
if ($PSBoundParameters.ContainsKey('OutputFilePath')) {
$out | Export-Csv -Path $OutputFilePath -Append
}
$out
}
}
By following these steps, you have built a comprehensive tool for generating a computer inventory report using PowerShell. This tool can read from various sources, query system information, handle errors, and export the results to a CSV file. Happy scripting!