VMware Cloud Community
steve31783
Enthusiast
Enthusiast
Jump to solution

scripting esxcfg-mpath -l results

Hello all...

I recently had an issue with a few of my ESX hosts, where particular HBA ports on the host were not seeing all of the paths to our SAN that I expect them to.

What I would like to do is have a script that could gather results similar to the esxcfg-mpath -l command for each host in a particular cluster, and then export that to csv so I can have a weekly check to ensure there aren't any SAN issues related to this particular problem...

I really have no idea where to start, or if a similar output is available using commands in the vi toolkit. I had done a little reading about using plink to do similar things, but id prefer to not go down that road if i dont have to.

Anyone have any ideas?

Reply
0 Kudos
1 Solution

Accepted Solutions
halr9000
Commander
Commander
Jump to solution

My bad. The previous script didn't account for multiple ESX servers because at the time I was only hooked up to one and I didn't get a lot of sleep the night before. Smiley Happy Here is a version which accepts VMhost info on the pipeline. However, there needs to be some filtering for inapplicable disks.

filter Get-VMHostMpath {
	$hostview = $_ | Get-View
	$VMHostName = $_.Name
	$mPathLun = $hostview.Config.StorageDevice.MultipathInfo.Lun
	foreach ( $lun in $mPathLun ) {
		$lunName = $lun.Id
		$pathCount = $lun.Path.Length
		$mPathPolicy = $lun.Policy.Policy
		Write-Host -foregroundcolor Yellow "Host server: $VMHostName"
		Write-Host "Disk $lunName has $pathCount paths and policy of $mPathPolicy."
	}
}

Usage:

PS > . .\filename.ps1 # you have to dot-source to make the function available in the current scope

PS > Get-VMHost | Get-VMHostMpath

Host server: phatlesx02.qatest.iss.net

Disk 02001f0000600a0b800026f1c20000000000000000556e69766572 has 2 paths and policy of PSP_MRU.






[PowerShell MVP|https://mvp.support.microsoft.com/profile=5547F213-A069-45F8-B5D1-17E5BD3F362F], VI Toolkit forum moderator

Author of the upcoming book: Managing VMware Infrastructure with PowerShell

Co-Host, PowerScripting Podcast (http://powerscripting.net)

Need general, non-VMware-related PowerShell Help? Try the forums at PowerShellCommunity.org

My signature used to be pretty, but then the forum software broked it. vExpert. Microsoft MVP (Windows PowerShell). Author, Podcaster, Speaker. I'm @halr9000

View solution in original post

Reply
0 Kudos
14 Replies
halr9000
Commander
Commander
Jump to solution

This should get you going:

$hostview = Get-VMHost | Get-View
$mPathLun = $hostview.Config.StorageDevice.MultipathInfo.Lun
foreach ( $lun in $mPathLun ) {
	$lunName = $lun.Id
	$pathCount = $lun.Path.Length
	$mPathPolicy = $lun.Policy.Policy
	Write-Host "Disk $lunName has $pathCount paths and policy of $mPathPolicy."
}

Output:

Disk vmhba0:0:0 has 1 paths and policy of mru.






[PowerShell MVP|https://mvp.support.microsoft.com/profile=5547F213-A069-45F8-B5D1-17E5BD3F362F], VI Toolkit forum moderator

Author of the upcoming book: Managing VMware Infrastructure with PowerShell

Co-Host, PowerScripting Podcast (http://powerscripting.net)

Need general, non-VMware-related PowerShell Help? Try the forums at PowerShellCommunity.org

My signature used to be pretty, but then the forum software broked it. vExpert. Microsoft MVP (Windows PowerShell). Author, Podcaster, Speaker. I'm @halr9000
steve31783
Enthusiast
Enthusiast
Jump to solution

Hey Hal..

Appreciate the help... I just ran that script, but the output returns as

"Disk has paths and polict of ."

Seems as though there's no values assigned to the variables.

My PS/Vi toolkit knowledge is limited but im going to try to work on this to see if I can make something of it... if you have any suggestions, then by all means please let me know...

$hostview = Get-Cluster "Tier2 (Dev)" | Get-VMHost | Get-View

$mPathLun = $hostview.Config.StorageDevice.MultipathInfo.Lun

foreach ( $lun in $mPathLun ) {

$lunName = $lun.Id

$pathCount = $lun.Path.Length

$mPathPolicy = $lun.Policy.Policy

Write-Host "Disk $lunName has $pathCount paths and policy of $mPathPolicy."

}

Reply
0 Kudos
halr9000
Commander
Commander
Jump to solution

My bad. The previous script didn't account for multiple ESX servers because at the time I was only hooked up to one and I didn't get a lot of sleep the night before. Smiley Happy Here is a version which accepts VMhost info on the pipeline. However, there needs to be some filtering for inapplicable disks.

filter Get-VMHostMpath {
	$hostview = $_ | Get-View
	$VMHostName = $_.Name
	$mPathLun = $hostview.Config.StorageDevice.MultipathInfo.Lun
	foreach ( $lun in $mPathLun ) {
		$lunName = $lun.Id
		$pathCount = $lun.Path.Length
		$mPathPolicy = $lun.Policy.Policy
		Write-Host -foregroundcolor Yellow "Host server: $VMHostName"
		Write-Host "Disk $lunName has $pathCount paths and policy of $mPathPolicy."
	}
}

Usage:

PS > . .\filename.ps1 # you have to dot-source to make the function available in the current scope

PS > Get-VMHost | Get-VMHostMpath

Host server: phatlesx02.qatest.iss.net

Disk 02001f0000600a0b800026f1c20000000000000000556e69766572 has 2 paths and policy of PSP_MRU.






[PowerShell MVP|https://mvp.support.microsoft.com/profile=5547F213-A069-45F8-B5D1-17E5BD3F362F], VI Toolkit forum moderator

Author of the upcoming book: Managing VMware Infrastructure with PowerShell

Co-Host, PowerScripting Podcast (http://powerscripting.net)

Need general, non-VMware-related PowerShell Help? Try the forums at PowerShellCommunity.org

My signature used to be pretty, but then the forum software broked it. vExpert. Microsoft MVP (Windows PowerShell). Author, Podcaster, Speaker. I'm @halr9000
Reply
0 Kudos
steve31783
Enthusiast
Enthusiast
Jump to solution

Awesome thanks, ill take a look!!!

Here's what me and a colleague have been working on..... probably not very clean looking to you, but it's getting there.

$outfile = "C:\Inetpub\wwwroot\multipath.htm"

"<table border=`"1`">" > $outfile

"<tr>" >> $outfile

"<th bgcolor=`"#BDBDBD`">VM Host Name</th>" >> $outfile

"<th bgcolor=`"#BDBDBD`">Lun Name</th>" >> $outfile

"<th bgcolor=`"#BDBDBD`">Path Count</th>" >> $outfile

"<th bgcolor=`"#BDBDBD`">Multipath Policy</th>" >>$outfile

"</tr>" >> $outfile

foreach ($esx in get-cluster "Tier2 (Dev)" | get-vmhost | sort-object -property Name ) {

$hostview = Get-VMHost $esx.name | get-view

$mPathLun = $hostview.Config.StorageDevice.MultipathInfo.Lun

"<tr><td align=`"center`" bgcolor=`"red`">" + $esx.name + "</td>" >> $outfile

"</tr><tr>" >> $outfile

foreach ( $lun in $mPathLun ) {

$lunName = $lun.Id

$pathCount = $lun.Path.Length

$mPathPolicy = $lun.Policy.Policy

"<td></td>" >> $outfile

"<td align=`"center`">" + $lunname + "</td><td align=`"center`">" + $pathCount + "</td><td align=`"center`">" + $mPathPolicy + "</td></tr>" >> $outfile

#"Disk $lunName has $pathCount paths and policy of $mPathPolicy." >> $outfile

}

}

"<tr><td COLSPAN=2 bgcolor=`"#BDBDBD`">" + $date + "</td><td COLSPAN=2 bgcolor=`"#BDBDBD`"></td></tr>" >> $outfile

"</table>" >> $outfile

Reply
0 Kudos
steve31783
Enthusiast
Enthusiast
Jump to solution

Hey Hal..

If I also wanted to display the disks name (\dev\sdi) and size, what would I use to put into those variables?

ie.

$diskname = needyourhelphere

$disksize = needyourhelphere

If it's easy to explain to me how I can look at these properties to see what attributed I can use, please let me know so I can stop bugging you!! There's a few things I might want to add like WWN of the SP/port on the active path, so once I know where this all is I should be able to figure it out. Thanks for the help.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

I was intrigued by the challenge.

Attached my attempt at emulating the esxcfg-mpath -l command.

There are some points that are not the there:

1) the PCI address of the HBA for a local disk is apparently stored in hex but displayed in decimal (I think).

My script displays the PCI address as it is stored (hex)

2) the diskname (/dev) is a name that is apparently not present in any of the SDK properties.

My script doesn't display this.

$esx = Get-VMHost -Name <esx-hostname> | Get-View
foreach($disk in $esx.Config.StorageDevice.ScsiLun){
  foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun){
    if($disk.CanonicalName -eq $lun.Id){
	  $pathNumber = $lun.Path.Count
	  $policyName = $lun.Policy.Policy
	  $capacityMb = ($disk.Capacity.Block * $disk.Capacity.BlockSize) / 1Mb
# Disk line
	  $line = "Disk " + $disk.CanonicalName + " (" + $capacityMb + "MB) has " + $pathNumber + " paths and policy of " + $policyName
        Write-Host $line
# Path line(s)
      $preferredPath = $lun.Policy.Prefer
	  foreach($path in $lun.Path){
	    $device = $disk.CanonicalName.Substring(0,$disk.CanonicalName.IndexOf(":"))
		foreach($hba in $esx.Config.StorageDevice.HostBusAdapter){
		  if($hba.Device -eq $device){break}
		}
		if($path.Name -eq $preferredPath){$preferred = "preferred"}
		else{$preferred = ""} 
		switch($path.PathState){
		  "active" {$pathStatus = "On active"}
		  "disabled" {$pathStatus = "Off"}
		  "standby" {$pathStatus = "On"}
                 default {$pathStatus = "unknown"}
		}
		switch($path.Transport.gettype().Name){
	          "HostParallelScsiTargetTransport" {
	            $line = " Local " + $hba.Pci + " " + $path.Name + " " + $pathStatus + " " + $preferred
	          }
	          "HostInternetScsiTargetTransport" {
		    $line = " iScsi sw " + $hba.IScsiName + " <-> " + $path.Transport.IScsiName + " " + $pathStatus + " " + $preferred
		  }
	        }
		Write-Host $line
	    }
	    break
	}
  }

The script, in this format, only handles 1 ESX server at the time but it can easily be converted to a filter.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
steve31783
Enthusiast
Enthusiast
Jump to solution

Forgive me for asking a stupid question, but what do you mean by it can be converted to a filter?

Thanks for your effort in looking into this... I appreciate the help.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Same thing Hal did with his script.

Instead of a standalone script you create a filter.

That way you can "pipe" objects to it.

The filter will be called for each object you place in the pipe.

The object can be accessed in the filter through the $_ variable.

Something like this

filter MyEsxcfgMpath {
  $esx = Get-VMHost -Name $_.Name | Get-View
  foreach($disk in $esx.Config.StorageDevice.ScsiLun){
  ....
}
# Call the filter for all your ESX servers
Get-VMHost | MyEsxcfgMpath


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

datta123
Contributor
Contributor
Jump to solution

Is it possible to collect the information (in a single file) vcms point of view for all esx servers as below...I am using esx 3.5

How many vm machines are laying in the lun (lun wise information with vm machine names / ip & notes)

A lun mapped on multilple esx servers or not? what are they? (lun id and esx server ip / hostname)

What is the source and manufacturer of the lun (full storage partition info)

Thanks .............

Reply
0 Kudos
justin_emerson
Enthusiast
Enthusiast
Jump to solution

Hi guys,

One of the most useful scripts I've found is the following script to automatically Load Balance paths on an ESX server:

http://www.yellow-bricks.com/2008/04/01/load-balancing-activeactive-sans/

Is there a way to replicate this script in PowerShell that will apply to all servers in a cluster, and have it also keep the same path for LUNs across servers (i.e. If server 1 uses Path 2 to access LUN 3, Server 2 will also use Path 2 to get to LUN3)? This is important for arrays which have to transfer ownership (such as active/passive ones).

Thanks a bunch.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Did you have a look at ?

It points to Carter's blog entry that shows how to set the preferred path.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
halr9000
Commander
Commander
Jump to solution

Is it possible to collect the information (in a single file) vcms point of view for all esx servers as below...I am using esx 3.5

It's very easy to do this sort of thing with powershell. Run your script or command and pipe it to set-content and give it a filename. Or, the old redirection symbol works too, e.g. "> lun.txt".

How many vm machines are laying in the lun (lun wise information with vm machine names / ip & notes)

Actually this one is hard to do because a datastore can have multiple LUNs. There is no direct relationship of VM to LUN. You can however, do VM to Datastore, and Datastore to LUN.

A lun mapped on multilple esx servers or not? what are they? (lun id and esx server ip / hostname)

Mess with Get-Datastore.






[PowerShell MVP|https://mvp.support.microsoft.com/profile=5547F213-A069-45F8-B5D1-17E5BD3F362F], VI Toolkit forum moderator

Author of the upcoming book: Managing VMware Infrastructure with PowerShell

Co-Host, PowerScripting Podcast (http://powerscripting.net)

Need general, non-VMware-related PowerShell Help? Try the forums at PowerShellCommunity.org

My signature used to be pretty, but then the forum software broked it. vExpert. Microsoft MVP (Windows PowerShell). Author, Podcaster, Speaker. I'm @halr9000
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

The first version of the script was missing FC paths.

It is now included.

The script still misses the instructions to handle block adapters but since I don't have access to that type of adapter I leave this open for now.

$esx = Get-VMHost -Name <ESX-hostname> | Get-View
foreach($disk in $esx.Config.StorageDevice.ScsiLun){
	foreach($lun in $esx.Config.StorageDevice.MultipathInfo.Lun){
		if($disk.CanonicalName -eq $lun.Id){
			$pathNumber = $lun.Path.Count
			$policyName = $lun.Policy.Policy
			$capacityMb = ($disk.Capacity.Block * $disk.Capacity.BlockSize) / 1Mb
			# Disk line
			$line = "Disk " + $disk.CanonicalName + " (" + $capacityMb + "MB) has " + $pathNumber + " paths and policy of " + $policyName
			Write-Host $line
			# Path line(s)
			$preferredPath = $lun.Policy.Prefer
			foreach($path in $lun.Path){
				$device = $disk.CanonicalName.Substring(0,$disk.CanonicalName.IndexOf(":"))
				foreach($hba in $esx.Config.StorageDevice.HostBusAdapter){
					if($hba.Device -eq $device){break}
				}
				if($path.Name -eq $preferredPath){$preferred = "preferred"}
				else{$preferred = ""} 
				switch($path.PathState){
					"active" {$pathStatus = "On active"}
					"disabled" {$pathStatus = "Off"}
					"standby" {$pathStatus = "On"}
					default {$pathStatus = "unknown"}
				}
				switch($path.Transport.gettype().Name){
				    "HostFibreChannelTargetTransport" {
						$line = " FC " + $hba.Pci + " " + [convert]::ToString($hba.PortWorldWideName,16) + " <-> " + [convert]::ToString($path.Transport.PortWorldWideName,16) + " " + $path.Name + " " + $pathStatus + " " + $preferred
					}
					"HostParallelScsiTargetTransport" {
						$line = " Local " + $hba.Pci + " " + $path.Name + " " + $pathStatus + " " + $preferred
					}
					"HostInternetScsiTargetTransport" {
						$line = " iScsi sw " + $hba.IScsiName + " <-> " + $path.Transport.IScsiName + " " + $pathStatus + " " + $preferred
					}
				}
				Write-Host $line
			}
			break
		}
	}
}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
gboskin
Enthusiast
Enthusiast
Jump to solution

As usual nice work LuCd ..any chance of exporting into HTML file ..

:smileyblush:

Reply
0 Kudos