Ok @cjwlford I think I have something for you, and an interesting nerd-story to go along with it.
I find it easier to make relationships between two WMI objects by querying them as…objects. Here I use ‘select objects’ rather than ‘string value of selects’ because to me it’s easier to keep them separated.
As you’ve seen, we can query Win32_DiskPartition and Win32_DiskDrive. On Win32_DiskPartition, the “DiskIndex” property refers to the “Index” property of Win32_DiskDrive. Both objects have “Size” properties as well.
q: (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi
A: DiskIndex=0, Size=524288000
A: DiskIndex=0, Size=508478619648
A: DiskIndex=0, Size=2970615808
A: DiskIndex=1, Size=1000203091968
T: 491.991 ms
I: plural ( wmi select, wmi select )
q: (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi
A: Index=0, Size=512105932800
A: Index=1, Size=1000202273280
T: 475.147 ms
I: plural ( wmi select, wmi select )
On my machine, I have two physical disks. The first disk has three partitions, the second disk only one.
We can start by making a cross-product tuple of every disk to every partition…here, “item 0” and “item 1” refer to the Win32_DiskDrive properties, and item 2 contains the DiskIndex and Size properties of Win32_DiskPartition.
q: (item 0 of it, item 1 of it,(properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi
A: Index=0, Size=512105932800, ( DiskIndex=0, Size=524288000 )
A: Index=0, Size=512105932800, ( DiskIndex=0, Size=508478619648 )
A: Index=0, Size=512105932800, ( DiskIndex=0, Size=2970615808 )
A: Index=0, Size=512105932800, ( DiskIndex=1, Size=1000203091968 )
A: Index=1, Size=1000202273280, ( DiskIndex=0, Size=524288000 )
A: Index=1, Size=1000202273280, ( DiskIndex=0, Size=508478619648 )
A: Index=1, Size=1000202273280, ( DiskIndex=0, Size=2970615808 )
A: Index=1, Size=1000202273280, ( DiskIndex=1, Size=1000203091968 )
T: 513.234 ms
I: plural ( wmi select, wmi select, ( wmi select, wmi select ) )
We’ll need to bring the DiskDrive’s “Index” property inside the tuple so we can filter for Win32_DiskPartition objects with matching DiskIndex values -
q: (item 0 of it, item 1 of it, (item 0 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi
A: Index=0, Size=512105932800, ( Index=0, ( DiskIndex=0, Size=524288000 ) )
A: Index=0, Size=512105932800, ( Index=0, ( DiskIndex=0, Size=508478619648 ) )
A: Index=0, Size=512105932800, ( Index=0, ( DiskIndex=0, Size=2970615808 ) )
A: Index=0, Size=512105932800, ( Index=0, ( DiskIndex=1, Size=1000203091968 ) )
A: Index=1, Size=1000202273280, ( Index=1, ( DiskIndex=0, Size=524288000 ) )
A: Index=1, Size=1000202273280, ( Index=1, ( DiskIndex=0, Size=508478619648 ) )
A: Index=1, Size=1000202273280, ( Index=1, ( DiskIndex=0, Size=2970615808 ) )
A: Index=1, Size=1000202273280, ( Index=1, ( DiskIndex=1, Size=1000203091968 ) )
T: 462.169 ms
I: plural ( wmi select, wmi select, ( wmi select, ( wmi select, wmi select ) ) )
Now that we have the whole cross-product we can begin filtering so we keep all the partitions with their correct disks…
q: (item 0 of it, item 1 of it, (item 0 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 1 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi
A: Index=0, Size=512105932800, ( Index=0, ( DiskIndex=0, Size=524288000 ) )
A: Index=0, Size=512105932800, ( Index=0, ( DiskIndex=0, Size=508478619648 ) )
A: Index=0, Size=512105932800, ( Index=0, ( DiskIndex=0, Size=2970615808 ) )
A: Index=1, Size=1000202273280, ( Index=1, ( DiskIndex=1, Size=1000203091968 ) )
T: 424.367 ms
I: plural ( wmi select, wmi select, ( wmi select, ( wmi select, wmi select ) ) )
Now we have the three partitions on disk 0 all together and related to disk 0, and all the (one) partitions of disk 1 in its disk. We’ll want to get those values converted into Integers so we can start adding them up together…
q: (item 0 of it, item 1 of it, integer values of items 1 of items 2 of (item 0 of it, item 1 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 1 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi
A: Index=0, Size=512105932800, 524288000
E: The expression could not be evaluated: Windows Error 0x8002000a: Out of present range.
Avast, a problem! WMI can’t seem to handle Integers this large. I found that BigFix itself doesn’t have a problem with it, so we can take a sidestep of pulling them out of WMI as strings and have BigFix cast them into Integers instead.
q: (item 0 of it, item 1 of it, string values of items 1 of items 2 of (item 0 of it, item 1 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 1 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi
A: Index=0, Size=512105932800, 524288000
A: Index=0, Size=512105932800, 508478619648
A: Index=0, Size=512105932800, 2970615808
A: Index=1, Size=1000202273280, 1000203091968
T: 376.431 ms
I: plural ( wmi select, wmi select, string )
q: (item 0 of it, item 1 of it, (it as integer) of string values of items 1 of items 2 of (item 0 of it, item 1 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 2 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi
A: Index=0, Size=512105932800, 524288000
A: Index=0, Size=512105932800, 508478619648
A: Index=0, Size=512105932800, 2970615808
A: Index=1, Size=1000202273280, 1000203091968
T: 331.430 ms
I: plural ( wmi select, wmi select, integer )
The next step is to sum up all of the partitions for each drive. We do this inside the “parentheses loop” so that we can still keep each drive separate.
q: (item 0 of it, item 1 of it, sum of (it as integer) of string values of items 1 of items 2 of (item 0 of it, item 1 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 2 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi
A: Index=0, Size=512105932800, 511973523456
A: Index=1, Size=1000202273280, 1000203091968
T: 285.579 ms
I: plural ( wmi select, wmi select, integer )
Now we can convert the Disk size to integer as well, taking the same sidestep through a string type, and figure out how much space is free (unpartitioned) on each Disk
q: (item 0 of it, item 1 of it - item 2 of it) of ((item 0 of it, (it as integer) of string value of item 1 of it, sum of (it as integer) of string values of items 1 of items 2 of (item 0 of it, item 1 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 2 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi)
A: Index=0, 132409344
A: Index=1, -818688
T: 150.090 ms
I: plural ( wmi select, integer )
Ooops, we really shouldn’t have negative values there. I can’t really account for it, except that maybe there is an inaccuracy in WMI when pulling partition sizes from a Bitlocker-to-Go partition that hasn’t been unlocked (as is the case for my second physical drive). So we’ll probably want to deal with “Absolute Values” to handle weird edge cases.
Finally, the following will show each physical disk, and how much free/unpartitioned space is on the disk:
q: (item 0 of it, absolute value of (item 1 of it - item 2 of it)) of ((item 0 of it, (it as integer) of string value of item 1 of it, sum of (it as integer) of string values of items 1 of items 2 of (item 0 of it, item 1 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 2 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi)
A: Index=0, 132409344
A: Index=1, 818688
T: 102.889 ms
I: plural ( wmi select, integer )
We probably shouldn’t bother trying to expand a partition if the disk free space is below some threshold. So the following relevance should show only those disks that have more than 500 MB of free space (I don’t have any, but you can try tuning the whose() filter at the end to test whether it works as expected, and decide your own threshold for “how much space is worth reclaiming”):
q: (item 0 of it, absolute value of (item 1 of it - item 2 of it)) of ((item 0 of it, (it as integer) of string value of item 1 of it, sum of (it as integer) of string values of items 1 of items 2 of (item 0 of it, item 1 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 2 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi) whose (absolute value of (item 1 of it - item 2 of it) > 500 * 1024 * 1024)
T: 54.978 ms
I: plural ( wmi select, integer )
Finally this relevance will return a True/False value indicating whether the machine has any partitions worth growing. Mine doesn’t, but if I tune that ‘500 MB’ down to ‘5 MB’, I get a True:
q: exists (item 0 of it, absolute value of (item 1 of it - item 2 of it)) of ((item 0 of it, (it as integer) of string value of item 1 of it, sum of (it as integer) of string values of items 1 of items 2 of (item 0 of it, item 1 of it, (properties "DiskIndex" of it, properties "Size" of it) of select objects "* from Win32_DiskPartition" of wmi) whose (integer value of item 0 of it = integer value of item 0 of item 2 of it) ) of (properties "Index" of it, properties "Size" of it) of select objects "* from Win32_DiskDrive" of wmi) whose (absolute value of (item 1 of it - item 2 of it) > 500 * 1024 * 1024)
A: False
T: 46.235 ms
I: singular boolean
I think you should be able to use this last query as a Task/Fixlet relevance, along with the earlier one showing which disks can be grown to fill-in your Diskpart script. The final relevance seems to run reasonably quickly, which is a bonus and not always the case for WMI queries.
Hope this helps, and it was a fun journey!