function Get-Devices {
    param (
        [string]$comp,
        [Parameter(Mandatory=$false)][string]$status
    )
    try {
        Write-Progress -Activity "Getting devices for $name" -Status 'Collecting USB devices' -PercentComplete 10 -ParentId 1
        if ($status -eq "Online") {
            $usb = Get-WmiObject Win32_USBControllerDevice -ComputerName $comp | ForEach-Object {[wmi]($_.Dependent)} | Select-Object Manufacturer,Description,@{N="DeviceID\SerialNumber";E={$_.DeviceID}} 
        } else {
            $usb = Get-SCCM_USB $comp | Select-Object Manufacturer,Description,@{N="DeviceID\SerialNumber";E={$_.DeviceID}} 
        }
        $usb | Add-Member -NotePropertyName Type -NotePropertyValue USB
        $usb | Add-Member -NotePropertyName AttachedComputer -NotePropertyValue $comp
        $usbi = 0
        $friendlyNames = $usb | ForEach-Object {
            $usbi++
            Write-Progress -Activity "Getting devices for $name" -Status "Parsing USB Devices ($usbi/$($usb.Length)" -PercentComplete (($usbi * (80-10) /  $usb.Length )+10) -ParentId 1
            Write-Output $_
        } | Select-Object -ExpandProperty 'DeviceID\SerialNumber' | FindUSBDevice
        for($usbi = 0; $usbi -lt $usb.Count; $usbi++){
            Write-Progress -Activity "Getting devices for $name" -Status "Populating fields ($usbi/$($usb.Length)" -PercentComplete (($usbi * (90-80) /  $usb.Length )+80) -ParentId 1
            if(!$friendlyNames[$usbi]){ continue }
            $usb[$usbi].Manufacturer = $friendlyNames[$usbi].Manufacturer
            if($usb[$usbi].Manufacturer.Length -le 5){ continue }
            if($usb[$usbi].Manufacturer.Substring(0,5) -eq '[SHS]'){
                $usb[$usbi].Type = 'SHS Issued USB'
                $len = $usb[$usbi].Manufacturer.Length -1
                $usb[$usbi].Manufacturer = $usb[$usbi].Manufacturer[5..$len] -join ''
            }
            if($friendlyNames[$usbi].Description){
                $usb[$usbi].Description = $friendlyNames[$usbi].Description
            }
        }
        Write-Progress -Activity "Getting devices for $name" -Status 'Sorting out duplicate devices' -PercentComplete 90 -ParentId 1
        $usb = $usb | Sort-Object Manufacturer,Description
        for ($i = 0; $i -lt $usb.Count - 1; $i++) {
            if($usb[$i].Manufacturer -eq $usb[$i+1].Manufacturer -and $usb[$i].Description -eq $usb[$i+1].Description){
                $usb[$i].Manufacturer = '__DUPE__'
            }
        }
        $usb = $usb | Where-Object -Property Manufacturer -NE '__DUPE__'
        $usb = $usb | Sort-Object Type,Manufacturer
    
    }
    catch{
        Write-warning 'Unable to grab USB info'
        $usb = $null
    }
    
    if ($status -eq 'Online') {
        Write-Progress -Activity "Getting devices for $name" -Status 'Getting monitors' -PercentComplete 90 -ParentId 1
        $monitors = @()
        $monitors += Get-Monitor $comp | Select-Object Manufacturer,@{N='Description';E={$_.Model}},@{N="DeviceID\SerialNumber";E={$_.SerialNumber}},AttachedComputer,ActivePort
        $monitors | Add-Member -NotePropertyName Type -NotePropertyValue Monitor

        $PortsHash = @{
            'DELL P170S'= @('DVI','VGA');
            'DELL P2317H'= @('DP','HDMI','VGA');
            'DELL P2314H'= @('DP','DVI','VGA');
            'DELL P2312H'= @('DVI','VGA');
            'DELL P2319H'= @('DP','HDMI','VGA');
            'DELL P2422H'= @('DP','HDMI','VGA');
            'DELL P2412H'= @('DP','HDMI','VGA');
        }
        
        foreach($item in $monitors){
            $portList = ''
            $found = $false
            foreach ($port in $PortsHash.($item.Description)) {
                if ($port -eq $item.ActivePort) { $portList += '*'; $found = $true }
                $portList += $port + ','
            }
            $portList = $portList -replace "\,$"
            $item.Description = $item.Description + ' (' + $portList + ')'
            if ($found -ne $true) { $item.Description += " *" + $item.ActivePort }
        }
    }

    $out = @()

    Write-Progress -Activity "Getting devices for $name" -Status 'Finalizing' -PercentComplete 100 -ParentId 1
    foreach($item in ($monitors + $usb)){
        $item.PSObject.TypeNames.Insert(0,'GetPC.Devices')
        $out += $item   
    }
    $item = [PSCustomObject]@{ }
    $item.PSObject.TypeNames.Insert(0,'GetPC.Devices')
    $out += $item
    
    Write-Output $out
}


Function Get-Monitor {

    <#
  
        .SYNOPSIS
        This powershell function gets information about the monitors attached to any computer. It uses EDID information provided by WMI. If this value is not specified it pulls the monitors of the computer that the script is being run on.
  
        .DESCRIPTION
        The function begins by looping through each computer specified. For each computer it gets a litst of monitors.
        It then gets all of the necessary data from each monitor object and converts and cleans the data and places it in a custom PSObject. It then adds
        the data to an array. At the end the array is displayed.
  
        .PARAMETER ComputerName
        Use this to specify the computer(s) which you'd like to retrieve information about monitors from.
  
        .EXAMPLE
        PS C:/> Get-Monitor.ps1 -ComputerName SSL1-F1102-1G2Z
  
        Manufacturer Model    SerialNumber AttachedComputer
        ------------ -----    ------------ ----------------
        HP           HP E241i CN12345678   SSL1-F1102-1G2Z 
        HP           HP E241i CN91234567   SSL1-F1102-1G2Z 
        HP           HP E241i CN89123456   SSL1-F1102-1G2Z
  
        .EXAMPLE
        PS C:/> $Computers = @("SSL7-F108F-9D4Z","SSL1-F1102-1G2Z","SSA7-F1071-0T7F")
        PS C:/> Get-Monitor.ps1 -ComputerName $Computers
  
        Manufacturer Model      SerialNumber AttachedComputer
        ------------ -----      ------------ ----------------
        HP           HP LA2405x CN12345678   SSL7-F108F-9D4Z
        HP           HP E241i   CN91234567   SSL1-F1102-1G2Z 
        HP           HP E241i   CN89123456   SSL1-F1102-1G2Z 
        HP           HP E241i   CN78912345   SSL1-F1102-1G2Z
        HP           HP ZR22w   CN67891234   SSA7-F1071-0T7F

        .NOTES
        This script was written by  MaxAnderson95 https://github.com/MaxAnderson95/Get-Monitor-Information/blob/master/Get-Monitor.psm1
  
    #>
  
  
    [CmdletBinding()]
    PARAM (
      [Parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
      [String[]]$ComputerName = $env:ComputerName
    )
    
    #List of Manufacture Codes that could be pulled from WMI and their respective full names. Used for translating later down.
    $ManufacturerHash = @{ 
      "AAC" =	"AcerView";
      "ACR" = "Acer";
      "AOC" = "AOC";
      "AIC" = "AG Neovo";
      "APP" = "Apple Computer";
      "AST" = "AST Research";
      "AUO" = "Asus";
      "BNQ" = "BenQ";
      "CMO" = "Acer";
      "CPL" = "Compal";
      "CPQ" = "Compaq";
      "CPT" = "Chunghwa Pciture Tubes, Ltd.";
      "CTX" = "CTX";
      "DEC" = "DEC";
      "DEL" = "Dell";
      "DPC" = "Delta";
      "DWE" = "Daewoo";
      "EIZ" = "EIZO";
      "ELS" = "ELSA";
      "ENC" = "EIZO";
      "EPI" = "Envision";
      "FCM" = "Funai";
      "FUJ" = "Fujitsu";
      "FUS" = "Fujitsu-Siemens";
      "GSM" = "LG Electronics";
      "GWY" = "Gateway 2000";
      "HEI" = "Hyundai";
      "HIT" = "Hyundai";
      "HSL" = "Hansol";
      "HTC" = "Hitachi/Nissei";
      "HWP" = "HP";
      "IBM" = "IBM";
      "ICL" = "Fujitsu ICL";
      "IVM" = "Iiyama";
      "KDS" = "Korea Data Systems";
      "LEN" = "Lenovo";
      "LGD" = "Asus";
      "LPL" = "Fujitsu";
      "MAX" = "Belinea"; 
      "MEI" = "Panasonic";
      "MEL" = "Mitsubishi Electronics";
      "MS_" = "Panasonic";
      "NAN" = "Nanao";
      "NEC" = "NEC";
      "NOK" = "Nokia Data";
      "NVD" = "Fujitsu";
      "OPT" = "Optoma";
      "PHL" = "Philips";
      "REL" = "Relisys";
      "SAN" = "Samsung";
      "SAM" = "Samsung";
      "SBI" = "Smarttech";
      "SGI" = "SGI";
      "SNY" = "Sony";
      "SRC" = "Shamrock";
      "SUN" = "Sun Microsystems";
      "SEC" = "Hewlett-Packard";
      "TAT" = "Tatung";
      "TOS" = "Toshiba";
      "TSB" = "Toshiba";
      "VSC" = "ViewSonic";
      "ZCM" = "Zenith";
      "UNK" = "Unknown";
      "_YV" = "Fujitsu";
        }
        
    $ActivePortHash = @{
      '0' = 'VGA';
      '4' = 'DVI';
      '5' = 'HDMI';
      '10' = 'DP';
    };

        
    
    #Takes each computer specified and runs the following code:
    ForEach ($Computer in $ComputerName) {
    
      #Grabs the Monitor objects from WMI
      $Monitors = Get-WmiObject -Namespace "root\WMI" -Class "WMIMonitorID" -ComputerName $Computer -ErrorAction SilentlyContinue

      #Grabs data about the port driving the monitors
      $activePortsData = get-ciminstance -namespace root/wmi -classname WmiMonitorConnectionParams -ComputerName $Computer -ErrorAction SilentlyContinue
      
      #Transforms results of $activePortsData into a lookup table
      $activePorts = @{}
      foreach ($data in $activePortsData) {
        #Translates port numeric code to a readable port identifier
        $activePorts[ $data.InstanceName ] = $ActivePortHash["$($data.VideoOutputTechnology)"]
        #Uses the raw code if the code isn't recognized (it's a really weird one)
        if ($null -eq $activePorts[ $data.InstanceName ]) {
          $activePorts[ $data.InstanceName ] = $data.VideoOutputTechnology
        }
      }
    
      
      #Creates an empty array to hold the data
      $Monitor_Array = @()
      
      
      #Takes each monitor object found and runs the following code:
      ForEach ($Monitor in $Monitors) {
        
        #Grabs respective data and converts it from ASCII encoding and removes any trailing ASCII null values
        If ($null -ne [System.Text.Encoding]::ASCII.GetString($Monitor.UserFriendlyName)) {
          $Mon_Model = ([System.Text.Encoding]::ASCII.GetString($Monitor.UserFriendlyName)).Replace("$([char]0x0000)","")
        } else {
          $Mon_Model = $null
        }
        $Mon_Serial_Number = ([System.Text.Encoding]::ASCII.GetString($Monitor.SerialNumberID)).Replace("$([char]0x0000)","")
        $Mon_Attached_Computer = ($Monitor.PSComputerName).Replace("$([char]0x0000)","")
        $Mon_Manufacturer = ([System.Text.Encoding]::ASCII.GetString($Monitor.ManufacturerName)).Replace("$([char]0x0000)","")
        
        #Filters out "non monitors". Place any of your own filters here. These two are all-in-one computers with built in displays. I don't need the info from these.
        If ($Mon_Model -like "*800 AIO*" -or $Mon_Model -like "*8300 AiO*") {Break}
        
        #Sets a friendly name based on the hash table above. If no entry found sets it to the original 3 character code
        $Mon_Manufacturer_Friendly = $ManufacturerHash.$Mon_Manufacturer
        If ($null -eq $Mon_Manufacturer_Friendly) {
          $Mon_Manufacturer_Friendly = $Mon_Manufacturer
        }

        $Mon_Active_Port = $activePorts[ $Monitor.InstanceName ]
        
        #Creates a custom monitor object and fills it with 4 NoteProperty members and the respective data
        $Monitor_Obj = [PSCustomObject]@{
          Manufacturer     = $Mon_Manufacturer_Friendly
          Model            = $Mon_Model
          SerialNumber     = $Mon_Serial_Number
          AttachedComputer = $Mon_Attached_Computer
          ActivePort       = $Mon_Active_Port
        }
        
        #Appends the object to the array
        $Monitor_Array += $Monitor_Obj
  
      } #End ForEach Monitor
    
      #Outputs the Array
      $Monitor_Array
      
  } #End ForEach Computer
  
  
  }

function FindUSBDevice {
    param (
        [string]$vid,
        [string]$p,
        [Parameter(ValueFromPipeline=$true)]
        [string]$deviceID
    )
    begin {
        # Start with SHS Equipment override
        $lookupTablePath = Join-Path (get-item $PSScriptRoot).Parent.FullName 'Data\SHSEquipmentLookup.txt'
        $usbIDs = Get-Content $lookupTablePath
        $lookupTablePath = Join-Path (get-item $PSScriptRoot).Parent.FullName 'Data\USBIDs.txt'
        $usbIDs += Get-Content $lookupTablePath
    } process {
        if($deviceID){
            $bool = $deviceID -match '(?<=VID_)(....)'
            if(!$bool){
                return $null
            }
            $vid = $Matches[0]
            $deviceID -match '(?<=PID_)(....)' | Out-Null
            $p = $Matches[0]
        }
        for ($i = 0; $i -lt $usbIDs.Count; $i++) {
            if ($usbIDs[$i] -match $vid){
                
                if($usbIDs[$i][0] -eq "`t"){
                    
                }
                else{
                    
                    $man = ($usbIDs[$i] -split ' ')
                    $man = $man[2..$man.count] -join ' '

                    for ($y = $i+1; $y -lt $usbIDs.Count; $y++) {
                        if($usbIDs[$y][0] -ne "`t"){
                            return @{
                                Manufacturer = $man
                                Description = $null
                            }
                        }
                        if($usbIDs[$y] -match $p){
                            $dev = ($usbIDs[$y] -split ' ')
                            $dev = $dev[2..$dev.count] -join ' '
                            return @{
                                Manufacturer = $man
                                Description = $dev
                            }
                        }
            
                    }
                    return @{
                        Manufacturer = $man
                        Description = $null
                    }
                }
            }
        }
    } end { 

    }
}
