PowerBGInfo.psm1

function Get-ComputerCPU {
    [CmdletBinding()]
    param([string[]] $ComputerName = $Env:COMPUTERNAME,
        [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default',
        [switch] $All)
    [string] $Class = 'win32_processor'
    if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'PSComputerName', 'Name', 'DeviceID', 'Caption', 'SystemName', 'CurrentClockSpeed', 'MaxClockSpeed', 'ProcessorID', 'ThreadCount', 'Architecture', 'Status', 'LoadPercentage', 'L3CacheSize', 'Manufacturer', 'VirtualizationFirmwareEnabled', 'NumberOfCores', 'NumberOfEnabledCore', 'NumberOfLogicalProcessors' }
    $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties
    if ($All) { $Information } else {
        foreach ($Info in $Information) {
            foreach ($Data in $Info) {
                [PSCustomObject] @{ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME }
                    Name                        = $Data.Name
                    DeviceID                    = $Data.DeviceID
                    Caption                     = $Data.Caption
                    CurrentClockSpeed           = $Data.CurrentClockSpeed
                    MaxClockSpeed               = $Data.MaxClockSpeed
                    ProcessorID                 = $Data.ProcessorID
                    ThreadCount                 = $Data.ThreadCount
                    Architecture                = $Data.Architecture
                    Status                      = $Data.Status
                    LoadPercentage              = $Data.LoadPercentage
                    Manufacturer                = $Data.Manufacturer
                    NumberOfCores               = $Data.NumberOfCores
                    NumberOfEnabledCore         = $Data.NumberOfEnabledCore
                    NumberOfLogicalProcessors   = $Data.NumberOfLogicalProcessors
                }
            }
        }
    }
}
function Get-ComputerRAM {
    [CmdletBinding()]
    param([string] $ComputerName = $Env:COMPUTERNAME,
        [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default',
        [switch] $All,
        [switch] $Extended)
    [string] $Class = 'Win32_physicalmemory '
    if ($All) { [string] $Properties = '*' } else {
        [string[]] $Properties = @('InstallDate'
            'Manufacturer'
            'Model'
            'OtherIdentifyingInfo'
            'PartNumber'
            'PoweredOn'
            'SerialNumber'
            'SKU'
            'Tag'
            'Version'
            'HotSwappable'
            'Removable'
            'Replaceable'
            'FormFactor'
            'BankLabel'
            'Capacity'
            'InterleavePosition'
            'MemoryType'
            'Speed'
            'ConfiguredClockSpeed'
            'ConfiguredVoltage'
            'DeviceLocator'
            'MaxVoltage'
            'MinVoltage'
            'SMBIOSMemoryType'
            'TypeDetail'
            'PSComputerName')
    }
    $FormFactor = @{'0' = 'Unknown'
        '1'             = 'Other'
        '2'             = 'SIP'
        '3'             = 'DIP'
        '4'             = 'ZIP'
        '5'             = 'SOJ'
        '6'             = 'Proprietary'
        '7'             = 'SIMM'
        '8'             = 'DIMM'
        '9'             = 'TSOP'
        '10'            = 'PGA'
        '11'            = 'RIMM'
        '12'            = 'SODIMM'
        '13'            = 'SRIMM'
        '14'            = 'SMD'
        '15'            = 'SSMP'
        '16'            = 'QFP'
        '17'            = 'TQFP'
        '18'            = 'SOIC'
        '19'            = 'LCC'
        '20'            = 'PLCC'
        '21'            = 'BGA'
        '22'            = 'FPBGA'
        '23'            = 'LGA'
    }
    $TypeDetails = @{'1' = 'Reserved'
        '2'              = 'Other'
        '4'              = 'Unknown'
        '8'              = 'Fast-paged'
        '16'             = 'Static column'
        '32'             = 'Pseudo-static'
        '64'             = 'RAMBUS'
        '128'            = 'Synchronous'
        '256'            = 'CMOS'
        '512'            = 'EDO'
        '1024'           = 'Window DRAM'
        '2048'           = 'Cache DRAM'
        '4096'           = 'Non-volatile'
    }
    $InterleavePosition = @{'0' = "Non-Interleaved"
        '1'                     = "First Position"
        '2'                     = "Second Position"
    }
    $MemoryType = @{'0' = "Unknown"
        '1'             = "Other"
        '2'             = "DRAM"
        '3'             = "Synchronous DRAM"
        '4'             = "Cache DRAM"
        '5'             = "EDO"
        '6'             = "EDRAM"
        '7'             = "VRAM"
        '8'             = "SRAM"
        '9'             = "ROM"
        '10'            = "ROM"
        '11'            = "FLASH"
        '12'            = "EEPROM"
        '13'            = "FEPROM"
        '14'            = "EPROM"
        '15'            = "CDRAM"
        '16'            = "3DRAM"
        '17'            = "SDRAM"
        '18'            = "SGRAM"
        '19'            = "RDRAM"
        '20'            = "DDR"
    }
    $MemoryTypeSMBIOS = @{'0' = 'Unknown'
        '1'                   = 'Other'
        '2'                   = 'DRAM'
        '3'                   = 'Synchronous DRAM'
        '4'                   = 'Cache DRAM'
        '5'                   = 'EDO'
        '6'                   = 'EDRAM'
        '7'                   = 'VRAM'
        '8'                   = 'SRAM'
        '9'                   = 'RAM'
        '10'                  = 'ROM'
        '11'                  = 'Flash'
        '12'                  = 'EEPROM'
        '13'                  = 'FEPROM'
        '14'                  = 'EPROM'
        '15'                  = 'CDRAM'
        '16'                  = '3DRAM'
        '17'                  = 'SDRAM'
        '18'                  = 'SGRAM'
        '19'                  = 'RDRAM'
        '20'                  = 'DDR'
        '21'                  = 'DDR2'
        '22'                  = 'DDR2 FB-DIMM'
        '24'                  = 'DDR3'
        '25'                  = 'FBD2'
        '26'                  = 'DDR4'
    }
    $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties
    if ($All) { $Information } else {
        foreach ($Info in $Information) {
            foreach ($Data in $Info) {
                $Ram = [ordered] @{ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME }
                    Manufacturer                = $Data.Manufacturer
                    FormFactor                  = $FormFactor["$($Data.FormFactor)"]
                    SMBIOSMemoryType            = $MemoryTypeSMBIOS["$($Data.SMBIOSMemoryType)"]
                    Size                        = [math]::round($Data.Capacity / 1GB, 2)
                    Speed                       = $Data.Speed
                    InterleavePosition          = $InterleavePosition["$($Data.InterleavePosition)"]
                    MemoryType                  = $MemoryType["$($Data.MemoryType)"]
                    TypeDetail                  = $TypeDetails["$($Data.TypeDetail)"]
                    PartNumber                  = $Data.PartNumber
                    DeviceLocator               = $Data.DeviceLocator
                }
                if ($Extended) {
                    $RamExtended = [ordered] @{InstallDate = $Data.InstallDate
                        Model                              = $Data.Model
                        OtherIdentifyingInfo               = $Data.OtherIdentifyingInfo
                        PoweredOn                          = $Data.PoweredOn
                        SerialNumber                       = $Data.SerialNumber
                        SKU                                = $Data.SKU
                        Tag                                = $Data.Tag
                        Version                            = $Data.Version
                        HotSwappable                       = $Data.HotSwappable
                        Removable                          = $Data.Removable
                        Replaceable                        = $Data.Replaceable
                        BankLabel                          = $Data.BankLabel
                        ConfiguredClockSpeed               = $Data.ConfiguredClockSpeed
                        ConfiguredVoltage                  = $Data.ConfiguredVoltage
                        MaxVoltage                         = $Data.MaxVoltage
                        MinVoltage                         = $Data.MinVoltage
                    }
                    [PSCustomObject] ($Ram + $RamExtended)
                } else { [PSCustomObject] $Ram }
            }
        }
    }
}
function Get-CimData {
    <#
    .SYNOPSIS
    Helper function for retreiving CIM data from local and remote computers
 
    .DESCRIPTION
    Helper function for retreiving CIM data from local and remote computers
 
    .PARAMETER ComputerName
    Specifies computer on which you want to run the CIM operation. You can specify a fully qualified domain name (FQDN), a NetBIOS name, or an IP address. If you do not specify this parameter, the cmdlet performs the operation on the local computer using Component Object Model (COM).
 
    .PARAMETER Protocol
    Specifies the protocol to use. The acceptable values for this parameter are: DCOM, Default, or Wsman.
 
    .PARAMETER Class
    Specifies the name of the CIM class for which to retrieve the CIM instances. You can use tab completion to browse the list of classes, because PowerShell gets a list of classes from the local WMI server to provide a list of class names.
 
    .PARAMETER Properties
    Specifies a set of instance properties to retrieve. Use this parameter when you need to reduce the size of the object returned, either in memory or over the network. The object returned also contains the key properties even if you have not listed them using the Property parameter. Other properties of the class are present but they are not populated.
 
    .EXAMPLE
    Get-CimData -Class 'win32_bios' -ComputerName AD1,EVOWIN
 
    Get-CimData -Class 'win32_bios'
 
    # Get-CimClass to get all classes
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([parameter(Mandatory)][string] $Class,
        [string] $NameSpace = 'root\cimv2',
        [string[]] $ComputerName = $Env:COMPUTERNAME,
        [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default',
        [string[]] $Properties = '*')
    $ExcludeProperties = 'CimClass', 'CimInstanceProperties', 'CimSystemProperties', 'SystemCreationClassName', 'CreationClassName'
    [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName
    $CimObject = @(# requires removal of this property for query
        [string[]] $PropertiesOnly = $Properties | Where-Object { $_ -ne 'PSComputerName' }
        $Computers = $ComputersSplit[1]
        if ($Computers.Count -gt 0) {
            if ($Protocol = 'Default') { Get-CimInstance -ClassName $Class -ComputerName $Computers -ErrorAction SilentlyContinue -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsToProcess | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties } else {
                $Option = New-CimSessionOption -Protocol $Protocol
                $Session = New-CimSession -ComputerName $Computers -SessionOption $Option -ErrorAction SilentlyContinue
                $Info = Get-CimInstance -ClassName $Class -CimSession $Session -ErrorAction SilentlyContinue -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsToProcess | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties
                $null = Remove-CimSession -CimSession $Session -ErrorAction SilentlyContinue
                $Info
            }
        }
        foreach ($E in $ErrorsToProcess) { Write-Warning -Message "Get-CimData - No data for computer $($E.OriginInfo.PSComputerName). Failed with errror: $($E.Exception.Message)" }
        $Computers = $ComputersSplit[0]
        if ($Computers.Count -gt 0) {
            $Info = Get-CimInstance -ClassName $Class -ErrorAction SilentlyContinue -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsLocal | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties
            $Info | Add-Member -Name 'PSComputerName' -Value $Computers -MemberType NoteProperty -Force
            $Info
        }
        foreach ($E in $ErrorsLocal) { Write-Warning -Message "Get-CimData - No data for computer $($Env:COMPUTERNAME). Failed with errror: $($E.Exception.Message)" })
    $CimObject
}
function Get-ComputerSplit {
    [CmdletBinding()]
    param([string[]] $ComputerName)
    if ($null -eq $ComputerName) { $ComputerName = $Env:COMPUTERNAME }
    try { $LocalComputerDNSName = [System.Net.Dns]::GetHostByName($Env:COMPUTERNAME).HostName } catch { $LocalComputerDNSName = $Env:COMPUTERNAME }
    $ComputersLocal = $null
    [Array] $Computers = foreach ($Computer in $ComputerName) {
        if ($Computer -eq '' -or $null -eq $Computer) { $Computer = $Env:COMPUTERNAME }
        if ($Computer -ne $Env:COMPUTERNAME -and $Computer -ne $LocalComputerDNSName) { $Computer } else { $ComputersLocal = $Computer }
    }
    , @($ComputersLocal, $Computers)
}
function New-BGInfo {
    <#
    .SYNOPSIS
    Provides a simple way to create PowerBGInfo configuration.
 
    .DESCRIPTION
    Provides a simple way to create PowerBGInfo configuration.
    It allows writting useful information on your desktop background.
    Every time the script is run, it will update existing image with new information.
 
    .PARAMETER BGInfoContent
    Special parameter that works as a scriptblock. It takes input and converts it into configuration.
    By using New-BGInfoLabel and New-BGInfoValue along with other supported PowerShell commands you can create your own configuration.
 
    .PARAMETER FilePath
    Path to the image that will be used as a background. If not provided current Desktop Background will be used.
 
    .PARAMETER ConfigurationDirectory
    Path to the directory where configuration will be stored, and where image for desktop background will be placed. If not provided, it will be stored in C:\TEMP
 
    .PARAMETER FontFamilyName
    Font family name that will be used to display information for Label.
    It's only used if New-BGInfoLabel or New-BGIInfoValue doesn't provide it's own value.
    If ValueFontFamilyName is not provided it will be used as a default value for that property as well
 
    .PARAMETER Color
    Color that will be used to display information for Label.
    It's only used if New-BGInfoLabel or New-BGIInfoValue doesn't provide it's own value.
    If ValueColor is not provided it will be used as a default value for that property as well
 
    .PARAMETER FontSize
    Font size that will be used to display information for Label.
    It's only used if New-BGInfoLabel or New-BGIInfoValue doesn't provide it's own value.
    If ValueFontSize is not provided it will be used as a default value for that property as well
 
    .PARAMETER ValueColor
    Color that will be used to display information for Value.
    It's only used if New-BGInfoLabel or New-BGIInfoValue doesn't provide it's own value.
    If not provided it will be taken from Color property.
 
    .PARAMETER ValueFontSize
    Font size that will be used to display information for Value.
    It's only used if New-BGInfoLabel or New-BGIInfoValue doesn't provide it's own value.
    If not provided it will be taken from FontSize property.
 
    .PARAMETER ValueFontFamilyName
    Font family name that will be used to display information for Value.
    It's only used if New-BGInfoLabel or New-BGIInfoValue doesn't provide it's own value.
    If not provided it will be taken from FontFamilyName property.
 
    .PARAMETER SpaceBetweenLines
    Length of the space between lines
 
    .PARAMETER SpaceBetweenColumns
    Length of the space between columns (Label and Value)
 
    .PARAMETER PositionX
    Position of the first column on the X axis.
 
    .PARAMETER PositionY
    Position of the first column on the Y axis.
 
    .PARAMETER MonitorIndex
    Index of the monitor that will be used to display the background image. By default it will be 0 (first monitor)
 
    .PARAMETER WallpaperFit
    WHat to do with the image if it is not the same size as the monitor resolution. It can be one of the following: 'Center', 'Fit', 'Stretch', 'Tile', 'Span', 'Fill'
 
    .EXAMPLE
    New-BGInfo -MonitorIndex 0 {
        # Lets add computer name, but lets use builtin values for that
        New-BGInfoValue -BuiltinValue HostName -Color Red -FontSize 20 -FontFamilyName 'Calibri'
        New-BGInfoValue -BuiltinValue FullUserName
        New-BGInfoValue -BuiltinValue CpuName
        New-BGInfoValue -BuiltinValue CpuLogicalCores
        New-BGInfoValue -BuiltinValue RAMSize
        New-BGInfoValue -BuiltinValue RAMSpeed
 
        # Lets add Label, but without any values, kinf of like section starting
        New-BGInfoLabel -Name "Drives" -Color LemonChiffon -FontSize 16 -FontFamilyName 'Calibri'
 
        # Lets get all drives and their labels
        foreach ($Disk in (Get-Disk)) {
            $Volumes = $Disk | Get-Partition | Get-Volume
            foreach ($V in $Volumes) {
                New-BGInfoValue -Name "Drive $($V.DriveLetter)" -Value $V.SizeRemaining
            }
        }
    } -FilePath $PSScriptRoot\Samples\PrzemyslawKlysAndKulkozaurr.jpg -ConfigurationDirectory $PSScriptRoot\Output -PositionX 100 -PositionY 100 -WallpaperFit Center
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([parameter(Mandatory)][scriptblock] $BGInfoContent,
        [string] $FilePath,
        [parameter(Mandatory)][string] $ConfigurationDirectory,
        [string] $FontFamilyName = 'Calibri',
        [SixLabors.ImageSharp.Color] $Color = [SixLabors.ImageSharp.Color]::Black,
        [int] $FontSize = 16,
        [SixLabors.ImageSharp.Color] $ValueColor = [SixLabors.ImageSharp.Color]::Black,
        [float] $ValueFontSize = 16,
        [string] $ValueFontFamilyName = 'Calibri',
        [int] $SpaceBetweenLines = 10,
        [int] $SpaceBetweenColumns = 30,
        [int] $PositionX = 10,
        [int] $PositionY = 10,
        [int] $MonitorIndex = 0,
        [ValidateSet('Center', 'Fit', 'Stretch', 'Tile', 'Span', 'Fill')][string] $WallpaperFit)
    $ConfigurationPath = [io.path]::Combine($ConfigurationDirectory, "PowerBGInfoConfiguration.xml")
    if (Test-Path -LiteralPath $ConfigurationPath) { $Configuration = Import-Clixml -LiteralPath $ConfigurationPath } else { $Configuration = [ordered] @{OriginalImage = '' } }
    if ($FilePath -eq "") { $WallpaperPath = Get-DesktopWallpaper -Index $MonitorIndex } else { $WallpaperPath = $FilePath }
    if ($WallpaperPath -eq "" -or (Test-Path -LiteralPath $WallpaperPath) -eq $false) {
        Write-Warning -Message "New-BGInfo - Wallpaper ($WallpaperPath) not found. Provide new wallpaper, or make sure one is already set."
        return
    }
    $Configuration['OriginalImage'] = $WallpaperPath
    $FileName = [io.path]::GetFileName($Configuration['OriginalImage'])
    $FilePathOutput = [io.path]::Combine($ConfigurationDirectory, $FileName)
    if ($FilePathOutput -ne $Configuration['OriginalImage']) { Copy-Item -Path $Configuration['OriginalImage'] -Destination $FilePathOutput -Force }
    if ($FilePathOutput -eq "" -or (Test-Path -LiteralPath $FilePathOutput) -eq $false) {
        Write-Warning -Message "New-BGInfo - Wallpaper ($FilePathOutput) not found. Copying failed?"
        return
    }
    $Image = Get-Image -FilePath $FilePathOutput
    $BGContent = & $BGInfoContent
    $HighestWidth = 0
    $HighestHeight = 0
    foreach ($Info in $BGContent) {
        if ($Info.Color) {} else { $Info.Color = $Color }
        if ($Info.FontSize) {} else { $Info.FontSize = $FontSize }
        if ($Info.FontFamilyName) {} else { $Info.FontFamilyName = $FontFamilyName }
        if ($Info.Type -ne 'Label') {
            if ($Info.ValueColor) {} else { if ($Info.Color) { $Info.ValueColor = $Info.Color } else { $Info.ValueColor = $ValueColor } }
            if ($Info.ValueFontSize) {} else { if ($Info.FontSize) { $Info.ValueFontSize = $Info.FontSize } else { $Info.ValueFontSize = $ValueFontSize } }
            if ($Info.ValueFontFamilyName) {} else { if ($Info.FontFamilyName) { $Info.ValueFontFamilyName = $Info.FontFamilyName } else { $Info.ValueFontFamilyName = $ValueFontFamilyName } }
        }
        $SizeOfText = $Image.GetTextSize($Info.Name, $Info.FontSize, $Info.FontFamilyName)
        if ($SizeOfText.Width -gt $HighestWidth) { $HighestWidth = $SizeOfText.Width }
        if ($SizeOfText.Height -gt $HighestHeight) { $HighestHeight = $SizeOfText.Height }
    }
    foreach ($Info in $BGContent) {
        if ($Info.Type -eq 'Label') { $Image.AddText($PositionX, $PositionY, $Info.Name, $Info.Color, $Info.FontSize, $Info.FontFamilyName) } else {
            $Image.AddText($PositionX, $PositionY, $Info.Name, $Info.Color, $Info.FontSize, $Info.FontFamilyName)
            $Image.AddText($PositionX + $HighestWidth + $SpaceBetweenColumns, $PositionY, $Info.Value, $Info.ValueColor, $Info.ValueFontSize, $Info.ValueFontFamilyName)
        }
        $PositionY += $HighestHeight + $SpaceBetweenLines
    }
    Save-Image -Image $Image -FilePath $FilePathOutput
    if ($WallpaperFit) { Set-DesktopWallpaper -Index $MonitorIndex -FilePath $FilePathOutput -Position $WallpaperFit } else { Set-DesktopWallpaper -Index $MonitorIndex -FilePath $FilePathOutput }
    $Configuration | Export-Clixml -LiteralPath $ConfigurationPath -Force
}
function New-BGInfoLabel {
    <#
    .SYNOPSIS
    Provides ability to set label without value. It can be used to separate different sections of information.
 
    .DESCRIPTION
    Provides ability to set label without value. It can be used to separate different sections of information.
 
    .PARAMETER Name
    Name of the label/section
 
    .PARAMETER Color
    Color for the label. If not provided it will be taken from the parent New-BGInfo command.
 
    .PARAMETER FontSize
    Font size for the label. If not provided it will be taken from the parent New-BGInfo command.
 
    .PARAMETER FontFamilyName
    Font family name for the label. If not provided it will be taken from the parent New-BGInfo command.
 
    .EXAMPLE
    # Lets add Label, but without any values, kinf of like section starting
    New-BGInfoLabel -Name "Drives" -Color LemonChiffon -FontSize 16 -FontFamilyName 'Calibri'
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([string] $Name,
        [SixLabors.ImageSharp.Color] $Color,
        [float] $FontSize,
        [string] $FontFamilyName)
    [PSCustomObject] @{Type = 'Label'
        Name                = $Name
        Color               = $Color
        FontSize            = $FontSize
        FontFamilyName      = $FontFamilyName
    }
}
function New-BGInfoValue {
    <#
    .SYNOPSIS
    Special function that provides a way to create a value that will be displayed on the background image.
 
    .DESCRIPTION
    Special function that provides a way to create a value that will be displayed on the background image.
    It allows using builtin values, or custom values depending on user needs.
 
    .PARAMETER Name
    Label that will be used on the left side of the value.
 
    .PARAMETER Value
    Cystom Value that will be displayed on the right side of the label.
 
    .PARAMETER BuiltinValue
    Builtin value that will be displayed on the right side of the label. It can be one of the following:
    - UserName - Current user name
    - HostName - Current host name
    - FullUserName - Current user name with domain
    - CpuName - CPU name
    - CpuMaxClockSpeed - CPU max clock speed
    - CpuCores - CPU cores
    - CpuLogicalCores - CPU logical cores
    - RAMSize - RAM size
    - RAMSpeed - RAM speed
    - RAMPartNumber - RAM part number
 
    .PARAMETER Color
    Color for the label. If not provided it will be taken from the parent New-BGInfo command.
 
    .PARAMETER FontSize
    Font size for the label. If not provided it will be taken from the parent New-BGInfo command.
 
    .PARAMETER FontFamilyName
    Font family name for the label. If not provided it will be taken from the parent New-BGInfo command.
 
    .PARAMETER ValueColor
    Color for the value. If not provided it will be taken first from Color of the label and if that is not provided from the parent New-BGInfo command.
 
    .PARAMETER ValueFontSize
    Font size for the value. If not provided it will be taken first from FontSize of the label and if that is not provided from the parent New-BGInfo command.
 
    .PARAMETER ValueFontFamilyName
    Font family name for the value. If not provided it will be taken first from FontFamilyName of the label and if that is not provided from the parent New-BGInfo command.
 
    .EXAMPLE
    New-BGInfoValue -BuiltinValue HostName -Color Red -FontSize 20 -FontFamilyName 'Calibri'
    New-BGInfoValue -BuiltinValue FullUserName
    New-BGInfoValue -BuiltinValue CpuName
 
    .EXAMPLE
    # Lets get all drives and their labels
    foreach ($Disk in (Get-Disk)) {
        $Volumes = $Disk | Get-Partition | Get-Volume
        foreach ($V in $Volumes) {
            New-BGInfoValue -Name "Drive $($V.DriveLetter)" -Value $V.SizeRemaining
        }
    }
 
    .NOTES
    General notes
    #>

    [CmdletBinding(DefaultParameterSetName = 'Values')]
    param([parameter(ParameterSetName = 'Values', Mandatory)]
        [string] $Name,
        [parameter(ParameterSetName = 'Values', Mandatory)]
        [string] $Value,
        [parameter(ParameterSetName = 'Builtin', Mandatory)]
        [ValidateSet('UserName',
            'HostName',
            'FullUserName',
            'CpuName',
            'CpuMaxClockSpeed',
            'CpuCores',
            'CpuLogicalCores',
            'RAMSize',
            'RAMSpeed',
            'RAMPartNumber')][string] $BuiltinValue,
        [parameter(ParameterSetName = 'Values')]
        [parameter(ParameterSetName = 'Builtin')]
        [SixLabors.ImageSharp.Color] $Color,
        [parameter(ParameterSetName = 'Values')]
        [parameter(ParameterSetName = 'Builtin')]
        [float] $FontSize,
        [parameter(ParameterSetName = 'Values')]
        [parameter(ParameterSetName = 'Builtin')]
        [string] $FontFamilyName,
        [parameter(ParameterSetName = 'Values')]
        [parameter(ParameterSetName = 'Builtin')]
        [SixLabors.ImageSharp.Color] $ValueColor,
        [parameter(ParameterSetName = 'Values')]
        [parameter(ParameterSetName = 'Builtin')]
        [float] $ValueFontSize,
        [parameter(ParameterSetName = 'Values')]
        [parameter(ParameterSetName = 'Builtin')]
        [string] $ValueFontFamilyName)
    if ($BuiltinValue) {
        if ($BuiltinValue -in 'CPUName', 'CpuMaxClockSpeed', 'CpuCores', 'CpuLogicalCores') { $ComputerCPU = Get-ComputerCPU } elseif ($BuiltinValue -in 'RAMSize', 'RAMSpeed', 'RAMPartNumber') { $ComputerRAM = Get-ComputerRAM }
        if ($BuiltinValue -eq 'UserName') { $SetValue = $env:USERNAME } elseif ($BuiltinValue -eq 'HostName') { $SetValue = $env:COMPUTERNAME } elseif ($BuiltinValue -eq 'FullUserName') { $SetValue = $env:USERDOMAIN + '\' + $env:USERNAME } elseif ($BuiltinValue -eq 'CPUName') { $SetValue = $ComputerCPU.Name } elseif ($BuiltinValue -eq 'CpuMaxClockSpeed') { $SetValue = $ComputerCPU.MaxClockSpeed } elseif ($BuiltinValue -eq 'CpuCores') { $SetValue = $ComputerCPU.NumberOfEnabledCore } elseif ($BuiltinValue -eq 'CpuLogicalCores') { $SetValue = $ComputerCPU.NumberOfLogicalProcessors } elseif ($BuiltinValue -eq 'RAMSize') { $SetValue = ($ComputerRAM.Size | ForEach-Object { $_.ToString('N0') + 'GB' }) -join " / " } elseif ($BuiltinValue -eq 'RAMSpeed') { $SetValue = ($ComputerRAM.Speed | ForEach-Object { $_.ToString('N0') + 'MHz' }) -join " / " } elseif ($BuiltinValue -eq 'RAMPartNumber') { $SetValue = $ComputerRAM.PartNumber -join ", " }
        $SetName = $BuiltinValue
    } else {
        $SetValue = $Value
        $SetName = $Name
    }
    [PSCustomObject] @{Type = 'Values'
        Name                = $SetName
        Value               = $SetValue
        Color               = $Color
        FontSize            = $FontSize
        FontFamilyName      = $FontFamilyName
        ValueColor          = $ValueColor
        ValueFontSize       = $ValueFontSize
        ValueFontFamilyName = $ValueFontFamilyName
    }
}
if ($PSVersionTable.PSEdition -eq 'Desktop' -and (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full").Release -lt 461808) { Write-Warning "This module requires .NET Framework 4.7.2 or later."; return }
Export-ModuleMember -Function @('New-BGInfo', 'New-BGInfoLabel', 'New-BGInfoValue') -Alias @()
# SIG # Begin signature block
# MIInPgYJKoZIhvcNAQcCoIInLzCCJysCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAmlp5eFev+Z0o+
# uP5kcMGS6irkEILUzRZ58nmuTdSSGKCCITcwggO3MIICn6ADAgECAhAM5+DlF9hG
# /o/lYPwb8DA5MA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBa
# Fw0zMTExMTAwMDAwMDBaMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lD
# ZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
# AQoCggEBAK0OFc7kQ4BcsYfzt2D5cRKlrtwmlIiq9M71IDkoWGAM+IDaqRWVMmE8
# tbEohIqK3J8KDIMXeo+QrIrneVNcMYQq9g+YMjZ2zN7dPKii72r7IfJSYd+fINcf
# 4rHZ/hhk0hJbX/lYGDW8R82hNvlrf9SwOD7BG8OMM9nYLxj+KA+zp4PWw25EwGE1
# lhb+WZyLdm3X8aJLDSv/C3LanmDQjpA1xnhVhyChz+VtCshJfDGYM2wi6YfQMlqi
# uhOCEe05F52ZOnKh5vqk2dUXMXWuhX0irj8BRob2KHnIsdrkVxfEfhwOsLSSplaz
# vbKX7aqn8LfFqD+VFtD/oZbrCF8Yd08CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGG
# MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEXroq/0ksuCMS1Ri6enIZ3zbcgP
# MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBBQUA
# A4IBAQCiDrzf4u3w43JzemSUv/dyZtgy5EJ1Yq6H6/LV2d5Ws5/MzhQouQ2XYFwS
# TFjk0z2DSUVYlzVpGqhH6lbGeasS2GeBhN9/CTyU5rgmLCC9PbMoifdf/yLil4Qf
# 6WXvh+DfwWdJs13rsgkq6ybteL59PyvztyY1bV+JAbZJW58BBZurPSXBzLZ/wvFv
# hsb6ZGjrgS2U60K3+owe3WLxvlBnt2y98/Efaww2BxZ/N3ypW2168RJGYIPXJwS+
# S86XvsNnKmgR34DnDDNmvxMNFG7zfx9jEB76jRslbWyPpbdhAbHSoyahEHGdreLD
# +cOZUbcrBwjOLuZQsqf6CkUvovDyMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1
# b5VQCDANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln
# aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtE
# aWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgx
# MDIyMTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT
# SEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLX
# cep2nQUut4/6kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSR
# I5aQd4L5oYQjZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXi
# TWAYvqrEsq5wMWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5
# Ng2Q7+S1TqSp6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8
# vYWxYoNzQYIH5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYD
# VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYB
# BQUHAwMweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k
# aWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4
# oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJv
# b3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dEFzc3VyZWRJRFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCow
# KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZI
# AYb9bAMwHQYDVR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaA
# FEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPz
# ItEVyCx8JSl2qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRu
# pY5a4l4kgU4QpO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKN
# JK4kxscnKqEpKBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmif
# z0DLQESlE/DmZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN
# 3fYBIM6ZMWM9CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKy
# ZqHnGKSaZFHvMIIFPTCCBCWgAwIBAgIQBNXcH0jqydhSALrNmpsqpzANBgkqhkiG
# 9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw
# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEy
# IEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTIwMDYyNjAwMDAwMFoXDTIz
# MDcwNzEyMDAwMFowejELMAkGA1UEBhMCUEwxEjAQBgNVBAgMCcWabMSFc2tpZTER
# MA8GA1UEBxMIS2F0b3dpY2UxITAfBgNVBAoMGFByemVteXPFgmF3IEvFgnlzIEVW
# T1RFQzEhMB8GA1UEAwwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7KB3iyBrhkLUbbFe9qxhKKPBYqDBqln
# r3AtpZplkiVjpi9dMZCchSeT5ODsShPuZCIxJp5I86uf8ibo3vi2S9F9AlfFjVye
# 3dTz/9TmCuGH8JQt13ozf9niHecwKrstDVhVprgxi5v0XxY51c7zgMA2g1Ub+3ti
# i0vi/OpmKXdL2keNqJ2neQ5cYly/GsI8CREUEq9SZijbdA8VrRF3SoDdsWGf3tZZ
# zO6nWn3TLYKQ5/bw5U445u/V80QSoykszHRivTj+H4s8ABiforhi0i76beA6Ea41
# zcH4zJuAp48B4UhjgRDNuq8IzLWK4dlvqrqCBHKqsnrF6BmBrv+BXQIDAQABo4IB
# xTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYE
# FBixNSfoHFAgJk4JkDQLFLRNlJRmMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
# BggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2Vy
# dC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQu
# ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3
# BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
# Y29tL0NQUzAIBgZngQwBBAEwgYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25p
# bmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAmr1sz4ls
# LARi4wG1eg0B8fVJFowtect7SnJUrp6XRnUG0/GI1wXiLIeow1UPiI6uDMsRXPHU
# F/+xjJw8SfIbwava2eXu7UoZKNh6dfgshcJmo0QNAJ5PIyy02/3fXjbUREHINrTC
# vPVbPmV6kx4Kpd7KJrCo7ED18H/XTqWJHXa8va3MYLrbJetXpaEPpb6zk+l8Rj9y
# G4jBVRhenUBUUj3CLaWDSBpOA/+sx8/XB9W9opYfYGb+1TmbCkhUg7TB3gD6o6ES
# Jre+fcnZnPVAPESmstwsT17caZ0bn7zETKlNHbc1q+Em9kyBjaQRcEQoQQNpezQu
# g9ufqExx6lHYDjCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZI
# hvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
# MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNz
# dXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVow
# YjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ
# d3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290
# IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjww
# IjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J5
# 8soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMH
# hOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6
# Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQ
# ecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4b
# A3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9
# WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCU
# tNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvo
# ZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/J
# vNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCP
# orF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMB
# Af8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXr
# oq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRt
# MGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEF
# BQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl
# ZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgw
# BgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cH
# vZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8
# UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTn
# f+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxU
# jG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8j
# LfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDCCBq4w
# ggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJKoZIhvcNAQELBQAwYjELMAkG
# A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp
# Z2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4X
# DTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAV
# BgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVk
# IEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklRVcclA8TykTepl1Gh1tKD0Z5M
# om2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54PMx9QEwsmc5Zt+FeoAn39Q7SE
# 2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupRPfDWVtTnKC3r07G1decfBmWN
# lCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvohGS0UvJ2R/dhgxndX7RUCyFo
# bjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV5huowWR0QKfAcsW6Th+xtVhN
# ef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OAe3Vu
# JyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6ic/rnH1pslPJSlRErWHRAKKtz
# Q87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++bPf4O
# uGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+OcD5
# sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oiqMEmCPkUEBIDfV8ju2TjY+Cm
# 4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZDNIz
# tM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS6
# FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qY
# rhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYB
# BQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20w
# QQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwz
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZ
# MBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAfVmO
# wJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvHUF3iSyn7cIoNqilp/GnBzx0H
# 6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXOlWk/
# R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCKrOX9jLxkJodskr2dfNBwCnzv
# qLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rAJ4JErpknG6skHibBt94q6/ae
# sXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZxhOACcS2n82HhyS7T6NJuXdm
# kfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEhQNC3
# EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1MrfvElXvtCl8zOYdBeHo46Zzh
# 3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXseGYs2uJPU5vIXmVnKcPA3v5gA
# 3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHzV9m8
# BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZVVCsf
# gPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPwwggbAMIIEqKADAgECAhAMTWly
# S5T6PCpKPSkHgD1aMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYD
# VQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBH
# NCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjIwOTIxMDAwMDAw
# WhcNMzMxMTIxMjM1OTU5WjBGMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNl
# cnQxJDAiBgNVBAMTG0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIyIC0gMjCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAM/spSY6xqnya7uNwQ2a26HoFIV0Mxom
# rNAcVR4eNm28klUMYfSdCXc9FZYIL2tkpP0GgxbXkZI4HDEClvtysZc6Va8z7GGK
# 6aYo25BjXL2JU+A6LYyHQq4mpOS7eHi5ehbhVsbAumRTuyoW51BIu4hpDIjG8b7g
# L307scpTjUCDHufLckkoHkyAHoVW54Xt8mG8qjoHffarbuVm3eJc9S/tjdRNlYRo
# 44DLannR0hCRRinrPibytIzNTLlmyLuqUDgN5YyUXRlav/V7QG5vFqianJVHhoV5
# PgxeZowaCiS+nKrSnLb3T254xCg/oxwPUAY3ugjZNaa1Htp4WB056PhMkRCWfk3h
# 3cKtpX74LRsf7CtGGKMZ9jn39cFPcS6JAxGiS7uYv/pP5Hs27wZE5FX/NurlfDHn
# 88JSxOYWe1p+pSVz28BqmSEtY+VZ9U0vkB8nt9KrFOU4ZodRCGv7U0M50GT6Vs/g
# 9ArmFG1keLuY/ZTDcyHzL8IuINeBrNPxB9ThvdldS24xlCmL5kGkZZTAWOXlLimQ
# prdhZPrZIGwYUWC6poEPCSVT8b876asHDmoHOWIZydaFfxPZjXnPYsXs4Xu5zGcT
# B5rBeO3GiMiwbjJ5xwtZg43G7vUsfHuOy2SJ8bHEuOdTXl9V0n0ZKVkDTvpd6kVz
# HIR+187i1Dp3AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/
# BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEE
# AjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8w
# HQYDVR0OBBYEFGKK3tBh/I8xFO2XC809KpQU31KcMFoGA1UdHwRTMFEwT6BNoEuG
# SWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQw
# OTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQG
# CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKG
# TGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJT
# QTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIB
# AFWqKhrzRvN4Vzcw/HXjT9aFI/H8+ZU5myXm93KKmMN31GT8Ffs2wklRLHiIY1UJ
# RjkA/GnUypsp+6M/wMkAmxMdsJiJ3HjyzXyFzVOdr2LiYWajFCpFh0qYQitQ/Bu1
# nggwCfrkLdcJiXn5CeaIzn0buGqim8FTYAnoo7id160fHLjsmEHw9g6A++T/350Q
# p+sAul9Kjxo6UrTqvwlJFTU2WZoPVNKyG39+XgmtdlSKdG3K0gVnK3br/5iyJpU4
# GYhEFOUKWaJr5yI+RCHSPxzAm+18SLLYkgyRTzxmlK9dAlPrnuKe5NMfhgFknADC
# 6Vp0dQ094XmIvxwBl8kZI4DXNlpflhaxYwzGRkA7zl011Fk+Q5oYrsPJy8P7mxNf
# arXH4PMFw1nfJ2Ir3kHJU7n/NBBn9iYymHv+XEKUgZSCnawKi8ZLFUrTmJBFYDOA
# 4CPe+AOk9kVH5c64A0JH6EE2cXet/aLol3ROLtoeHYxayB6a1cLwxiKoT5u92Bya
# UcQvmvZfpyeXupYuhVfAYOd4Vn9q78KVmksRAsiCnMkaBXy6cbVOepls9Oie1FqY
# yJ+/jbsYXEP10Cro4mLueATbvdH7WwqocH7wl4R44wgDXUcsY6glOJcB0j862uXl
# 9uab3H4szP8XTE0AotjWAQ64i+7m4HJViSwnGWH2dwGMMYIFXTCCBVkCAQEwgYYw
# cjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ
# d3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVk
# IElEIENvZGUgU2lnbmluZyBDQQIQBNXcH0jqydhSALrNmpsqpzANBglghkgBZQME
# AgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEM
# BgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqG
# SIb3DQEJBDEiBCAl18w1F24II3S+GxRvaEugjb2LZITMBZs54EbSJK+JWDANBgkq
# hkiG9w0BAQEFAASCAQCvVlAp+uHrHgfDkQ05k5YdCxX9cHEXkLj1TbFx9c81EQgY
# BtN1l5wOgUnFfCBQzTLF1NvgGfm249ecLwjbtqlOO7T8b5cilO4AU6EbpBxLOqU3
# GxMFrOjNRdsORlXLtOdAGbXWijuwF739EDQy8N1gOHVd4cOFOPG5J44a26+b2vcz
# OReLrlFxuH0hNPx2O/QJWRA5UMF4lj6rVletYRLl9WXhx3+s8Ox3L5fQ3tX5nP2l
# 3cKuMBWlLZONs42hsLjhipLJbHoqsepyUKnPBboGbVAePLKcocPRnasRwm4Yx7/w
# VbAduQJ6lG3QUFxv1xQoOf0ZXnuRwPMM08+E+8CToYIDIDCCAxwGCSqGSIb3DQEJ
# BjGCAw0wggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0
# LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hB
# MjU2IFRpbWVTdGFtcGluZyBDQQIQDE1pckuU+jwqSj0pB4A9WjANBglghkgBZQME
# AgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X
# DTIyMTIzMTE3MDg0NVowLwYJKoZIhvcNAQkEMSIEINg6k9yRYuxtmOHjCDtm3nNb
# G6LufF4RvfgXMU9IwZb8MA0GCSqGSIb3DQEBAQUABIICADb4RRcGb7E0rMJLgyUP
# 6bEqSUkghidN68X4ni8ZcUzHu+Y5SDVEzZVIvJdmp7yIoKuUn5IROY0qXMRELac/
# TL1paRREWbT3P7LLbF6ggHS2fmt7jXm7/vAK2M/4p9R6rEZ8886xsaP3stO2y6dW
# WZ+F1pNavhv5Bquh4CahtRkxHRKInZ08bxHzMqQY+SfT8OSo/05wZdIO/S+EgQAl
# TUa4vm9DEzdMQbyFAb4AZjbCddHA9INkYYN3wTu+sS2ttUZ9wOeSdKboEQjMptBu
# 7ZpUuu/ecpNVVYcyfKF7w3eLu0f7i/BocQyCaKALVpMRbVraaWBUJVTAXvDihVOF
# EilcjYhNg2MnjVxRGvnca0u1MHbOfm1D6tUGhaINz4oUSVPEbRl3DvD72hBfb5ny
# esfrHW2Z4+r++zKoNGSjchzuu2Ss8jlYFSTgq0oLXqGQFH5q0rRFgGPX/ukFu4Ma
# Zs24jenyZOl4t2ex7Mr5686uB/tIoEdcqSKS0km6R/WeZM44o7D+E8ushabvCFkX
# +P5sAwBRTbXi/xnMSOBhDNhAk+Z+sdfHZLUBTDnsdeX3WRcAaHm5GBYvtIcYPLOs
# Ib+R0cMIoO+i+mnZMxuRwt6F4c6uLH1PtwKvk9Z2xy03ni2F+GiEys2eiuczK5Z5
# ZZ5ieS4IacehlDmfazmmz2Tg
# SIG # End signature block