Description:

This script will compare all ESX hosts inside each cluster. It checks wether all datastores, LUNs and Port Groups are available to all hosts in the cluster. It generates a nicely formatted HTML page with the output.

Code:

$outputFile = 'D:sciptscompare.html'
$VCServer = "MyVCServer"
 
Function Create-HTMLTable
	{
	param([array]$Array)
	$arrHTML = $Array | ConvertTo-Html
	$arrHTML[-1] = $arrHTML[-1].ToString().Replace('',"")
	Return $arrHTML[5..1000]
	}
 
$output = @()
$output += ''
$output += '<!--
table{border-style:solid;border-width:1px;font-size:8pt;background-color:#ccc;width:100%;}th{text-align:left;}td{background-color:#fff;width:20%;border-style:solid;border-width:1px;}body{font-family:verdana;font-size:8pt;}h1{font-size:12pt;}h2{font-size:10pt;}
-->'
$output += '
<h1>VMWARE CONFIGURATION INCONSISTENCIES</h1>
'
$output += '
 
The following items are not available to all ESX servers in the cluster:
 
'
 
$VC = Connect-VIServer $VCServer
 
ForEach ($Cluster in (Get-Cluster | Sort Name))
	{
	$VMHosts = $Cluster | Get-VMHost | Sort Name
	$VMHostViews = $VMHosts | Get-View | Sort Name
 
	$myDSCol = @()
	$Datastores = Get-Datastore -VMHost $VMHosts
	$DSdiffs = $VMHosts | ForEach {Compare-Object $Datastores (Get-Datastore -VMHost $_) -SyncWindow 1000} | ForEach {$_.InputObject} | Sort Name | Select Name -Unique
	ForEach ($DSdiff in $DSdiffs)
		{
		If ($DSdiff.Name -ne $null)
			{
			$myDSObj = "" | Select Datastore
			$myDSObj.Datastore = $DSdiff.Name
			ForEach ($VMHost in $VMHosts)
				{
				$myDSObj | Add-Member -MemberType NoteProperty -Name $VMHost.Name -Value (!!(Get-Datastore -Name $myDSObj.Datastore -VMHost $VMHost -ErrorAction SilentlyContinue))
				}
			$myDSCol += $myDSObj
			}
		}
 
	$myLUNCol = @()
	$LUNs = $VMHostViews | ForEach {$_.Config.StorageDevice.ScsiLun | ForEach {$_.Uuid}} | Select -Unique
	$LUNdiffs = @()
	ForEach ($VMHostView in $VMHostViews)
		{
		$HostLUNs = $VMHostView.Config.StorageDevice.ScsiLun | ForEach {$_.Uuid} | Select -Unique
		$LUNdiffs += Compare-Object $LUNs $HostLUNs -SyncWindow 1000 | ForEach {$_.InputObject}
		Clear-Variable HostLUNs -ErrorAction SilentlyContinue
		}
	ForEach ($LUNdiff in ($LUNdiffs | Select -Unique | Sort))
		{
		If ($LUNdiff -ne $null)
			{
			$myLUNObj = "" | Select LunUuid
			$myLUNObj.LunUuid = $LUNdiff
			ForEach ($VMHostView in $VMHostViews)
				{
				If (($VMHostView.Config.StorageDevice.ScsiLun | Where {$_.Uuid -eq $myLUNObj.LunUuid}) -ne $null)
					{
					$myLUNObj | Add-Member -MemberType NoteProperty -Name $VMHostView.Name -Value (($VMHostView.Config.StorageDevice.ScsiLun | Where {$_.Uuid -eq $myLUNObj.LunUuid}).CanonicalName)
					}
				Else
					{
					$myLUNObj | Add-Member -MemberType NoteProperty -Name $VMHostView.Name -Value $False
					}
				}
			$myLUNCol += $myLUNObj
			}
		}
 
	$myPGCol = @()
	$PortGroups = Get-VirtualPortGroup -VMHost $VMHosts | ForEach {$_.Name} | Select -Unique
	$PGdiffs = @()
	ForEach ($VMHost in $VMHosts)
		{
		$HostPGs = Get-VirtualPortGroup -VMHost $VMHost | ForEach {$_.Name} | Select -Unique
		$PGdiffs += Compare-Object $PortGroups $HostPGs -SyncWindow 1000 | ForEach {$_.InputObject}
		Clear-Variable HostPGs -ErrorAction SilentlyContinue
		}
	ForEach ($PGdiff in ($PGdiffs | Select -Unique | Sort))
		{
		If ($PGdiff -ne $null)
			{
			$myPGObj = "" | Select PortGroup
			$myPGObj.PortGroup = $PGdiff
			ForEach ($VMHost in $VMHosts)
				{
				$myPGObj | Add-Member -MemberType NoteProperty -Name $VMHost.Name -Value (!!(Get-VirtualPortGroup -Name $myPGObj.PortGroup -VMHost $VMHost -ErrorAction SilentlyContinue))
				}
			$myPGCol += $myPGObj
			}
		}
 
	$output+= '
<h2>'
	$output += $Cluster.Name
	$output+= '</h2>
'
	If ($myDSCol.Count -eq 0)
		{
		$output += '
 
'
		$output += "All datastores OK."
		$output += '
 
'
		}
	Else
		{
		$output += '
 
'
		$output += Create-HTMLTable $myDSCol
		$output += '
 
'
		}
		If ($myLUNCol.Count -eq 0)
		{
		$output += '
 
'
		$output += 'All LUNs OK.'
		$output += '
 
'
		}
	Else
		{
		$output += '
 
'
		$output += Create-HTMLTable $myLUNCol
		$output += '
 
'
		}
	If ($myPGCol.Count -eq 0)
		{
		$output += '
 
'
		$output += "All portgroups OK."
		$output += '
 
'
		}
	Else
		{
		$output += '
 
'
		$output += Create-HTMLTable $myPGCol
		$output += '
 
'
		}
 
	Clear-Variable VMHosts -ErrorAction SilentlyContinue
	Clear-Variable Datastores -ErrorAction SilentlyContinue
	Clear-Variable DSdiffs -ErrorAction SilentlyContinue
	Clear-Variable PortGroups -ErrorAction SilentlyContinue
	Clear-Variable PGdiffs -ErrorAction SilentlyContinue
	Clear-Variable LUNs -ErrorAction SilentlyContinue
	Clear-Variable LUNdiffs -ErrorAction SilentlyContinue
	}
 
$output += ''
$output | Out-File $outputFile -Force
ii $outputfile
 
Disconnect-VIServer -Confirm:$False

Download:

Compare-Clusters (Rename to .ps1)

Disclaimer:

All the scripts on PeetersOnline.nl are published under a Creative Commons license, which means you should refer to me if you want to republish (pieces of) them. Thank you. More information about Creative Commons can be found here: Creative Commons Attribution 3.0 Netherlands License.

Creative Commons License

 

7 Responses to Compare-Clusters

  1. Bert says:

    Nice script, It did almost everything I needed. I made some modifications to deal with empty clusters, local storage, the combination of Portgroup name and VLAN-ID and checking if LUNs with the same UUID are seen with the same LU number across the cluster. My changes are not very elegant but if you are interested I could send you the changed version.

    Thank you very much for this script, it saved me quite a bit of time.

    • admin says:

      You’re very welcome. Thank you for dropping a comment! You’re the reason I run this website.
      Nice ideas for additions. I’ll note them and might update the script in the near future.
      Hugo

  2. Todd Hayward says:

    Hello,

    have you considered porting your scripts for use in PowerGUI, in conjuncture with the VMWare PowerPack ?

    I know a little about powershell, but certainly not enough to be able to modify your scripts to work in the VMWare PowePack (inheriting the VC session login, etc).

    Thanks, – T in Chicago

    »crosslinked«

    • admin says:

      The existing VMware PowerPack is way better than the parts I created myself, so I abandoned that idea. Some scripts can be run straight from PowerGUI without modifications. Would be nice to modify those that target specific items in the hierarchy, I agree.
      Don’t have too much time for that though… I’ll keep it in mind.

  3. Osama El-Zorkani says:

    Great script. I ran into some prblem with the html format. I wonder if you could directed the output to csv file? Thanks again for hosting your web site..

    Thanks, O in Austin

    • admin says:

      Outputting to csv requires to rewrite a large part of the script. Do-able, but I don’t think I can find the time soon. Sorry.
      Hugo

  4. Simon says:

    Bert/Hugo

    Any chance you can post a version with the changes suggested by Bert ?

    Simon