CLI/Sparing.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: Sparing.psm1 ## Description: Sparing cmdlets ## ## Created: December 2019 ## Last Modified: December 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 Get-Spare ################### #################################################################### Function Get-Spare { <# .SYNOPSIS Displays information about chunklets in the system that are reserved for spares .DESCRIPTION Displays information about chunklets in the system that are reserved for spares and previously free chunklets selected for spares by the system. .EXAMPLE Get-Spare Displays information about chunklets in the system that are reserved for spares .PARAMETER used Display only used spare chunklets .PARAMETER count Number of loop iteration .PARAMETER SANConnection Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection .Notes NAME: Get-Spare LASTEDIT: December 2019 KEYWORDS: Get-Spare .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$false, ValueFromPipeline=$true)] [Switch] $used, [Parameter(Position=1, Mandatory=$false)] [Switch] $count, [Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true)] $SANConnection = $global:SANConnection ) Write-DebugLog "Start: In Get-Spare - 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-Spare since SAN connection object values are null/empty" $Debug return "Unable to execute the cmdlet Get-Spare since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session." } } } $cliresult1 = Test-PARCli -SANConnection $SANConnection if(($cliresult1 -match "FAILURE :")) { write-debuglog "$cliresult1" "ERR:" return $cliresult1 } $spareinfocmd = "showspare " if($used) { $spareinfocmd+= " -used " } write-debuglog "Get list of spare information cmd is => $spareinfocmd " "INFO:" $Result = Invoke-CLICommand -Connection $SANConnection -cmds $spareinfocmd $tempFile = [IO.Path]::GetTempFileName() $range1 = $Result.count - 3 $range = $Result.count if($count) { foreach ($s in $Result[0..$range] ) { if ($s -match "Total chunklets") { del $tempFile return $s } } } if($Result.count -eq 3) { del $tempFile return "No data available" } foreach ($s in $Result[0..$range1] ) { if (-not $s) { write-host "No data available" write-debuglog "No data available" "INFO:"\ del $tempFile return } $s= [regex]::Replace($s,"^ +","") $s= [regex]::Replace($s," +"," ") $s= [regex]::Replace($s," ",",") #write-host "s is $s=" Add-Content -Path $tempFile -Value $s } Import-Csv $tempFile del $tempFile } ### End Get-Spare ##################################################### ################### FUNCTION New-Spare ############## ##################################################### Function New-Spare { <# .SYNOPSIS Allocates chunklet resources as spares. Chunklets marked as spare are not used for logical disk creation and are reserved explicitly for spares, thereby guaranteeing a minimum amount of spare space. .DESCRIPTION Allocates chunklet resources as spares. Chunklets marked as spare are not used for logical disk creation and are reserved explicitly for spares, thereby guaranteeing a minimum amount of spare space. .EXAMPLE New-Spare -Pdid_chunkNumber "15:1" This example marks chunklet 1 as spare for physical disk 15 .EXAMPLE New-Spare –pos "1:0.2:3:121" This example specifies the position in a drive cage, drive magazine, physical disk,and chunklet number. –pos 1:0.2:3:121, where 1 is the drive cage, 0.2 is the drive magazine, 3 is the physical disk, and 121 is the chunklet number. .PARAMETER Pdid_chunkNumber Specifies the identification of the physical disk and the chunklet number on the disk. .PARAMETER pos Specifies the position of a specific chunklet identified by its position in a drive cage, drive magazine, physical disk, and chunklet number. .PARAMETER Partial Specifies that partial completion of the command is acceptable. .PARAMETER SANConnection Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection .Notes NAME: New-Spare LASTEDIT: December 2019 KEYWORDS: New-Spare .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$false,ValueFromPipeline=$true)] [System.String] $Pdid_chunkNumber, [Parameter(Position=1, Mandatory=$false,ValueFromPipeline=$true)] [System.String] $pos, [Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true)] [Switch] $Partial, [Parameter(Position=3, Mandatory=$false, ValueFromPipeline=$true)] $SANConnection = $global:SANConnection ) Write-DebugLog "Start: In New-Spare - 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 New-Spare since SAN connection object values are null/empty" $Debug return "Unable to execute the cmdlet New-Spare since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session." } } } $cliresult1 = Test-PARCli -SANConnection $SANConnection if(($cliresult1 -match "FAILURE :")) { write-debuglog "$cliresult1" "ERR:" return $cliresult1 } $newsparecmd = "createspare " if($Partial) { $newsparecmd +=" -p " } if(!(($pos) -or ($Pdid_chunkNumber))) { return "FAILURE : Please specify any one of the params , specify either -PDID_chunknumber or -pos" } if($Pdid_chunkNumber) { $newsparecmd += " -f $Pdid_chunkNumber" if($pos) { return "FAILURE : Do not specify both the params , specify either -PDID_chunknumber or -pos" } } if($pos) { $newsparecmd += " -f -pos $pos" if($Pdid_chunkNumber) { return "FAILURE : Do not specify both the params , specify either -PDID_chunknumber or -pos" } } $Result = Invoke-CLICommand -Connection $SANConnection -cmds $newsparecmd write-debuglog "Spare cmd -> $newsparecmd " "INFO:" #write-host "Result = $Result" if(-not $Result) { write-host "Success : Create spare chunklet " } else { return "$Result" } } ## End New-Spare ########################################################################## ########################### FUNCTION Move-Chunklet ####################### ########################################################################## Function Move-Chunklet { <# .SYNOPSIS Moves a list of chunklets from one physical disk to another. .DESCRIPTION Moves a list of chunklets from one physical disk to another. .EXAMPLE Move-Chunklet -SourcePD_Id 24 -SourceChunk_Position 0 -TargetPD_Id 64 -TargetChunk_Position 50 This example moves the chunklet in position 0 on disk 24, to position 50 on disk 64 and chunklet in position 0 on disk 25, to position 1 on disk 27 .PARAMETER SourcePD_Id Specifies that the chunklet located at the specified PD .PARAMETER SourceChunk_Position Specifies that the the chunklet’s position on that disk .PARAMETER TargetPD_Id specified target destination disk .PARAMETER TargetChunk_Position Specify target chunklet position .PARAMETER nowait Specifies that the command returns before the operation is completed. .PARAMETER Devtype Permits the moves to happen to different device types. .PARAMETER Perm Specifies that chunklets are permanently moved and the chunklets' original locations are not remembered. .PARAMETER Ovrd Permits the moves to happen to a destination even when there will be a loss of quality because of the move. .PARAMETER DryRun Specifies that the operation is a dry run .PARAMETER SANConnection Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection .Notes NAME: Move-Chunklet LASTEDIT: December 2019 KEYWORDS: Move-Chunklet .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$true,ValueFromPipeline=$true)] [System.String] $SourcePD_Id, [Parameter(Position=1, Mandatory=$true,ValueFromPipeline=$true)] [System.String] $SourceChunk_Position, [Parameter(Position=2, Mandatory=$false,ValueFromPipeline=$true)] [System.String] $TargetPD_Id, [Parameter(Position=3, Mandatory=$false,ValueFromPipeline=$true)] [System.String] $TargetChunk_Position, [Parameter(Position=5, Mandatory=$false)] [Switch] $DryRun, [Parameter(Position=6, Mandatory=$false)] [Switch] $NoWait, [Parameter(Position=7, Mandatory=$false)] [Switch] $Devtype, [Parameter(Position=8, Mandatory=$false)] [Switch] $Perm, [Parameter(Position=9, Mandatory=$false)] [Switch] $Ovrd, [Parameter(Position=10, Mandatory=$false, ValueFromPipeline=$true)] $SANConnection = $global:SANConnection ) Write-DebugLog "Start: In Move-Chunklet - 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 Move-Chunklet since SAN connection object values are null/empty" $Debug return "Unable to execute the cmdlet Move-Chunklet since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session." } } } $cliresult1 = Test-PARCli -SANConnection $SANConnection if(($cliresult1 -match "FAILURE :")) { write-debuglog "$cliresult1" "ERR:" return $cliresult1 } $movechcmd = "movech -f" if($DryRun) { $movechcmd += " -dr " } if($NoWait) { $movechcmd += " -nowait " } if($Devtype) { $movechcmd += " -devtype " } if($Perm) { $movechcmd += " -perm " } if($Ovrd) { $movechcmd += " -ovrd " } if(($SourcePD_Id)-and ($SourceChunk_Position)) { $params = $SourcePD_Id+":"+$SourceChunk_Position $movechcmd += " $params" if(($TargetPD_Id) -and ($TargetChunk_Position)) { $movechcmd += "-"+$TargetPD_Id+":"+$TargetChunk_Position } } else { return "FAILURE : No parameters specified " } write-debuglog "move chunklet cmd -> $movechcmd " "INFO:" $Result = Invoke-CLICommand -Connection $SANConnection -cmds $movechcmd if([string]::IsNullOrEmpty($Result)) { return "FAILURE : Disk $SourcePD_Id chunklet $SourceChunk_Position is not in use. " } if($Result -match "Move") { $range = $Result.count $tempFile = [IO.Path]::GetTempFileName() foreach ($s in $Result[0..$range] ) { $s= [regex]::Replace($s,"^ +","") $s= [regex]::Replace($s," +"," ") $s= [regex]::Replace($s," ",",") $s= $s.Trim() -replace 'Move,-State-,-Detailed_State-','Move,State,Detailed_State' Add-Content -Path $tempFile -Value $s } Import-Csv $tempFile del $tempFile } else { return $Result } } ## End Move-Chunklet ########################################################################## ######################## FUNCTION Move-ChunkletToSpare ################### ########################################################################## Function Move-ChunkletToSpare { <# .SYNOPSIS Moves data from specified Physical Disks (PDs) to a temporary location selected by the system .DESCRIPTION Moves data from specified Physical Disks (PDs) to a temporary location selected by the system .EXAMPLE Move-ChunkletToSpare -SourcePD_Id 66 -SourceChunk_Position 0 -force Examples shows chunklet 0 from physical disk 66 is moved to spare .EXAMPLE Move-ChunkletToSpare -SourcePD_Id 3 -SourceChunk_Position 0 .EXAMPLE Move-ChunkletToSpare -SourcePD_Id 4 -SourceChunk_Position 0 -nowait .EXAMPLE Move-ChunkletToSpare -SourcePD_Id 5 -SourceChunk_Position 0 -Devtype .PARAMETER SourcePD_Id Indicates that the move takes place from the specified PD .PARAMETER SourceChunk_Position Indicates that the move takes place from chunklet position .PARAMETER force Specifies that the command is forced. If this option is not used,it will do dry run,No chunklets are actually moved. .PARAMETER nowait Specifies that the command returns before the operation is completed. .PARAMETER Devtype Permits the moves to happen to different device types. .PARAMETER DryRun Specifies that the operation is a dry run .PARAMETER SANConnection Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection .Notes NAME: Move-ChunkletToSpare LASTEDIT: December 2019 KEYWORDS: Move-ChunkletToSpare .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] [System.String] $SourcePD_Id, [Parameter(Position=1, Mandatory=$true, ValueFromPipeline=$true)] [System.String] $SourceChunk_Position, [Parameter(Position=2, Mandatory=$false)] [Switch] $DryRun, [Parameter(Position=3, Mandatory=$false)] [Switch] $nowait, [Parameter(Position=4, Mandatory=$false)] [Switch] $Devtype, [Parameter(Position=5, Mandatory=$false, ValueFromPipeline=$true)] $SANConnection = $global:SANConnection ) Write-DebugLog "Start: In Move-ChunkletToSpare - 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 Move-ChunkletToSpare since SAN connection object values are null/empty" $Debug return "Unable to execute the cmdlet Move-ChunkletToSpare since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session." } } } $cliresult1 = Test-PARCli -SANConnection $SANConnection if(($cliresult1 -match "FAILURE :")) { write-debuglog "$cliresult1" "ERR:" return $cliresult1 } $movechcmd = "movechtospare -f" if($DryRun) { $movechcmd += " -dr " } if($nowait) { $movechcmd += " -nowait " } if($Devtype) { $movechcmd += " -devtype " } if(($SourcePD_Id) -and ($SourceChunk_Position)) { $params = $SourcePD_Id+":"+$SourceChunk_Position $movechcmd += " $params" } else { return "FAILURE : No parameters specified" } write-debuglog "cmd is -> $movechcmd " "INFO:" $Result = Invoke-CLICommand -Connection $SANConnection -cmds $movechcmd if([string]::IsNullOrEmpty($Result)) { return "FAILURE : " } elseif($Result -match "does not exist") { return $Result } elseif($Result.count -gt 1) { $range = $Result.count $tempFile = [IO.Path]::GetTempFileName() foreach ($s in $Result[0..$range] ) { #write-host "s = $s" $s= [regex]::Replace($s,"^ +","") $s= [regex]::Replace($s," +"," ") $s= [regex]::Replace($s," ",",") $s= $s.Trim() -replace 'Move,-State-,-Detailed_State-','Move,State,Detailed_State' Add-Content -Path $tempFile -Value $s } Import-Csv $tempFile del $tempFile } else { return $Result } } ## End Move-ChunkletToSpare ################################################################################ ################################### FUNCTION Move-PD ########################### ################################################################################ Function Move-PD { <# .SYNOPSIS Moves data from specified Physical Disks (PDs) to a temporary location selected by the system .DESCRIPTION Moves data from specified Physical Disks (PDs) to a temporary location selected by the system .EXAMPLE Move-PD -PD_Id 0 -force Example shows moves data from Physical Disks 0 to a temporary location .EXAMPLE Move-PD -PD_Id 0 Example displays a dry run of moving the data on physical disk 0 to free or sparespace .PARAMETER PD_Id Specifies the physical disk ID. This specifier can be repeated to move multiple physical disks. .PARAMETER force Specifies that the command is forced. If this option is not used,it will do dry run,No chunklets are actually moved. .PARAMETER DryRun Specifies that the operation is a dry run, and no physical disks are actually moved. .PARAMETER Nowait Specifies that the command returns before the operation is completed. .PARAMETER Devtype Permits the moves to happen to different device types. .PARAMETER Perm Makes the moves permanent, removes source tags after relocation .PARAMETER SANConnection Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection .Notes NAME: Move-PD LASTEDIT: December 2019 KEYWORDS: Move-PD .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position=1, Mandatory=$false)] [Switch] $DryRun, [Parameter(Position=2, Mandatory=$false)] [Switch] $nowait, [Parameter(Position=3, Mandatory=$false)] [Switch] $Devtype, [Parameter(Position=4, Mandatory=$true, ValueFromPipeline=$true)] [System.String] $PD_Id, [Parameter(Position=5, Mandatory=$false, ValueFromPipeline=$true)] $SANConnection = $global:SANConnection ) Write-DebugLog "Start: In Move-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 Move-PD since SAN connection object values are null/empty" $Debug return "Unable to execute the cmdlet Move-PD since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session." } } } $cliresult1 = Test-PARCli -SANConnection $SANConnection if(($cliresult1 -match "FAILURE :")) { write-debuglog "$cliresult1" "ERR:" return $cliresult1 } $movechcmd = "movepd -f" if($DryRun) { $movechcmd += " -dr " } if($nowait) { $movechcmd += " -nowait " } if($Devtype) { $movechcmd += " -devtype " } if($PD_Id) { $params = $PD_Id $movechcmd += " $params" } else { return "FAILURE : No parameters specified" } write-debuglog "Push physical disk command => $movechcmd " "INFO:" $Result = Invoke-CLICommand -Connection $SANConnection -cmds $movechcmd if([string]::IsNullOrEmpty($Result)) { return "FAILURE : $Result" } if($Result -match "FAILURE") { return $Result } if($Result -match "-Detailed_State-") { $range = $Result.count $tempFile = [IO.Path]::GetTempFileName() foreach ($s in $Result[0..$range] ) { $s= [regex]::Replace($s,"^ +","") $s= [regex]::Replace($s," +"," ") $s= [regex]::Replace($s," ",",") $s= $s.Trim() -replace 'Move,-State-,-Detailed_State-','Move,State,Detailed_State' Add-Content -Path $tempFile -Value $s } Import-Csv $tempFile del $tempFile } else { return $Result } } ## End Move-PD ################################################################################ ############################ FUNCTION Move-PDToSpare ########################### ################################################################################ Function Move-PDToSpare { <# .SYNOPSIS Moves data from specified Physical Disks (PDs) to a temporary location selected by the system. .DESCRIPTION Moves data from specified Physical Disks (PDs) to a temporary location selected by the system. .EXAMPLE Move-PDToSpare -PD_Id 0 -force Displays moving the data on PD 0 to free or spare space .EXAMPLE Move-PDToSpare -PD_Id 0 Displays a dry run of moving the data on PD 0 to free or spare space .EXAMPLE Move-PDToSpare -PD_Id 0 -DryRun .EXAMPLE Move-PDToSpare -PD_Id 0 -Vacate .EXAMPLE Move-PDToSpare -PD_Id 0 -Permanent .PARAMETER PD_Id Specifies the physical disk ID. .PARAMETER force Specifies that the command is forced. If this option is not used,it will do dry run,No chunklets are actually moved. .PARAMETER nowait Specifies that the command returns before the operation is completed. .PARAMETER Devtype Permits the moves to happen to different device types. .PARAMETER DryRun Specifies that the operation is a dry run. No physical disks are actually moved. .PARAMETER Vacate Deprecated, use -perm instead. .PARAMETER Permanent Makes the moves permanent, removes source tags after relocation. .PARAMETER Ovrd Permits the moves to happen to a destination even when there will be a loss of quality because of the move. This option is only necessary when the target of the move is not specified and the -perm flag is used. .PARAMETER SANConnection Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection .Notes NAME: Move-PDToSpare LASTEDIT: December 2019 KEYWORDS: Move-PDToSpare .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] [System.String] $PD_Id, [Parameter(Position=1, Mandatory=$false)] [Switch] $DryRun, [Parameter(Position=2, Mandatory=$false)] [Switch] $nowait, [Parameter(Position=3, Mandatory=$false)] [Switch] $DevType, [Parameter(Position=4, Mandatory=$false)] [Switch] $Vacate, [Parameter(Position=5, Mandatory=$false)] [Switch] $Permanent, [Parameter(Position=6, Mandatory=$false)] [Switch] $Ovrd, [Parameter(Position=7, Mandatory=$false, ValueFromPipeline=$true)] $SANConnection = $global:SANConnection ) Write-DebugLog "Start: In Move-PDToSpare - 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 Move-PDToSpare since SAN connection object values are null/empty" $Debug return "Unable to execute the cmdlet Move-PDToSpare since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session." } } } $cliresult1 = Test-PARCli -SANConnection $SANConnection if(($cliresult1 -match "FAILURE :")) { write-debuglog "$cliresult1" "ERR:" return $cliresult1 } $movechcmd = "movepdtospare -f" if($DryRun) { $movechcmd += " -dr " } if($nowait) { $movechcmd += " -nowait " } if($DevType) { $movechcmd += " -devtype " } if($Vacate) { $movechcmd += " -vacate " } if($Permanent) { $movechcmd += " -perm " } if($Ovrd) { $movechcmd += " -ovrd " } if($PD_Id) { $params = $PD_Id $movechcmd += " $params" } else { return "FAILURE : No parameters specified" } write-debuglog "push physical disk to spare cmd is => $movechcmd " "INFO:" $Result = Invoke-CLICommand -Connection $SANConnection -cmds $movechcmd if([string]::IsNullOrEmpty($Result)) { return "FAILURE : " } if($Result -match "Error:") { return $Result } if($Result -match "Move") { $range = $Result.count $tempFile = [IO.Path]::GetTempFileName() foreach ($s in $Result[0..$range] ) { #write-host "s = $s" $s= [regex]::Replace($s,"^ +","") $s= [regex]::Replace($s," +"," ") $s= [regex]::Replace($s," ",",") $s= $s.Trim() -replace 'Move,-State-,-Detailed_State-','Move,State,Detailed_State' Add-Content -Path $tempFile -Value $s } Import-Csv $tempFile del $tempFile } else { return $Result } } ## End Move-PDToSpare ################################################################################ ############################ FUNCTION Move-RelocPD ############################# ################################################################################ Function Move-RelocPD { <# .SYNOPSIS Command moves chunklets that were on a physical disk to the target of relocation. .DESCRIPTION Command moves chunklets that were on a physical disk to the target of relocation. .EXAMPLE Move-RelocPD -diskID 8 -DryRun moves chunklets that were on physical disk 8 that were relocated to another position, back to physical disk 8 .PARAMETER diskID Specifies that the chunklets that were relocated from specified disk (<fd>), are moved to the specified destination disk (<td>). If destination disk (<td>) is not specified then the chunklets are moved back to original disk (<fd>). The <fd> specifier is not needed if -p option is used, otherwise it must be used at least once on the command line. If this specifier is repeated then the operation is performed on multiple disks. .PARAMETER DryRun Specifies that the operation is a dry run. No physical disks are actually moved. .PARAMETER nowait Specifies that the command returns before the operation is completed. .PARAMETER partial Move as many chunklets as possible. If this option is not specified, the command fails if not all specified chunklets can be moved. .PARAMETER SANConnection Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection .Notes NAME: Move-RelocPD LASTEDIT: December 2019 KEYWORDS: Move-RelocPD .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$true,ValueFromPipeline=$true)] [System.String] $diskID, [Parameter(Position=1, Mandatory=$false)] [Switch] $DryRun, [Parameter(Position=2, Mandatory=$false)] [Switch] $nowait, [Parameter(Position=3, Mandatory=$false)] [Switch] $partial, [Parameter(Position=4, Mandatory=$false, ValueFromPipeline=$true)] $SANConnection = $global:SANConnection ) Write-DebugLog "Start: In Move-RelocPD - 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 Move-RelocPD since SAN connection object values are null/empty" $Debug return "Unable to execute the cmdlet Move-RelocPD since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session." } } } $cliresult1 = Test-PARCli -SANConnection $SANConnection if(($cliresult1 -match "FAILURE :")) { write-debuglog "$cliresult1" "ERR:" return $cliresult1 } $movechcmd = "moverelocpd -f " if($DryRun) { $movechcmd += " -dr " } if($nowait) { $movechcmd += " -nowait " } if($partial) { $movechcmd += " -partial " } if($diskID) { $movechcmd += " $diskID" } else { return "FAILURE : No parameters specified" } write-debuglog "move relocation pd cmd is => $movechcmd " "INFO:" $Result = Invoke-CLICommand -Connection $SANConnection -cmds $movechcmd if([string]::IsNullOrEmpty($Result)) { return "FAILURE : " } if($Result -match "Error:") { return $Result } if($Result -match "There are no chunklets to move") { return "There are no chunklets to move" } if($Result -match " Move -State- -Detailed_State-") { $range = $Result.count $tempFile = [IO.Path]::GetTempFileName() foreach ($s in $Result[0..$range] ) { $s= [regex]::Replace($s,"^ +","") $s= [regex]::Replace($s," +"," ") $s= [regex]::Replace($s," ",",") $s= $s.Trim() -replace 'Move,-State-,-Detailed_State-','Move,State,Detailed_State' Add-Content -Path $tempFile -Value $s } Import-Csv $tempFile del $tempFile } else { return $Result } } ## End Move-RelocPD ################################################################################ ############################ FUNCTION Remove-Spare ############################# ################################################################################ Function Remove-Spare { <# .SYNOPSIS Command removes chunklets from the spare chunklet list. .DESCRIPTION Command removes chunklets from the spare chunklet list. .EXAMPLE Remove-Spare -Pdid_chunkNumber "1:3" Example removes a spare chunklet from position 3 on physical disk 1: .EXAMPLE Remove-Spare –pos "1:0.2:3:121" Example removes a spare chuklet from the position in a drive cage, drive magazine, physical disk,and chunklet number. –pos 1:0.2:3:121, where 1 is the drive cage, 0.2 is the drive magazine, 3 is the physical disk, and 121 is the chunklet number. .PARAMETER Pdid_chunkNumber Specifies the identification of the physical disk and the chunklet number on the disk. .PARAMETER pos Specifies the position of a specific chunklet identified by its position in a drive cage, drive magazine, physical disk, and chunklet number. .PARAMETER SANConnection Specify the SAN Connection object created with New-CLIConnection or New-PoshSshConnection .Notes NAME: Remove-Spare LASTEDIT: December 2019 KEYWORDS: Remove-Spare .Link http://www.hpe.com #Requires PS -Version 3.0 #> [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$false,ValueFromPipeline=$true)] [System.String] $Pdid_chunkNumber, [Parameter(Position=1, Mandatory=$false,ValueFromPipeline=$true)] [System.String] $pos, [Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true)] $SANConnection = $global:SANConnection ) Write-DebugLog "Start: In Remove-Spare - 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 Remove-Spare since SAN connection object values are null/empty" $Debug return "Unable to execute the cmdlet Remove-Spare since no active storage connection session exists. `nUse New-PoshSSHConnection or New-CLIConnection to start a new storage connection session." } } } $cliresult1 = Test-PARCli -SANConnection $SANConnection if(($cliresult1 -match "FAILURE :")) { write-debuglog "$cliresult1" "ERR:" return $cliresult1 } $newsparecmd = "removespare " if(!(($Pdid_chunkNumber) -or ($pos))) { return "FAILURE: No parameters specified" } if($Pdid_chunkNumber) { $newsparecmd += " -f $Pdid_chunkNumber" if($pos) { return "FAILURE: Please select only one params, either -Pdid_chunkNumber or -pos " } } if($pos) { $newsparecmd += " -f -pos $pos" } $Result = Invoke-CLICommand -Connection $SANConnection -cmds $newsparecmd write-debuglog "Remove spare command -> newsparecmd " "INFO:" if($Result -match "removed") { write-debuglog "Success : Removed spare chunklet " "INFO:" return "Success : $Result" } else { return "$Result" } } ## End Remove-Spare Export-ModuleMember Get-Spare , New-Spare , Move-Chunklet , Move-ChunkletToSpare , Move-PD , Move-PDToSpare , Move-RelocPD , Remove-Spare # SIG # Begin signature block # MIIh0AYJKoZIhvcNAQcCoIIhwTCCIb0CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAa2qit1vOJbH9c # js7DaUS/X0zZoy2439Ol3htv/Swu8aCCEKswggUpMIIEEaADAgECAhB4Lu4fcD9z # 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 # OjcP8wUiXlN35g0dIVvp6A5dXu1Sake5NegcSgC0DakwDQYJKoZIhvcNAQEBBQAE # ggEAq2O/lOfNzQWbK2llx8w+o+SvZkb2Xr+FjFGKge4aiIUUONsq1b/K7HCqCNCS # f0zEBh5fNWFdqpTfTvycxVBBsOp5SDXi5O65CKPK/J2zHxhFfD0AfaP0qqpaoVK2 # V8tWHwnZQYedasRdUb6TDfZF6aVvCoQZLyafUfJwNFflepThHydn5R1iozxzmdFd # 4Ro/l7ntoEWfRfZBUCPzq81dVqia69/T9263j9ZfIutq2wHOUXymgrHTUKbmxGUG # JgDZY/icvVSBThHz7Bmt4IKbQwI2cfxQ0C8wSe8JOxkLJWUY24QSxoPoX8ubogbH # E5fbh+63Z6A5oOVnh3Kl3iuMR6GCDj0wgg45BgorBgEEAYI3AwMBMYIOKTCCDiUG # CSqGSIb3DQEHAqCCDhYwgg4SAgEDMQ0wCwYJYIZIAWUDBAIBMIIBDwYLKoZIhvcN # AQkQAQSggf8EgfwwgfkCAQEGC2CGSAGG+EUBBxcDMDEwDQYJYIZIAWUDBAIBBQAE # IF3WE1rVzuSGniY2mXoRXYYFy51FFQ1yTk+/NC1UCbJqAhUA9G3tiOS4OCOW8Jfl # /WzKj735DckYDzIwMjEwNjE5MDQyNDA0WjADAgEeoIGGpIGDMIGAMQswCQYDVQQG # 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 # hkiG9w0BCQUxDxcNMjEwNjE5MDQyNDA0WjAvBgkqhkiG9w0BCQQxIgQgYen0DqnM # JW6xJRP9PtCpEnkKaMhWD8gcKEPMEFPDjjYwNwYLKoZIhvcNAQkQAi8xKDAmMCQw # IgQgxHTOdgB9AjlODaXk3nwUxoD54oIBPP72U+9dtx/fYfgwCwYJKoZIhvcNAQEB # BIIBAD61QaQMsMgQbUpZhq9tcmnsITueLAEIhoOi0KFi/Vu8Hi4NNC386oLhQm/U # zmT9XZKbTKxU5QzqnIZTPrOMiCHnxE3C8xL2RKijacay5hP+Duv3rviRroZD+ViB # Fm6rbLQXroFMWjxTCbYxAWz6mDnEtMOTJS8rxE3xmzBCdmwDvyccZZXdVV5Fmh8c # iCX2AY7791WfF+w9xTuNUCGRDwVEG75MsASh7332ia+aVc1Ft0apmn60AzF/3LO6 # Jqgmd6owRryeSm3LbhSIf4RgcKdfukifybRAHhcV+G0I65K0XLg3WtRKNunJEnrq # d4bRyhS/iop8xtB7bSFR+rfdOgI= # SIG # End signature block |