PS Splitting an Expanded Property

Hi, All.

This is, I feel, an easy one for most. I can’t seem to wrap my head around how to do it though.

I’m getting the disk partitions from a remote system using the following:

invoke-command -ComputerName "Server1" -ScriptBlock{get-partition | Select DriveLetter, diskNumber, AccessPaths | FT -Auto}

The “AccessPaths” needs to be expanded, then split or trimmed, so I can get the drive labels. If I just have the info (run from the CMD above) I get:

DriveLetter diskNumber AccessPaths
----------- ---------- -----------
                    0 {\\?\Volume{da6802b2-0000-0000-0000-100000000000}\}
          C          0 {C:\, \\?\Volume{da6702b2-0000-0000-0000-501600000000}\}
                    0 {\\?\Volume{da6702b2-0000-0000-0000-c0db23000000}\}
                    1
          E          1 {E:\, \\?\Volume{4ffea9a0-a11f-4296-a52b-225beaf57b83}\}
                    2
          L          2 {L:\, \\?\Volume{62216345-cd70-4717-8ad3-b267856b034a}\}
                    3
          P          3 {P:\, \\?\Volume{8491eec4-acdb-416d-881e-32a0e0c11ede}\}
                    4
          U          4 {U:\, \\?\Volume{64fe0a79-aa52-4ed0-b5ef-a934b4eb9954}\}
                    5
          Z          5 {Z:\, \\?\Volume{974dcfae-686f-48af-b3d0-4fc60c2b149d}\}
                    6 {Z:\Test01\, \\?\Volume{7553a6a6-0000-0000-0000-010000000000}\}

What I’m hoping to get is output that captures all drives and mounted drives (disks mounted to a folder). That looks something like the follow:

DriveLetter        diskNumber          Label
---------------    ----------------    -------
C                    0                     C:\
E                    1                     E:\
L                    2                      L:\
P                    3                     P:\
U                    4                     U:\
Z                    5                     Z:\
                      6                     Z:\Test01\

Again, I’m sure this is easy, but I can’t wrap my head around how this would be done.

Thanks!

AccessPaths is an array so you use index notation to get the first element.

$PartitionInfo = Invoke-Command -ComputerName 'Server1' -ScriptBlock {
    Get-Partition | Select DriveLetter,DiskNumber,AccessPaths 
}

$PartitionInfo | Where-Object {$_.DriveLetter} | 
    Select-Object DriveLetter,DiskNumber,@{l='Label';e={$_.AccessPaths[0]}}
1 Like

Thank, Matt.

I modified this a little so it would report the mount points as well as the disks. Here’s what I did;

$PartitionInfo | Where-Object {
$_.AccessPaths -Match '^[a-zA-Z]:\\'} | 
Select-Object DriveLetter,
@{n='Label';e={$_.AccessPaths[0]}},
DiskNumber,
@{n="Partition";e{$_.PartitionNumber}},
@{n="Size(GB)";e={$_.size /1GB -as [int]}}

I added a few line breaks to make it a little easier to read.

Need a little further explanation, though. How does it report back the disk label in AccessPaths without running that through some sort of loop to extract the info? It’s not adding up for me how “…$_.AccessPaths[0]…” does what I need it to.

Thanks again,
Dale

Think about it as an implicit foreach loop. The objects in the $PartitionInfo collection are passed one at a time down the pipeline to Select-Object. The current object is represented by the $_.

So $_.AccessPaths[0] represents the element at index 0 of the AccessPaths array property of the current object in the pipeline.

1 Like

Will this work?

Get-Partition | Where-Object -Property DriveLetter -ne ([char]0)  | Select-Object -Property `
    DriveLetter,DiskNumber,@{Label="AccessPaths";Expression={($_.AccessPaths -split ",")[0]}} 

DriveLetter DiskNumber AccessPaths
----------- ---------- -----------
          C          0 C:\        
          D          1 D:\        
          F          2 F:\        
          T          3 T:\        
          E          4 E:\ 

So, correct me where I’m wrong, when an array such as this is piped through the Select-Object, each item is sent through one element at a time. The specified element in the array will automagically increment as if it’s in a loop?

Correct? If my thought here is correct that is a really interesting nuance that I wasn’t aware.

Hey, Ima.

That works, but it only grabs the disks that have a drive letter. What I need is something that gets the disks with a drive letter and mounted drives that have no drive letter.

I have this ridiculous setup in my environment where we have a standard build with certain drive letters for different disks. But then we have some systems that have folders that are mounted to a drive (mount points) for whatever data needs to be stored. Those mount points aren’t assigned a drive letter and when we have to expand those disks, it becomes a problem reconciling what disk is what between the Windows drives and the assigned drives in vCenter.

So, I’m writing a script to do that reconciliation and expand the target disk. In order to do that I need to know the Windows disk number (which this will pull out) and the partition number.

Anyway, using the regex match works really well to get all disks regardless of assigned drive letter or not.

Correct, but it’s not just arrays, it’s any type that implements the IEnumerable interface (with some exceptions).

See about Pipelines - PowerShell | Microsoft Learn

That’s a pretty interesting phenomena. I did not know that was a thing. Thank you for the lesson!

Yup, only read about that mount point now. I probably only skimmed that part. This should work:

#Re-create dalebert's partition from given example
$Partitions=@"
,0,{\\?\Volume{da6802b2-0000-0000-0000-100000000000}\"
C,0,"{C:\, \\?\Volume{da6702b2-0000-0000-0000-501600000000}\}"
,0,{\\?\Volume{da6702b2-0000-0000-0000-c0db23000000}\}"
,1,
E,1,"{E:\, \\?\Volume{4ffea9a0-a11f-4296-a52b-225beaf57b83}\}"
,2,
L,2,"{L:\, \\?\Volume{62216345-cd70-4717-8ad3-b267856b034a}\}"
,3
P,3,"{P:\, \\?\Volume{8491eec4-acdb-416d-881e-32a0e0c11ede}\}"
,4,
U,4,"{U:\, \\?\Volume{64fe0a79-aa52-4ed0-b5ef-a934b4eb9954}\}"
,5,
Z,5,"{Z:\, \\?\Volume{974dcfae-686f-48af-b3d0-4fc60c2b149d}\}"
,6,"{Z:\Test01\, \\?\Volume{7553a6a6-0000-0000-0000-010000000000}\}"
"@ | ConvertFrom-Csv -Header DriveLetter,diskNumber,AccessPaths | `
    Select-Object -Property DriveLetter,diskNumber,
        @{Label="AccessPaths";Expression={
            If (($_.AccessPaths -split ",").Count -eq 2) { `
                $_.AccessPaths -replace "{" -replace "}" -split ","
            } else {
                $_.AccessPaths
            }
        }
    }

#Remove objects without drive letters in the DriveLetter property
#If a DriveLetter does exist, is there a drive letter in AccessPaths, determined by more than 1 index when split by a comma
$Partitions | Where-Object -FilterScript {$_.DriveLetter -ne ([char]0) -or (($_.AccessPaths -split ",").Count -eq 2 -and `
    ($_.AccessPaths -split ",")[0] -match "^[A-z]:\\")} |Select-Object -Property DriveLetter,DiskNumber,
    @{Label="AccessPaths";Expression={($_.AccessPaths -split ",")[0]}}

The actual command you would run:

Get-Partition | Where-Object -FilterScript {$_.DriveLetter -ne ([char]0) -or (($_.AccessPaths -split ",").Count -eq 2 -and `
    ($_.AccessPaths -split ",")[0] -match "^[A-z]:\\")} |Select-Object -Property DriveLetter,DiskNumber,
    @{Label="AccessPaths";Expression={($_.AccessPaths -split ",")[0]}}

This is the output:

DriveLetter diskNumber AccessPaths
----------- ---------- -----------
C           0          C:\        
E           1          E:\        
L           2          L:\        
P           3          P:\        
U           4          U:\        
Z           5          Z:\        
            6          Z:\Test01\