Search code examples
powershellpowercli

Displaying Column Headers Once in Output Report


I'm writing a script to audit the disk partition types in my company's virtual environment using PowerCLI. I've got this code so far:

$report = @()

$VMs = (Get-VM).where{$_.PowerState -eq 'PoweredOn' -and $_.Guest.OSFullName -match 'Windows'}

foreach ($VM in $VMs){
    $vmName = $VM.Name
    $output = Invoke-VMScript -ScriptText @'
      Get-Disk | 
        select @{ l="ComputerName"; e={ $env:COMPUTERNAME } },
               Number, 
               @{ name='Size'; expr={[int]($_.Size/1GB)} },
               PartitionStyle
'@ -VM $vmName -GuestUser $Username -GuestPassword $Password

    $output.ScriptOutput #printing each for testing
    $report += $output.ScriptOutput
}
$report | FT -AutoSize

This will produce an output that looks like this:

ComputerName Number Size PartitionStyle
VMNAME1 0 100 MBR
VMNAME1 1 20 GPT
VMNAME1 2 20 MBR
ComputerName Number Size PartitionStyle
VMNAME2 0 100 MBR
VMNAME2 1 20 GPT

The issue I'm facing is that the output report has the column headers repeated for each VM. How can I fix this to only have the column headers displayed one time, like this:

ComputerName Number Size PartitionStyle
VMNAME1 0 100 MBR
VMNAME1 1 20 GPT
VMNAME1 2 20 MBR
VMNAME2 0 100 MBR
VMNAME2 1 20 GPT

Any ideas for how I can do this? I'm new to powershell so I'm not sure what to do.


Solution

  • Since the output of ScriptOutput is string, you'd have to parse it yourself. Instead I recommend transforming it into a format suitable to be passed around as text, such as CSV.

    $VMs = (Get-VM).where{$_.PowerState -eq 'PoweredOn' -and $_.Guest.OSFullName -match 'Windows'}
    
    $report = foreach ($VM in $VMs){
        $vmName = $VM.name
        $output = Invoke-VMScript -ScriptText @'
          Get-Disk | 
            select @{ l="ComputerName"; e={ $env:COMPUTERNAME } },
                   Number, 
                   @{ name='Size'; expr={[int]($_.Size/1GB)} },
                   PartitionStyle | ConvertTo-Csv
    '@ -VM $vmName -GuestUser $Username -GuestPassword $Password
    
        $output.ScriptOutput | ConvertFrom-Csv
    }
    
    $report | FT -AutoSize
    

    Also, as Theo commented, += can be very expensive and is almost always unnecessary. As shown here you can simply collect the output of the foreach directly into the variable.

    Edit

    Since any extra output such as errors gets capture along with the data you want, it can cause the extra blank lines you mentioned. One way I was able to overcome this was to check for the existence of a column header and then strip away any junk before.

    $VMs = (Get-VM).where{$_.PowerState -eq 'PoweredOn' -and $_.Guest.OSFullName -match 'Windows'}
    
    $report = foreach ($VM in $VMs){
        $output = Invoke-VMScript -ScriptText @'
            Get-Disk | Foreach-Object{
                [PSCustomObject]@{
                    ComputerName   = $env:COMPUTERNAME
                    Number         = $_.number
                    Size           = [int]($_.size/1GB)
                    PartitionStyle = $_.PartitionStyle
                }
            } | ConvertTo-Csv -NoTypeInformation
    
    '@ -VM $vm.Name -GuestUser $Username -GuestPassword $Password
    
        if($output.ScriptOutput -match 'PartitionStyle')
        {
            $output.ScriptOutput -replace '(?s)^.+(?="Com)' | ConvertFrom-Csv
        }
    }
    
    $report | FT -AutoSize