I have promised you I would post this script, so here it is!

This Powershell script generates an overview of any items that are not available to every ESX server in a VMware cluster. These items might prevent your vm’s being vmotioned by DRS or restarted by HA. Pretty serious business, I’d say!

The items involved are:
1. datastores
2. LUNs (important when using Raw Device Mappings)
3. port groups

The output is a nicely formatted HTML page showing not only which items are misconfigured, but also where the are available and where they are absent.

Here’s an example:
Compare Screenshot

And here’s the script:
Compare-Clusters (Rename to .ps1)

Enjoy!
Hugo

Tagged with:
 

25 Responses to Check VMware Configuration with Powershell

  1. [...] it’s no surprise probably that Hugo Peeters created a script that does exactly that: This Powershell script generates an overview of any items that are not [...]

  2. Alan Renouf says:

    That is one usefull script, nice one.

  3. Sven Huisman says:

    Very nice! Bookmarked, downloaded and printed! Thanks.

  4. Compare your hosts… « H9Newser’s Blog says:

    [...] it’s no surprise probably that Hugo Peeters created a script that does exactly that: This Powershell script generates an overview of any items that are not [...]

  5. Jay Rogers says:

    I had problems running your script:

    PS C:\iso\powershell> ./compare-clusters.ps1
    There were one or more problems with the server certificate:

    * A certification chain processed correctly, but terminated in a root certificate which isn’t trust
    d by the trust provider.

    * A required certificate is not within its validity period.

    * The certificate’s CN name does not match the passed value.

    Get-View : The argument cannot be null or empty.
    At C:\iso\powershell\compare-clusters.ps1:23 char:36
    + $VMHostViews = $VMHosts | Get-View <<<< | Sort Name
    Get-Datastore : The argument cannot be null or empty.
    At C:\iso\powershell\compare-clusters.ps1:26 char:37
    + $Datastores = Get-Datastore -VMHost <<<< $VMHosts
    Get-Datastore : The argument cannot be null or empty.
    At C:\iso\powershell\compare-clusters.ps1:27 char:82
    + $DSdiffs = $VMHosts | ForEach {Compare-Object $Datastores (Get-Datastore -VMHost <<<< $_) -S
    yncWindow 1000} | ForEach {$_.InputObject} | Sort Name | Select Name -Unique
    Compare-Object : Cannot bind argument to parameter ‘ReferenceObject’ because it is null.
    At C:\iso\powershell\compare-clusters.ps1:48 char:30
    + $LUNdiffs += Compare-Object <<<< $LUNs $HostLUNs -SyncWindow 1000 | ForEach {$_.InputObj
    ect}
    Get-VirtualPortGroup : The argument cannot be null or empty.
    At C:\iso\powershell\compare-clusters.ps1:73 char:44
    + $PortGroups = Get-VirtualPortGroup -VMHost <<<< $VMHosts | ForEach {$_.Name} | Select -Uniqu
    e
    Get-VirtualPortGroup : The argument cannot be null or empty.
    At C:\iso\powershell\compare-clusters.ps1:77 char:42
    + $HostPGs = Get-VirtualPortGroup -VMHost <<<< $VMHost | ForEach {$_.Name} | Select -Uniqu
    e
    Compare-Object : Cannot bind argument to parameter ‘ReferenceObject’ because it is null.
    At C:\iso\powershell\compare-clusters.ps1:78 char:29
    + $PGdiffs += Compare-Object <<<< $PortGroups $HostPGs -SyncWindow 1000 | ForEach {$_.Inpu
    tObject}

    • admin says:

      The first error says that Get-View did not get any arguments. So there are two possible causes:
      1) Get-View does not support input from pipeline. This is only the case for the beta release of the VI Toolkit. Make suer you use the v1.0.
      2) The $VMHosts variable is empty, which would mean filling it somehow went wrong. Try dot-sourcing the script (start powershell interactively and run “. c:\iso\compare-clusters.ps1″ (without the quotes). Then take a look ate the variable $VMHosts if it contains anything.

      Good luck,
      Hugo

  6. Daniel Hernandez says:

    Hey thanks for the great script. I also get a bunch errors similar to the one posted above. For the most part the script seems to run and produce a report its been very helpful in identifying invalid configurations.

    As for possible debugging information that may help with the errors.

    VC is 2.5 Update 3 on Win2k3 Server
    Host are mostly 3.01
    Toolkit Version is 1.0 build 113525

    Am not sure if your open to feed back to continue to improve the script or if you released it to the community and for them to have at it.

    If so here is my feedback.

    Since its a cluster audit it would be nice not to see the local disk. Since I’ve seen most environments local label vary from host to host usually something along the lines with the hostname this usually helps to ensure that nobody puts a VM on the Local host.

    Also I glance thru the script and I’m not sure are you checking for VLAN tags. Are you ? I’ve seen many issues because somebody fat fingered a VLAN tag. So a VM will move but not respond to any pings. Or even the VMotion port group wont move the VM because of the VLAN tag.

    Thanks again

    • admin says:

      Hi Daniel, thank you for taking the time to post your comment. I read every comment on my site and try to improve my scripts or help out in other ways. Keep watching my site and you might see an improved version of the script some time soon. Thanks again for your comments!
      Hugo

  7. Roderick says:

    How do I get rid of this annoying output when I run the powershell scripts?

    There were one or more problems with the server certificate:

    * A certification chain processed correctly, but terminated in a root certificat
    e which isn’t trusted by the trust provider.

    • admin says:

      You can import the certificate to get rid of the first message, but the second one will remain as your server will most likely not be called ‘vmware’. Might work to create a dns alias for it, but that’s not very nice. Maybe you can find out a way to generate a new certificate with the proper server name in it. If anybody finds a way before I do, let me know.
      Hugo

  8. Larry says:

    Thanks for lots of great scripts. Looking for VCB ones but liked what I found anyway. My script works some time but other times the snapshot times out. Wanted your clear connection script to see if that was my issue, wasn’t. Your list disks script will help also.

  9. Roderick says:

    This is probably an open door, but how do I import a certificate?

  10. Paul says:

    Hi Hugo,

    I was trying to do exactly as Daniel requested and managed to fudge something together. Would appreciate it if you would take the time to have a look and see how it could be improved as i think the method I came up with to compare VLANS works but is a little convoluted.

    let me know if you have the time or inclination to take a look and i’ll post the script.

  11. Hugo says:

    @Paul
    Hi Paul,
    Sure I’d like to check what you did. Drop me an email at: contact at peetersonline nl
    Hugo

  12. Duncan says:

    Just ran this script and it works fine but:
    - you might want to filter the local luns (vmhba0:0:0) cause they usually have a different name on every single host in a cluster
    - the script throws an error when a cluster doesn’t contain hosts

  13. Nick says:

    I was wondering if Paul had a workable solution or addition for auditing the port group VLANs. I love the script above but really need to audit the por group VLANs as well.

  14. Alan says:

    agree with Duncan, GREAT script but is there an easy way to filter out local luns?

  15. level67 says:

    Hi Guys,

    Got the same issue, its reporting my local drives as datastores and reporting a mismatch on the clusters.

    Any chance of looking into this? Great work otherwise… love it!

  16. Andy says:

    Hi Hugo,

    Great script, I was a little confused on one of my outputs because there were several vmhba devices denoted across the ESXhosts. It is simple to figure out the ones that have 1 vmhba denoted and the rest saying true or false but having more than one has confused me. Can you help to decipher this?

    LunUuid ESX001.xxx ESX002.xxx ESX003.xxx ESX005.xxx ESX011.xxx ESX020.xxx
    0200010000600508b400106b3400009000020c0000485356323130 vmhba0:4:1 vmhba0:2:1 vmhba0:4:1 vmhba0:1:1 False vmhba0:2:1
    0200020000600508b400106b3400009000020c0000485356323130 False False False False vmhba0:4:2 False
    0200020000600508b400106b340000900002110000485356323130 vmhba0:4:2 vmhba0:2:2 vmhba0:4:2 vmhba0:1:2 False vmhba0:2:2
    0200030000600508b400106b340000900002110000485356323130 False False False False vmhba0:4:3 False

    Thanks!

    Also, it would take longer but could you include a host rescan before the script starts executing so that all of the data can be current?

  17. Simon says:

    Would it be possible to exclude local disks ? Apart from
    that great script!

  18. [...] – I took the really cool looking cluster config check from the following site: http://www.peetersonline.nl/index.php/vmware/check-vmware-configuration-with-powershell/ and changed the output so it would appear in vCheck. This is a really cool looking report with [...]

  19. Dan D says:

    Thanks for the script. I took a couple of snips from the vCheck script to add send-email capability. Also made some formatting and colorization additions.

    # When displaying to the screen an output file is created. Set the format of the filename below:
    $dateFormat = “yyyy-MM-dd__HH-mm”

    # path and file name of output report
    $date = Get-Date -format $dateFormat
    $outputFile = ‘C:\vCheck_Reports\ESX-comparison_’ + $date + ‘.html’

    # Virtual Center servername
    $VCServer = “vcenter”

    # Set the SMTP Server address
    $SMTPSRV = “mail.domain.local”

    # Set the Email address to recieve from
    $EmailFrom = “user@domain.com”

    # Set the Email address to send the email to – seperate multiple with comma
    $EmailTo = “user@domain.com”

    # When displaying to the screen an output file is created. Set the format of the filename below:
    $dateFormat = “yyyyMMdd_HHmm” # use “d-M-yyyy” for legacy v5.0 format

    # Use the following item to define if an email report should be sent once completed
    $SendEmail = $true

    # Use the following item to define if the output should be displayed in the local browser once completed
    $DisplaytoScreen = $false

    function Send-SMTPmail($to, $from, $subject, $smtpserver, $body) {
    $mailer = new-object Net.Mail.SMTPclient($smtpserver)
    $msg = new-object Net.Mail.MailMessage($from,$to,$subject,$body)
    $msg.IsBodyHTML = $true
    $mailer.send($msg)
    }

    Function Create-HTMLTable
    {
    param([array]$Array)
    $arrHTML = $Array | ConvertTo-Html
    $arrHTML[-1] = $arrHTML[-1].ToString().Replace(”,””)
    Return $arrHTML[5..1000]
    }

    $output = @()
    $output += ”
    $output += ‘.sectionTitle{color:blue;font-weight:bold;}.section{margin-top:10px;margin-bottom:30px;}.errorDiv{color:red;font-weight:bold;}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 += ‘ESXi Host Inconsistency Report’
    # $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+= ”
    $output += $Cluster.Name
    $output+= ”
    $output += ‘Datastore check: ‘
    If ($myDSCol.Count -eq 0)
    {
    $output += “All datastores OK.”
    $output += ”
    }
    Else
    {
    $output += ‘ERROR: Datastore config has incontistencies! Please investigate.’
    $output += Create-HTMLTable $myDSCol
    $output += ”
    }

    $output += ‘LUN check: ‘
    If ($myLUNCol.Count -eq 0)
    {
    $output += ‘All LUNs OK.’
    $output += ”
    }
    Else
    {
    $output += ‘ERROR: LUN config has incontistencies! Please investigate.’
    $output += Create-HTMLTable $myLUNCol
    $output += ”
    }

    $output += ‘Portgroup check: ‘
    If ($myPGCol.Count -eq 0)
    {
    $output += “All portgroups OK.”
    $output += ”
    }
    Else
    {
    $output += ‘ERROR: Portgroup config has incontistencies! Please investigate.’
    $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
    if ($DisplayToScreen) {
    Write-Host “..Displaying HTML results”
    Invoke-Item $Filename
    }

    Disconnect-VIServer -Confirm:$False

    if ($SendEmail) {
    Write-Host “..Emailing HTML results”
    send-SMTPmail $EmailTo $EmailFrom “$VCServer ESXi host comparison check” $SMTPSRV $output
    }

  20. JohnP says:

    newbie here….been trying to filter out local datastores, but no luck. anyone have any pointers or solutions?

  21. Gopi kiran says:

    tried it on the powercli 5.1 not able to generate the report, could you please guide on this..

Leave a Reply