Sharing.ps1
#requires -Version 5.1 function Show-KeeperRecordShare { <# .Synopsis Shows a record sharing information .Parameter Record Record UID or any object containing property Uid #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true)]$Records ) Begin { [KeeperSecurity.Vault.VaultOnline]$vault = getVault [string[]]$recordUids = @() } Process { foreach ($r in $Records) { $uid = $null if ($r -is [String]) { $uid = $r } elseif ($null -ne $r.Uid) { $uid = $r.Uid } if ($uid) { [KeeperSecurity.Vault.KeeperRecord] $rec = $null if (-not $vault.TryGetKeeperRecord($uid, [ref]$rec)) { $entries = Get-KeeperChildItem -Filter $uid -ObjectType Record if ($entries.Uid) { $vault.TryGetRecord($entries[0].Uid, [ref]$rec) | Out-Null } } if ($rec) { $recordUids += $rec.Uid } else { Write-Error -Message "Cannot find a Keeper record: $r" -ErrorAction SilentlyContinue } } } } End { $vault.GetSharesForRecords($recordUids).GetAwaiter().GetResult() } } New-Alias -Name kshrsh -Value Show-KeeperRecordShare function Move-KeeperRecordOwnership { <# .Synopsis Transfers record ownership to a user .Parameter Record Record UID or any object containing property Uid .Parameter User User email #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Record, [Parameter(Mandatory = $true)]$User ) [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($Record -is [Array]) { if ($Record.Count -ne 1) { Write-Error -Message 'Only one record is expected' -ErrorAction Stop } $Record = $Record[0] } $uid = $null if ($Record -is [String]) { $uid = $Record } elseif ($null -ne $Record.Uid) { $uid = $Record.Uid } if ($uid) { [KeeperSecurity.Vault.KeeperRecord] $rec = $null if (-not $vault.TryGetKeeperRecord($uid, [ref]$rec)) { $entries = Get-KeeperChildItem -Filter $uid -ObjectType Record if ($entries.Uid) { $vault.TryGetRecord($entries[0].Uid, [ref]$rec) | Out-Null } } if ($rec) { try { $vault.TransferRecordToUser($rec.Uid, $User).GetAwaiter().GetResult() | Out-Null Write-Output "Record `"$($rec.Title)`" was transfered to $($User)`nThe new record owner can edit or remove your access to this record." } catch [KeeperSecurity.Vault.NoActiveShareWithUserException] { Write-Output $_ $prompt = "Do you want to send share invitation request to `"$($User)`"? (Yes/No)" $answer = Read-Host -Prompt $prompt if ($answer -in 'yes', 'y') { $vault.SendShareInvitationRequest($User).GetAwaiter().GetResult() | Out-Null Write-Output("Invitation has been sent to $($User)`nPlease repeat this command when your invitation is accepted."); } } } else { Write-Error -Message "Cannot find a Keeper record: $Record" } } } New-Alias -Name ktr -Value Move-KeeperRecordOwnership function Grant-KeeperRecordAccess { <# .SYNOPSIS Shares a Keeper record with a specified user, with optional edit/share permissions and flexible expiration input. .DESCRIPTION Grants access to a Keeper record to another user. You can specify edit and share permissions and optionally set an expiration using a time offset (as a TimeSpan object, minutes as an integer or string, or a TimeSpan-formatted string) or an ISO 8601-formatted absolute expiration datetime. .PARAMETER Record The UID of the Keeper record to share, or an object containing a 'Uid' property. .PARAMETER User The email address of the user to share the record with. .PARAMETER CanEdit Optional switch to grant edit permissions on the record. .PARAMETER CanShare Optional switch to grant re-share permissions on the record. .PARAMETER ExpireIn Optional. Expiration time offset from now. Can be a TimeSpan object, integer (minutes), or a string representing minutes or a TimeSpan. .PARAMETER ExpireAt Optional. An absolute expiration time in ISO 8601 or RFC 1123 format (e.g., "2025-05-23T08:59:11Z" or "Fri, 23 May 2025 08:59:11 GMT"). .EXAMPLE Grant-KeeperRecordAccess -Record "XP-TKMqg9kIf4RXLuW4Qwg" -User "jane.doe@example.com" -CanEdit -CanShare Shares the record with full permissions (edit and re-share) with Jane Doe. .EXAMPLE Grant-KeeperRecordAccess -Record "XP-TKMqg9kIf4RXLuW4Qwg" -User "john.doe@example.com" -ExpireIn 60 Shares the record with John Doe for 1 hour from now. .EXAMPLE Grant-KeeperRecordAccess -Record "XP-TKMqg9kIf4RXLuW4Qwg" -User "alice@example.com" -ExpireIn "00:30:00" Shares the record with Alice for 30 minutes. .EXAMPLE Grant-KeeperRecordAccess -Record "XP-TKMqg9kIf4RXLuW4Qwg" -User "bob@example.com" -ExpireAt "2025-05-23T08:59:11Z" Shares the record with Bob until the specified UTC datetime. #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Record, [Parameter(Mandatory = $true)]$User, [Parameter()][switch]$CanEdit, [Parameter()][switch]$CanShare, [Parameter()][System.Object]$ExpireIn, [Parameter()][string]$ExpireAt ) [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($Record -is [Array]) { if ($Record.Count -ne 1) { Write-Error -Message 'Only one record is expected' -ErrorAction Stop } $Record = $Record[0] } $uid = $null if ($Record -is [String]) { $uid = $Record } elseif ($null -ne $Record.Uid) { $uid = $Record.Uid } $options = [KeeperSecurity.Vault.SharedFolderRecordOptions]::new() try{ $expiration = Get-ExpirationDate -ExpireIn $ExpireIn -ExpireAt $ExpireAt $options.CanEdit = $CanEdit.IsPresent $options.CanShare = $CanShare.IsPresent $options.Expiration = $expiration }catch { Write-Error "Error: $($_.Exception.Message)" -ErrorAction Stop throw } if ($uid) { [KeeperSecurity.Vault.KeeperRecord] $rec = $null if (-not $vault.TryGetKeeperRecord($uid, [ref]$rec)) { $entries = Get-KeeperChildItem -Filter $uid -ObjectType Record if ($entries.Uid) { $vault.TryGetRecord($entries[0].Uid, [ref]$rec) | Out-Null } } if ($rec) { try { $shareOptions = New-Object KeeperSecurity.Vault.SharedFolderRecordOptions $shareOptions.CanEdit = $CanEdit.IsPresent $shareOptions.CanShare = $CanShare.IsPresent $vault.ShareRecordWithUser($rec.Uid, $User, $shareOptions).GetAwaiter().GetResult() | Out-Null Write-Output "Record `"$($rec.Title)`" was shared with $($User)" } catch [KeeperSecurity.Vault.NoActiveShareWithUserException] { Write-Output $_ $prompt = "Do you want to send share invitation request to `"$($User)`"? (Yes/No)" $answer = Read-Host -Prompt $prompt if ($answer -in 'yes', 'y') { $vault.SendShareInvitationRequest($User).GetAwaiter().GetResult() | Out-Null Write-Output("Invitation has been sent to $($User)`nPlease repeat this command when your invitation is accepted."); } } } else { Write-Error -Message "Cannot find a Keeper record: $Record" } } } New-Alias -Name kshr -Value Grant-KeeperRecordAccess function Get-ExpirationDate { param( [object]$ExpireIn, [string]$ExpireAt ) $expireOffset = $null if ($ExpireIn) { if ($ExpireIn -is [TimeSpan]) { $expireOffset = $ExpireIn } elseif ($ExpireIn -is [int]) { $expireOffset = [TimeSpan]::FromMinutes($ExpireIn) } elseif ($ExpireIn -is [string]) { $parsedMinutes = $null if ([int]::TryParse($ExpireIn, [ref]$parsedMinutes)) { $expireOffset = [TimeSpan]::FromMinutes($parsedMinutes) } else { try { $expireOffset = [TimeSpan]::Parse($ExpireIn) } catch { throw "Cannot parse ExpireIn string value '$ExpireIn' - not a number or valid TimeSpan string." } } } else { throw "Unsupported type for ExpireIn: $($ExpireIn.GetType().FullName)" } return [DateTimeOffset]::UtcNow.Add($expireOffset) } elseif ($ExpireAt) { try { return [DateTimeOffset]::Parse($ExpireAt) } catch { throw "Cannot parse ExpireAt: '$ExpireAt'. Must be a valid ISO 8601 or RFC 1123 string." } } else { return $null # No expiration } } function Revoke-KeeperRecordAccess { <# .Synopsis Shares a record with user .Parameter Record Record UID or any object containg record UID .Parameter User User email #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Record, [Parameter(Mandatory = $true)]$User ) [KeeperSecurity.Vault.VaultOnline]$vault = getVault if ($Record -is [Array]) { if ($Record.Count -ne 1) { Write-Error -Message 'Only one record is expected' return } $Record = $Record[0] } $uid = $null if ($Record -is [String]) { $uid = $Record } elseif ($null -ne $Record.Uid) { $uid = $Record.Uid } $found = $false if ($uid) { [KeeperSecurity.Vault.KeeperRecord] $rec = $null if (-not $vault.TryGetKeeperRecord($uid, [ref]$rec)) { $entries = Get-KeeperChildItem -Filter $uid -ObjectType Record if ($entries.Uid) { $vault.TryGetRecord($entries[0].Uid, [ref]$rec) | Out-Null } } if ($rec) { $found = $true $vault.RevokeShareFromUser($rec.Uid, $User).GetAwaiter().GetResult() | Out-Null Write-Output "Record `"$($rec.Title)`" share has been removed from $($username)" } } if (-not $found) { Write-Error -Message "Cannot find a Keeper record: $Record" } } New-Alias -Name kushr -Value Revoke-KeeperRecordAccess function Grant-KeeperSharedFolderAccess { <# .Synopsis Adds a user or team to a shared foler .Parameter SharedFolder Shared Folder UID, name or any object containing property Uid .Parameter User User email .Parameter Team Team Name or UID .Parameter ManageRecords Grant Manage Records permission .Parameter ManageUsers Grant Manage Users permission #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true, Position = 0)]$SharedFolder, [Parameter(Mandatory = $true, ParameterSetName='user')]$User, [Parameter(Mandatory = $true, ParameterSetName='team')]$Team, [Parameter()][switch]$ManageRecords, [Parameter()][switch]$ManageUsers ) [KeeperSecurity.Vault.VaultOnline]$private:vault = getVault if ($SharedFolder -is [Array]) { if ($SharedFolder.Count -ne 1) { Write-Error -Message 'Only one shared folder is expected' return } $SharedFolder = $SharedFolder[0] } $uid = $null if ($SharedFolder -is [String]) { $uid = $SharedFolder } elseif ($null -ne $Record.Uid) { $uid = $SharedFolder.Uid } if (-not $uid) { Write-Error -Message "Cannot find Shared Folder: $SharedFolder" -ErrorAction Stop } [KeeperSecurity.Vault.SharedFolder] $sf = $null if (-not $vault.TryGetSharedFolder($uid, [ref]$sf)) { $sf = $vault.SharedFolders | Where-Object { $_.Name -eq $uid } | Select-Object -First 1 } if (-not $sf) { Write-Error -Message "Cannot find Shared Folder: $SharedFolder" -ErrorAction Stop } if ($User) { $userType = [KeeperSecurity.Vault.UserType]::User $userId = ([MailAddress]$User).Address $userName = $userId if (-not $userId) { return } } elseif ($Team) { $userType = [KeeperSecurity.Vault.UserType]::Team [KeeperSecurity.Vault.TeamInfo]$teamInfo = $null if ($vault.TryGetTeam($Team, [ref]$teamInfo)) { $userId = $teamInfo.TeamUid $userName = $teamInfo.Name } else { $teamInfo = $vault.Teams | Where-Object { $_.Name -eq $Team } | Select-Object -First 1 if ($teamInfo) { $userId = $teamInfo.TeamUid $userName = $teamInfo.Name } } if (-not $userId) { ensureAvalableLoaded $teamInfo = $Script:Context.AvailableTeams | Where-Object { $_.TeamUid -ceq $Team -or $_.Name -eq $Team } | Select-Object -First 1 if ($teamInfo) { $userId = $teamInfo.TeamUid $userName = $teamInfo.Name } } if (-not $userId) { Write-Error -Message "Cannot find team: $Team" -ErrorAction Stop } } try { $options = New-Object KeeperSecurity.Vault.SharedFolderUserOptions $options.ManageRecords = $ManageRecords.IsPresent $options.ManageUsers = $ManageUsers.IsPresent $vault.PutUserToSharedFolder($sf.Uid, $userId, $userType, $options).GetAwaiter().GetResult() | Out-Null Write-Output "${userType} `"$($userName)`" has been added to shared folder `"$($sf.Name)`"" } catch [KeeperSecurity.Vault.NoActiveShareWithUserException] { Write-Output $_ $prompt = "Do you want to send share invitation request to `"$($User)`"? (Yes/No)" $answer = Read-Host -Prompt $prompt if ($answer -in 'yes', 'y') { $vault.SendShareInvitationRequest($User).GetAwaiter().GetResult() | Out-Null Write-Output("Invitation has been sent to `"$($User)`"`nPlease repeat this command when your invitation is accepted."); } } } function Revoke-KeeperSharedFolderAccess { <# .Synopsis Removes record share from user .Parameter SharedFolder Shared Folder UID, name or any object containing property Uid .Parameter User User email .Parameter Team Team Name or UID #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true, Position = 0)]$SharedFolder, [Parameter(Mandatory = $true, ParameterSetName='user')]$User, [Parameter(Mandatory = $true, ParameterSetName='team')]$Team ) [KeeperSecurity.Vault.VaultOnline]$private:vault = getVault if ($SharedFolder -is [Array]) { if ($SharedFolder.Count -ne 1) { Write-Error -Message 'Only one shared folder is expected' return } $SharedFolder = $SharedFolder[0] } $uid = $null if ($SharedFolder -is [String]) { $uid = $SharedFolder } elseif ($null -ne $Record.Uid) { $uid = $SharedFolder.Uid } if (-not $uid) { Write-Error -Message "Cannot find Shared Folder: $SharedFolder" -ErrorAction Stop } [KeeperSecurity.Vault.SharedFolder] $sf = $null if (-not $vault.TryGetSharedFolder($uid, [ref]$sf)) { $sf = $vault.SharedFolders | Where-Object { $_.Name -eq $uid } | Select-Object -First 1 } if (-not $sf) { Write-Error -Message "Cannot find Shared Folder: $SharedFolder" -ErrorAction Stop } if ($User) { $userType = [KeeperSecurity.Vault.UserType]::User $userId = ([MailAddress]$User).Address $userName = $userId if (-not $userId) { return } } elseif ($Team) { $userType = [KeeperSecurity.Vault.UserType]::Team [KeeperSecurity.Vault.TeamInfo]$teamInfo = $null if ($vault.TryGetTeam($Team, [ref]$teamInfo)) { $userId = $teamInfo.TeamUid $userName = $teamInfo.Name } else { $teamInfo = $vault.Teams | Where-Object { $_.Name -eq $Team } | Select-Object -First 1 if ($teamInfo) { $userId = $teamInfo.TeamUid $userName = $teamInfo.Name } } if (-not $userId) { ensureAvalableLoaded $teamInfo = $Script:Context.AvailableTeams | Where-Object { $_.TeamUid -ceq $Team -or $_.Name -eq $Team } | Select-Object -First 1 if ($teamInfo) { $userId = $teamInfo.TeamUid $userName = $teamInfo.Name } } if (-not $userId) { Write-Error -Message "Cannot find team: $Team" -ErrorAction Stop } } $vault.RemoveUserFromSharedFolder($sf.Uid, $userId, $userType).GetAwaiter().GetResult() | Out-Null Write-Output "${userType} `"$($userName)`" has been removed from shared folder `"$($sf.Name)`"" } function ensureAvalableLoaded { $vault = $Script:Context.Vault if (-not $vault) { return } if ($null -ne $Script:Context.AvailableTeams) { return } $Script:Context.AvailableTeams = @() $Script:Context.AvailableUsers = @() $teamTask = $vault.GetTeamsForShare() $userTask = $vault.GetUsersForShare() [System.Threading.Tasks.Task[]]$tasks = $teamTask, $userTask [System.Threading.Tasks.Task]::WaitAll($tasks) | Out-Null $Script:Context.AvailableTeams += $teamTask.GetAwaiter().GetResult() $userInfo = $userTask.GetAwaiter().GetResult() $users = @() $users += $userInfo.SharesWith $users += $userInfo.SharesFrom $users += $userInfo.GroupUsers $Script:Context.AvailableUsers += ($users | Sort-Object | Get-Unique) } $Keeper_TeamCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) ensureAvalableLoaded if (-not $Script:Context.AvailableTeams) { return $null } $result = @() $toComplete = $wordToComplete if ($toComplete.Length -ge 1) { if ($toComplete[0] -eq '''') { $toComplete = $toComplete.Substring(1, $toComplete.Length - 1) $toComplete = $toComplete -replace '''''', '''' } if ($toComplete[0] -eq '"') { $toComplete = $toComplete.Substring(1, $toComplete.Length - 1) $toComplete = $toComplete -replace '""', '"' $toComplete = $toComplete -replace '`"', '"' } } $toComplete += '*' foreach ($team in $Script:Context.AvailableTeams) { if ($team.Name -like $toComplete) { $name = $team.Name if ($name -match ' ') { $name = $name -replace '''', '''''' $name = '''' + $name + '''' } $result += $name } } if ($result.Count -gt 0) { return $result } else { return $null } } $Keeper_UserCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) ensureAvalableLoaded if (-not $Script:Context.AvailableUsers) { return $null } $result = @() $toComplete = $wordToComplete if ($toComplete.Length -ge 1) { if ($toComplete[0] -eq '''') { $toComplete = $toComplete.Substring(1, $toComplete.Length - 1) $toComplete = $toComplete -replace '''''', '''' } if ($toComplete[0] -eq '"') { $toComplete = $toComplete.Substring(1, $toComplete.Length - 1) $toComplete = $toComplete -replace '""', '"' $toComplete = $toComplete -replace '`"', '"' } } $toComplete += '*' foreach ($user in $Script:Context.AvailableUsers) { if ($user -like $toComplete) { $result += $user } } if ($result.Count -gt 0) { return $result } else { return $null } } Register-ArgumentCompleter -CommandName Grant-KeeperSharedFolderAccess -ParameterName Team -ScriptBlock $Keeper_TeamCompleter Register-ArgumentCompleter -CommandName Grant-KeeperSharedFolderAccess -ParameterName User -ScriptBlock $Keeper_UserCompleter Register-ArgumentCompleter -CommandName Grant-KeeperSharedFolderAccess -ParameterName SharedFolder -ScriptBlock $Keeper_SharedFolderCompleter New-Alias -Name kshf -Value Grant-KeeperSharedFolderAccess Register-ArgumentCompleter -CommandName Revoke-KeeperSharedFolderAccess -ParameterName Team -ScriptBlock $Keeper_TeamCompleter Register-ArgumentCompleter -CommandName Revoke-KeeperSharedFolderAccess -ParameterName User -ScriptBlock $Keeper_UserCompleter Register-ArgumentCompleter -CommandName Revoke-KeeperSharedFolderAccess -ParameterName SharedFolder -ScriptBlock $Keeper_SharedFolderCompleter New-Alias -Name kushf -Value Revoke-KeeperSharedFolderAccess function Get-KeeperAvailableTeam { <# .Synopsis Get Keeper Available Teams .Parameter Uid Team UID .Parameter Filter Return matching teams only #> [CmdletBinding()] [OutputType([KeeperSecurity.Vault.TeamInfo[]])] Param ( [string] $Uid, [string] $Filter ) ensureAvalableLoaded $teams = $Script:Context.AvailableTeams if ($Uid) { $teams | Where-Object { $_.TeamUid -ceq $Uid } | Select-Object -First 1 } else { foreach ($team in $teams) { if ($Filter) { $match = $($team.Uid, $team.Name) | Select-String $Filter | Select-Object -First 1 if (-not $match) { continue } } $team } } } New-Alias -Name kat -Value Get-KeeperAvailableTeam function New-KeeperOneTimeShare { <# .SYNOPSIS Creates a secure one-time share link for a Keeper record, with optional expiration settings and a custom name. .DESCRIPTION This command generates a one-time access link to a specified Keeper record. You can choose to set the link to expire after a specific duration (ExpireIn) or at an exact date/time (ExpireAt). You may also provide a custom name for easier identification. Once the link expires or is used, it can no longer be accessed. .PARAMETER Uid The UID of the record to share. .PARAMETER ExpireIn Optional. Expiration offset (TimeSpan, string, or integer in minutes). .PARAMETER ExpireAt Optional. Absolute expiration timestamp (ISO 8601 or RFC 1123). .PARAMETER ShareName Optional. Custom label for the one-time share. .EXAMPLE New-KeeperOneTimeShare -Uid "XP-TKMqg9kIf4RXLuW4Qwg" -ExpireIn 60 Creates a one-time share link for the record that expires in 60 minutes from now. .EXAMPLE New-KeeperOneTimeShare -Uid "XP-TKMqg9kIf4RXLuW4Qwg" -ExpireIn "00:45:00" -ShareName "Temporary Share" Creates a one-time share that expires in 45 minutes with a custom label "Temporary Share". .EXAMPLE New-KeeperOneTimeShare -Uid "XP-TKMqg9kIf4RXLuW4Qwg" -ExpireAt "2025-05-28T12:00:00Z" Creates a one-time share that will expire exactly at the specified UTC time. .EXAMPLE New-KeeperOneTimeShare -Uid "XP-TKMqg9kIf4RXLuW4Qwg" -ExpireAt "Wed, 28 May 2025 12:00:00 GMT" -ShareName "Expires Noon" Creates a one-time share that expires at 12 PM UTC on May 28, 2025, with the name "Expires Noon". #> [CmdletBinding()] [OutputType([string])] Param ( [Parameter(Mandatory = $true)][string] $Uid, [Parameter()][object] $ExpireIn, [Parameter()][string] $ExpireAt, [Parameter()][string] $ShareName ) try { $expiration = Get-ExpirationDate -ExpireIn $ExpireIn -ExpireAt $ExpireAt if (-not $expiration) { throw "You must provide either ExpireIn or ExpireAt." } $expirationTimeSpan = $expiration.ToUniversalTime() - [DateTimeOffset]::UtcNow [KeeperSecurity.Vault.VaultOnline]$vault = GetVault $oneTimeShare = [KeeperSecurity.Vault.ExternalRecordShareExtensions]::CreateExternalRecordShare( $vault, $Uid, $expirationTimeSpan, $ShareName ).GetAwaiter().GetResult() return $oneTimeShare } catch { Write-Error "Error creating one-time share: $($_.Exception.Message)" -ErrorAction Stop } } New-Alias -Name kotsn -Value New-KeeperOneTimeShare function Get-KeeperOneTimeShare { <# .Synopsis Get Keeper One-Time Shares .Parameter Uid Shared Record UID #> [CmdletBinding()] [OutputType([string])] Param ( [Parameter(Mandatory = $true, Position=0)][string] $Uid ) [KeeperSecurity.Vault.VaultOnline]$vault = getVault [KeeperSecurity.Vault.ExternalRecordShareExtensions]::GetExernalRecordShares($vault, $Uid).GetAwaiter().GetResult() } New-Alias -Name kotsg -Value Get-KeeperOneTimeShare function Remove-KeeperOneTimeShare { <# .Synopsis Deletes Keeper One-Time Share(s) .Parameter Uid Shared Record UID .Parameter ShareName One-Time Share Name #> [CmdletBinding()] [OutputType([string])] Param ( [Parameter(Mandatory = $true)][string] $Uid, [string[]] $ShareName ) [KeeperSecurity.Vault.VaultOnline]$vault = getVault $shares = Get-KeeperOneTimeShare $Uid [String[]]$clientUids = @() foreach ($n in $ShareName) { $share = $shares | Where-Object { $_.Name -eq $n } | Select-Object -First 1 if ($share) { $clientUids += $share.ClientId } else { Write-Information -MessageData "One-Time Share not found: $n" } } [KeeperSecurity.Vault.ExternalRecordShareExtensions]::DeleteExernalRecordShares($vault, $Uid, $clientUids).GetAwaiter().GetResult() | Out-Null } New-Alias -Name kotsr -Value Remove-KeeperOneTimeShare # SIG # Begin signature block # MIIngQYJKoZIhvcNAQcCoIIncjCCJ24CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD8jhbiTBzuKzdK # nREOQtVFgQMq4dQy7swsoBKWm0Ie36CCIQQwggWNMIIEdaADAgECAhAOmxiO+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 # twGpn1eqXijiuZQwggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqG # SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMy # RGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcg # Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXH # JQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMf # UBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w # 1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRk # tFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYb # qMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUm # cJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP6 # 5x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzK # QtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo # 80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjB # Jgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXche # MBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB # /wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU # 7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoG # CCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29j # c3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDig # NqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v # dEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZI # hvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd # 4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiC # qBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl # /Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeC # RK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYT # gAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/ # a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37 # xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmL # NriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0 # YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJ # RyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIG # sDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw # HhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEX # MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0 # ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjAN # BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zr # PYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHM # gQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8Irg # nQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyC # EUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0 # p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQa # khCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0 # XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960I # HnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2 # FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBH # X8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q2 # 7IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD # VR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1k # TN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcD # AzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj # ZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t # L0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0 # cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmww # HAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIB # ADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6j # fCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmI # moqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtf # JqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrx # oj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3 # LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx # 4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9 # Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+I # Cw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug # 0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5 # Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIGvDCCBKSgAwIBAgIQ # C65mvFq6f5WHxvnpBOMzBDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEX # MBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0 # ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTI0MDkyNjAw # MDAwMFoXDTM1MTEyNTIzNTk1OVowQjELMAkGA1UEBhMCVVMxETAPBgNVBAoTCERp # Z2lDZXJ0MSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyNDCCAiIwDQYJ # KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL5qc5/2lSGrljC6W23mWaO16P2RHxjE # iDtqmeOlwf0KMCBDEr4IxHRGd7+L660x5XltSVhhK64zi9CeC9B6lUdXM0s71EOc # Re8+CEJp+3R2O8oo76EO7o5tLuslxdr9Qq82aKcpA9O//X6QE+AcaU/byaCagLD/ # GLoUb35SfWHh43rOH3bpLEx7pZ7avVnpUVmPvkxT8c2a2yC0WMp8hMu60tZR0Cha # V76Nhnj37DEYTX9ReNZ8hIOYe4jl7/r419CvEYVIrH6sN00yx49boUuumF9i2T8U # uKGn9966fR5X6kgXj3o5WHhHVO+NBikDO0mlUh902wS/Eeh8F/UFaRp1z5SnROHw # SJ+QQRZ1fisD8UTVDSupWJNstVkiqLq+ISTdEjJKGjVfIcsgA4l9cbk8Smlzddh4 # EfvFrpVNnes4c16Jidj5XiPVdsn5n10jxmGpxoMc6iPkoaDhi6JjHd5ibfdp5uzI # Xp4P0wXkgNs+CO/CacBqU0R4k+8h6gYldp4FCMgrXdKWfM4N0u25OEAuEa3Jyidx # W48jwBqIJqImd93NRxvd1aepSeNeREXAu2xUDEW8aqzFQDYmr9ZONuc2MhTMizch # NULpUEoA6Vva7b1XCB+1rxvbKmLqfY/M/SdV6mwWTyeVy5Z/JkvMFpnQy5wR14GJ # cv6dQ4aEKOX5AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/ # BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEE # AjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8w # HQYDVR0OBBYEFJ9XLAN3DigVkGalY17uT5IfdqBbMFoGA1UdHwRTMFEwT6BNoEuG # SWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQw # OTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQG # CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKG # TGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJT # QTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIB # AD2tHh92mVvjOIQSR9lDkfYR25tOCB3RKE/P09x7gUsmXqt40ouRl3lj+8QioVYq # 3igpwrPvBmZdrlWBb0HvqT00nFSXgmUrDKNSQqGTdpjHsPy+LaalTW0qVjvUBhcH # zBMutB6HzeledbDCzFzUy34VarPnvIWrqVogK0qM8gJhh/+qDEAIdO/KkYesLyTV # OoJ4eTq7gj9UFAL1UruJKlTnCVaM2UeUUW/8z3fvjxhN6hdT98Vr2FYlCS7Mbb4H # v5swO+aAXxWUm3WpByXtgVQxiBlTVYzqfLDbe9PpBKDBfk+rabTFDZXoUke7zPgt # d7/fvWTlCs30VAGEsshJmLbJ6ZbQ/xll/HjO9JbNVekBv2Tgem+mLptR7yIrpaid # RJXrI+UzB6vAlk/8a1u7cIqV0yef4uaZFORNekUgQHTqddmsPCEIYQP7xGxZBIhd # mm4bhYsVA6G2WgNFYagLDBzpmk9104WQzYuVNsxyoVLObhx3RugaEGru+SojW4dH # PoWrUhftNpFC5H7QEY7MhKRyrBe7ucykW7eaCuWBsBb4HOKRFVDcrZgdwaSIqMDi # CLg4D+TPVgKx2EgEdeoHNHT9l3ZDBD+XgbF+23/zBjeCtxz+dL/9NWR6P2eZRi7z # cEO1xwcdcqJsyz/JceENc2Sg8h3KeFUCS7tpFk7CrDqkMIIHSTCCBTGgAwIBAgIQ # BaOjGrg1T58olh09AgdhuDANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEX # MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0 # ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMB4XDTI0 # MTIzMTAwMDAwMFoXDTI1MTIzMDIzNTk1OVowgdExEzARBgsrBgEEAYI3PAIBAxMC # VVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVsYXdhcmUxHTAbBgNVBA8MFFByaXZhdGUg # T3JnYW5pemF0aW9uMRAwDgYDVQQFEwczNDA3OTg1MQswCQYDVQQGEwJVUzERMA8G # A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xHTAbBgNVBAoTFEtlZXBl # ciBTZWN1cml0eSBJbmMuMR0wGwYDVQQDExRLZWVwZXIgU2VjdXJpdHkgSW5jLjCC # AaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAM7/rBevApUP+XJjlSxdyASA # AnLFQ1r4NFXPo/S0RaTv1OCahApEeSN6oy+0OwbLNlwaQeooOanMcZhh64/+fF8S # zCMHDc/Pv8aBsd1B2XIw/VT+Nawfj0NxAX1zpKPp/tPqavm6smRDMOAeOo7qLxzI # u68bS2EnqvST1367tMpxhggrVl3GYKPhdCPeNDRskwheCSxI2czR8oe7mguo2nVa # ZR5VEq4xYkMZwTuT7RN8ER4r5crOSbJFyabp79SgYP7NyKmDcYZ6XJ26AfZsEDZr # e4VhzaqO0rl8i5HBmVmDKwU0PaIoAUdyeultIaS5oe0FjcTjGtrkBl+B7TCtvN1J # RE9Tmy3spnqLyvlRhrVJdDKCGovQKKJk87BAjIoiNSmEXs0H0PbB1ZYOA6m4ce7/ # BOmUafliYWBqrWHmHixqi/ha5ZKxKlYxGlikD4p1WlMmDEBhg3RPodW1Z5eGq92Z # exMGOWsfOQp3YhTDdMOA7tjWP2XzAaebGxCeOENEpQIDAQABo4ICAjCCAf4wHwYD # VR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFOcovsKg6xAz # zjzRmmWQRpa7p47MMD0GA1UdIAQ2MDQwMgYFZ4EMAQMwKTAnBggrBgEFBQcCARYb # aHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIHgDATBgNV # HSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3Js # My5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQw # OTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAy # MUNBMS5jcmwwgZQGCCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUFBzABhhhodHRwOi8v # b2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI # QTM4NDIwMjFDQTEuY3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBALIq # AoEjkKZluMiOffwU+V+wiKkmDblKIZymyszEZot+niB6g7tRXrWkQo6gn8OG2qG6 # IO8L+o0VvwW0+V08p6gVqb0jeR9kCm7kDZk2RmzevhZDrRbZj0Q7Kb3pIeD9KEuc # RfEF0UGqgp0q7jerFXPzKtQk5kJpP65sSRV7bghIMWtq5sdHn/iGUMj+8Fd9AExq # 4kR+dyTw/6p1ZFiY7pIv4YAjjDrjkyUMSogt6ej9YGwTC8yVXJsjarLq2F+svwn8 # NlU+T03U/ZjXc/ZxDc5g3iqrl5Gm9QCaLhG2aLIrGRXN59Pcokp7JFNa6nkkWSSg # h4w01tz+xRSyiqKWAXNs2lHTD2F9ceGlz9Uw/RvPhPcl6bILqJcR6RUkzZtrKHNK # j85PBm/Kmurx0co5xRxXsXsF3tmp2r+Tt11veA9je+pyzuqE/kRQPn5hF8fIRuea # h7JVMaaHBTMbRaDcVFioGmCGHUx270yhLapA0eYXpZJv0n62QIMoX9NPcW2EcwhL # WGAV1IW+TIo/xcprAXBtXCO/mhscgInbMzesdg0uWsboiy4HfeTEzCe9ld54biUK # TJQu4wqbzkN5SGewOKTd/+c4k5w6yzuUWsk3YZpjWqsgpTlA3zU591uvMFsq0FYd # A3Py8YsVabLwTxz9d7kpBAHTPRYwDcsKNLGMPc+6MYIF0zCCBc8CAQEwfTBpMQsw # CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERp # Z2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIw # MjEgQ0ExAhAFo6MauDVPnyiWHT0CB2G4MA0GCWCGSAFlAwQCAQUAoIGEMBgGCisG # AQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIA3l # DZv6+9cumA+984feBuwsYjs+U9Lrdw3dJ5TaGka6MA0GCSqGSIb3DQEBAQUABIIB # gF7OW/6wc6W/n6OrfEAvXlAgO4oxVC4P6gLmX7ZAFxccny2RiHix5ak6f7x3ZJSK # bA2v/urGIwMX/j3NFfn03R3tS7Bikvy1+ESs4TW479NGtpU1WvVIpjni8YFsKl5r # ZCl0IE5KgiFn2fb8XynvHdh9+blRq9ZhNGdK9rfUzXyVVf+n/6ttfOH790A0Hipo # y1iOGoSd7/O/4lkdAMM4Q1adXykf3JIrqN/dTEG5eaQnrvtw0n9wmjFsfKHK98bD # jO8gNLD5BqiNRqMtUPhskoQlKiA7buXImJJTXx4qghiCBPg719QkUkR0wKTRvmyD # rGoEdCtVjgdq8kPiC4DHrwhXBfB1lqguoQleRYOJkpEhv95dTLoZC8Qk7OuTGDOB # p7XwKZc6ZznE6efiDhoGcByDF4K3ZreFN3jY2Tyw1y+5lkLkmhxVMVdafSX08x2a # kK9Dc/D1Y7j11Nfivw/2RYQ3Z7eZ3xs7cCVbLKXalmheIhE8giOaOKzZN01SAd+G # nqGCAyAwggMcBgkqhkiG9w0BCQYxggMNMIIDCQIBATB3MGMxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1 # c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEAuuZrxaun+V # h8b56QTjMwQwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcN # AQcBMBwGCSqGSIb3DQEJBTEPFw0yNTA2MzAxNzI2MjBaMC8GCSqGSIb3DQEJBDEi # BCCjSSff1f3C1lLBGqBJA8Hk4mMBeKc9jvmw/mH4EXvCZDANBgkqhkiG9w0BAQEF # AASCAgBCikeZnPuSF8KPixVSZfSgFxtA5s8rbodZn30JYSNbMSU8qwFPHdt7E8wF # Xe6KDN9Rn2CtLGULakO5LWWeeY4lAtOF6465ysPyqJ9hIhS2l0BJP5p0Vjxe5A9J # E9q+RN7er+f7i2WY4nKZLnkA2Xh9kAOAbnr7M433UqCSei8elBclfPJQSdG0dVJt # 3LJ4Lxo0RKb834LE7qMSni4NhjThVKP19C6kODxJQ6wRyVFArSfPMdhWjsRfkQ5u # NRoDWET2/tomObWtZUK8JQ0A9kvOee/oZUaf5UbJlmDAHsgAdfvamcuCXLfC7WcQ # 5He/C7axPhxcAF/b/BKheM73eFh9WiITMaQZAOfEl04lvlGU+mLy0vYOdI4WPJPi # 6Ii9x0cFBtGYfvro+zpyu2GNMXm8cf1ANZ8LD+F7/R2rP0Zk+Jmhxvb4wfSyT6xg # gtdq4hJcPKQdRqzyT4zLP07ZiJCCgGmFKP4DhUYd4A3fLyE9VhioqeVZh82El0g1 # +Du0tGEDKLvEt4oGbAK/9s0hohpznacv+FivMSvdyar5KbXCnus6+lxFchtiPLzk # aUJ4qb7o06oVdRJZkwtpQuaqpVRroT8AoFEq2wABXiX5IgbaFvZC/DlEVBaW60yd # 58n3JaqSAOcStAk03nGouih/Slsd3dIGPa/EnVZHh0xMgXmudA== # SIG # End signature block |