HP.Sinks.psm1

#
# Copyright 2018-2021 HP Development Company, L.P.
# All Rights Reserved.
#
# NOTICE: All information contained herein is, and remains the property of HP Development Company, L.P.
#
# The intellectual and technical concepts contained herein are proprietary to HP Development Company, L.P
# and may be covered by U.S. and Foreign Patents, patents in process, and are protected by
# trade secret or copyright law. Dissemination of this information or reproduction of this material
# is strictly forbidden unless prior written permission is obtained from HP Development Company, L.P.


Add-Type -TypeDefinition @"
        public enum syslog_facility_t
        {
                kernel_message = 0,
                user_message = 1,
                mail_system = 2,
                system_daemon =3,
                auth = 4,
                syslog_internal = 5,
                lpr = 6,
                news = 7,
                uucp = 8,
                clock = 9,
                secauth = 10,
                ftp = 11,
                ntp = 12,
                log_audit = 13,
                log_alert = 14,
                cron = 15,
                local0 = 16,
                local1 = 17,
                local2 = 18,
                local3 = 19,
                local4 = 20,
                local5 = 21,
                local6 = 22,
                local7 = 23
        }
 
        public enum syslog_severity_t
        {
                emergency = 0,
                alert = 1,
                critical = 2,
                error = 3,
                warning = 4,
                notice = 5,
                informational = 6,
                debug = 7
        }
 
        public enum eventlog_severity_t {
                error = 0x01,
                warning = 0x02,
                informational = 0x04,
                success_audit = 0x08,
                failure_audit = 0x10
            }
"@



enum LogType{
  Simple
  CMTrace
}

enum LogSeverity{
  Information = 1
  Warning = 2
  Error = 3
}

function Get-HPPrivateThreadID { [Threading.Thread]::CurrentThread.ManagedThreadId }
function Get-HPPrivateUserIdentity { [System.Security.Principal.WindowsIdentity]::GetCurrent().Name }
function Get-HPPrivateLogVar { $Env:HPCMSL_LOG_FORMAT }

<#
.SYNOPSIS
    Send a message to a syslog server
 
.DESCRIPTION
    Use this function to forward data to a syslog server. Currently supports UDP (default) and TCP connections. For more information see RFC 5424 in the "See also" section.
 
    The function currently supports UDP and TCP transports.
 
 
.PARAMETER message
    The message to send
 
.PARAMETER severity
    The severity of the message. IF not specified, it defaults to "informational".
 
.PARAMETER facility
    The facility of the mesage. If not specified, it default to "user message"
 
.PARAMETER clientname
    The client name. If not specified, it uses the current computer name.
 
.PARAMETER timestamp
    The event time stamp. If not specified, it uses the current time.
 
.PARAMETER port
    The target port. If not specified, and HPSINK_SYSLOG_MESSAGE_TARGET_PORT is not set, it uses port 514 for both TCP and UDP.
 
.PARAMETER tcp
    Use TCP instead of UDP. Default is UDP which is unacknowledged. Switching to TCP may generate additional traffic, but
    allows the protocol to acknowledge delivery.
 
.PARAMETER tcpframing
    Choose between octet-counting and non-transparent-framing TCP framing. Only applies if -tcp is specified. Default is octet-counting, unless
    HPSINK_SYSLOG_MESSAGE_TCPFRAMING is specified. For more information see RFC 6587 in the "See also" section.
     
 
.PARAMETER maxlen
    Specify maximum length of message that the syslog server accepts. Common sizes are between 480 and 2048 bytes. Default is 2048 if not specified and
    HPSINK_SYSLOG_MESSAGE_MAXLEN is not set.
 
 
.PARAMETER target
    The computer on which to perform this operation. Local computer is assumed if not specified and HPSINK_SYSLOG_MESSAGE_TARGET is not set.
 
.PARAMETER PassThru
    Send the message to the pipeline upon completion. When passthru is set, an error in the function is non-terminating.
 
 
.NOTES
 
    This function supports the following environment variables. These overwrite the defaults documented above.
 
    * HPSINK_SYSLOG_MESSAGE_TARGET_PORT - override default target port
    * HPSINK_SYSLOG_MESSAGE_TCPFRAMING - override TCP Framing format
    * HPSINK_SYSLOG_MESSAGE_MAXLEN - override syslog message max length
    * HPSINK_SYSLOG_MESSAGE_TARGET - override host name of the syslog server
 
 
    Defaults can be configured via the environment. This affects all related commands. For example, when applying them to
    event-log related functions, all eventlog-related functions are affected.
 
    In the following example, the HPSINK_EVENTLOG_MESSAGE_TARGET and HPSINK_EVENTLOG_MESSAGE_SOURCE variables affect
    both the Register-EventLogSink and Send-ToEventLog functions.
 
    ```PowerShell
    $ENV:HPSINK_EVENTLOG_MESSAGE_TARGET="remotesyslog.mycompany.com"
    $ENV:HPSINK_EVENTLOG_MESSAGE_SOURCE="mysource"
    Register-EventLogSink
    "hello" | Send-ToEventLog
    ```
 
 
.INPUTS
    The message can be piped to this command, rather than provided via the -message parameter.
 
.OUTPUTS
    If -passthru is specified, the original message is returned. This allows chaining multiple SendTo-XXX commands.
 
.EXAMPLE
   "hello" | Send-ToSyslog -tcp -server mysyslogserver.mycompany.com
     
   This sends "hello" to the syslog server on mysyslogserver.mycompany.com via TCP. Alternately, the syslog server could be set in the environment variable HPSINK_SYSLOG_MESSAGE_TARGET.
 
.LINK
    [RFC 5424 - "The Syslog Protocol"](https://tools.ietf.org/html/rfc5424)
 
.LINK
    [RFC 6587 - "Transmission of Syslog Messages over TCP"](https://tools.ietf.org/html/rfc6587)
 
.LINK
    [Send-ToEventlog](Send-ToEventLog)
 
 
#>

function Send-ToSyslog
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Send%E2%80%90ToSyslog")]
  param
  (
    [ValidateNotNullOrEmpty()][Parameter(Position = 0,ValueFromPipeline = $True,Mandatory = $True)] $message,
    [Parameter(Position = 1,Mandatory = $false)] [syslog_severity_t]$severity = [syslog_severity_t]::informational,
    [Parameter(Position = 2,Mandatory = $false)] [syslog_facility_t]$facility = [syslog_facility_t]::user_message,
    [Parameter(Position = 3,Mandatory = $false)] [string]$clientname,
    [Parameter(Position = 4,Mandatory = $false)] [string]$timestamp,
    [Parameter(Position = 5,Mandatory = $false)] [int]$port = $HPSINK:HPSINK_SYSLOG_MESSAGE_TARGET_PORT,
    [Parameter(Position = 6,Mandatory = $false)] [switch]$tcp,
    [ValidateSet("octet-counting","non-transparent-framing")][Parameter(Position = 7,Mandatory = $false)] [string]$tcpframing = $ENV:HPSINK_SYSLOG_MESSAGE_TCPFRAMING,
    [Parameter(Position = 8,Mandatory = $false)] [int]$maxlen = $ENV:HPSINK_SYSLOG_MESSAGE_MAXLEN,
    [Parameter(Position = 9,Mandatory = $false)] [switch]$PassThru,
    [Parameter(Position = 10,Mandatory = $false)] [string]$target = $ENV:HPSINK_SYSLOG_MESSAGE_TARGET
  )

  # Create a UDP Client Object
  $tcpclient = $null
  $use_tcp = $false


  #defaults (change these in environment)
  if ($target -eq $null -or $target -eq "") { throw "parameter $target is required" }
  if ($tcpframing -eq $null -or $tcpframing -eq "") { $tcpframing = "octet-counting" }
  if ($port -eq 0) { $port = 514 }
  if ($maxlen -eq 0) { $maxlen = 2048 }


  if ($tcp.IsPresent -eq $false) {
    switch ([int]$ENV:HPSINK_SYSLOG_MESSAGE_USE_TCP) {
      0 { $use_tcp = $false }
      1 { $use_tcp = $true }
    }
  }
  else { $use_tcp = $tcp.IsPresent }


  Write-Verbose "Sending message to syslog server"
  if ($use_tcp) {
    Write-Verbose "TCP Connection to $target`:$port"
    $client = New-Object System.Net.Sockets.TcpClient
  }
  else
  {
    Write-Verbose "UDP Connection to $target`:$port"
    $client = New-Object System.Net.Sockets.UdpClient
  }

  try {
    $client.Connect($target,$port)
  }
  catch {
    if ($_.Exception.InnerException -ne $null) {
      Write-Error $_.Exception.InnerException.Message -Category ConnectionError -ErrorAction Stop
    } else {
      Write-Error $_.Exception.Message -Category ConnectionError -ErrorAction Stop
    }
  }

  if ($use_tcp -and -not $client.Connected)
  {
    $prefix = "udp"
    if ($use_tcp) { $prefix = $tcp }
    throw "Could not connect to syslog host $prefix`://$target`:$port"
  }


  Write-Verbose "Syslog faciliy=$($facility.value__), severity=$($severity.value__)"

  $priority = ($facility.value__ * 8) + $severity.value__
  Write-Verbose "Priority is $priority"

  if (($clientname -eq "") -or ($clientname -eq $null)) {
    Write-Verbose "Defaulting to client = $($ENV:computername)"
    $clientname = $env:computername
  }

  if (($timestamp -eq "") -or ($timestamp -eq $null)) {
    $timestamp = Get-Date -Format "yyyy:MM:dd:-HH:mm:ss zzz"
    Write-Verbose "Defaulting to timestamp = $timestamp"
  }

  $msg = "<{0}>{1} {2} {3}" -f $priority,$timestamp,$hostname,$message

  Write-Verbose ("Sending the message: $msg")
  if ($use_tcp) {
    Write-Verbose ("Sending via TCP")


    if ($msg.length -gt $maxlen) {
      $maxlen = $maxlen - ([string]$maxlen).length
      Write-Verbose ("This message has been truncated, because maximum effective length is $maxlen but the message is $($msg.length) ")
      $msg = $msg.Substring(0,$maxlen - ([string]$maxlen).length)
    }

    switch ($tcpframing) {
      "octet-counting" {
        Write-Verbose "Encoding TCP payload with 'octet-counting'"
        $encoded = '{0} {1}' -f $msg.length,$msg
        $bytes = [System.Text.Encoding]::ASCII.GetBytes($encoded)
      }

      "non-transparent-framing" {
        Write-Verbose "Encoding with 'non-transparent-framing'"
        $encoded = '{0}{1}' -f $msg.length,$msg
        $bytes = [System.Text.Encoding]::ASCII.GetBytes($encoded)
      }
    }

    try {
      [void]$client.getStream().Write($bytes,0,$bytes.length)
    }
    catch {
      throw ("Could not send syslog message: $($_.Exception.Message)")
    }
  }
  else
  {

    Write-Verbose ("Sending via UDP")
    try {
      $bytes = [System.Text.Encoding]::ASCII.GetBytes($msg)
      if ($bytes.length -gt $maxlen) {
        Write-Verbose ("This message has been truncated, because maximum length is $maxlen but the message is $($bytes.length) ")
        $bytes = $bytes[0..($maxlen - 1)]
      }
      [void]$client.Send($bytes,$bytes.length)
    }
    catch {
      if (-not $PassThru.IsPresent) {
        throw ("Could not send syslog message: $($_.Exception.Message)")
      }
      else
      {
        Write-Error -Message $_.Exception.Message -ErrorAction Continue
      }

    }
  }

  Write-Verbose "Send complete"
  $client.Close();
  if ($PassThru) { return $message }
}


<#
.SYNOPSIS
  Register a source in event log
 
.DESCRIPTION
   THis is required before sending messages to the event log, via "Send-ToEventLog".
    The source must match the source in Send-ToEventLog. My default, it is assumed that the source is "HP-CSL".
 
    This operation can be undone by Unregister-EventLogSink.
 
.PARAMETER logname
    The log section in which to register this source
 
.PARAMETER source
    The event log source that will be used when logging.
 
    The source can also be specified via the HPSINK_EVENTLOG_MESSAGE_SOURCE environment variable.
 
.PARAMETER target
    The computer on which to perform this operation. Local computer is assumed if not specified, unless environment variable
    HPSINK_EVENTLOG_MESSAGE_TARGET is defined.
 
    Important: the user identity running the PowerShell script must have permissions to write to the remote event log.
 
.NOTES
    This function reads the following environment variables for setting defaults:
 
    - HPSINK_EVENTLOG_MESSAGE_SOURCE - override default source name
    - HPSINK_EVENTLOG_MESSAGE_LOG - override default message log name
    - HPSINK_EVENTLOG_MESSAGE_TARGET - override event log server name
 
.LINK
    [Unregister-EventLogSink](Unregister-EventLogSink)
 
.LINK
    [Send-ToEventLog](Send-ToEventLog)
#>

function Register-EventLogSink
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Register%E2%80%90EventLogSink")]
  param
  (
    [Parameter(Position = 0,Mandatory = $false)] [string]$logname = $ENV:HPSINK_EVENTLOG_MESSAGE_LOG,
    [Parameter(Position = 1,Mandatory = $false)] [string]$source = $ENV:HPSINK_EVENTLOG_MESSAGE_SOURCE,
    [Parameter(Position = 2,Mandatory = $false)] [string]$target = $ENV:HPSINK_EVENTLOG_MESSAGE_TARGET
  )


  #defaults (change these in environment)
  if ($source -eq $null -or $source -eq "") { $source = "HP-CSL" }
  if ($logname -eq $null -or $logname -eq "") { $logname = "Application" }
  if ($target -eq $null -or $target -eq "") { $target = "." }


  Write-Verbose "Registering source $logname / $source"
  $params = @{
    LogName = $logname
    Source = $source
  }

  if ($target -ne ".") { $params.Add("ComputerName",$target) }
  New-EventLog @params
}

<#
.SYNOPSIS
   Unregisters a source registered by Register-EventLogSink
 
.DESCRIPTION
    This function removes a registration that was previously done by Register-EventLogSink.
 
Note:
Switching between formats changes the file encoding. The "Simple" mode uses unicode encoding (UTF-16) while the "CMTrace" mode uses UTF-8. This is partly due to historical reasons
(default encoding in UTF1-16 and existing log is UTF-16) and partly due to limitations in CMTrace tool, which seems to have trouble with UTF-16 in some cases.
 
Therefore it is important to start with a new log when switching modes. Writing UTF-8 to UTF-16 files or vice versa will cause encoding and display issues.
 
.PARAMETER source
    The event log source that was registered via Register-EventLogSink
 
    The source can also be specified via the HPSINK_EVENTLOG_MESSAGE_SOURCE environment variable.
 
.PARAMETER target
    The computer on which to perform this operation. Local computer is assumed if not specified, unless environment variable
    HPSINK_EVENTLOG_MESSAGE_TARGET is defined.
 
    Important: the user identity running the PowerShell script must have permissions to write to the remote event log.
 
.NOTES
    This function reads the following environment variables for setting defaults:
 
    - HPSINK_EVENTLOG_MESSAGE_SOURCE - override default source name
    - HPSINK_EVENTLOG_MESSAGE_TARGET - override event log server name
 
.LINK
    [Register-EventLogSink](Register-EventLogSink)
 
.LINK
    [Send-ToEventLog](Send-ToEventLog)
 
#>

function Unregister-EventLogSink
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Unregister%E2%80%90EventLogSink")]
  param
  (
    [Parameter(Position = 0,Mandatory = $false)] [string]$source = $ENV:HPSINK_EVENTLOG_MESSAGE_SOURCE,
    [Parameter(Position = 1,Mandatory = $false)] [string]$target = $ENV:HPSINK_EVENTLOG_MESSAGE_TARGET
  )

  #defaults (change these in environment)
  if ($source -eq $null -or $source -eq "") { $source = "HP-CSL" }
  if ($target -eq $null -or $target -eq "") { $target = "." }


  Write-Verbose "Unregistering source $source"
  $params = @{
    Source = $source
  }

  if ($target -ne ".") { $params.Add("ComputerName",$target) }
  Remove-EventLog @params

}

<#
.SYNOPSIS
    Send a message to event log.
 
.DESCRIPTION
    This message creates a Windows Event Log entry.
 
    Normally the source will need to be initialized with Register-EventLogSink to register
    the source name.
 
.PARAMETER id
    The "event id" that will be registered under the "Event ID" column in the event log. By default, this is 0.
 
.PARAMETER source
    The event log source that will be used when logging. This source should've been previously registered, potentially
    by using Register-EventLogSink.
 
    The source can also be specified via the HPSINK_EVENTLOG_MESSAGE_SOURCE environment variable.
 
.PARAMETER message
    The message to log. This parameter is required.
 
.PARAMETER severity
    The message severity. If not specified, the severity is Information.
 
.PARAMETER category
    The message category, which shows up under the "Task Category" column. If not specified, it is "General", unless
    environment variable HPSINK_EVENTLOG_MESSAGE_CATEGORY is defined.
 
.PARAMETER logname
    The log in which to log (e.g. Application, System, etc). If not specified, it will log to Application, unless
    environment variable HPSINK_EVENTLOG_MESSAGE_LOG is defined.
 
.PARAMETER rawdata
    Any raw data to add to the log entry.
 
.PARAMETER target
    The computer on which to perform this operation. Local computer is assumed if not specified, unless environment variable
    HPSINK_EVENTLOG_MESSAGE_TARGET is defined.
 
    Important: the user identity running the PowerShell script must have permissions to write to the remote event log.
 
.PARAMETER PassThru
    Send the message to the pipeline upon completion. When passthru is set, an error in the function is non-terminating.
 
.EXAMPLE
    "hello" | Send-ToEventLog
 
.NOTES
    This function reads the following environment variables for setting defaults.
 
    - HPSINK_EVENTLOG_MESSAGE_SOURCE - override default source name
    - HPSINK_EVENTLOG_MESSAGE_CATEGORY - override default category id
    - HPSINK_EVENTLOG_MESSAGE_LOG - override default message log name
    - HPSINK_EVENTLOG_MESSAGE_TARGET - override event log server name
 
    Defaults can be configured via the environment. This affects all related commands. For example, when applying them to
    event-log related functions, all eventlog-related functions are affected.
 
    In the following example, the HPSINK_EVENTLOG_MESSAGE_TARGET and HPSINK_EVENTLOG_MESSAGE_SOURCE variables affect
    both the Register-EventLogSink and Send-ToEventLog functions.
 
    ```PowerShell
    $ENV:HPSINK_EVENTLOG_MESSAGE_TARGET="remotesyslog.mycompany.com"
    $ENV:HPSINK_EVENTLOG_MESSAGE_SOURCE="mysource"
    Register-EventLogSink
    "hello" | Send-ToEventLog
    ```
 
 
.LINK
    [Unregister-EventLogSink](Unregister-EventLogSink)
 
.LINK
    [Register-EventLogSink](Register-EventLogSink)
 
.LINK
    [Send-ToSyslog](Send-ToSyslog.md)
 
 
#>

function Send-ToEventLog
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Send%E2%80%90ToEventlog")]
  param
  (

    [Parameter(Position = 0,Mandatory = $false)] [string]$source = $ENV:HPSINK_EVENTLOG_MESSAGE_SOURCE,
    [Parameter(Position = 1,Mandatory = $false)] [int]$id = 0,
    [ValidateNotNullOrEmpty()][Parameter(Position = 2,ValueFromPipeline = $true,Mandatory = $True)] $message,
    [Parameter(Position = 3,Mandatory = $false)] [eventlog_severity_t]$severity = [eventlog_severity_t]::informational,
    [Parameter(Position = 4,Mandatory = $false)] [int16]$category = $ENV:HPSINK_EVENTLOG_MESSAGE_CATEGORY,
    [Parameter(Position = 5,Mandatory = $false)] [string]$logname = $ENV:HPSINK_EVENTLOG_MESSAGE_LOG,
    [Parameter(Position = 6,Mandatory = $false)] [byte[]]$rawdata = $null,
    [Parameter(Position = 7,Mandatory = $false)] [string]$target = $ENV:HPSINK_EVENTLOG_MESSAGE_TARGET,
    [Parameter(Position = 8,Mandatory = $false)] [switch]$PassThru
  )

  #defaults (change these in environment)
  if ($source -eq $null -or $source -eq "") { $source = "HP-CSL" }
  if ($logname -eq $null -or $logname -eq "") { $logname = "Application" }
  if ($target -eq $null -or $target -eq "") { $target = "." }

  Write-Verbose "Sending message (category=$category, id=$id) to eventlog $logname with source $source"
  $params = @{
    EntryType = $severity.value__
    Category = $category
    Message = $message
    LogName = $logname
    Source = $source
    EventId = $id
  }


  if ($target -ne ".") {
    $params.Add("ComputerName",$target)
    Write-Verbose ("The target machine is remote ($target)")
  }

  if ($rawdata -ne $null) { $params.Add("RawData",$rawdata) }

  try {
    Write-EventLog @params
  }
  catch {
    if (-not $PassThru.IsPresent) {
      throw ("Could not send eventlog message: $($_.Exception.Message)")
    }
    else
    {
      Write-Error -Message $_.Exception.Message -ErrorAction Continue
    }
  }
  if ($PassThru) { return $message }
}




<#
.SYNOPSIS
   Write a "simple" LOG entry
   Private function. Do not export
#>

function Write-HPPrivateSimple {

  [CmdletBinding()]
  param
  (
    [Parameter(Mandatory = $True,Position = 0)]
    [LogSeverity]$Severity,
    [Parameter(Mandatory = $True,Position = 1)]
    [string]$Message,
    [Parameter(Mandatory = $True,Position = 2)]
    [string]$Component,
    [Parameter(Mandatory = $False,Position = 3)]
    [string]$File = $Null
  )
  $prefix = switch ($severity) {
    Error   { " [ERROR] " }
    Warning { " [WARN ] " }
    default { "" }
  }
 
  if ($File) {
    if (-not [System.IO.Directory]::Exists([System.IO.Path]::GetDirectoryName($File)))
    {
      throw [System.IO.DirectoryNotFoundException]"Path not found: $([System.IO.Path]::GetDirectoryName($File))"
    }
  }

  $context=Get-HPPrivateUserIdentity

  $line = "[$(Get-Date -Format o)] $Context - $Prefix $Message"
  if ($File) {
    $line | Out-File -Width 1024 -Append -Encoding unicode -FilePath $File
  }
  else {
    $line
  }

}

<#
.SYNOPSIS
   Write a "CMTrace" LOG entry
   Private function. Do not export
#>

function Write-HPPrivateCMTrace {
  [CmdletBinding()]
  param
  (
    [Parameter(Mandatory = $True,Position = 0)]
    [LogSeverity]$Severity,
    [Parameter(Mandatory = $True,Position = 1)]
    [string]$Message,
    [Parameter(Mandatory = $True,Position = 2)]
    [string]$Component,
    [Parameter(Mandatory = $False,Position = 3)]
    [string]$File

  )

  $line = "<![LOG[$Message]LOG]!>" + `
     "<time=`"$(Get-Date -Format "HH:mm:ss.ffffff")`" " + `
     "date=`"$(Get-Date -Format "M-d-yyyy")`" " + `
     "component=`"$Component`" " + `
     "context=`"$(Get-HPPrivateUserIdentity)`" " + `
     "type=`"$([int]$Severity)`" " + `
     "thread=`"$(Get-HPPrivateThreadID)`" " + `
     "file=`"`">"

  if ($File) {
    if (-not [System.IO.Directory]::Exists([System.IO.Path]::GetDirectoryName($File)))
    {
      throw [System.IO.DirectoryNotFoundException]"Path not found: $([System.IO.Path]::GetDirectoryName($File))"
    }
  }

  if ($File) {
    $line | Out-File -Append -Encoding UTF8 -FilePath $File -Width 1024
  }
  else {
    $line
  }

}




<#
.SYNOPSIS
    Set the format used by the Write-Log* functions
     
.DESCRIPTION
    This function changes the log format between simple (human readable) format, and CMtrace format used by configuration
    manager.
 
    The format is stored in the HPCMSL_LOG_FORMAT environment variable. To set the default format without using the function, update
    the variable by setting it to either "Simple" or "CMTrace" ahead of time.
 
    The default format is 'Simple'
 
    | Important: Switching to
.PARAMETER Format
    Select between 'Simple' (human readable) and 'CMTrace' (XML format used by the CMTrace tool)
 
.EXAMPLE
    Set-HPCMSLLogFormat -Format CMTrace
 
.LINK
    [Write-LogInfo](Write-LogInfo)
.LINK
    [Write-LogWarning](Write-LogWarning)
.LINK
    [Write-LogError](Write-LogError)
.LINK
    [Get-HPCMSLLogFormat](Get-HPCMSLLogFormat)
 
#>

function Set-HPCMSLLogFormat
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Set%E2%80%90HPCMSLLogFormat")]
  param(
    [Parameter(Mandatory = $True,Position = 0)]
    [LogType]$Format
  )
  $Env:HPCMSL_LOG_FORMAT = $Format
  $Global:CmslLog = $Global:CmslLogType

  Write-Debug "Set log type to $($Global:CmslLog)"
}

<#
.SYNOPSIS
    Get the format used by the log functions
     
.DESCRIPTION
    This function returns the configured log format used by the Write-Log* functions. The function returns the value of the HPCMSL_LOG_FORMAT environment variable, or
    'Simple' if the variable is not configured.
 
.PARAMETER Format
    Select between 'Simple' (human readable) and 'CMTrace' (XML format used by the CMTrace tool)
 
.EXAMPLE
    Get-HPCMSLLogFormat -Format CMTrace
 
.LINK
    [Write-LogInfo](Write-LogInfo)
.LINK
    [Write-LogWarning](Write-LogWarning)
.LINK
    [Write-LogError](Write-LogError)
.LINK
    [Set-HPCMSLLogFormat](Set-HPCMSLLogFormat)
 
#>

function Get-HPCMSLLogFormat
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPCMSLLogFormat")]
  param()

  if (-not $Global::CmslLog)
  {
    $Global:CmslLog = Get-HPPrivateLogVar
  }

  if (-not $Global:CmslLog)
  {
    $Global:CmslLog = 'Simple'
  }

  Write-Verbose "Configured log type is $($Global:CmslLog)"

  switch ($Global:CmslLog)
  {
    'CMTrace' { 'CMTrace' }
    Default { 'Simple' }
  }

}


<#
.SYNOPSIS
    Write a "warning" log entry
     
.DESCRIPTION
    Writes a log entry to default output or a specified file.
 
.PARAMETER Message
    The message to write
 
.PARAMETER Component
    A 'Component' tag for the message entry, used by some log readers to group messages. If not specified, the component tag is 'General'.
    This parameter is ignored in 'Simple' mode, due to backwards compatibility reasons.
 
.PARAMETER File
    The file to update with the new log entry. If not specified, the log entry is written to the pipeline.
 
.EXAMPLE
    Write-LogWarning -Component "Repository" -Message "Something bad may have happened" -File myfile.log
 
.LINK
    [Write-LogInfo](Write-LogInfo)
.LINK
    [Write-LogError](Write-LogError)
.LINK
    [Get-HPCMSLLogFormat](Get-HPCMSLLogFormat)
.LINK
    [Set-HPCMSLLogFormat](Set-HPCMSLLogFormat)
 
#>

function Write-LogWarning
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Write%E2%80%90LogWarning")]
  param(
    [Parameter(Mandatory = $True,Position = 0)]
    [string]$Message,
    [Parameter(Mandatory = $False,Position = 1)]
    [string]$Component = "General",
    [Parameter(Mandatory = $False,Position = 2)]
    [string]$File
  )
  if ($File) {
    $file =  $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($file)
  }
  switch (Get-HPCMSLLogFormat)
  {
    CMTrace {
      Write-HPPrivateCMTrace -severity Warning -Message $Message -Component $Component -File $File
    }
    default {
      Write-HPPrivateSimple -severity Warning -Message $Message -Component $Component -File $file
    }
  }


}


<#
.SYNOPSIS
    Write an "error" log entry
     
.DESCRIPTION
    Writes a log entry to default output or a specified file.
 
.PARAMETER Message
    The message to write
 
.PARAMETER Component
    A 'Component' tag for the message entry, used by some log readers to group messages. If not specified, the component tag is 'General'
    This parameter is ignored in 'Simple' mode, due to backwards compatibility reasons.
 
.PARAMETER File
    The file to update with the new log entry. If not specified, the log entry is written to pipeline.
 
.EXAMPLE
    Write-LogError -Component "Repository" -Message "Something bad happened" -File myfile.log
 
.LINK
    [Write-LogInfo](Write-LogInfo)
.LINK
    [Write-LogWarning](Write-LogWarning)
.LINK
    [Get-HPCMSLLogFormat](Get-HPCMSLLogFormat)
.LINK
    [Set-HPCMSLLogFormat](Set-HPCMSLLogFormat)
     
#>

function Write-LogError
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Write%E2%80%90LogError")]
  param(
    [Parameter(Mandatory = $True,Position = 0)]
    [string]$Message,
    [Parameter(Mandatory = $False,Position = 1)]
    [string]$Component = "General",
    [Parameter(Mandatory = $False,Position = 2)]
    [string]$File
  )

  if ($File) {
    $file =  $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($file)
  }
  switch (Get-HPCMSLLogFormat)
  {
    CMTrace {
      Write-HPPrivateCMTrace -severity Error -Message $Message -Component $Component -File $file
    }
    default {
      Write-HPPrivateSimple -severity Error -Message $Message -Component $Component -File $file
    }
  }

}

<#
.SYNOPSIS
    Write an "informational" log entry
     
.DESCRIPTION
    Writes a log entry to default output or a specified file.
 
.PARAMETER Message
    The message to write
 
.PARAMETER Component
    A 'Component' tag for the message entry, used by some log readers to group messages. If not specified, the component tag is 'General'
    This parameter is ignored in 'Simple' mode, due to backwards compatibility reasons.
 
.PARAMETER File
    The file to update with the new log entry. If not specified, the log entry is written to pipeline.
 
.EXAMPLE
    Write-LogInfo -Component "Repository" -Message "Nothing bad happened" -File myfile.log
#>

function Write-LogInfo
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Write%E2%80%90LogInfo")]
  param(
    [Parameter(Mandatory = $True,Position = 0)]
    [string]$Message,
    [Parameter(Mandatory = $False,Position = 1)]
    [string]$Component = "General",
    [Parameter(Mandatory = $False,Position = 2)]
    [string]$File
  )
  if ($File) {
    $file =  $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($file)
  }

  switch (Get-HPCMSLLogFormat)
  {
    CMTrace {
      Write-HPPrivateCMTrace -severity Information -Message $Message -Component $Component -File $file
    }
    default {
      Write-HPPrivateSimple -severity Information -Message $Message -Component $Component -File $file
    }
  }

}

# SIG # Begin signature block
# MIIakgYJKoZIhvcNAQcCoIIagzCCGn8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCC0h/5rapl9D4bu
# sMbZ8iCHnJryGyqRexEHE9d7sFQCZ6CCCm8wggUwMIIEGKADAgECAhAECRgbX9W7
# ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBa
# Fw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lD
# ZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3
# DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/l
# qJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fT
# eyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqH
# CN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+
# bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLo
# LFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIB
# yTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK
# BggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
# Y3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHow
# eDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl
# ZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwA
# AgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAK
# BghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0j
# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7s
# DVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGS
# dQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6
# r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo
# +MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qz
# sIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHq
# aGxEMrJmoecYpJpkUe8wggU3MIIEH6ADAgECAhAFUi3UAAgCGeslOwtVg52XMA0G
# CSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0
# IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcNMjEwMzIyMDAwMDAw
# WhcNMjIwMzMwMjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv
# cm5pYTESMBAGA1UEBxMJUGFsbyBBbHRvMRAwDgYDVQQKEwdIUCBJbmMuMRkwFwYD
# VQQLExBIUCBDeWJlcnNlY3VyaXR5MRAwDgYDVQQDEwdIUCBJbmMuMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtJ+rYUkseHcrB2M/GyomCEyKn9tCyfb+
# pByq/Jyf5kd3BGh+/ULRY7eWmR2cjXHa3qBAEHQQ1R7sX85kZ5sl2ukINGZv5jEM
# 04ERNfPoO9+pDndLWnaGYxxZP9Y+Icla09VqE/jfunhpLYMgb2CuTJkY2tT2isWM
# EMrKtKPKR5v6sfhsW6WOTtZZK+7dQ9aVrDqaIu+wQm/v4hjBYtqgrXT4cNZSPfcj
# 8W/d7lFgF/UvUnZaLU5Z/+lYbPf+449tx+raR6GD1WJBAzHcOpV6tDOI5tQcwHTo
# jJklvqBkPbL+XuS04IUK/Zqgh32YZvDnDohg0AEGilrKNiMes5wuAQIDAQABo4IB
# xDCCAcAwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYE
# FD4tECf7wE2l8kA6HTvOgkbo33MvMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
# BggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2Vy
# dC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQu
# ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwSwYDVR0gBEQwQjA2
# BglghkgBhv1sAwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5j
# b20vQ1BTMAgGBmeBDAEEATCBhAYIKwYBBQUHAQEEeDB2MCQGCCsGAQUFBzABhhho
# dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTgYIKwYBBQUHMAKGQmh0dHA6Ly9jYWNl
# cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURDb2RlU2lnbmlu
# Z0NBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQBZca1CZfgn
# DucOwEDZk0RXqb8ECXukFiih/rPQ+T5Xvl3bZppGgPnyMyQXXC0fb94p1socJzJZ
# fn7rEQ4tHxL1vpBvCepB3Jq+i3A8nnJFHSjY7aujglIphfGND97U8OUJKt2jwnni
# EgsWZnFHRI9alEvfGEFyFrAuSo+uBz5oyZeOAF0lRqaRht6MtGTma4AEgq6Mk/iP
# LYIIZ5hXmsGYWtIPyM8Yjf//kLNPRn2WeUFROlboU6EH4ZC0rLTMbSK5DV+xL/e8
# cRfWL76gd/qj7OzyJR7EsRPg92RQUC4RJhCrQqFFnmI/K84lPyHRgoctAMb8ie/4
# X6KaoyX0Z93PMYIPeTCCD3UCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoT
# DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UE
# AxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQBVIt
# 1AAIAhnrJTsLVYOdlzANBglghkgBZQMEAgEFAKB8MBAGCisGAQQBgjcCAQwxAjAA
# MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgor
# BgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCCtMwdfkQkbxmTEwUKEHky+dATAynpH
# xYNn6XtqmX1BcTANBgkqhkiG9w0BAQEFAASCAQApHnt2hyW89OOj9DBJ3R8GV/mI
# lVf1VCG0UYZwZkm7yBM0zGQ/VOtc7sb6lGMWiceSeCqxuKBbTBLjUcaPQsompfy9
# qNhB1X86WyYP9rvj8opKFDiuDgvVgYreSD6fPGfvAJX8HnhBh6StTjKLENneuOdo
# Hj/tJh556ISSi5nCcl98V3gPD0bohfQfPNhJ90l2U4xrar1A5ckDeJPgNbqryKyd
# zYseORWUMCLJhQw3jdxhZtaIlWa8IjVa28BXHgFfJLtJGVy/NisI0XRDeYzhgCtV
# OgKrrIcLnO9RIpUdDAQo7iRHMHU7WHoQ2PDA9Qj5PUqhGddkA9sygpnxB86ooYIN
# RTCCDUEGCisGAQQBgjcDAwExgg0xMIINLQYJKoZIhvcNAQcCoIINHjCCDRoCAQMx
# DzANBglghkgBZQMEAgEFADB4BgsqhkiG9w0BCRABBKBpBGcwZQIBAQYJYIZIAYb9
# bAcBMDEwDQYJYIZIAWUDBAIBBQAEIBjI9+8jvimD8b1nqll8JWpLQBsfUQyc17Rd
# 9g4NBme6AhEAynBPa81bYkwX/7P+ziqSEBgPMjAyMTA0MTkxNzA0MzVaoIIKNzCC
# BP4wggPmoAMCAQICEA1CSuC+Ooj/YEAhzhQA8N0wDQYJKoZIhvcNAQELBQAwcjEL
# MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
# LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElE
# IFRpbWVzdGFtcGluZyBDQTAeFw0yMTAxMDEwMDAwMDBaFw0zMTAxMDYwMDAwMDBa
# MEgxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEgMB4GA1UE
# AxMXRGlnaUNlcnQgVGltZXN0YW1wIDIwMjEwggEiMA0GCSqGSIb3DQEBAQUAA4IB
# DwAwggEKAoIBAQDC5mGEZ8WK9Q0IpEXKY2tR1zoRQr0KdXVNlLQMULUmEP4dyG+R
# awyW5xpcSO9E5b+bYc0VkWJauP9nC5xj/TZqgfop+N0rcIXeAhjzeG28ffnHbQk9
# vmp2h+mKvfiEXR52yeTGdnY6U9HR01o2j8aj4S8bOrdh1nPsTm0zinxdRS1LsVDm
# QTo3VobckyON91Al6GTm3dOPL1e1hyDrDo4s1SPa9E14RuMDgzEpSlwMMYpKjIjF
# 9zBa+RSvFV9sQ0kJ/SYjU/aNY+gaq1uxHTDCm2mCtNv8VlS8H6GHq756WwogL0sJ
# yZWnjbL61mOLTqVyHO6fegFz+BnW/g1JhL0BAgMBAAGjggG4MIIBtDAOBgNVHQ8B
# Af8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDBB
# BgNVHSAEOjA4MDYGCWCGSAGG/WwHATApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3
# LmRpZ2ljZXJ0LmNvbS9DUFMwHwYDVR0jBBgwFoAU9LbhIB3+Ka7S5GGlsqIlssgX
# NW4wHQYDVR0OBBYEFDZEho6kurBmvrwoLR1ENt3janq8MHEGA1UdHwRqMGgwMqAw
# oC6GLGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtdHMuY3Js
# MDKgMKAuhixodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRz
# LmNybDCBhQYIKwYBBQUHAQEEeTB3MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k
# aWdpY2VydC5jb20wTwYIKwYBBQUHMAKGQ2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURUaW1lc3RhbXBpbmdDQS5jcnQwDQYJ
# KoZIhvcNAQELBQADggEBAEgc3LXpmiO85xrnIA6OZ0b9QnJRdAojR6OrktIlxHBZ
# vhSg5SeBpU0UFRkHefDRBMOG2Tu9/kQCZk3taaQP9rhwz2Lo9VFKeHk2eie38+dS
# n5On7UOee+e03UEiifuHokYDTvz0/rdkd2NfI1Jpg4L6GlPtkMyNoRdzDfTzZTlw
# S/Oc1np72gy8PTLQG8v1Yfx1CAB2vIEO+MDhXM/EEXLnG2RJ2CKadRVC9S0yOIHa
# 9GCiurRS+1zgYSQlT7LfySmoc0NR2r1j1h9bm/cuG08THfdKDXF+l7f0P4TrweOj
# SaH6zqe/Vs+6WXZhiV9+p7SOZ3j5NpjhyyjaW4emii8wggUxMIIEGaADAgECAhAK
# oSXW1jIbfkHkBdo2l8IVMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUw
# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
# JDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xNjAxMDcx
# MjAwMDBaFw0zMTAxMDcxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxE
# aWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMT
# KERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwggEiMA0G
# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC90DLuS82Pf92puoKZxTlUKFe2I0rE
# DgdFM1EQfdD5fU1ofue2oPSNs4jkl79jIZCYvxO8V9PD4X4I1moUADj3Lh477sym
# 9jJZ/l9lP+Cb6+NGRwYaVX4LJ37AovWg4N4iPw7/fpX786O6Ij4YrBHk8JkDbTuF
# fAnT7l3ImgtU46gJcWvgzyIQD3XPcXJOCq3fQDpct1HhoXkUxk0kIzBdvOw8YGqs
# LwfM/fDqR9mIUF79Zm5WYScpiYRR5oLnRlD9lCosp+R1PrqYD4R/nzEU1q3V8mTL
# ex4F0IQZchfxFwbvPc3WTe8GQv2iUypPhR3EHTyvz9qsEPXdrKzpVv+TAgMBAAGj
# ggHOMIIByjAdBgNVHQ4EFgQU9LbhIB3+Ka7S5GGlsqIlssgXNW4wHwYDVR0jBBgw
# FoAUReuir/SSy4IxLVGLp6chnfNtyA8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNV
# HQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgweQYIKwYBBQUHAQEEbTBr
# MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUH
# MAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ
# RFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2lj
# ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6
# Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmww
# UAYDVR0gBEkwRzA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v
# d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUA
# A4IBAQBxlRLpUYdWac3v3dp8qmN6s3jPBjdAhO9LhL/KzwMC/cWnww4gQiyvd/Mr
# HwwhWiq3BTQdaq6Z+CeiZr8JqmDfdqQ6kw/4stHYfBli6F6CJR7Euhx7LCHi1lss
# FDVDBGiy23UC4HLHmNY8ZOUfSBAYX4k4YU1iRiSHY4yRUiyvKYnleB/WCxSlgNcS
# R3CzddWThZN+tpJn+1Nhiaj1a5bA9FhpDXzIAbG5KHW3mWOFIoxhynmUfln8jA/j
# b7UBJrZspe6HUSHkWGCbugwtK22ixH67xCUrRwIIfEmuE7bhfEJCKMYYVs9BNLZm
# XbZ0e/VWMyIvIjayS6JKldj1po5SMYICTTCCAkkCAQEwgYYwcjELMAkGA1UEBhMC
# VVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0
# LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFt
# cGluZyBDQQIQDUJK4L46iP9gQCHOFADw3TANBglghkgBZQMEAgEFAKCBmDAaBgkq
# hkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIxMDQxOTE3
# MDQzNVowKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQU4deCqOGRvu9ryhaRtaq0lKYk
# m/MwLwYJKoZIhvcNAQkEMSIEIAJU8XYbkBLJhgZlxlq2aS2P0cnwtri/KKapcGTm
# +eC+MA0GCSqGSIb3DQEBAQUABIIBAMDldDBJ6r5GM6N1m5LBT2Qyq29/dWbRQVWg
# 49HB5ot2dcW2t41BV+RyDegoEbPPS0rFUWzLPkQSpNFkuZWS7hbJdprrzNZd+Q1f
# ZzKth7Zceyc6rbx2EPZWQLP64vEEi59l0HrXle/26AJw3BmidCZw0kcFr++p77P6
# 0QsENtQ0KQYQiHHlEVDJzaS2u+dOXrZRPzxqotB8HEr5mKimkonlIStyQcxEApPk
# Yd5Czi4sQG2+Cq6wLnFQ8Numie24b/rgpQ5XyFbTTGUVV4XoNYmNFX0RaTrorsmY
# sE0dzQDB/oeW11O60IU9KJHDXgDsSuTlc8pXcY66OiHZdsoHdbg=
# SIG # End signature block