Get-SystemInfo.ps1

<#PSScriptInfo
 
.VERSION 2.0.0
 
.GUID 21f7b5b3-f9bd-4611-a846-9372c3a89275
 
.AUTHOR asheroto
 
.COMPANYNAME asheroto
 
.TAGS PowerShell Windows get system info information hardware firmware details disk memory network pending reboot usage shutdown event last
 
.PROJECTURI https://github.com/asheroto/Get-SystemInfo
 
.RELEASENOTES
[Version 1.0.0] - Initial Release.
[Version 1.0.1] - Added TPM information support.
[Version 1.0.2] - Added graphics card information support.
[Version 2.0.0] - Redesigned for improved functionality with robust support for object-oriented usage, allowing easy access to specific diagnostic sections.
 
#>


<#
.SYNOPSIS
    Gathers detailed system diagnostics, including configuration, hardware, network, and OS status.
 
.DESCRIPTION
    This function provides a complete overview of system information, hardware specifications, network details, and pending reboot status. It is designed to be used either as a standalone script for console output or programmatically as a function to retrieve diagnostics as an object.
 
.PARAMETER CheckForUpdate
    Checks if there is an update available for the script. The latest version information is retrieved from GitHub.
 
.PARAMETER UpdateSelf
    Updates the script to the latest version available in the PowerShell Gallery.
 
.PARAMETER Version
    Displays the current version of the script.
 
.PARAMETER Help
    Displays detailed help information for the script, including usage examples.
 
.PARAMETER Silent
    Suppresses console output when running the script. Useful for retrieving the diagnostics as an object without any visible output.
 
.EXAMPLE
    .\Get-SystemInfo.ps1
    Runs the script and displays all diagnostics in a well-formatted console output.
 
.EXAMPLE
    . .\Get-SystemInfo.ps1 -Silent
    $info = Get-SystemInfo
    Retrieves all diagnostics as an object for programmatic access.
 
.EXAMPLE
    Get-SystemInfo -CheckForUpdate
    Checks for updates to the script.
 
.EXAMPLE
    Get-SystemInfo -UpdateSelf
    Updates the script to the latest version from the PowerShell Gallery.
 
.INPUTS
    None.
 
.OUTPUTS
    [PSCustomObject]
    Returns a custom object containing system diagnostics, including sections such as System, Hardware, TPM, OS, CPU, Memory, Disks, Graphics, NetworkAdapters, PendingReboot, and ShutdownEvents.
 
.NOTES
    Author: asheroto
    Version: 2.0.0
    Repository: https://github.com/asheroto/Get-SystemInfo
 
.LINK
    https://github.com/asheroto/Get-SystemInfo
#>


[CmdletBinding()]
param (
    [switch]$CheckForUpdate,
    [switch]$UpdateSelf,
    [switch]$Version,
    [switch]$Help,
    [switch]$Silent
)

# Script information
$CurrentVersion = '2.0.0'
$RepoOwner = 'asheroto'
$RepoName = 'Get-SystemInfo'
$PowerShellGalleryName = 'Get-SystemInfo'

# Preferences
$ProgressPreference = 'SilentlyContinue'
$ConfirmPreference = 'None'

if ($Version.IsPresent) {
    $CurrentVersion
    exit 0
}

if ($Help) {
    Get-Help -Name $MyInvocation.MyCommand.Source -Full
    exit 0
}

function Get-SystemInfo {
    $result = [PSCustomObject]@{
        System          = [PSCustomObject]@{
            Hostname = $env:COMPUTERNAME
        }
        Hardware        = [PSCustomObject]@{
            MakeModel            = $null
            SerialNumber         = $null
            FirmwareManufacturer = $null
            FirmwareVersion      = $null
        }
        TPM             = [PSCustomObject]@{
            IsActivated = $false
            IsEnabled   = $false
            IsOwned     = $false
            Version     = $null
        }
        OS              = [PSCustomObject]@{
            Version        = $null
            DisplayVersion = $null
            Architecture   = $null
            Type           = $null
            InstallDate    = $null
            LastBootTime   = $null
            Uptime         = $null
        }
        CPU             = [PSCustomObject]@{
            MakeModel = $null
            SpeedGHz  = $null
            Usage     = $null
            Cores     = $null
            Threads   = $null
        }
        Memory          = [PSCustomObject]@{
            TotalGB      = $null
            UsedGB       = $null
            UsagePercent = $null
            DIMMs        = @()
        }
        Disks           = @()
        Graphics        = @()
        NetworkAdapters = @()
        PendingReboot   = @()
        ShutdownEvents  = @()
    }

    # Populate Hardware Information
    $cs = Get-CimInstance -ClassName Win32_ComputerSystem
    $bios = Get-CimInstance -ClassName Win32_BIOS
    $result.Hardware.MakeModel = "$($cs.Manufacturer) $($cs.Model)"
    $result.Hardware.SerialNumber = $bios.SerialNumber
    $result.Hardware.FirmwareManufacturer = $bios.Manufacturer
    $result.Hardware.FirmwareVersion = $bios.SMBIOSBIOSVersion

    # Populate TPM Information
    $tpm = Get-CimInstance -Namespace "root\cimv2\security\microsofttpm" -ClassName Win32_Tpm
    if ($tpm) {
        $result.TPM.IsActivated = $tpm.IsActivated_InitialValue
        $result.TPM.IsEnabled = $tpm.IsEnabled_InitialValue
        $result.TPM.IsOwned = $tpm.IsOwned_InitialValue
        $result.TPM.Version = ($tpm.SpecVersion -split ',')[0]
    }

    # Populate OS Information
    $os = Get-CimInstance -ClassName Win32_OperatingSystem
    $uptime = (Get-Date) - $os.LastBootUpTime
    $displayVersion = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name DisplayVersion).DisplayVersion

    $result.OS.Version = $os.Caption
    $result.OS.DisplayVersion = $displayVersion
    $result.OS.Architecture = $os.OSArchitecture
    $result.OS.InstallDate = $os.InstallDate
    $result.OS.LastBootTime = $os.LastBootUpTime
    $result.OS.Uptime = "$([math]::Floor($uptime.TotalDays)) days, $($uptime.Hours) hours, $($uptime.Minutes) minutes"

    # Determine OS type (Workstation/Server)
    $result.OS.Type = if ($os.ProductType -eq 1) {
        "Workstation"
    } elseif ($os.ProductType -eq 2 -or $os.ProductType -eq 3) {
        "Server"
    } else {
        "Unknown"
    }

    # Populate CPU Information
    $cpu = Get-CimInstance -ClassName Win32_Processor
    $result.CPU.MakeModel = $cpu.Name
    $result.CPU.SpeedGHz = [math]::Round($cpu.MaxClockSpeed / 1000, 2)
    $result.CPU.Usage = "$(($cpu | Measure-Object -Property LoadPercentage -Average).Average)%"
    $result.CPU.Cores = $cpu.NumberOfCores
    $result.CPU.Threads = $cpu.NumberOfLogicalProcessors

    # Populate Memory Information
    $result.Memory.TotalGB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
    $result.Memory.UsedGB = $result.Memory.TotalGB - [math]::Round($os.FreePhysicalMemory / 1MB, 2)
    $result.Memory.UsagePercent = [math]::Round(($result.Memory.UsedGB / $result.Memory.TotalGB) * 100, 2)
    $result.Memory.DIMMs = Get-CimInstance -ClassName Win32_PhysicalMemory | ForEach-Object {
        [PSCustomObject]@{
            DIMMNumber   = $_.DeviceLocator
            SizeGB       = if ($_.Capacity) { [math]::Round($_.Capacity / 1GB, 2) } else { "N/A" }
            Model        = if ($_.PartNumber) { $_.PartNumber } else { "Unknown" }
            SpeedMHz     = if ($_.Speed) { $_.Speed } else { "Unknown" }
            Manufacturer = if ($_.Manufacturer) { $_.Manufacturer } else { "Unknown" }
        }
    }

    # Populate Disk Information
    $result.Disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
        [PSCustomObject]@{
            Drive        = $_.DeviceID
            TotalSizeGB  = [math]::Round($_.Size / 1GB, 2)
            FreeSpaceGB  = [math]::Round($_.FreeSpace / 1GB, 2)
            UsagePercent = [math]::Round((($_.Size - $_.FreeSpace) / $_.Size) * 100, 2)
        }
    }

    # Populate Graphics Card Information
    $result.Graphics = Get-CimInstance -ClassName Win32_VideoController | ForEach-Object {
        [PSCustomObject]@{
            Name          = $_.Name
            MemoryGB      = [math]::Round($_.AdapterRAM / 1GB, 2)
            DriverVersion = $_.DriverVersion
            DriverDate    = $_.DriverDate
        }
    }

    $result.NetworkAdapters = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true } | ForEach-Object {
        $adapter = Get-CimInstance -Query "SELECT * FROM Win32_NetworkAdapter WHERE Index = $($_.Index)"
        [PSCustomObject]@{
            Adapter     = $_.Description
            IP          = $_.IPAddress -join ", "
            MAC         = $_.MACAddress
            SpeedMbps   = if ($adapter.Speed) { [math]::Round($adapter.Speed / 1e6, 2) } else { "Unknown" }
            DHCPEnabled = $_.DHCPEnabled
        }
    }

    # Populate Pending Reboot Information
    $result.PendingReboot = @()

    if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") {
        $result.PendingReboot += [PSCustomObject]@{
            Source  = "Windows Update"
            Details = "Reboot required for pending updates."
            Path    = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired"
        }
    }

    if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") {
        $result.PendingReboot += [PSCustomObject]@{
            Source  = "Component-Based Servicing"
            Details = "Reboot required for servicing stack changes."
            Path    = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending"
        }
    }

    if ((Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager").PendingFileRenameOperations) {
        $result.PendingReboot += [PSCustomObject]@{
            Source  = "Pending File Rename Operations"
            Details = "Reboot required for file operations."
            Path    = "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager"
        }
    }

    if (Test-Path "HKLM:\SOFTWARE\Microsoft\Cluster\PendingReboot") {
        $result.PendingReboot += [PSCustomObject]@{
            Source  = "Cluster Pending Reboot"
            Details = "Cluster changes require a reboot."
            Path    = "HKLM:\SOFTWARE\Microsoft\Cluster\PendingReboot"
        }
    }

    # Populate Shutdown Events
    $result.ShutdownEvents = Get-WinEvent -FilterHashtable @{ LogName = 'System'; ID = 1074 } |
    Select-Object -First 5 -Property TimeCreated, Message

    return $result
}

if ($CheckForUpdate) {
    CheckForUpdate -RepoOwner $RepoOwner -RepoName $RepoName -CurrentVersion $CurrentVersion -PowerShellGalleryName $PowerShellGalleryName
}

if ($UpdateSelf) {
    UpdateSelf
}

# Main execution
if (-not $Silent) {
    $info = Get-SystemInfo

    function Write-Section($text) {
        <#
            .SYNOPSIS
            Prints a text block surrounded by a section divider for enhanced output readability.
 
            .DESCRIPTION
            This function takes a string input and prints it to the console, surrounded by a section divider made of hash characters.
            It is designed to enhance the readability of console output.
 
            .PARAMETER text
            The text to be printed within the section divider.
 
            .EXAMPLE
            Write-Section "Downloading Files..."
            This command prints the text "Downloading Files..." surrounded by a section divider.
        #>

        Write-Output ""
        Write-Output ("#" * ($text.Length + 4))
        Write-Output "# $text #"
        Write-Output ("#" * ($text.Length + 4))
        Write-Output ""
    }

    Write-Section "System Information"
    $info.System | Format-List

    Write-Section "Hardware Information"
    $info.Hardware | Format-List

    Write-Section "TPM Information"
    $info.TPM | Format-List

    Write-Section "OS Information"
    $info.OS | Format-List

    Write-Section "CPU Information"
    $info.CPU | Format-List

    Write-Section "Memory Information"
    $info.Memory | Select-Object -Property * -ExcludeProperty DIMMs | Format-List
    $info.Memory.DIMMs | Format-Table -AutoSize

    Write-Section "Disk Information"
    $info.Disks | Format-Table -AutoSize

    Write-Section "Graphics Information"
    $info.Graphics | Format-Table -AutoSize

    Write-Section "Network Adapters"
    $info.NetworkAdapters | Format-Table -AutoSize

    Write-Section "Pending Reboot Information"
    $info.PendingReboot | Format-Table -AutoSize

    Write-Section "Last Shutdown Events"
    $info.ShutdownEvents | Format-Table -AutoSize
}
# SIG # Begin signature block
# MIIhEQYJKoZIhvcNAQcCoIIhAjCCIP4CAQExDzANBglghkgBZQMEAgIFADCBiQYK
# KwYBBAGCNwIBBKB7MHkwNAYKKwYBBAGCNwIBHjAmAgMBAAAEEB/MO2BZSwhOtyTS
# xil+81ECAQACAQACAQACAQACAQAwQTANBglghkgBZQMEAgIFAAQw6p27+UiU/d9Q
# c7gms6u3LJU3WgVUMRAAp9gGC6dX2egJPAWFD+9or6Em/uogbz6LoIIHZDCCA1kw
# ggLfoAMCAQICEA+4p0C5FY0DUUO8WdnwQCkwCgYIKoZIzj0EAwMwYTELMAkGA1UE
# BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj
# ZXJ0LmNvbTEgMB4GA1UEAxMXRGlnaUNlcnQgR2xvYmFsIFJvb3QgRzMwHhcNMjEw
# NDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBkMQswCQYDVQQGEwJVUzEXMBUGA1UE
# ChMORGlnaUNlcnQsIEluYy4xPDA6BgNVBAMTM0RpZ2lDZXJ0IEdsb2JhbCBHMyBD
# b2RlIFNpZ25pbmcgRUNDIFNIQTM4NCAyMDIxIENBMTB2MBAGByqGSM49AgEGBSuB
# BAAiA2IABLu0rCelSA2iU1+PLoE+L1N2uAiUopqqiouYtbHw/CoVu7mzpSIv/WrA
# veJVaGBrlzTBZlNxI/wa1cogDwJAoqNKWkajkVMrlfID6aum04d2L+dkn541UfzD
# YzV4duT4d6OCAVcwggFTMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJtf
# sDa6nQauGSe9wKAiwIuLOHftMB8GA1UdIwQYMBaAFLPbSKT5ocXYrjZBzBFjaWIp
# vEvGMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB2BggrBgEF
# BQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBA
# BggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# R2xvYmFsUm9vdEczLmNydDBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290RzMuY3JsMBwGA1UdIAQVMBMw
# BwYFZ4EMAQMwCAYGZ4EMAQQBMAoGCCqGSM49BAMDA2gAMGUCMHi9SZVlcQHQRldo
# ZQ5oqdw2CMHu/dSO20BlPw3/k6/CrmOGo37LtJFaeOwHA2cHfAIxAOefH/EHW6w0
# xji8taVQzubqOH4+eZDkpFurAg3oB/xWplqK3bNQst3y+mZ0ntAWYzCCBAMwggOJ
# oAMCAQICEAExw+sKUABDj0yZt5afTZQwCgYIKoZIzj0EAwMwZDELMAkGA1UEBhMC
# VVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTwwOgYDVQQDEzNEaWdpQ2VydCBH
# bG9iYWwgRzMgQ29kZSBTaWduaW5nIEVDQyBTSEEzODQgMjAyMSBDQTEwHhcNMjQw
# MzA3MDAwMDAwWhcNMjUwMzA4MjM1OTU5WjBvMQswCQYDVQQGEwJVUzERMA8GA1UE
# CBMIT2tsYWhvbWExETAPBgNVBAcTCE11c2tvZ2VlMRwwGgYDVQQKExNBc2hlciBT
# b2x1dGlvbnMgSW5jMRwwGgYDVQQDExNBc2hlciBTb2x1dGlvbnMgSW5jMHYwEAYH
# KoZIzj0CAQYFK4EEACIDYgAExsP0nyCZ1QtY7aXin+tdZVcF0uPHJJjRpjVVgUmb
# 3iKJeKapvWBSAbroBouKIP9+Qoz197aNbZCSOBQsWX53SUyTu1Trvwku7ksL+eQh
# bJvnRJ20UqF566z5KbniyLrAo4IB8zCCAe8wHwYDVR0jBBgwFoAUm1+wNrqdBq4Z
# J73AoCLAi4s4d+0wHQYDVR0OBBYEFNdgDYHKEBunNDYgivfxKeS4YX0/MD4GA1Ud
# IAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNl
# cnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMw
# gasGA1UdHwSBozCBoDBOoEygSoZIaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0R2xvYmFsRzNDb2RlU2lnbmluZ0VDQ1NIQTM4NDIwMjFDQTEuY3JsME6g
# TKBKhkhodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHM0Nv
# ZGVTaWduaW5nRUNDU0hBMzg0MjAyMUNBMS5jcmwwgY4GCCsGAQUFBwEBBIGBMH8w
# JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBXBggrBgEFBQcw
# AoZLaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsRzND
# b2RlU2lnbmluZ0VDQ1NIQTM4NDIwMjFDQTEuY3J0MAkGA1UdEwQCMAAwCgYIKoZI
# zj0EAwMDaAAwZQIxAJHtFqbIBTSZ6AiYEyHsjjlZ7treTZfTSPiyyr8KAKBPKVXt
# B2859Jj8A3c9lEXrLgIwGTu2YV8DhFy9OqIDwkCZfoYH8oMo1LRtYhYZtVzkr3WF
# er8mkmAdOyNbW/DI0pZPMYIY8jCCGO4CAQEweDBkMQswCQYDVQQGEwJVUzEXMBUG
# A1UEChMORGlnaUNlcnQsIEluYy4xPDA6BgNVBAMTM0RpZ2lDZXJ0IEdsb2JhbCBH
# MyBDb2RlIFNpZ25pbmcgRUNDIFNIQTM4NCAyMDIxIENBMQIQATHD6wpQAEOPTJm3
# lp9NlDANBglghkgBZQMEAgIFAKCBjDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG
# 9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIB
# FTA/BgkqhkiG9w0BCQQxMgQwMHfxkKb08P014rPd+/L+/3bZn6WNeFhRnZCkGm67
# bXXVLavOxRtQATxQ7CjJYeuCMAsGByqGSM49AgEFAARmMGQCMExqJ9Z2L/0vq7V9
# WQzEPZOe8hbvOMo5zRHn1wu6uXEfAXS8bh52e6VKFxW+K85L/AIwM5/DkQR8qMg2
# rOOafS24DHUc9duv2h+X9FBmAaSda2/To1eb27Uygv/znCH7O1yVoYIXWjCCF1YG
# CisGAQQBgjcDAwExghdGMIIXQgYJKoZIhvcNAQcCoIIXMzCCFy8CAQMxDzANBglg
# hkgBZQMEAgIFADCBhwYLKoZIhvcNAQkQAQSgeAR2MHQCAQEGCWCGSAGG/WwHATBB
# MA0GCWCGSAFlAwQCAgUABDAsUZ+VBHToys/wZuizB887E/lzpiY0KRz7fGiCHK2N
# /7tqqhBi3BMRJ9s9wZFdDSUCECCQIq+5Vaht0VAlnucyh44YDzIwMjUwMTE1MDAw
# MDA3WqCCEwMwgga8MIIEpKADAgECAhALrma8Wrp/lYfG+ekE4zMEMA0GCSqGSIb3
# DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7
# MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1l
# U3RhbXBpbmcgQ0EwHhcNMjQwOTI2MDAwMDAwWhcNMzUxMTI1MjM1OTU5WjBCMQsw
# CQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQxIDAeBgNVBAMTF0RpZ2lDZXJ0
# IFRpbWVzdGFtcCAyMDI0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
# vmpzn/aVIauWMLpbbeZZo7Xo/ZEfGMSIO2qZ46XB/QowIEMSvgjEdEZ3v4vrrTHl
# eW1JWGErrjOL0J4L0HqVR1czSzvUQ5xF7z4IQmn7dHY7yijvoQ7ujm0u6yXF2v1C
# rzZopykD07/9fpAT4BxpT9vJoJqAsP8YuhRvflJ9YeHjes4fduksTHulntq9WelR
# WY++TFPxzZrbILRYynyEy7rS1lHQKFpXvo2GePfsMRhNf1F41nyEg5h7iOXv+vjX
# 0K8RhUisfqw3TTLHj1uhS66YX2LZPxS4oaf33rp9HlfqSBePejlYeEdU740GKQM7
# SaVSH3TbBL8R6HwX9QVpGnXPlKdE4fBIn5BBFnV+KwPxRNUNK6lYk2y1WSKour4h
# JN0SMkoaNV8hyyADiX1xuTxKaXN12HgR+8WulU2d6zhzXomJ2PleI9V2yfmfXSPG
# YanGgxzqI+ShoOGLomMd3mJt92nm7Mheng/TBeSA2z4I78JpwGpTRHiT7yHqBiV2
# ngUIyCtd0pZ8zg3S7bk4QC4RrcnKJ3FbjyPAGogmoiZ33c1HG93Vp6lJ415ERcC7
# bFQMRbxqrMVANiav1k425zYyFMyLNyE1QulQSgDpW9rtvVcIH7WvG9sqYup9j8z9
# J1XqbBZPJ5XLln8mS8wWmdDLnBHXgYly/p1DhoQo5fkCAwEAAaOCAYswggGHMA4G
# A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF
# BwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAfBgNVHSMEGDAW
# gBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4EFgQUn1csA3cOKBWQZqVjXu5P
# kh92oFswWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybDMuZGlnaWNlcnQuY29t
# L0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNy
# bDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
# Z2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDovL2NhY2VydHMuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NB
# LmNydDANBgkqhkiG9w0BAQsFAAOCAgEAPa0eH3aZW+M4hBJH2UOR9hHbm04IHdEo
# T8/T3HuBSyZeq3jSi5GXeWP7xCKhVireKCnCs+8GZl2uVYFvQe+pPTScVJeCZSsM
# o1JCoZN2mMew/L4tpqVNbSpWO9QGFwfMEy60HofN6V51sMLMXNTLfhVqs+e8haup
# WiArSozyAmGH/6oMQAh078qRh6wvJNU6gnh5OruCP1QUAvVSu4kqVOcJVozZR5RR
# b/zPd++PGE3qF1P3xWvYViUJLsxtvge/mzA75oBfFZSbdakHJe2BVDGIGVNVjOp8
# sNt70+kEoMF+T6tptMUNlehSR7vM+C13v9+9ZOUKzfRUAYSyyEmYtsnpltD/GWX8
# eM70ls1V6QG/ZOB6b6Yum1HvIiulqJ1Elesj5TMHq8CWT/xrW7twipXTJ5/i5pkU
# 5E16RSBAdOp12aw8IQhhA/vEbFkEiF2abhuFixUDobZaA0VhqAsMHOmaT3XThZDN
# i5U2zHKhUs5uHHdG6BoQau75KiNbh0c+hatSF+02kULkftARjsyEpHKsF7u5zKRb
# t5oK5YGwFvgc4pEVUNytmB3BpIiowOIIuDgP5M9WArHYSAR16gc0dP2XdkMEP5eB
# sX7bf/MGN4K3HP50v/01ZHo/Z5lGLvNwQ7XHBx1yomzLP8lx4Q1zZKDyHcp4VQJL
# u2kWTsKsOqQwggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqGSIb3
# DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAX
# BgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0
# ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJ
# BgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGln
# aUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0Ew
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE
# 8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMfUBML
# JnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w1lbU
# 5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRktFLy
# dkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFk
# dECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUmcJgm
# f6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP65x9a
# bJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzKQtwY
# SH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo80Vg
# vCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5
# FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXcheMBK9
# Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIB
# ADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU7Nfj
# gtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsG
# AQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
# ZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2Vy
# dC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0
# hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0
# LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcN
# AQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp
# +3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiCqBa9
# qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8
# ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeCRK6Z
# JxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYTgAnE
# tp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fx
# ZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37xJV7
# 7QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmLNriT
# 1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0YgkP
# Cr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJRyvm
# fxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIFjTCC
# BHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0BAQwFADBlMQswCQYD
# VQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGln
# aWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
# HhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEV
# MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t
# MSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZ
# wuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4V
# pX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAd
# YyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3
# T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjU
# N6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNda
# SaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
# mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyV
# w4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3
# AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYi
# Cd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmp
# sh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7Nfj
# gtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNt
# yA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MEUG
# A1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3
# DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyhhyzshV6pGrsi+Ica
# aVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO0Cre+i1Wz/n096ww
# epqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcD
# x4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++hUD38dglohJ9vytsg
# jTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5xaiNrIv8SuFQtJ37Y
# OtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYIDhjCCA4ICAQEwdzBjMQswCQYD
# VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lD
# ZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBAhAL
# rma8Wrp/lYfG+ekE4zMEMA0GCWCGSAFlAwQCAgUAoIHhMBoGCSqGSIb3DQEJAzEN
# BgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjUwMTE1MDAwMDA3WjArBgsq
# hkiG9w0BCRACDDEcMBowGDAWBBTb04XuYtvSPnvk9nFIUIck1YZbRTA3BgsqhkiG
# 9w0BCRACLzEoMCYwJDAiBCB2dp+o8mMvH0MLOiMwrtZWdf7Xc9sF1mW5BZOYQ4+a
# 2zA/BgkqhkiG9w0BCQQxMgQw3CjsTO+R/Hao8N5idm3EAgz4sd11hLlvt/ey6EJQ
# HP8lQ/1iG79JcGbOfOuMSyhmMA0GCSqGSIb3DQEBAQUABIICAIp0/54VMygd3Jka
# Z1v+8Yv3FLxxpqb9kFvf7TFGV2uRvBkIAiUZLlSWqpu4d78/ZXaJ/0I7isdbUw61
# YgLxBiHWQ0+vKpFav6jxe9HV5BCbthHO00oOtQ2kRUKzhXQNGphmtFLltCvx4Ua/
# KHufalzPP4r0DketOw+Li4yv9doL6iVIPuKKU1XfGJZaaLFZKfAz3oXd3dbWPve0
# TX+EE7EKLf+Jr+Rlzyn3f+Wb7QRCznNmc119O0dvPy4wW+MqnTLFX5rM01zBp927
# J4PkrGfhK2sGEsKaz3KFVvAIG3rKJs7RQTxsT+EyzAYRCS6NqSA6+1ZWxnYrzp23
# mY2aAw0GHTc01MnC3pAlIgtPnMbCm7R2gh3SBgDvg7RFxVsErEPt0b9dpryO/VHu
# glE2Eu4f7ePq/p/Sx5KJPK1I8eRk1MwOkpiYrZ9mKfOKg+3r/U5Coou5PBo6T3A4
# +E2uRh3kr16YXmvLrhtkC0Xra6pCu3tePl/MnsFc2P76Fjxe14HkgeXn+cgxmnhA
# zBC0mrUT1ZcmbWvqTdcftaxaLIoVBCC+WbbBuKhIm8ErkLyN3gcpSRbyl9KNJz2H
# lfPzXX91oi2aRCBmABx592smCZutTdhve4HJpqUSXxumgGQxzj46j/i5u0QOEQIX
# XCf/fuSjMm9/loLBgAuHidRr87zk
# SIG # End signature block