VmWare and Powershell multi-valued attributes

Hello guys and Happy New Year!!
I have a question about multi-valued attributes and how to export them as csv.
While I know how to work with multi-valued attributes I’ve come to a dead end with this script that I am writing.
Here are the details:
I have to export a csv file that will contain VMName, HardDiskName, FileName etc.
At first I tried this approach (1):
$hdd = Get-HardDisk -VM “vmname” -DiskType RawPhysical| select Parent, Name
$props = @{‘VMName’ = $hdd.parent
‘HDDName’ = $hdd.name

		}

$obj = New-Object -TypeName PSObject -Property $props
#Write-Output $obj
$obj | Export-Csv vm.csv -NoTypeInformation
I quickly realised that this approach won’t work because I am dealing with multi-valued attributes and I won’t be able to export them properly.
…than I tried this (approach 2)

$hdd = Get-HardDisk -VM “vmname” -DiskType RawPhysical| select @{Name=‘VmName’;Expression={[string]::join(“;”, ($.parent))}}, @{Name=‘HDDName’;Expression={[string]::join(“;”, ($.name))}}
$props = @{‘VMName’ = $hdd.parent
‘HDDName’ = $hdd.name
}

$obj = New-Object -TypeName PSObject -Property $props
#Write-Output $obj
$obj | Export-Csv vm.csv -NoTypeInformation

Needles to say that this did not work either

Some attributes are not multi-valued and I could get them with approach 1 but I cannot get the multi-valued attributes.

if I do this
$hdd = Get-HardDisk -VM svwdbn21 -DiskType RawPhysical| select @{Name=‘VmName’;Expression={[string]::join(“;”, ($.parent))}}, @{Name=‘HDDName’;Expression={[string]::join(“;”, ($.name))}},`
@{Name=‘FileName’;Expression={[string]::join(“;”, ($.filename))}}, @{Name=‘DeviceName’;Expression={[string]::join(“;”, ($.devicename))}},`
@{Name=‘CanonicalName’;Expression={[string]::join(“;”, ($_.ScsiCanonicalName))}}| Export-csv test.csv

I can get almost all details I need except LUN info which I am getting it with the following piece of code:

$hdd = Get-HardDisk -VM “vmname” -DiskType RawPhysical| select parent, name, filename, devicename, ScsiCanonicalName
$Lun = Get-SCSILun $hdd.SCSICanonicalName -VMHost $vm.vmhost
$lunpaths=$lun|Get-ScsiLunPath
$luns = $lunpaths | select name, sanid, State, Preferred
$luns

… and here is where I got really stuck.
I need a way to combine in one csv file all the multi-valued atributes and LUN info which right now is stored in $luns.
Any ideas/help will be much appreciated.
Thank you

Please can you give some sample data for $luns and the output you would like in the CSV. It’s hard to answer the question without knowing specifically what data you have and what you want the CSV file to look like.

If you’re just looking to get a multivalued property or array in a single cell then I think you’re working along the right lines using the join method. Here’s a quick example with Win32_LogicalDisk

$disks = Get-WmiObject Win32_LogicalDisk | Select-Object DeviceId,VolumeName

$obj = [PSCustomObject] @{

    Id   = $disks.DeviceId -join ';'
    Name = $disks.VolumeName -join ';'
  
}

$obj | ConvertTo-Csv

Hi Matt and thank you.
I do not have some sample data for $luns. I have to be at work to be able to get that data but you gave me an idea
All the info that I need (with the exception of VmHost) I can get it from Get-HardDisk so please follow my logic here and let me know if I make sense:

https://gist.github.com/anonymous/1219033be14200e25dbe

What do you think?
Thank you Matt

Yes, that’s the kind of approach I would take and I think using the second options for the luns should work.

In the CSV, that will give you columns something like this:

VMName, ... ,LunName,SANId,State,Preferred
VM01, ... ,LUN0;LUN3;LUN5,SAN0;SAN1;SAN2,Online;Offline;Online,No;Yes;No
VM02, ... ,LUN7;LUN8,SAN1;SAN2,Online;Offline,Yes;No

Hi Matt,
this is working in the sense that I am getting all the info that I need but the .csv file is giving me what I really want.
Right now as you mentioned i get all the info on one row:
HardDisk LunName FileName …
Hdd1;hdd2; lun1;lun2;lun3 filename1;filename2…
what i really want is:
HardDisk LunName FileName
Hdd1 lun1 filename1
hdd2 lun2 filename2
hdd3 lun3 filename3
Is this possible?
Thank you again Matt

That should be possible using a foreach loop and a collection of objects. Here’s a working example with Win32_LogicalDisk as PoC:

$disks = Get-WmiObject Win32_LogicalDisk | Select-Object DeviceId,VolumeName

$objColl = @()

foreach ($disk in $disks) {

    $obj = [PSCustomObject] @{

        Id   = $disk.DeviceId
        Name = $disk.VolumeName
  
    }

    $objColl += $obj

}

$objColl | Export-Csv F:\report.csv -NoTypeInformation

I can’t test your code but I imagine it would look something like this:

$vm = Get-VM "vnname"| select name,VMHost
$hdd = Get-HardDisk -VM "vmname" -DiskType RawPhysical| select Parent, Name, Filename, SCSICanonicalName, DeviceName
$Lun = Get-SCSILun $hdd.SCSICanonicalName -VMHost $vm.vmhost
$lunpaths=$lun|Get-ScsiLunPath
$luns = $lunpaths | select name, sanid, State, Preferred

$objColl = @()

foreach ($lun in $luns) {
      
    $props = @{'VMName' = $hdd.parent 
        'HDDName' = $hdd.name 
        'FileName' = $hdd.filename 
        'DeviceName' = $hdd.devicename 
        'CanonicalName' = $hdd.scsicanonicalname 
        'LunName' = $luns.name 
        'SANId' = $luns.sanid
        'State' = $luns.state
        'Preferred' = $luns.preferred 
      
    }

    $obj = New-Object -TypeName PSObject -Property $props

    $objColl += $obj

}

#Write-Output $obj
      $objColl | Export-Csv vm.csv -NoTypeInformation

Almost there Matt. This is what I am getting when I run the script.
I won’t take more of your time. I will have to figure out this all by myself now.
Thank you again for your help.
HDDName LunName FileName SANId Preferred DeviceName State CanonicalName VMName
System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[]
System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[]
System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[]
System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[]
System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[]
System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[]
System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[]
System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[] System.Object[]

Looks like you’ve still got collections for those properties. I’m sure a combination of the techniques will get you where you need to be. I’m happy to continue looking at it if you want to post some sample data. If not, hopefully some combination of the above will get you what you’re after.

Thank you Matt.
Would it be possible to take this off-line for now until we sort this out and post the code after we are done.
I am afraid that this thread will get too long.
I’ve made some changes to the code and I would like to show them to you.