Get-SystemInfo.ps1
<#PSScriptInfo
.VERSION 2.0.1 .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. [Version 2.0.1] - Fixed issue with parameters. #> <# .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.1 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.1' $RepoOwner = 'asheroto' $RepoName = 'Get-SystemInfo' $PowerShellGalleryName = 'Get-SystemInfo' # Preferences $ProgressPreference = 'SilentlyContinue' $ConfirmPreference = 'None' function ExitWithDelay { <# .SYNOPSIS Exits the script with a specified exit code after a specified delay, 10 seconds by default. .DESCRIPTION This function takes an exit code as an argument, waits for 10 seconds unless specified, and then exits the script with the given exit code. .PARAMETER ExitCode The exit code to use when exiting the script. .EXAMPLE ExitWithDelay -ExitCode 1 Waits for 10 seconds (default) and then exits the script with an exit code of 1. .EXAMPLE ExitWithDelay -ExitCode 2 -Seconds 5 Waits for 5 seconds and then exits the script with an exit code of 2. .NOTES Use this function to introduce a delay before exiting the script, allowing time for any cleanup or logging activities. #> param ( [int]$ExitCode, [int]$Seconds = 10 ) # Debug mode output if ($Debug -and $Wait) { Write-Warning "Wait specified, waiting several seconds..." } elseif ($Debug -and !$Wait) { Write-Warning "Wait not specified, exiting immediately..." } # If Wait is specified, wait for x seconds before exiting if ($Wait) { # Waiting for x seconds output Write-Output "`nWaiting for $Seconds seconds before exiting..." Start-Sleep -Seconds $Seconds } # If NoExit is specified, do not exit the script if ($NoExit) { Write-Output "Script completed. Pausing indefinitely. Press any key to exit..." Read-Host } # Exit the script with exit code if ($MyInvocation.CommandOrigin -eq "Runspace") { Break } else { Exit $ExitCode } } 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 } function Get-GitHubRelease { <# .SYNOPSIS Fetches the latest release information of a GitHub repository. .DESCRIPTION This function uses the GitHub API to get information about the latest release of a specified repository, including its version and the date it was published. .PARAMETER Owner The GitHub username of the repository owner. .PARAMETER Repo The name of the repository. .EXAMPLE Get-GitHubRelease -Owner "asheroto" -Repo "Get-SystemInfo" This command retrieves the latest release version and published datetime of the Get-SystemInfo repository owned by asheroto. #> [CmdletBinding()] param ( [string]$Owner, [string]$Repo ) try { $url = "https://api.github.com/repos/$Owner/$Repo/releases/latest" $response = Invoke-RestMethod -Uri $url -ErrorAction Stop $latestVersion = $response.tag_name $publishedAt = $response.published_at # Convert UTC time string to local time $UtcDateTime = [DateTime]::Parse($publishedAt, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::RoundtripKind) $PublishedLocalDateTime = $UtcDateTime.ToLocalTime() [PSCustomObject]@{ LatestVersion = $latestVersion PublishedDateTime = $PublishedLocalDateTime } } catch { Write-Error "Unable to check for updates.`nError: $_" exit 1 } } function CheckForUpdate { param ( [string]$RepoOwner, [string]$RepoName, [version]$CurrentVersion, [string]$PowerShellGalleryName ) $Data = Get-GitHubRelease -Owner $RepoOwner -Repo $RepoName Write-Output "" Write-Output ("Repository: {0,-40}" -f "https://github.com/$RepoOwner/$RepoName") Write-Output ("Current Version: {0,-40}" -f $CurrentVersion) Write-Output ("Latest Version: {0,-40}" -f $Data.LatestVersion) Write-Output ("Published at: {0,-40}" -f $Data.PublishedDateTime) if ($Data.LatestVersion -gt $CurrentVersion) { Write-Output ("Status: {0,-40}" -f "A new version is available.") Write-Output "`nOptions to update:" Write-Output "- Download latest release: https://github.com/$RepoOwner/$RepoName/releases" if ($PowerShellGalleryName) { Write-Output "- Run: $RepoName -UpdateSelf" Write-Output "- Run: Install-Script $PowerShellGalleryName -Force" } } else { Write-Output ("Status: {0,-40}" -f "Up to date.") } exit 0 } function UpdateSelf { try { # Get PSGallery version of script $psGalleryScriptVersion = (Find-Script -Name $PowerShellGalleryName).Version # If the current version is less than the PSGallery version, update the script if ($CurrentVersion -lt $psGalleryScriptVersion) { Write-Output "Updating script to version $psGalleryScriptVersion..." # Install NuGet PackageProvider if not already installed if (-not (Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue)) { Install-PackageProvider -Name "NuGet" -Force } # Trust the PSGallery if not already trusted $psRepoInstallationPolicy = (Get-PSRepository -Name 'PSGallery').InstallationPolicy if ($psRepoInstallationPolicy -ne 'Trusted') { Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted | Out-Null } # Update the script Install-Script $PowerShellGalleryName -Force # If PSGallery was not trusted, reset it to its original state if ($psRepoInstallationPolicy -ne 'Trusted') { Set-PSRepository -Name 'PSGallery' -InstallationPolicy $psRepoInstallationPolicy | Out-Null } Write-Output "Script updated to version $psGalleryScriptVersion." exit 0 } else { Write-Output "Script is already up to date." exit 0 } } catch { Write-Output "An error occurred: $_" exit 1 } } if ($Version.IsPresent) { $CurrentVersion ExitWithDelay 0 } if ($Help) { Get-Help -Name $MyInvocation.MyCommand.Source -Full ExitWithDelay 0 } if ($CheckForUpdate) { CheckForUpdate -RepoOwner $RepoOwner -RepoName $RepoName -CurrentVersion $CurrentVersion -PowerShellGalleryName $PowerShellGalleryName } if ($UpdateSelf) { UpdateSelf } # Display $PSVersionTable and Get-Host if -Verbose is specified if ($PSBoundParameters.ContainsKey('Verbose') -and $PSBoundParameters['Verbose']) { $PSVersionTable Get-Host } # Set debug preferences if -Debug is specified if ($PSBoundParameters.ContainsKey('Debug') -and $PSBoundParameters['Debug']) { $DebugPreference = 'Continue' $ConfirmPreference = 'None' } # ============================================================================ # # Main # ============================================================================ # $info = Get-SystemInfo if (-not $Silent) { 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 # MIIhEwYJKoZIhvcNAQcCoIIhBDCCIQACAQExDzANBglghkgBZQMEAgIFADCBiQYK # KwYBBAGCNwIBBKB7MHkwNAYKKwYBBAGCNwIBHjAmAgMBAAAEEB/MO2BZSwhOtyTS # xil+81ECAQACAQACAQACAQACAQAwQTANBglghkgBZQMEAgIFAAQwr/6igk/z87wD # IpBkejPx6bDR6ZLwUs2rWXqLoLwABzb9kIUfeLJzZcLC+vF6JD6SoIIHZDCCA1kw # 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/DI0pZPMYIY9DCCGPACAQEweDBkMQswCQYDVQQGEwJVUzEXMBUG # A1UEChMORGlnaUNlcnQsIEluYy4xPDA6BgNVBAMTM0RpZ2lDZXJ0IEdsb2JhbCBH # MyBDb2RlIFNpZ25pbmcgRUNDIFNIQTM4NCAyMDIxIENBMQIQATHD6wpQAEOPTJm3 # lp9NlDANBglghkgBZQMEAgIFAKCBjDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG # 9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIB # FTA/BgkqhkiG9w0BCQQxMgQwjzg9Plx7HIfxTVcBlqmOILwt8SxwPOMdIOWYUG+3 # /Tz31KH/+dCl6esLi6j8X0obMAsGByqGSM49AgEFAARnMGUCMQCaHafUXgt+BwW/ # cpQZALtmr/XUkw5QfVKuePn95AHLAV8+KA1jB/F361RbwQWY8fUCMAgvm4Agt+Vw # /Bl2J+qFfCwRqWQQcrqrgkfys+iN0zK5JHbOEdnvxUd0MVz7WMMIp6GCF1swghdX # BgorBgEEAYI3AwMBMYIXRzCCF0MGCSqGSIb3DQEHAqCCFzQwghcwAgEDMQ8wDQYJ # YIZIAWUDBAICBQAwgYgGCyqGSIb3DQEJEAEEoHkEdzB1AgEBBglghkgBhv1sBwEw # QTANBglghkgBZQMEAgIFAAQwYcAxhvxuSyQanCV7zCy0/9qT6jcjcLZGxLexCgnB # D4lf+zhzAOVBKL7p02/uo2ehAhEAt00gxrRp21TnUBMhBIWaRxgPMjAyNTAxMTUw # MDA2NDlaoIITAzCCBrwwggSkoAMCAQICEAuuZrxaun+Vh8b56QTjMwQwDQYJKoZI # hvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRp # bWVTdGFtcGluZyBDQTAeFw0yNDA5MjYwMDAwMDBaFw0zNTExMjUyMzU5NTlaMEIx # CzAJBgNVBAYTAlVTMREwDwYDVQQKEwhEaWdpQ2VydDEgMB4GA1UEAxMXRGlnaUNl # cnQgVGltZXN0YW1wIDIwMjQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC # AQC+anOf9pUhq5Ywultt5lmjtej9kR8YxIg7apnjpcH9CjAgQxK+CMR0Rne/i+ut # MeV5bUlYYSuuM4vQngvQepVHVzNLO9RDnEXvPghCaft0djvKKO+hDu6ObS7rJcXa # /UKvNminKQPTv/1+kBPgHGlP28mgmoCw/xi6FG9+Un1h4eN6zh926SxMe6We2r1Z # 6VFZj75MU/HNmtsgtFjKfITLutLWUdAoWle+jYZ49+wxGE1/UXjWfISDmHuI5e/6 # +NfQrxGFSKx+rDdNMsePW6FLrphfYtk/FLihp/feun0eV+pIF496OVh4R1TvjQYp # AztJpVIfdNsEvxHofBf1BWkadc+Up0Th8EifkEEWdX4rA/FE1Q0rqViTbLVZIqi6 # viEk3RIySho1XyHLIAOJfXG5PEppc3XYeBH7xa6VTZ3rOHNeiYnY+V4j1XbJ+Z9d # I8ZhqcaDHOoj5KGg4YuiYx3eYm33aebsyF6eD9MF5IDbPgjvwmnAalNEeJPvIeoG # JXaeBQjIK13SlnzODdLtuThALhGtyconcVuPI8AaiCaiJnfdzUcb3dWnqUnjXkRF # wLtsVAxFvGqsxUA2Jq/WTjbnNjIUzIs3ITVC6VBKAOlb2u29Vwgfta8b2ypi6n2P # zP0nVepsFk8nlcuWfyZLzBaZ0MucEdeBiXL+nUOGhCjl+QIDAQABo4IBizCCAYcw # DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYB # BQUHAwgwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMB8GA1UdIwQY # MBaAFLoW2W1NhS9zKXaaL3WMaiCPnshvMB0GA1UdDgQWBBSfVywDdw4oFZBmpWNe # 7k+SH3agWzBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsMy5kaWdpY2VydC5j # b20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5nQ0Eu # Y3JsMIGQBggrBgEFBQcBAQSBgzCBgDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au # ZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAChkxodHRwOi8vY2FjZXJ0cy5kaWdpY2Vy # dC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5n # Q0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQA9rR4fdplb4ziEEkfZQ5H2EdubTggd # 0ShPz9Pce4FLJl6reNKLkZd5Y/vEIqFWKt4oKcKz7wZmXa5VgW9B76k9NJxUl4Jl # KwyjUkKhk3aYx7D8vi2mpU1tKlY71AYXB8wTLrQeh83pXnWwwsxc1Mt+FWqz57yF # q6laICtKjPICYYf/qgxACHTvypGHrC8k1TqCeHk6u4I/VBQC9VK7iSpU5wlWjNlH # lFFv/M93748YTeoXU/fFa9hWJQkuzG2+B7+bMDvmgF8VlJt1qQcl7YFUMYgZU1WM # 6nyw23vT6QSgwX5Pq2m0xQ2V6FJHu8z4LXe/371k5QrN9FQBhLLISZi2yemW0P8Z # Zfx4zvSWzVXpAb9k4Hpvpi6bUe8iK6WonUSV6yPlMwerwJZP/Gtbu3CKldMnn+Lm # mRTkTXpFIEB06nXZrDwhCGED+8RsWQSIXZpuG4WLFQOhtloDRWGoCwwc6ZpPddOF # kM2LlTbMcqFSzm4cd0boGhBq7vkqI1uHRz6Fq1IX7TaRQuR+0BGOzISkcqwXu7nM # pFu3mgrlgbAW+BzikRVQ3K2YHcGkiKjA4gi4OA/kz1YCsdhIBHXqBzR0/Zd2QwQ/ # l4Gxftt/8wY3grcc/nS//TVkej9nmUYu83BDtccHHXKibMs/yXHhDXNkoPIdynhV # Aku7aRZOwqw6pDCCBq4wggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJKoZI # hvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ # MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1 # c3RlZCBSb290IEc0MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVowYzEL # MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJE # aWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBD # QTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklRVccl # A8TykTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54PMx9Q # Ewsmc5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupRPfDW # VtTnKC3r07G1decfBmWNlCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvohGS0 # UvJ2R/dhgxndX7RUCyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV5huo # wWR0QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYVVSZw # mCZ/oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6ic/rn # H1pslPJSlRErWHRAKKtzQ87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/CiPMpC # 3BhIfxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5K6jz # RWC8I41Y99xh3pP+OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oiqMEm # CPkUEBIDfV8ju2TjY+Cm4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuldyF4w # Er1GnrXTdrnSDmuZDNIztM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/ # AgEAMB0GA1UdDgQWBBS6FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAWgBTs # 1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYI # KwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz # cC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2lj # ZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDowOKA2 # oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290 # RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG # 9w0BAQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvHUF3i # Syn7cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0MCIKo # Fr2pVs8Vc40BIiXOlWk/R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCKrOX9 # jLxkJodskr2dfNBwCnzvqLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rAJ4JE # rpknG6skHibBt94q6/aesXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZxhOA # CcS2n82HhyS7T6NJuXdmkfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScsPT9r # p/Fmw0HNT7ZAmyEhQNC3EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1MrfvE # lXvtCl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXseGYs2 # uJPU5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWYMbRi # CQ8KvYHZE/6/pNHzV9m8BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYphwlH # K+Z/GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPwwggWN # MIIEdaADAgECAhAOmxiO+dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJ # BgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k # aWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBD # QTAeFw0yMjA4MDEwMDAwMDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVT # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j # b20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZI # hvcNAQEBBQADggIPADCCAgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK # 2FnC4SmnPVirdprNrnsbhA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/G # nhWlfr6fqVcWWVVyr2iTcMKyunWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJ # IB1jKS3O7F5OyJP4IWGbNOsFxl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4M # K7dPpzDZVu7Ke13jrclPXuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN # 2NQ3pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I # 11pJpMLmqaBn3aQnvKFPObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KIS # G2aadMreSx7nDmOu5tTvkpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9 # HJXDj/chsrIRt7t/8tWMcCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4 # pncB4Q+UDCEdslQpJYls5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpy # FiIJ33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS31 # 2amyHeUbAgMBAAGjggE6MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs # 1+OC0nFdZEzfLmc/57qYrhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd # 823IDzAOBgNVHQ8BAf8EBAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzAB # hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9j # YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQw # RQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lD # ZXJ0QXNzdXJlZElEUm9vdENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZI # hvcNAQEMBQADggEBAHCgv0NcVec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4 # hxppVCLtpIh3bb0aFPQTSnovLbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3 # rDB6mouyXtTP0UNEm0Mh65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs # 9wPHh6jSTEAZNUZqaVSwuKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K # 2yCNNWAcAgPLILCsWKAOQGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0n # ftg62fC2h5b9W9FcrBjDTZ9ztwGpn1eqXijiuZQxggOGMIIDggIBATB3MGMxCzAJ # BgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGln # aUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EC # EAuuZrxaun+Vh8b56QTjMwQwDQYJYIZIAWUDBAICBQCggeEwGgYJKoZIhvcNAQkD # MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNTAxMTUwMDA2NDlaMCsG # CyqGSIb3DQEJEAIMMRwwGjAYMBYEFNvThe5i29I+e+T2cUhQhyTVhltFMDcGCyqG # SIb3DQEJEAIvMSgwJjAkMCIEIHZ2n6jyYy8fQws6IzCu1lZ1/tdz2wXWZbkFk5hD # j5rbMD8GCSqGSIb3DQEJBDEyBDC3t9xewmf05HVcvmTTUOnLUtyqKSRY4cM9Ecqa # 0jFCWZq2aLK28YAb+F/n/imK5QEwDQYJKoZIhvcNAQEBBQAEggIAuvScMwV8Mg/W # SRploegPAgryssagvF6amxDvySaDubbvHwmlQarlP3clKfYgAFRyNh/cduyN4+1k # dhi5RgsP61cVjXy2NY+4t4Ym1F5OqMj07tILc1EtS7NMrePvzJk3hoPXuXBeGDnS # jRhm3JEKJpLxXMEheMBTL/t3NtoqQDjm2Mu0NFGRrmQYxGI5wlE+19coTngcWGAc # RzyhGNoekZEtznt1XNb/qJEV9DvtewyFXSd8XIUqBLXoVxbBaOaXve+DldxkwGSH # b+hgXE4gfhrhYqzl5c0wXrNo8xnLpZFU/2k3RB6S1DS07CzGHjkLhLNxYMrTYy3+ # fMBzVqqrBidzn+vX4IolevBpY7KXOyYKSQvpemOmBYHqySzoCX7VmjUTJ9/jPMzD # 9Gjkca2OfZ3iZkGoirT8NzJ3dFU7z5TXNrXs2btCscByXVtePiSNvw4H3cZu1JVz # 0XVoKpSUCt7zQE03Z6nqeyGZtlg9RxY5uIdx3GA5oeC4J6Mir56SLhuj1pNGLorB # W0z9UQQJXi7P5/TXQsX9xI+9EMX34skW9L4HAQaVfaSWxKcvB9AVCfALJMPrsl+X # a3Dqj3IcQAweEC7TgmAuSZr9ikE3MsXPOv4ke/Unv6XuCnK8oCNyLchinnRIVPCO # zN3GTOklXwJK79FQkUB5+W6T9BgFlqg= # SIG # End signature block |