1

I have a simple Powershell script to gather disk information from an array of servers:

$servers="ALPHA", "BRAVO", "CHARLIE", "DELTA", "ECHO", "FOXTROT", "GOLF", "HOTEL"

ForEach ($s in $servers)
{ 
 get-wmiobject win32_logicaldisk -ComputerName $s -Filter "Drivetype=3"| select @{n='Server '; e={$s}}, 
                                                                                DeviceID,
                                                                                @{n="Size [GB]";e={[math]::truncate($_.size / 1GB)}},  
                                                                                @{n="Free [GB]";e={[math]::truncate($_.freespace / 1GB)}}  
}

which yields the desidered output:

Server       DeviceID Size [GB] Free [GB]
-------      -------- --------- ---------
ALPHA        C:             299       161
ALPHA        E:             499       201
BRAVO        C:             476       148
CHARLIE      C:             233        46
DELTA        C:             475        94
ECHO         C:             464       256
ECHO         S:             465       222
FOXTROT      C:             476       224
GOLF         C:             475       100
HOTEL        C:             476        50

I'd like to add to the output table a calculated column showing the free percentage of each disk, so I add , @{n="Free [%]";e={($_.freespace / $_.Size).ToString("P0")}} to my select list, and the resulting script is hence:

ForEach ($s in $servers)
{ 
        get-wmiobject win32_logicaldisk -ComputerName $s -Filter "Drivetype=3"| select @{n='Server '; e={$s}}, 
                                                                                       DeviceID,
                                                                                       @{n="Size [GB]";e={[math]::truncate($_.size / 1GB)}},  
                                                                                       @{n="Free [GB]";e={[math]::truncate($_.freespace / 1GB)}} , 
                                                                                       @{n="Free [%]";e={($_.freespace / $_.Size).ToString("P0")}} 
}

which, to my surprise, doesn't just add a column to previous output table, but instead yields the output:

Server    : ALPHA
DeviceID  : C:
Size [GB] : 299
Free [GB] : 161
Free [%]  : 54%

Server    : ALPHA
DeviceID  : E:
Size [GB] : 499
Free [GB] : 198
Free [%]  : 40%

Server    : BRAVO
DeviceID  : C:
Size [GB] : 476
Free [GB] : 142
Free [%]  : 30%

Server    : CHARLIE
DeviceID  : C:
Size [GB] : 233
Free [GB] : 44
Free [%]  : 19%

Server    : DELTA
DeviceID  : C:
Size [GB] : 475
Free [GB] : 88
Free [%]  : 19%

Server    : ECHO
DeviceID  : C:
Size [GB] : 464
Free [GB] : 256
Free [%]  : 55%

Server    : ECHO
DeviceID  : S:
Size [GB] : 465
Free [GB] : 222
Free [%]  : 48%

Server    : FOXTROT
DeviceID  : C:
Size [GB] : 476
Free [GB] : 224
Free [%]  : 47%

Server    : GOLF
DeviceID  : C:
Size [GB] : 475
Free [GB] : 100
Free [%]  : 21%

Server    : HOTEL
DeviceID  : C:
Size [GB] : 476
Free [GB] : 46
Free [%]  : 10%

where the "bidimensional-table" format is completely lost, at the expense of concise readability.

Addinng | Format-Table just causes the output to be:

Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
ALPHA        C:             299       161 54%     
ALPHA        E:             499       192 39%     



Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
BRAVO        C:             476       137 29%     



Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
CHARLIE      C:             233        45 19%     



Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
DELTA        C:             475        78 16%     



Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
ECHO         C:             464       256 55%     
ECHO         S:             465       222 48%     



Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
FOXTROT      C:             476       224 47%     



Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
GOLF         C:             475       100 21%     



Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
HOTEL        C:             476        42 9% 

while the desired output would be:

Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
ALPHA        C:             299       161 54%     
ALPHA        E:             499       192 39%     
BRAVO        C:             476       137 29%     
CHARLIE      C:             233        45 19%
DELTA        C:             475        78 16%
ECHO         C:             464       256 55%     
ECHO         S:             465       222 48%
FOXTROT      C:             476       224 47%
GOLF         C:             475       100 21%
HOTEL        C:             476        42 9% 

or, even better:

Server       DeviceID Size [GB] Free [GB] Free [%]
------------ -------- --------- --------- --------
ALPHA        C:             299       161 54%     
ALPHA        E:             499       192 39% 
------------ -------- --------- --------- --------
BRAVO        C:             476       137 29%
------------ -------- --------- --------- --------
CHARLIE      C:             233        45 19%
------------ -------- --------- --------- --------
DELTA        C:             475        78 16%
------------ -------- --------- --------- --------
ECHO         C:             464       256 55%     
ECHO         S:             465       222 48%
------------ -------- --------- --------- --------
FOXTROT      C:             476       224 47%
------------ -------- --------- --------- --------
GOLF         C:             475       100 21% 
------------ -------- --------- --------- --------
HOTEL        C:             476        42 9% 

How could I obtain one of these two last output formats?

Fry Simpson
  • 1,125
  • 11
  • 15
  • 1
    As an aside: The CIM cmdlets (e.g., `Get-CimInstance`) superseded the WMI cmdlets (e.g., `Get-WmiObject`) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell _Core_, where all future effort will go, doesn't even _have_ them anymore. For more information, see [this answer](https://stackoverflow.com/a/54508009/45375). – mklement0 Feb 24 '20 at 21:25

2 Answers2

1

This behavior is due to how powershell handles multiple writes of same object (Explained here: https://github.com/PowerShell/PowerShell/issues/2228).

I can suggest a small change which would fix this:

$output = @()
ForEach ($s in $servers)
{ 
        $output += get-wmiobject win32_logicaldisk -ComputerName $s -Filter "Drivetype=3"| Select-Object  @{n='Server '; e={$s}}, 
                         DeviceID,
                         @{n="Size [GB]";e={[math]::truncate($_.size / 1GB)}},  
                         @{n="Free [GB]";e={[math]::truncate($_.freespace / 1GB)}} , 
                         @{n="Free [%]";e={($_.freespace / $_.Size).ToString("P0")}} 
}

$output | ft 

output: result image

ClumsyPuffin
  • 3,909
  • 1
  • 17
  • 17
1

which, to my surprise, doesn't just add a column to previous output table

Since the additional, calculated property makes your output objects have more than 4 properties, PowerShell automatically switches from tabular (implied Format-Table to list (implied Format-List) display (which is the default behavior for objects that do not have predefined format data associated with them).

Adding | Format-Table just causes the output to be:

The reason for multiple headers getting displayed is that you're calling Format-Table for each call to the obsolete[1] get-wmiobject cmdlet, instead of applying a single Format-Table call to the combined output of the loop.

The simplest solution is to use the ForEach-Object cmdlet in the pipeline instead of a foreach loop statement:

$servers | ForEach-Object {
 $server = $_ 
 get-wmiobject win32_logicaldisk -ComputerName $_ -Filter "Drivetype=3" | 
   select @{n='Server '; e={$server}},                                                                                 
          DeviceID,                                                                                
          @{n="Size [GB]";e={[math]::truncate($_.size / 1GB)}},                                                                                  
          @{n="Free [GB]";e={[math]::truncate($_.freespace / 1GB)}}  
} | Format-Table

Note the use of automatic variable $_ to refer to the input object at hand.

If you wanted to stick with a foreach loop, wrap it in & { ... } | Format-Table


[1] Note that the CIM cmdlets (e.g., Get-CimInstance) superseded the WMI cmdlets (e.g., Get-WmiObject) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell Core, where all future effort will go, doesn't even have them anymore. For more information, see this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Your suggested code works except for a particular: the strings in the "Server" columns are not ```SERVERNAME``` as in my first script, instead they are ```\\SERVERNAME\root\cimv2:Win32_LogicalDisk.DeviceID="C:"```. Any suggestion to get rid of the leading ```\\``` and, most of all, of the trailing ```\root\cimv2:Win32_LogicalDisk.DeviceID="C:"```? – Fry Simpson Feb 25 '20 at 08:29
  • Ok, i figured it out. To print just ```SERVERNAME``` instead of ```\\SERVERNAME\root\cimv2:Win32_LogicalDisk.DeviceID="C:"```, substitute ```@{n='Server '; e={$_}}``` with ```@{n='Server '; e={$_.PSComputerName}}``` as the first column of the select statement. For some reason ```select @{n='Server '; e={$_}}``` seems to be equivalent to ```select @{n='Server '; e={$_.Path}}``` which is equivalent to ```select @{n='Server '; e={$_.__PATH}}```. While choosing $_.Path to represent the object $_ itself... any idea of why having two vars Path and __PATH holding apparentely the same value? – Fry Simpson Feb 25 '20 at 12:02
  • 1
    @FrySimpson, good point - please see my update, which simply uses aux. variable `$server` in the script block to capture the _original_ `$_` value, for use in the _nested_ pipeline. The problem was that the inner, nested pipeline has its own `$_`, which refers to the `get-wmiobject` output. – mklement0 Feb 25 '20 at 13:35