CLI/PerformanceManagement.psm1

####################################################################################
## © 2020,2021 Hewlett Packard Enterprise Development LP
##
## Permission is hereby granted, free of charge, to any person obtaining a
## copy of this software and associated documentation files (the "Software"),
## to deal in the Software without restriction, including without limitation
## the rights to use, copy, modify, merge, publish, distribute, sublicense,
## and/or sell copies of the Software, and to permit persons to whom the
## Software is furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included
## in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
## OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
## ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
## OTHER DEALINGS IN THE SOFTWARE.
##
## File Name: PerformanceManagement.psm1
## Description: Performance Management cmdlets
##
## Created: October 2019
## Last Modified: October 2019
## History: v3.0 - Created
#####################################################################################

$Info = "INFO:"
$Debug = "DEBUG:"
$global:VSLibraries = Split-Path $MyInvocation.MyCommand.Path
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

############################################################################################################################################
## FUNCTION Test-CLIObject
############################################################################################################################################
Function Test-CLIObject 
{
Param(     
    [string]$ObjectType, 
    [string]$ObjectName ,
    [string]$ObjectMsg = $ObjectType, 
    $SANConnection = $global:SANConnection
    )

    $IsObjectExisted = $True
    $ObjCmd = $ObjectType -replace ' ', '' 
    $Cmds = "show$ObjCmd $ObjectName"
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmds
    if ($Result -like "no $ObjectMsg listed")
    {
        $IsObjectExisted = $false
    }
    return $IsObjectExisted
    
} # End FUNCTION Test-CLIObject

######################################################################################################################
## FUNCTION Compress-VV
######################################################################################################################
Function Compress-VV
{
<#
  .SYNOPSIS
    The Compress-VV command is used to change the properties of a virtual volume that
    was created with the createvv command by associating it with a different CPG.
    
  .DESCRIPTION
    The Compress-VV command is used to change the properties of a virtual volume that
    was created with the createvv command by associating it with a different CPG.
    
  .EXAMPLE
    Compress-VV -SUBCommand usr_cpg -CPGName XYZ
        
  .EXAMPLE
    Compress-VV -SUBCommand usr_cpg -CPGName XYZ -VVName XYZ
    
  .EXAMPLE
    Compress-VV -SUBCommand usr_cpg -CPGName XYZ -Option XYZ -VVName XYZ
    
  .EXAMPLE
    Compress-VV -SUBCommand usr_cpg -CPGName XYZ -Option keepvv -KeepVVName XYZ -VVName XYZ
        
  .EXAMPLE
    Compress-VV -SUBCommand snp_cpg -CPGName XYZ -VVName XYZ
    
  .PARAMETER SUBCommand
    usr_cpg <cpg>
        Moves the logical disks being used for user space to the specified CPG.
        
    snp_cpg <cpg>
        Moves the logical disks being used for snapshot space to the specified
        CPG.
        
    restart
        Restarts a tunevv command call that was previously interrupted because
        of component failure, or because of user initiated cancellation. This
        cannot be used on TPVVs or TDVVs.
        
    rollback
        Returns to a previously issued tunevv operation call that was
        interrupted. The canceltask command needs to run before the rollback.
        This cannot be used on TPVVs or TDVVs.
    
  .PARAMETER CPGName
    Indicates that only regions of the VV which are part of the the specified
    CPG should be tuned to the destination USR or SNP CPG.
    
  .PARAMETER VVName
     Specifies the name of the existing virtual volume.

  .PARAMETER WaitTask
    Specifies that the command will wait for any created tasks to
    complete.

  .PARAMETER DryRun
    Specifies that the command is a dry run and that no logical disks or
    virtual volumes are actually tuned. Cannot be used with the -tpvv,
    -dedup, -full, or -compr options.

  .PARAMETER Count
    Specifies the number of identical virtual volumes to tune using an
    integer from 1 through 999. If not specified, one virtual volume
    is tuned. If the '-cnt' option is specified, then the subcommands,
    "restart" and "rollback" are not permitted.

  .PARAMETER TPVV
    Indicates that the VV should be converted to a thin provision virtual
    volume. Cannot be used with the -dedup or -full options.

  .PARAMETER TDVV
    This option is deprecated, see -dedup.

  .PARAMETER DeDup
    Indicates that the VV should be converted to a thin provision virtual
    volume that shares logical disk space with other instances of this
    volume type. Cannot be used with the -tpvv or -full options.

  .PARAMETER Full
    Indicates that the VV should be converted to a fully provisioned virtual
    volume. Cannot be used with the -tpvv, -dedup, or -compr options.

  .PARAMETER Compr
    Indicates that the VV should be converted to a compressed virtual
    volume. Cannot be used with the -full option.

  .PARAMETER KeepVV
    Indicates that the original logical disks should be saved under a new
    virtual volume with the given name. Can only be used with the -tpvv,
    -dedup, -full, or -compr options.

  .PARAMETER Src_Cpg
    Indicates that only regions of the VV which are part of the the specified
    CPG should be tuned to the destination USR or SNP CPG. This option is
    recommended when a VV belongs to an AO configuration and will avoid
    disrupting any optimizations already performed.

  .PARAMETER Threshold
    Slice threshold. Volumes above this size will be tuned in slices.
    <threshold> must be in multiples of 128GiB. Minimum is 128GiB.
    Default is 16TiB. Maximum is 16TiB.

  .PARAMETER SliceSize
    Slice size. Size of slice to use when volume size is greater than
    <threshold>. <size> must be in multiples of 128GiB. Minimum is 128GiB.
     Default is 2TiB. Maximum is 16TiB.
    
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Compress-VV
    LASTEDIT: November 2019
    KEYWORDS: Compress-VV
   
    .Link
        http://www.hpe.com
 
 #Requires PS -Version 3.0
 #>

[CmdletBinding()]
    param(    
        [Parameter(Position=0, Mandatory=$true)]
        [System.String]
        $SUBCommand ,
        
        [Parameter(Position=1, Mandatory=$true)]
        [System.String]
        $VVName ,
        
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $CPGName ,    
        
        [Parameter(Position=3, Mandatory=$false)]
        [switch]
        $WaitTask ,        
        
        [Parameter(Position=4, Mandatory=$false)]
        [switch]
        $DryRun ,        
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $Count ,
        
        [Parameter(Position=6, Mandatory=$false)]
        [switch]
        $TPVV ,
        
        [Parameter(Position=7, Mandatory=$false)]
        [switch]
        $TDVV ,
        
        [Parameter(Position=8, Mandatory=$false)]
        [switch]
        $DeDup ,
        
        [Parameter(Position=9, Mandatory=$false)]
        [switch]
        $Full ,
        
        [Parameter(Position=10, Mandatory=$false)]
        [switch]
        $Compr ,
        
        [Parameter(Position=11, Mandatory=$false)]
        [System.String]
        $KeepVV ,        
        
        [Parameter(Position=13, Mandatory=$false)]
        [System.String]
        $Threshold , 
        
        [Parameter(Position=14, Mandatory=$false)]
        [System.String]
        $SliceSize , 
        
        [Parameter(Position=15, Mandatory=$false)]
        [System.String]
        $Src_Cpg ,
                
        [Parameter(Position=16, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )        
    
    Write-DebugLog "Start: In Compress-VV - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {        
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Compress-VV since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Compress-VV since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli -SANConnection $SANConnection
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }
    
    $Cmd = " tunevv "
    
    if($SUBCommand)
    {
        $test="usr_cpg","snp_cpg","restart","rollback"
        $SbCmd = $SUBCommand.toLower()
        if ($test -eq $SbCmd)
        {
            $Cmd += " $SUBCommand"            
        }
        else
        {
            return "SubCommand Should be [usr_cpg | snp_cpg | restart | rollback]"
        }
        if($SUBCommand -eq "usr_cpg" -Or $SUBCommand -eq "snp_cpg")
        {
            if($CPGName)
            {
                $Cmd += " $CPGName"
            }
            else
            {
                return "SubCommand : $SUBCommand,Must Require CPG Name."
            }
        }
    }
    $Cmd += " -f "
    
    if($WaitTask)
    {
        $Cmd += " -waittask "
    }
    if($DryRun)
    {
        $Cmd += " -dr "
    }
    if($Count)
    {
        $Cmd += " -cnt $Count"
    }
    if($TPVV)
    {
        $Cmd += " -tpvv "
    }
    if($TDVV)
    {
        $Cmd += " -tdvv "
    }
    if($DeDup)
    {
        $Cmd += " -dedup "
    }
    if($Full)
    {
        $Cmd += " -full "
    }
    if($Compr)
    {
        $Cmd += " -compr "
    }
    if($KeepVV)
    {
        $Cmd += " -keepvv $KeepVV"
    }
    if($Src_Cpg)
    {
        $Cmd += " -src_cpg $Src_Cpg"
    }
    if($Threshold)
    {
        $Cmd += " -slth $Threshold"
    }
    if($SliceSize)
    {
        $Cmd += " -slsz $SliceSize"
    }
    if($VVName)
    {                    
        $Cmd += " $VVName"            
    }
    
    #write-host "Command = $Cmd"
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
    write-debuglog " Executing Compress-VV for tuning virtual volume.--> " "INFO:" 
    return  $Result

} ## End-of Compress-VV

####################################################################################################################
## FUNCTION Get-HistChunklet
#####################################################################################################################

Function Get-HistChunklet  
{
<#
  .SYNOPSIS
    The Get-HistChunklet command displays a histogram of service times in a timed loop for individual chunklets
  
  .DESCRIPTION
    The Get-HistChunklet command displays a histogram of service times in a timed loop for individual chunklets
        
  .EXAMPLE
  
    Get-HistChunklet -Iteration 1
    This example displays one iteration of a histogram of service
        
  .EXAMPLE
    Get-HistChunklet –LDname dildil -Iteration 1
    identified by name, from which chunklet statistics are sampled.
    
  .EXAMPLE
    Get-HistChunklet -Iteration 1 -Previous

  .PARAMETER Chunklet_num
    Specifies that statistics are limited to only the specified chunklet, identified
    by number.

  .PARAMETER Metric both|time|size
    Selects which metric to display. Metrics can be one of the following:
        both - (Default)Display both I/O time and I/O size histograms
        time - Display only the I/O time histogram
        size - Display only the I/O size histogram

  .PARAMETER Percentage
    Shows the access count in each bucket as a percentage. If this option is
    not specified, the histogram shows the access counts.

  .PARAMETER Previous
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
        
  .PARAMETER Beginning
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.

  .PARAMETER RW
    Specifies that the display includes separate read and write data. If not
    specified, the total is displayed.

  .PARAMETER Interval
    Specifies the interval in seconds that statistics are sampled from
    using an integer from 1 through 2147483. If no count is specified, the
    command defaults to 2 seconds.

  .PARAMETER Iteration
    Specifies that the histogram is to stop after the indicated number of
    iterations using an integer from 1 through 2147483647.
        
  .PARAMETER NI
    Specifies that histograms for only non-idle devices are displayed. This
    option is shorthand for the option -filt t,0,0.

  .PARAMETER LDname
    Specifies the Logical Disk (LD), identified by name, from which chunklet statistics are sampled.
 
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-HistChunklet
    LASTEDIT: November 2019
    KEYWORDS: Get-HistChunklet
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(    
        [Parameter(Position=0, Mandatory=$false, ValueFromPipeline=$true)]
        [System.String]
        $LDname,
        
        [Parameter(Position=1, Mandatory=$false, ValueFromPipeline=$true)]
        [System.String]
        $Chunklet_num,
        
        [Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true)]
        [System.String]
        $Metric,
        
        [Parameter(Position=3, Mandatory=$false, ValueFromPipeline=$true)]
        [System.String]
        $Iteration,
        
        [Parameter(Position=4, Mandatory=$false)]
        [switch]
        $Percentage,
        
        [Parameter(Position=5, Mandatory=$false)]
        [switch]
        $Previous,
        
        [Parameter(Position=6, Mandatory=$false)]
        [switch]
        $Beginning,
        
        [Parameter(Position=7, Mandatory=$false)]
        [switch]
        $RW,
        
        [Parameter(Position=8, Mandatory=$false)]
        [System.String]
        $Interval,
        
        [Parameter(Position=9, Mandatory=$false)]
        [switch]
        $NI,
            
        [Parameter(Position=10, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )        
    
    Write-DebugLog "Start: In Get-HistChunklet - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {        
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        { 
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-HistChunklet since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-HistChunklet since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli 
    
    if($plinkresult -match "FAILURE :")    
    {
        Write-DebugLog "$plinkresult" "ERR:" 
        return $plinkresult
    }
    
    $histchCMD = "histch"
    
    if($Iteration )
    {
        $histchCMD+=" -iter $iteration"
    }
    else
    {
        return "Iteration is mandatory..."
    }
    if($LDname)
    {
        $histchCMD +=" -ld $LDname "
    }
    if($Chunklet_num)
    {
        $histchCMD +=" -ch $Chunklet_num "
    } 
    if($Metric)
    {
        $histchCMD +=" -metric $Metric "
    }
    if($Percentage)
    {
        $histchCMD +=" -pct "
    }
    if($Previous)
    {
        $histchCMD +=" -prev "
    }
    if($Beginning)
    {
        $histchCMD +=" -begin "
    }
    if($RW)
    {
        $histchCMD +=" -rw "
    }
    if($Interval)
    {
        $histchCMD +=" -d $Interval "
    }
    if($NI)
    {
        $histchCMD +=" -ni "
    }    
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $histchCMD
    
    $range1 = $Result.count
    
    if($range1 -le "5")
    {
        return "No data available Please try with valid input."
    }
    Write-DebugLog " displays a histogram of service -->$histchCMD "INFO:"" 
    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        
        $LastItem = $Result.Count        
        if($RW)
        {
            $LastItem = $LastItem - 4            
        }        
        Add-Content -Path $tempFile -Value 'Ldid,Ldname,logical_Disk_CH,Pdid,PdCh,0.5,1.0,2.0,4.0,8.0,16,32,64,128,256,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date'
        foreach ($s in  $Result[0..$LastItem] )
        {
            if ($s -match "millisec")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $split1=$s.split(",")
                $global:time1 = $split1[0]
                $global:date1 = $split1[1]
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "Ldname"))
            {
                continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +"," ")
            $s= [regex]::Replace($s," +",",")            # Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "20")
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }    
}
#END Get-HistChunklet

####################################################################################################################
## FUNCTION Get-HistLD
####################################################################################################################
Function Get-HistLD
{
<#
  .SYNOPSIS
    The Get-HistLD command displays a histogram of service times for Logical Disks (LDs) in a timed loop.
  
  .DESCRIPTION
    The Get-HistLD command displays a histogram of service times for Logical Disks (LDs) in a timed loop.
        
  .EXAMPLE
    Get-HistLD -Iteration 1
    displays a histogram of service Iteration number of times
    
     
  .EXAMPLE
    Get-HistLD -LdName abcd -Iteration 1
    displays a histogram of service linked with LD_NAME on Iteration number of times
    
  .EXAMPLE
    Get-HistLD -Iteration 1 -VV_Name ZXZX
    Shows only logical disks that are mapped to virtual volumes with names
    matching any of the names or patterns specified.
    
  .EXAMPLE
    Get-HistLD -Iteration 1 -Domain ZXZX
    Shows only logical disks that are in domains with names matching any
    of the names or patterns specified.
    
  .EXAMPLE
    Get-HistLD -Iteration 1 -Percentage
    Shows the access count in each bucket as a percentage.

  .PARAMETER Timecols
    For the I/O time histogram, shows the columns from the first column
    <fcol> through last column <lcol>. The available columns range from 0
    through 31.

    The first column (<fcol>) must be a value greater than or equal to 0,
    but less than the value of the last column (<lcol>).

    The last column (<lcol>) must be less than or equal to 31.

    The first column includes all data accumulated for columns less than the
    first column and the last column includes accumulated data for all
    columns greater than the last column.

    The default value of <fcol> is 6.
    The default value of <lcol> is 15.

  .PARAMETER Sizecols
    For the I/O size histogram, shows the columns from the first column
    (<fcol>) through the last column (<lcol>). Available columns range from
    0 through 15.

    The first column (<fcol>) must be a value greater than or equal to 0,
    but less than the value of the last column (<lcol>) (default value of 3).
    The last column (<lcol>) must be less than or equal to 15 (default value
    of 11).

    The default value of <fcol> is 3.
    The default value of <lcol> is 11.

  .PARAMETER Percentage
    Shows the access count in each bucket as a percentage. If this option is
    not specified, the histogram shows the access counts.

  .PARAMETER Secs
    Specifies the interval in seconds that statistics are sampled from
    using an integer from 1 through 2147483. If no count is specified, the
    command defaults to 2 seconds.

  .PARAMETER NI
    Specifies that histograms for only non-idle devices are displayed. This
    option is shorthand for the option -filt t,0,0.
    
  .PARAMETER Iteration
    displays a histogram of service Iteration number of times
  
  .PARAMETER LdName
    displays a histogram of service linked with LD_NAME
    
  .PARAMETER VV_Name
    Shows only logical disks that are mapped to virtual volumes with names
    matching any of the names or patterns specified. Multiple volumes or
    patterns can be repeated using a comma separated list.

  .PARAMETER Domain
    Shows only logical disks that are in domains with names matching any
    of the names or patterns specified. Multiple domain names or patterns
    can be repeated using a comma separated list.

  .PARAMETER Metric
    Selects which metric to display. Metrics can be one of the following:
    both - (Default)Display both I/O time and I/O size histograms
    time - Display only the I/O time histogram
    size - Display only the I/O size histogram

  .PARAMETER Previous
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
        
  .PARAMETER Beginning
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-HistLD
    LASTEDIT: November 2019
    KEYWORDS: Get-HistLD
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(    
        [Parameter(Position=0, Mandatory=$false)]
        [System.String]
        $Iteration,    

        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $Metric,

        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $VV_Name,
        
        [Parameter(Position=3, Mandatory=$false)]
        [System.String]
        $Domain,
                
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $Timecols,
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $Sizecols, 
        
        [Parameter(Position=6, Mandatory=$false)]
        [Switch]
        $Percentage,
        
        [Parameter(Position=7, Mandatory=$false)]
        [Switch]
        $Previous,
        
        [Parameter(Position=8, Mandatory=$false)]
        [Switch]
        $Beginning,
        
        [Parameter(Position=9, Mandatory=$false)]
        [Switch]
        $NI,
        
        [Parameter(Position=10, Mandatory=$false)]
        [System.String]
        $Secs,
                
        [Parameter(Position=11, Mandatory=$false)]
        [System.String]
        $LdName,
        
        [Parameter(Position=12, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )        
    
    Write-DebugLog "Start: In Get-HistLD - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {        
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-HistLD since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-HistLD since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }
    $histldCmd = "histld "
    if ($Iteration)
    {
        $histldCmd += " -iter $Iteration "
    }
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "        
    }
    if ($Metric)
    {
        $a = "both","time","size"
        $l=$Metric
        if($a -eq $l)
        {
            $histldCmd+=" -metric $Metric "                        
        }
        else
        {             
            Return "FAILURE : -Metric $Metric is an Invalid Value Please used only [ both|time|size ]. "
        }
    }
    if($VV_Name)
    {
        $cmd= "showvv "
        $demo = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
        if($demo -match $VV_Name )
        {
            $histldCmd+=" -vv $VV_Name"
        }
        else
        { 
            return  "FAILURE : No Virtual Volume : $VV_Name found, Please try with valid input."
        }        
    } 
    if($Domain)
    {        
        $cmd= "showdomain "
        $demo = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
        if($demo -match $Domain )
        {
            $histldCmd+=" -domain $Domain"
        }
        else
        { 
            return  "FAILURE : No Domain : $Domain found, Please try with valid input."
        }
    }    
    if($Timecols)
    {
        $histldCmd+=" -timecols $Timecols"
    }
    if($Sizecols)
    {
        $histldCmd+=" -sizecols $Sizecols"
    }    
    if ($Percentage)
    {
        $histldCmd += " -pct "
    }
    if ($Previous)
    {
        $histldCmd += " -prev "
    }    
    if ($Beginning)
    {
        $histldCmd += " -begin "
    }
    if($Secs)
    {
        $histldCmd+=" -d $Secs"
    }
    if ($NI)
    {
        $histldCmd += " -ni "
    }
    if ($LdName)
    {
        #check wether ld is available or not
        $cmd= "showld "
        $demo = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
        if($demo -match $LdName )
        {
            $histldCmd += " $LdName"
        }
        else
        { 
            return  "FAILURE : No LD_name $LdName found "
        }
    }
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $histldCmd
    write-debuglog " The Get-HistLD command displays a histogram of service times for Logical Disks (LDs) in a timed loop.->$cmd" "INFO:"    
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -lt "5")
    {
        write-host ""
        return "No data available Please Try With Valid Data. `n"
    }    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count
        if ($Metric -eq "time")
        {
            Add-Content -Path $tempFile -Value  'Logical_Disk_Name,0.50,1,2,4,8,16,32,64,128,256,time,date'
        }
        if ($Metric -eq "size")
        {
            Add-Content -Path $tempFile -Value  'Logical_Disk_Name,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date' 
        }
        else
        {
            Add-Content -Path $tempFile -Value  'Logical_Disk_Name,0.50,1,2,4,8,16,32,64,128,256,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date' 
        }
        foreach ($s in  $Result[0..$LastItem] )
        {            
            if ($s -match "millisec")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $split1=$s.split(",")
                $global:time1 = $split1[0]
                $global:date1 = $split1[1]
                continue
            }
            if (($s -match "-------") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "Ldname"))
            {
                #write-host " s equal-1 $s"
                continue
            }
            #write-host "s = $s"
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +"," ")
            $s= [regex]::Replace($s," +",",")            # Replace one or more spaces with comma to build CSV line
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
            #write-host "s final $s"
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-HistLD

####################################################################################################################
## FUNCTION Get-HistPD
###################################################################################################################
Function Get-HistPD
{
<#
  .SYNOPSIS
    The Get-HistPD command displays a histogram of service times for Physical Disks (PDs).
  
  .DESCRIPTION
    The Get-HistPD command displays a histogram of service times for Physical Disks (PDs).
       
  .EXAMPLE
    Get-HistPD -iteration 1 -WWN abcd
    Specifies the world wide name of the PD for which service times are displayed.
     
  .EXAMPLE
    Get-HistPD -iteration 1
    The Get-HistPD displays a histogram of service iteration number of times
    Histogram displays data from when the system was last started (–begin).
    
  .EXAMPLE
    Get-HistPD -iteration 1 -Devinfo
    Indicates the device disk type and speed.
    
  .EXAMPLE
    Get-HistPD -iteration 1 -Metric both
    (Default)Display both I/O time and I/O size histograms

  .PARAMETER WWN
    Specifies the world wide name of the PD for which service times are displayed.

  .PARAMETER Nodes
    Specifies that the display is limited to specified nodes and physical
    disks connected to those nodes. The node list is specified as a series
    of integers separated by commas (e.g. 1,2,3). The list can also consist
    of a single integer. If the node list is not specified, all disks on all
    nodes are displayed.

  .PARAMETER Slots
    Specifies that the display is limited to specified PCI slots and
    physical disks connected to those PCI slots. The slot list is specified
    as a series of integers separated by commas (e.g. 1,2,3). The list can
    also consist of a single integer. If the slot list is not specified, all
    disks on all slots are displayed.

  .PARAMETER Ports
    Specifies that the display is limited to specified ports and
    physical disks connected to those ports. The port list is specified
    as a series of integers separated by commas (e.g. 1,2,3). The list can
    also consist of a single integer. If the port list is not specified, all
    disks on all ports are displayed.
        
  .PARAMETER Percentage
    Shows the access count in each bucket as a percentage. If this option is
    not specified, the histogram shows the access counts.

  .PARAMETER Previous
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
    
  .PARAMETER Beginning
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.

  .PARAMETER Devinfo
    Indicates the device disk type and speed.

  .PARAMETER Metric both|time|size
    Selects which metric to display. Metrics can be one of the following:
        both - (Default)Display both I/O time and I/O size histograms
        time - Display only the I/O time histogram
        size - Display only the I/O size histogram
        
  .PARAMETER Iteration
    Specifies that the histogram is to stop after the indicated number of iterations using an integer from 1 up-to 2147483647.
  
  .PARAMETER FSpec
    Specifies that histograms below the threshold specified by the <fspec>
    argument are not displayed. The <fspec> argument is specified in the
    syntax of <op>,<val_ms>, <count>.
    <op>
        The <op> argument can be specified as one of the following:
            r - Specifies read statistics.
            w - Specifies write statistics.
            t - Specifies total statistics.
            rw - Specifies total read and write statistics.
    <val_ms>
        Specifies the threshold service time in milliseconds.
    <count>
    Specifies the minimum number of access above the threshold service
    time. When filtering is done, the <count> is compared with the sum
    of all columns starting with the one which corresponds to the
    threshold service time. For example, -t,8,100 means to only display
    the rows where the 8ms column and all columns to the right adds
    up to more than 100.
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-HistPD
    LASTEDIT: November 2019
    KEYWORDS: Get-HistPD
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [System.String]
        $Iteration,
        
        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $WWN,
        
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $Nodes,
        
        [Parameter(Position=3, Mandatory=$false)]
        [System.String]
        $Slots,
        
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $Ports,
        
        [Parameter(Position=5, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Devinfo,
        
        [Parameter(Position=6, Mandatory=$false)]
        [System.String]
        $Metric,
        
        [Parameter(Position=7, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Percentage,
        
        [Parameter(Position=8, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Previous,
        
        [Parameter(Position=9, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Beginning,    
            
        [Parameter(Position=10, Mandatory=$false)]
        [System.String]
        $FSpec,
        
        [Parameter(Position=11, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )        
    
    Write-DebugLog "Start: In Get-HistPD - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {        
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-HistPD since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-HistPD since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }
    $Cmd = "histpd "
    if($Iteration)
    {
        $Cmd += "-iter $Iteration"    
    }
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }    
        
    if ($WWN)
    {
        $Cmd += " -w $WWN"
    }
    if ($Nodes)
    {
        $Cmd += " -nodes $Nodes"
    }
    if ($Slots)
    {
        $Cmd += " -slots $Slots"
    }
    if ($Ports)
    {
        $Cmd += " -ports $Ports"
    }
    if ($Devinfo)
    {
        $Cmd += " -devinfo "
    }
    if($Metric)
    {
        $Met = $Metric
        $c = "both","time","size"
        $Metric = $metric.toLower()
        if($c -eq $Met)
        {
            $Cmd += " -metric $Metric "
        }
        else
        {
            return "FAILURE: -Metric $Metric is Invalid. Use only [ both | time | size ]."
        }
    }
    if ($Previous)
    {
        $Cmd += " -prev "
    }
    if ($Beginning)
    {
        $Cmd += " -begin "
    }
    if ($Percentage)
    {
        $Cmd += " -pct "
    }    
    if ($FSpec)
    {
        $Cmd += " -filt $FSpec"
    }
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd 
    write-debuglog " The Get-HistPD command displays a histogram of service times for Physical Disks (PDs). " "INFO:" 
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -lt "5")
    {
        return "No data available"
    }        
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()

        $LastItem = $Result.Count
        
        if("time" -eq $Metric.trim().tolower())
        {
            #write-host " in time"
            Add-Content -Path $tempFile -Value 'ID,Port,0.50,1,2,4,8,16,32,64,128,256,time,date'
            $LastItem = $Result.Count - 3
        }
        elseif("size" -eq $Metric.trim().tolower())
        {
            #write-host " in size"
            Add-Content -Path $tempFile -Value 'ID,Port,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date'    
            $LastItem = $Result.Count - 3
        }
        elseif ($Devinfo)
        {    
            Add-Content -Path $tempFile -Value  'ID,Port,Type,K_RPM,0.50,1,2,4,8,16,32,64,128,256,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date'
        }
        else
        {
            Add-Content -Path $tempFile -Value  'ID,Port,0.50,1,2,4,8,16,32,64,128,256,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date'            
        }
        foreach ($s in  $Result[0..$LastItem] )
        {
            if ($s -match "millisec")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $split1=$s.split(",")
                $global:time1 = $split1[0]
                $global:date1 = $split1[1]
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "ID"))
            {
                continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s,"-+","-")
            $s= [regex]::Replace($s," +",",")            # Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "20") 
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-HistPD

####################################################################################################################
## FUNCTION Get-HistPort
####################################################################################################################
Function Get-HistPort
{
<#
  .SYNOPSIS
    The Get-HistPort command displays a histogram of service times for ports within the system.
  
  .DESCRIPTION
   The Get-HistPort command displays a histogram of service times for ports within the system.
      
  .EXAMPLE
    Get-HistPort -iteration 1
    displays a histogram of service times with option it can be one of these [both|ctrl|data].
     
  .EXAMPLE
    Get-HistPort -iteration 1 -Both
    Specifies that both control and data transfers are displayed(-both)
    
  .EXAMPLE
    Get-HistPort -iteration 1 -Nodes nodesxyz
    Specifies that the display is limited to specified nodes and physical disks connected to those nodes.
    
  .EXAMPLE
    Get-HistPort –Metric both -iteration 1
    displays a histogram of service times with -metric option. metric can be one of these –metric [both|time|size]
    
  .PARAMETER Both
    Specifies that both control and data transfers are displayed(-both),
    only control transfers are displayed (-ctl), or only data transfers are
    displayed (-data). If this option is not specified, only data transfers
    are displayed.

  .PARAMETER CTL
    Specifies that both control and data transfers are displayed(-both),
    only control transfers are displayed (-ctl), or only data transfers are
    displayed (-data). If this option is not specified, only data transfers
    are displayed.
        
  .PARAMETER Data
    Specifies that both control and data transfers are displayed(-both),
    only control transfers are displayed (-ctl), or only data transfers are
    displayed (-data). If this option is not specified, only data transfers
    are displayed.
        
  .PARAMETER Nodes
    Specifies that the display is limited to specified nodes and physical
    disks connected to those nodes. The node list is specified as a series
    of integers separated by commas (e.g. 1,2,3). The list can also consist
    of a single integer. If the node list is not specified, all disks on all
    nodes are displayed.

  .PARAMETER Slots
    Specifies that the display is limited to specified PCI slots and
    physical disks connected to those PCI slots. The slot list is specified
    as a series of integers separated by commas (e.g. 1,2,3). The list can
    also consist of a single integer. If the slot list is not specified, all
    disks on all slots are displayed.

  .PARAMETER Ports
    Specifies that the display is limited to specified ports and
    physical disks connected to those ports. The port list is specified
    as a series of integers separated by commas (e.g. 1,2,3). The list can
    also consist of a single integer. If the port list is not specified, all
    disks on all ports are displayed.
    
  .PARAMETER Host
    Specifies to display only host ports (target ports), only disk ports
    (initiator ports), only Fibre Channel Remote Copy configured ports, or
    only Fibre Channel ports for Data Migration.
    If no option is specified, all ports are displayed.
        
  .PARAMETER Disk
    Specifies to display only host ports (target ports), only disk ports
    (initiator ports), only Fibre Channel Remote Copy configured ports, or
    only Fibre Channel ports for Data Migration.
    If no option is specified, all ports are displayed.
        
  .PARAMETER RCFC
    Specifies to display only host ports (target ports), only disk ports
    (initiator ports), only Fibre Channel Remote Copy configured ports, or
    only Fibre Channel ports for Data Migration.
    If no option is specified, all ports are displayed.
        
  .PARAMETER PEER
    Specifies to display only host ports (target ports), only disk ports
    (initiator ports), only Fibre Channel Remote Copy configured ports, or
    only Fibre Channel ports for Data Migration.
    If no option is specified, all ports are displayed.

  .PARAMETER Metric
    Selects which metric to display. Metrics can be one of the following:
        both - (Default)Display both I/O time and I/O size histograms
        time - Display only the I/O time histogram
        size - Display only the I/O size histogram
    
  .PARAMETER Iteration
    Specifies that the histogram is to stop after the indicated number of iterations using an integer from 1 up-to 2147483647.

  .PARAMETER Percentage
    Shows the access count in each bucket as a percentage. If this option is
    not specified, the histogram shows the access counts.

  .PARAMETER Previous
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
    
  .PARAMETER Beginning
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.

  .PARAMETER RW
    Specifies that the display includes separate read and write data. If not
    specified, the total is displayed.
        
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-HistPort
    LASTEDIT: November 2019
    KEYWORDS: Get-HistPort
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [System.String]
        $Iteration,    
        
        [Parameter(Position=1, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Both,
        
        [Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $CTL,
        
        [Parameter(Position=3, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Data,
        
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $Nodes,
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $Slots,
        
        [Parameter(Position=6, Mandatory=$false)]
        [System.String]
        $Ports,
        
        [Parameter(Position=7, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Host,
        
        [Parameter(Position=8, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $PEER,
        
        [Parameter(Position=9, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Disk,
        
        [Parameter(Position=10, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $RCFC,
        
        [Parameter(Position=11, Mandatory=$false)]
        [System.String]
        $Metric,        
        
        [Parameter(Position=12, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Percentage,
        
        [Parameter(Position=13, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Previous,
        
        [Parameter(Position=14, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Beginning,
        
        [Parameter(Position=14, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $RW,
        
        [Parameter(Position=15, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    Write-DebugLog "Start: In Get-HistPort - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {                
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-HistPort since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-HistPort since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }
    $Cmd = "histport "
    if($Iteration)
    {    
        $Cmd +=" -iter $Iteration"
    }
    else
    {
        write-debuglog "Get-HistPort parameter is empty. Simply return " "INFO:"
        return "Error: -Iteration mandatory"
    }
    if($Both)
    {    
        $Cmd +=" -both "
    }
    if($CTL)
    {    
        $Cmd +=" -ctl "
    }
    if($Data)
    {    
        $Cmd +=" -data "
    }
    if ($Nodes)
    {
        $Cmd += " -nodes $Nodes"
    }
    if ($Slots)
    {
        $Cmd += " -slots $Slots"
    }
    if ($Ports)
    {
        $Cmd += " -ports $Ports"
    }
    if($Host)
    {    
        $Cmd +=" -host "
    }
    if($Disk)
    {    
        $Cmd +=" -disk "
    }
    if($RCFC)
    {    
        $Cmd +=" -rcfc "
    }
    if($PEER)
    {    
        $Cmd +=" -peer "
    }
    if ($Metric)
    {
        $Cmd += " -metric "
        $a1="both","time","size"
        $Metric = $Metric.toLower()
        if($a1 -eq $Metric )
        {
            $Cmd += "$Metric "
        }        
        else
        {
            return "FAILURE: -Metric $Metric is Invalid. Only [ both | time | size ] can be used."
        }
    }    
    if ($Previous)
    {
        $Cmd += " -prev "
    }
    if ($Beginning)
    {
        $Cmd += " -begin "
    }
    if ($Percentage)
    {
        $Cmd += " -pct "
    }
    if ($RW)
    {
        $Cmd += " -rw "
    }
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd 
    
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -lt "5")
    {
        return "No data available"
    }        
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        
        $LastItem = $Result.Count
        
        if("time" -eq $Metric.trim().tolower())
        {
            Add-Content -Path $tempFile -Value 'Port,Data/Ctrl,0.50,1,2,4,8,16,32,64,128,256,time,date'
        }
        elseif("size" -eq $Metric.trim().tolower())
        {
            #write-host " in size"
            Add-Content -Path $tempFile -Value 'Port,Data/Ctrl,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date'
        }
        elseif($RW)
        {
            #write-host " in else"
            Add-Content -Path $tempFile -Value 'Port,Data/Ctrl,R/W,0.50,1,2,4,8,16,32,64,128,256,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date'
        }
        else
        {
            #write-host " in else"
            Add-Content -Path $tempFile -Value 'Port,Data/Ctrl,0.50,1,2,4,8,16,32,64,128,256,4k,8k,16k,32k,64k,128k,256k,512k,1m,time,date'
        }
        
        foreach ($s in  $Result[0..$LastItem] )
        {        
            if ($s -match "millisec")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $split1=$s.split(",")
                $global:time1 = $split1[0]
                $global:date1 = $split1[1]
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "Ldname"))
            {
                continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s,"-+","-")
            $s= [regex]::Replace($s," +",",")            # Replace one or more spaces with comma to build CSV line
            $s +=",$global:time1,$global:date1"    
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-HistPort

####################################################################################################################
## FUNCTION Get-HistRCopyVv
###################################################################################################################
Function Get-HistRCopyVv
{
<#
  .SYNOPSIS
   The Get-HistRCopyVv command shows a histogram of total remote-copy service times and backup system remote-copy service times in a timed loop.
    
  .DESCRIPTION
   The Get-HistRCopyVv command shows a histogram of total remote-copy service times and backup system remote-copy service times in a timed loop
  
  .EXAMPLE
    Get-HistRCopyVv -iteration 1
    The Get-HistRCopyVv command shows a histogram of total remote-copy service iteration number of times
  
  .EXAMPLE
    Get-HistRCopyVv -iteration 1 -Sync
    The Get-HistRCopyVv command shows a histogram of total remote-copy service iteration number of times
    with option sync
    
  .EXAMPLE
    Get-HistRCopyVv -group groupvv_1 -iteration

  .EXAMPLE
    Get-HistRCopyVv -iteration 1 -Periodic
    
  .EXAMPLE
    Get-HistRCopyVv -iteration 1 -PortSum
    
  .EXAMPLE
    Get-HistRCopyVv -target name_vv1 -iteration 1
    The Get-HistRCopyVv command shows a histogram of total remote-copy service with specified target name.
    
  .EXAMPLE
    Get-HistRCopyVv -group groupvv_1 -iteration
    The Get-HistRCopyVv command shows a histogram of total remote-copy service with specified Group name.
    
  .PARAMETER Async - Show only volumes which are being copied in asynchronous mode.

  .PARAMETER sync - Show only volumes that are being copied in synchronous mode.
  
  .PARAMETER periodic- Show only volumes which are being copied in asynchronous periodic mode.
  
  .PARAMETER primary - Show only virtual volumes in the primary role.
  
  .PARAMETER secondary - Show only virtual volumes in the secondary role.
  
  .PARAMETER targetsum - Displays the sums for all volumes of a target.
  
  .PARAMETER portsum - Displays the sums for all volumes on a port.
  
  .PARAMETER groupsum - Displays the sums for all volumes of a volume group.
  
  .PARAMETER vvsum - Displays the sums for all targets and links of a virtual volume.
  
  .PARAMETER domainsum - Displays the sums for all volumes of a domain.

  .PARAMETER VV_Name
    Displays statistics only for the specified virtual volume or volume name
    pattern. Multiple volumes or patterns can be repeated (for example,
    <VV_name> <VV_name>). If not specified, all virtual volumes that are
    configured for remote copy are listed.
  
  .PARAMETER interval
    <secs> Specifies the interval in seconds that statistics are sampled from using an integer from 1 through 2147483. If no count is specified, the command defaults to 2 seconds.
  
  .PARAMETER Pct
    Shows the access count in each bucket as a percentage. If this option is
    not specified, the histogram shows the access counts.

  .PARAMETER Prev
    Specifies that the histogram displays data from a previous sample.
    If no option is specified, the histogram shows data from the beginning
    of the command's execution.
  
  .PARAMETER domain
    Shows only the virtual volumes that are in domains with names that match the specified domain name(s) or pattern(s).
    
  .PARAMETER target
   Shows only volumes whose group is copied to the specified target name or pattern. Multiple target names or patterns may be specified using a comma-separated list.
   
  .PARAMETER group
    Shows only volumes whose volume group matches the specified group name or pattern of names.
    Multiple group names or patterns may be specified using a comma-separated list.
  
  .PARAMETER iteration
    Specifies that the statistics are to stop after the indicated number of iterations using an integer from
    1 through 2147483647.
    
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-HistRCopyVv
    LASTEDIT: November 2019
    KEYWORDS: Get-HistRCopyVv
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [switch]
        $ASync,
        
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $Sync,
        
        [Parameter(Position=2, Mandatory=$false)]
        [switch]
        $Periodic,
        
        [Parameter(Position=3, Mandatory=$false)]
        [switch]
        $Primary,
        
        [Parameter(Position=4, Mandatory=$false)]
        [switch]
        $Secondary,
        
        [Parameter(Position=5, Mandatory=$false)]
        [switch]
        $TargetSum,
        
        [Parameter(Position=6, Mandatory=$false)]
        [switch]
        $PortSum,
        
        [Parameter(Position=7, Mandatory=$false)]
        [switch]
        $GroupSum,
        
        [Parameter(Position=8, Mandatory=$false)]
        [switch]
        $VVSum,
        
        [Parameter(Position=9, Mandatory=$false)]
        [switch]
        $DomainSum,
        
        [Parameter(Position=10, Mandatory=$false)]
        [switch]
        $Pct,
        
        [Parameter(Position=11, Mandatory=$false)]
        [switch]
        $Prev,

        [Parameter(Position=12, Mandatory=$false)]
        [System.String]
        $VV_Name,
        
        [Parameter(Position=13, Mandatory=$false)]
        [System.String]
        $interval,    
        
        [Parameter(Position=14, Mandatory=$false)]
        [System.String]
        $domain,
        
        [Parameter(Position=15, Mandatory=$false)]
        [System.String]
        $group,
        
        [Parameter(Position=16, Mandatory=$false)]
        [System.String]
        $target,
        
        [Parameter(Position=17, Mandatory=$false)]
        [System.String]
        $iteration,        
        
        [Parameter(Position=18, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )    
    Write-DebugLog "Start: In Get-HistRCopyVv - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {                
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-HistRCopyVv since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-HistRCopyVv since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }    
    $Cmd = "histrcvv "
    
    if($ASync)    
    {
        $Cmd += " -async "
    }
    if($Sync)    
    {
        $Cmd += " -sync "
    }
    if($Periodic)    
    {
        $Cmd += " -periodic "
    }
    if($Primary)    
    {
        $Cmd += " -primary "
    }
    if($Secondary)    
    {
        $Cmd += " -secondary "
    }
    if($TargetSum)    
    {
        $Cmd += " -targetsum "
    }
    if($PortSum)    
    {
        $Cmd += " -portsum "
    }
    if($GroupSum)    
    {
        $Cmd += " -groupsum "
    }
    if($VVSum)    
    {
        $Cmd += " -vvsum "
    }
    if($DomainSum)    
    {
        $Cmd += " -domainsum "
    }
    if($Pct)    
    {
        $Cmd += " -pct "
    }
    if($Prev)    
    {
        $Cmd += " -prev "
    }    
    if($interval)
    {
        $Cmd += " -d $interval"
    }
    if ($domain)
    { 
        $Cmd += " -domain $domain"
    }
    if ($group)
    { 
        $Cmd += " -g $group"            
    }
    if ($target)
    { 
        $Cmd += " -t $target"            
    }
    if ($VV_Name)
    { 
        $Cmd += " $VV_Name"            
    }
    if ($iteration)
    { 
        $Cmd += " -iter $iteration "            
    }    
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "        
    }
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
    write-debuglog " histograms sums for all synchronous remote - copy volumes" "INFO:" 
    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count - 2
        if($VVSum)
        {
            Add-Content -Path $tempFile -Value "VVname,RCGroup,Target,Mode,Svt_0.50,Svt_1,Svt_2,Svt_4,Svt_8,Svt_16,Svt_32,Svt_64,Svt_128,Svt_256,Rmt_0.50,Rmt_1,Rmt_2,Rmt_4,Rmt_8,Rmt_16,Rmt_32,Rmt_64,Rmt_128,Rmt_256,Time,Date" 
        }
        elseif($PortSum) 
        {
            Add-Content -Path $tempFile -Value "Link,Target,Type,Svt_0.50,Svt_1,Svt_2,Svt_4,Svt_8,Svt_16,Svt_32,Svt_64,Svt_128,Svt_256,Rmt_0.50,Rmt_1,Rmt_2,Rmt_4,Rmt_8,Rmt_16,Rmt_32,Rmt_64,Rmt_128,Rmt_256,Time,Date"
        }
        elseif($GroupSum) 
        {
            Add-Content -Path $tempFile -Value "Group,Target,Mode,Svt_0.50,Svt_1,Svt_2,Svt_4,Svt_8,Svt_16,Svt_32,Svt_64,Svt_128,Svt_256,Rmt_0.50,Rmt_1,Rmt_2,Rmt_4,Rmt_8,Rmt_16,Rmt_32,Rmt_64,Rmt_128,Rmt_256,Time,Date"
        }
        elseif($TargetSum)
        {
            Add-Content -Path $tempFile -Value "Target,Svt_0.50,Svt_1,Svt_2,Svt_4,Svt_8,Svt_16,Svt_32,Svt_64,Svt_128,Svt_256,Rmt_0.50,Rmt_1,Rmt_2,Rmt_4,Rmt_8,Rmt_16,Rmt_32,Rmt_64,Rmt_128,Rmt_256,Time,Date"
        }
        elseif($DomainSum)
        {
            Add-Content -Path $tempFile -Value "Domain,Svt_0.50,Svt_1,Svt_2,Svt_4,Svt_8,Svt_16,Svt_32,Svt_64,Svt_128,Svt_256,Rmt_0.50,Rmt_1,Rmt_2,Rmt_4,Rmt_8,Rmt_16,Rmt_32,Rmt_64,Rmt_128,Rmt_256,Time,Date"
        }
        else 
        {
            Add-Content -Path $tempFile -Value "VVname,RCGroup,Target,Mode,Port,Type,Svt_0.50,Svt_1,Svt_2,Svt_4,Svt_8,Svt_16,Svt_32,Svt_64,Svt_128,Svt_256,Rmt_0.50,Rmt_1,Rmt_2,Rmt_4,Rmt_8,Rmt_16,Rmt_32,Rmt_64,Rmt_128,Rmt_256,Time,Date"
        }
        foreach($s in  $Result[0..$LastItem] )
        {
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +"," ")
            $s= [regex]::Replace($s," ",",")
            
            if($s -match "millisec")
            {             
                $split1=$s.split(",")
                $global:time1 = $split1[0]
                $global:date1 = $split1[1]
                continue
            }
            $lent=$s.split(",").length
            
            $var2 = $lent[0]
            if( "total" -eq $var2)
            {
                continue
            }    
            if(($s -match "-------") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "RCGroup"))
            {
                continue
            }    
            
            # Replace one or more spaces with comma to build CSV line
            $s +=",$global:time1,$global:date1"    
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }
    elseif($Result -match "No virtual volume")
    { 
        Return "No data available : $Result"
    }
    else
    {
        return $Result
    }
} # End Get-HistRCopyVv

####################################################################################################################
## FUNCTION Get-HistVLun
####################################################################################################################

Function Get-HistVLun
{
<#
  .SYNOPSIS
    The Get-HistVLun command displays Virtual Volume Logical Unit Number (VLUN) service time histograms.
    
  .DESCRIPTION
    The Get-HistVLun command displays Virtual Volume Logical Unit Number (VLUN) service time histograms.
        
  .EXAMPLE
    Get-HistVLun -iteration 1
    This example displays two iterations of a histogram of service times for all VLUNs.
        
  .EXAMPLE
    Get-HistVLun -iteration 1 -nodes 1
    This example displays two iterations of a histogram only exports from the specified nodes.
    
  .EXAMPLE
    Get-HistVLun -iteration 1 -domain DomainName
    Shows only VLUNs whose Virtual Volumes (VVs) are in domains with names that match one or more of the specified domain names or patterns.
    
  .EXAMPLE
    Get-HistVLun -iteration 1 -Percentage
    Shows the access count in each bucket as a percentage.
    
  .PARAMETER domain
    Shows only VLUNs whose Virtual Volumes (VVs) are in domains with names that match one or more of the specified domain names or patterns. Multiple domain names or patterns can be
    repeated using a comma-separated list.
        
  .PARAMETER host
   Shows only VLUNs exported to the specified host(s) or pattern(s). Multiple host names or patterns
    can be repeated using a comma-separated list.
    
  .PARAMETER vvname
  Requests that only LDs mapped to VVs that match and of the specified names or patterns be displayed. Multiple volume names or patterns can be repeated using a comma-separated list.

  .PARAMETER Nodes
    Specifies that the display is limited to specified nodes and physical
    disks connected to those nodes. The node list is specified as a series
    of integers separated by commas (e.g. 1,2,3). The list can also consist
    of a single integer. If the node list is not specified, all disks on all
    nodes are displayed.

  .PARAMETER Slots
    Specifies that the display is limited to specified PCI slots and
    physical disks connected to those PCI slots. The slot list is specified
    as a series of integers separated by commas (e.g. 1,2,3). The list can
    also consist of a single integer. If the slot list is not specified, all
    disks on all slots are displayed.

  .PARAMETER Ports
    Specifies that the display is limited to specified ports and
    physical disks connected to those ports. The port list is specified
    as a series of integers separated by commas (e.g. 1,2,3). The list can
    also consist of a single integer. If the port list is not specified, all
    disks on all ports are displayed.
        
  .PARAMETER Metric
    Selects which metric to display. Metrics can be one of the following:
        both - (Default)Display both I/O time and I/O size histograms
        time - Display only the I/O time histogram
        size - Display only the I/O size histogram

  .PARAMETER Percentage
    Shows the access count in each bucket as a percentage. If this option is
    not specified, the histogram shows the access counts.

  .PARAMETER Previous
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
    
  .PARAMETER Beginning
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
        
  .PARAMETER Lun
  Specifies that VLUNs with LUNs matching the specified LUN(s) or pattern(s) are displayed. Multiple LUNs or patterns can be repeated using a comma-separated list.
  
 .PARAMETER iteration
  Specifies that the statistics are to stop after the indicated number of iterations using an integer from
    1 through 2147483647.
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-HistVLun
    LASTEDIT: November 2019
    KEYWORDS: Get-HistVLun
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [System.String]
        $iteration,
        
        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $domain,
        
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $host,
        
        [Parameter(Position=3, Mandatory=$false)]
        [System.String]
        $vvname,
        
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $lun,
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $Nodes,
        
        [Parameter(Position=6, Mandatory=$false)]
        [System.String]
        $Slots,
        
        [Parameter(Position=7, Mandatory=$false)]
        [System.String]
        $Ports,
        
        [Parameter(Position=8, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Percentage,
        
        [Parameter(Position=9, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Previous,
        
        [Parameter(Position=10, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Beginning,
        
        [Parameter(Position=11, Mandatory=$false)]
        [System.String]
        $Metric,            
        
        [Parameter(Position=12, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection       
    )        
    
    Write-DebugLog "Start: In Get-HistVLun - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-HistVLun since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-HistVLun since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }    
    $Cmd = "histvlun "
    if ($iteration)
    { 
        $Cmd += " -iter $iteration"
    }    
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }
    if ($domain)
    { 
        $Cmd += " -domain $domain"
    }    
    if($host)
    {
        $objType = "host"
        $objMsg  = "hosts"        
        ## Check Host Name
        if ( -not (Test-CLIObject -objectType $objType -objectName $host -objectMsg $objMsg))
        {
            write-debuglog "host $host does not exist. Nothing to List" "INFO:" 
            return "FAILURE : No host $host found"
        }        
        $Cmd += " -host $host "        
    }
    if ($vvname)
    { 
        $GetvVolumeCmd="showvv"
        $Res = Invoke-CLICommand -Connection $SANConnection -cmds  $GetvVolumeCmd
        if ($Res -match $vvname)
            {
                $Cmd += " -v $vvname"
            }
            else
            { 
                write-debuglog "vvname $vvname does not exist. Nothing to List" "INFO:" 
                return "FAILURE : No vvname $vvname found"            
            }
    }    
    if ($lun)
    { 
        $Cmd += " -l $lun"            
    }
    if ($Nodes)
    {
        $Cmd += " -nodes $Nodes"
    }
    if ($Slots)
    {
        $Cmd += " -slots $Slots"
    }
    if ($Ports)
    {
        $Cmd += " -ports $Ports"
    }    
    if($Metric)
    {
        $Met = $Metric
        $c = "both","time","size"
        $Metric = $metric.toLower()
        if($c -eq $Met)
        {
            $Cmd += " -metric $Metric "
        }
        else
        {
            return "FAILURE: -Metric $Metric is Invalid. Use only [ both | time | size ]."
        }
    }
    if ($Previous)
    {
        $Cmd += " -prev "
    }
    if ($Beginning)
    {
        $Cmd += " -begin "
    }
    if ($Percentage)
    {
        $Cmd += " -pct "
    }        
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
    write-debuglog " histograms The Get-HistVLun command displays Virtual Volume Logical Unit Number (VLUN) " "INFO:" 
    $range1 = $Result.Count
    #write-host "count = $range1"
    if($range1 -le "5" )
    {
        return "No Data Available"
    }    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count 
        
        if("time" -eq $Metric.trim().tolower())
        {            
            Add-Content -Path $tempFile -Value 'Lun,VVname,Host,Port,0.50(millisec),1(millisec),2(millisec),4(millisec),8(millisec),16(millisec),32(millisec),64(millisec),128(millisec),256(millisec),time,date'
            $LastItem = $Result.Count -3
        }
        elseif("size" -eq $Metric.trim().tolower())
        {
            Add-Content -Path $tempFile -Value 'Lun,VVname,Host,Port,4k(bytes),8k(bytes),16k(bytes),32k(bytes),64k(bytes),128k(bytes),256k(bytes),512k(bytes),1m(bytes),time,date'
            $LastItem = $Result.Count -3
        }
        else
        {
            Add-Content -Path $tempFile -Value 'Lun,VVname,Host,Port,0.50(millisec),1(millisec),2(millisec),4(millisec),8(millisec),16(millisec),32(millisec),64(millisec),128(millisec),256(millisec),4k(bytes),8k(bytes),16k(bytes),32k(bytes),64k(bytes),128k(bytes),256k(bytes),512k(bytes),1m(bytes),time,date'
        }
        foreach ($s in  $Result[0..$LastItem] )
        {            
            if ($s -match "millisec"){
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $split1=$s.split(",")
                $global:time1 = $split1[0]
                $global:date1 = $split1[1]

                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "VVname"))
            {
                continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s,"-+","-")
            $s= [regex]::Replace($s," +",",")            # Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "20")
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }    
    else
    {
        return $Result
    }
} # End Get-HistVLun

####################################################################################################################
## FUNCTION Get-HistVv
####################################################################################################################
Function Get-HistVv
{

<#
  .SYNOPSIS
    The Get-HistVv command displays Virtual Volume (VV) service time histograms in a timed loop.
    
  .DESCRIPTION
   The Get-HistVv command displays Virtual Volume (VV) service time histograms in a timed loop.
          
  .EXAMPLE
    Get-HistVv -iteration 1
    This Example displays Virtual Volume (VV) service time histograms service iteration number of times.
    
     
  .EXAMPLE
    Get-HistVv -iteration 1 -domain domain.com
    This Example Shows only the VVs that are in domains with names that match the specified domain name(s)
    
  .EXAMPLE
    Get-HistVv -iteration 1 –Metric both
    This Example Selects which Metric to display.
    
  .EXAMPLE
    Get-HistVv -iteration 1 -Timecols "1 2"
    
  .EXAMPLE
    Get-HistVv -iteration 1 -Sizecols "1 2"
        
  .EXAMPLE
    Get-HistVv –Metric both -VVname demoVV1 -iteration 1
    This Example Selects which Metric to display. associated with Virtual Volume name.
 
    
  .PARAMETER domain
    Shows only the VVs that are in domains with names that match the specified domain name(s) .
        
  .PARAMETER Metric
    Selects which Metric to display. Metrics can be one of the following:
    1)both - (Default) Displays both I/O time and I/O size histograms.
    2)time - Displays only the I/O time histogram.
    3)size - Displays only the I/O size histogram.
    
  .PARAMETER Timecols
    For the I/O time histogram, shows the columns from the first column
    <fcol> through last column <lcol>. The available columns range from 0
    through 31.

    The first column (<fcol>) must be a value greater than or equal to 0,
    but less than the value of the last column (<lcol>).

    The last column (<lcol>) must be less than or equal to 31.

    The first column includes all data accumulated for columns less than the
    first column and the last column includes accumulated data for all
    columns greater than the last column.

    The default value of <fcol> is 6.
    The default value of <lcol> is 15.

  .PARAMETER Sizecols
    For the I/O size histogram, shows the columns from the first column
    (<fcol>) through the last column (<lcol>). Available columns range from
    0 through 15.

    The first column (<fcol>) must be a value greater than or equal to 0,
    but less than the value of the last column (<lcol>) (default value of 3).
    The last column (<lcol>) must be less than or equal to 15 (default value
    of 11).

    The default value of <fcol> is 3.
    The default value of <lcol> is 11.
  
  .PARAMETER Percentage
    Shows the access count in each bucket as a percentage. If this option is
    not specified, the histogram shows the access counts.

  .PARAMETER Previous
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
    
  .PARAMETER Beginning
    Histogram displays data either from a previous sample(-prev) or from
    when the system was last started(-begin). If no option is specified, the
    histogram shows data from the beginning of the command's execution.
        
  .PARAMETER RW
    Specifies that the display includes separate read and write data. If not
    specified, the total is displayed.

  .PARAMETER IntervalInSeconds
    Specifies the interval in seconds that statistics are sampled from
    using an integer from 1 through 2147483. If no count is specified, the
    command defaults to 2 seconds.
    
  .PARAMETER FSpace
    Specifies that histograms below the threshold specified by the <fspec>
    argument are not displayed. The <fspec> argument is specified in the
    syntax of <op>,<val_ms>, <count>.
    <op>
        The <op> argument can be specified as one of the following:
            r - Specifies read statistics.
            w - Specifies write statistics.
            t - Specifies total statistics.
            rw - Specifies total read and write statistics.
    <val_ms>
        Specifies the threshold service time in milliseconds.
    <count>
    Specifies the minimum number of access above the threshold service
    time. When filtering is done, the <count> is compared with the sum
    of all columns starting with the one which corresponds to the
    threshold service time. For example, -t,8,100 means to only display
    the rows where the 8ms column and all columns to the right adds
    up to more than 100.
    
  .PARAMETER VVName
    Virtual Volume name
      
 .PARAMETER iteration
    Specifies that the statistics are to stop after the indicated number of iterations using an integer from
    1 through 2147483647.
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME:Get-HistVv
    LASTEDIT: November 2019
    KEYWORDS: Get-HistVv
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [System.String]
        $iteration,
        
        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $domain,
        
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $Metric,
        
        [Parameter(Position=3, Mandatory=$false)]
        [System.String]
        $Timecols,
        
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $Sizecols,
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $VVname,        
        
        [Parameter(Position=6, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Percentage,
        
        [Parameter(Position=7, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $Previous,    

        [Parameter(Position=8, Mandatory=$false, ValueFromPipeline=$true)]
        [Switch]
        $RW,
        
        [Parameter(Position=9, Mandatory=$false, ValueFromPipeline=$true)]
        [System.String]
        $IntervalInSeconds,
        
        [Parameter(Position=10, Mandatory=$false, ValueFromPipeline=$true)]
        [System.String]
        $FSpace,
        
        [Parameter(Position=11, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )        
    
    Write-DebugLog "Start: In Get-HistVv - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {        
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-HistVv since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-HistVv since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }    
    $Cmd = "histvv "
    if ($iteration)
    { 
        $Cmd += " -iter $iteration "    
    }
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }
    if ($domain)
    { 
        $Cmd += " -domain $domain "        
    }
    if($Metric)
    {
        $opt="both","time","size"
        $Metric = $Metric.toLower()
        if ($opt -eq $Metric)
        {
            $Cmd += " -metric $Metric"                    
        }
        else 
        {
            Write-DebugLog "Stop: Exiting Get-HistVv since SAN connection object values are null/empty" $Debug
            return " metrics $Metric not found only [ both | time | size ] can be passed one at a time "
        }
    }
    if ($Timecols)
    { 
        $Cmd += " -timecols $Timecols "        
    }
    if ($Sizecols)
    { 
        $Cmd += " -sizecols $Sizecols "        
    }
    if ($Previous)
    {
        $Cmd += " -prev "
    }    
    if ($Percentage)
    {
        $Cmd += " -pct "
    }
    if ($RW)
    {
        $Cmd += " -rw "
    }
    if ($IntervalInSeconds)
    { 
        $Cmd += " -d $IntervalInSeconds "        
    }
    if ($FSpace)
    { 
        $Cmd += " -filt $FSpace "        
    }
    if($VVname)
    { 
        $vv=$VVname
        $Cmd1 ="showvv"
        $Result1 = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd1
        if($Result1 -match $vv)            
        {
            $cmd += " $vv "
        }
        else
        {
            Write-DebugLog " Error : No VVname Found. "
            Return "Error: -VVname $VVname is not available `n Try Using Get-VvList to list all the VV's Available "
        }
    }        
            
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
    write-debuglog " Get-HistVv command displays Virtual Volume Logical Unit Number (VLUN) " "INFO:" 
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -le "5")
    {
        return "No data available"
    }    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count
        if("time" -eq $Metric.trim().tolower())
        {
        #write-host " in time"
            Add-Content -Path $tempFile -Value 'VVname,0.50(millisec),1(millisec),2(millisec),4(millisec),8(millisec),16(millisec),32(millisec),64(millisec),128(millisec),256(millisec),time,date'
        }
        elseif("size" -eq $Metric.trim().tolower())
        {
            #write-host " in size"
            Add-Content -Path $tempFile -Value 'VVname,4k(bytes),8k(bytes),16k(bytes),32k(bytes),64k(bytes),128k(bytes),256k(bytes),512k(bytes),1m(bytes),time,date'
        }
        else
        {
            Add-Content -Path $tempFile -Value         'VVname,0.50(millisec),1(millisec),2(millisec),4(millisec),8(millisec),16(millisec),32(millisec),64(millisec),128(millisec),256(millisec),4k(bytes),8k(bytes),16k(bytes),32k(bytes),64k(bytes),128k(bytes),256k(bytes),512k(bytes),1m(bytes),time,date'
        }
        foreach ($s in  $Result[0..$LastItem] )
        {
            if ($s -match "millisec")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $split1=$s.split(",")
                $global:time1 = $split1[0]
                $global:date1 = $split1[1]

                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "VVname"))
            {
                continue
            }            
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s,"-+","-")
            $s= [regex]::Replace($s," +",",")            # Replace one or more spaces with comma to build CSV line
            $s +=",$global:time1,$global:date1"    
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-HistVv

####################################################################################################################
## FUNCTION Get-StatChunklet
####################################################################################################################

Function Get-StatChunklet
{
<#
  .SYNOPSIS
   The Get-StatChunklet command displays chunklet statistics in a timed loop.
   
  .DESCRIPTION
   The Get-StatChunklet command displays chunklet statistics in a timed loop.
    
  .EXAMPLE
    Get-StatChunklet -Iterration 1
    This example displays chunklet statistics in a timed loop.
    
  .EXAMPLE
   Get-StatChunklet -RW -Iteration 1
   This example Specifies that reads and writes are displayed separately.while displays chunklet statistics in a timed loop.
       
  .EXAMPLE
    Get-StatChunklet -LDname demo1 -CHnum 5 -Iterration 1
    This example Specifies particular chunklet number & logical disk.
    
  .PARAMETER RW
    Specifies that reads and writes are displayed separately. If this option is not used, then the total
    of reads plus writes is displayed.
                
  .PARAMETER Idlep
  Specifies the percent of idle columns in the output.
    
  .PARAMETER Begin
  Specifies that I/O averages are computed from the system start time. If not specified, the average
  is computed since the first iteration of the command.
                
  .PARAMETER NI
  Specifies that statistics for only non-idle devices are displayed
    
  .PARAMETER Delay
    Specifies the interval, in seconds, that statistics are sampled using an integer from 1 through
    2147483.
    
  .PARAMETER LDname
    Specifies that statistics are restricted to chunklets from a particular logical disk.
    
  .PARAMETER CHnum
    Specifies that statistics are restricted to a particular chunklet number.
    
  .PARAMETER Iteration
    Specifies that CMP statistics are displayed a specified number of times as indicated by the num argument using an integer
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatChunklet
    LASTEDIT: November 2019
    KEYWORDS: Get-StatChunklet
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [System.String]
        $Iteration ,
        
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $RW,
        
        [Parameter(Position=2, Mandatory=$false)]
        [switch]
        $IDLEP,
        
        [Parameter(Position=3, Mandatory=$false)]
        [switch]
        $Begin,
        
        [Parameter(Position=4, Mandatory=$false)]
        [switch]
        $NI,
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $Delay,
        
        [Parameter(Position=6, Mandatory=$false)]
        [System.String]
        $LDname ,
        
        [Parameter(Position=7, Mandatory=$false)]
        [System.String]
        $CHnum ,        
                
        [Parameter(Position=8, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    
    Write-DebugLog "Start: In Get-StatChunklet - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatChunklet since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatChunklet since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }        
    $cmd= "statch"
    
    if($Iteration )
    {    
        $cmd+=" -iter $Iteration "    
    }
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "        
    }
    
    if($RW)    
    {
        $cmd +=" -rw "
    }
    if($IDLEP)    
    {
        $cmd+=" -idlep "
    }
    if($Begin)    
    {
        $cmd+=" -begin "
    }
    if($NI)    
    {
        $cmd+=" -ni "
    }
    if($Delay)    
    {
        $cmd+=" -d $Delay"
    }
    if($LDname)    
    {
        $ld="showld"
        $Result1 = Invoke-CLICommand -Connection $SANConnection -cmds  $ld
        if($Result1 -match $LDname )
        {
            $cmd+=" -ld $LDname "
        }
        else 
        {
            Write-DebugLog "Stop: Exiting Get-StatChunklet since -LDname $LDname in unavailable "
            Return "FAILURE : -LDname $LDname is not available . "
        }
    }
    if($CHnum)
    {
        $cmd+=" -ch $CHnum "
    }
    
    #write-host "$cmd"
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd
    write-debuglog " Executing Get-StatChunklet command displays chunklet statistics in a timed loop. with the command " "INFO:" 
    $range1 = $Result.Count
    if($range1 -le "5" )
    {
        return "No Data Available"
    }
    if( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count
        if($IDLEP)    
        {
            Add-Content -Path $tempFile -Value "Logical_Disk_I.D,LD_Name,Ld_Ch,Pd_id,Pd_Ch,R/W,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max,Svt_Cur,Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Idle_Cur,Idle_Avg,Time,Date" 
        }
        else 
        {
            Add-Content -Path $tempFile -Value "Logical_Disk_I.D,LD_Name,Ld_Ch,Pd_id,Pd_Ch,R/W,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max,Svt_Cur,Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Time,Date"
        }
        foreach ($s in  $Result[0..$LastItem] )
        {
            if ($s -match "r/w")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $global:time1 = $s.substring(0,8)
                $global:date1 = $s.substring(9,19)
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "Qlen"))
            {
            continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +",",")# Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "11")
            {
                continue
            }
            if (($aa -eq "13") -and ($IDLEP))
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        
        Import-Csv $tempFile
        del $tempFile
    }    
    else
    {
        return $Result
    }    
} # End Get-StatChunklet

####################################################################################################################
## FUNCTION Get-StatCMP
####################################################################################################################
Function Get-StatCMP
{
<#
  .SYNOPSIS
   The Get-StatCMP command displays Cache Memory Page (CMP) statistics by node or by Virtual Volume (VV).
   
  .DESCRIPTION
   The Get-StatCMP command displays Cache Memory Page (CMP) statistics by node or by Virtual Volume (VV).
  
    
  .EXAMPLE
    Get-StatCMP -Iteration 1
    This Example displays Cache Memory Page (CMP).
    
  .EXAMPLE
   Get-StatCMP -VVname Demo1 -Iteration 1
   This Example displays Cache Memory Page (CMP) statistics by node or by Virtual Volume (VV).
    
          
  .PARAMETER VVname
    Specifies that statistics are displayed for virtual volumes matching the specified name or pattern.
    
  .PARAMETER Domian
    Shows VVs that are in domains with names that match one or more of the specified domains or patterns.
    
  .PARAMETER Delay
    Specifies the interval, in seconds, that statistics are sampled using an integer from 1 through
    2147483.

  .PARAMETER NI
    Specifies that statistics for only non-idle VVs are displayed.
    This option is valid only if -v is also specified.
    
  .PARAMETER Iteration
    Specifies that CMP statistics are displayed a specified number of times as indicated by the num argument using an integer
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatCMP
    LASTEDIT: November 2019
    KEYWORDS: Get-StatCMP
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [switch]
        $NI,
        
        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $VVname ,
        
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $Domian ,
        
        [Parameter(Position=3, Mandatory=$false)]
        [System.String]
        $Delay  ,
        
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $Iteration ,
                
        [Parameter(Position=5, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    
    Write-DebugLog "Start: In Get-StatCMP - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {    
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatCMP since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatCMP since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }        
    $cmd= "statcmp -v "    
    
    if($Iteration)
    {
        $cmd+=" -iter $Iteration "
    }
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "        
    }    
    if ($NI)
    {
        $cmd +=" -ni "
    }
    if($VVname)    
    {
        $cmd+=" -n $VVname "
    }        
    if ($Domian)
    {
        $cmd+= " -domain $Domian "    
    }
    if($Delay)    
    {
        $cmd+=" -d $Delay"
    }    
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd
    write-debuglog " Executing Get-StatCMP command displays Cache Memory Page (CMP) statistics. with the command " "INFO:" 
    $range1 = $Result.count
    
    if($range1 -le "3")
    {
        return "No data available"
    }    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count
        Add-Content -Path $tempFile -Value "VVid,VVname,Type,Curr_Accesses,Curr_Hits,Curr_Hit%,Total_Accesses,Total_Hits,Total_Hit%,Time,Date"
        foreach ($s in  $Result[0..$LastItem] )
        {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                if ($s -match "Current"){    
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]
                continue
            }
            if (($s -match "---") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "VVname"))
            {
            continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +",",")# Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "11")
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
            }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-StatCMP

####################################################################################################################
## FUNCTION Get-StatCPU
####################################################################################################################

Function Get-StatCPU
{
<#
  .SYNOPSIS
   The Get-StatCPU command displays CPU statistics for all nodes.
   
  .DESCRIPTION
   The Get-StatCPU command displays CPU statistics for all nodes.

  .EXAMPLE
    Get-StatCPU -iteration 1
    This Example Displays CPU statistics for all nodes.
    
  .EXAMPLE
    Get-StatCPU -delay 2 -total -iteration 1
    This Example Show only the totals for all the CPUs on each node.
    
              
  .PARAMETER delay
    Specifies the interval, in seconds, that statistics are sampled using an integer from 1 through 2147483
    
  .PARAMETER total
    Show only the totals for all the CPUs on each node.
        
  .PARAMETER Iteration
    Specifies that CMP statistics are displayed a specified number of times as indicated by the num argument using an integer
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatCPU
    LASTEDIT: November 2019
    KEYWORDS: Get-StatCPU
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [System.String]
        $delay,
        
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $total,
        
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $Iteration ,
                
        [Parameter(Position=3, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )        
    
    Write-DebugLog "Start: In Get-StatCPU - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {    
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatCPU since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatCPU since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }    
    
    $cmd= "statcpu "
    
    if($Iteration)
    {
        $cmd+=" -iter $Iteration "
    }
    else
    {
        Write-DebugLog "Stop: Exiting Get-StatCPU Iteration in unavailable "
        Return "FAILURE : -Iteration is Mandatory for Get-StatCPU command to execute. "
    }        
    if($delay)    
    {
        $cmd+=" -d $delay "
    }
    if ($total  )
    {
        $cmd+= " -t "    
    }
        
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd    
    write-debuglog " Executing Get-StatCPU command displays Cache Memory Page (CMP) statistics. with the command " "INFO:" 
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -eq "5"){
        return "No data available"
    }        
    if ( $Result.Count -gt 1)
    {
        $flg = "False"
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count
        Add-Content -Path $tempFile -Value "node,cpu,user,sys,idle,intr/s,ctxt/s,Time,Date"
        foreach ($s in  $Result[0..$LastItem] )
        {
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s,"-+","-")
            $s= [regex]::Replace($s," +",",")
            $s= [regex]::Replace($s,"---","")
            $s= [regex]::Replace($s,"-","")  
            $a=$s.split(",")
            $c=$a.length
            $b=$a.length
            if ( 2 -eq $b )
            {
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]
            }
            if (([string]::IsNullOrEmpty($s)) -or ($s -match "node"))
            {
                continue
            }
            if($c -eq "6")
            {
                $s +=",,$global:time1,$global:date1"
            }
            else
            {
                $s +=",$global:time1,$global:date1"
            }
            if($flg -eq "True")
            {
                Add-Content -Path $tempFile -Value $s    
            }
            $flg = "True"            
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-StatCPU

####################################################################################################################
## FUNCTION Get-StatLD
####################################################################################################################

Function Get-StatLD
{
<#
  .SYNOPSIS
   The Get-StatLD command displays read/write (I/O) statistics about Logical Disks (LDs) in a timed loop.
   
  .DESCRIPTION
   The Get-StatLD command displays read/write (I/O) statistics about Logical Disks (LDs) in a timed loop.
    
  .EXAMPLE
    Get-StatLD -Iteration 1
    This example displays read/write (I/O) statistics about Logical Disks (LDs).
    
  .EXAMPLE
   Get-StatLD -rw -Iteration 1
   This example displays statistics about Logical Disks (LDs).with Specification read/write
   
  .EXAMPLE
    Get-StatLD -Begin -delay 2 -Iteration 1
    This example displays statistics about Logical Disks (LDs).with Specification begin & delay in execution of 2 sec.
    
  .EXAMPLE
    Get-StatLD -Begin -VVname demo1 -Delay 2 -Iteration 1
    This example displays statistics about Logical Disks (LDs) Show only LDs that are mapped to Virtual Volumes (VVs)
    
    
  .EXAMPLE
    Get-StatLD -begin -LDname demoLD1 -delay 2 -Iteration 1
    This example displays statistics about Logical Disks (LDs).With Only statistics are displayed for the specified LD

  .PARAMETER RW
    Specifies that reads and writes are displayed separately. If this option is not used, then the total
    of reads plus writes is displayed.
            
  .PARAMETER Begin
    Specifies that I/O averages are computed from the system start time. If not specified, the average
    is computed since the first iteration of the command.
            
  .PARAMETER IDLEP
    Specifies the percent of idle columns in the output.
    
  .PARAMETER VVname
    Show only LDs that are mapped to Virtual Volumes (VVs) with names matching any of names or patterns specified
    
  .PARAMETER LDname
    Only statistics are displayed for the specified LD or pattern
    
  .PARAMETER Domain
    Shows only LDs that are in domains with names matching any of the names or specified patterns.
    
  .PARAMETER Delay
    Specifies the interval, in seconds, that statistics are sampled using an integer from 1 through
    2147483.

  .PARAMETER Iteration
    Specifies that I/O statistics are displayed a specified number of times as indicated by the number
    argument using an integer from 1 through 2147483647.
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatLD
    LASTEDIT: November 2019
    KEYWORDS: Get-StatLD
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [switch]
        $RW,
        
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $IDLEP,
        
        [Parameter(Position=2, Mandatory=$false)]
        [switch]
        $Begin,
        
        [Parameter(Position=3, Mandatory=$false)]
        [switch]
        $NI,
        
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $VVname ,
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $LDname,
        
        [Parameter(Position=6, Mandatory=$false)]
        [System.String]
        $Domain,
        
        [Parameter(Position=7, Mandatory=$false)]
        [System.String]
        $Delay,
                
        [Parameter(Position=8, Mandatory=$false)]
        [System.String]
        $Iteration,
                
        [Parameter(Position=9, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    
    Write-DebugLog "Start: In Get-StatLD - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {        
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatLD since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatLD since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }        
    $cmd= "statld"    
    
    if($Iteration )
    {    
        $cmd+=" -iter $Iteration "    
    }
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }
    if($RW)    
    {
        $cmd +=" -rw "
    }
    if($IDLEP)    
    {
        $cmd+=" -idlep "
    }
    if($Begin)    
    {
        $cmd+=" -begin "
    }
    if($NI)    
    {
        $cmd+=" -ni "
    }
    if($VVname)    
    {
        $ld="showvv"
        $Result1 = Invoke-CLICommand -Connection $SANConnection -cmds  $ld
        if($Result1 -match $VVname )
        {
            $cmd+=" -vv $VVname "
        }
        else 
        {
            Write-DebugLog "Stop: Exiting Get-StatLD since -VVname $VVname in unavailable "
            Return "FAILURE : -VVname $VVname is not available .`n Try Using Get-VvList to get all available VV "
        }
    }
    if($LDname)    
    {
        if($cmd -match "-vv")
        {
            return "Stop: Executing -VVname $VVname and -LDname $LDname cannot be done in a single Execution "
        }
        $ld="showld"
        $Result1 = Invoke-CLICommand -Connection $SANConnection -cmds  $ld        
        if($Result1 -match $LDname )
        {
            $cmd+=" $LDname "
        }
        else 
        {
            Write-DebugLog "Stop: Exiting Get-StatLD since -LDname $LDname in unavailable "
            Return "FAILURE : -LDname $LDname is not available . "
        }
    }    
    if($Domain)    
    {
        $cmd+=" -domain $Domain "
    }    
    if($Delay)    
    {
        $cmd+=" -d $Delay "
    }        
        
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd
    write-debuglog " Executing Get-StatLD command displays read/write (I/O) statistics about Logical Disks (LDs) in a timed loop. with the command " "INFO:" 
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -le "5")
    {
        return "No data available"
    }    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count - 1        
        if($IDLEP)    
        {
            Add-Content -Path $tempFile -Value "Ldname,r/w,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max,Svt_Cur,Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Idle_Cur,Idle_Avg,Time,Date"
        }
        else 
        {
            Add-Content -Path $tempFile -Value "Ldname,r/w,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max,Svt_Cur,Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Time,Date"    
        }
        foreach ($s in  $Result[0..$LastItem] )
        {
        if ($s -match "r/w")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "Ldname"))
            {
                continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +",",")# Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "11")
            {
                continue
            }
            if (($aa -eq "13") -and ($IDLEP))
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s        
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-StatLD

####################################################################################################################
## FUNCTION Get-StatLink
####################################################################################################################

Function Get-StatLink
{
<#
  .SYNOPSIS
  The Get-StatLink command displays statistics for link utilization for all nodes in a timed loop.
  
  .DESCRIPTION
  The Get-StatLink command displays statistics for link utilization for all nodes in a timed loop.
   
    
  .EXAMPLE
    Get-StatLink -Iteration 1
    This Example displays statistics for link utilization for all nodes in a timed loop.
        
  .EXAMPLE
    Get-StatLink -Interval 3 -Iteration 1
   This Example displays statistics for link utilization for all nodes in a timed loop, with a delay of 3 sec.
  
  .EXAMPLE
    Get-StatLink -Detail -Iteration 1
  
  .PARAMETER Detail
    Displays detailed information regarding the Queue statistics.
  
  .PARAMETER Interval
    Specifies the interval, in seconds, that statistics are sampled using an integer from 1 through
    2147483.

  .PARAMETER Iteration
    Specifies that I/O statistics are displayed a specified number of times as indicated by the number
    argument using an integer from 1 through 2147483647.
  
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatLink
    LASTEDIT: November 2019
    KEYWORDS: Get-StatLink
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [switch]
        $Detail,
                
        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $Interval,
                
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $Iteration,
                
        [Parameter(Position=3, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    Write-DebugLog "Start: In Get-StatLink - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {            
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatLink since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatLink since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }        
    $cmd= "statlink"
    if($Iteration )
    {
        $cmd+=" -iter $Iteration "
    }
    else
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }
    if ($Detail)
    {
        $cmd+=" -detail "
    }
    if ($Interval)
    {
        $cmd+=" -d $Interval "
    }
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd
    write-debuglog " Executing Get-StatLink displays statistics for link utilization for all nodes in a timed loop. with the command " "INFO:" 
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -eq "3"){
        return "No data available"
    }    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count
        Add-Content -Path $tempFile -Value "Node,Q,ToNode,XCB_Cur,XCB_Avg,XCB_Max,KB_Cur,KB_Avg,KB_Max,XCBSz_KB_Cur,XCBSz_KB_Avg,Time,Date"
        foreach ($s in  $Result[0..$LastItem] )
        {
            if ($s -match "Local DMA 0")
            {
                $s= [regex]::Replace($s,"Local DMA 0","Local_DMA_0")            
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s,"-+","-")
            $s= [regex]::Replace($s," +",",")
            if ($s -match "XCB_sent_per_second")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]
                continue
            }
            if ($s -match "Local DMA 0")
            {
             $s= [regex]::Replace($s,"Local DMA 0","Local_DMA_0")            
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "ToNode"))
            {
            continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-StatLink

####################################################################################################################
## FUNCTION Get-StatPD
####################################################################################################################

Function Get-StatPD
{
<#
  .SYNOPSIS
   The Get-StatPD command displays the read/write (I/O) statistics for physical disks in a timed loop.
   
 .DESCRIPTION
    The Get-StatPD command displays the read/write (I/O) statistics for physical disks in a timed loop.
    
  .EXAMPLE
    Get-StatPD -RW –Iteration 1
    This example displays one iteration of I/O statistics for all PDs.
   
  .EXAMPLE
    Get-StatPD -IDLEP –nodes 2 –Iteration 1
   This example displays one iteration of I/O statistics for all PDs with the specification idlep preference of node 2.
   
  .EXAMPLE
    Get-StatPD -NI -wwn 1122112211221122 –nodes 2 –Iteration 1
    This Example Specifies that statistics for a particular Physical Disk (PD) identified by World Wide Names (WWNs) and nodes
  
  .PARAMETER Devinfo
    Indicates the device disk type and speed.
    
  .PARAMETER RW
    Specifies that reads and writes are displayed separately. If this option is not used, then the total
    of reads plus writes is displayed.
    
  .PARAMETER Begin
    Specifies that I/O averages are computed from the system start time. If not specified, the average
    is computed since the first iteration of the command.
    
  .PARAMETER IDLEP
   Specifies the percent of idle columns in the output.
    
  .PARAMETER NI
   Specifies that statistics for only non-idle devices are displayed. This option is shorthand for the option
    
  .PARAMETER wwn
    Specifies that statistics for a particular Physical Disk (PD) identified by World Wide Names (WWNs) are displayed.
    
  .PARAMETER nodes
    Specifies that the display is limited to specified nodes and PDs connected to those nodes
        
  .PARAMETER ports
    Specifies that the display is limited to specified ports and PDs connected to those ports

 .PARAMETER Iteration
    Specifies that the histogram is to stop after the indicated number of iterations using an integer from
    1 through 2147483647.
 
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatPD
    LASTEDIT: November 2019
    KEYWORDS: Get-StatPD
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $RW,
        
        [Parameter(Position=2, Mandatory=$false)]
        [switch]
        $IDLEP,
        
        [Parameter(Position=3, Mandatory=$false)]
        [switch]
        $Begin,
        
        [Parameter(Position=4, Mandatory=$false)]
        [switch]
        $NI,
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $wwn ,
        
        [Parameter(Position=6, Mandatory=$false)]
        [System.String]
        $nodes,
        
        [Parameter(Position=7, Mandatory=$false)]
        [System.String]
        $slots,
        
        [Parameter(Position=8, Mandatory=$false)]
        [System.String]
        $ports ,
        
        [Parameter(Position=9, Mandatory=$false)]
        [System.String]
        $Iteration ,
        
        [Parameter(Position=10, Mandatory=$false)]
        [switch]
        $DevInfo,
        
        [Parameter(Position=11, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )        
    
    Write-DebugLog "Start: In Get-StatPD - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {    
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatPD since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatPD since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }    
    $cmd= "statpd "    
    
    if($Iteration)
    {
        $cmd+=" -iter $Iteration "
    }
    else    
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }
    if($RW)    
    {
        $cmd +=" -rw "
    }
    if($Begin)    
    {
        $cmd+=" -begin "
    }
    if($IDLEP)    
    {
        $cmd+=" -idlep "
    }    
    if($NI)    
    {
        $cmd+=" -ni "
    }
    if($DevInfo)    
    {
        $cmd+=" -devinfo "
    }
    
    if ($wwn)
    {
        $cmd+=" -w $wwn "
    }    
    if ($nodes)
    {
        $cmd+=" -nodes $nodes "
    }    
    if ($slots)
    {
        $cmd+=" -slots $slots "
    }    
    if ($ports )
    {
        $cmd+=" -ports $ports "
    }            
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd    
    write-debuglog " Executing Get-StatPD command displays the read/write (I/O) statistics for physical disks in a timed loop. with the command " "INFO:" 
    $range1 = $Result.count    
    
    if($range1 -eq "4")
    {
        return "No data available"
    }    
    if ( $Result.Count -gt 1)
    {        
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count - 3
        if($DevInfo)
        {
            Add-Content -Path $tempFile -Value "ID,Port,Type,K_RPM,r/w,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max,Svt_Cur,Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Idle_Cur,Idle_Avg,Time,Date"
        }
        else
        {
            Add-Content -Path $tempFile -Value "ID,Port,r/w,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max,Svt_Cur,Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Idle_Cur,Idle_Avg,Time,Date"
        }
        foreach ($s in  $Result[0..$LastItem] )
        {
            if ($s -match "r/w")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]                
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "Port"))
            {
            continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +",",")# Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "13")
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {        
        return $Result
    }
} # End Get-StatPD

####################################################################################################################
## FUNCTION Get-StatPort
####################################################################################################################
Function Get-StatPort
{
<#
  .SYNOPSIS
   The Get-StatPort command displays read/write (I/O) statistics for ports.
   
 .DESCRIPTION
   The Get-StatPort command displays read/write (I/O) statistics for ports.
    
  .EXAMPLE
    Get-StatPort -Iteration 1
    This example displays one iteration of I/O statistics for all ports.
   
  .EXAMPLE
    Get-StatPort -Both -Iteration 1
    This example displays one iteration of I/O statistics for all ports,Show data transfers only.
   
  .EXAMPLE
    Get-StatPort -Host -nodes 2 -Iteration 1
    This example displays I/O statistics for all ports associated with node 2.
  
  .PARAMETER Both
    Show data transfers only.
     
  .PARAMETER Ctl
    Show control transfers only.
     
  .PARAMETER Data
    Show both data and control transfers only.
     
  .PARAMETER Rcfc
    includes only statistics for Remote Copy over Fibre Channel ports related to cached READ requests
    
  .PARAMETER Rcip
    Includes only statistics for Ethernet configured Remote Copy ports.
     
  .PARAMETER RW
    Specifies that the display includes separate read and write data.
     
  .PARAMETER Begin
    Specifies that I/O averages are computed from the system start time
     
  .PARAMETER Idlep
    Specifies the percent of idle columns in the output.
     
  .PARAMETER Host
    Displays only host ports (target ports).
     
  .PARAMETER Disk
    Displays only disk ports (initiator ports).
     
  .PARAMETER Rcfc
    Displays only Fibre Channel remote-copy configured ports.
     
  .PARAMETER NI
    Specifies that statistics for only non-idle devices are displayed.
  
  .PARAMETER FS
    Includes only statistics for File Persona ports.

  .PARAMETER Peer
    Specifies to display only host ports (target ports), only disk ports
    (initiator ports), only Fibre Channel Remote Copy configured ports, or
    only Fibre Channel ports for Data Migration.
    If no option is specified, all ports are displayed.
    
  .PARAMETER nodes
    Specifies that the display is limited to specified nodes and PDs connected to those nodes
        
  .PARAMETER ports
    Specifies that the display is limited to specified ports and PDs connected to those ports

  .PARAMETER slots
    Specifies that the display is limited to specified PCI slots and
    physical disks connected to those PCI slots. The slot list is specified
    as a series of integers separated by commas (e.g. 1,2,3). The list can
    also consist of a single integer. If the slot list is not specified, all
    disks on all slots are displayed.
    
 .PARAMETER Iteration
    Specifies that the histogram is to stop after the indicated number of iterations using an integer from
    1 through 2147483647.
 
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatPort
    LASTEDIT: November 2019
    KEYWORDS: Get-StatPort
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [switch]
        $Both ,
        
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $Ctl ,
        
        [Parameter(Position=2, Mandatory=$false)]
        [switch]
        $Data ,
        
        [Parameter(Position=3, Mandatory=$false)]
        [switch]
        $Rcfc ,
        
        [Parameter(Position=4, Mandatory=$false)]
        [switch]
        $Rcip ,
        
        [Parameter(Position=5, Mandatory=$false)]
        [switch]
        $RW ,
        
        [Parameter(Position=6, Mandatory=$false)]
        [switch]
        $FS ,
        
        [Parameter(Position=7, Mandatory=$false)]
        [switch]
        $Host ,
        
        [Parameter(Position=8, Mandatory=$false)]
        [switch]
        $Peer ,
        
        [Parameter(Position=9, Mandatory=$false)]
        [switch]
        $IDLEP,
        
        [Parameter(Position=10, Mandatory=$false)]
        [switch]
        $Begin,
        
        [Parameter(Position=11, Mandatory=$false)]
        [switch]
        $NI,
        
        [Parameter(Position=12, Mandatory=$false)]
        [switch]
        $Disk,
                    
        [Parameter(Position=13, Mandatory=$false)]
        [System.String]
        $nodes,
        
        [Parameter(Position=14, Mandatory=$false)]
        [System.String]
        $slots,
        
        [Parameter(Position=15, Mandatory=$false)]
        [System.String]
        $ports ,
        
        [Parameter(Position=16, Mandatory=$false)]
        [System.String]
        $Iteration ,
                
        [Parameter(Position=17, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    
    Write-DebugLog "Start: In Get-StatPort - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {    
            
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatPort since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatPort since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }        
    $cmd= "statport "
    
    if($Iteration)
    {    
        $cmd+=" -iter $Iteration "    
    }
    else    
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }    
    if($Both)    
    {
        $cmd +=" -both "
    }
    if($Ctl)    
    {
        $cmd +=" -ctl "
    }
    if($Data)    
    {
        $cmd +=" -data "
    }
    if($Rcfc)    
    {
        $cmd +=" -rcfc "
    }
    if($Rcip)    
    {
        $cmd +=" -rcip "
    }
    if($FS)    
    {
        $cmd +=" -fs "
    }
    if($Host)    
    {
        $cmd +=" -host "
    }
    if($Disk)    
    {
        $cmd +=" -disk "
    }
    if($Peer)    
    {
        $cmd +=" -peer "
    }    
    if($RW)    
    {
        $cmd +=" -rw "
    }
    if($Begin)    
    {
        $cmd+=" -begin "
    }
    if($IDLEP)    
    {
        $cmd+=" -idlep "
    }    
    if($NI)    
    {
        $cmd+=" -ni "
    }
    if ($nodes)
    {
        $cmd+=" -nodes $nodes "
    }
    if ($slots)
    {
        $cmd+=" -slots $slots "
    }
    if ($ports )
    {
        $cmd+=" -ports $ports "
    }                
        
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd    
    write-debuglog " Executing Get-StatPort command displays the read/write (I/O) statistics for physical disks in a timed loop. with the command " "INFO:" 
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -eq "4")
    {
        return "No data available"
    }
    if(($Both) -And ($range -eq "6"))
    {
        return "No data available"
    }
        
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count -3
        if($Rcip)
        {
            Add-Content -Path $tempFile -Value "Port,r/w,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max,Errs,Drops,Time,Date"
        }
        elseif ($IDLEP)
        {
            Add-Content -Path $tempFile -Value "Port,D/C,r/w,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max, Svt_Cur, Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Idle_Cur,Idle_Avg,Time,Date"
        }
        else
        {
            Add-Content -Path $tempFile -Value "Port,D/C,r/w,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max, Svt_Cur, Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Time,Date"
        }    
        foreach ($s in  $Result[0..$LastItem] )
        {
            if ($s -match "r/w")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "Port"))
            {
            continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +",",")# Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if (($aa -eq "12") -or ($aa -eq "8") -or ($aa -eq "8"))
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }    
    else
    {
        return $Result
    }
} # End Get-StatPort

####################################################################################################################
## FUNCTION Get-StatRcVv
####################################################################################################################

Function Get-StatRcVv
{
<#
    .SYNOPSIS
    The Get-StatRcVv command displays statistics for remote-copy volumes in a timed loop.
   
    .DESCRIPTION
    The Get-StatRcVv command displays statistics for remote-copy volumes in a timed loop.
  
    .EXAMPLE
    Get-StatRcVv -Iteration 1
    This Example displays statistics for remote-copy volumes in a timed loop.
   
    .EXAMPLE
    Get-StatRcVv -Iteration 1 -ASync

    .EXAMPLE
    Get-StatRcVv -Iteration 1 -Sync -VVname $VV

    .EXAMPLE
    Get-StatRcVv -Iteration 1 -TargetSum

    .EXAMPLE
    Get-StatRcVv -Iteration 1 -VVSum
   
   .EXAMPLE
    Get-StatRcVv -Iteration 1 -periodic
    This Example displays statistics for remote-copy volumes in a timed loop and show only volumes that are being copied in asynchronous periodic mode
   
    .EXAMPLE
    Get-StatRcVv -target demotarget1 -Iteration 1
    This Example displays statistics for remote-copy volumes in a timed loop and Show only volumes whose group is copied to the specified target name.

  .PARAMETER Async : Show only volumes which are being copied in asynchronous mode.
    
  .PARAMETER sync : Show only volumes that are being copied in synchronous mode.
    
  .PARAMETER periodic : Show only volumes that are being copied in asynchronous periodic mode
    
  .PARAMETER primary : Show only volumes that are in the primary role.
    
  .PARAMETER secondary : Show only volumes that are in the secondary role.
    
  .PARAMETER targetsum : Specifies that the sums for all volumes of a target are displayed.
    
  .PARAMETER portsum : Specifies that the sums for all volumes on a port are displayed.
    
  .PARAMETER groupsum : Specifies that the sums for all volumes of a group are displayed.
    
  .PARAMETER vvsum : Specifies that the sums for all targets and links of a volume are displayed.
    
  .PARAMETER domainsum : Specifies that the sums for all volumes of a domain are displayed.
    
  .PARAMETER ni : Specifies that statistics for only non-idle devices are displayed.
    
  .PARAMETER target
    Show only volumes whose group is copied to the specified target name.
    
  .PARAMETER port
    Show only volumes that are copied over the specified port or pattern.
    
  .PARAMETER group
    Show only volumes whose group matches the specified group name or pattern.
    
  .PARAMETER VVname
    Displays statistics only for the specified virtual volume or volume name pattern.
    
 .PARAMETER Iteration
    Specifies that the histogram is to stop after the indicated number of iterations using an integer from
    1 through 2147483647.
    
 .PARAMETER DomainName
    Shows only the virtual volumes that are in domains with names that match
    the specified domain name(s) or pattern(s).
        
 .PARAMETER Interval
    Specifies the interval in seconds that statistics are sampled from
    using an integer from 1 through 2147483. If no count is specified, the
    command defaults to 2 seconds.
    
 .PARAMETER Subset
    Show subset statistics for Asynchronous Remote Copy on a per group basis.
    
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatRcVv
    LASTEDIT: November 2019
    KEYWORDS: Get-StatRcVv
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        
        [Parameter(Position=0, Mandatory=$false)]
        [System.String]
        $Iteration ,        
        
        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $Interval ,    
        
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $Target ,
                        
        [Parameter(Position=3, Mandatory=$false)]
        [System.String]
        $Port,
        
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $Group ,
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $VVname  ,
        
        [Parameter(Position=6, Mandatory=$false)]
        [System.String]
        $DomainName  ,

        [Parameter(Position=7, Mandatory=$false)]
        [switch]
        $ASync,
        
        [Parameter(Position=8, Mandatory=$false)]
        [switch]
        $Sync,
        
        [Parameter(Position=9, Mandatory=$false)]
        [switch]
        $Periodic,
        
        [Parameter(Position=10, Mandatory=$false)]
        [switch]
        $Primary,
        
        [Parameter(Position=11, Mandatory=$false)]
        [switch]
        $Secondary,
        
        [Parameter(Position=12, Mandatory=$false)]
        [switch]
        $TargetSum,
        
        [Parameter(Position=13, Mandatory=$false)]
        [switch]
        $PortSum,
        
        [Parameter(Position=14, Mandatory=$false)]
        [switch]
        $GroupSum,
        
        [Parameter(Position=15, Mandatory=$false)]
        [switch]
        $VVSum,
        
        [Parameter(Position=16, Mandatory=$false)]
        [switch]
        $DomainSum,
        
        [Parameter(Position=17, Mandatory=$false)]
        [switch]
        $NI,
        
        [Parameter(Position=18, Mandatory=$false)]
        [switch]
        $SubSet,
                
        [Parameter(Position=19, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    
    Write-DebugLog "Start: In Get-StatRcVv - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {    
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatRcVv since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatRcVv since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }        
    $cmd= "statrcvv "    
    
    if($Iteration)
    {
        $cmd+=" -iter $Iteration "
    }
    else
    {
        Write-DebugLog "Stop: Exiting Get-StatRcVv Iteration in unavailable "
        Return "FAILURE : -Iteration is Mandatory for Get-StatRcVv command to execute. "
    }
    if ($Interval)
    {
        $cmd+=" -d $Interval"
    }    
    if ($Target)
    {
        $cmd+=" -t $Target"
    }    
    if ($Port)
    {
        $cmd+=" -port $Port "
    }
    if ($Group)
    {
        $cmd+=" -g $Group"
    }
    if($ASync)    
    {
        $cmd += " -async "
    }
    if($Sync)    
    {
        $cmd += " -sync "
    }
    if($Periodic)    
    {
        $cmd += " -periodic "
    }
    if($Primary)    
    {
        $cmd += " -primary "
    }
    if($Secondary)    
    {
        $cmd += " -secondary "
    }
    if($TargetSum)    
    {
        $cmd += " -targetsum "
    }
    if($PortSum)    
    {
        $cmd += " -portsum "
    }
    if($GroupSum)    
    {
        $cmd += " -groupsum "
    }
    if($VVSum)    
    {
        $cmd += " -vvsum "
    }
    if($DomainSum)    
    {
        $cmd += " -domainsum "
    }
    if($DomainName)    
    {
        $cmd += " -domain $DomainName "
    }
    if($NI)    
    {
        $cmd += " -ni "
    }
    if($SubSet)    
    {
        $cmd += " -subset "
    }
    if ($VVname)
    {
        $s= Get-Vv -vvName  $VVname
        if ($s -match $VVname )
        {
            $cmd+=" $VVname"
        }
        else
        {
            Write-DebugLog "Stop: Exiting Get-StatRcVv VVname in unavailable "
            Return "FAILURE : -VVname $VVname is Unavailable to execute. "
        }        
    }
    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd
    write-debuglog " Executing Get-StatRcVv command displays statistics for remote-copy volumes in a timed loop. with the command " "INFO:" 
    $range1 = $Result.count
    
    if($range1 -eq "4")
    {
        return "No data available"
    }
    if( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count - 2
        
        if($TargetSum)
        {
            Add-Content -Path $tempFile -Value "Target,Mode,I/O_Cur,I/O_Avg,I/O_Max,KBytes_Cur,KBytes_Avg,KBytes_Max,Svt_Cur,Svt_Avg,Rmt_Cur,Rmt_Avg,IOSz_Cur,IOSz_Avg,Time,Date"        
        }
        elseif ($PortSum)
        {
            Add-Content -Path $tempFile -Value "Link,Target,Type,I/O_Cur,I/O_Avg,I/O_Max,KBytes_Cur,KBytes_Avg,KBytes_Max,Svt_Cur,Svt_Avg,Rmt_Cur,Rmt_Avg,IOSz_Cur,IOSz_Avg,Time,Date"
        }
        elseif ($GroupSum)
        {
            Add-Content -Path $tempFile -Value "Group,Target,Mode,I/O_Cur,I/O_Avg,I/O_Max,KBytes_Cur,KBytes_Avg,KBytes_Max,Svt_Cur,Svt_Avg,Rmt_Cur,Rmt_Avg,IOSz_Cur,IOSz_Avg,Time,Date"
        }
        elseif ($VVSum)
        {
            Add-Content -Path $tempFile -Value "VVname,RCGroup,Target,Mode,I/O_Cur,I/O_Avg,I/O_Max,KBytes_Cur,KBytes_Avg,KBytes_Max,Svt_Cur,Svt_Avg,Rmt_Cur,Rmt_Avg,IOSz_Cur,IOSz_Avg,Time,Date"
        }
        elseif ($DomainSum)
        {
            Add-Content -Path $tempFile -Value "Domain,I/O_Cur,I/O_Avg,I/O_Max,KBytes_Cur,KBytes_Avg,KBytes_Max,Svt_Cur,Svt_Avg,Rmt_Cur,Rmt_Avg,IOSz_Cur,IOSz_Avg,Time,Date"
        }
        else 
        {        
            Add-Content -Path $tempFile -Value "VVname,RCGroup,Target,Mode,Port,Type,I/O_Cur,I/O_Avg,I/O_Max,KBytes_Cur,KBytes_Avg,KBytes_Max,Svt_Cur,Svt_Avg,Rmt_Cur,Rmt_Avg,IOSz_Cur,IOSz_Avg,Time,Date"
        }
        foreach ($s in  $Result[0..$LastItem] )
        {
            $s= [regex]::Replace($s,"^ +","")
            #$s= [regex]::Replace($s,"-+","-")
            $s= [regex]::Replace($s," +",",")            # Replace one or more spaces with comma to build CSV line
            if ($s -match "I/O")
            {
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]
                continue
            }
            if (($s -match "-------") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "Avg"))
            {
            continue
            }
            $aa=$s.split(",").length
            if ($aa -eq "11")
            {
                continue
            }            
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s        
            #$s= $s.Trim() -replace 'Cur,Avg,Max,Cur,Avg,Max,Cur,Avg,Cur,Avg,Cur,Avg','I/O_Cur,I/O_Avg,I/O_Max,KBytes_Cur,KBytes_Avg,KBytes_Max,Svt_Cur,Svt_Avg,Rmt_Cur,Rmt_Avg,IOSz_Cur,IOSz_Avg'
            #Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
    
} # End Get-StatRcVv

####################################################################################################################
## FUNCTION Get-StatVLun
####################################################################################################################
Function Get-StatVLun
{
<#
  .SYNOPSIS
   The Get-StatVLun command displays statistics for Virtual Volumes (VVs) and Logical Unit Number (LUN) host attachments.
   
  .DESCRIPTION
   The Get-StatVLun command displays statistics for Virtual Volumes (VVs) and Logical Unit Number (LUN) host attachments.
   
  .EXAMPLE
    Get-StatVLun -Iteration 1
    This example displays statistics for Virtual Volumes (VVs) and Logical Unit Number (LUN) host attachments.
   
  .EXAMPLE
    Get-StatVLun -vvSum -Iteration 1
    This example displays statistics for Virtual Volumes (VVs) and Specifies that sums for VLUNs of the same VV are displayed.
    
  .EXAMPLE
    Get-StatVLun -vvSum -RW -Iteration 1
    
  .EXAMPLE
    Get-StatVLun -vvSum -RW -VVname xxx -Iteration 1
   
  .EXAMPLE
    Get-StatVLun -VVname demovv1 -Iteration 1
    This example displays statistics for Virtual Volumes (VVs) and only Logical Disks (LDs) mapped to VVs that match any of the specified names to be displayed.
                 
  .PARAMETER LW : Lists the host’s World Wide Name (WWN) or iSCSI names.
            
  .PARAMETER Domainsum : Specifies that sums for VLUNs are grouped by domain in the display.
    
  .PARAMETER vvSum : Specifies that sums for VLUNs of the same VV are displayed.
    
  .PARAMETER Hostsum : Specifies that sums for VLUNs are grouped by host in the display.
    
  .PARAMETER RW : Specifies reads and writes to be displayed separately.
    
  .PARAMETER Begin : Specifies that I/O averages are computed from the system start time.
    
  .PARAMETER IDLEP : Includes a percent idle columns in the output.
    
  .PARAMETER NI : Specifies that statistics for only nonidle devices are displayed.
    
  .PARAMETER domian
    Shows only Virtual Volume Logical Unit Number (VLUNs) whose VVs are in domains with names that match one or more of the specified domain names or patterns.
    
  .PARAMETER VVname
    Requests that only Logical Disks (LDs) mapped to VVs that match any of the specified names to be displayed.
    
  .PARAMETER LUN
    Specifies that VLUNs with LUNs matching the specified LUN(s) or pattern(s) are displayed.
    
  .PARAMETER nodes
    Specifies that the display is limited to specified nodes and Physical Disks (PDs) connected to those
    nodes.
    
  .PARAMETER Iteration
    Specifies that the histogram is to stop after the indicated number of iterations using an integer from
    1 through 2147483647.
 
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatVLun
    LASTEDIT: November 2019
    KEYWORDS: Get-StatVLun
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $RW,
        
        [Parameter(Position=2, Mandatory=$false)]
        [switch]
        $IDLEP,
        
        [Parameter(Position=3, Mandatory=$false)]
        [switch]
        $Begin,
        
        [Parameter(Position=4, Mandatory=$false)]
        [switch]
        $NI, 
        
        [Parameter(Position=5, Mandatory=$false)]
        [switch]
        $LW,
        
        [Parameter(Position=6, Mandatory=$false)]
        [switch]
        $DomainSum,
        
        [Parameter(Position=7, Mandatory=$false)]
        [switch]
        $vvSum,
        
        [Parameter(Position=8, Mandatory=$false)]
        [switch]
        $HostSum,
        
        [Parameter(Position=9, Mandatory=$false)]
        [System.String]
        $domian  ,
                        
        [Parameter(Position=10, Mandatory=$false)]
        [System.String]
        $VVname ,
        
        [Parameter(Position=11, Mandatory=$false)]
        [System.String]
        $LUN ,
        
        [Parameter(Position=12, Mandatory=$false)]
        [System.String]
        $nodes,
        
        [Parameter(Position=13, Mandatory=$false)]
        [System.String]
        $Iteration ,
                
        [Parameter(Position=14, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    
    Write-DebugLog "Start: In Get-StatVLun - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {    
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatVLun since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatVLun since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }        
    $cmd= "statvlun "
    if($Iteration)
    {    
        $cmd+=" -iter $Iteration "    
    }
    else    
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }    
    
    if($RW)    
    {
        $cmd +=" -rw "
    }
    if($Begin)    
    {
        $cmd+=" -begin "
    }
    if($IDLEP)    
    {
        $cmd+=" -idlep "
    }    
    if($NI)    
    {
        $cmd+=" -ni "
    }    
    if($LW)    
    {
        $cmd +=" -lw "
    }
    if($DomainSum)    
    {
        $cmd+=" -domainsum "
    }
    if($vvSum)    
    {
        $cmd+=" -vvsum "
    }    
    if($HostSum)    
    {
        $cmd+=" -hostsum "
    }
    if ($domian)
    {
        $cmd+=" -domain $domian"
    }    
    if ($VVname)
    {
        $s= Get-Vv -vvName  $VVname
        if ($s -match $VVname )
        {
            $cmd+=" -v $VVname"
        }
        else
        {
            Write-DebugLog "Stop: Exiting Get-StatVLun VVname in unavailable "
            Return "FAILURE : -VVname $VVname is Unavailable to execute. "
        }        
    }
    if ($LUN)
    {
        $cmd+=" -l $LUN"
    }    
    if ($nodes)
    {
        $cmd+=" -nodes $nodes"
    }                
        
    #write-host " $cmd"
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd
    write-debuglog " Executing Get-StatVLun command command displays statistics for Virtual Volumes (VVs) and Logical Unit Number (LUN) host attachments. with the command " "INFO:"
    $range1 = $Result.count
    #write-host "count = $range1"
    if($range1 -eq "4")
    {
        return "No data available"
    }    
    if(($range1 -eq "6") -and ($NI))
    {
        return "No data available"
    }
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count - 3
        if($LW)
        {    
            Add-Content -Path $tempFile -Value "Lun,VVname,Host,Port,Host_WWN/iSCSI_Name,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,Time,Date"
        }
        elseif($DomainSum)
        {
            Add-Content -Path $tempFile -Value "Domain,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,Time,Date" 
        }
        elseif($vvSum)
        {
            Add-Content -Path $tempFile -Value "VVname,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,Time,Date"
        }
        elseif($RW)
        {
            Add-Content -Path $tempFile -Value "Lun,VVname,Host,Port,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,Time,Date"
        }
        elseif($Begin)
        {
            Add-Content -Path $tempFile -Value "Lun,VVname,Host,Port,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,Time,Date"
        }
        elseif($IDLEP)
        { #IOSz
            Add-Content -Path $tempFile -Value "Lun,VVname,Host,Port,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,IOSz_Cur,IOSz_Avg,Time,Date"
        }
        elseif($NI)
        {
            Add-Content -Path $tempFile -Value "Lun,VVname,Host,Port,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,Time,Date"
        }
        elseif($HostSum)
        {
            Add-Content -Path $tempFile -Value "Hostname,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,Time,Date"
        }
        else
        {
            Add-Content -Path $tempFile -Value "Lun,VVname,Host,Port,r/w,r/w_Cur,r/w_Avg,r/w_Max,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,Svt_Cur,Svt_Avg,Qlen,Time,Date" 
        }
        foreach ($s in  $Result[0..$LastItem] )
        {
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +",",")    
            if ($s -match "r/w")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "cur"))
            {
            continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +",",")# Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "11")
            {
                continue
            }
            if (($aa -eq "13") -And ($IDLEP))
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile
        del $tempFile
    }
    else
    {
        return $Result
    }
} # End Get-StatVLun

####################################################################################################################
## FUNCTION Get-StatVv
####################################################################################################################

Function Get-StatVv
{
<#
  .SYNOPSIS
   The Get-StatVv command displays statistics for Virtual Volumes (VVs) in a timed loop.
   
  .DESCRIPTION
    The Get-StatVv command displays statistics for Virtual Volumes (VVs) in a timed loop.
   
  .EXAMPLE
    Get-StatVv -Iteration 1
   This Example displays statistics for Virtual Volumes (VVs) in a timed loop.
   
   
  .EXAMPLE
    Get-StatVv -RW -Iteration 1
   This Example displays statistics for Virtual Volumes (VVs) with specification of read/write option.
   
  .EXAMPLE
    Get-StatVv -Delay -Seconds 2 -Iteration 1
    Specifies the interval in seconds that statistics are sampled from using an integer from 1 through 2147483.
    
  .EXAMPLE
    Get-StatVv -RW -domain ZZZ -VVname demovv1 -Iteration 1
    This Example displays statistics for Virtual Volumes (VVs) with Only statistics are displayed for the specified VVname.

  .PARAMETER RW : Specifies reads and writes to be displayed separately.
 
  .PARAMETER Delay : <Seconds> Specifies the interval in seconds that statistics are sampled from using an integer from 1 through 2147483. If no count is specified, the
                         command defaults to 2 seconds.
        
  .PARAMETER NI : Specifies that statistics for only non-idle devices are displayed. This option is shorthand for the option -filt curs,t,iops,0.
    
  .PARAMETER domian
    Shows only Virtual Volume Logical Unit Number (VLUNs) whose VVs are in domains with names that match one or more of the specified domain names or patterns.
    
  .PARAMETER Iteration
    Specifies that the histogram is to stop after the indicated number of iterations using an integer from
    1 through 2147483647.
    
  .PARAMETER VVname
    Only statistics are displayed for the specified VV.

  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Get-StatVv
    LASTEDIT: November 2019
    KEYWORDS: Get-StatVv
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [switch]
        $RW ,
        
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $NI ,
        
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $Delay  ,
        
        [Parameter(Position=3, Mandatory=$false)]
        [System.String]
        $domian  ,
                    
        [Parameter(Position=4, Mandatory=$false)]
        [System.String]
        $VVname ,    
        
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $Iteration ,
                
        [Parameter(Position=6, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection 
       
    )        
    Write-DebugLog "Start: In Get-StatVv - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {    
            
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Get-StatVv since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Get-StatVv since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }    
    $cmd= "statvv "
    if($Iteration)
    {
        $cmd+=" -iter $Iteration "    
    }
    else    
    {
        Write-DebugLog "Stop: Iteration is mandatory" $Debug
        return "Error : -Iteration is mandatory. "
    }    
    
    if ($RW)
    {
        $cmd+=" -rw "
    }
    if ($Delay)
    {
        $cmd+=" -d $Delay "
    }
    if ($NI)
    {
        $cmd+=" -ni "
    }
    if ($domian)
    {
        $cmd+=" -domain $domian"
    }            
    if ($VVname)
    {
        $cmd+=" $VVname"
    }    
        
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd    
    write-debuglog " Executing The Get-StatVv command displays statistics for Virtual Volumes (VVs) in a timed loop. with the command " "INFO:" 
    $range1 = $Result.count
    if($range1 -eq "4")
    {
        return "No data available"
    }    
    if ( $Result.Count -gt 1)
    {
        $tempFile = [IO.Path]::GetTempFileName()
        $LastItem = $Result.Count
        Add-Content -Path $tempFile -Value "VVname,r/w,I/O_Cur,I/O_Avg,I/O_Max,KB_Cur,KB_Avg,KB_Max,Svt_Cur,Svt_Avg,IOSz_Cur,IOSz_Avg,Qlen,Time,Date"
        foreach ($s in  $Result[0..$LastItem] )
        {
            if ($s -match "r/w")
            {
                $s= [regex]::Replace($s,"^ +","")
                $s= [regex]::Replace($s," +"," ")
                $s= [regex]::Replace($s," ",",")
                $a=$s.split(",")
                $global:time1 = $a[0]
                $global:date1 = $a[1]
                continue
            }
            if (($s -match "----") -or ([string]::IsNullOrEmpty($s)) -or ($s -match "VVname"))
            {
            continue
            }
            $s= [regex]::Replace($s,"^ +","")
            $s= [regex]::Replace($s," +",",")# Replace one or more spaces with comma to build CSV line
            $aa=$s.split(",").length
            if ($aa -eq "11")
            {
                continue
            }
            $s +=",$global:time1,$global:date1"
            Add-Content -Path $tempFile -Value $s
        }
        Import-Csv $tempFile    
        del $tempFile
    }
    else
    {
        return $Result
    }    
} # End Get-StatVv

####################################################################################################################
## FUNCTION Set-Statch
####################################################################################################################
Function Set-Statch
{
<#
  .SYNOPSIS
    The Set-Statch command sets the statistics collection mode for all in-use chunklets on a Physical Disk (PD).
  
  .DESCRIPTION
   The Set-Statch command sets the statistics collection mode for all in-use chunklets on a Physical Disk (PD).
  
  .EXAMPLE
    Set-Statch -Start -LDname test1 -CLnum 1
    This example starts and stops the statistics collection mode for chunklets.with the LD name test1.
    
  .PARAMETER Start
    Specifies that the collection of statistics is either started or stopped for the specified Logical Disk
    (LD) and chunklet.
    
  .PARAMETER Stop
    Specifies that the collection of statistics is either started or stopped for the specified Logical Disk
    (LD) and chunklet.
    
  .PARAMETER LDname
    Specifies the name of the logical disk in which the chunklet to be configured resides.
    
  .PARAMETER CLnum
    Specifies the chunklet that is configured using the setstatch command.
     
  .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Set-Statch
    LASTEDIT: November 2019
    KEYWORDS: Set-Statch
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false)]
        [switch]
        $Start,
        
        [Parameter(Position=1, Mandatory=$false)]
        [switch]
        $Stop,
                
        [Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true)]
        [System.String]
        $LDname,
        
        [Parameter(Position=3, Mandatory=$false, ValueFromPipeline=$true)]
        [System.String]
        $CLnum,    
        
        [Parameter(Position=4, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )        
    
    Write-DebugLog "Start: In Set-Statch - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {            
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Set-Statch since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Set-Statchsince no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }    
    
    $cmd1 = "setstatch "
    if ($Start)
    {
        $cmd1 += " start "
    }
    if ($Stop)
    {
        $cmd1 += " stop "
    }
    
    if($LDname)
    {
        $cmd2="showld"
        $Result1 = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd2
        if($Result1 -match $LDname)
        {
            $cmd1 += " $LDname "
        }
        Else
        {
            write-debuglog "LDname parameter is Unavailable. Simply return " "INFO:"
            return "Error: LDname is Invalid ."
        }
    }
    else
    {
        write-debuglog "-LDname parameter is empty. Simply return " "INFO:"
        return "Error: -LDname parameter is mandatory ."
    }
    if($CLnum)
    {
        $cmd1+="$CLnum"
    }
    else    
    {
        write-debuglog "-CLnum parameter is Unavailable. Simply return " "INFO:"
        return "Error: -CLnum parameter is mandatory ."
    }    
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd1
    write-debuglog " The Set-Statch command sets the statistics collection mode for all in-use chunklets on a Physical Disk (PD).->$cmd" "INFO:"
    if([string]::IsNullOrEmpty($Result))
    {
        return  "Success : Set-Statch $Result "
    }
    else
    {
        return  "FAILURE : While Executing Set-Statch $Result"
    } 
} # End Set-Statch

####################################################################################################################
## FUNCTION Set-StatPdch
#####################################################################################################################

Function Set-StatPdch
{
<#
  .SYNOPSIS
    The Set-StatPdch command starts and stops the statistics collection mode for chunklets.

  .DESCRIPTION
    The Set-StatPdch command starts and stops the statistics collection mode for chunklets.
 
  .EXAMPLE
   Set-StatPdch -Start -PD_ID 2
   This Example sets the statistics collection mode for all in-use chunklets on a Physical Disk (PD) 2.

  
  .PARAMETER Start
    Specifies that the collection of statistics is either started or stopped for the specified Logical Disk
    (LD) and chunklet.
    
  .PARAMETER Stop
    Specifies that the collection of statistics is either started or stopped for the specified Logical Disk
    (LD) and chunklet.
    
  .PARAMETER PD_ID
    Specifies the PD ID.

     .PARAMETER SANConnection
    Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection
    
  .Notes
    NAME: Set-StatPdch
    LASTEDIT: November 2019
    KEYWORDS: Set-StatPdch
   
  .Link
     http://www.hpe.com
 
 #Requires PS -Version 3.0

 #>

[CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$false,ValueFromPipeline=$true)]
        [switch]
        $Start,
        
        [Parameter(Position=0, Mandatory=$false,ValueFromPipeline=$true)]
        [switch]
        $Stop,
        
        [Parameter(Position=1, Mandatory=$false,ValueFromPipeline=$true)]
        [System.String]
        $PD_ID,        
        
        [Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true)]
        $SANConnection = $global:SANConnection        
    )            
    Write-DebugLog "Start: In Set-StatPdch - validating input values" $Debug 
    #check if connection object contents are null/empty
    if(!$SANConnection)
    {            
        #check if connection object contents are null/empty
        $Validate1 = Test-CLIConnection $SANConnection
        if($Validate1 -eq "Failed")
        {
            #check if global connection object contents are null/empty
            $Validate2 = Test-CLIConnection $global:SANConnection
            if($Validate2 -eq "Failed")
            {
                Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" "ERR:"
                Write-DebugLog "Stop: Exiting Set-StatPdch since SAN connection object values are null/empty" $Debug
                return "Unable to execute the cmdlet Set-StatPdchsince no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
            }
        }
    }
    $plinkresult = Test-PARCli
    if($plinkresult -match "FAILURE :")
    {
        write-debuglog "$plinkresult" "ERR:" 
        return $plinkresult
    }        
    $cmd1 = "setstatpdch "
    if ($Start)
    {
        $cmd1 += " start "
    }
    if ($Stop)
    {
        $cmd1 += " stop "
    }
    if($PD_ID)
    {
        $cmd2="showpd"
        $Result1 = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd2
        if($Result1 -match $PD_ID)
        {
            $cmd1 += " $PD_ID "
        }
        Else
        {
            write-debuglog "PD_ID parameter $PD_ID is Unavailable. Simply return " "INFO:"
            return "Error: PD_ID is Invalid ."
        }        
    }
    else
    {
        write-debuglog "PD_ID parameter $PD_ID is empty. Simply return " "INFO:"
        return "Error : PD_ID is mandatory . Command is not successful "
    }
    $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $cmd1
    write-debuglog " The Set-StatPdch command starts and stops the statistics collection mode for chunklets.->$cmd" "INFO:"
    if([string]::IsNullOrEmpty($Result))
    {
        $Result
        return  "Success : Executing Set-StatPdch "
    }
    else
    {
        $Result
        return  "FAILURE : While Executing Set-StatPdch "
    } 
} # End Set-StatPdch

##########################################################################
######################### FUNCTION Measure-SYS #########################
##########################################################################
Function Measure-SYS()
{
<#
  .SYNOPSIS
   Measure-SYS - Change the layout of a storage system.

  .DESCRIPTION
   The Measure-SYS command is used to analyze and detect poor layout
   and disk utilization across an entire storage system. The
   command runs a series of low level operations to re-balance
   resources on the system.

  .EXAMPLE
   Inter-node tuning options:

  .PARAMETER Cpg
   Limits the scope of a Measure-SYS operation to the named CPG(s).
   The specified CPGs must all be in the same domain as the user.
   If this option is specified the intra-node (tunenodech) phase is
   not run. -chunkpct and -tunenodech cannot be used with this
   option.

  .PARAMETER Nodepct
   Controls the detection of utilization imbalances between nodes.
   If any node has a PD devtype where the average utilization is
   more than <percentage> less than the average for that devtype,
   then detailed VV level analysis is performed. VVs which are
   poorly balanced between nodes will have a tune generated to
   correct the imbalance. <percentage> must be between 1 and 100.
   The default value is 3.

  .PARAMETER Spindlepct
   Specifies the percentage difference between node pairs that can
   exist before Measure-SYS warns that an imbalance exists. The percentage
   difference calculated between node pairs must be less than
   spindlepct. <percentage> must be between 1 and 200. 200 is the
   least restrictive and would allow the Measure-SYS to not warn with
   any difference in the number of PDs, while 1 is the most
   restrictive. 0 cannot be specified as this would always generate
   a warning. The default for <percentage> is 50 (allow for a 50%
   difference).

  .PARAMETER Force
   Bypass top-level inter-node balance checks and force detailed
   analysis of every VV. This option can be used to complete the
   re-balance of a relatively well balanced system where only a few
   volumes are unbalanced.

  .PARAMETER Slth
   Slice threshold. Volumes above this size will be tuned in slices.
   <threshold> must be in multiples of 128GiB. Minimum is 128GiB.
   Default is 2TiB. Maximum is 16TiB.

  .PARAMETER Slsz
   Slice size. Size of slice to use when volume size is greater than
   <threshold>. <size> must be in multiples of 128GiB. Minimum is 128GiB.
   Default is 2TiB. Maximum is 16TiB.
   
   Intra-node tuning options:

  .PARAMETER Chunkpct
   Controls the detection of any imbalance in PD chunklet
   allocation between PDs owned by individual nodes. If a PD has
   utilization of more than <percentage> less than the average for
   that device type, then that disk can potentially be tuned.
   <percentage> must be between 1 and 100. The default value is 10.
   This option cannot be used with the -cpg option.

  .PARAMETER Devtype
   Only tune the specified device type. Applies to the intra-node tune
   phase only and must be used with the -tunenodech option. Multiple
   devtypes can be specified. If -devtype is not used, all devtypes
   will be tuned when -tunenodech is specified.

  .PARAMETER Fulldiskpct
   This option is used in the intra-node tuning phase.
   If a PD has more than <percentage> of its capacity utilized, chunklet
   movement is used to reduce its usage to <percentage> before LD tuning
   is used to complete the rebalance. For example, if a PD is 98% utilized
   and <percentage> is 90, chunklets will be redistributed to other PDs until
   the utilization is less than 90%. If <percentage> is less than the
   devtype average then the calculated average will be used instead.
   <percentage> must be between 1 and 100. The default value is 90.

  .PARAMETER Maxchunk
   Specifies the maximum number of chunklets which can be moved
   from any PD in a single operation. <number> must be between
   1 and 8. The default value is 8.

  .PARAMETER Tunenodech
   Specifies that only intra-node rebalancing should be performed.
   
   LD tuning options:

  .PARAMETER Ss
   Trigger LD re-tuning for any LD where the stepsize value
   does not match the parent CPG.
   
   Cleaning and compacting options:

  .PARAMETER Cleanwait
   Maximum number of minutes to wait for chunklet cleaning after each tune.
   <value> must be between 0 (tunes will be started immediately) and
   720 (12 hours). The default value is 120 (2 hours).

  .PARAMETER Compactmb
   Used in the inter-node and LD tuning phases. Once tunes have moved an
   amount of space greater than <value> the source CPG will be compacted.
   <value> can be between 0 (compact after every tune) and 2TiB. The default
   is 512GiB.
   
   General tuning options:

  .PARAMETER Dr
   Specifies that the command is a dry run and that the system will
   not be tuned. The result of the analysis will be displayed.

  .PARAMETER Maxtasks
   Specifies the maximum number of individual inter-node tune tasks
   which the Measure-SYS command can run simultaneously. <number> must
   be between 1 and 8. The default value is 2.

  .PARAMETER Maxnodetasks
   Specifies the maximum number of tunenodech tasks which the Measure-SYS
   command can run simultaneously. <number> must be between 1 and 8.
   The default value is 1.

  .PARAMETER Waittask
   Wait for all tasks created by this command to complete before
   returning.

  .Notes
    NAME: Measure-SYS
    LASTEDIT January 2020
    KEYWORDS: Measure-SYS
  
  .Link
    http://www.hpe.com

 #Requires PS -Version 3.0
#>

[CmdletBinding()]
 param(
    [Parameter(Position=0, Mandatory=$false)]
    [System.String]
    $Cpg,

    [Parameter(Position=1, Mandatory=$false)]
    [System.String]
    $Nodepct,

    [Parameter(Position=2, Mandatory=$false)]
    [System.String]
    $Spindlepct,

    [Parameter(Position=3, Mandatory=$false)]
    [switch]
    $Force,

    [Parameter(Position=4, Mandatory=$false)]
    [System.String]
    $Slth,

    [Parameter(Position=5, Mandatory=$false)]
    [System.String]
    $Slsz,

    [Parameter(Position=6, Mandatory=$false)]
    [System.String]
    $Chunkpct,

    [Parameter(Position=7, Mandatory=$false)]
    [System.String]
    $Devtype,

    [Parameter(Position=8, Mandatory=$false)]
    [System.String]
    $Fulldiskpct,

    [Parameter(Position=9, Mandatory=$false)]
    [System.String]
    $Maxchunk,

    [Parameter(Position=10, Mandatory=$false)]
    [switch]
    $Tunenodech,

    [Parameter(Position=11, Mandatory=$false)]
    [switch]
    $Ss,

    [Parameter(Position=12, Mandatory=$false)]
    [System.String]
    $Cleanwait,

    [Parameter(Position=13, Mandatory=$false)]
    [System.String]
    $Compactmb,

    [Parameter(Position=14, Mandatory=$false)]
    [switch]
    $Dr,

    [Parameter(Position=15, Mandatory=$false)]
    [System.String]
    $Maxtasks,

    [Parameter(Position=16, Mandatory=$false)]
    [System.String]
    $Maxnodetasks,

    [Parameter(Position=17, Mandatory=$false)]
    [switch]
    $Waittask,

    [Parameter(Position=18, Mandatory=$false, ValueFromPipeline=$true)]
    $SANConnection = $global:SANConnection
 )

 Write-DebugLog "Start: In Measure-SYS - validating input values" $Debug 
 #check if connection object contents are null/empty
 if(!$SANConnection)
 {
    #check if connection object contents are null/empty
    $Validate1 = Test-CLIConnection $SANConnection
    if($Validate1 -eq "Failed")
    {
        #check if global connection object contents are null/empty
        $Validate2 = Test-CLIConnection $global:SANConnection
        if($Validate2 -eq "Failed")
        {
            Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" " ERR: "
            Write-DebugLog "Stop: Exiting Measure-SYS since SAN connection object values are null/empty" $Debug 
            Return "Unable to execute the cmdlet Measure-SYS since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
        }
    }
 }

 $plinkresult = Test-PARCli -SANConnection $SANConnection
 if($plinkresult -match "FAILURE :")
 {
   write-debuglog "$plinkresult"
   Return $plinkresult
 }

 $Cmd = " tunesys -f "

 if($Cpg)
 {
    $Cmd += " -cpg $Cpg "
 }

 if($Nodepct)
 {
    $Cmd += " -nodepct $Nodepct "
 }

 if($Spindlepct)
 {
    $Cmd += " -spindlepct $Spindlepct "
 }

 if($Force)
 {
    $Cmd += " -force "
 }

 if($Slth)
 {
    $Cmd += " -slth $Slth "
 }

 if($Slsz)
 {
    $Cmd += " -slsz $Slsz "
 }

 if($Chunkpct)
 {
    $Cmd += " -chunkpct $Chunkpct "
 }

 if($Devtype)
 {
    $Cmd += " -devtype $Devtype "
 }

 if($Fulldiskpct)
 {
    $Cmd += " -fulldiskpct $Fulldiskpct "
 }

 if($Maxchunk)
 {
    $Cmd += " -maxchunk $Maxchunk "
 }

 if($Tunenodech)
 {
    $Cmd += " -tunenodech "
 }

 if($Ss)
 {
    $Cmd += " -ss "
 }

 if($Cleanwait)
 {
    $Cmd += " -cleanwait $Cleanwait "
 }

 if($Compactmb)
 {
    $Cmd += " -compactmb $Compactmb "
 }

 if($Dr)
 {
    $Cmd += " -dr "
 }

 if($Maxtasks)
 {
    $Cmd += " -maxtasks $Maxtasks "
 }

 if($Maxnodetasks)
 {
    $Cmd += " -maxnodetasks $Maxnodetasks "
 }

 if($Waittask)
 {
    $Cmd += " -waittask "
 }

 $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
 Write-DebugLog "Executing Function : Measure-SYS Command -->" INFO: 
 
 Return $Result
} ## End-of Measure-SYS

##########################################################################
######################### FUNCTION Optimize-PD #######################
##########################################################################
Function Optimize-PD()
{
<#
  .SYNOPSIS
   Optimize-PD - show physical disks with high service times and optionally perform
   load balancing.

  .DESCRIPTION
   The Optimize-PD command identifies physical disks with high service times and
   optionally executes load balancing.

  .EXAMPLE
  
  .PARAMETER MaxSvct
    Specifies that either the maximum service time threshold (<msecs>) that
    is used to discover over-utilized physical disks, or the physical disks
    that have the highest maximum service times (highest). If a threshold is
    specified, then any disk whose maximum service time exceeds the
    specified threshold is considered a candidate for load balancing.
 
  .PARAMETER AvgSvct
    Specifies that either the average service time threshold (<msecs>) that
    is used to discover over-utilized physical disks, or the physical disks
    that have the highest average service time (highest). If a threshold is
    specified, any disk whose average service time exceeds the specified
    threshold is considered a candidate for load balancing.

  .PARAMETER Nodes
   Specifies that the display is limited to specified nodes and physical
   disks connected to those nodes. The node list is specified as a series
   of integers separated by commas (e.g. 1,2,3). The list can also consist
   of a single integer. If the node list is not specified, all disks on all
   nodes are displayed.

  .PARAMETER Slots
   Specifies that the display is limited to specified PCI slots and
   physical disks connected to those PCI slots. The slot list is specified
   as a series of integers separated by commas (e.g. 1,2,3). The list can
   also consist of a single integer. If the slot list is not specified, all
   disks on all slots are displayed.

  .PARAMETER Ports
   Specifies that the display is limited to specified ports and
   physical disks connected to those ports. The port list is specified
   as a series of integers separated by commas (e.g. 1,2,3). The list can
   also consist of a single integer. If the port list is not specified, all
   disks on all ports are displayed.

  .PARAMETER VV_Name
   Specifies that the physical disks used by the indicated virtual volume
   name are included for statistic sampling.

  .PARAMETER D
   Specifies the interval, in seconds, that statistics are sampled using an
   integer from 1 through 2147483. If no interval is specified, the option
   defaults to 30 seconds.

  .PARAMETER Iter
   Specifies that I/O statistics are sampled a specified number of times as
   indicated by the number argument using an integer greater than 0. If 0
   is specified, I/O statistics are looped indefinitely. If this option is
   not specified, the command defaults to 1 iteration.

  .PARAMETER Freq
   Specifies the interval, in minutes, that the command enters standby mode
   between iterations using an integer greater than 0. If this option is
   not specified, the number of iterations is looped indefinitely.

  .PARAMETER Vvlayout
   Specifies that the layout of the virtual volume is displayed. If this
   option is not specified, the layout of the virtual volume is not
   displayed.

  .PARAMETER Portstat
   Specifies that statistics for all disk ports in the system are
   displayed. If this option is not specified, statistics for ports are not
   displayed.

  .PARAMETER Pdstat
   Specifies that statistics for all physical disk, rather than only those
   with high service times, are displayed. If this option is not specified,
   statistics for all disks are not displayed.

  .PARAMETER Chstat
   Specifies that chunklet statistics are displayed. If not specified,
   chunklet statistics are not displayed. If this option is used with the

  .PARAMETER Maxpd
   Specifies that only the indicated number of physical disks with high
   service times are displayed. If this option is not specified, 10
   physical disks are displayed.

  .PARAMETER Movech_Auto
   Specifies that if any disks with unbalanced loads are detected that
   chunklets are moved from those disks for load balancing.
   auto
   Specifies that the system chooses source and destination chunklets.
   If not specified, you are prompted for selecting the source and
   destination chunklets.
   
  .PARAMETER Movech_Manual
   Specifies that if any disks with unbalanced loads are detected that
   chunklets are moved from those disks for load balancing.
   manual
   Specifies that the source and destination chunklets are manually
   entered.

  .Notes
    NAME: Optimize-PD
    LASTEDIT January 2020
    KEYWORDS: Optimize-PD
  
  .Link
    http://www.hpe.com

 #Requires PS -Version 3.0
#>

[CmdletBinding()]
 param(
    [Parameter(Position=0, Mandatory=$false)]
    [System.String]
    $Nodes,

    [Parameter(Position=1, Mandatory=$false)]
    [System.String]
    $Slots,

    [Parameter(Position=2, Mandatory=$false)]
    [System.String]
    $Ports,

    [Parameter(Position=3, Mandatory=$false)]
    [System.String]
    $VV_Name,

    [Parameter(Position=4, Mandatory=$false)]
    [System.String]
    $D,

    [Parameter(Position=5, Mandatory=$false)]
    [System.String]
    $Iter,

    [Parameter(Position=6, Mandatory=$false)]
    [System.String]
    $Freq,

    [Parameter(Position=7, Mandatory=$false)]
    [switch]
    $Vvlayout,

    [Parameter(Position=8, Mandatory=$false)]
    [switch]
    $Portstat,

    [Parameter(Position=9, Mandatory=$false)]
    [switch]
    $Pdstat,

    [Parameter(Position=10, Mandatory=$false)]
    [switch]
    $Chstat,

    [Parameter(Position=12, Mandatory=$false)]
    [System.String]
    $Maxpd,

    [Parameter(Position=13, Mandatory=$false)]
    [switch]
    $Movech_Auto,

    [Parameter(Position=14, Mandatory=$false)]
    [switch]
    $Movech_Manual,

    [Parameter(Position=15, Mandatory=$false)]
    [System.String]
    $MaxSvct,

    [Parameter(Position=16, Mandatory=$false)]
    [System.String]
    $AvgSvct,

    [Parameter(Position=17, Mandatory=$false, ValueFromPipeline=$true)]
    $SANConnection = $global:SANConnection
 )

 Write-DebugLog "Start: In Optimize-PD - validating input values" $Debug 
 #check if connection object contents are null/empty
 if(!$SANConnection)
 {
    #check if connection object contents are null/empty
    $Validate1 = Test-CLIConnection $SANConnection
    if($Validate1 -eq "Failed")
    {
        #check if global connection object contents are null/empty
        $Validate2 = Test-CLIConnection $global:SANConnection
        if($Validate2 -eq "Failed")
        {
            Write-DebugLog "Connection object is null/empty or the array address (FQDN/IP Address) or user credentials in the connection object are either null or incorrect. Create a valid connection object using New-CLIConnection or New-PoshSshConnection" " ERR: "
            Write-DebugLog "Stop: Exiting Optimize-PD since SAN connection object values are null/empty" $Debug 
            Return "Unable to execute the cmdlet Optimize-PD since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session."
        }
    }
 }

 $plinkresult = Test-PARCli -SANConnection $SANConnection
 if($plinkresult -match "FAILURE :")
 {
   write-debuglog "$plinkresult"
   Return $plinkresult
 }

 $Cmd = " tunepd "
 
 if($Nodes)
 {
    $Cmd += " -nodes $Nodes "
 }
 
 if($Slots)
 {
    $Cmd += " -slots $Slots "
 }
 
 if($Ports)
 {
    $Cmd += " -ports $Ports "
 }
 
 if($VV_Name)
 {
    $Cmd += " -vv $VV_Name "
 }
 
 if($D)
 {
    $Cmd += " -d $D "
 }
 
 if($Iter)
 {
    $Cmd += " -iter $Iter "
 }
 
 if($Freq)
 {
    $Cmd += " -freq $Freq "
 }
 
 if($Vvlayout)
 {
    $Cmd += " -vvlayout "
 }
 
 if($Portstat)
 {
    $Cmd += " -portstat"
 }
 
 if($Pdstat)
 {
    $Cmd += " -pdstat"
 }
 
 if($Chstat)
 {
    $Cmd += " -chstat"
 }
 
 if($Maxpd)
 {
    $Cmd += " -maxpd $Maxpd "
 }
 
 if($Movech_Auto)
 {
    $Cmd += " -movech auto "
 }
 
 if($Movech_Manual)
 {
    $Cmd += " -movech manual "
 } 
 
 if($MaxSvct)
 {
    $Cmd += " maxSvct $MaxSvct "
 } 
 elseif($AvgSvct)
 {
    $Cmd += " avgsvct $AvgSvct "
 }
 else
 {
    return    "Please select at list one from [ MaxSvct or AvgSvct]."
 }

 $Result = Invoke-CLICommand -Connection $SANConnection -cmds  $Cmd
 Write-DebugLog "Executing Function : Optimize-PD Command -->" INFO: 
 
 Return $Result
} ## End-of Optimize-PD

Export-ModuleMember Compress-VV , Get-HistChunklet , Get-HistLD , Get-HistPD , Get-HistPort , Get-HistRCopyVv , Get-HistVLun ,
Get-HistVv , Get-StatChunklet , Get-StatCMP , Get-StatCPU , Get-StatLD , Get-StatLink , Get-StatPD , Get-StatPort , Get-StatRcVv , 
Get-StatVLun , Get-StatVv , Set-Statch , Set-StatPdch , Measure-SYS , Optimize-PD
# SIG # Begin signature block
# MIIh0AYJKoZIhvcNAQcCoIIhwTCCIb0CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCN9SDNaxjxx9Fn
# L2dAEi9stYt7K8JNMewzXQ0/TgL82aCCEKswggUpMIIEEaADAgECAhB4Lu4fcD9z
# xUgD+jf1OoqlMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoT
# D1NlY3RpZ28gTGltaXRlZDEkMCIGA1UEAxMbU2VjdGlnbyBSU0EgQ29kZSBTaWdu
# aW5nIENBMB4XDTIxMDUyODAwMDAwMFoXDTIyMDUyODIzNTk1OVowgZAxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8x
# KzApBgNVBAoMIkhld2xldHQgUGFja2FyZCBFbnRlcnByaXNlIENvbXBhbnkxKzAp
# BgNVBAMMIkhld2xldHQgUGFja2FyZCBFbnRlcnByaXNlIENvbXBhbnkwggEiMA0G
# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDmclZSXJBXA55ijwwFymuq+Y4F/quF
# mm2vRdEmjFhzRvTpnGjIYtVcG11ka4JGCROmNVDZGAelnqcXn5DKO710j5SICTBC
# 5gXOLwga7usifs21W+lVT0BsZTiUnFu4hEhuFTlahJIEvPGVgO1GBcuItD2QqB4q
# 9j15GDI5nGBSzIyJKMctcIalxsTSPG1kiDbLkdfsIivhe9u9m8q6NRqDUaYYQTN+
# /qGCqVNannMapH8tNHqFb6VdzUFI04t7kFtSk00AkdD6qUvA4u8mL2bUXAYz8K5m
# nrFs+ckx5Yqdxfx68EO26Bt2qbz/oTHxE6FiVzsDl90bcUAah2l976ebAgMBAAGj
# ggGQMIIBjDAfBgNVHSMEGDAWgBQO4TqoUzox1Yq+wbutZxoDha00DjAdBgNVHQ4E
# FgQUlC56g+JaYFsl5QWK2WDVOsG+pCEwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB
# /wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJYIZIAYb4QgEBBAQDAgQQMEoG
# A1UdIARDMEEwNQYMKwYBBAGyMQECAQMCMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8v
# c2VjdGlnby5jb20vQ1BTMAgGBmeBDAEEATBDBgNVHR8EPDA6MDigNqA0hjJodHRw
# Oi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29SU0FDb2RlU2lnbmluZ0NBLmNybDBz
# BggrBgEFBQcBAQRnMGUwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQuc2VjdGlnby5j
# b20vU2VjdGlnb1JTQUNvZGVTaWduaW5nQ0EuY3J0MCMGCCsGAQUFBzABhhdodHRw
# Oi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAY+1n2UUlQU6Z
# VoEVaZKqZf/zrM/d7Kbx+S/t8mR2E+uNXStAnwztElqrm3fSr+5LMRzBhrYiSmea
# w9c/0c7qFO9mt8RR2q2uj0Huf+oAMh7TMuMKZU/XbT6tS1e15B8ZhtqOAhmCug6s
# DuNvoxbMpokYevpa24pYn18ELGXOUKlqNUY2qOs61GVvhG2+V8Hl/pajE7yQ4diz
# iP7QjMySms6BtZV5qmjIFEWKY+UTktUcvN4NVA2J0TV9uunDbHRt4xdY8TF/Clgz
# Z/MQHJ/X5yX6kupgDeN2t3o+TrColetBnwk/SkJEsUit0JapAiFUx44j4w61Qanb
# Zmi0tr8YGDCCBYEwggRpoAMCAQICEDlyRDr5IrdR19NsEN0xNZUwDQYJKoZIhvcN
# AQEMBQAwezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3Rl
# cjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQx
# ITAfBgNVBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0xOTAzMTIwMDAw
# MDBaFw0yODEyMzEyMzU5NTlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3
# IEplcnNleTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VS
# VFJVU1QgTmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0
# aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIAS
# ZRc2DsPbCLPQrFcNdu3NJ9NMrVCDYeKqIE0JLWQJ3M6Jn8w9qez2z8Hc8dOx1ns3
# KBErR9o5xrw6GbRfpr19naNjQrZ28qk7K5H44m/Q7BYgkAk+4uh0yRi0kdRiZNt/
# owbxiBhqkCI8vP4T8IcUe/bkH47U5FHGEWdGCFHLhhRUP7wz/n5snP8WnRi9UY41
# pqdmyHJn2yFmsdSbeAPAUDrozPDcvJ5M/q8FljUfV1q3/875PbcstvZU3cjnEjpN
# rkyKt1yatLcgPcp/IjSufjtoZgFE5wFORlObM2D3lL5TN5BzQ/Myw1Pv26r+dE5p
# x2uMYJPexMcM3+EyrsyTO1F4lWeL7j1W/gzQaQ8bD/MlJmszbfduR/pzQ+V+DqVm
# sSl8MoRjVYnEDcGTVDAZE6zTfTen6106bDVc20HXEtqpSQvf2ICKCZNijrVmzyWI
# zYS4sT+kOQ/ZAp7rEkyVfPNrBaleFoPMuGfi6BOdzFuC00yz7Vv/3uVzrCM7LQC/
# NVV0CUnYSVgaf5I25lGSDvMmfRxNF7zJ7EMm0L9BX0CpRET0medXh55QH1dUqD79
# dGMvsVBlCeZYQi5DGky08CVHWfoEHpPUJkZKUIGy3r54t/xnFeHJV4QeD2PW6WK6
# 1l9VLupcxigIBCU5uA4rqfJMlxwHPw1S9e3vL4IPAgMBAAGjgfIwge8wHwYDVR0j
# BBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFFN5v1qqK0rPVIDh
# 2JvAnfKyA2bLMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MBEGA1Ud
# IAQKMAgwBgYEVR0gADBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9k
# b2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQo
# MCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG
# 9w0BAQwFAAOCAQEAGIdR3HQhPZyK4Ce3M9AuzOzw5steEd4ib5t1jp5y/uTW/qof
# nJYt7wNKfq70jW9yPEM7wD/ruN9cqqnGrvL82O6je0P2hjZ8FODN9Pc//t64tIrw
# kZb+/UNkfv3M0gGhfX34GRnJQisTv1iLuqSiZgR2iJFODIkUzqJNyTKzuugUGrxx
# 8VvwQQuYAAoiAxDlDLH5zZI3Ge078eQ6tvlFEyZ1r7uq7z97dzvSxAKRPRkA0xdc
# Ods/exgNRc2ThZYvXd9ZFk8/Ub3VRRg/7UqO6AZhdCMWtQ1QcydER38QXYkqa4Ux
# FMToqWpMgLxqeM+4f452cpkMnf7XkQgWoaNflTCCBfUwggPdoAMCAQICEB2iSDBv
# myYY0ILgln0z02owDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMV
# VGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENl
# cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTEwMjAwMDAwMFoXDTMwMTIzMTIz
# NTk1OVowfDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3Rl
# cjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSQw
# IgYDVQQDExtTZWN0aWdvIFJTQSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3
# DQEBAQUAA4IBDwAwggEKAoIBAQCGIo0yhXoYn0nwli9jCB4t3HyfFM/jJrYlZilA
# hlRGdDFixRDtsocnppnLlTDAVvWkdcapDlBipVGREGrgS2Ku/fD4GKyn/+4uMyD6
# DBmJqGx7rQDDYaHcaWVtH24nlteXUYam9CflfGqLlR5bYNV+1xaSnAAvaPeX7Wpy
# vjg7Y96Pv25MQV0SIAhZ6DnNj9LWzwa0VwW2TqE+V2sfmLzEYtYbC43HZhtKn52B
# xHJAteJf7wtF/6POF6YtVbC3sLxUap28jVZTxvC6eVBJLPcDuf4vZTXyIuosB69G
# 2flGHNyMfHEo8/6nxhTdVZFuihEN3wYklX0Pp6F8OtqGNWHTAgMBAAGjggFkMIIB
# YDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUDuE6
# qFM6MdWKvsG7rWcaA4WtNA4wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYB
# Af8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwMGCCsGAQUFBwMIMBEGA1UdIAQKMAgw
# BgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5j
# b20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYB
# BQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20v
# VVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9v
# Y3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAE1jUO1HNEphpNve
# aiqMm/EAAB4dYns61zLC9rPgY7P7YQCImhttEAcET7646ol4IusPRuzzRl5ARokS
# 9At3WpwqQTr81vTr5/cVlTPDoYMot94v5JT3hTODLUpASL+awk9KsY8k9LOBN9O3
# ZLCmI2pZaFJCX/8E6+F0ZXkI9amT3mtxQJmWunjxucjiwwgWsatjWsgVgG10Xkp1
# fqW4w2y1z99KeYdcx0BNYzX2MNPPtQoOCwR/oEuuu6Ol0IQAkz5TXTSlADVpbL6f
# ICUQDRn7UJBhvjmPeo5N9p8OHv4HURJmgyYZSJXOSsnBf/M6BZv5b9+If8AjntIe
# Q3pFMcGcTanwWbJZGehqjSkEAnd8S0vNcL46slVaeD68u28DECV3FTSK+TbMQ5Lk
# uk/xYpMoJVcp+1EZx6ElQGqEV8aynbG8HArafGd+fS7pKEwYfsR7MUFxmksp7As9
# V1DSyt39ngVR5UR43QHesXWYDVQk/fBO4+L4g71yuss9Ou7wXheSaG3IYfmm8SoK
# C6W59J7umDIFhZ7r+YMp08Ysfb06dy6LN0KgaoLtO0qqlBCk4Q34F8W2WnkzGJLj
# tXX4oemOCiUe5B7xn1qHI/+fpFGe+zmAEc3btcSnqIBv5VPU4OOiwtJbGvoyJi1q
# V3AcPKRYLqPzW0sH3DJZ84enGm1YMYIQezCCEHcCAQEwgZAwfDELMAkGA1UEBhMC
# R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9y
# ZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSQwIgYDVQQDExtTZWN0aWdvIFJT
# QSBDb2RlIFNpZ25pbmcgQ0ECEHgu7h9wP3PFSAP6N/U6iqUwDQYJYIZIAWUDBAIB
# BQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIB
# BDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQg
# MUeM+nsQPcxhWCpWojH+UcA0zxpdNhztr39xI91XjL0wDQYJKoZIhvcNAQEBBQAE
# ggEAX2v5azjMrJiikUyRVseVjvPr2t80qgcDNH3f3tmxnzHK/ixcBOQg7PA6jA+s
# ItuevM/lfRQieYj7zNRcw2rDn4q0kcIdoTq4L1ASfLjcnX5k6rogeGYk0Edh6YKK
# VpDyI8QXrwKXA0SDTM1tk3kR6/lXVKK6qWRfuWYIAuI4Pm1vBT04j8Xfeoh5fqYr
# 2IppSU1h7V6K+tbNHj4RAM3rw6qHbUMESk8cuFoQzwEYpk8u1eD/0AFMZbsYZB2A
# tZ0HKUr97l7BzzKS0lmNRsiBAs1AC9mrVgqeGBCGb8t4lsYRqQxjW3tOgmpTxuz0
# GlMHGNTEuZzY3FTLwng2Yq5EVaGCDj0wgg45BgorBgEEAYI3AwMBMYIOKTCCDiUG
# CSqGSIb3DQEHAqCCDhYwgg4SAgEDMQ0wCwYJYIZIAWUDBAIBMIIBDwYLKoZIhvcN
# AQkQAQSggf8EgfwwgfkCAQEGC2CGSAGG+EUBBxcDMDEwDQYJYIZIAWUDBAIBBQAE
# IB0aaw2jpJjzjbRy6f6679Ltg09HEX59HNrsvGjAwdHEAhUAteL+OzIdzIGRs4UO
# Zbc3SVoBbm8YDzIwMjEwNjE5MDQyMDE1WjADAgEeoIGGpIGDMIGAMQswCQYDVQQG
# EwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5
# bWFudGVjIFRydXN0IE5ldHdvcmsxMTAvBgNVBAMTKFN5bWFudGVjIFNIQTI1NiBU
# aW1lU3RhbXBpbmcgU2lnbmVyIC0gRzOgggqLMIIFODCCBCCgAwIBAgIQewWx1Elo
# UUT3yYnSnBmdEjANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UEBhMCVVMxFzAVBgNV
# BAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
# b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
# b3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9v
# dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNjAxMTIwMDAwMDBaFw0zMTAx
# MTEyMzU5NTlaMHcxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jw
# b3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEoMCYGA1UE
# AxMfU3ltYW50ZWMgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBALtZnVlVT52Mcl0agaLrVfOwAa08cawyjwVrhpon
# ADKXak3JZBRLKbvC2Sm5Luxjs+HPPwtWkPhiG37rpgfi3n9ebUA41JEG50F8eRzL
# y60bv9iVkfPw7mz4rZY5Ln/BJ7h4OcWEpe3tr4eOzo3HberSmLU6Hx45ncP0mqj0
# hOHE0XxxxgYptD/kgw0mw3sIPk35CrczSf/KO9T1sptL4YiZGvXA6TMU1t/HgNuR
# 7v68kldyd/TNqMz+CfWTN76ViGrF3PSxS9TO6AmRX7WEeTWKeKwZMo8jwTJBG1kO
# qT6xzPnWK++32OTVHW0ROpL2k8mc40juu1MO1DaXhnjFoTcCAwEAAaOCAXcwggFz
# MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMGYGA1UdIARfMF0w
# WwYLYIZIAYb4RQEHFwMwTDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNv
# bS9jcHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwLgYI
# KwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRwOi8vcy5zeW1jZC5jb20wNgYD
# VR0fBC8wLTAroCmgJ4YlaHR0cDovL3Muc3ltY2IuY29tL3VuaXZlcnNhbC1yb290
# LmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAoBgNVHREEITAfpB0wGzEZMBcGA1UE
# AxMQVGltZVN0YW1wLTIwNDgtMzAdBgNVHQ4EFgQUr2PWyqNOhXLgp7xB8ymiOH+A
# dWIwHwYDVR0jBBgwFoAUtnf6aUhHn1MS1cLqBzJ2B9GXBxkwDQYJKoZIhvcNAQEL
# BQADggEBAHXqsC3VNBlcMkX+DuHUT6Z4wW/X6t3cT/OhyIGI96ePFeZAKa3mXfSi
# 2VZkhHEwKt0eYRdmIFYGmBmNXXHy+Je8Cf0ckUfJ4uiNA/vMkC/WCmxOM+zWtJPI
# TJBjSDlAIcTd1m6JmDy1mJfoqQa3CcmPU1dBkC/hHk1O3MoQeGxCbvC2xfhhXFL1
# TvZrjfdKer7zzf0D19n2A6gP41P3CnXsxnUuqmaFBJm3+AZX4cYO9uiv2uybGB+q
# ueM6AL/OipTLAduexzi7D1Kr0eOUA2AKTaD+J20UMvw/l0Dhv5mJ2+Q5FL3a5NPD
# 6itas5VYVQR9x5rsIwONhSrS/66pYYEwggVLMIIEM6ADAgECAhB71OWvuswHP6EB
# IwQiQU0SMA0GCSqGSIb3DQEBCwUAMHcxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRT
# eW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0
# d29yazEoMCYGA1UEAxMfU3ltYW50ZWMgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTAe
# Fw0xNzEyMjMwMDAwMDBaFw0yOTAzMjIyMzU5NTlaMIGAMQswCQYDVQQGEwJVUzEd
# MBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVj
# IFRydXN0IE5ldHdvcmsxMTAvBgNVBAMTKFN5bWFudGVjIFNIQTI1NiBUaW1lU3Rh
# bXBpbmcgU2lnbmVyIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQCvDoqq+Ny/aXtUF3FHCb2NPIH4dBV3Z5Cc/d5OAp5LdvblNj5l1SQgbTD53R2D
# 6T8nSjNObRaK5I1AjSKqvqcLG9IHtjy1GiQo+BtyUT3ICYgmCDr5+kMjdUdwDLNf
# W48IHXJIV2VNrwI8QPf03TI4kz/lLKbzWSPLgN4TTfkQyaoKGGxVYVfR8QIsxLWr
# 8mwj0p8NDxlsrYViaf1OhcGKUjGrW9jJdFLjV2wiv1V/b8oGqz9KtyJ2ZezsNvKW
# lYEmLP27mKoBONOvJUCbCVPwKVeFWF7qhUhBIYfl3rTTJrJ7QFNYeY5SMQZNlANF
# xM48A+y3API6IsW0b+XvsIqbAgMBAAGjggHHMIIBwzAMBgNVHRMBAf8EAjAAMGYG
# A1UdIARfMF0wWwYLYIZIAYb4RQEHFwMwTDAjBggrBgEFBQcCARYXaHR0cHM6Ly9k
# LnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9kLnN5bWNiLmNv
# bS9ycGEwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL3RzLWNybC53cy5zeW1hbnRl
# Yy5jb20vc2hhMjU2LXRzcy1jYS5jcmwwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgw
# DgYDVR0PAQH/BAQDAgeAMHcGCCsGAQUFBwEBBGswaTAqBggrBgEFBQcwAYYeaHR0
# cDovL3RzLW9jc3Aud3Muc3ltYW50ZWMuY29tMDsGCCsGAQUFBzAChi9odHRwOi8v
# dHMtYWlhLndzLnN5bWFudGVjLmNvbS9zaGEyNTYtdHNzLWNhLmNlcjAoBgNVHREE
# ITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtNjAdBgNVHQ4EFgQUpRMB
# qZ+FzBtuFh5fOzGqeTYAex0wHwYDVR0jBBgwFoAUr2PWyqNOhXLgp7xB8ymiOH+A
# dWIwDQYJKoZIhvcNAQELBQADggEBAEaer/C4ol+imUjPqCdLIc2yuaZycGMv41Up
# ezlGTud+ZQZYi7xXipINCNgQujYk+gp7+zvTYr9KlBXmgtuKVG3/KP5nz3E/5jMJ
# 2aJZEPQeSv5lzN7Ua+NSKXUASiulzMub6KlN97QXWZJBw7c/hub2wH9EPEZcF1rj
# pDvVaSbVIX3hgGd+Yqy3Ti4VmuWcI69bEepxqUH5DXk4qaENz7Sx2j6aescixXTN
# 30cJhsT8kSWyG5bphQjo3ep0YG5gpVZ6DchEWNzm+UgUnuW/3gC9d7GYFHIUJN/H
# ESwfAD/DSxTGZxzMHgajkF9cVIs+4zNbgg/Ft4YCTnGf6WZFP3YxggJaMIICVgIB
# ATCBizB3MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRp
# b24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5
# bWFudGVjIFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEHvU5a+6zAc/oQEjBCJBTRIw
# CwYJYIZIAWUDBAIBoIGkMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkq
# hkiG9w0BCQUxDxcNMjEwNjE5MDQyMDE1WjAvBgkqhkiG9w0BCQQxIgQgiKAFqVi9
# 4NAaejFB3Yxv+Qu5Ylqg/llwht8ifvlhca4wNwYLKoZIhvcNAQkQAi8xKDAmMCQw
# IgQgxHTOdgB9AjlODaXk3nwUxoD54oIBPP72U+9dtx/fYfgwCwYJKoZIhvcNAQEB
# BIIBAF7nWLy7UNRki0ZRdUkd5GVTfMVuhuf0sL5CE8VObTjy+gkBIclxuJ3sUyRx
# /pghOG/ea0xfFDjJEsJjAo/Km5UlwZAji8IMAT/BrLyEtvdbcrdt8rMF0mPS40Aj
# OmLx3D/2LsBQ/x8JD7DUdPX1kxpB5kS38cmANfPeUdwr6uAdvWhRUQHcm9DMqONr
# LomcMdUuCQzEO+EbERkU5rLBeymhlEfdxVnPOhr8jvUtjhkMI0Df5m0aPoS4WQCr
# x+OQ7FPlMuKbw246YWS41eQQVZsUjCW4yzTbcJ1Lp40ssHo6M2S1cOVqKtTVj/hv
# KzOoq+uCdROvvulWUD7mlJBFF0c=
# SIG # End signature block