The problem is due to the fact that the cmdlet Export-Csv in this case takes the objects that are in the pipeline to write to the CSV file.
In this case the objects that are in the pipeline is the output of the Get-Harddisk cmdlet, which is a HardDiskImpl object.
And the HardDiskImpl object doesn't contain the name of the guest.
One way of solving this is to use "calculated properties" on the Select-Object cmdlet.
Something like this for example
Get-VM | select Name, Description, MemoryMB, numcpu, @{Name="HardDisk";E={$_ | Get-HardDisk | Select Name, CapacityKB, Filename}} | Export-Csv "D:\output\results.csv"
The problem you will in your CSV file is that the hard disk information is all in one column.
That's because all the hard disk information is considered 1 object, a so-called PsObject with all the hard disk properties in there.
If you want to have the hard disk information in separate columns you could do
Get-VM | select Name, Description, MemoryMB, numcpu, @{Name="HardDisk";E={($_ | Get-HardDisk).Name}},
@{Name="HDCapacity";Expression={($_ | Get-HardDisk).CapacityKB}} | Export-Csv "D:\output\results.csv"
The problem with this line is that it doesn't handle guests with more than 1 hard disk very well.
One of the solutions is to create your own "custom object" and populate the properties yourself.
The disadvantage is that it will be difficult to maintain the one-liner format in this case.
This is a possible solution
$report = @()
Get-VM | %{
$vm = $_
$_ | Get-HardDisk | %{
$row = "" | select VMname, Description, MemoryMB, numcpu, HDName, HDCapacity, HDFilename
$row.VMname = $vm.Name
$row.Description = $vm.Description
$row.MemoryMB = $vm.MemoryMB
$row.numcpu = $vm.numcpu
$row.HDName = $_.Name
$row.HDCapacity = $_.CapacityKB
$row.HDFilename = $_.Filename
$report += $row
}
}
$report | Export-Csv "C:\report.csv" -noTypeInformation
Note that the resulting CSV file will contain a row for each hard disk for each guest.