GLOBAL/VS-Functions.psm1
#################################################################################### ## © 2019,2020 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: VS-Functions.psm1 ## Description: Common Module functions. ## ## Pre-requisites: Needs HPE 3PAR cli.exe for New-CLIConnection ## Needs POSH SSH Module for New-PoshSshConnection ## WSAPI uses HPE 3PAR CLI commands to start, configure, and modify the WSAPI server. ## For more information about using the CLI, see: ## • HPE 3PAR Command Line Interface Administrator Guide ## • HPE 3PAR Command Line Interface Reference ## ## Starting the WSAPI server : The WSAPI server does not start automatically. ## Using the CLI, enter startwsapi to manually start the WSAPI server. ## Configuring the WSAPI server: To configure WSAPI, enter setwsapi in the CLI. ## ## Created: June 2015 ## Last Modified: July 2020 ## ## History: v1.0 - Created ## v2.0 - Added support for HP3PAR CLI ## v2.1 - Added support for POSH SSH Module ## v2.2 - Added support for WSAPI ## v2.3 - Added Support for all CLI cmdlets ## v2.3.1 - Added support for primara array with wsapi ## v3.0 - Added Support for wsapi 1.7 ## v3.0 - Modularization ## v3.0.1 (07/30/2020) - Fixed the Show-RequestException function to show the actual error message ## ##################################################################################### # Generic connection object add-type @" public struct _Connection{ public string SessionId; public string Name; public string IPAddress; public string SystemVersion; public string Model; public string Serial; public string TotalCapacityMiB; public string AllocatedCapacityMiB; public string FreeCapacityMiB; public string UserName; public string epwdFile; public string CLIDir; public string CLIType; } "@ add-type @" public struct _SANConnection{ public string SessionId; public string Name; public string IPAddress; public string SystemVersion; public string Model; public string Serial; public string TotalCapacityMiB; public string AllocatedCapacityMiB; public string FreeCapacityMiB; public string UserName; public string epwdFile; public string CLIDir; public string CLIType; } "@ add-type @" public struct _TempSANConn{ public string SessionId; public string Name; public string IPAddress; public string SystemVersion; public string Model; public string Serial; public string TotalCapacityMiB; public string AllocatedCapacityMiB; public string FreeCapacityMiB; public string UserName; public string epwdFile; public string CLIDir; public string CLIType; } "@ add-type @" public struct _vHost { public string Id; public string Name; public string Persona; public string Address; public string Port; } "@ add-type @" public struct _vLUN { public string Name; public string LunID; public string PresentTo; public string vvWWN; } "@ add-type @" public struct _Version{ public string ReleaseVersionName; public string Patches; public string CliServer; public string CliClient; public string SystemManager; public string Kernel; public string TPDKernelCode; } "@ add-type @" public struct _vHostSet { public string ID; public string Name; public string Members; } "@ add-type @" public struct _vHostSetSummary { public string ID; public string Name; public string HOST_Cnt; public string VVOLSC; public string Flashcache; public string QoS; public string RC_host; } "@ add-type @" public struct WSAPIconObject{ public string Id; public string Name; public string SystemVersion; public string Patches; public string IPAddress; public string Model; public string SerialNumber; public string TotalCapacityMiB; public string AllocatedCapacityMiB; public string FreeCapacityMiB; public string Key; } "@ $global:LogInfo = $true $global:DisplayInfo = $true $global:SANConnection = $null #set in HPE3PARPSToolkit.psm1 $global:WsapiConnection = $null $global:ArrayType = $null $global:ArrayName = $null $global:ConnectionType = $null [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 if (!$global:VSVersion) { $global:VSVersion = "v3.0" } if (!$global:ConfigDir) { $global:ConfigDir = $null } $Info = "INFO:" $Debug = "DEBUG:" ############################################################################################################################################ ## FUNCTION Invoke-CLICommand ############################################################################################################################################ Function Invoke-CLICommand { <# .SYNOPSIS Execute a command against a device using HP3PAR CLI .DESCRIPTION Execute a command against a device using HP3PAR CLI .PARAMETER Connection Pointer to an object that contains passwordfile, HP3parCLI installed path and IP address .PARAMETER Cmds Command to be executed .EXAMPLE Invoke-CLICommand -Connection $global:SANConnection -Cmds "showsysmgr" The command queries a array to get the system information $global:SANConnection is created wiith the cmdlet New-CLIConnection or New-PoshSshConnection .Notes NAME: Invoke-CLICommand LASTEDIT: June 2012 KEYWORDS: Invoke-CLICommand .Link http://www.hpe.com #Requires HP3PAR CLI -Version 3.2.2 #> [CmdletBinding()] Param( [Parameter(Mandatory = $true)] $Connection, [Parameter(Mandatory = $true)] [string]$Cmds ) Write-DebugLog "Start: In Invoke-CLICommand - validating input values" $Debug #check if connection object contents are null/empty if (!$Connection) { $connection = [_Connection]$Connection #check if connection object contents are null/empty $Validate1 = Test-CLIConnection $Connection if ($Validate1 -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-*Connection and pass it as parameter" "ERR:" Write-DebugLog "Stop: Exiting Invoke-CLICommand since connection object values are null/empty" "ERR:" return } } #check if cmd is null/empty if (!$Cmds) { Write-DebugLog "No command is passed to the Invoke-CLICommand." "ERR:" Write-DebugLog "Stop: Exiting Invoke-CLICommand since command parameter is null/empty null/empty" "ERR:" return } $clittype = $Connection.cliType if ($clittype -eq "3parcli") { #write-host "In Invoke-CLICommand -> entered in clitype $clittype" Invoke-CLI -DeviceIPAddress $Connection.IPAddress -epwdFile $Connection.epwdFile -CLIDir $Connection.CLIDir -cmd $Cmds } elseif ($clittype -eq "SshClient") { $Result = Invoke-SSHCommand -Command $Cmds -SessionId $Connection.SessionId if ($Result.ExitStatus -eq 0) { return $Result.Output } else { $ErrorString = "Error :-" + $Result.Error + $Result.Output return $ErrorString } } else { return "FAILURE : Invalid cliType option selected/chosen" } }# End Invoke-CLICommand ############################################################################################################################################ ## FUNCTION SET-DEBUGLOG ############################################################################################################################################ Function Set-DebugLog { <# .SYNOPSIS Enables creating debug logs. .DESCRIPTION Creates Log folder and debug log files in the directory structure where the current modules are running. .EXAMPLE Set-DebugLog -LogDebugInfo $true -Display $true Set-DEbugLog -LogDebugInfo $true -Display $false .PARAMETER LogDebugInfo Specify the LogDebugInfo value to $true to see the debug log files to be created or $false if no debug log files are needed. .PARAMETER Display Specify the value to $true. This will enable seeing messages on the PS console. This switch is set to true by default. Turn it off by setting it to $false. Look at examples. .Notes NAME: Set-DebugLog LASTEDIT: 04/18/2012 KEYWORDS: DebugLog .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] [System.Boolean] $LogDebugInfo = $false, [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)] [System.Boolean] $Display = $true ) $global:LogInfo = $LogDebugInfo $global:DisplayInfo = $Display Write-DebugLog "Exiting function call Set-DebugLog. The value of logging debug information is set to $global:LogInfo and the value of Display on console is $global:DisplayInfo" $Debug } ############################################################################################################################################ ## FUNCTION Invoke-CLI ############################################################################################################################################ Function Invoke-CLI { <# .SYNOPSIS This is private method not to be used. For internal use only. .DESCRIPTION Executes 3par cli command with the specified paramaeters to get data from the specified virtual Connect IP Address .EXAMPLE Invoke-CLI -DeviceIPAddress "DeviceIPAddress" -CLIDir "Full Installed Path of cli.exe" -epwdFile "C:\loginencryptddetails.txt" -cmd "show server $serverID" .PARAMETER DeviceIPAddress Specify the IP address for Virtual Connect(VC) or Onboard Administrator(OA) or Storage or any other device .PARAMETER CLIDir Specify the absolute path of HP3PAR CLI's cli.exe .PARAMETER epwdFIle Specify the encrypted password file location .PARAMETER cmd Specify the command to be run for Virtual Connect .Notes NAME: Invoke-CLI LASTEDIT: 04/04/2012 KEYWORDS: 3parCLI .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] [System.String] $DeviceIPAddress = $null, [Parameter(Position = 1)] [System.String] #$CLIDir="C:\Program Files (x86)\Hewlett-Packard\HP 3PAR CLI\bin", $CLIDir = "C:\Program Files (x86)\Hewlett Packard Enterprise\HPE 3PAR CLI\bin", [Parameter(Position = 2)] [System.String] $epwdFile = "C:\HP3PARepwdlogin.txt", [Parameter(Position = 3)] [System.String] $cmd = "show -help" ) #write-host "Password in Invoke-CLI = ",$password Write-DebugLog "start:In function Invoke-CLI. Validating PUTTY path." $Debug if (Test-Path -Path $CLIDir) { $clifile = $CLIDir + "\cli.exe" if ( -not (Test-Path $clifile)) { Write-DebugLog "Stop: HP3PAR cli.exe file not found. Make sure the cli.exe file present in $CLIDir." "ERR:" return "HP3PAR cli.exe file not found. Make sure the cli.exe file present in $CLIDir. " } } else { $SANCObj = $global:SANConnection $CLIDir = $SANCObj.CLIDir } if (-not (Test-Path -Path $CLIDir )) { Write-DebugLog "Stop: HP3PAR cli.exe not found. Make sure the HP3PAR CLI installed" "ERR:" return "FAILURE : HP3PAR cli.exe not found. Make sure the HP3PAR CLI installed" } Write-DebugLog "Running: Calling function Invoke-CLI. Calling Test Network with IP Address $DeviceIPAddress" $Debug $Status = Test-Network $DeviceIPAddress if ($null -eq $Status) { Write-DebugLog "Stop: Calling function Invoke-CLI. Invalid IP Address" "ERR:" Throw "Invalid IP Address" } if ($Status -eq "Failed") { Write-DebugLog "Stop:Calling function Invoke-CLI. Unable to ping the device with IP $DeviceIPAddress. Check the IP address and try again." "ERR:" Throw "Unable to ping the device with IP $DeviceIPAddress. Check the IP address and try again." } Write-DebugLog "Running: Calling function Invoke-CLI. Check the Test Network with IP Address = $DeviceIPAddress. Invoking the HP3par cli...." $Debug try { #if(!($global:epwdFile)){ # Write-DebugLog "Stop:Please create encrpted password file first using New-CLIConnection" "ERR:" # return "`nFAILURE : Please create encrpted password file first using New-CLIConnection" #} #write-host "encrypted password file is $epwdFile" $pwfile = $epwdFile $test = $cmd.split(" ") #$test = [regex]::split($cmd," ") $fcmd = $test[0].trim() $count = $test.count $fcmd1 = $test[1..$count] #$cmdtemp= [regex]::Replace($fcmd1,"\n"," ") #$cmd2 = $fcmd+".bat" #$cmdFinal = " $cmd2 -sys $DeviceIPAddress -pwf $pwfile $fcmd1" #write-host "Command is : $cmdFinal" #Invoke-Expression $cmdFinal $CLIDir = "$CLIDir\cli.exe" $path = "$CLIDir\$fcmd" #write-host "command is 1: $cmd2 $fcmd1 -sys $DeviceIPAddress -pwf $pwfile" & $CLIDir -sys $DeviceIPAddress -pwf $pwfile $fcmd $fcmd1 if (!($? )) { return "FAILURE : FATAL ERROR" } } catch { $msg = "Calling function Invoke-CLI -->Exception Occured. " $msg += $_.Exception.ToString() Write-Exception $msg -error Throw $msg } Write-DebugLog "End:Invoke-CLI called. If no errors reported on the console, the HP3par cli with the cmd = $cmd for user $username completed Successfully" $Debug } ############################################################################################################################################ ## FUNCTION TEST-NETWORK ############################################################################################################################################ Function Test-Network ([string]$IPAddress) { <# .SYNOPSIS Pings the given IP Adress. .DESCRIPTION Pings the IP address to test for connectivity. .EXAMPLE Test-Network -IPAddress 10.1.1. .PARAMETER IPAddress Specify the IP address which needs to be pinged. .Notes NAME: Test-Network LASTEDITED: May 9 2012 KEYWORDS: Test-Network .Link http://www.hpe.com #Requires PS -Version 3.0 #> $Status = Test-IPFormat $IPAddress if ($Status -eq $null) { return $Status } try { $Ping = new-object System.Net.NetworkInformation.Ping $result = $ping.Send($IPAddress) $Status = $result.Status.ToString() } catch [Exception] { ## Server does not exist - skip it $Status = "Failed" } return $Status } ############################################################################################################################################ ## FUNCTION TEST-IPFORMAT ############################################################################################################################################ Function Test-IPFormat { <# .SYNOPSIS Validate IP address format .DESCRIPTION Validates the given value is in a valid IP address format. .EXAMPLE Test-IPFormat -Address .PARAMETER Address Specify the Address which will be validated to check if its a valid IP format. .Notes NAME: Test-IPFormat LASTEDIT: 05/09/2012 KEYWORDS: Test-IPFormat .Link http://www.hpe.com #Requires PS -Version 3.0 #> param([string]$Address = $(throw "Missing IP address parameter")) trap { $false; continue; } [bool][System.Net.IPAddress]::Parse($Address); } ############################################################################################################################################ ## FUNCTION Test-WSAPIConnection ############################################################################################################################################ Function Test-WSAPIConnection { [CmdletBinding()] Param( [Parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)] $WsapiConnection = $global:WsapiConnection ) Write-DebugLog "Request: Test-WSAPIConnection to Test if the session key exists." $Debug Write-DebugLog "Running: Validate the session key" $Debug $Validate = "Success" if (($null -eq $WsapiConnection) -or (-not ($WsapiConnection.IPAddress)) -or (-not ($WsapiConnection.Key))) { Write-DebugLog "Stop: No active WSAPI connection to an HPE Alletra 9000 or Primera or 3PAR storage system or the current session key is expired. Use New-WSAPIConnection cmdlet to connect back." Write-Host Write-Host "Stop: No active WSAPI connection to an HPE Alletra 9000 or Primera or 3PAR storage system or the current session key is expired. Use New-WSAPIConnection cmdlet to connect back." -foreground yellow Write-Host throw } else { Write-DebugLog " End: Connected" $Info } Write-DebugLog "End: Test-WSAPIConnection" $Debug } #END Test-WSAPIConnection ############################################################################################################################################ ## FUNCTION Invoke-WSAPI ############################################################################################################################################ function Invoke-WSAPI { [CmdletBinding()] Param ( [parameter(Position = 0, Mandatory = $true, HelpMessage = "Enter the resource URI (ex. /volumes)")] [ValidateScript( { if ($_.startswith('/')) { $true } else { throw "-URI must begin with a '/' (eg. /volumes) in its value. Correct the value and try again." } })] [string] $uri, [parameter(Position = 1, Mandatory = $true, HelpMessage = "Enter request type (GET POST DELETE)")] [string] $type, [parameter(Position = 2, Mandatory = $false, HelpMessage = "Body of the message")] [array] $body, [Parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)] $WsapiConnection = $global:WsapiConnection ) Write-DebugLog "Request: Request Invoke-WSAPI URL : $uri TYPE : $type " $Debug $ip = $WsapiConnection.IPAddress $key = $WsapiConnection.Key $arrtyp = $global:ArrayType if ($arrtyp.ToLower() -eq "3par") { $APIurl = 'https://' + $ip + ':8080/api/v1' } Elseif (($arrtyp.ToLower() -eq "primera") -or ($arrtyp.ToLower() -eq "alletra9000")) { $APIurl = 'https://' + $ip + ':443/api/v1' } else { return "Array type is Null." } $url = $APIurl + $uri #Construct header Write-DebugLog "Running: Constructing header." $Debug $headers = @{} $headers["Accept"] = "application/json" $headers["Accept-Language"] = "en" $headers["Content-Type"] = "application/json" $headers["X-HP3PAR-WSAPI-SessionKey"] = $key $data = $null #write-host "url = $url" # Request If ($type -eq 'GET') { Try { Write-DebugLog "Request: Invoke-WebRequest for Data, Request Type : $type" $Debug if ($PSEdition -eq 'Core') { $data = Invoke-WebRequest -Uri "$url" -Headers $headers -Method $type -UseBasicParsing -SkipCertificateCheck } else { $data = Invoke-WebRequest -Uri "$url" -Headers $headers -Method $type -UseBasicParsing } return $data } Catch { Write-DebugLog "Stop: Exception Occurs" $Debug Show-RequestException -Exception $_ return } } If (($type -eq 'POST') -or ($type -eq 'PUT')) { Try { Write-DebugLog "Request: Invoke-WebRequest for Data, Request Type : $type" $Debug $json = $body | ConvertTo-Json -Compress -Depth 10 #write-host "Invoke json = $json" if ($PSEdition -eq 'Core') { $data = Invoke-WebRequest -Uri "$url" -Body $json -Headers $headers -Method $type -UseBasicParsing -SkipCertificateCheck } else { $data = Invoke-WebRequest -Uri "$url" -Body $json -Headers $headers -Method $type -UseBasicParsing } return $data } Catch { Write-DebugLog "Stop: Exception Occurs" $Debug Show-RequestException -Exception $_ return } } If ($type -eq 'DELETE') { Try { Write-DebugLog "Request: Invoke-WebRequest for Data, Request Type : $type" $Debug if ($PSEdition -eq 'Core') { $data = Invoke-WebRequest -Uri "$url" -Headers $headers -Method $type -UseBasicParsing -SkipCertificateCheck } else { $data = Invoke-WebRequest -Uri "$url" -Headers $headers -Method $type -UseBasicParsing } return $data } Catch { Write-DebugLog "Stop: Exception Occurs" $Debug Show-RequestException -Exception $_ return } } Write-DebugLog "End: Invoke-WSAPI" $Debug } #END Invoke-WSAPI ############################################################################################################################################ ## FUNCTION Format-Result ############################################################################################################################################ function Format-Result { [CmdletBinding()] Param ( [parameter(Mandatory = $true)] $dataPS, [parameter(Mandatory = $true)] [string]$TypeName ) Begin { $AlldataPS = @() } Process { # Add custom type to the resulting oject for formating purpose Foreach ($data in $dataPS) { If ($data) { $data.PSObject.TypeNames.Insert(0, $TypeName) } $AlldataPS += $data } } End { return $AlldataPS } } #END Format-Result ############################################################################################################################################ ## FUNCTION Show-RequestException ############################################################################################################################################ Function Show-RequestException { [CmdletBinding()] Param( [parameter(Mandatory = $true)] $Exception ) #Exception catch when there's a connectivity problem with the array If ($Exception.Exception.InnerException) { Write-Host "Please verify the connectivity with the array. Retry with the parameter -Verbose for more informations" -foreground yellow Write-Host Write-Host "Status: $($Exception.Exception.Status)" -foreground yellow Write-Host "Error code: $($Exception.Exception.Response.StatusCode.value__)" -foreground yellow Write-Host "Message: $($Exception.Exception.InnerException.Message)" -foreground yellow Write-Host Write-DebugLog "Stop: Please verify the connectivity with the array. Retry with the parameter -Verbose for more informations." $Debug Write-DebugLog "Stop: Status: $($Exception.Exception.Status)" $Debug Write-DebugLog "Stop: Error code: $($Exception.Exception.Response.StatusCode.value__)" $Debug Write-DebugLog "Stop: Message: $($Exception.Exception.InnerException.Message)" $Debug Return $Exception.Exception.Status } #Exception catch when the rest request return an error If ($_.Exception.Response) { $result = ConvertFrom-Json -InputObject $Exception.ErrorDetails.Message Write-Host "The array sends an error message: $($result.desc)." -foreground yellow Write-Host Write-Host "Status: $($Exception.Exception.Status)" -foreground yellow Write-Host "Error code: $($result.code)" -foreground yellow Write-Host "HTTP Error code: $($Exception.Exception.Response.StatusCode.value__)" -foreground yellow Write-Host "Message: $($result.desc)" -foreground yellow Write-Host Write-DebugLog "Stop:The array sends an error message: $($Exception.Exception.Message)." $Debug Write-DebugLog "Stop: Status: $($Exception.Exception.Status)" $Debug Write-DebugLog "Stop: Error code: $($result.code)" $Debug Write-DebugLog "Stop: HTTP Error code: $($Exception.Exception.Response.StatusCode.value__)" $Debug Write-DebugLog "Stop: Message: $($result.desc)" $Debug Return $result.code } Write-DebugLog "End: Show-RequestException" $Debug } #END Show-RequestException ############################################################################################################################################ ## FUNCTION TEST-FILEPATH ############################################################################################################################################ Function Test-FilePath ([String[]]$ConfigFiles) { <# .SYNOPSIS Validate an array of file paths. For Internal Use only. .DESCRIPTION Validates if a path specified in the array is valid. .EXAMPLE Test-FilePath -ConfigFiles .PARAMETER -ConfigFiles Specify an array of config files which need to be validated. .Notes NAME: Test-FilePath LASTEDIT: 05/30/2012 KEYWORDS: Test-FilePath .Link http://www.hpe.com #Requires PS -Version 3.0 #> Write-DebugLog "Start: Entering function Test-FilePath." $Debug $Validate = @() if (-not ($global:ConfigDir)) { Write-DebugLog "STOP: Configuration Directory path is not set. Run scripts Init-PS-Session.ps1 OR import module VS-Functions.psm1 and run cmdlet Set-ConfigDirectory" "ERR:" $Validate = @("Configuration Directory path is not set. Run scripts Init-PS-Session.ps1 OR import module VS-Functions.psm1 and run cmdlet Set-ConfigDirectory.") return $Validate } foreach ($argConfigFile in $ConfigFiles) { if (-not (Test-Path -Path $argConfigFile )) { $FullPathConfigFile = $global:ConfigDir + $argConfigFile if (-not (Test-Path -Path $FullPathConfigFile)) { $Validate = $Validate + @(, "Path $FullPathConfigFile not found.") } } } Write-DebugLog "End: Leaving function Test-FilePath." $Debug return $Validate } Function Test-PARCLi { <# .SYNOPSIS Test-PARCli object path .EXAMPLE Test-PARCli t .Notes NAME: Test-PARCli LASTEDIT: 06/16/2015 KEYWORDS: Test-PARCli .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)] $SANConnection = $global:SANConnection ) $SANCOB = $SANConnection $clittype = $SANCOB.CliType Write-DebugLog "Start : in Test-PARCli function " "INFO:" if ($clittype -eq "3parcli") { Test-PARCliTest -SANConnection $SANConnection } elseif ($clittype -eq "SshClient") { Test-SSHSession -SANConnection $SANConnection } else { return "FAILURE : Invalid cli type" } } Function Test-SSHSession { <# .SYNOPSIS Test-SSHSession .PARAMETER pathFolder Test-SSHSession .EXAMPLE Test-SSHSession -SANConnection $SANConnection .Notes NAME: Test-SSHSession LASTEDIT: 14/03/2017 KEYWORDS: Test-SSHSession .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param ( [Parameter(Position = 1, Mandatory = $false, ValueFromPipeline = $true)] $SANConnection = $global:SANConnection ) $Result = Get-SSHSession | fl if ($Result.count -gt 1) { } else { return "`nFAILURE : FATAL ERROR : Please check your connection and try again" } } Function Test-PARCliTest { <# .SYNOPSIS Test-PARCli pathFolder .PARAMETER pathFolder Specify the names of the HP3par cli path .EXAMPLE Test-PARCli path -pathFolder c:\test .Notes NAME: Test-PARCliTest LASTEDIT: 06/16/2015 KEYWORDS: Test-PARCliTest .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $false)] [System.String] #$pathFolder = "C:\Program Files (x86)\Hewlett-Packard\HP 3PAR CLI\bin\", $pathFolder = "C:\Program Files (x86)\Hewlett Packard Enterprise\HPE 3PAR CLI\bin", [Parameter(Position = 1, Mandatory = $false, ValueFromPipeline = $true)] $SANConnection = $global:SANConnection ) $SANCOB = $SANConnection $DeviceIPAddress = $SANCOB.IPAddress Write-DebugLog "Start : in Test-PARCli function " "INFO:" #Write-host "Start : in Test-PARCli function " $CLIDir = $pathFolder if (Test-Path -Path $CLIDir) { $clitestfile = $CLIDir + "\cli.exe" if ( -not (Test-Path $clitestfile)) { return "FAILURE : HP3PAR cli.exe file was not found. Make sure you have cli.exe file under $CLIDir " } $pwfile = $SANCOB.epwdFile $cmd2 = "help.bat" #$cmdFinal = "$cmd2 -sys $DeviceIPAddress -pwf $pwfile" & $cmd2 -sys $DeviceIPAddress -pwf $pwfile #Invoke-Expression $cmdFinal if (!($?)) { return "`nFAILURE : FATAL ERROR" } } else { $SANCObj = $SANConnection $CLIDir = $SANCObj.CLIDir $clitestfile = $CLIDir + "\cli.exe" if (-not (Test-Path $clitestfile )) { return "FAILURE : HP3PAR cli.exe was not found. Make sure you have cli.exe file under $CLIDir " } $pwfile = $SANCObj.epwdFile $cmd2 = "help.bat" #$cmdFinal = "$cmd2 -sys $DeviceIPAddress -pwf $pwfile" #Invoke-Expression $cmdFinal & $cmd2 -sys $DeviceIPAddress -pwf $pwfile if (!($?)) { return "`nFAILURE : FATAL ERROR" } } Write-DebugLog "Stop : in Test-PARCli function " "INFO:" } ############################################################################################################################################ ## FUNCTION Test-CLIConnection ############################################################################################################################################ Function Test-CLIConnection ($SANConnection) { <# .SYNOPSIS Validate CLI connection object. For Internal Use only. .DESCRIPTION Validates if CLI connection object for VC and OA are null/empty .EXAMPLE Test-CLIConnection -SANConnection .PARAMETER -SANConnection Specify the VC or OA connection object. Ideally VC or Oa connection object is obtained by executing New-VCConnection or New-OAConnection. .Notes NAME: Test-CLIConnection LASTEDIT: 05/09/2012 KEYWORDS: Test-CLIConnection .Link http://www.hpe.com #Requires PS -Version 3.0 #> $Validate = "Success" if (($SANConnection -eq $null) -or (-not ($SANConnection.AdminName)) -or (-not ($SANConnection.Password)) -or (-not ($SANConnection.IPAddress)) -or (-not ($SANConnection.SSHDir))) { #Write-DebugLog "Connection object is null/empty or username, password,IP address are null/empty. Create a valid connection object and retry" "ERR:" $Validate = "Failed" } return $Validate } Export-ModuleMember Test-IPFormat , Test-WSAPIConnection , Invoke-WSAPI , Format-Result , Show-RequestException , Test-SSHSession , Set-DebugLog , Test-Network , Invoke-CLI , Invoke-CLICommand , Test-FilePath , Test-PARCli , Test-PARCliTest, Test-CLIConnection # SIG # Begin signature block # MIIh0AYJKoZIhvcNAQcCoIIhwTCCIb0CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDxBbZvOwfZzVVJ # 4YFlp6bz8II4cllVPj4U+bi7MIsD2aCCEKswggUpMIIEEaADAgECAhB4Lu4fcD9z # 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 # BOcsdRja+DFqTg9y7xixCOHZG1153m6oTjxFAA/x6SwwDQYJKoZIhvcNAQEBBQAE # ggEAVaud2N2ZXMr8gjbZxK2Xw2GVNgpCX+Ob1vkeOQ/Ar+U4UKARYBVpq/YT0SKA # F81xizfabGSXd4M96OeAjU2shyU1L4hiv3GYHpeLJoLi0osxivvLQeQyF4tpIsP4 # J5aJ7+O7dmR9mnk7mdFLJv9/YrYNTlliZ3EvWVk77TuN0+/kkde1H4feWmPF3EHw # F+g1Ex6VUTBK+oNQeBmAgs2WEqorTA87+hBfoP6fB8em6y8JmUtT8Eam+zK/ZdB3 # 8YCeUIUWUcAJcFjfm2AybGMGtA6yeZyN3cU8VyX/vjoR7T9kcoiHaD9kx5vVfnEE # uOrHPBwGhQuFbFC58m1gdexGMKGCDj0wgg45BgorBgEEAYI3AwMBMYIOKTCCDiUG # CSqGSIb3DQEHAqCCDhYwgg4SAgEDMQ0wCwYJYIZIAWUDBAIBMIIBDwYLKoZIhvcN # AQkQAQSggf8EgfwwgfkCAQEGC2CGSAGG+EUBBxcDMDEwDQYJYIZIAWUDBAIBBQAE # IJ6ezFucObY0Mm6hxHnQXxdGGVBAr45eMEsXPIG1bGB7AhUArvtaOKe0Tq0XI1pS # 5prKEC5Ib4UYDzIwMjEwNjE5MDQ1OTE2WjADAgEeoIGGpIGDMIGAMQswCQYDVQQG # 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 # hkiG9w0BCQUxDxcNMjEwNjE5MDQ1OTE2WjAvBgkqhkiG9w0BCQQxIgQgVRG9QPs1 # 1gdfxsMcrzC7x+EoZavCHzMuIGtDyMgTeMQwNwYLKoZIhvcNAQkQAi8xKDAmMCQw # IgQgxHTOdgB9AjlODaXk3nwUxoD54oIBPP72U+9dtx/fYfgwCwYJKoZIhvcNAQEB # BIIBADXr4w5FBbTo+INYs4kFT/CyLAwcjVqS0Yv6zHWPojQud+b7VsoUuGccRg55 # aVifDof7tgeYyNc6vh0Njq5xj2QUi6ahhWkrGa3XxvuMAsPaQxSMHWyZ+hP3gIsI # ahw+o319JwCKFb/giJcWHzTk2cocAN45Wg6b+ynJifpZltJccn28CQ9FMoO2CL86 # O9PkluI0cO8vOCv55aclOFCOWfuEbp2NAGe5xDZqg/4ASdELIBRR14aWNQeTNdih # Q32k+Y0wnt2KtlflEq6yILIeEMAdGl3RACp5EEaF+kT1PbzSrLVzQSGoEKtjEMDE # WphFXZ8L/Kqi4jXsnVSNWRpGqP0= # SIG # End signature block |