PowerShell Tool-Building 101: Building a Computer Inventory Report

Published:30 May 2024 - < 1 min. read

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!

Hate ads? Want to support the writer? Get many of our tutorials packaged as an ATA Guidebook.

Explore ATA Guidebooks

Looks like you're offline!