Combine `Get-Disk` info and `LogicalDisk` info in PowerShell (but with formatted output)
Asked Answered
W

2

2

This is a question about an answer for this Combine `Get-Disk` info and `LogicalDisk` info in PowerShell?

Here is the answer which I've tried to change to get the output formatted how I want it: https://mcmap.net/q/715596/-combine-get-disk-info-and-logicaldisk-info-in-powershell

It needs to work for multiple drives like the code below only in the desired format.

This is the code with all the details on what my attempts are to do so:

$info_diskdrive_basic = Get-WmiObject Win32_DiskDrive | ForEach-Object {
  $disk = $_
  $partitions = "ASSOCIATORS OF " + "{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " + "WHERE AssocClass = Win32_DiskDriveToDiskPartition"
  Get-WmiObject -Query $partitions | ForEach-Object {
    $partition = $_
    $drives = "ASSOCIATORS OF " + "{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " + "WHERE AssocClass = Win32_LogicalDiskToPartition"
    Get-WmiObject -Query $drives | ForEach-Object {
      [PSCustomObject][Ordered]@{
        Disk          = $disk.DeviceID
        DiskModel     = $disk.Model
        Partition     = $partition.Name
        RawSize       = '{0:d} GB' -f [int]($partition.Size/1GB)
        DriveLetter   = $_.DeviceID
        VolumeName    = $_.VolumeName
        Size          = '{0:d} GB' -f [int]($_.Size/1GB)
        FreeSpace     = '{0:d} GB' -f [int]($_.FreeSpace/1GB)
      }
    }
  }
}

# Here's my attempt at formatting the output of the code above.

# 1. This trims the dead whitespace from the output.
$info_diskdrive_basic = ($info_diskdrive_basic | Out-String) -replace '^\s+|\s+$', ('')

# 2. I then separate the DiskModel, RawSize, DriveLetter, VolumeName, FreeSpace with the regexp below so this becomes:
# Disk Model, Raw Size, Drive Letter, Volume Name, Free Space
$info_diskdrive_basic = ($info_diskdrive_basic) -replace '(?-i)(?=\B[A-Z][a-z])', (' ')

# 3. Here I then format the string to how I want:
$info_diskdrive_basic = ($info_diskdrive_basic) -replace '(.+?)(\s+):\s*(?!\S)', ($id2 + '$1:$2                                       ')

$info_diskdrive_basic

The output should look like this:

I want to format the properties and the values like so: Properties: >spaces< value where the value is over to the right and aligned along the left of them

# Disk:                                                 \\.\PHYSICALDRIVE0
# Disk Model:                                           Crucial_CT512MX100SSD1
# Partition:                                            Disk #0, Partition #2
# Raw Size:                                             476 GB
# Drive Letter:                                         C:
# Volume Name:
# Size:                                                 476 GB
# Free Space:                                           306 GB

But my output ends up like this: (Notice how the text is not aligned)

# Disk:                                                \\.\PHYSICALDRIVE0
# Disk Model:                                           Crucial_CT512MX100SSD1
# Partition:                                           Disk #0, Partition #2
# Raw Size:                                             476 GB
# Drive Letter:                                         C:
# Volume Name:
# Size:                                                476 GB
# Free Space:                                           306 GB
Wardship answered 2/8, 2020 at 18:49 Comment(4)
Why not simply output $info_diskdrive_basic | Format-List instead of doing those steps 1, 2 and 3 ?Margueritamarguerite
I have a lot of other code that outputs the system info which follows this format with the Description: Value so I want to go with the same for this.Wardship
So basically, you want the output as Format-List produces, but with a lot of extra whitespace between the property name and the actual value? Again: WHY?Margueritamarguerite
I gave the reason, all other output is like this and it aligns the property on the right with left justification as per the example.Wardship
M
2

To output the info as you apparently need, we need to know the maximum line length (which in your example is 79 characters) and work our way from that.

$maxLineLength  = 79  # counted from the longest line in your example
$maxValueLength = 0   # a counter to keep track of the largest value length in characters

$info_diskdrive_basic = Get-WmiObject Win32_DiskDrive | ForEach-Object {
    $disk = $_
    $partitions = "ASSOCIATORS OF " + "{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " + "WHERE AssocClass = Win32_DiskDriveToDiskPartition"
    Get-WmiObject -Query $partitions | ForEach-Object {
        $partition = $_
        $drives = "ASSOCIATORS OF " + "{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " + "WHERE AssocClass = Win32_LogicalDiskToPartition"
        Get-WmiObject -Query $drives | ForEach-Object {
            $obj = [PSCustomObject]@{
                'Disk'         = $disk.DeviceID
                'Disk Model'   = $disk.Model
                'Partition'    = $partition.Name
                'Raw Size'     = '{0:d} GB' -f [int]($partition.Size/1GB)
                'Drive Letter' = $_.DeviceID
                'Volume Name'  = $_.VolumeName
                'Size'         = '{0:d} GB' -f [int]($_.Size/1GB)
                'Free Space'   = '{0:d} GB' -f [int]($_.FreeSpace/1GB)
            }
            # get the maximum length for all values
            $len = ($obj.PsObject.Properties.Value.ToString().Trim() | Measure-Object -Property Length -Maximum).Maximum
            $maxValueLength = [Math]::Max($maxValueLength, $len)
                                          
            # output the object to be collected in $info_diskdrive_basic
            $obj
        }
    }
}

# sort the returned array of objects on the DriveLetter property and loop through
$result = $info_diskdrive_basic | Sort-Object DriveLetter | ForEach-Object {
    # loop through all the properties and calculate the padding needed for the output
    $_.PsObject.Properties | ForEach-Object {
        $label   = '# {0}:' -f $_.Name.Trim()
        $padding = $maxLineLength - $maxValueLength - $label.Length
        # output a formatted line
        "{0}{1,-$padding}{2}" -f $label, '', $_.Value.ToString().Trim()
    }
    # add a separator line between the disks
    ''
}

# output the result on screen
$result

# write to disk
$result | Set-Content -Path 'X:\theResult.txt'

# format for HTML mail:
'<pre>{0}</pre>' -f ($result -join '<br>')

Example output:

# Disk:                                              \\.\PHYSICALDRIVE1
# Disk Model:                                        Samsung SSD 750 EVO 250GB
# Partition:                                         Disk #1, Partition #0
# Raw Size:                                          232 GB
# Drive Letter:                                      C:
# Volume Name:                                       System
# Size:                                              232 GB
# Free Space:                                        160 GB

# Disk:                                              \\.\PHYSICALDRIVE2
# Disk Model:                                        WDC WD7501AALS-00J7B0
# Partition:                                         Disk #2, Partition #0
# Raw Size:                                          699 GB
# Drive Letter:                                      D:
# Volume Name:                                       Data
# Size:                                              699 GB
# Free Space:                                        385 GB

P.S. with creating [PsCustomObject], there is no need to add [Ordered]

Margueritamarguerite answered 3/8, 2020 at 10:51 Comment(5)
Thanks, that is exactly what I'm after. The only thing I changed was line $label = '# {0}:' -f $_.Name to $label = '{0}:' -f $_.Name -replace '(?-i)(?=\B[A-Z][a-z])', (' ') to change DiskModel to Disk Model. Edit: The first drive doesn't line up. See here: i.imgur.com/H68hKTR.pngWardship
@Wardship Thanks for letting me know. BTW, you could have changed that label in the definition of the [PsCustomObject] straight away: DiskModel --> 'Disk Model', so you wouldn't have to do the regex afterwards.Margueritamarguerite
When I tried that it returned an error. There's one minor thing with the your code. The first drive in the list doesn't line up. i.imgur.com/H68hKTR.pngWardship
@Wardship Please see the edited answer. It now allows for spaces in the returned property labels and calculates the maximum value length on a higher levelMargueritamarguerite
Great Theo. Thanks. This is working perfectly. I have a network drive that's connected but that could be something for another Q. The Get-PSDrive -PSProvider FileSystem returns this: i.imgur.com/L7Dfa6B.png which has the drive highlight yellow.Wardship
P
0

Using your posted code as is, 'stringify' your properties

For example:

($info_diskdrive_basic = Get-WmiObject Win32_DiskDrive | 
ForEach-Object {
  $disk       = $_
  $partitions = "ASSOCIATORS OF " + 
                  "{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " + 
                  "WHERE AssocClass = Win32_DiskDriveToDiskPartition"
  Get-WmiObject -Query $partitions | 
  ForEach-Object {
    $partition = $_
    $drives    = "ASSOCIATORS OF " + 
                "{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " + 
                "WHERE AssocClass = Win32_LogicalDiskToPartition"
    Get-WmiObject -Query $drives | 
    ForEach-Object {
      [PSCustomObject][Ordered]@{
        Disk          = "$($disk.DeviceID)"
        DiskModel     = "$($disk.Model)"
        Partition     = "$($partition.Name)"
        RawSize       = "$('{0:d} GB' -f [int]($partition.Size/1GB))"
        DriveLetter   = "$($_.DeviceID)"
        VolumeName    = "$($_.VolumeName)"
        Size          = "$('{0:d} GB' -f [int]($_.Size/1GB))"
        FreeSpace     = "$('{0:d} GB' -f [int]($_.FreeSpace/1GB))"
      }
    }
  }
})
# Results
<#
Disk        : \\.\PHYSICALDRIVE0
DiskModel   : Samsung SSD 950 PRO 512GB
Partition   : Disk #0, Partition #0
RawSize     : 477 GB
DriveLetter : D:
VolumeName  : Data
Size        : 477 GB
FreeSpace   : 364 GB
...
#>

Point of note:

I am using PowerShell variable squeezing to assign the results to the variable and output to the screen at the same time.

Update

As for this...

"I want to format the properties and the values like so: Properties: >spaces< value"

$Spacer = ("`t")*8

($info_diskdrive_basic = Get-WmiObject Win32_DiskDrive | 
ForEach-Object {
  $disk       = $_
  $partitions = "ASSOCIATORS OF " + 
                  "{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " + 
                  "WHERE AssocClass = Win32_DiskDriveToDiskPartition"
  Get-WmiObject -Query $partitions | 
  ForEach-Object {
    $partition = $_
    $drives    = "ASSOCIATORS OF " + 
                "{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " + 
                "WHERE AssocClass = Win32_LogicalDiskToPartition"
    Get-WmiObject -Query $drives | 
    ForEach-Object {
      [PSCustomObject][Ordered]@{
        Disk          = "$Spacer$($disk.DeviceID)"
        DiskModel     = "$Spacer$($disk.Model)"
        Partition     = "$Spacer$($partition.Name)"
        RawSize       = "$Spacer$('{0:d} GB' -f [int]($partition.Size/1GB))"
        DriveLetter   = "$Spacer$($PSItem.DeviceID)"
        VolumeName    = "$Spacer$($PSItem.VolumeName)"
        Size          = "$Spacer$('{0:d} GB' -f [int]($PSItem.Size/1GB))"
        FreeSpace     = "$Spacer$('{0:d} GB' -f [int]($PSItem.FreeSpace/1GB))"
      }
    }
  }
})
# Results
<#
Disk        :                               \\.\PHYSICALDRIVE0
DiskModel   :                               Samsung SSD 950 PRO 512GB
Partition   :                               Disk #0, Partition #0
RawSize     :                               477 GB
DriveLetter :                               D:
VolumeName  :                               Data
Size        :                               477 GB
FreeSpace   :                               364 GB
...
#>
Phasia answered 3/8, 2020 at 5:29 Comment(3)
Thanks for posting but that returns the same as the code in my question. I want to format the properties and the values like so: Properties: >spaces< value where the value is over to the right and aligned along the left of them.Wardship
Then in the formatting, just put in the additional character/string formatting code. It's just a string at this point.Phasia
That was something I initially tried. The details of the output are in the original question. That was just just a brief description. Also, the accepted answer is what the output should be.Wardship

© 2022 - 2024 — McMap. All rights reserved.