PeetersOnline.nl
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.
7 Responses to Compare-Clusters
Tags
Active Directory API bind order cleanup cluster CPU Custom Fields datastores description device management directory tree errors Event Log file name filter Fun function HA IT known issues License Server LUN multipath NIC objects Oneliner portgroups PowerCLI PowerShell profile recursive Registry Scripts security session share snapshots SQL Stat VI Toolkit VMware vSphere WMI WSUS ZenArchives
- July 2012
- July 2011
- February 2011
- January 2011
- December 2010
- May 2010
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008


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.
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
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«
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.
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
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
Bert/Hugo
Any chance you can post a version with the changes suggested by Bert ?
Simon