Hi Guys,
I have been working on this script to collect the ESX hosts within a cluster and detail the datastores and number of paths to each datastore.
I do get an output but i seem to get redunency in terms of the datastores being listed. What i am trying to get is the Host and within this the datastores and path count to each datastore. Basically trying to make sure there is more than one path to a datastore.
# Function to create the headings for the output
function New-Row{
param($hostname,$diskname,$paths)
$row = "" | Select-Object VMHost, DiskNAA, PathCount
$row.VMHost = $hostname
$row.DiskNAA = $Diskname
$row.Pathcount = $paths
$row
}
$list = get-Cluster "testcluster" | get-VMHost
$diskpaths =@()
foreach ($srv in $list){
$diskpaths += (New-Row $srv.Name $null $null)
$esx = $srv | Get-View
foreach($disk in $esx.Config.StorageDevice.ScsiLun){
foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun){
$diskpaths += (New-Row null $disk.CanonicalName $lun.Path.Count)
}
}
}
$diskpaths
Any help would be appreciated.
Dougie
Under the storageDevice property sits a HostStorageDeviceInfo object.
In this object you have several lists of storage related entries.
The ScsiLun property is an array that holds all the LUNs present on the host. In these entries you will find the CanonicalName for each LUN.
The multiPath property is also an array that holds again all the LUNs together with the Path information for each of these LUNs.
Unfortunately these entries do not contain the CanonicalName for a LUN.
So we have to combine the information of these 2 arrays together.
The outer loop runs through all the LUNs present in the array under the ScsiLun property.
The inner loop runs through all the LUNs present in the array under the multiPath property.
Since we only want to count the paths for 1 specific LUN, we use the "key" of the ScsiLun entry to select only the multiPath entries that correspond with that specific LUN. The ScsiLun "key" is present in the multiPath LUN as the "LUN" property.
So the line
foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun | where {$_.Lun -eq $disk.Key}){
will:
I hope I didn't confuse you more :smileygrin:
Updated: nearly forgot to answer your datastore question.
Yes, that is possible.
Have a look at my LUN report – datastore, RDM and node visibility post where I do exactly that.
Your script would become something like this
# Function to create the headings for the output function New-Row{ param($hostname,$dsname, $diskname,$paths) $row = "" | Select-Object VMHost, Datastore, DiskNAA, PathCount
$row.VMHost = $hostname
$row.Datastore = $dsname
$row.DiskNAA = $Diskname
$row.Pathcount = $paths
$row
} $list = Get-Cluster | Get-VMHost $datastore = @{} foreach($ds in ($list | Get-Datastore | Sort-Object -Unique)){ if($ds.Extensiondata.Info.Vmfs){ $ds.Extensiondata.Info.Vmfs.Extent | %{ $datastore[$_.DiskName] = $ds.Name } } } $diskpaths =@() foreach ($srv in $list){ $diskpaths += (New-Row $srv.Name $null $null $null) $esx = $srv | Get-View
foreach($disk in $esx.Config.StorageDevice.ScsiLun){ foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun | where {$_.Lun -eq $disk.Key}){ $diskpaths += (New-Row null $datastore[$disk.CanonicalName] $disk.CanonicalName $lun.Path.Count) } } } $diskpaths
The script first created a hash tab with the datastore names and as the key it uses the CanonicalName of each extent of the datastore.
Later on, the script uses the CanonicalName from each ScsiLun entry to find, if any, the corresponding datastore.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
If you change the line:
foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun){
into:
foreach($lun in ($esx.Config.StorageDevice.MultipathInfo.Lun | Sort-Object -Unique)){
you will only get unique lines.
Regards, Robert
Yes I have tested this script and it returns the number of Path in my each NAA is... 4 for all ?
You only have to take the paths that belong to a specific LUN.
That is done with the where-clause
# Function to create the headings for the output
function New-Row{ param($hostname,$diskname,$paths) $row = "" | Select-Object VMHost, DiskNAA, PathCount
$row.VMHost = $hostname
$row.DiskNAA = $Diskname
$row.Pathcount = $paths
$row
} $list = get-Cluster | get-VMHost $diskpaths =@() foreach ($srv in $list){ $diskpaths += (New-Row $srv.Name $null $null) $esx = $srv | Get-View
foreach($disk in $esx.Config.StorageDevice.ScsiLun){ foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun | where {$_.Lun -eq $disk.Key}){ $diskpaths += (New-Row null $disk.CanonicalName $lun.Path.Count) } } } $diskpaths
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Robert,
lol..so simple
Just what i was looking for.
Thats great thanks.
Dougie
Simple, but incorrect I'm afraid.
Each LUN comes back with the same number of paths, which is ok if that is indeed your config.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi Luc,
I am curious about the line you entered.
$lun in $esx.Config.StorageDevice.MultipathInfo.Lun | where {$_.Lun -eq $disk.Key})
What exactly is this doing and how did it resolve the enumeration issue?
Also instead of having the canonical name in the output is it possible to put the datastore name in?
Thanks
Douglas
Under the storageDevice property sits a HostStorageDeviceInfo object.
In this object you have several lists of storage related entries.
The ScsiLun property is an array that holds all the LUNs present on the host. In these entries you will find the CanonicalName for each LUN.
The multiPath property is also an array that holds again all the LUNs together with the Path information for each of these LUNs.
Unfortunately these entries do not contain the CanonicalName for a LUN.
So we have to combine the information of these 2 arrays together.
The outer loop runs through all the LUNs present in the array under the ScsiLun property.
The inner loop runs through all the LUNs present in the array under the multiPath property.
Since we only want to count the paths for 1 specific LUN, we use the "key" of the ScsiLun entry to select only the multiPath entries that correspond with that specific LUN. The ScsiLun "key" is present in the multiPath LUN as the "LUN" property.
So the line
foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun | where {$_.Lun -eq $disk.Key}){
will:
I hope I didn't confuse you more :smileygrin:
Updated: nearly forgot to answer your datastore question.
Yes, that is possible.
Have a look at my LUN report – datastore, RDM and node visibility post where I do exactly that.
Your script would become something like this
# Function to create the headings for the output function New-Row{ param($hostname,$dsname, $diskname,$paths) $row = "" | Select-Object VMHost, Datastore, DiskNAA, PathCount
$row.VMHost = $hostname
$row.Datastore = $dsname
$row.DiskNAA = $Diskname
$row.Pathcount = $paths
$row
} $list = Get-Cluster | Get-VMHost $datastore = @{} foreach($ds in ($list | Get-Datastore | Sort-Object -Unique)){ if($ds.Extensiondata.Info.Vmfs){ $ds.Extensiondata.Info.Vmfs.Extent | %{ $datastore[$_.DiskName] = $ds.Name } } } $diskpaths =@() foreach ($srv in $list){ $diskpaths += (New-Row $srv.Name $null $null $null) $esx = $srv | Get-View
foreach($disk in $esx.Config.StorageDevice.ScsiLun){ foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun | where {$_.Lun -eq $disk.Key}){ $diskpaths += (New-Row null $datastore[$disk.CanonicalName] $disk.CanonicalName $lun.Path.Count) } } } $diskpaths
The script first created a hash tab with the datastore names and as the key it uses the CanonicalName of each extent of the datastore.
Later on, the script uses the CanonicalName from each ScsiLun entry to find, if any, the corresponding datastore.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Great explanation Luc and totally understandable.
A couple of scenarios highlighted themselves when running the script.
I had an ESXi host with 2 HBAs. vmhba1 showed no paths or showed paths dead and vmhba 2 showed active connections.
The script produced the paths as 4 quite rightly, but it did highlight how could to find this issue.
As far as i see it, you would have to look at each vmhba and count the paths for each datastore.
Having looked about a bit it seems to me this type of enumeration wouldnt be possible.
Is this correct?
Thanks
Dougie
I think you can use the operationlState property of the LUN and the pathState for each path, to have a report on the status.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks Luc I will have a look
Dougie