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.
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