Search code examples
powershell

Get VID PID from Device ID in Powershell


I am fairly new to PowerShell and I want for a USB key plugged, to retrieve some info. Right now my script is:

Get-WmiObject win32_diskdrive | 
    ForEach-Object{ 
        $disk = $_
        $_.GetRelated('Win32_PnPEntity')|
        ForEach-Object{ 
            $pnp = $_
            $_.GetRelated('Win32_USBController') |
            ForEach-Object{
                $usb = $_
                [pscustomobject]@{
                    SerialNumber = $disk.SerialNumber
                    Model = $disk.Model
                    Size = $disk.Size
                    if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {VID=$matches['vid']; PID=$matches['pid']}

                    
                }   
            }
       }
}

The line beginning with

if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {VID=$matches['vid']; PID=$matches['pid']}

does not work. I want to translate deviceid (which I can get by doing USBDeviceID = $usb.DeviceID) ID in PID UID directly.

It throws the following error

Error with code “Missing = operator after key in hash literal" for the statement "if ($usb.DeviceID -match '.* ...

What am I missing ? many thanks for helping me .

Gerald


Solution

  • This is because the way you intend to add properties to the PsCustomObject is wrong.

    Either do this:

    $result = [PsCustomObject]@{
        SerialNumber = $disk.SerialNumber
        Model        = $disk.Model
        Size         = $disk.Size
    }
    # add items to the object if the condition is true
    if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {
        $result | Add-Member -MemberType NoteProperty -Name 'VID' -Value $matches['vid']
        $result | Add-Member -MemberType NoteProperty -Name 'PID' -Value $matches['pid']
    }
    # output the PsCustomObject
    $result 
    

    or use a Hashtable as temporary storage:

    # create a Hastable to temporarily store results in
    $hash = [ordered]@{
        SerialNumber = $disk.SerialNumber
        Model        = $disk.Model
        Size         = $disk.Size
    }
    # add items to the hash if the condition is true
    if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {
        $hash['VID']=$matches['vid']
        $hash['PID']=$matches['pid']
    }
    # next cast to PsCustomObject and output
    [PsCustomObject]$hash
    

    Nowadays you should not use Get-WMIObject anymore and instead use Get-CimInstance.

    The code could then be rewritten as below:

    $result = Get-CimInstance -ClassName Win32_DiskDrive | 
              Where-Object {$_.InterfaceType -eq 'USB'} |
              ForEach-Object { 
                $out = [PsCustomObject]@{
                    SerialNumber = $_.SerialNumber
                    Model        = $_.Model
                    Size         = $_.Size
                    VID          = 'N/A'
                    PID          = 'N/A'
                }
                # if the condition is true update the .VID and .PID values
                if ($_.PNPDeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {
                    $out.VID = $matches['vid']
                    $out.PID = $matches['pid']
                }
                # output the object to be collected in variable $result
                $out
              }
    
    $result | Format-Table -AutoSize
    

    a demo output would look like this:

    SerialNumber             Model                              Size        VID PID
    ------------             -----                              ----        --- ---
    000000264001             Generic Ultra HS-SD/MMC USB Device             N/A N/A
    0018F3D97163BB918148003C Kingston DT R400 USB Device        15989944320 N/A N/A
    

    Regex details

    .                  Match any single character that is not a line break character
       *               Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
    VID_               Match the characters “VID_” literally
    (?<vid>            Match the regular expression below and capture its match into backreference with name “vid”
       [0-9A-F]        Match a single character present in the list below
                       A character in the range between “0” and “9”
                       A character in the range between “A” and “F” (Case-Insensitive)
          {4}          Exactly 4 times
    )                 
    &PID_              Match the characters “&PID_” literally
    (?<pid>            Match the regular expression below and capture its match into backreference with name “pid”
       [0-9A-F]        Match a single character present in the list below
                       A character in the range between “0” and “9”
                       A character in the range between “A” and “F” (Case-Insensitive)
          {4}          Exactly 4 times
    )
    .                  Match any single character that is not a line break character
       *               Between zero and unlimited times, as many times as possible, giving back as needed (greedy)