"Normalizing" Output of an Inventory Function

Hello friends, first time poster here :slight_smile: .

I am trying to “normalize” the output of my function so it reads like:

ComputerName Model MonitorModel MonitorSerial
ABC123456 HP ZBook LG QHD 361343
ABC123456 HP ZBook D3218HN X9R5K78200GE
ABC123567 Surface Book TDM13056 94441728
Like I'm joining a computer name table and a monitor table.

However, it is currently outputting like this:

ComputerName Model MonitorModel MonitorSerial
ABC123456 HP ZBook D3218HN X9R5K78200GE
ABC123567 Surface Book TDM13056 TDM1305694441728
...Omitting the second monitor of the HP ZBook.
# Adapted from https://powershell.org/forums/topic/monitor-serial-numbers-of-remote-machines-from-text-file/
function Get-Monitor {
    [CmdletBinding()]
    param (
        [Parameter(
        ValueFromPipeline=$True,
        ValueFromPipelineByPropertyName=$True)]
        [String[]]$ComputerName = '.'
    )
begin 
{
    $inventory = New-Object -TypeName PSObject
}

process
{
foreach ($Computer in $ComputerName)
{

            $ComputerSystemInfo = Get-CimInstance -Class win32_computersystem -ComputerName $Computer
            $MonitorInfo = Get-CimInstance -Namespace root\wmi -Class WmiMonitorID -ComputerName $Computer
            
            $props = [ordered]@{
                    'ComputerName' = $ComputerSystemInfo.Name
                    'Model' = $ComputerSystemInfo.Model
                }   
        
            $inventory | Add-Member -NotePropertyMembers $props -Force

            foreach ($monitor in $MonitorInfo) 
                {    
                $inventory | Add-Member -MemberType NoteProperty -Name 'MonitorModel' -Value ([system.text.encoding]::ascii.GetString($monitor.UserFriendlyName)) -Force
                $inventory | Add-Member -MemberType NoteProperty -Name 'MonitorSerial' -Value ([system.text.encoding]::ascii.GetString($monitor.SerialNumberid)) -Force
                }

            Write-output -InputObject $inventory
        } 
        
    }

}

Thanks! I'm sure I'm missing something obvious.

If you’re not interested in all monitors attached to a particular pc why are you collecting them anyway? And what criteria do you use to decide what monitor you want to omit? You could simply use the first one with:

$MonitorInfo = @(Get-CimInstance -Namespace root\wmi -Class WmiMonitorID -ComputerName $Computer)[0]

And of course you don’t need the loop to process the monitor list anymore. :wink:

What if you just run this against the two monitor HP? Powershell likes to combine output so if 2 objects have one monitor and 1 has 2… it will probably just not display it by default. Other test would be instead of write output do a | select * and confirm if that monitor is there, just not being shown when grouped.

Danke gentlemen,

Toggling -Passthru on the internal foreach gets me close, but I still have dups. Tried outputting with Sort-Object | Get-Unique but no effects. Worst cause I can export to Excel and filter out unique rows, but I’d rather not do that.

                foreach ($monitor in $MonitorInfo) 
                {   

                $inventory | Add-Member -MemberType NoteProperty -Name 'MonitorModel' -Value ([system.text.encoding]::ascii.GetString($monitor.UserFriendlyName)) -Force 

                $inventory | Add-Member -MemberType NoteProperty -Name 'MonitorSerial' -Value ([system.text.encoding]::ascii.GetString($monitor.SerialNumberid)) -Force -PassThru

                }</pre>

Latest Draft

# Adapted from https://powershell.org/forums/topic/monitor-serial-numbers-of-remote-machines-from-text-file/

function Get-Monitor {

[CmdletBinding()]

param (

    [Parameter(

    ValueFromPipeline=$True,

    ValueFromPipelineByPropertyName=$True)]

    [String[]]$ComputerName = '.'

)

begin 

{

    $inventory = New-Object -TypeName PSObject

}

process

    {

    foreach ($Computer in $ComputerName) 

        {

            $ComputerSystemInfo = Get-CimInstance -Class win32_computersystem -ComputerName $Computer

            $MonitorInfo = Get-CimInstance -Namespace root\wmi -Class WmiMonitorID -ComputerName $Computer | Select-Object -Property UserFriendlyName, SerialNumberID                

            $props = [ordered]@{

                    'ComputerName' = $ComputerSystemInfo.Name

                    'Model' = $ComputerSystemInfo.Model

                }   

        

            $inventory | Add-Member -NotePropertyMembers $props -Force

            foreach ($monitor in $MonitorInfo) 

                {   

                $inventory | Add-Member -MemberType NoteProperty -Name 'MonitorModel' -Value ([system.text.encoding]::ascii.GetString($monitor.UserFriendlyName)) -Force 

                $inventory | Add-Member -MemberType NoteProperty -Name 'MonitorSerial' -Value ([system.text.encoding]::ascii.GetString($monitor.SerialNumberid)) -Force -PassThru

                }

            $inventory 

        }             

    }      

} # End of Function

Output on my local HP machine: Two Monitors, 1x LG and 1x Dell

One duplicate, the second "D3218HN":
PS C:\> Get-Monitor $env:COMPUTERNAME

ComputerName Model MonitorModel MonitorSerial


ABC123456 HP ZBook 14u G5 LG QHD 361343
ABC123456 HP ZBook 14u G5 D3218HN X9R5K78200GE
ABC123456 HP ZBook 14u G5 D3218HN X9R5K78200GE

Output on the remote Surface machine: No external monitors

Only its own factory, internal monitor, but duplicated:
PS C:\> Get-Monitor -ComputerName ABC123457

ComputerName Model MonitorModel MonitorSerial


ABC123457 Surface Book TDM13O56 94441728
ABC123457 Surface Book TDM13O56 94441728

Running Function with an array of the two machines

Same results
Get-Monitor -ComputerName $computers

ComputerName Model MonitorModel MonitorSerial


ABC123456 HP ZBook 14u G5 LG QHD 361343
ABC123456 HP ZBook 14u G5 D3218HN X9R5K78200GE
ABC123456 HP ZBook 14u G5 D3218HN X9R5K78200GE
ABC123457 Surface Book TDM13O56 94441728
ABC123457 Surface Book TDM13O56 94441728


Thanks again for your help.

I’m reading on my phone, but your original code wouldn’t it just overwrite there first monitor with the second since it’s the same property name. Are you trying to collect them both in that single property?

That’s correct, Doug. I would like the output like this:

ComputerName Model MonitorModel MonitorSerial 
------------ ----- ------------ ------------- 
ABCDEF123456 HP ZBook 14u G5 LG QHD 361343
ABCDEF123456 HP ZBook 14u G5 D3218HN X9R5K78200GE 
ABCDEF123457 Surface Book TDM13O56 94441728

It would be like a SQL Inner Join between a Computer Table and a Monitor Table, one computer can have 1 or more monitors. Thanks!

I connot test at the moment but something like this should be enough actually:

function Get-Monitor {
    [CmdletBinding()]
    param (
        [Parameter(
            ValueFromPipeline = $True,
            ValueFromPipelineByPropertyName = $True)]
        [String[]]$ComputerName = '.'
    )
    process {
        foreach ($Computer in $ComputerName) {
            $ComputerSystemInfo = Get-CimInstance -Class win32_computersystem -ComputerName $Computer
            $MonitorInfo = Get-CimInstance -Namespace root\wmi -Class WmiMonitorID -ComputerName $Computer
            foreach ($Monitor in $MonitorInfo) {
                [PSCustomObject]@{
                    ComputerName  = $ComputerSystemInfo.Name
                    Model         = $ComputerSystemInfo.Model
                    MonitorModel  = $Monitor.UserFriendlyName
                    MonitorSerial = $monitor.SerialNumberid
                }
            }
        }
    }
}

Thank you Olaf! I’m seeing good results on my home computer - no duplicates. Appreciate the help.

function Get-Monitor {
[CmdletBinding()]

param (

    [Parameter(
        ValueFromPipeline = $True,
        ValueFromPipelineByPropertyName = $True)]
    [String[]]$ComputerName = '.'

)

process {

    foreach ($Computer in $ComputerName) {

        $ComputerSystemInfo = Get-CimInstance -Class win32_computersystem -ComputerName $Computer
        $MonitorInfo = Get-CimInstance -Namespace root\wmi -Class WmiMonitorID -ComputerName $Computer
        foreach ($Monitor in $MonitorInfo) {

            [PSCustomObject]@{
                ComputerName  = $ComputerSystemInfo.Name
                Model         = $ComputerSystemInfo.Model
                MonitorModel  = [system.text.encoding]::ascii.GetString($monitor.UserFriendlyName)
                MonitorSerial = [system.text.encoding]::ascii.GetString($monitor.SerialNumberID)
            }
        }
    }
}

}
PS C:&gt; Get-Monitor

ComputerName Model MonitorModel MonitorSerial


HOME-BOX AB350N LG QHD 361343
HOME-BOX AB350N D3218HN X9R5K78200GE

PS C:&gt; Get-Monitor # Second monitor unplugged

ComputerName Model MonitorModel MonitorSerial


HOME-BOX AB350N LG QHD 361343