EnterpriseUser.ps1
|
# Enterprise User Management Functions 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 } } else { $nodeId = $enterprise.enterpriseData.RootNode.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 $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 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 $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 function Move-KeeperEnterpriseUser { <# .Synopsis Transfers an enterprise user's vault (records, shared folders, teams) to another user .Parameter FromUser Email or enterprise user ID of the source user whose vault will be transferred .Parameter TargetUser Email or enterprise user ID of the destination user who will receive the vault .Parameter Force Skip confirmation prompt in non-interactive sessions .Description Transfers all records, shared folders, and team memberships from one enterprise user to another. The source user's vault contents are merged into the target user's vault. Use -Force to skip confirmation in automated scripts. .Example Move-KeeperEnterpriseUser -FromUser "departing@company.com" -TargetUser "replacement@company.com" Transfers the departing user's vault to the replacement user (prompts for confirmation) .Example transfer-user "departing@company.com" "replacement@company.com" -Force Transfers vault without confirmation prompt #> [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) { if (Test-InteractiveSession) { Write-Output "This action cannot be undone.`n" $answer = Read-Host -Prompt "Do you want to proceed with transferring $($fromUserObject.Email) account (Yes/No)? > " } else { Write-Output('Non-interactive session. Use -Force parameter') $answer = '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 Transferred:" 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 (-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 Invoke-ResendKeeperEnterpriseInvite { <# .Synopsis Resends enterprise invitation email to a user .Parameter User User email address .Description Resends the enterprise invitation email to a user who has not yet accepted their invitation. The user must be in Inactive status (not yet accepted invitation). .Example Invoke-ResendKeeperEnterpriseInvite -User "user@example.com" Resends invitation email to user@example.com #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)][string] $User ) [Enterprise]$enterprise = getEnterprise [KeeperSecurity.Enterprise.EnterpriseUser]$userObject = $null if ($enterprise.enterpriseData.TryGetUserByEmail($User, [ref]$userObject)) { # here user is found by email Write-Debug "User `"$User`" found by email" } elseif ($User -is [long] -or ($User -is [string] -and $User -match '^\d+$')) { $userId = if ($User -is [long]) { $User } else { [long]$User } if (-not $enterprise.enterpriseData.TryGetUserById($userId, [ref]$userObject)) { Write-Error "User `"$User`" not found" -ErrorAction Stop return } # here user is found by ID Write-Debug "User `"$User`" found by ID" } else { # here user is not found by email or ID Write-Error "User `"$User`" not found" -ErrorAction Stop return } if ($userObject.UserStatus -ne [KeeperSecurity.Enterprise.UserStatus]::Inactive) { Write-Error "User has already accepted invitation. Only inactive users can have invitations resent." -ErrorAction Stop return } try { $enterprise.enterpriseData.ResendEnterpriseInvite($userObject).GetAwaiter().GetResult() | Out-Null Write-Output "Invite for $User resent." } catch { Write-Error "Failed to resend invite: $($_.Exception.Message)" -ErrorAction Stop } } Register-ArgumentCompleter -CommandName Invoke-ResendKeeperEnterpriseInvite -ParameterName User -ScriptBlock $Keeper_EnterpriseUserCompleter function Set-KeeperEnterpriseUserMasterPasswordExpire { <# .Synopsis Sets master password expiration for an enterprise user .Parameter User User email address .Description Sets the master password expiration for an active enterprise user, requiring them to change their password on next login. .Example Set-KeeperEnterpriseUserMasterPasswordExpire -User "user@example.com" Sets master password expiration for user@example.com #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)][string] $User ) [Enterprise]$enterprise = getEnterprise $userObject = resolveUser $enterprise.enterpriseData $User if (-not $userObject) { Write-Error "User `"$User`" not found" -ErrorAction Stop return } if ($userObject.UserStatus -ne [KeeperSecurity.Enterprise.UserStatus]::Active) { Write-Error "User $User is not active" -ErrorAction Stop return } try { $enterprise.enterpriseData.SetMasterPasswordExpire($userObject.Email).GetAwaiter().GetResult() | Out-Null Write-Output "Master password expiration set for $User" } catch { Write-Error "Failed to set master password expiration: $($_.Exception.Message)" -ErrorAction Stop } } Register-ArgumentCompleter -CommandName Set-KeeperEnterpriseUserMasterPasswordExpire -ParameterName User -ScriptBlock $Keeper_ActiveUserCompleter function Update-KeeperEnterpriseTeamUser { <# .Synopsis Updates a user's type in an enterprise team .Parameter Team Team name or UID .Parameter User User email address .Parameter UserType User type: 0, 1, or 2. 0 = User (normal member), 1 = Administrator (can manage team, sees shared folders), 2 = Administrator Only (can manage team but does not see shared folders) .Description Updates the user type for a user in a specific enterprise team. UserType must be 0, 1, or 2. .Example Update-KeeperEnterpriseTeamUser -Team "Engineering" -User "user@example.com" -UserType 1 Makes user@example.com an Administrator in the Engineering team .Example Update-KeeperEnterpriseTeamUser -Team "Engineering" -User "user@example.com" -UserType 0 Makes user@example.com a normal User in the Engineering team #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)][string] $Team, [Parameter(Position = 1, Mandatory = $true)][string] $User, [Parameter(Position = 2, Mandatory = $true)][int] $UserType ) [Enterprise]$enterprise = getEnterprise if ([string]::IsNullOrWhiteSpace($Team)) { Write-Error "Team name parameter is mandatory." -ErrorAction Stop return } if ([string]::IsNullOrWhiteSpace($User)) { Write-Error "User email parameter is mandatory." -ErrorAction Stop return } if ($UserType -lt 0 -or $UserType -gt 2) { Write-Error "User type must be 0, 1, or 2" -ErrorAction Stop return } $teamObject = resolveTeam $enterprise.enterpriseData $Team if (-not $teamObject) { Write-Error "Team `"$Team`" not found" -ErrorAction Stop return } $userObject = resolveUser $enterprise.enterpriseData $User if (-not $userObject) { Write-Error "User `"$User`" not found" -ErrorAction Stop return } if ($userObject.UserStatus -ne [KeeperSecurity.Enterprise.UserStatus]::Active) { Write-Error "User $User is not active" -ErrorAction Stop return } try { $enterprise.enterpriseData.TeamEnterpriseUserUpdate($teamObject, $userObject, $UserType).GetAwaiter().GetResult() | Out-Null Write-Output "Team user $User updated" } catch { Write-Error "Failed to update team user: $($_.Exception.Message)" -ErrorAction Stop } } Register-ArgumentCompleter -CommandName Update-KeeperEnterpriseTeamUser -ParameterName Team -ScriptBlock $Keeper_TeamNameCompleter Register-ArgumentCompleter -CommandName Update-KeeperEnterpriseTeamUser -ParameterName User -ScriptBlock $Keeper_ActiveUserCompleter function Update-KeeperEnterpriseUser { <# .Synopsis Updates enterprise user information .Parameter User User email address .Parameter Node Node name or ID (optional) .Parameter FullName User's full name (optional) .Parameter JobTitle User's job title (optional) .Parameter InviteeLocale User's locale for invitations (optional) .Description Updates enterprise user information including node assignment, full name, job title, and invitee locale. If node is not specified, the user's current parent node is used. .Example Update-KeeperEnterpriseUser -User "user@example.com" -FullName "John Doe" -JobTitle "Software Engineer" Updates user's full name and job title .Example Update-KeeperEnterpriseUser -User "user@example.com" -Node "Engineering" -InviteeLocale "en-US" Moves user to Engineering node and sets locale #> [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory = $true)][string] $User, [Parameter()][string] $Node, [Parameter()][string] $FullName, [Parameter()][string] $JobTitle, [Parameter()][string] $InviteeLocale ) [Enterprise]$enterprise = getEnterprise if ([string]::IsNullOrWhiteSpace($User)) { Write-Error "User email parameter is mandatory." -ErrorAction Stop return } $userObject = resolveUser $enterprise.enterpriseData $User if (-not $userObject) { Write-Error "User `"$User`" not found" -ErrorAction Stop return } if ($userObject.UserStatus -ne [KeeperSecurity.Enterprise.UserStatus]::Active) { Write-Error "User $User is not active" -ErrorAction Stop return } $nodeId = $null if ($Node) { $nodeObject = resolveSingleNode $Node if ($nodeObject) { $nodeId = $nodeObject.Id } else { Write-Warning "Node `"$Node`" not found so we are taking user's parent node" } } try { $updatedUser = $enterprise.enterpriseData.EnterpriseUserUpdate($userObject, $nodeId, $FullName, $JobTitle, $InviteeLocale).GetAwaiter().GetResult() Write-Output "User $User updated" return $updatedUser } catch { Write-Error "Failed to update user: $($_.Exception.Message)" -ErrorAction Stop } } Register-ArgumentCompleter -CommandName Update-KeeperEnterpriseUser -ParameterName User -ScriptBlock $Keeper_ActiveUserCompleter # SIG # Begin signature block # MIInvgYJKoZIhvcNAQcCoIInrzCCJ6sCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDkOOwYnVj0/AKH # liNoV5z3A2sfeULBGfY79JhmyZO/tKCCITswggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0GCSqG # SIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTlaMGkx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4 # RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEzODQg # MjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C0Cit # eLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce2vnS # 1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0daE6ZM # swEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6TSXBC # Mo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoAFdE3 # /hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7OhD26j # q22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM1bL5 # OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z8ujo # 7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05huzU # tw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNYmtwm # KwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP/2NP # TLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0TAQH/ # BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYDVR0j # BBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1Ud # JQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0 # cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0 # cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8E # PDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz # dGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATANBgkq # hkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95RysQDK # r2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HLIvda # qpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5BtfQ/g+ # lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnhOE7a # brs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIhdXNS # y0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV9zeK # iwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/jwVYb # KyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYHKi8Q # xAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmCXBVm # zGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l/aCn # HwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZWeE4w # gga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0GCSqGSIb3DQEBCwUAMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH # NDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTlaMGkxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1 # c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwggIi # MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHTCphBcr48RsAcrHXbo0Zo # dLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPhof6pvF4uGjwjqNjfEvUi # 6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mAxAHeHYNnQxqXmRinvuNg # xVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBvMgEdgkFiDNYiOTx4OtiF # cMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps0wjUjsZvkgFkriK9tUKJ # m/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF83bRVFLeGkuAhHiGPMvS # GmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXiUOeSLsJygoLPp66bkDX1 # ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOMCZIVNSaz7BX8VtYGqLt9 # MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydPpOjL6s36czwzsucuoKs7 # Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrUG2ZdSoQbU2rMkpLiQ6bG # RinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+sdFUeEY0qVjPKOWug/G6 # X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAd # BgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYDVR0jBBgwFoAU7NfjgtJx # XWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUF # BwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln # aWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j # b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJo # dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNy # bDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQEL # BQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WIGjB/T8ObXAZz8OjuhUxj # aaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+IQhQE7jU/kXjjytJgnn0 # hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8Myb9rEVKChHyfpzee5kH0 # F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2th9y1IsA0QF8dTXqvcnT # mpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjajV/gxdEkMx1NKU4uHQcKf # ZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2Lr3ty9qIijanrUR3anzE # wlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFzeGxcytL5TTLL4ZaoBdqbh # OhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG7uEBYTptMSbhdhGQDpOX # gpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+NJpud/v4+7RWsWCiKi9EO # LLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckTetiSuEtQvLsNz3Qbp7wG # WqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszWkPZPubdcMIIG7TCCBNWg # AwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQG # EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0 # IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0Ex # MB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVowYzELMAkGA1UEBhMCVVMx # FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBTSEEy # NTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIwMjUgMTCCAiIwDQYJKoZI # hvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5gVrMrV7pvUf+GcAoB38o3 # zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN+vo8dE2/pPvOx/Vj8Tch # TySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qome7MrxVyfQO9sMx6ZAWj # FDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ//nBZZREr4h/GI6Dxb2Uo # yrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouTMYFOnHoRh6+86Ltc5zjP # KHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8DD+nigNJFmt6LAHvH3KS # uNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnpJeItK/DhKbPxTTuGoX7w # JNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP51ho1zBp+xUIZkpSFA8vW # doUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49kPmk8iyyizNDIXj//cOg # rY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5PWPsWeupWs7NpChUk555K # 096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7YufAkprxMiXAJQ1XCmnCf # gPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTkO/zy # Me39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK6eQGfHrK4pBW9i/USezL # TjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwgZUGCCsG # AQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j # b20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp # Q2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNy # dDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln # aUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5j # cmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEB # CwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP2zWLpQq1b4URGnwWBdEZ # D9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O6Lgjg8K8elC4+oWCqnU/ # ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskgiC3QYIUP2S3HQvHG1FDu # +WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMUBaB5bdrPbF6MRYs03h4o # bEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDFkxUGtMTaiLR9wjxUxu2h # ECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+zJNEsuEB7O7/cuvTQasn # M9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/lwd6UArb+BOVAkg2oOvol # /DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxlRcGG0LIhp6GvReQGgMgY # xQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2zRWVFjF7mcr4C34Mj3oc # CVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJgbaP5t2nGj/ULLi49xTcB # ZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOCIUjsarfNZzCCB0kwggUx # oAMCAQICEAe0P3SLJmcoVNrErUyxTt0wDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE # BhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2Vy # dCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENB # MTAeFw0yNTEyMzEwMDAwMDBaFw0yOTAxMDIyMzU5NTlaMIHRMRMwEQYLKwYBBAGC # NzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMR0wGwYDVQQPDBRQ # cml2YXRlIE9yZ2FuaXphdGlvbjEQMA4GA1UEBRMHMzQwNzk4NTELMAkGA1UEBhMC # VVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQHEwdDaGljYWdvMR0wGwYDVQQK # ExRLZWVwZXIgU2VjdXJpdHkgSW5jLjEdMBsGA1UEAxMUS2VlcGVyIFNlY3VyaXR5 # IEluYy4wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCUcNMoSVmxAi0a # vG+StFJMNFFTUIOo3HdBZ+0gqA1XpNgUx11vB1vCZrvFsD9m5oA58tdp4gZN3LmQ # aMvCl2ANUT7MilI02Hf1RWlygBzon6iE0GpU3lgRrwrk1dhtLpGsR6dbMKUUHprc # vKpXk90/VN+vhzY1uik1tCTxkDCPu/AYJg7m9+tR2KqvMuYMaMLhii66eWUAGsBC # h/uZxjkGoJF6qZ0DgFd7rW7VYljbfYSNPeZNGTDgB0J/wOsKl0mn612DTseIvAKt # 4vra/FLFukyEyStnfQ8lWYDcLLCMCjNVrzGipmT5E2iyx7Y1RZCIpNwVogp3Ixbk # Gbq5A/41YNOLLd4cFewyB2F037RevBCRsUODZEt1qBf7Jbu3DiYo1G+zTj9E0R1s # FzyijcfdsTm6X5ble+yCJeGkX5XgsyPnZpyz/FX9Fr0N9pMPGWwW2PKyHEnSytXm # 0Dxdq2P4mA4CBUxq7YoV26L2PF6QEh9BQdXTPcnLysUv7SI/a0ECAwEAAaOCAgIw # ggH+MB8GA1UdIwQYMBaAFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB0GA1UdDgQWBBRG # 4H6CH8pvNX632bsdnrda4MtJLDA9BgNVHSAENjA0MDIGBWeBDAEDMCkwJwYIKwYB # BQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMC # B4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0 # cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25p # bmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI # QTM4NDIwMjFDQTEuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JT # QTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUA # A4ICAQA1Wlq0WzJa3N6DgjgBU7nagIJBab1prPARXZreX1MOv9VjnS5o0CrfQLr6 # z3bmWHw7xT8dt6bcSwRixqvPJtv4q8Rvo80O3eUMvMxQzqmi7z1zf+HG+/3G4F+2 # IYegvPc8Ui151XCV9rjA8tvFWRLRMX0ZRxY1zfT027HMw0iYL20z44+Cky//FAnL # iRwoNDGiRkZiHbB9YOftPAYNMG3gm1z3zOW5RdfKPrqvMuijE+dfyLIAA6Immpzu # FMH+Wgn8NnSlot9b4YKycaqqdjd7wXDjPub/oQ7VShuCSBWj+UNOTVh0vcZGackc # H1DLVgwp2dcKlxJiQKtkHT/T6LloY6LTe6+8wkVkr8EAv1W+q/+M1a4Ao+ykFbIA # 2LBEmA9qdgoLtenAYIiEg+48SjMPgyBbVPE3bhL1vIqjEIxYCfdmi6wx33oYX7HB # +bJ7zitHw4GgtpfPV8y8QRZImKmeDOKyXjQPDmQM/Eglm/Ns0GzBkVXM8h6UI34b # WZrHz9sbLSE20m5Svmxftvw5zju+I3WsmS/stNfWlOkwU0niUgwPHaz21kjXEA5A # g+aqv26wodqZcnGOlChoWDvSJ8KKgdOFbeAYKAMp1NY7iWV315zpGH19RipCR1NH # 0ND8iIubk3WGNf2rzEfqlOi3h2ywqVkU6AKXHdO5JV4otSKKEDGCBdkwggXVAgEB # MH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYD # VQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNI # QTM4NCAyMDIxIENBMQIQB7Q/dIsmZyhU2sStTLFO3TANBglghkgBZQMEAgEFAKCB # hDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE # AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJ # BDEiBCB5gLK7CAC8ACIDc/cP7xcjpkBtBKehA11/kJCF99/JqDANBgkqhkiG9w0B # AQEFAASCAYBqt8scWoZE1NGksTrhWYQbCEiHEk8FK1ySb6k3UXd7bwW7znWdJBEG # qheIl0X5+hjMRvqDTeQ8/QJRrS8vv6Uaaq4NJOu7aq09U45BrPGAS+ljYoJrM1AF # ED80WKOnzEfBLMYmYfjSeAs2CfvGeSuJXdyir/DSRabkSzW+7POmIsZkonWT08qt # HC+S1LhGAwIoneMR84fqxTh7pEh0ceHkCtXMvUFD0zxmdiyIwbIs4X5yedG2AlYb # 4Zg5rYVGS/mAGydgMhuROLCSipPZaZDdAcTkYlu2NeQtJ803BVh+2yCS9QK/4YRx # 9h2TUecLj+q/+aT8tvJ0+mC86cJCL9i0WJ+05uE7zj++iy9k8dyQeYk4N8+P5h8G # KHyo1ALw5EHlWlnC3qtk8u8HJwzCNFQGjVvlaj3gItQvNQchDcgyoP+YcjHMleju # DrUVCPBoILOL0emC6S9nt1bIjXBtlZfjGMOAtEvYc3RHdzXxfr6dAVPefk+SGtJz # WT8TNScPydahggMmMIIDIgYJKoZIhvcNAQkGMYIDEzCCAw8CAQEwfTBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUg # Q0ExAhAKgO8YS43xBYLRxHanlXRoMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcN # AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjYwNTAxMDA1MDA3WjAv # BgkqhkiG9w0BCQQxIgQgdS5Vf/W53TieOKL2vei8+WDtxT0MmokjGF2ynZUIPAkw # DQYJKoZIhvcNAQEBBQAEggIAnbaV3Jf3MWYoUDQXltA4R0h0w3U/2cXUXBNbHUBL # ldZb0us9uHwwMBgM/15C8LcJtkQptCo13i0yQMSL6I/+n6RvovZ9Gn2FF616qE8m # 4p1xCnARMnSrSqGUhtVjrISSj2eT+Titd9HTp6u9u7GYL2KEZgGVlMwuzKiqBze8 # 3eDkmvoxQDcueroFq3C0fE3bpKnsIRcwq5nD7c8jlRom4BWWmgFuUECdO7Q7PrOJ # hWxDfcIXXWtLNFnKZtHIs8LfQJersvISpLOGMYRNTlZ3tmJJZ3Q71Xt7mZ5W82fX # IDHp5FQz4H6yPiYN8mSN57GqmPYh13ByTXCpVR3BlX1emNzTsKqRySw7DgfYWBKB # RvkwVCbq4E7zBkGYaOMt4jVI2FpefX5+/X3V6I9rK6c1j84JKvGqPXfr1t7OUiGx # nQFuGpM5oLpfj4mfDFGv8K4ABDIJVXa/0jGwGVrpr16QpRT4oEknRE310pVXdNfz # T2AnYhMJu/TVzGhO/kv+ZkGmZVYWcT+lqXosh3n1X+XD98EdT4Icqjj41h1zmhCO # kJcx9Zyer8TxlldbqC2q1NqIVx2U3uCsdWYXELx4E8jeqJ3GpZXwnoL/MHl2bhAG # JnFr2033sPi6B/5132ohD4m36Z0AgrUORKF7t2bQKvesgjIOQE8HGDg3enGLduUG # M7s= # SIG # End signature block |