1

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.

Daniel
  • 476
  • 6
  • 21

1 Answers1

1

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
Doug Maurer
  • 8,090
  • 3
  • 12
  • 13
  • This produces a nearly blank output except for some permission denied errors when trying to connect to some VMs - see [here](https://gist.github.com/VTSquirrel/8853e69d42cb46483f08dc40966f4495) – Daniel Dec 13 '20 at 01:53
  • That’s a separate issue – Doug Maurer Dec 13 '20 at 02:04
  • Yeah I know, not really concerned about those errors at the moment, though. Will investigate each of them separately. Just not sure why the output would be blank to begin with... – Daniel Dec 13 '20 at 02:05
  • If there is any other output including errors included that all goes into the output. I'd run each VM one by one and see what errors you're getting. – Doug Maurer Dec 13 '20 at 03:13
  • 2
    Check my edit. Some extra steps should help you get the desired output. If you have the choice to switch to Invoke-Command, for your own sake please do. Sending a script as a string and all output being returned as a string is what powershell was made to save us from. – Doug Maurer Dec 13 '20 at 08:58