Public/Get/Get-CUCredentialManagerContents.ps1

function Get-CUCredentialManagerContents {
    <#
    .SYNOPSIS
    Returns Credential Manager entry metadata for the current user context,
    including remote interactive user sessions.
 
    .DESCRIPTION
    Uses `cmdkey /list` and parses only metadata fields (Target, Type, User,
    Persistence, Comment). No secret material is read or returned.
 
    For remote hosts, this function can query the active interactive session by
    creating a short-lived scheduled task in the interactive user context on the
    target machine.
 
    .PARAMETER ComputerName
    One or more computer names to query. Defaults to localhost.
 
    .PARAMETER Credential
    Credential used for remoting.
 
    .PARAMETER UseSsh
    Use SSH transport instead of WSMan when creating remote sessions.
 
    .PARAMETER UseCredSSP
    Use CredSSP for WSMan remoting.
 
    .PARAMETER Port
    SSH port when -UseSsh is specified.
 
    .PARAMETER Ps7ConfigName
    WSMan PowerShell 7 endpoint name.
 
    .PARAMETER WinPsConfigName
    WSMan Windows PowerShell endpoint name.
 
    .PARAMETER UserName
    SSH username when not using PSCredential.
 
    .PARAMETER KeyFilePath
    SSH private key path when using key-based authentication.
 
    .PARAMETER TimeoutSec
    Maximum time to wait for the remote interactive collection task to finish.
    #>

    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [Alias('Name', 'CN')]
        [string[]]$ComputerName = @('localhost'),

        [pscredential]$Credential,

        [switch]$UseSsh,
        [switch]$UseCredSSP,

        [int]$Port = 22,

        [string]$Ps7ConfigName = 'PowerShell.7',
        [string]$WinPsConfigName = 'Microsoft.PowerShell',

        [string]$UserName,
        [string]$KeyFilePath,

        [ValidateRange(5, 300)]
        [int]$TimeoutSec = 45
    )

    begin {
        Set-StrictMode -Version Latest
        Initialize-TechToolboxRuntime

        function ConvertFrom-CmdKeyText {
            [CmdletBinding()]
            param(
                [Parameter(Mandatory)]
                [string]$Text,

                [Parameter(Mandatory)]
                [string]$HostName,

                [Parameter(Mandatory)]
                [string]$ContextUser,

                [Parameter(Mandatory)]
                [string]$CollectionMode
            )

            $results = New-Object System.Collections.Generic.List[object]
            if ([string]::IsNullOrWhiteSpace($Text)) {
                return $results
            }

            function Get-FieldValue {
                param(
                    [Parameter(Mandatory)]
                    [hashtable]$Map,
                    [Parameter(Mandatory)]
                    [string]$Key
                )

                if ($Map.Contains($Key)) {
                    return [string]$Map[$Key]
                }

                return ''
            }

            $current = [ordered]@{}
            $seenAnyField = $false

            foreach ($line in ($Text -split "`r?`n")) {
                if ([string]::IsNullOrWhiteSpace($line)) {
                    if ($seenAnyField) {
                        $results.Add([pscustomobject]@{
                                ComputerName   = $HostName
                                SessionUser    = $ContextUser
                                CollectionMode = $CollectionMode
                                Target         = Get-FieldValue -Map $current -Key 'Target'
                                Type           = Get-FieldValue -Map $current -Key 'Type'
                                User           = Get-FieldValue -Map $current -Key 'User'
                                Persistence    = Get-FieldValue -Map $current -Key 'Persistence'
                                Comment        = Get-FieldValue -Map $current -Key 'Comment'
                            })
                        $current = [ordered]@{}
                        $seenAnyField = $false
                    }
                    continue
                }

                if ($line -match '^\s*([^:]+):\s*(.*)$') {
                    $key = $matches[1].Trim()
                    $value = $matches[2].Trim()

                    switch -Regex ($key) {
                        '^(Target|Ziel)$' {
                            $current.Target = $value
                            $seenAnyField = $true
                        }
                        '^(Type|Typ)$' {
                            $current.Type = $value
                            $seenAnyField = $true
                        }
                        '^(User|Benutzer)$' {
                            $current.User = $value
                            $seenAnyField = $true
                        }
                        '^Persistence$' {
                            $current.Persistence = $value
                            $seenAnyField = $true
                        }
                        '^Comment$' {
                            $current.Comment = $value
                            $seenAnyField = $true
                        }
                    }
                }
            }

            if ($seenAnyField) {
                $results.Add([pscustomobject]@{
                        ComputerName   = $HostName
                        SessionUser    = $ContextUser
                        CollectionMode = $CollectionMode
                        Target         = Get-FieldValue -Map $current -Key 'Target'
                        Type           = Get-FieldValue -Map $current -Key 'Type'
                        User           = Get-FieldValue -Map $current -Key 'User'
                        Persistence    = Get-FieldValue -Map $current -Key 'Persistence'
                        Comment        = Get-FieldValue -Map $current -Key 'Comment'
                    })
            }

            return $results
        }

        function Test-IsLocalTarget {
            param([Parameter(Mandatory)][string]$Target)

            $norm = $Target.Trim().ToLowerInvariant()
            $localNames = @(
                '.',
                'localhost',
                $env:COMPUTERNAME.ToLowerInvariant(),
                "$($env:COMPUTERNAME).$($env:USERDNSDOMAIN)".TrimEnd('.').ToLowerInvariant()
            )

            return $localNames -contains $norm
        }
    }

    process {
        foreach ($targetComputer in $ComputerName) {
            if ([string]::IsNullOrWhiteSpace($targetComputer)) {
                continue
            }

            if (Test-IsLocalTarget -Target $targetComputer) {
                try {
                    $raw = & cmdkey.exe /list 2>$null | Out-String
                    $localUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
                    $parsed = ConvertFrom-CmdKeyText -Text $raw -HostName $env:COMPUTERNAME -ContextUser $localUser -CollectionMode 'LocalCurrentUser'

                    foreach ($entry in $parsed) {
                        Write-Output $entry
                    }
                }
                catch {
                    Write-Log -Level Warn -Message "[$targetComputer] Failed to query local Credential Manager metadata: $($_.Exception.Message)"
                }

                continue
            }

            $session = $null
            try {
                Write-Log -Level Info -Message "[$targetComputer] Querying Credential Manager metadata from active interactive session."

                $sessionParams = @{
                    ComputerName    = $targetComputer
                    Credential      = $Credential
                    UseSsh          = $UseSsh
                    UseCredSSP      = $UseCredSSP
                    Port            = $Port
                    Ps7ConfigName   = $Ps7ConfigName
                    WinPsConfigName = $WinPsConfigName
                }

                if ($PSBoundParameters.ContainsKey('UserName')) {
                    $sessionParams.UserName = $UserName
                }

                if ($PSBoundParameters.ContainsKey('KeyFilePath')) {
                    $sessionParams.KeyFilePath = $KeyFilePath
                }

                $session = Start-NewPSRemoteSession @sessionParams

                $remoteResult = Invoke-Command -Session $session -ErrorAction Stop -ScriptBlock {
                    param([int]$TaskTimeoutSec)

                    Set-StrictMode -Version Latest
                    $ErrorActionPreference = 'Stop'

                    function Get-ActiveInteractiveUser {
                        $quser = Get-Command quser.exe -ErrorAction SilentlyContinue
                        if (-not $quser) {
                            return $null
                        }

                        $lines = & quser.exe 2>$null
                        if (-not $lines) {
                            return $null
                        }

                        foreach ($line in $lines) {
                            if ($line -match '^\s*>?\s*(\S+)\s+\S+\s+\d+\s+Active\b') {
                                return $matches[1]
                            }
                        }

                        return $null
                    }

                    $activeUser = Get-ActiveInteractiveUser
                    if ([string]::IsNullOrWhiteSpace($activeUser)) {
                        throw 'No active interactive user session was found on the remote host.'
                    }

                    if ($activeUser -notmatch '\\') {
                        if (-not [string]::IsNullOrWhiteSpace($env:USERDOMAIN)) {
                            $activeUser = "{0}\{1}" -f $env:USERDOMAIN, $activeUser
                        }
                    }

                    $stamp = [guid]::NewGuid().ToString('N')
                    $taskName = "TT-CredList-$stamp"
                    $outFile = Join-Path $env:windir "Temp\TT-CredList-$stamp.txt"

                    $cmd = "cmdkey.exe /list > `"$outFile`""
                    $runWithCmdlets = [bool](Get-Command -Name New-ScheduledTaskAction -ErrorAction SilentlyContinue)

                    try {
                        if ($runWithCmdlets) {
                            $action = New-ScheduledTaskAction -Execute 'cmd.exe' -Argument "/c $cmd"
                            $trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddSeconds(3))

                            # Host versions differ on accepted enum values for interactive task logon.
                            try {
                                $principal = New-ScheduledTaskPrincipal -UserId $activeUser -LogonType Interactive -RunLevel Limited
                            }
                            catch {
                                $principal = New-ScheduledTaskPrincipal -UserId $activeUser -LogonType InteractiveOrPassword -RunLevel Limited
                            }

                            Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Force | Out-Null
                            Start-ScheduledTask -TaskName $taskName
                        }
                        else {
                            $startTime = (Get-Date).AddMinutes(1).ToString('HH:mm')
                            $startDate = (Get-Date).ToString('MM/dd/yyyy', [cultureinfo]::InvariantCulture)

                            & schtasks.exe /Create /SC ONCE /TN $taskName /TR ("cmd.exe /c $cmd") /ST $startTime /SD $startDate /RU $activeUser /IT /RL LIMITED /F | Out-Null
                            & schtasks.exe /Run /TN $taskName | Out-Null
                        }

                        $deadline = (Get-Date).AddSeconds($TaskTimeoutSec)
                        while ((Get-Date) -lt $deadline) {
                            if (Test-Path -LiteralPath $outFile) {
                                break
                            }
                            Start-Sleep -Milliseconds 500
                        }

                        if (-not (Test-Path -LiteralPath $outFile)) {
                            throw "Timed out waiting for task output file: $outFile"
                        }

                        $txt = Get-Content -LiteralPath $outFile -Raw -Encoding UTF8
                        [pscustomobject]@{
                            ComputerName = $env:COMPUTERNAME
                            SessionUser  = $activeUser
                            RawText      = $txt
                        }
                    }
                    finally {
                        if ($runWithCmdlets) {
                            Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
                        }
                        else {
                            & schtasks.exe /Delete /TN $taskName /F 2>$null | Out-Null
                        }
                        Remove-Item -LiteralPath $outFile -Force -ErrorAction SilentlyContinue
                    }
                } -ArgumentList $TimeoutSec

                $parsedRemote = ConvertFrom-CmdKeyText -Text ([string]$remoteResult.RawText) -HostName ([string]$remoteResult.ComputerName) -ContextUser ([string]$remoteResult.SessionUser) -CollectionMode 'RemoteInteractiveSession'

                foreach ($entry in $parsedRemote) {
                    Write-Output $entry
                }
            }
            catch {
                Write-Log -Level Warn -Message "[$targetComputer] Failed to query Credential Manager metadata: $($_.Exception.Message)"
            }
            finally {
                if ($session) {
                    Stop-PSRemoteSession -Session $session -ErrorAction SilentlyContinue
                }
            }
        }
    }
}

# SIG # Begin signature block
# MIIfAgYJKoZIhvcNAQcCoIIe8zCCHu8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCASvRnBa8OTDTp3
# ELKlqUwWJWUfT6MexenKczsqzbIRnaCCGEowggUMMIIC9KADAgECAhAR+U4xG7FH
# qkyqS9NIt7l5MA0GCSqGSIb3DQEBCwUAMB4xHDAaBgNVBAMME1ZBRFRFSyBDb2Rl
# IFNpZ25pbmcwHhcNMjUxMjE5MTk1NDIxWhcNMjYxMjE5MjAwNDIxWjAeMRwwGgYD
# VQQDDBNWQURURUsgQ29kZSBTaWduaW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEA3pzzZIUEY92GDldMWuzvbLeivHOuMupgpwbezoG5v90KeuN03S5d
# nM/eom/PcIz08+fGZF04ueuCS6b48q1qFnylwg/C/TkcVRo0WFcKoFGT8yGxdfXi
# caHtapZfbSRh73r7qR7w0CioVveNBVgfMsTgE0WKcuwxemvIe/ptmkfzwAiw/IAC
# Ib0E0BjiX4PySbwWy/QKy/qMXYY19xpRItVTKNBtXzADUtzPzUcFqJU83vM2gZFs
# Or0MhPvM7xEVkOWZFBAWAubbMCJ3rmwyVv9keVDJChhCeLSz2XR11VGDOEA2OO90
# Y30WfY9aOI2sCfQcKMeJ9ypkHl0xORdhUwZ3Wz48d3yJDXGkduPm2vl05RvnA4T6
# 29HVZTmMdvP2475/8nLxCte9IB7TobAOGl6P1NuwplAMKM8qyZh62Br23vcx1fXZ
# TJlKCxBFx1nTa6VlIJk+UbM4ZPm954peB/fIqEacm8LkZ0cPwmLE5ckW7hfK4Trs
# o+RaudU1sKeA+FvpOWgsPccVRWcEYyGkwbyTB3xrIBXA+YckbANZ0XL7fv7x29hn
# gXbZipGu3DnTISiFB43V4MhNDKZYfbWdxze0SwLe8KzIaKnwlwRgvXDMwXgk99Mi
# EbYa3DvA/5ZWikLW9PxBFD7Vdr8ZiG/tRC9I2Y6fnb+PVoZKc/2xsW0CAwEAAaNG
# MEQwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQW
# BBRfYLVE8caSc990rnrIHUjoB7X/KjANBgkqhkiG9w0BAQsFAAOCAgEAiGB2Wmk3
# QBtd1LcynmxHzmu+X4Y5DIpMMNC2ahsqZtPUVcGqmb5IFbVuAdQphL6PSrDjaAR8
# 1S8uTfUnMa119LmIb7di7TlH2F5K3530h5x8JMj5EErl0xmZyJtSg7BTiBA/UrMz
# 6WCf8wWIG2/4NbV6aAyFwIojfAcKoO8ng44Dal/oLGzLO3FDE5AWhcda/FbqVjSJ
# 1zMfiW8odd4LgbmoyEI024KkwOkkPyJQ2Ugn6HMqlFLazAmBBpyS7wxdaAGrl18n
# 6bS7QuAwCd9hitdMMitG8YyWL6tKeRSbuTP5E+ASbu0Ga8/fxRO5ZSQhO6/5ro1j
# PGe1/Kr49Uyuf9VSCZdNIZAyjjeVAoxmV0IfxQLKz6VOG0kGDYkFGskvllIpQbQg
# WLuPLJxoskJsoJllk7MjZJwrpr08+3FQnLkRuisjDOc3l4VxFUsUe4fnJhMUONXT
# Sk7vdspgxirNbLmXU4yYWdsizz3nMUR0zebUW29A+HYme16hzrMPOeyoQjy4I5XX
# 3wXAFdworfPEr/ozDFrdXKgbLwZopymKbBwv6wtT7+1zVhJXr+jGVQ1TWr6R+8ea
# tIOFnY7HqGaxe5XB7HzOwJKdj+bpHAfXft1vUoiKr16VajLigcYCG8MdwC3sngO3
# JDyv2V+YMfsYBmItMGBwvizlQ6557NbK95EwggWNMIIEdaADAgECAhAOmxiO+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
# twGpn1eqXijiuZQwgga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0GCSqG
# SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx
# GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy
# dXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTlaMGkx
# CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4
# RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYg
# MjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHTCphB
# cr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPhof6p
# vF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mAxAHe
# HYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBvMgEd
# gkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps0wjU
# jsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF83bR
# VFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXiUOeS
# LsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOMCZIV
# NSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydPpOjL
# 6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrUG2Zd
# SoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+sdFU
# eEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0TAQH/
# BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYDVR0j
# BBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0
# cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8E
# PDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEw
# DQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WIGjB/
# T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+IQhQ
# E7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8Myb9r
# EVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2th9y
# 1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjajV/gx
# dEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2Lr3t
# y9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFzeGxcy
# tL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG7uEB
# YTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+NJpud
# /v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckTetiS
# uEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszWkPZP
# ubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0BAQsF
# ADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNV
# BAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hB
# MjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVowYzEL
# MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJE
# aWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIwMjUg
# MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5gVrMr
# V7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN+vo8
# dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qome7M
# rxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ//nBZ
# ZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouTMYFO
# nHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8DD+n
# igNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnpJeIt
# K/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP51ho1
# zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49kPmk
# 8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5PWPsW
# eupWs7NpChUk555K096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7YufAk
# prxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAAMB0G
# A1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK6eQG
# fHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYB
# BQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
# cC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRpZ2lj
# ZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZTSEEy
# NTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hB
# MjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcB
# MA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP2zWL
# pQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O6Lgj
# g8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskgiC3Q
# YIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMUBaB5
# bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDFkxUG
# tMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+zJNE
# suEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/lwd6U
# Arb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxlRcGG
# 0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2zRWV
# FjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJgbaP5
# t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOCIUjs
# arfNZzGCBg4wggYKAgEBMDIwHjEcMBoGA1UEAwwTVkFEVEVLIENvZGUgU2lnbmlu
# ZwIQEflOMRuxR6pMqkvTSLe5eTANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3
# AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisG
# AQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCDQxv5S//Q1
# N98ovqLWfhkHTAgvIsQhHCmx7Jr9oInOATANBgkqhkiG9w0BAQEFAASCAgDb2uFS
# RTH8EwFqC2/ViXEfsMsg3mYEdv1IK5GuJcuxnZo3v1YMQI8fxjBPnP69n0Ge4F78
# ugRe07Im48iTJaELuq0BeOu85ij7nnHrYSKbZ0hZpSzn5FuM/hTj8WY3rJIKGBZz
# meuYMKVaDHGZlmeb2e6mLGnWKrDELdtingN/GMyM+q9PFb5kGbehOed8MihiM1Jt
# W+QyqhlA8X6JEjGqcbmuCXfUGDMtg6+4Ml5Kt4ibV2yIENRXsZ+XBFfcoZb9h4t5
# vv1sDVeLMnHC1RbV3opH+aKR4k0+H/wOrHvUIXRRLMY3AkkZag1zv3ao+Sdu5Z2O
# OJ9BWWGS8TLStjpnKCxAIHjiARjnkemwqoMntKVJAgr2ECJiNJp1rNSUm6mk4dWV
# 3DH1SgTZB6TUDjOHEehKn50Fu9V36YZ5hBpqLDOrn6cwVulo8MWS7BMpNxDJ5ev8
# NBK56wBzjG4vZFXa4+CXr7t5F6pN8ogoxtfbic7SOqaMLhkti3cbSaG/aCtThvG4
# VjimczV3qTwABMMALV4LLQc5lKp7bb6O0uWLEiUyseWKDUOvtdWXPyd4sTgmN7Lq
# bcTBrlyWSuaHrWKugr9oi9i2e0pZSQadqUkHOoIL0Mox4pSmukFOMYwRMpaHZNut
# NWLxPVdaXqtfdkW6TcZM6b/EG+7i7e3e+p88oKGCAyYwggMiBgkqhkiG9w0BCQYx
# ggMTMIIDDwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcg
# UlNBNDA5NiBTSEEyNTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZI
# AWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJ
# BTEPFw0yNjA1MTkyMTQxNDNaMC8GCSqGSIb3DQEJBDEiBCA6YB6kNElZFreMuT3h
# w1AVDONuBLuCQ12UfLq4JXUZmTANBgkqhkiG9w0BAQEFAASCAgASgbOYfRfLPma/
# fJ8TZFVv3VbiA+mfUb9rMjiZt/L8V1RD6intCcmXAbPYNv6La7UOcNi0TbT8v8PM
# gU8C3Uikbm7TcGKsjGPX7AXz0v7sqM2exgbVeCW0SEEjdZ2ARV39vxZ/TyWKIWpN
# 8MFL/241i2UKdiK0MEjeu6b7qHS3Lvl6gcYtMIsXh2F/hbcW5N98xhu3W5NPrhWD
# O0wv4uiBMOLr3kl3lQ1GmZw07dm24WlPksFj6/t5rRxs5Z7rClRqllJ+30bh2csX
# v8n/4Z1KjfwVop36GsBZolU9TbYzFFbGQbPqv8STplXUmt2+9GDFCf8oFaihtAwm
# zXxQP3fasiDBmzta2GRQK1sgWIqEcg7uQRYkaC2LjD2N0Tw0uAaiQ2XSH79Ya/w4
# halDk/kJCiobGY0cyAfchJzau4YbCJqU8syMLinRyiWFB8yR4yrF30Hj0v+3KeVb
# x7j51KPLe97MA8G6K+KUKGiP0AYqml/XNh+DKFrZRp1wzRbq9mpqWuV7P6NNk0Ai
# mkAJ35K+M+rJ5eqB4cHeZjlMHKRAqVMXhgCKLsImuSX5fTovtr6H+0b4w5jNUtya
# zVkEsMjPzO/RXcVgjYkxBxXNlocQ4fPVVLAnInryeCM+th4+NYg9g3+561JZfkpV
# rUukJAYHKENQYeAINjGxTx1VHRHdoA==
# SIG # End signature block