Public/New-SecurityScan.ps1

<#
.SYNOPSIS
    This function will scan the files in the OneDrive folder for any security issues.
.DESCRIPTION
    This function will scan the files in the OneDrive folder for any security issues.
.PARAMETER pathOfOneDrive
    The path of the OneDrive folder. This is a relative path to the user's OneDrive folder, don't provide the full path here.
.PARAMETER accessToken
    The access token to access the OneDrive folder. This is optional, if not provided, the function will prompt for the access token.
.OUTPUTS
    This function will generate a report of the security issues found in the OneDrive folder, and can be export to csv.
.LINK
    https://github.com/code365opensource/microsoft.security.toolkit
#>

function New-SecurityScan {
    [cmdletbinding()]
    [Alias("amisecure")]
    param (
        [Parameter(Mandatory = $true)]
        [string]$pathOfOneDrive,
        [string]$accessToken
    )

    Send-AppInsightsTrace -Message "microsoft.security.toolkit" -Properties @{ "command" = "New-SecurityScan" } -ErrorAction SilentlyContinue

    # connect to Microsoft Graph, if the accessToken is not provided, prompt for the access token, otherwise use the provided access token (parse it to secure string)
    if (-not $accessToken) {
        Connect-Graph -Scopes "Files.Read.All", "InformationProtectionPolicy.Read" -NoWelcome
    }
    else {
        Connect-Graph -AccessToken (ConvertTo-SecureString $accessToken -AsPlainText -Force) -NoWelcome
    }
        
    # initialize the result
    $file_info = @{}
    $file_info_sensi = @{}
    $file_info_access = @{}
    $file_info_permission = @{}
    $file_info_scope = @{}
    $file_info_shared = @{}
    $file_info_access_90days = @{}

    try {
        # Get all files in the specified folder from OneDrive
        $graph_url_getItems = "https://graph.microsoft.com/v1.0/me/drive/root:/${pathOfOneDrive}:/children?select=name,id"
        $response = Invoke-MgRestMethod -Uri $graph_url_getItems -Method GET -ErrorAction Stop
    
        # Check if the response contains any files
        if ($response.value -and $response.value.Count -gt 0) {
            $data = $response.value
            foreach ($file in $data) {
                # Store file id and name in the dictionary
                $file_info[$file.id] = $file.name
            }
        } else {
            Write-Host "No files found in the specified folder."
            Exit 1
        }
    }
    catch {
        Write-Host "An error occurred while retrieving files: $_"
        Exit 1
    }
    
    # get the required information for each file
    $graph_baseUrl = 'https://graph.microsoft.com/v1.0/me/drive/items'
    $id_to_display_name = Get-SensitivityLabelsMapping
    $file_count = $file_info.Keys.Count
    $counter = 0
    foreach ($key in $file_info.Keys) {
        # show notification for users
        $counter++
        $fileName = $file_info[$key]
        Write-Host "Processing $fileName ($counter of $file_count files)..."

        # get sensitivity label
        try{
            $url_sen = "$graph_baseUrl/$key/extractSensitivityLabels"
            $response = Invoke-MgRestMethod -Uri $url_sen -Method POST -ErrorAction Stop
            $data = $response.labels
            $id = $data[0].sensitivityLabelId
            if ($data -and $data[0].sensitivityLabelId) {
                $id = $data[0].sensitivityLabelId
                $file_info_sensi[$file_info[$key]] = 
                    if ($id_to_display_name.ContainsKey($id)) 
                        { $id_to_display_name[$id] } 
                    else { "General" }
            } else {
                $file_info_sensi[$file_info[$key]] = "General"
            }
        }
        catch {
            Write-Host "An error occurred while retrieving sensitivity label: $_"
            $file_info_sensi[$file_info[$key]] = "General"
        }

    
        try {
            $url_access = "$graph_baseUrl/$key/analytics/alltime?select=access"
            
            $response = Invoke-MgRestMethod -Uri $url_access -Method GET -ErrorAction Stop
            
            $accessLog = $response.access
            
            if ($null -ne $accessLog) {
                $file_info_access[$file_info[$key]] = $accessLog
            } else {
                $file_info_access[$file_info[$key]] = $null
            }
        } catch {
            Write-Host "An error occurred while retrieving access data: $_"
            $file_info_access[$file_info[$key]] = $null
        }
        
    
        # get recent 90 days analytics log
        try {
            $startDate = (Get-Date).AddDays(-90).ToString('yyyy-MM-dd')
            
            $url_access = "$graph_baseUrl/$key/getActivitiesByInterval(startDateTime='$startDate',endDateTime='',interval='month')?select=access"
            
            $response = Invoke-MgRestMethod -Uri $url_access -Method GET -ErrorAction Stop
            
            $accessLog = $response.value
            
            if ($null -ne $accessLog) {
                $file_info_access_90days[$file_info[$key]] = $accessLog
            } else {
                $file_info_access_90days[$file_info[$key]] = $null
            }
        } catch {
            Write-Host "An error occurred while retrieving access data: $_"
            $file_info_access_90days[$file_info[$key]] = $null
        }
        
    
        # get permissions
        try {
            $url_userNum = "$graph_baseUrl/$key/permissions?count=true&top=0"
            $response_userNum = Invoke-MgRestMethod -Uri $url_userNum -Method GET -ErrorAction Stop
            $userNum = $response_userNum['@odata.count']
            
            $url_linkNum = "$graph_baseUrl/$key/permissions?filter=link/scope eq 'organization' or link/scope eq 'anonymous'&count=true&top=0"
            $response_linkNum = Invoke-MgRestMethod -Uri $url_linkNum -Method GET -ErrorAction Stop
            $linkNum = $response_linkNum['@odata.count']
            
            $url_owner = "$graph_baseUrl/$key/permissions?filter=roles/any(property:property eq 'owner')&select=grantedToV2,roles"
            $response_owner = Invoke-MgRestMethod -Uri $url_owner -Method GET -ErrorAction Stop
            if ($response_owner.value -and $response_owner.value[0] -and $response_owner.value[0].grantedToV2.user.email) {
                $owner = $response_owner.value[0].grantedToV2.user.email
            } else {
                $owner = $null
            }

            $file_info_permission[$file_info[$key]] = $userNum
            $file_info_scope[$file_info[$key]] = $linkNum
        
        } catch {
            Write-Host "An error occurred while retrieving permission data: $_"
            $file_info_permission[$file_info[$key]] = -1
            $file_info_scope[$file_info[$key]] = -1
            $owner = $null
        }
    
        # get activities log
        try {
            $url_activities = "$graph_baseUrl/$key/activities?select=action,actor"
            
            $response = Invoke-MgRestMethod -Uri $url_activities -Method GET -ErrorAction Stop
            
            $shared = $false
            
            foreach ($item in $response.value) {
                Get-Activity -entry $item -owner $owner -shared ([ref]$shared)
                if ($shared) {
                    break
                }
            }
            
            $file_info_shared[$file_info[$key]] = $shared
        
        } catch {
            Write-Host "An error occurred while retrieving activity data: $_"
            $file_info_shared[$file_info[$key]] = $null
        }        
    }
    
    $timestamp = (Get-Date).ToString("yyyy-MM-dd_HH-mm-ss")
    $csvFileName = "scan_report_$timestamp.csv"
    $csvFilePath = (Get-Location).Path + "\$csvfileName"

    $csvData = @()
    
    # generate report for each file
    Write-Host "Generating scan report for all files..."
    foreach ($key in $file_info.Keys) {
        $fileName = $file_info[$key]
        $sensitivity = $file_info_sensi[$fileName]
        $accessLog = $file_info_access[$fileName]
        $accessLog90days = $file_info_access_90days[$fileName]
        $permissionCount = $file_info_permission[$fileName]
        $scope = $file_info_scope[$fileName]
        $sharedWithOthers = $file_info_shared[$fileName]

        # Check if the file is private, and no access logs belongs to others.
        $passPrivateAndNoAccessTest = Test-PrivateAndOthersNoAccess -permissionCount $permissionCount -accessLog $accessLog

        # Check if the file has been shared by others, rather than by the owner.
        $passSharedByOthersTest = Test-SharedByOthers -sharedWithOthers $sharedWithOthers

        # Check if the file is classified as 'confidential' or 'high confidential', but shared with 'organization' or 'anonymous'.
        $passConfidentialAndNoOrgScopeTest = Test-ConfidentialAndNoOrgScope -scope $scope -sensitivity $sensitivity

        # Check if the file has not been used in the last 90 days, but still has permission settings.
        $passUnusedWithPermissionsTest = Test-UnusedWithPermissions -accessLog90days $accessLog90days -permissionCount $permissionCount
        # Generate report based on check results
        $csvData += New-Report -fileName $fileName `
        -passPrivateAndNoAccessTest $passPrivateAndNoAccessTest `
        -passSharedByOthersTest $passSharedByOthersTest `
        -passConfidentialAndNoOrgScopeTest $passConfidentialAndNoOrgScopeTest `
        -passUnusedWithPermissionsTest $passUnusedWithPermissionsTest
    }
    
    $csvData | Export-Csv -Path $csvFilePath -NoTypeInformation
    
    Write-Host "Scan report saved to: $csvFilePath"

    $result
}
# SIG # Begin signature block
# MIIdKgYJKoZIhvcNAQcCoIIdGzCCHRcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBRTnPz4sFOG+9E
# 4bZ5izu39FVemyim3v0P9waLBc6n86CCA0YwggNCMIICKqADAgECAhAdkYHz+qFO
# vkQjYqzHr3pKMA0GCSqGSIb3DQEBCwUAMDkxNzA1BgNVBAMMLkNvZGVTaWduaW5n
# IENlcnRpZmljYXRlIGZvciBQb3dlclNoZWxsIE1vZHVsZXMwHhcNMjQwNjEyMDUw
# ODAyWhcNMjUwNjEyMDUyODAyWjA5MTcwNQYDVQQDDC5Db2RlU2lnbmluZyBDZXJ0
# aWZpY2F0ZSBmb3IgUG93ZXJTaGVsbCBNb2R1bGVzMIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEAwdSzTBb7ni0tRubblITxoGHzXlvwu8Y5ndoElOvIKaey
# AFW8+tYCPG5zATsoGGE3f8g6Wtv8JgEjH45ZOhRBjghEVpw/9Iszal5SmucjUlqB
# fMvts+M/x9G7h6GGAQFy65xgQqyCVJA10x2NDheb7cBRCRRZVkT+CUv1dbS41bsO
# BMKDUTumbU7vHk2FSJ5H6f31cj238qboI4g2GD2gIsWID+GhAfzxrmXMV6VgMKqW
# GNlK5g/X2tSM6Aygnx1itXrrV3LwDOYiAAs+j87jEsYhxe3CnFgtDsi4UtW/lFem
# eEiOh9Vd6LaTxNoleV/PGz3FU7t6nnZmIOsjOFWLHQIDAQABo0YwRDAOBgNVHQ8B
# Af8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFMTYcpJNvUO8
# TYpuvvHtzPkUUUmkMA0GCSqGSIb3DQEBCwUAA4IBAQAihkTQ6zo1SNboEZ2C5yXr
# Hf5FoMRFBij0o0drMYEwDbiVCNGXkk74nNqXnGm+CJ0jkPHkM35uC/JGGGyToyBF
# uC27hC6+WsTMlVlJZKr7N5WLaM97hwf5xtEWg1c1s0vLKx92AKSGgqJRU7rlRMaX
# 5oOROmFwLqMj15Oon73EhZNqpjfRsKgMxJJw03n6KwMNvzNTXlsiaS0mvAnFzKFp
# msuvtWJfp8fxHvEQckJzFr2EldNKKyTTZjbN5JfbQWZGIuxftYXZ0JKwXleZhNxZ
# MtkuHzjcpCoBgdIYI3FidWcZgUltoSLRZzM/iVLX6MAX2mjHQOBNWG/gOeZk28qo
# MYIZOjCCGTYCAQEwTTA5MTcwNQYDVQQDDC5Db2RlU2lnbmluZyBDZXJ0aWZpY2F0
# ZSBmb3IgUG93ZXJTaGVsbCBNb2R1bGVzAhAdkYHz+qFOvkQjYqzHr3pKMA0GCWCG
# SAFlAwQCAQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisG
# AQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcN
# AQkEMSIEILcBgnMUOo4otbsxKf2Ukh4bU4qReegCZCzgCUN3tXjUMA0GCSqGSIb3
# DQEBAQUABIIBAKQXcdGMP4WnVugmdyg2ZEy4RtcU+ENAWUAk+xDERdUVbpxPsayx
# dLVHOMeXiLYxLvmfONsizrmPUsN2x5/ivQRfMW9ATfhwSmjH7oUeEM0cHHc4E5J+
# pJ+k79KMwjjCZBhWesK5qrcC8wwHMLIi/l633ZFU3xnlvR9tx4aLmB1u1+7QZLJF
# 8SNdbjylbllVd1zdVmpBz804rdx8LIzWHxt8fQbljAb1nrH7jbZUmgAZBabn+aKK
# Cb9E+kwYcrdgROnL5QhRI3Swx5OxV7bmhEQ8VSEkLQu+gtE+/qfMMBWYh9UIi7ct
# yXB9ZYjPuTq6FXc+vHlcjZZYg8VNgTwEjaOhghdAMIIXPAYKKwYBBAGCNwMDATGC
# FywwghcoBgkqhkiG9w0BBwKgghcZMIIXFQIBAzEPMA0GCWCGSAFlAwQCAQUAMHgG
# CyqGSIb3DQEJEAEEoGkEZzBlAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEF
# AAQg4A23DuwgbRS7K/lXd1DrfCL48Ohrao/+h9figymafrICEQC1GPsFCa5p4GnB
# VH6U0UTrGA8yMDI0MDkxOTA5MjY0MFqgghMJMIIGwjCCBKqgAwIBAgIQBUSv85Sd
# CDmmv9s/X+VhFjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UE
# ChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQg
# UlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIzMDcxNDAwMDAwMFoX
# DTM0MTAxMzIzNTk1OVowSDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0
# LCBJbmMuMSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMzCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKNTRYcdg45brD5UsyPgz5/X5dLnXaEO
# CdwvSKOXejsqnGfcYhVYwamTEafNqrJq3RApih5iY2nTWJw1cb86l+uUUI8cIOrH
# mjsvlmbjaedp/lvD1isgHMGXlLSlUIHyz8sHpjBoyoNC2vx/CSSUpIIa2mq62DvK
# Xd4ZGIX7ReoNYWyd/nFexAaaPPDFLnkPG2ZS48jWPl/aQ9OE9dDH9kgtXkV1lnX+
# 3RChG4PBuOZSlbVH13gpOWvgeFmX40QrStWVzu8IF+qCZE3/I+PKhu60pCFkcOvV
# 5aDaY7Mu6QXuqvYk9R28mxyyt1/f8O52fTGZZUdVnUokL6wrl76f5P17cz4y7lI0
# +9S769SgLDSb495uZBkHNwGRDxy1Uc2qTGaDiGhiu7xBG3gZbeTZD+BYQfvYsSzh
# Ua+0rRUGFOpiCBPTaR58ZE2dD9/O0V6MqqtQFcmzyrzXxDtoRKOlO0L9c33u3Qr/
# eTQQfqZcClhMAD6FaXXHg2TWdc2PEnZWpST618RrIbroHzSYLzrqawGw9/sqhux7
# UjipmAmhcbJsca8+uG+W1eEQE/5hRwqM/vC2x9XH3mwk8L9CgsqgcT2ckpMEtGlw
# Jw1Pt7U20clfCKRwo+wK8REuZODLIivK8SgTIUlRfgZm0zu++uuRONhRB8qUt+JQ
# ofM604qDy0B7AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/
# BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEE
# AjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8w
# HQYDVR0OBBYEFKW27xPn783QZKHVVqllMaPe1eNJMFoGA1UdHwRTMFEwT6BNoEuG
# SWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQw
# OTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQG
# CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKG
# TGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJT
# QTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIB
# AIEa1t6gqbWYF7xwjU+KPGic2CX/yyzkzepdIpLsjCICqbjPgKjZ5+PF7SaCinEv
# GN1Ott5s1+FgnCvt7T1IjrhrunxdvcJhN2hJd6PrkKoS1yeF844ektrCQDifXcig
# LiV4JZ0qBXqEKZi2V3mP2yZWK7Dzp703DNiYdk9WuVLCtp04qYHnbUFcjGnRuSvE
# xnvPnPp44pMadqJpddNQ5EQSviANnqlE0PjlSXcIWiHFtM+YlRpUurm8wWkZus8W
# 8oM3NG6wQSbd3lqXTzON1I13fXVFoaVYJmoDRd7ZULVQjK9WvUzF4UbFKNOt50MA
# cN7MmJ4ZiQPq1JE3701S88lgIcRWR+3aEUuMMsOI5ljitts++V+wQtaP4xeR0arA
# VeOGv6wnLEHQmjNKqDbUuXKWfpd5OEhfysLcPTLfddY2Z1qJ+Panx+VPNTwAvb6c
# Kmx5AdzaROY63jg7B145WPR8czFVoIARyxQMfq68/qTreWWqaNYiyjvrmoI1VygW
# y2nyMpqy0tg6uLFGhmu6F/3Ed2wVbK6rr3M66ElGt9V/zLY4wNjsHPW2obhDLN9O
# TH0eaHDAdwrUAuBcYLso/zjlUlrWrBciI0707NMX+1Br/wd3H3GXREHJuEbTbDJ8
# WC9nR2XlG3O2mflrLAZG70Ee8PBf4NvZrZCARK+AEEGKMIIGrjCCBJagAwIBAgIQ
# BzY3tyRUfNhHrP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEV
# MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t
# MSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIwMzIzMDAw
# MDAwWhcNMzcwMzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln
# aUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5
# NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEAxoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCwzIP5WvYR
# oUQVQl+kiPNo+n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFzsbPuK4CE
# iiIY3+vaPcQXf6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ7Gnf2ZCH
# RgB720RBidx8ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7QKxfst5K
# fc71ORJn7w6lY2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/tePc5OsLDni
# pUjW8LAxE6lXKZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCYOjgRs/b2
# nuY7W+yB3iIU2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9KoRxrOMUp
# 88qqlnNCaJ+2RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6dSgkQe1C
# vwWcZklSUPRR8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM1+mYSlg+
# 0wOI/rOP015LdhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbCdLI/Hgl2
# 7KtdRnXiYKNYCQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbECAwEAAaOC
# AV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1NhS9zKXaa
# L3WMaiCPnshvMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1Ud
# DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkw
# JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcw
# AoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv
# b3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwB
# BAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7ZvmKlEIgF+
# ZtbYIULhsBguEE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI2AvlXFvX
# bYf6hCAlNDFnzbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/tydBTX/6tP
# iix6q4XNQ1/tYLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVPulr3qRCy
# Xen/KFSJ8NWKcXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmBo1aGqwpF
# yd/EjaDnmPv7pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc6UsCUqc3
# fpNTrDsdCEkPlM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3cHXg65J6t
# 5TRxktcma+Q4c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0dKNPH+ejx
# mF/7K9h+8kaddSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZPJ/tgZxah
# ZrrdVcA6KYawmKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLeMt8EifAA
# zV3C+dAjfwAL5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDyDivl1vup
# L0QVSucTDh3bNzgaoSv27dZ8/DCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghA
# GFowDQYJKoZIhvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lD
# ZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGln
# aUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEw
# OTIzNTk1OVowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
# MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1
# c3RlZCBSb290IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQ
# c2jeu+RdSjwwIjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW
# 61bGl20dq7J58soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU
# 0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzr
# yc/NrDRAX7F6Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17c
# jo+A2raRmECQecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypu
# kQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaP
# ZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUl
# ibaaRBkrfsCUtNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESV
# GnZifvaAsPvoZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2
# QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZF
# X50g/KEexcCPorF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1Ud
# EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1Ud
# IwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5Bggr
# BgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv
# bTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lD
# ZXJ0QXNzdXJlZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8v
# Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEG
# A1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0
# Gz22Ftf3v1cHvZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+A
# ufih9/Jy3iS8UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51P
# pwYDE3cnRNTnf+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix
# 3P0c2PR3WlxUjG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVV
# a88nq2x2zm8jLfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6pe
# KOK5lDGCA3YwggNyAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD
# ZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYg
# U0hBMjU2IFRpbWVTdGFtcGluZyBDQQIQBUSv85SdCDmmv9s/X+VhFjANBglghkgB
# ZQMEAgEFAKCB0TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcN
# AQkFMQ8XDTI0MDkxOTA5MjY0MFowKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQUZvAr
# MsLCyQ+CXc6qisnGTxmcz0AwLwYJKoZIhvcNAQkEMSIEILoJSG8Ou9coadBQbEl9
# pXcHMjOTwH3+qTrQZH6tIiyhMDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEINL25G3t
# dCLM0dRAV2hBNm+CitpVmq4zFq9NGprUDHgoMA0GCSqGSIb3DQEBAQUABIICAHZ0
# Pp2mV9NzS5UneYUTg96kFfDKKnAMCcSV29dNokRmEO4dz5D08JELZUCMTbJNILb0
# 9vDHuF6LtrM+YgumgleocMccH4+37tmJLQyKfxSnAeC8XhPkejT0zKjASllkJ3IH
# gbFcD9amDO0WBO2TfAmcLEs1Oc/caWXSvWdXRBguGBfxHjGu90gQp2jXzvA2kWkz
# sONz9Syg0R9tYfAok7AFOxPbpA7c49u/WGkUtop7Z7YAeHbF9i+NsT7F4t7UxXDU
# tuBN1S8EEo5UkQK+dTPl9XxT/5MFr24PhtbNLF1eLTdutE2D9IuYF+XaIVP5Amtp
# UOk/K0Utcc32A6w/pVa/+pQGj7dxeOdy7qeBR+kRjwvyDWt6EhnAimRzX4t0j71A
# T7AXPhZklFcIn/Sf+tabuJ8bqZRdJSQBw3y1B+CtCbVZWbOqgu8V9RrXgQdIYU/w
# 1pwUvoqGHZPswESVnxMYMxA84HlfDa89I80jyKJrjE22qQZKIHhEvDOQAOWpNa68
# 3NQvu+xKFsvwZxB18tZygfT3EPiIImuDMbKHbTJrqwRPdRjLV/DZj/HAri013gKf
# ofW4k9bUrsckyV49nlULBzD0B3UWXb+KylroiCxxGUUY6f9OYuq3zXQDc6wSTyPG
# AJnHPkmRtCqpOw0laa9MEZ6mVFzEsBtd88PJPGjn
# SIG # End signature block