Enterprise.ps1
function getEnterprise { [KeeperSecurity.Authentication.IAuthentication] $auth = $Script:Context.Auth if (-not $auth) { Write-Error -Message "Not Connected" -ErrorAction Stop } if (-not $auth.AuthContext.IsEnterpriseAdmin) { Write-Error -Message "Not an Enterprise Administrator" -ErrorAction Stop } $enterprise = $Script:Context.Enterprise if (-not $enterprise) { $enterprise = New-Object Enterprise $enterprise.enterpriseData = New-Object KeeperSecurity.Enterprise.EnterpriseData $enterprise.roleData = New-Object KeeperSecurity.Enterprise.RoleData $enterprise.mspData = New-Object KeeperSecurity.Enterprise.ManagedCompanyData [KeeperSecurity.Enterprise.EnterpriseDataPlugin[]] $plugins = $enterprise.enterpriseData, $enterprise.roleData, $enterprise.mspData $enterprise.loader = New-Object KeeperSecurity.Enterprise.EnterpriseLoader($auth, $plugins) $enterprise.loader.Load().GetAwaiter().GetResult() | Out-Null if ($enterprise.enterpriseData.EnterpriseLicense.licenseStatus.StartsWith("msp")) { $enterprise.ManagedCompanies = @{} } $Script:Context.Enterprise = $enterprise $Script:Context.ManagedCompanyId = 0 } if ($Script:Context.ManagedCompanyId -gt 0) { if ($null -ne $enterprise.ManagedCompanies) { $enterpriseMc = $enterprise.ManagedCompanies[$Script:Context.ManagedCompanyId] if ($null -eq $enterpriseMc) { $authMc = New-Object KeeperSecurity.Enterprise.ManagedCompanyAuth $authMc.LoginToManagedCompany($Script:Context.Enterprise.loader, $Script:Context.ManagedCompanyId).GetAwaiter().GetResult() | Out-Null $enterpriseMc = New-Object Enterprise $enterpriseMc.enterpriseData = New-Object KeeperSecurity.Enterprise.EnterpriseData $enterpriseMc.roleData = New-Object KeeperSecurity.Enterprise.RoleData [KeeperSecurity.Enterprise.EnterpriseDataPlugin[]] $plugins = $enterpriseMc.enterpriseData, $enterpriseMc.roleData $enterpriseMc.loader = New-Object KeeperSecurity.Enterprise.EnterpriseLoader($authMc, $plugins) $enterpriseMc.loader.Load().GetAwaiter().GetResult() | Out-Null $enterprise.ManagedCompanies[$Script:Context.ManagedCompanyId] = $enterpriseMc } $enterprise = $enterpriseMc } else { $Script:Context.ManagedCompanyId = 0 } } return $enterprise } function Sync-KeeperEnterprise { <# .Synopsis Sync Keeper Enterprise Information #> [CmdletBinding()] [Enterprise]$enterprise = getEnterprise $task = $enterprise.loader.Load() $task.GetAwaiter().GetResult() | Out-Null } New-Alias -Name ked -Value Sync-KeeperEnterprise function Get-KeeperEnterpriseUser { <# .Synopsis Get a list of enterprise users #> [CmdletBinding()] [Enterprise]$enterprise = getEnterprise return $enterprise.enterpriseData.Users } New-Alias -Name keu -Value Get-KeeperEnterpriseUser function Get-KeeperEnterpriseTeam { <# .Synopsis Get a list of enterprise teams #> [CmdletBinding()] [Enterprise]$enterprise = getEnterprise return $enterprise.enterpriseData.Teams } New-Alias -Name ket -Value Get-KeeperEnterpriseTeam $Keeper_TeamNameCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $result = @() [Enterprise]$enterprise = $Script:Context.Enterprise if (-not $enterprise) { return $null } if ($wordToComplete) { $to_complete = $wordToComplete + '*' } else { $to_complete = '*' } foreach ($team in $enterprise.enterpriseData.Teams) { if ($team.Name -like $to_complete) { $teamName = $team.Name if ($teamName -match '[\s'']') { $teamName = $teamName -replace '''', '''''' $teamName = "'${teamName}'" } $result += $teamName } } if ($result.Count -gt 0) { return $result } else { return $null } } function Get-KeeperEnterpriseTeamUser { <# .Synopsis Get a list of enterprise users for team #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)]$Team ) [Enterprise]$enterprise = getEnterprise $enterpriseData = $enterprise.enterpriseData $uid = $null if ($Team -is [String]) { $uids = Get-KeeperEnterpriseTeam | Where-Object { $_.Uid -ceq $Team -or $_.Name -ieq $Team } | Select-Object -Property Uid if ($uids.Length -gt 1) { Write-Error -Message "Team name `"$Team`" is not unique. Use Team UID" -ErrorAction Stop } if ($null -ne $uids.Uid) { $uid = $uids.Uid } } elseif ($null -ne $Team.Uid) { $uid = $Team.Uid } if ($uid) { $team = $null if ($enterpriseData.TryGetTeam($uid, [ref]$team)) { foreach ($userId in $enterpriseData.GetUsersForTeam($uid)) { $user = $null foreach ($userId in $enterpriseData.TryGetUserById($userId, [ref]$user)) { $user } } } else { Write-Error -Message "Team `"$uid`" not found" -ErrorAction Stop } } else { Write-Error -Message "Team `"$Team`" not found" -ErrorAction Stop } } New-Alias -Name ketu -Value Get-KeeperEnterpriseTeamUser Register-ArgumentCompleter -CommandName Get-KeeperEnterpriseTeamUser -ParameterName Team -ScriptBlock $Keeper_TeamNameCompleter $Keeper_ActiveUserCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $result = @() [Enterprise]$enterprise = $Script:Context.Enterprise if (-not $enterprise) { return $null } if ($wordToComplete) { $to_complete = '*' + $wordToComplete + '*' } else { $to_complete = '*' } foreach ($user in $enterprise.enterpriseData.Users) { if ($user.UserStatus -in @([KeeperSecurity.Enterprise.UserStatus]::Active, [KeeperSecurity.Enterprise.UserStatus]::Disabled, [KeeperSecurity.Enterprise.UserStatus]::Blocked)) { if ($user.Email -like $to_complete) { $result += $user.Email } } } if ($result.Count -gt 0) { return $result } else { return $null } } function New-KeeperEnterpriseNode { <# .SYNOPSIS Creates Enterprise Node .PARAMETER ParentNode Parent Node name or ID .PARAMETER NodeName Node name #> [CmdletBinding()] Param ( [Parameter()][string] $ParentNode, [Parameter(Position = 0, Mandatory = $true)] $NodeName ) [Enterprise]$enterprise = getEnterprise [KeeperSecurity.Enterprise.EnterpriseNode] $parent = $null if ($ParentNode) { $parent = resolveSingleNode $ParentNode } $n = [KeeperSecurity.Enterprise.EnterpriseExtensions]::CreateNode($enterprise.enterpriseData, $NodeName, $parent).GetAwaiter().GetResult() Write-Information "Added node `"$($n.DisplayName)`"" } New-Alias -Name kena -Value New-KeeperEnterpriseNode function Add-KeeperEnterpriseUser { <# .SYNOPSIS Invites Enterprise Users .PARAMETER Node Node Name or ID .PARAMETER Email Email address to invite .PARAMETER Emails Extra email addresses to invite #> [CmdletBinding()] Param ( [Parameter()][string] $FullName, [Parameter()][string] $Node, [Parameter(Position = 0, Mandatory = $true)] $Email, [Parameter(ValueFromRemainingArguments = $true)] $Emails ) [Enterprise]$enterprise = getEnterprise [Int64] $nodeId = 0 if ($Node) { $n = resolveSingleNode $Node if ($n) { $nodeId = $n.Id } } $inviteOptions = New-Object KeeperSecurity.Enterprise.InviteUserOptions if ($nodeId -gt 0) { $inviteOptions.NodeId = $nodeId } if ($FullName) { $inviteOptions.FullName = $FullName } $user = $enterprise.enterpriseData.InviteUser($Email, $inviteOptions).GetAwaiter().GetResult() if ($user) { Write-Output "User `"$Email`" is invited" } $inviteOptions.FullName = $null foreach ($e in $Emails) { $user = $enterprise.enterpriseData.InviteUser($e, $inviteOptions).GetAwaiter().GetResult() if ($user) { Write-Output "User `"$e`" is invited" } } } New-Alias -Name invite-user -Value Add-KeeperEnterpriseUser function Lock-KeeperEnterpriseUser { <# .Synopsis Locks Enterprise User .Parameter User User email, enterprise Id, or instance. #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)]$User ) [Enterprise]$enterprise = getEnterprise $userObject = resolveUser $enterprise.enterpriseData $User if ($userObject) { $saved = $enterprise.enterpriseData.SetUserLocked($userObject, $true).GetAwaiter().GetResult() if ($saved) { Write-Output "User `"$($saved.Email)`" was locked" } } } Register-ArgumentCompleter -CommandName Lock-KeeperEnterpriseUser -ParameterName User -ScriptBlock $Keeper_ActiveUserCompleter New-Alias -Name lock-user -Value Lock-KeeperEnterpriseUser $Keeper_LockedUserCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $result = @() [Enterprise]$enterprise = $Script:Context.Enterprise if (-not $enterprise) { return $null } if ($wordToComplete) { $to_complete = '*' + $wordToComplete + '*' } else { $to_complete = '*' } foreach ($user in $enterprise.enterpriseData.Users) { if ($user.UserStatus -eq [KeeperSecurity.Enterprise.UserStatus]::Locked) { if ($user.Email -like $to_complete) { $result += $user.Email } } } if ($result.Count -gt 0) { return $result } else { return $null } } function Unlock-KeeperEnterpriseUser { <# .Synopsis Unlocks Enterprise User .Parameter User User email, enterprise Id, or instance. #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)]$User ) [Enterprise]$enterprise = getEnterprise $userObject = resolveUser $enterprise.enterpriseData $User if ($userObject) { $saved = $enterprise.enterpriseData.SetUserLocked($userObject, $false).GetAwaiter().GetResult() if ($saved) { Write-Output "User `"$($saved.Email)`" was unlocked" } } } Register-ArgumentCompleter -CommandName Unlock-KeeperEnterpriseUser -ParameterName User -ScriptBlock $Keeper_LockedUserCompleter New-Alias -Name unlock-user -Value Unlock-KeeperEnterpriseUser $Keeper_EnterpriseUserCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $result = @() [Enterprise]$enterprise = $Script:Context.Enterprise if (-not $enterprise) { return $null } if ($wordToComplete) { $to_complete = '*' + $wordToComplete + '*' } else { $to_complete = '*' } foreach ($user in $enterprise.enterpriseData.Users) { if ($user.Email -like $to_complete) { $result += $user.Email } } if ($result.Count -gt 0) { return $result } else { return $null } } function Move-KeeperEnterpriseUser { <# .Synopsis Transfers enterprise user account to another user .Parameter FromUser email or user ID to transfer vault from user .Parameter TargetUser email or user ID to transfer vault to user #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)]$FromUser, [Parameter(Position = 1, Mandatory = $true)]$TargetUser, [Switch] $Force ) [Enterprise]$enterprise = getEnterprise $fromUserObject = resolveUser $enterprise.enterpriseData $FromUser if (-not $fromUserObject) { return } $targetUserObject = resolveUser $enterprise.enterpriseData $TargetUser if (-not $targetUserObject) { return } if (-not $Force.IsPresent) { Write-Output "This action cannot be undone.`n" $answer = Read-Host -Prompt "Do you want to proceed with transferring $($fromUserObject.Email) account (Yes/No)? > " if ($answer -ne 'yes' -and $answer -ne 'y') { return } } $transferResult = $enterprise.enterpriseData.TransferUserAccount($enterprise.roleData, $fromUserObject, $targetUserObject).GetAwaiter().GetResult() if ($transferResult) { Write-Information "Successfully Transfered:" Write-Information " Records: $($transferResult.RecordsTransfered)" Write-Information " Shared Folders: $($transferResult.SharedFoldersTransfered)" Write-Information " Team: $($transferResult.TeamsTransfered)" if ($transferResult.RecordsCorrupted -gt 0 -or $transferResult.SharedFoldersCorrupted -gt 0 -or $transferResult.TeamsCorrupted -gt 0) { Write-Information "Failed to Transfer:" if ($transferResult.RecordsCorrupted -gt 0) { Write-Information " Records: $($transferResult.RecordsCorrupted)" } if ($transferResult.SharedFoldersCorrupted -gt 0) { Write-Information " Shared Folders: $($transferResult.SharedFoldersCorrupted)" } if ($transferResult.TeamsCorrupted -gt 0) { Write-Information " Team: $($transferResult.TeamsCorrupted)" } } } } Register-ArgumentCompleter -CommandName Move-KeeperEnterpriseUser -ParameterName FromUser -ScriptBlock $Keeper_LockedUserCompleter Register-ArgumentCompleter -CommandName Move-KeeperEnterpriseUser -ParameterName TargetUser -ScriptBlock $Keeper_ActiveUserCompleter New-Alias -Name transfer-user -Value Move-KeeperEnterpriseUser function Remove-KeeperEnterpriseUser { <# .Synopsis Removes Enterprise User .Parameter User User email, enterprise Id, or instance. #> [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact = 'High')] Param ( [Parameter(Position = 0, Mandatory = $true)]$User, [Switch] $Force ) [Enterprise]$enterprise = getEnterprise $userObject = resolveUser $enterprise.enterpriseData $User if ($userObject) { if (-not $Force.IsPresent) { Write-Output "`nDeleting a user will also delete any records owned and shared by this user." "Before you delete this user, we strongly recommend you lock their account" "and transfer any important records to other user.`n" "This action cannot be undone." if ($PSCmdlet.ShouldProcess($userObject.Email, "Removing Enterprise User")) { $enterprise.enterpriseData.DeleteUser($userObject).GetAwaiter().GetResult() | Out-Null Write-Output "User $($userObject.Email) has been deleted" } } } } Register-ArgumentCompleter -CommandName Remove-KeeperEnterpriseUser -ParameterName User -ScriptBlock $Keeper_EnterpriseUserCompleter New-Alias -Name delete-user -Value Remove-KeeperEnterpriseUser function resolveUser { Param ( $enterpriseData, $user ) [KeeperSecurity.Enterprise.EnterpriseUser] $u = $null if ($user -is [long]) { if ($enterpriseData.TryGetUserById($user, [ref]$u)) { return $u } } elseif ($user -is [string]) { if ($enterpriseData.TryGetUserByEmail($user, [ref]$u)) { return $u } } elseif ($user -is [KeeperSecurity.Enterprise.EnterpriseUser]) { if ($enterpriseData.TryGetUserById($user.Id, [ref]$u)) { return $u } } Write-Error "`"${user}`" cannot be resolved as enterprise user" -ErrorAction Stop } function resolveSingleNode { Param ($node) if ($node) { $nodes = Get-KeeperEnterpriseNode | Where-Object { $_.Id -eq $node } if ($nodes.Length -eq 0) { $nodes = Get-KeeperEnterpriseNode | Where-Object { $_.DisplayName -like $node + '*' } } if ($nodes.Length -eq 0) { Write-Error -Message "Node `"$node`" not found" -ErrorAction Stop } if ($nodes.Length -gt 1) { Write-Error -Message "Node name `"$node`" is not unique. Use Node ID." -ErrorAction Stop } $nodes[0] } } function Get-KeeperEnterpriseNode { <# .Synopsis Get a list of enterprise nodes #> [CmdletBinding()] [Enterprise]$enterprise = getEnterprise return $enterprise.enterpriseData.Nodes } New-Alias -Name ken -Value Get-KeeperEnterpriseNode function Get-KeeperEnterpriseRole { <# .SYNOPSIS Get a list of enterprise roles .PARAMETER Role Role Name or ID #> [CmdletBinding()] [Enterprise]$enterprise = getEnterprise return $enterprise.roleData.Roles } New-Alias -Name ker -Value Get-KeeperEnterpriseRole $Keeper_RoleNameCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $result = @() [Enterprise]$enterprise = $Script:Context.Enterprise if (-not $enterprise) { return $null } if ($wordToComplete) { $to_complete = $wordToComplete + '*' } else { $to_complete = '*' } foreach ($role in $enterprise.roleData.Roles) { if ($role.DisplayName -like $to_complete) { $roleName = $role.DisplayName if ($roleName -match '[\s'']') { $roleName = $roleName -replace '''', '''''' $roleName = "'${roleName}'" } $result += $roleName } } if ($result.Count -gt 0) { return $result } else { return $null } } function Get-KeeperEnterpriseRoleUsers { <# .SYNOPSIS Get a list of enterprise users for a role .PARAMETER Role Role Name or ID #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)]$Role ) [Enterprise]$enterprise = getEnterprise $enterpriseData = $enterprise.enterpriseData $roleData = $enterprise.roleData $roleId = $null if ($Role -is [String]) { $ids = Get-KeeperEnterpriseRole | Where-Object { $_.Id -eq $Role -or $_.DisplayName -ieq $Role } | Select-Object -Property Id if ($ids.Length -gt 1) { Write-Error -Message "Role name `"$Role`" is not unique. Use Role ID" -ErrorAction Stop } if ($null -ne $ids.Id) { $roleId = $ids.Id } } elseif ($Role -is [long]) { $ids = Get-KeeperEnterpriseRole | Where-Object { $_.Id -ceq $Role } | Select-Object -First 1 if ($ids.Length -eq 1) { $roleId = $ids[0].Id } } elseif ($null -ne $Role.Id) { $roleId = $Role.Id } if ($roleId) { $erole = $null if ($roleData.TryGetRole($roleId, [ref]$erole)) { foreach ($userId in $roleData.GetUsersForRole($erole.Id)) { $user = $null if ($enterpriseData.TryGetUserById($userId, [ref]$user)) { $user } } } else { Write-Error -Message "Role `"$roleId`" not found" -ErrorAction Stop } } else { Write-Error -Message "Role `"$Role`" not found" -ErrorAction Stop } } New-Alias -Name keru -Value Get-KeeperEnterpriseRoleUsers Register-ArgumentCompleter -CommandName Get-KeeperEnterpriseRoleUsers -ParameterName Role -ScriptBlock $Keeper_RoleNameCompleter function Get-KeeperEnterpriseRoleTeams { <# .SYNOPSIS Get a list of enterprise teams for a role .PARAMETER Role Role Name or ID #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)]$Role ) [Enterprise]$enterprise = getEnterprise $enterpriseData = $enterprise.enterpriseData $roleData = $enterprise.roleData $roleId = $null if ($Role -is [String]) { $ids = Get-KeeperEnterpriseRole | Where-Object { $_.Id -eq $Role -or $_.DisplayName -ieq $Role } | Select-Object -Property Id if ($ids.Length -gt 1) { Write-Error -Message "Role name `"$Role`" is not unique. Use Role ID" -ErrorAction Stop } if ($null -ne $ids.Id) { $roleId = $ids.Id } } elseif ($Role -is [long]) { $ids = Get-KeeperEnterpriseRole | Where-Object { $_.Id -ceq $Role } | Select-Object -First 1 if ($ids.Length -eq 1) { $roleId = $ids[0].Id } } elseif ($null -ne $Role.Id) { $roleId = $Role.Id } if ($roleId) { $erole = $null if ($roleData.TryGetRole($roleId, [ref]$erole)) { foreach ($teamUid in $roleData.GetTeamsForRole($erole.Id)) { $team = $null if ($enterpriseData.TryGetTeam($teamUid, [ref]$team)) { $team } } } else { Write-Error -Message "Role `"$roleId`" not found" -ErrorAction Stop } } else { Write-Error -Message "Role `"$Role`" not found" -ErrorAction Stop } } New-Alias -Name kert -Value Get-KeeperEnterpriseRoleTeams Register-ArgumentCompleter -CommandName Get-KeeperEnterpriseRoleTeams -ParameterName Role -ScriptBlock $Keeper_RoleNameCompleter function Get-KeeperEnterpriseAdminRole { <# .SYNOPSIS Get a list of Administrator Permissions .PARAMETER Pattern Role search pattern #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $false)]$Pattern ) [Enterprise]$enterprise = getEnterprise $roleData = $enterprise.roleData $roles = $null if ($Pattern -is [String]) { $roles = Get-KeeperEnterpriseRole | Where-Object { $_.Id -eq $Pattern -or $_.DisplayName -match $Pattern } } elseif ($Pattern -is [long]) { $roles = Get-KeeperEnterpriseRole | Where-Object { $_.Id -eq $Pattern } } elseif ($null -ne $Pattern.Id) { $roles = $Pattern } else { $roles = Get-KeeperEnterpriseRole } if ($null -ne $roles -and $roles.Length -gt 0 ) { $roles = $roles | Sort-Object -Property DisplayName foreach ($role in $roles) { if ($null -ne $role.Id) { foreach ($rp in $roleData.GetRolePermissions($role.Id)) { $rp } } } } else { Write-Error -Message "Role `"$Role`" not found" -ErrorAction Stop } } New-Alias -Name kerap -Value Get-KeeperEnterpriseAdminRole function Script:Get-KeeperNodeName { Param ( [long]$nodeId ) $enterprise = getEnterprise [KeeperSecurity.Enterprise.EnterpriseNode]$node = $null if ($enterprise.enterpriseData.TryGetNode($nodeId, [ref]$node)) { if ($node.ParentNodeId -gt 0) { return $node.DisplayName } else { return $enterprise.loader.EnterpriseName } } } function Script:Get-KeeperRoleName { Param ( [long]$roleId ) $enterprise = getEnterprise [KeeperSecurity.Enterprise.EnterpriseRole]$role = $null if ($enterprise.roleData.TryGetRole($roleId, [ref]$role)) { return $role.DisplayName } } # SIG # Begin signature block # MIIR1wYJKoZIhvcNAQcCoIIRyDCCEcQCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUlBA6H7RRJHocSP55ulsuyvyw # XQ2ggg4jMIIGsDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0B # AQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVk # IFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg # Q0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5 # WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJP # DqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXz # ENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bq # HPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTC # fMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaD # G7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urO # kfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7AD # K5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4 # R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlN # Wdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0I # U0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYB # Af8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaA # FOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK # BggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v # Y3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4 # oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv # b3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcN # AQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcT # Ep6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WT # auPrINHVUHmImoqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9 # ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np37 # 5SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0 # HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL # 6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+1 # 6oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8 # M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrF # hsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy # 1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIHazCC # BVOgAwIBAgIQAnNTGQOIer82vZ1cJyDJDjANBgkqhkiG9w0BAQsFADBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg # Q0ExMB4XDTIyMDIwMjAwMDAwMFoXDTI1MDIwMTIzNTk1OVowcDELMAkGA1UEBhMC # VVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGljYWdvMR0wGwYDVQQK # ExRLZWVwZXIgU2VjdXJpdHkgSW5jLjEdMBsGA1UEAxMUS2VlcGVyIFNlY3VyaXR5 # IEluYy4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDNgTqmksdjUyKF # 5zWkDyghf0PLWJWdzG0TX2j8B4J55xwt+B17zd4Xc3n0dvmSVAyPQANeN+mP1chf # 4LTRn9h4jWb8Jsfn+JzyRhj/gYINYvBnpRpqoM0z7QC9Ebwj5T61Cogm9EKGcrG+ # Ujh+Z7pTqfSUrHD8NMXhDL/UpVn+w0Pb4qg7o7AH2o94n7u/qTlMGZCs+VCAvhNr # wPABxvFY07YGb9t5/IZlPE8vG3p1vw2SbgREgFWSEQFj6X2CIhSrbiFCW/766/Mq # EX6qm+RyF71fD4d3yShg39guaE9o+TBl1MqVCje4bK/wGoNxCho0I6Z1fBBKloyp # vlx3gPpU7tJJ+KpuIiel9R9dGQuscqKzehPtbRc9Abr9ThN/HrLg1sFFVMdn2oMR # 63QCUdz+B1NuS7Ap8Ti7XvAPJHzEuQDcdMcRbkIfllJVqrb9UXEFwOPzvRU2KrcQ # 42Jlnn4T+WenPx5Nr3o/o08WLhLTicEK1OacEowyRLBmih4Gxpdk3fUAVCEkdvmq # TSydQpl1Bk8V88dxCkB1wMZyFYLNcddBL4kUbwjso/z6f2TtfAVYs/iIRWqs7Xqt # 4F2BBqobOGMymwg6VgVjjzDIgJCZSbjpq2IoVTci5vli6vxgSoZ01fccSaKa4Izm # B7DbobIkIjLgPqpnCkqlHuJj5hQ9twIDAQABo4ICBjCCAgIwHwYDVR0jBBgwFoAU # aDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFCZd3/KEdT2t5WTIFb3TUaM4 # sTikMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYDVR0f # BIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBToFGg # T4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29k # ZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwPgYDVR0gBDcwNTAzBgZn # gQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BT # MIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln # aWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j # b20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIx # Q0ExLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQAGyDM3Cbxq # Auhr8O2xwOoCSVKmFkXqicwlrugwLW44Y4WX+imvTrGfjj2S99k/4D5H8DgtW/u8 # tOxcCoehTOCIEwP5TLrieHppsqAR4jaJRcdAHOWiJ1bmwQBv/cBU9vaelL0oXxxf # TwD9oDaQNuyq6p+nIJMqbKv33b8AWGe3zq4JwblaFjRDL5lUDNhPx3g/pm7JhnbX # 7QTKydAJvpbuP5cqUH1GEeVMjc5vEELtGNy/fy7Ekm4dndX4IZcFXW5L0Lx8cReB # hIZwA+pzdzTWQYvfxgRMb/j2uY+Tkb6Wz2x9BBS1UXiP2qrs3rhQv8DZRkUSqnko # YD4uJP8gk8BXcIXIThgEF2YCq2hBiwna5Ijbwkmjn1lWwGv15SznTOTnrVApJqB1 # tB2s2ovUNV4CyKDPVr+9/CS6IQJfEZeHYcYLsIga2q5NZCrqZAasBfCwALVkALos # DIWhs33vYLfETMSuk5Hd5JC+hLjVM3ZJwslvnc/wec2r0GNAiZ3a1aweC7NYuzRz # 29Mi/eR/4ylmCltyZqYJ1JcC/g6eY2Q0xkdWc8P0yHfQ/3fe7+AKXXKNjfv858GW # lg1Ck2lvwPdLqJWqj1FwJPiGRCB+WulPe0csTyWnf+ed45TXx69tZ6BZr0Xr2jXu # ybBdJtg0NN0a62xxWrmX42CgsrzHzRm7OzGCAx4wggMaAgEBMH0waTELMAkGA1UE # BhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2Vy # dCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENB # MQIQAnNTGQOIer82vZ1cJyDJDjAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEK # MAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3 # AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQULsDBjQIJV7WCw+MS # Jra3KcKiRY8wDQYJKoZIhvcNAQEBBQAEggIAFkve44+34a/0oo56GHg3B7yPTcTV # 9Z/+XHJgVGsBmIYU1qGINJxW0XN7KbSwG5FORuwRORzWFz8zOQbUA3nzeclNnPOw # oMjBlRvj1DIsAoT0e+c+h2N2pIjrmqVuhFXqVPcu3to+geBYEd30II/6Gtt3dXMO # yTytwKJ5+mIzbjzxYo4HsxPA4NnkcmQ4AwsFiwrRR84c0GfTkt4VExXBW9wY/V8v # xv2OlxwAXCvnQXD2Dku/WUzbmF+gcbArtl/ehg9/DY4158m2KwqHRs36sm5tyG3z # JYmDN1Me+4vXtGdWL7Z24BRHoMjrGk/E1/K8r/cFBAhp22Z64PDHXTVxU2nD8aX3 # fUWMZRAmOtL9qrn5+bD0ny7Y9sl3ipkJ8rTzmP3ySrGkaOYGDPohZHHwZcRK/ZQ9 # 3RO6mwppnWszG5n6ngwdYqOSrHGVqZuEkiAEjpIQgamuZqPjsNQlScwDNhEtRqRQ # ar91LM80cQBN5U8nvqotHtyI+3BYk39Ojyuh7GHFuGqzwEfqyhVdpKuWxcvMgBV7 # 1qcLev/cfQH4DL8NtOXeufJPojDnGSVQ/+YEMlYmW81AeDbYXVDrw6dcbglx8y06 # Eh1y/rSJunGCPiu4r8p1fY2fgT3PT0CSQ1xjmPoyHnW7EpoaoC6iqiAbPdH51J4w # tJij+JK6RSWj+l0= # SIG # End signature block |