“Normalizing” Output of an Inventory Function

Welcome Forums General PowerShell Q&A “Normalizing” Output of an Inventory Function

Viewing 7 reply threads
  • Author
    Posts
    • #236923
      Participant
      Topics: 1
      Replies: 3
      Points: 58
      Rank: Member

      Hello friends, first time poster here ūüôā .

      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.

      • This topic was modified 2 weeks, 4 days ago by tluizzi.
      • This topic was modified 2 weeks, 4 days ago by tluizzi.
    • #236974
      Participant
      Topics: 5
      Replies: 2372
      Points: 6,005
      Helping Hand
      Rank: Community MVP

      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. ūüėČ

    • #236977
      Participant
      Topics: 3
      Replies: 417
      Points: 1,462
      Helping Hand
      Rank: Community Hero

      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.

    • #236986
      Participant
      Topics: 1
      Replies: 3
      Points: 58
      Rank: Member

      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
      
                          }

      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.

    • #236989
      Participant
      Topics: 3
      Replies: 417
      Points: 1,462
      Helping Hand
      Rank: Community Hero

      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?

    • #237001
      Participant
      Topics: 1
      Replies: 3
      Points: 58
      Rank: Member

      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!

    • #237007
      Participant
      Topics: 5
      Replies: 2372
      Points: 6,005
      Helping Hand
      Rank: Community MVP

      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
                      }
                  }
              }
          }
      }
      
    • #237016
      Participant
      Topics: 1
      Replies: 3
      Points: 58
      Rank: Member

      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:\> Get-Monitor
      
      ComputerName Model      MonitorModel  MonitorSerial   
      ------------ -----      ------------  -------------
      HOME-BOX     AB350N     LG QHD        361343
      HOME-BOX     AB350N     D3218HN       X9R5K78200GE
      
      PS C:\> Get-Monitor # Second monitor unplugged
      
      ComputerName Model      MonitorModel  MonitorSerial   
      ------------ -----      ------------  -------------
      HOME-BOX     AB350N     LG QHD        361343
      
Viewing 7 reply threads
  • You must be logged in to reply to this topic.