Drive Letters + Drive Physical Types (Powershell)

Is there a method that allows us to get its letter and physical type for each driver? That is, get one array where something like this will be:

$Drivers = *Get-Something*   # Where $Drivers is @{} array 
$Drivers
---
C: SSD
D: HDD
E: SSD
F: SSD

I need to bind the data of these two in an array. The first contains letters. the second contains physical types:

$DriversName = (Get-WmiObject -Class Win32_Volume).DriveLetter | Where-Object { $_ }
$DriversType = Get-PhysicalDisk | Select-Object -ExpandProperty MediaType

But I do not know which element of the first array refers to the element of the second array. Because the system does not prioritize them.

Thanks so much for the answers.

Upvotes: 2

Views: 7318

Answers (5)

Here is the solution (thanks js2010 for the idea). Nearly. Since you need logical drives to display. Decision by Chris Dent:

powershell
Get-PhysicalDisk | ForEach-Object {
    $physicalDisk = $_
    $physicalDisk |
        Get-Disk |
        Get-Partition |
        Where-Object DriveLetter |
        Select-Object DriveLetter, @{n='MediaType';e={ $physicalDisk.MediaType }}
}

Upvotes: 5

js2010
js2010

Reputation: 27418

Get-Volume returns DriveLetter and DriveType properties.

EDIT:

Get-PhysicalDisk has the MediaType property. But its ObjectId doesn't match up with a drive letter.

$disk = get-physicaldisk
$disk | get-disk | get-partition | select DriveLetter, 
  @{n='MediaType';e={$disk.MediaType}}

DriveLetter MediaType
----------- ---------
          C SSD

Hmm why doesn't pipevariable work? There can be multiple drive letters.

get-physicaldisk -pv disk | get-disk | get-partition | select DriveLetter,
  @{n='MediaType';e={$disk.MediaType}}

DriveLetter MediaType
----------- ---------
          C

Upvotes: 0

Theo
Theo

Reputation: 61013

You can use the SerialNumber property of the disks to map the output and combine the logical drive letter with the MediaType of the physical disks.

# create a Hashtable to store the DriveLetter and SerialNumber obtained from WMI (I use Get-CimInstance here)
$ht = @{}
$wmiQuery1 = 'ASSOCIATORS OF {{Win32_DiskDrive.DeviceID="{0}"}} WHERE AssocClass = Win32_DiskDriveToDiskPartition'
$wmiQuery2 = 'ASSOCIATORS OF {{Win32_DiskPartition.DeviceID="{0}"}} WHERE AssocClass = Win32_LogicalDiskToPartition'

# for PowerShell < 3.0 use Get-WmiObject instead of Get-CimInstance
Get-CimInstance -ClassName Win32_DiskDrive | Where-Object { $_.MediaType -match '^(Fixed|External)' } |
    ForEach-Object {
        # store the disk serialnumber of the physical disk and get the get the partition info for each disk
        $serial = $_.SerialNumber                  
        Get-CimInstance -Query ($wmiQuery1 -f $_.DeviceID.Replace('\','\\'))   #'# double-up the backslashes
    } |
    ForEach-Object {
        # now get the logical disks on each partition to find the drive letters in property DeviceID
        Get-CimInstance -Query ($wmiQuery2 -f $_.DeviceID)
    } | 
    ForEach-Object { $ht[$_.DeviceID] = $serial }  # store the drive letters as key, the disk serial as value

# get the serialnumber and mediatype for each physical disk with Get-PhysicalDisk
$disks = Get-PhysicalDisk | Select-Object SerialNumber, MediaType

# loop through the Hashtable with partition/volume info gathered before and map on the SerialNumber property
$ht.Keys | ForEach-Object {
    $drive = $_
    $type = ($disks | Where-Object { $_.SerialNumber -eq $ht[$drive] }).MediaType
    [PsCustomObject]@{
        DriveLetter = $drive
        MediaType   = if ($type) { $type } else { 'Unspecified' }
    }        
} | Sort-Object DriveLetter

The result should look like

DriveLetter  MediaType
-----------  ---------
C:           SSD
D:           HHD
E:           SSD
F:           SSD

Upvotes: 1

Holli
Holli

Reputation: 5072

First you want to look at Win32_LogicalDiskToPartition.

PS C:\> Get-WMIObject Win32_LogicalDiskToPartition | Select-Object Antecedent, Dependent | Write

Which gives on my system

Antecedent                                                                        Dependent
----------                                                                        ---------
\\DESKTOP-JJASNFC\root\cimv2:Win32_DiskPartition.DeviceID="Disk #1, Partition #0" \\DESKTOP-JJASNFC\root\cimv2:Win32_LogicalDisk.DeviceID="C:"
\\DESKTOP-JJASNFC\root\cimv2:Win32_DiskPartition.DeviceID="Disk #0, Partition #1" \\DESKTOP-JJASNFC\root\cimv2:Win32_LogicalDisk.DeviceID="D:"

Query Win32_LogicalDisk to get information about the drive letter.

Get-WMIObject Win32_LogicalDisk | Select DeviceID, Path | Write

yields for me

DeviceID Path
-------- ----
C:       \\DESKTOP-JJASNFC\root\cimv2:Win32_LogicalDisk.DeviceID="C:"
D:       \\DESKTOP-JJASNFC\root\cimv2:Win32_LogicalDisk.DeviceID="D:"
F:       \\DESKTOP-JJASNFC\root\cimv2:Win32_LogicalDisk.DeviceID="F:"

Here the Path property is connected to the Dependent property we saw before.

In Win32_DiskPartition we can find the device Id

Get-WMIObject Win32_DiskPartition | Select DiskIndex, MedPath | Write

Again, for me

DiskIndex Path
--------- ----
        1 \\DESKTOP-JJASNFC\root\cimv2:Win32_DiskPartition.DeviceID="Disk #1, Partition #0"
        0 \\DESKTOP-JJASNFC\root\cimv2:Win32_DiskPartition.DeviceID="Disk #0, Partition #0"
        0 \\DESKTOP-JJASNFC\root\cimv2:Win32_DiskPartition.DeviceID="Disk #0, Partition #1"

Now, the most interesting part for you is when we query MSFT_Physicaldisk.

Get-WmiObject MSFT_Physicaldisk -Namespace root\Microsoft\Windows\Storage | Select DeviceId, MediaType | Write

...

DeviceId MediaType
-------- ---------
1                4
0                4

Here, MediaType is the key. A value of 4 means SSD, 3 means HDD. DeviceId corresponds to the DiskIndex.

So, if you join those 4 "tables" together you can achieve what you want. My Powershell-Fu is not good enough.

To recap: The joins are like

MSFT_Physicaldisk.MediaType, MSFT_Physicaldisk.DeviceID <-->

Win32_DiskPartition.DiskIndex, *Win32_DiskPartition.Path <-->

Win32_LogicalDiskToPartition.Dependent, Win32_LogicalDiskToPartition.Antecedent <-->

Win32_LogicalDisk.Path, Win32_LogicalDisk.DeviceID

Upvotes: 3

hcm
hcm

Reputation: 1010

This is working for me:

$partitions = Get-CimInstance Win32_DiskPartition
$physDisc = get-physicaldisk
$arr = @()
foreach ($partition in $partitions){
    $cims = Get-CimInstance -Query "ASSOCIATORS OF `
                          {Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} `
                          WHERE AssocClass=Win32_LogicalDiskToPartition"
    $regex = $partition.name -match "(\d+)"
    $physDiscNr = $matches[0]
    foreach ($cim in $cims){
        $arr += [PSCustomObject]@{
            Drive = $cim.deviceID
            Partition = $partition.name
            MediaType = $($physDisc | ? {$_.DeviceID -eq $physDiscNr} | select -expand MediaType)
        }
    }
}

$arr

It does seem kind of clunky though with the regex, so maybe there is a better approach I'm not seeing.

Upvotes: 3

Related Questions