PowerCLI script to count paths to VMFS volumes

PowerCLI script to count paths to VMFS volumes

When implementing new storages or configure existing ones it is a good idea to check paths (state and amount) to volumes. When operating a few hosts using a few datastores this can be a very time-consuming task when using the GUI. Therefore I wrote the following function.


function Get-VMFSPathCount ($DatastorePattern='', $ClusterPattern='', $VMHostPattern='', [Switch]$TextOutput=$false, [int]$ShouldCount=-1)  {

    #
    # .NOTES
    # ===========================================================================
    # Blog:           vnote42.net
    # Twitter:        @vnote42
    # Version:        1.0
    # ===========================================================================
    # .SYNOPSIS
    #     Function counts paths of VMFS-LUNs. 

    # .DESCRIPTION
    #     Function can be used get current state of paths for reporting or further processing.
    #     You can use a color-coded text-report or table/list-output. For selecting volumes,
    #     pattern of VMFS datastore names can be used. Furthermore, you can list just volumes,
    #     path count does not meet your expectation.

    # .PARAMETER DatastorePattern
    #     With this parameter, you can select for which VMFS Volumes to count paths.
    #     No input, means to take any Volume into account.
    #     When using the exact name, just this Volume is analyzed.
    #     All other inputs are takes as part of datastore name. 

    # .PARAMETER ClusterPattern
    #     Just hosts of selected clusters are analyzed.
    #     No input, means to take all hosts (in any or no cluster) into account.
    #     When using the exact name, just hosts of this cluster are analyzed.
    #     All other inputs are takes as part of cluster name. 

    # .PARAMETER VMHostPattern
    #     Just selected hosts are analyzed.
    #     No input, to not filter any hosts.
    #     When using the exact name, just this host is analyzed.
    #     All other inputs are takes as part of host name. 

    # .PARAMETER TextOutput
    #     When set to $false (default), output is an array
    #     When set to $true, output is text-based and color-coded. Can be used, for reporting.

    # .PARAMETER ShouldCount
    #     You can define the amount of paths that should exists (active+standby+dead).
    #     No input means every volume is analyzed.
    #     When there are dead paths to a volume, this volume is always in output.

    # .OUTPUTS
    #     Depending on parameter TextOutput, output is an array or text.

    # .EXAMPLE
    #     Get-VMFSPathCount
    #     Count paths for all VMFS-volume for all hosts for connected VIserver (vCenter or single host)

    # .EXAMPLE
    #     Get-VMFSPathCount -DatastorePattern 3par
    #     Count paths for all VMFS-volume, containing string "3par"

    # .EXAMPLE
    #     Get-VMFSPathCount -DatastorePattern 3par | Format-Table -AutoSize
    #     To show table instead of list, use:

    # .EXAMPLE
    #     Get-VMFSPathCount -DatastorePattern 3par -TextOutput:$true
    #     Report output as text

    # .EXAMPLE
    #     Get-VMFSPathCount -DatastorePattern 3par -ShouldCount 2 | Format-Table -AutoSize
    #     Analyse all volumes, containing string "3par" and count of all paths is not 2

    #

    $Result = @()
    $VmfsDatastores = @{}
    $QueryClusterList = Get-Cluster ("*"+$ClusterPattern+"*")
    ForEach ($DS in (Get-Datastore ("*"+$DatastorePattern+"*") | Where-Object {$_.Type -eq "vmfs"})){
        $DS.Extensiondata.Info.Vmfs.Extent | ForEach-Object {
            $VmfsDatastores[$_.DiskName] = $DS.Name
        }
    }
    if ($VmfsDatastores.Count -eq 0) {break}

    ForEach ($VmHost in (Get-VMHost ("*"+$VMHostPattern+"*") | Where-Object {$_.ConnectionState -eq "Connected" -or $_.ConnectionState -eq "Maintenance"})) {
        $Cluster = Get-Cluster -VMHost $VmHost.Name
        if ($ClusterPattern -ne '' -and $Cluster.Name -notin $QueryClusterList.Name) {continue}

        $Luns = $VmHost | Get-ScsiLun | Where-Object {$_.IsLocal -ne "true" -and $_.CanonicalName -in $VmfsDatastores.Keys}

        if ($TextOutput) {Write-Host $VmHost.name}

        ForEach ($Lun in $Luns) {
            $CountTab = $Lun | Get-ScsiLunPath
            $CountAll = $CountTab.Count
            $CountActive = ($CountTab | Where-Object {$_.state -eq "Active"}).count
            $CountStandby = ($CountTab | Where-Object {$_.state -eq "Standby"}).count
            $CountDead = ($CountTab | Where-Object {$_.state -eq "Dead"}).count

            $VmfsName = $Lun.CanonicalName
            if($VmfsDatastores.ContainsKey($Lun.CanonicalName)){
                $Vmfsname = $VmfsDatastores[$Lun.CanonicalName]
            }

            if ($ShouldCount -ne $CountActive -or $CountDead -gt 0) {
                if ($TextOutput) {
                    Write-Host "`t" $VmfsName -NoNewline
                    Write-Host -ForegroundColor Green "`t" "Active:" $CountActive -NoNewline
                    if ($CountDead -ne 0) {Write-Host -ForegroundColor Red "`t" "Dead:" $CountDead} else {Write-Host}
                } else {
                    $NewEntry = [PScustomObject] @{
                        Cluster = $Cluster.Name
                        VMhost = $VmHost.Name
                        Datastore = $Vmfsname
                        AllPathCount = $CountAll
                        ActivePathCount = $CountActive
                        StandbyPathCount = $CountStandby
                        DeadPathCount = $CountDead
                        MultipathPolicy = $lun.MultipathPolicy
                    }
                    $Result += $NewEntry
                }
            }
        }
    }
    if (!$TextOutput) {$Result | Sort-Object Cluster, VMhost, Datastore}
}

Input

Before running the function, a connection to a vCenter or single host has to be established. Depending on entered parameters the function uses hosts of this connection to count paths to VMFS volumes. You can restrict to analyze specific clusters, hosts or volumes. These parameters can be used to enter a exact name or a part of the name. For example ClusterPattern “Cluster” would select “Cluster1” and “Cluster2”. Furthermore you can enter an expected path-count, when this is not met, volume will be in output. Selected Volumes with dead paths are always in output.

Output

You have the option to got output as table or text-based. Text-based can be used for reporting purpose. Table is useful for documentation and further processing. In Table you get counter for active, standby and dead paths. Because most often multipath policy is also a very interesting property, it is also in table.

[Update 1.4.2020]

  • Selection of hosts line 81 includes now ConnectionState, so disconnected hosts will not cause delays when running the script.
  • Thanks to @RFrankemolle who found a typo, correct output columne name is MultipathPolicy now.

Notes

  • Needed module is VMware.VimAutomation.Core.
  • If you want to get Get-Help functionality to work for this function, replace per-line comment to block-comment (<# … #>) from .NOTES to last .EXAMPLE. This notation did not work in wordpress-plugin.
  • Possible VIservers: vCenter and single ESXi host.
  • Host and cluster selection takes single hosts, host in clusters and hosts not in clusters into account.
  • When a datastore is within selection, it is always in output when any path is dead.
  • In text-based output there are no cluster names.
  • Because of cmdlet Get-ScsiLun function needs some time to complete.
  • If you see dead paths, you can check for Permanent Device Loss (PDL) state

Feel free, to post bugs or ideas for improvements.

Leave a Reply

Your email address will not be published. Required fields are marked *