HP.ClientManagement.psm1

# Copyright (C)2018 HP Inc
# All Rights Reserved.
#
# NOTICE: All information contained herein is, and remains the property of HP Inc.
#
# The intellectual and technical concepts contained herein are proprietary to HP Inc
# 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 Inc.


Add-Type -AssemblyName System.Web
Set-StrictMode -Version 3.0
#requires -Modules "HP.Private"

Add-Type -TypeDefinition @'
    public enum BiosUpdateCriticality
    {
        Recommended=0,
        Critical=1
    }
'@


<#
.SYNOPSIS
    Retrieve an HP BIOS Setting object by name
 
.DESCRIPTION
    Read an HP-specific BIOS setting, identified by the specified name.
 
.PARAMETER Name
    The name of the setting to retrieve. This parameter is mandatory, and has no default.
 
.PARAMETER Format
    This parameter allows to specify the formatting of the result. Possible values are:
     
       * bcu: format as HP Bios Config Utility input format
       * csv: format as a comma-separated values list
       * xml: format as XML
       * json: format as Json
 
    if format is not specified, default powershell formatting is used.
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
 
.NOTES
    Required HP BIOS.
 
 
.EXAMPLE
    Get-HPBIOSSetting "Serial Number" bcu
#>

function Get-HPBIOSSetting {
  [CmdletBinding(DefaultparameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSSetting")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $true)] 
    $Name,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $false)]  
    [ValidateSet('Xml', 'Json', 'BCU', 'CSV')]
    $Format,
    [Parameter(ParameterSetName = 'NewSession', Position = 2, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 3, Mandatory = $true)] 
    [CimSession]$CimSession
  )

  $ns = getNamespace
  Write-Verbose "Reading HP BIOS Setting '$Name' from $ns on '$ComputerName'"
  $result = $null
  
  $params = @{
    Class      = "HP_BIOSSetting"
    Namespace  = $ns
    Filter     = "Name='$name'"
  }

  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { 
    $params.CimSession = newCimSession -target $ComputerName 
  }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { 
    $params.CimSession = $CimSession 
  }
 
  try {
    $result = Get-CimInstance @params -ErrorAction stop
  } catch [Microsoft.Management.Infrastructure.CimException]
  {
    if ($_.Exception.Message.trim() -eq "Access denied")
    {
      throw [System.UnauthorizedAccessException]"Access denied: Please ensure you have the rights to perform this operation."
    }
    throw [System.NotSupportedException]"$($_.Exception.Message): Please ensure this is a supported HP device."
  }


  if (-not $result) {
    $Err = "Setting not found: '" + $name + "'"
    throw [System.Management.Automation.ItemNotFoundException]$Err
  }
  Add-Member -InputObject $result  -Force -NotePropertyName "Class" -NotePropertyValue  $result.CimClass.CimClassName | Out-Null
  Write-Verbose "Retrieved HP BIOS Setting '$name' ok."

  switch ($format) {
    { $_ -eq 'csv' } { return convertSettingToCSV ($result) }
    { $_ -eq 'xml' } { return convertSettingToXML ($result) }
    { $_ -eq 'bcu' } { return convertSettingToBCU ($result) }
    { $_ -eq 'json' } { return convertSettingToJSON ($result) }
    default { return $result }
  }
}


<#
 .SYNOPSIS
    Get device UUID
 
.DESCRIPTION
    This function gets the system UUID via standard OS providers. This should normally match the result from Get-HPBIOSUUID.
 
.PARAMETER ComputerName
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
   
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.EXAMPLE
    Get-HPDeviceUUID
#>

function Get-HPDeviceUUID () {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDeviceUUID")]
  param(    
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $params = @{
    ClassName = 'Win32_ComputerSystemProduct'
    Namespace = 'root\cimv2'
  }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  $obj = Get-CimInstance @params -ErrorAction stop
  ([string](getWmiField $obj "UUID")).trim().ToUpper()
}


<#
 .SYNOPSIS
    Get BIOS UUID
 
.DESCRIPTION
    This function gets the system UUID from the BIOS. This should normally match the result from Get-HPDeviceUUID.
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.EXAMPLE
    Get-HPBIOSUUID
#>

function Get-HPBIOSUUID {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSUUID")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )

  $params = @{ Name = 'Universally Unique Identifier (UUID)' }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }

  $obj = Get-HPBIOSSetting @params -ErrorAction stop
  if ($obj.Value -match '-') {
    return (getFormattedBiosSettingValue $obj)
  }
  else {
    $raw = ([guid]::new($obj.Value)).ToByteArray()
    $raw[0], $raw[3] = $raw[3], $raw[0]
    $raw[1], $raw[2] = $raw[2], $raw[1]
    $raw[4], $raw[5] = $raw[5], $raw[4]
    return ([guid]::new($raw)).ToString().ToUpper().trim()
  }
}


<#
.SYNOPSIS
    Get the current BIOS version
 
.DESCRIPTION
    This function gets the current BIOS version. If available, and the -includeFamily switch is specified,
    the BIOS family is also included.
 
.PARAMETER IncludeFamily
    Include BIOS family in the result
 
.PARAMETER ComputerName
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
   
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
#>

function Get-HPBIOSVersion {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSVersion")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $false)] 
    [switch]$IncludeFamily,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $false)] 
    [Parameter(Position = 1, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 2, Mandatory = $true)] 
    [CimSession]$CimSession
  )

  $params = @{
    ClassName = 'Win32_BIOS'
    Namespace = 'root\cimv2'
  }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  $obj = Get-CimInstance @params -ErrorAction stop
  $verfield = getWmiField $obj "SMBIOSBIOSVersion"
  $ver = $null

  write-verbose "Received object with $verfield" 
  try {
    $ver = extractBIOSVersion $verfield
  }
  catch { throw [System.InvalidOperationException]"The BIOS version on this system could not be parsed. This BIOS may not be supported." }
  if ($includeFamily.IsPresent) { $result = $ver + " " + $verfield.split()[0] }
  else { $result = $ver }
  $result.TrimStart("0").trim()
}

<#
.SYNOPSIS
    Get the BIOS author (manufacturer)
 
.DESCRIPTION
    This function gets the BIOS manufacturer via the Win32_BIOS WMI class. In some cases, the BIOS manufacturer
    may be different than the device manufacturer.
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.EXAMPLE
    Get-HPBIOSAuthor
#>

function Get-HPBIOSAuthor {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSAuthor")]
  param(    
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $params = @{
    ClassName = 'Win32_BIOS'
    Namespace = 'root\cimv2'
  }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  $obj = Get-CimInstance @params -ErrorAction stop
  ([string](getWmiField $obj "Manufacturer")).trim()

}

<#
.SYNOPSIS
    Get the Device manufacturer
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.DESCRIPTION
    This function gets the device manufacturer via standard Windows WMI providers. In some cases, the BIOS manufacturer
  may be different than the device manufacturer.
   
 
.EXAMPLE
    Get-HPDeviceManufacturer
#>

function Get-HPDeviceManufacturer {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDeviceManufacturer")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $params = @{
    ClassName = 'Win32_ComputerSystem'
    Namespace = 'root\cimv2'
  }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  $obj = Get-CimInstance @params -ErrorAction stop
  ([string](getWmiField $obj "Manufacturer")).trim()
}

<#
.SYNOPSIS
    Get the device serial number
 
.DESCRIPTION
    Get the system serial number via Windows WMI. This command is equivalent to reading the SerialNumber property in
    the Win32_BIOS WMI class.
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
   
.EXAMPLE
    Get-HPDeviceSerialNumber
#>

function Get-HPDeviceSerialNumber {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDeviceSerialNumber")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $params = @{
    ClassName = 'Win32_BIOS'
    Namespace = 'root\cimv2'
  }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  $obj = Get-CimInstance @params -ErrorAction stop

  ([string](getWmiField $obj "SerialNumber")).trim()
}

<#
.SYNOPSIS
    Get the device model string, which is the marketing name of the device.
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
   
   
.EXAMPLE
    Get-HPDeviceModel
#>

function Get-HPDeviceModel {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDeviceModel")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $params = @{
    ClassName = 'Win32_ComputerSystem'
    Namespace = 'root\cimv2'
  }

  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  $obj = Get-CimInstance @params -ErrorAction stop

  ([string](getWmiField $obj "Model")).trim()
}




<#
.SYNOPSIS
    Get the device PartNumber (or SKU)
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
   
 
.DESCRIPTION
    Get the device part number for the current device. This function is equivalent to reading the field SystemSKUNumber from
    the WMI class Win32_ComputerSystem.
 
.EXAMPLE
    Get-HPDevicePartNumber
#>

function Get-HPDevicePartNumber {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDevicePartNumber")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $params = @{
    ClassName = 'Win32_ComputerSystem'
    Namespace = 'root\cimv2'
  }

  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  $obj = Get-CimInstance @params -ErrorAction stop

  ([string](getWmiField $obj "SystemSKUNumber")).trim().ToUpper()
}


<#
.SYNOPSIS
    Get the product ID
 
.DESCRIPTION
    This product ID (Platform ID) is a 4-character hexadecimal string. It corresponds to the Product field in the Win32_BaseBoard WMI class.
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
   
.EXAMPLE
    Get-HPDeviceProductID
#>

function Get-HPDeviceProductID {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDeviceProductID")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $params = @{
    ClassName = 'Win32_BaseBoard'
    Namespace = 'root\cimv2'
  }

  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  
  $obj = Get-CimInstance @params -ErrorAction stop
  ([string](getWmiField $obj "Product")).trim().ToUpper()
}


<#
.SYNOPSIS
    Get the device asset tag
 
.DESCRIPTION
    Retrieves the asset tag for a device (also called the Asset Tracking Number).
    Some computers may have a blank asset tag, others may have the asset tag prepopulated with the serial number value.
 
 
.PARAMETER target
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
   
.PARAMETER CimSession
  A pre-created CIM Session (as returned by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.EXAMPLE
    Get-HPDeviceAssetTag
#>

function Get-HPDeviceAssetTag {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDeviceAssetTag")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )

  $params = @{
    Name = 'Asset Tracking Number'
  }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }

  $obj = Get-HPBIOSSetting @params -ErrorAction stop
  getFormattedBiosSettingValue $obj
}


<#
.SYNOPSIS
    Get the value of a BIOS setting.
 
.DESCRIPTION
    This function retrieves the value of a bios setting. Whereas the Get-HPBIOSSetting retrieves all setting fields,
    Get-HPBIOSSettingValue retrieves only the setting's value.
 
.NOTES
    Requires HP BIOS.
 
.PARAMETER name
    The name of the setting to retrieve
 
.PARAMETER target
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.EXAMPLE
    Get-HPBIOSSettingValue $name
#>

function Get-HPBIOSSettingValue {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSSettingValue")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $true)] 
    [string]$Name,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 2, Mandatory = $false)] 
    [CimSession]$CimSession
  )
  $params = @{
    Name = $Name
  }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }

  $obj = Get-HPBIOSSetting @params
  if ($obj) { 
    getFormattedBiosSettingValue $obj 
  }


}


<#
.SYNOPSIS
    Retrieve all BIOS settings
 
.DESCRIPTION
    Retrieve all BIOS settings on a machine, either as native objects, or as a specified format.
 
 
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
 
.PARAMETER Format
    This parameter allows to specify the formatting of the result. Possible values are:
     
       * bcu: format as HP Bios Config Utility input format
       * csv: format as a comma-separated values list
       * xml: format as XML
       * brief: (default) format as a list of names
 
.PARAMETER NoReadonly
     when true, don't include read-only settings into the response. Default is false.
      
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
 
.EXAMPLE
    Get-HPBIOSSettingsList -format bcu
 
.NOTES
    - Although the function supports BCU, not that redirecting the function's output to a file will not be usable by BCU,
    because powershell will insert a unicode BOM in the file. To obtain a compatible file, either remove the BOM manually
  or consider using bios-cli.ps1.
  - BIOS settings of type 'password' are not output when using XML, JSON, BCU, or CSV formats.
  - By convention, when representing multiple values in an enumeration as a single string, the value with an asterisk in front is the currently active value. For example,
    given the string "One,*Two,Three" representing three possible enumeration choices, the current active value is "Two".
    - Requires HP BIOS.
#>

function Get-HPBIOSSettingsList {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSSettingsList")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $false)] 
    [Parameter(Position = 0, Mandatory = $false)]
    [ValidateSet('Xml', 'Json', 'BCU', 'CSV', 'brief')]
    [string]$Format,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $false)] 
    [Parameter(Position = 1, Mandatory = $false)] [switch]$NoReadonly,
    [Parameter(ParameterSetName = 'NewSession', Position = 2, Mandatory = $false)] 
    [Alias('Target')]
    [Parameter(Position = 2, Mandatory = $false)] [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 3, Mandatory = $false)]     
    [Parameter(Position = 3, Mandatory = $false)] [CimSession]$CimSession
  )
  $ns = getNamespace

  Write-Verbose "Getting all BIOS settings from '$ComputerName'"
  $params = @{
    ClassName = 'HP_BIOSSetting'
    Namespace = $ns 
  }

  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }

  try {
  $cs = Get-CimInstance @params -ErrorAction stop
  }
  catch [Microsoft.Management.Infrastructure.CimException] {
    if ($_.Exception.Message.trim() -eq "Access denied")
    {
      throw [System.UnauthorizedAccessException]"Access denied: Please ensure you have the rights to perform this operation."
    }
    throw [System.NotSupportedException]"$($_.Exception.Message): Please ensure this is a supported HP device."
  }

  switch ($format) {
    { $_ -eq 'bcu' } {
      # to BCU format
      $now = Get-Date
      Write-Output "BIOSConfig 1.0"
      Write-Output ";"
      Write-Output "; Created by CMSL function Get-HPBIOSSettingsList"
      Write-Output "; Date=$now"
      Write-Output ";"
      Write-Output "; Found $($cs.count) settings"
      Write-Output ";"
      foreach ($c in $cs) {
        if ($c.CimClass.CimClassName -ne "HPBIOS_BIOSPassword") {
          if ((-not $noreadonly.IsPresent) -or ($c.IsReadOnly -eq 0)) {
            convertSettingToBCU ($c)
          }
        }
      }
      return
    }

    { $_ -eq 'xml' } {
      # to IA format
      Write-Output "<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes"" ?>"
      Write-Output "<ImagePal>"
      Write-Output " <BIOSSettings>"

      foreach ($c in $cs) {
        if ($c.CimClass.CimClassName -ne "HPBIOS_BIOSPassword") {
          if ((-not $noreadonly.IsPresent) -or ($c.IsReadOnly -eq 0)) {
            convertSettingToXML ($c)
          }
        }
      }
      Write-Output " </BIOSSettings>"
      Write-Output "</ImagePal>"
      return
    }

    { $_ -eq 'json' } {
      # to JSON format
      $first = $true
      "[" | Write-Output


      foreach ($c in $cs) {
        Add-Member -InputObject $c  -Force -NotePropertyName "Class" -NotePropertyValue  $c.CimClass.CimClassName | Out-Null

        if ($c.CimClass.CimClassName -ne "HPBIOS_BIOSPassword") {
          if ((-not $noreadonly.IsPresent) -or ($c.IsReadOnly -eq 0)) {
            if ($first -ne $true) {
              Write-Output ","
            }
            convertSettingToJSON ($c)
            $first = $false
          }
        }

      }
      "]" | Write-Output

    }

    { $_ -eq 'csv' } {
      # to CSV format
      Write-Output ("NAME,CURRENT_VALUE,READONLY,TYPE,PHYSICAL_PRESENCE_REQUIRED,MIN,MAX,");
      foreach ($c in $cs) {
        if ($c.CimClass.CimClassName -ne "HPBIOS_BIOSPassword") {
          if ((-not $noreadonly.IsPresent) -or ($c.IsReadOnly -eq 0)) {
            convertSettingToCSV ($c)
          }
        }
      }
      return
    }
    { $_ -eq 'brief' } {
      foreach ($c in $cs) {
        if ((-not $noreadonly.IsPresent) -or ($c.IsReadOnly -eq 0)) {
          Write-Output $c.Name
        }
      }
      return
    }
    default {
      if (-not $noreadonly.IsPresent) {
        return $cs
      }
      else {
        return $cs | Where-Object IsReadOnly -EQ 0
      }
    }
  }
}

<#
.SYNOPSIS
    Set the value of a BIOS setting
 
.DESCRIPTION
    This function sets the value of an HP BIOS setting. Note that the setting may have various constrains
    restricting the input that can be provided.
 
.PARAMETER Name
    The name of a setting. Note that the setting name is usually case sensitive.
 
.PARAMETER Value
    The new value of a setting
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER Password
    The setup password, if a password is active
 
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.PARAMETER PassThru
   Create an object that can be consumed by the [ConvertTo-SecurePlatformPayload](ConvertTo-SecurePlatformPayload)
   in order to create an HP Secure Platform payloads that can be applied via the
   [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
   Note that BIOS passwords passed thru are not encrypted, so it is essential to protect the resulting payload until applied to the target system.
 
.PARAMETER SkipPrecheck
    Skip reading the setting value from the BIOS, before applying it. This is useful as an optimization when the setting is guaranteed to exist on the system,
    or when preparing an HP Sure Admin platform for a remote platform which may contain settings not present on the local platform.
 
.NOTES
    - Requires HP BIOS.
    - Use single quotes around the password to prevent PowerShell from interpreting special characters in the string.
    - By convention, when representing multiple values in an enumeration as a single string, the value with an asterisk in front is the currently active value. For example,
    given the string "One,*Two,Three" representing three possible enumeration choices, the current active value is "Two".
 
 
     
#>

function Set-HPBIOSSettingValue {
  [CmdletBinding(DefaultParameterSetName = 'NoPassthruNewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Set%E2%80%90HPBIOSSettingValue")]
  param(
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'PassThru', Position = 0, Mandatory = $true)] 
    [string]$Name,
    [AllowEmptyString()]
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 1, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 1, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'PassThru', Position = 1, Mandatory = $true)] 
    [string]$Value,
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 2, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 2, Mandatory = $false)] 
    [string]$Password,
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 3, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 3, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'PassThru', Position = 4, Mandatory = $true)] 
    [switch]$PassThru,
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 5, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 5, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'PassThru', Position = 5, Mandatory = $false)] 
    [switch]$SkipPrecheck,
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 6, Mandatory = $true)] 
    [CimSession]$CimSession  
  )

  $params = @{ }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruNewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruReuseSession' ) { $params.CimSession = $CimSession }

  if (-not $SkipPrecheck.IsPresent) {
    $obj = Get-HPBIOSSetting -Name $name  @params
    if (-not $obj) { throw [System.Management.Automation.ItemNotFoundException]"Setting does not exist." }
    $type = $obj.CimClass.CimClassName
  }
  else {
    if ($Name -eq "Setup Password" -or $Name -eq "Power-On Password") {
      $type = 'HPBIOS_BIOSPassword'
    }
    else {
      $type = 'HPBIOS_Setting'
    }
  }

  $c = getBiosSettingInterface @params
  switch ($type) {
    { $_ -eq 'HPBIOS_BIOSPassword' } {
      Write-Verbose "Setting Password setting '$Name' on '$ComputerName'"
      if ($PassThru.IsPresent) {
        return New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $Name; Value = "<utf-16/>" + $Value }
      }
      else {
        $r = $c | Invoke-CimMethod -MethodName  SetBiosSetting -Arguments  @{Name = $Name; Value = "<utf-16/>" + [string]$value; Password = "<utf-16/>" + $Password; }
      }
    }

    default {
      Write-Verbose "Setting HP BIOS Setting '$Name' to value '$Value' on '$ComputerName'"
      if ($PassThru.IsPresent) {
        return New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $Name; Value = $Value }
      }
      else {
        $r = $c | Invoke-CimMethod -MethodName  SetBiosSetting -Arguments  @{Name = $Name; Value = [string]$value; Password = "<utf-16/>" + $Password; }
      }       
    }
  }

  if ($r.Return -ne 0) {
    if ($r.Return -eq 5) {
      Write-Host -ForegroundColor Magenta "Operation failed. Please make sure that you are passing a valid value."
      Write-Host -ForegroundColor Magenta "Some variable names or values may be case sensitive."
    }
    $Err = "$(biosErrorCodesToString($r.Return))"
    throw $Err
  }
}


<#
.SYNOPSIS
    Check if the BIOS Setup password is set
 
.DESCRIPTION
    This function returns $true if a BIOS password is currently active, or $false otherwise.
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.PARAMETER PassThru
   Create an object that can be consumed by the [ConvertTo-SecurePlatformPayload](ConvertTo-SecurePlatformPayload)
   in order to create an HP Secure Platform payloads that can be applied via the
   [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
   Note that BIOS passwords passed thru are not encrypted, so it is essential to protect the resulting payload until applied to the target system.
 
 
.NOTES
    Requires HP BIOS.
 
 
.EXAMPLE
    Get-HPBIOSSetupPasswordIsSet
 
.LINK
    [Set-HPBIOSSetupPassword](Set-HPBIOSSetupPassword)
 
.LINK
    [Get-HPBIOSSetupPasswordIsSet](Get-HPBIOSSetupPasswordIsSet)
#>

function Get-HPBIOSSetupPasswordIsSet () {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSSetupPasswordIsSet")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession  

  )
  $params = @{ Name = "Setup Password" }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }

  $obj = Get-HPBIOSSetting @params
  return [boolean]$obj.IsSet
}

<#
.SYNOPSIS
    Set the BIOS Setup password
 
.DESCRIPTION
    Set the BIOS Setup password to the specific value. The password must comply with the current active security policy.
 
.PARAMETER NewPassword
    The new password to set. A value is required. To clear the password, use Clear-HPBIOSSetupPassword
 
.PARAMETER Password
    The existing setup password, if any. If there is no password set, this parameter may be omitted. Use Get-HPBIOSSetupPasswordIsSet
    to determine if a password is currently set.
 
.PARAMETER PassThru
   Create an object that can be consumed by the [ConvertTo-SecurePlatformPayload](ConvertTo-SecurePlatformPayload)
   in order to create an HP Secure Platform payloads that can be applied via the
   [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
   Note that BIOS passwords passed thru are not encrypted, so it is essential to protect the resulting payload until applied to the target system.
 
 
.PARAMETER ComputerName
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
   
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
 
.EXAMPLE
    Set-HPBIOSSetupPassword -NewPassword 'newpw' -Password 'oldpw'
 
 
.LINK
    [Clear-HPBIOSSetupPassword](Clear-HPBIOSSetupPassword)
 
.LINK
    [Get-HPBIOSSetupPasswordIsSet](Get-HPBIOSSetupPasswordIsSet)
 
.NOTES
    - Requires HP BIOS.
    - Use single quotes around the password to prevent PowerShell from interpreting special characters in the string.
    - Multiple attempts to change the password with an incorrect existing password may trigger BIOS lockout mode, which can be cleared by rebooting the system.
 
#>

function Set-HPBIOSSetupPassword {
  [CmdletBinding(DefaultParameterSetName = 'NoPassthruNewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/set%E2%80%90HPBIOSSetupPassword")]
  param(
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'PassThru', Position = 0, Mandatory = $true)] 
    [string]$NewPassword,

    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 1, Mandatory = $false)] 
    [string]$Password,

    [Parameter(ParameterSetName = 'PassThru', Position = 2, Mandatory = $true)] 
    [switch]$PassThru,

    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 3, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",

    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 4, Mandatory = $true)] 
    [CimSession]$CimSession  
  )
  $params = @{ }
  $settingName = 'Setup Password'

  if ($PassThru.IsPresent) {
    return New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $settingName; Value = '<utf-16/>' + $newPassword }
  }
  
  
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruNewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruReuseSession' ) { $params.CimSession = $CimSession }
  
  $iface = getBiosSettingInterface @params

  $r = $iface | Invoke-CimMethod  -ErrorAction Stop -MethodName  'SetBIOSSetting' -Arguments  @{
    Name     = $settingName
    Password = '<utf-16/>' + $Password
    Value    = '<utf-16/>' + $newPassword
  }

  if ($r.Return -ne 0) {
    $Err = "$(biosErrorCodesToString($r.Return))"
    throw [System.InvalidOperationException]$Err
  }
}

<#
.SYNOPSIS
    Clear the BIOS Setup password
 
.DESCRIPTION
    This function clears the BIOS setup password. To set the password, use Set-HPBIOSSetupPassword
 
.PARAMETER Password
    The existing setup password. Use Get-HPBIOSSetupPasswordIsSet to determine if a password is currently set.
 
 
.PARAMETER PassThru
   Create an object that can be consumed by the [ConvertTo-SecurePlatformPayload](ConvertTo-SecurePlatformPayload)
   in order to create an HP Secure Platform payloads that can be applied via the
   [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
   Note that BIOS passwords passed thru are not encrypted, so it is essential to protect the resulting payload until applied to the target system.
 
.PARAMETER ComputerName
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
   
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
 
.EXAMPLE
    Clear-HPBIOSSetupPassword 'oldpw'
 
.NOTES
    - Requires HP BIOS.
    - Use single quotes around the password to prevent PowerShell from interpreting special characters in the string.
    - Multiple attempts to change the password with an incorrect existing password may trigger BIOS lockout mode, which can be cleared by rebooting the system.
 
.LINK
    [Set-HPBIOSSetupPassword](Set-HPBIOSSetupPassword)
 
.LINK
    [Get-HPBIOSSetupPasswordIsSet](Get-HPBIOSSetupPasswordIsSet)
#>

function Clear-HPBIOSSetupPassword {
  [CmdletBinding(DefaultParameterSetName = 'NoPassthruNewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Clear%E2%80%90HPBIOSSetupPassword")]
  param(
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'PassThru', Position = 0, Mandatory = $true)] 
    [string]$Password,
    [Parameter(ParameterSetName = 'PassThru', Position = 1, Mandatory = $true)] 
    [switch]$PassThru,

    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 2, Mandatory = $false)] 
    [Alias('Target')]
    $ComputerName = ".",
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 3, Mandatory = $true)] 
    [CimSession]$CimSession  
  )
  $settingName = 'Setup Password'

  if ($PassThru.IsPresent) {
    return New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $settingName; Value = "<utf-16/>" }
  }

  $params = @{ }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruNewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruReuseSession' ) { $params.CimSession = $CimSession }

  $iface = getBiosSettingInterface @params
  $r = $iface | Invoke-CimMethod -MethodName SetBiosSetting -Arguments  @{Name = "Setup Password"; Value = "<utf-16/>"; Password = "<utf-16/>" + $Password; }
  if ($r.Return -ne 0) {
    $Err = "$(biosErrorCodesToString($r.Return))"
    throw [System.InvalidOperationException]$Err
  }
}


<#
.SYNOPSIS
    Check if the BIOS Power-On password is set
 
.DESCRIPTION
    This function returns $true if a BIOS power-on password is currently active, or $false otherwise.
 
.PARAMETER ComputerName
    Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.NOTES
  Changes in the state of the BIOS Power-On Password may not be visible until the system is rebooted and the POST prompt is accepted
  to enable the BIOS Power-On password.
 
.EXAMPLE
    Get-HPBIOSPowerOnPasswordIsSet
 
.LINK
    [Set-HPBIOSPowerOnPassword](Set-HPBIOSPowerOnPassword)
 
.LINK
    [Clear-HPBIOSPowerOnPassword](Clear-HPBIOSPowerOnPassword)
#>

function Get-HPBIOSPowerOnPasswordIsSet () {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSPowerOnPasswordIsSet")]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession  

  )
  $params = @{ Name = "Power-On Password" }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }

  $obj = Get-HPBIOSSetting @params
  return [boolean]$obj.IsSet
}

<#
.SYNOPSIS
    Set the BIOS Power-On password
 
.DESCRIPTION
    This function clears any active power-on password. The Password must comply with password complexity requirements active on the system.
 
.PARAMETER NewPassword
    The password to set. A value is required. To clear the password, use Clear-HPBIOSPowerOnPassword
 
.PARAMETER Password
    The existing setup password (not power-on password), if any. If there is no setup password set, this parameter may be omitted. Use Get-HPBIOSSetupPasswordIsSet
    to determine if a setup password is currently set.
 
.PARAMETER ComputerName
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
 
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
   
.NOTES
  Changes in the state of the BIOS Power-On Password may not be visible until the system is rebooted and the POST prompt is accepted
  to enable the BIOS Power-On password.
 
.EXAMPLE
    Set-HPBIOSPowerOnPassword -NewPassword 'newpw' -Password 'setuppw'
 
.LINK
    [Clear-HPBIOSPowerOnPassword](Clear-HPBIOSPowerOnPassword)
 
.LINK
    [Get-HPBIOSPowerOnPasswordIsSet](Get-HPBIOSPower\OnPasswordIsSet)
 
.NOTES
    - Requires HP BIOS.
    - Use single quotes around the password to prevent PowerShell from interpreting special characters in the string.
    - On many platform families, changing the Power-On password requires that a BIOS password is active.
 
#>

function Set-HPBIOSPowerOnPassword {
  [CmdletBinding(DefaultParameterSetName = 'NoPassthruNewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Set%E2%80%90HPBIOSPowerOnPassword")]
  param(
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'PassThru', Position = 0, Mandatory = $true)] 
    [string]$NewPassword,
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 1, Mandatory = $false)] 
    [string]$Password,
    [Parameter(ParameterSetName = 'PassThru', Position = 2, Mandatory = $true)] 
    [switch]$PassThru,

    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 3, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 4, Mandatory = $true)] 
    [CimSession]$CimSession  
  )
  $settingName = 'Power-On Password'
  if ($PassThru.IsPresent) {
    return New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $settingName; Value = "<utf-16/>" }
  }

  $params = @{ }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruNewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruReuseSession' ) { $params.CimSession = $CimSession }

  $iface = getBiosSettingInterface @params
  $r = $iface | Invoke-CimMethod -MethodName  SetBiosSetting -Arguments  @{Name = $settingName; Value = "<utf-16/>" + $newPassword; Password = "<utf-16/>" + $Password; } 
  if ($r.Return -ne 0) {
    $Err = "$(biosErrorCodesToString($r.Return))"
    throw $Err
  }
}

<#
.SYNOPSIS
    Clear the BIOS Power-On password
 
.DESCRIPTION
    This function clears any active power-on password.
 
.PARAMETER Password
    The existing setup (not power-on) password. Use Get-HPBIOSSetupPasswordIsSet to determine if a password is currently set.
 
.PARAMETER ComputerName
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
   
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
 
.EXAMPLE
    Clear-HPBIOSPowerOnPassword "setuppassword"
 
.LINK
    [Set-HPBIOSPowerOnPassword](Set-HPBIOSPowerOnPassword)
 
.LINK
    [Get-HPBIOSPowerOnPasswordIsSet](Get-HPBIOSPowerOnPasswordIsSet)
 
.LINK
    [Get-HPBIOSSetupPasswordIsSet](Get-HPBIOSSetupPasswordIsSet)
 
.NOTES
  - Requires HP BIOS.
  - Use single quotes around the password to prevent PowerShell from interpreting special characters in the string.
  - On many platform families, changing the Power-On password requires that a BIOS password is active.
 
#>

function Clear-HPBIOSPowerOnPassword {
  [CmdletBinding(DefaultParameterSetName = 'NoPassthruNewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Clear%E2%80%90HPBIOSPowerOnPassword")]
  param(
    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 0, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 0, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'PassThru', Position = 0, Mandatory = $false)] 
    [string]$Password,

    [Parameter(ParameterSetName = 'PassThru', Position = 2, Mandatory = $true)] 
    [switch]$PassThru,

    [Parameter(ParameterSetName = 'NoPassthruNewSession', Position = 1, Mandatory = $false)] 
    [Alias('Target')]
    $ComputerName = ".",
    [Parameter(ParameterSetName = 'NoPassthruReuseSession', Position = 2, Mandatory = $true)] 
    [CimSession]$CimSession  
  )

  $settingName = 'Power-On Password'
  if ($PassThru.IsPresent) {
    return New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $settingName; Value = "<utf-16/>" }
  }


  $params = @{ }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruNewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'NoPassthruReuseSession' ) { $params.CimSession = $CimSession }

  $iface = getBiosSettingInterface @params
  $r = $iface | Invoke-CimMethod -MethodName SetBiosSetting -Arguments  @{
    Name     = "Power-On Password"
    Value    = "<utf-16/>"
    Password = ("<utf-16/>" + $Password) 
  }
  if ($r.Return -ne 0) {
    $Err = "$(biosErrorCodesToString($r.Return))"
    throw [System.InvalidOperationException]$Err
  }
}

<#
.SYNOPSIS
    Set one or more BIOS settings from a file
 
.DESCRIPTION
    This function sets multiple bios settings from a file. The file format may be specified via the -format parameter, however the function
    will try to infer the format from the file extension.
 
 
.PARAMETER File
    The file (relative or absolute path) to the file to process
 
.PARAMETER Format
    The file format (xml, json, csv, or bcu).
 
.PARAMETER Password
    The current BIOS setup password, if any.
 
.PARAMETER NoSummary
    Suppress the one line summary at the end of the import
 
.PARAMETER ErrorHandling
    This value is used by wrapping scripts to prevent this function from raising exceptions or warnings.
     0 - operate normally
     1 - raise exceptions as warnings
   2 - no warnings or exceptions, fail silently
    
.PARAMETER ComputerName
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
   
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.PARAMETER PassThru
   Create an object that can be consumed by the [ConvertTo-SecurePlatformPayload](ConvertTo-SecurePlatformPayload)
   in order to create an HP Secure Platform payloads that can be applied via the
   [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
   Note that BIOS passwords passed thru are not encrypted, so it is essential to protect the resulting payload until applied to the target system.
 
.EXAMPLE
    Set-HPBIOSSettingValueFromFile .\file.bcu -nosummary
 
.NOTES
    - Requires HP BIOS.
    - Use single quotes around the password to prevent PowerShell from interpreting special characters in the string.
#>

function Set-HPBIOSSettingValuesFromFile {
  [CmdletBinding(DefaultParameterSetName = "NotPassThruNewSession", 
    HelpUri = "https://developers.hp.com/hp-client-management/doc/Set%E2%80%90HPBIOSSettingValuesFromFile")]
  param(
    [Parameter(ParameterSetName = "PassThru", Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = "NotPassThruNewSession", Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = "NotPassThruReuseSession", Position = 0, Mandatory = $true)] 
    [string]$File,

    [Parameter(ParameterSetName = "PassThru", Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = "NotPassThruNewSession", Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = "NotPassThruReuseSession", Position = 1, Mandatory = $false)] 
    [ValidateSet('Xml', 'Json', 'BCU', 'CSV')]
    [string]$Format = $null,

    [Parameter(ParameterSetName = "NotPassThruNewSession", Position = 2, Mandatory = $false)] 
    [Parameter(ParameterSetName = "NotPassThruReuseSession", Position = 2, Mandatory = $false)]  
    [string]$Password,

    [Parameter(ParameterSetName = "NotPassThruNewSession", Position = 3, Mandatory = $false)] 
    [Parameter(ParameterSetName = "NotPassThruReuseSession", Position = 3, Mandatory = $false)]   
    [switch]$NoSummary,

    [Parameter(ParameterSetName = "NotPassThruNewSession", Position = 4, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",

    [Parameter(ParameterSetName = "NotPassThruNewSession", Position = 5, Mandatory = $false)] 
    [Parameter(ParameterSetName = "NotPassThruReuseSession", Position = 5, Mandatory = $false)] 
    $ErrorHandling = 2,

    [Parameter(ParameterSetName = "PassThru", Position = 6, Mandatory = $true)] 
    [switch]$PassThru,

    
    [Parameter(ParameterSetName = "NotPassThruReuseSession", Position = 7, Mandatory = $true)] 
    [CimSession]$CimSession  
  )


  if (-not $Format) {
    $Format = (Split-Path -Path $File -Leaf).split(".")[1].ToLower()
    Write-Verbose "Format from file extension: $Format"
  }

  $params = @{
    File          = $file
    Password      = $password
    ErrorHandling = $ErrorHandling
    PassThru      = $PassThru.IsPresent
  }

  if ($PSCmdlet.ParameterSetName -eq 'NotPassThruNewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'NotPassThruReuseSession' ) { $params.CimSession = $CimSession }

  switch ($Format) {
    { $_ -eq 'csv' } { $result = setSettingsFromCsv @params }
    { $_ -eq 'xml' } { $result = setSettingsFromXml @params }
    { $_ -eq 'json' } { $result = setSettingsFromJson @params }
    { $_ -eq 'bcu' } { $result = setSettingsFromBcu @params }
    default { throw [System.FormatException]"Format specifier not provided, and could not determine format from file extension" }
  }

  if ($result -and $PassThru.IsPresent) {
    return ,@($result)
  }
  elseif ($result -and -not $NoSummary.IsPresent ) {
    $summary = "Total: $($result[0]), not found: $($result[2]), different but read-only: $($result[1]), already set: $($result[3])"
    Write-Output $summary
  }

}


<#
.SYNOPSIS
    Reset BIOS settings to shipping defaults
 
.DESCRIPTION
    Reset BIOS to shipping defaults. The actual defaults are platform specific.
     
.PARAMETER Password
  The current BIOS setup password, if any.
   
.PARAMETER ComputerName
  Execute the command on specified target computer. If not specified, the command is executed on the local computer.
   
.PARAMETER CimSession
  A pre-established CIM Session (as created by [New-CIMSession](https://docs.microsoft.com/en-us/powershell/module/cimcmdlets/new-cimsessionoption?view=powershell-5.1)
  cmdlet). Use this to pass a preconfigured session object to optimize remote connections or specify the connection
  protocol (Wsman or DCOM). If not specified, the function will create its own one-time use CIM Session object, and default to DCOM protocol.
 
.PARAMETER PassThru
   Create an object that can be consumed by the [ConvertTo-SecurePlatformPayload](ConvertTo-SecurePlatformPayload)
   in order to create an HP Secure Platform payloads that can be applied via the
   [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
   Note that BIOS passwords passed thru are not encrypted, so it is essential to protect the resulting payload until applied to the target system.
 
.EXAMPLE
    Set-HPBIOSSettingDefaults
 
.NOTES
    - Requires HP BIOS.
    - Use single quotes around the password to prevent PowerShell from interpreting special characters in the string.
 
#>

function Set-HPBIOSSettingDefaults {
  [CmdletBinding(DefaultParameterSetname = 'NotPassThruNewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Set%E2%80%90HPBIOSSettingDefaults")]
  param(
    [Parameter(ParameterSetName = "PassThru", Position = 0, Mandatory = $false)] 
    [Parameter(ParameterSetName = "NotPassThruNewSession", Position = 0, Mandatory = $false)] 
    [Parameter(ParameterSetName = "NotPassThruReuseSession", Position = 0, Mandatory = $false)] 
    [string]$Password,


    [Parameter(ParameterSetName = "PassThru", Position = 1, Mandatory = $true)] 
    [switch]$PassThru,

    [Parameter(ParameterSetName = 'NotPassThruNewSession', Position = 2, Mandatory = $false)] 
    [Alias('Target')]
    $ComputerName = ".",
    [Parameter(ParameterSetName = 'NotPassThruReuseSession', Position = 3, Mandatory = $true)] 
    [CimSession]$CimSession  
  )

  $params = @{ }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  $iface = getBiosSettingInterface @params

  if ($PassThru.IsPresent) {
    return New-Object PSObject -Property @{ Type = "hp:sureadmin:set_defaults"; Name = 'SetSystemDefaults'; Value = "" }
  }

  Write-Verbose 'Calling SetSystemDefaults() on $ComputerName'
  $r = $iface | Invoke-CimMethod -MethodName SetSystemDefaults -Arguments  @{ Password = "<utf-16/>" + $Password; }

  if ($r.Return -ne 0) {
    $Err = "$(biosErrorCodesToString($r.Return))"
    throw $Err
  }
}

<#
.SYNOPSIS
    Get system uptime
 
.DESCRIPTION
    Get the system boot time and uptime
     
.PARAMETER target
    Optionally specify a remote computer
 
.EXAMPLE
    (Get-HPDeviceUptime).BootTime
 
#>

function Get-HPDeviceUptime {
  [CmdletBinding(DefaultParameterSetName = 'NewSession', HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDeviceUptime")]
  param(    
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [Alias('Target')]
    [string]$ComputerName = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $params = @{
    ClassName = 'Win32_OperatingSystem'
    Namespace = 'root\cimv2'
  }
  if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
  if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  
  $result = Get-CimInstance @params -ErrorAction stop
  $resultobject = @{ }
  $resultobject.BootTime = $result.LastBootUpTime

  $span = (Get-Date) - ($resultobject.BootTime)
  $resultobject.Uptime = "$($span.days) days, $($span.hours) hours, $($span.minutes) minutes, $($span.seconds) seconds"
  $resultobject
}



<#
.SYNOPSIS
    Get current boot mode and uptime
 
.DESCRIPTION
    Returns an object containing system uptime, last boot time, whether secure boot is enabled, and whether the system was booted in UEFI or Legacy mode.
 
 
.EXAMPLE
    $IsUefi = (Get-HPDeviceBootInformation).Mode -eq "UEFI"
 
#>

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

  $mode = @{ }
  $err = $null

  try {
    $sb = Confirm-SecureBootUEFI
    $mode.Mode = "UEFI"
    $mode.SecureBoot = $sb
  }
  catch {
    $mode.Mode = "Legacy"
    $mode.SecureBoot = $false
  }

  try {
    $uptime = Get-HPDeviceUptime
    $mode.Uptime = $uptime.Uptime
    $mode.BootTime = $uptime.BootTime
  }
  catch {
    $mode.Uptime = "N/A"
    $mode.BootTime = "N/A"
  }

  $mode
}



<#
.SYNOPSIS
    Check and apply available BIOS updates (or downgrades)
 
.DESCRIPTION
    This function uses an internet service to retrieve the list of BIOS updates available for a platform, and optionally checks it against the current system.
 
    The result is a series of records, with the following definition:
 
        * Ver - the BIOS update version
        * Date - the BIOS release date
        * Bin - the BIOS update binary file
 
.PARAMETER platform
    the Platform ID to check. If not specified, check the current platform. The platform id can be obtained via Get-HPDeviceProductID.
    The platform ID cannot be specified for a flash operation.
 
.PARAMETER format
    The file format (xml, json, csv) to output. If not specified, a list of powershell objects is returned
 
.PARAMETER latest
    If specified, only return or download latest available BIOS version
 
.PARAMETER check
    If specified, return true if the latest version corresponds to the installed version, false otherwise. This check is only valid
    when comparing against current platform.
 
.PARAMETER all
   Include all known BIOS update information. This may include additional data such as dependencies, rollback support, and criticality.
 
.PARAMETER download
   Download the BIOS file to the current directory or a path specified by saveAs.
 
.PARAMETER flash
    Apply the BIOS update to the current system.
 
.PARAMETER password
    Specify the BIOS password, if a password is active. This switch is only used when -flash is specified. - Use single quotes around the password to prevent PowerShell
    from interpreting special characters in the string.
 
.PARAMETER version
   The BIOS version to download. If not specified, the latest version available will be downloaded.
 
.PARAMETER saveAs
   The filename for the downloaded BIOS file. If not specified, the remote file name will be used.
 
.PARAMETER quiet
   Do not display a progress bar during BIOS file download.
 
.PARAMETER overwrite
   Force overwriting any existing file with the same name during BIOS file download. This switch is only used when -download is specified.
 
.PARAMETER yes
   Answer 'yes' to the 'Are you sure you want to flash' prompt.
 
.PARAMETER Force
   Force the BIOS to update, even if the target BIOS is already installed.
 
.PARAMETER bitlocker
    Provide an answer to the Bitlocker check prompt (if any). The value may be one of:
     stop - stop if bitlocker is detected but not suspended, and prompt.
     stop is default when bitlocker switch is provided.
     ignore - skip the bitlocker check
     suspend - suspend bitlocker if active, and continue
 
 
.NOTES
    - Flash is only supported on Windows 10 1709 (Fall Creators Updated) and later.
    - UEFI boot mode is required for flashing, legacy mode is not supported.
 
    **WinPE notes**
 
    - Use '-bitlocker ignore' when using this function in WinPE, as bitlocker checks are not applicable in Windows PE.
    - Requires that the WInPE image is built with the WinPE-SecureBootCmdlets.cab component.
 
.EXAMPLE
    Get-HPBIOSUpdates
#>

function Get-HPBIOSUpdates {

  [CmdletBinding(DefaultParameterSetName = "ViewSet",
    HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPBIOSUpdates")]
  param(
    [Parameter(ParameterSetName = "DownloadSet", Position = 0, Mandatory = $false)]
    [Parameter(ParameterSetName = "ViewSet", Position = 0, Mandatory = $false)]
    [Parameter(Position = 0, Mandatory = $false)]
    [ValidatePattern("^[a-fA-F0-9]{4}$")]
    [string]$Platform,

    [ValidateSet('Xml', 'Json',  'CSV')]
    [Parameter(ParameterSetName = "ViewSet", Position = 1, Mandatory = $false)]
    [string]$Format,

    [Parameter(ParameterSetName = "ViewSet", Position = 2, Mandatory = $false)]
    [switch]$Latest,

    [Parameter(ParameterSetName = "CheckSet", Position = 3, Mandatory = $false)]
    [switch]$Check,

    [Parameter(ParameterSetName = "FlashSet", Position = 4, Mandatory = $false)]
    [Parameter(ParameterSetName = "DownloadSet", Position = 4, Mandatory = $false)]
    [Parameter(ParameterSetName = "ViewSet", Position = 4, Mandatory = $false)]
    [string]$Target = ".",

    [Parameter(ParameterSetName = "ViewSet", Position = 5, Mandatory = $false)]
    [switch]$All,

    [Parameter(ParameterSetName = "DownloadSet", Position = 6, Mandatory = $true)]
    [switch]$Download,

    [Parameter(ParameterSetName = "FlashSet", Position = 7, Mandatory = $true)]
    [switch]$Flash,

    [Parameter(ParameterSetName = 'FlashSet', Position = 8, Mandatory = $false)]
    [string]$Password,

    [Parameter(ParameterSetName = "FlashSet", Position = 9, Mandatory = $false)]
    [Parameter(ParameterSetName = "DownloadSet", Position = 9, Mandatory = $false)]
    [string]$Version,

    [Parameter(ParameterSetName = "FlashSet", Position = 10, Mandatory = $false)]
    [Parameter(ParameterSetName = "DownloadSet", Position = 10, Mandatory = $false)]
    [string]$SaveAs,

    [Parameter(ParameterSetName = "FlashSet", Position = 11, Mandatory = $false)]
    [Parameter(ParameterSetName = "DownloadSet", Position = 11, Mandatory = $false)]
    [switch]$Quiet,

    [Parameter(ParameterSetName = "FlashSet", Position = 12, Mandatory = $false)]
    [Parameter(ParameterSetName = "DownloadSet", Position = 12, Mandatory = $false)]
    [switch]$Overwrite,

    [Parameter(ParameterSetName = 'FlashSet', Position = 13, Mandatory = $false)]
    [switch]$Yes,

    [Parameter(ParameterSetName = 'FlashSet', Position = 14, Mandatory = $false)]
    [ValidateSet('stop', 'ignore', 'suspend')]
    [string]$Bitlocker = 'stop',
    
    [Parameter( ParameterSetName = 'FlashSet', Position = 15, Mandatory = $false)]
    [switch]$Force
  )

  if ($PSCmdlet.ParameterSetName -eq "FlashSet") {
    Test-HPFirmwareFlashSupported -checkplatform 
  }

  if (-not $platform) {
    $platform = Get-HPDeviceProductID -target $target 
  }

  $platform = $platform.ToUpper()
  Write-Verbose "Using platform ID $platform"


  $uri = [string]"https://ftp.hp.com/pub/pcbios/{0}/{0}.xml" -f $platform.ToUpper()
  Write-Verbose "Retrieving catalog file $uri"
  $ua = Get-HPPrivateUserAgent
  try {
    [System.Net.ServicePointManager]::SecurityProtocol = Get-HPPrivateAllowedHttpsProtocols
    $data = Invoke-WebRequest -Uri $uri -UserAgent $ua -UseBasicParsing  -ErrorAction Stop
  }
  catch [System.Net.WebException] {
    if ($_.Exception.Message.contains("(404) Not Found"))
    {
      throw [System.Management.Automation.ItemNotFoundException]"Unable to retrieve BIOS data for a platform with ID $platform (data file not found)."
    }
    throw $_.Exception
  }

  [xml]$doc = [System.IO.StreamReader]::new($data.RawContentStream).ReadToEnd()
  if ((-not $doc) -or (-not (Get-Member -InputObject $doc -Type Property -Name "BIOS")) -or (-not (Get-Member -InputObject $doc.BIOS -Type Property -Name "Rel")))
  {
      throw [System.FormatException]"Source data file is unsupported or corrupt"
  }
  
  $latestVer = $doc.BIOS.REL `
  | Sort-Object -Property ver -Descending `
  | Select-Object -Property @{ Name = 'Ver'; expr = { $_.Ver.TrimStart("0") } }, 'Bin' -First 1


  if (($PSCmdlet.ParameterSetName -eq "ViewSet") -or ($PSCmdlet.ParameterSetName -eq "CheckSet")) {
    Write-Verbose "Proceeding with parameter set => view"
    if ($check.IsPresent -eq $true) {
      [string]$haveVer = Get-HPBIOSVersion -target $target
      return ([string]$haveVer.TrimStart("0") -eq [string]$latestVer[0].Ver)
    }

    $args = @{ }
    if ($all.IsPresent) {
      $args.Property = (@{ Name = 'Ver'; expr = { $_.Ver.TrimStart("0") } }, "Date", "Bin", `
        (@{ Name = 'RollbackAllowed'; expr = { [bool][int]$_.RB.trim() } }), `
        (@{ Name = 'Importance'; expr = { [Enum]::ToObject([BiosUpdateCriticality], [int]$_.L.trim()) } }), `
        (@{ Name = 'Dependency'; expr = { [string]$_.DP.trim() } }))
    }
    else {
      $args.Property = (@{ Name = 'Ver'; expr = { $_.Ver.TrimStart("0") } }, "Date", "Bin")
    }

    if ($latest) { $args.First = 1 }
    formatBiosVersionsOutputList ($doc.BIOS.REL | Sort-Object -Property ver -Descending | Select-Object @args)
  }
  else {
    $download_params = @{ }

    if ($version) {
      $latestVer = $doc.BIOS.REL `
      | Where-Object { $_.Ver.TrimStart("0") -eq $version } `
      | Select-Object -Property Ver, Bin -First 1
    }

    if (-not $latestVer) { throw [System.ArgumentOutOfRangeException]"Version $version was not found." }

    if (($flash.IsPresent) -and (-not $saveAs)) {
      $saveAs = Get-HPPrivateTemporaryFileName  -filename $latestVer.Bin
      $download_params.NoClobber = "yes"
      Write-Verbose "Temporary file name for download is $saveAs"
    }
    else { $download_params.NoClobber = if ($overwrite.IsPresent) { "yes" } else { "no" } }

    Write-Verbose "Proceeding with parameter set => download, overwrite=$($download_params.NoClobber)"


    $remote_file = $latestVer.Bin
    $local_file = $latestVer.Bin
    $remote_ver = $latestVer.Ver

    if (($PSCmdlet.ParameterSetName -eq "FlashSet")) {
      $running = Get-HPBIOSVersion
      if ((-not $Force.IsPresent) -and ($running.TrimStart("0").trim() -eq $remote_ver.TrimStart("0").trim())) {
        Write-Host "This system is already running BIOS version $($remote_ver.TrimStart(`"0`").Trim())"
        Write-Host -ForegroundColor Cyan "You can specify -Force on the command line to proceed anyway."
        return
      }
    }

    if ($saveAs) {
      $local_file = $saveAs
    }

    [Environment]::CurrentDirectory = $pwd
    #if (-not [System.IO.Path]::IsPathRooted($to)) { $to = ".\$to" }

    $download_params.url = [string]"https://ftp.hp.com/pub/pcbios/{0}/{1}" -f $platform, $remote_file
    $download_params.Target = [IO.Path]::GetFullPath($local_file)
    $download_params.progress = ($quiet.IsPresent -eq $false)
    Invoke-HPPrivateDownloadFile @download_params  -panic

    if (($PSCmdlet.ParameterSetName -eq "FlashSet")) {
      if (-not $yes) {
        Write-Host -ForegroundColor Cyan "Are you sure you want to flash this system with version '$remote_ver'?"
        Write-Host -ForegroundColor Cyan "Current BIOS version is $(Get-HPBIOSVersion)."
        Write-Host -ForegroundColor Cyan "A reboot will be required for the operation to complete."
        $response = Read-Host -Prompt "Type 'Y' to continue and anything else to abort. Or specify -Yes on the command line to skip this prompt"
        if ($response -ne "Y") {
          Write-Verbose "User did not confirm and did not disable confirmation, aborting."
          return
        }
      }

      Write-Verbose "Passing to flash process with file $($download_params.target)"

      $update_params = @{ }
      $update_params.file = $download_params.Target
      if ($password) {
        $update_params.password = $password
      }
      $update_params.bitlocker = $bitlocker
      $update_params.Force = $Force
     
      Update-HPFirmware @update_params 
    }
  }

}





<#
 .SYNOPSIS
    Get platform name, system ID, or operating system support using either the platform name or its system ID.
 
.DESCRIPTION
    This function retrieves information about the platform, given a platform name or system id. It can
    be used to convert between platform name and system IDs. Note that a platform may have multiple system IDs,
    or a system ID may map to multiple platforms.
 
    Currently returns the following information:
 
    - SystemID - the system iD for this platform
    - FamilyID - the platform family ID
  - Name - the name of the platform
  - DriverPackSupport - this platform supports driver packs
 
  Get-HPDeviceDetails functionality is not supported in WinPE.
 
.PARAMETER platform
    Query by platform id (a 4-digit hexadecimal number).
 
.PARAMETER name
    Query by platform name. The name must match exactly, unless the -match parameter is also specified.
 
.PARAMETER match
    Relax the match to a substring match. if the platform contains the substring defined by the -name parameter, it will
    be included in the return.
 
.PARAMETER oslist
    Return the list of supported operating systems for the specified platform.
 
.EXAMPLE
    Get-HPDeviceDetails -platform 8100
 
.EXAMPLE
    Get-HPDeviceDetails -name 'HP ProOne 400 G3 20-inch Touch All-in-One PC'
 
.EXAMPLE
    Get-HPDeviceDetails -name '840 G5' -match
 
#>

function Get-HPDeviceDetails {
  [CmdletBinding(
    DefaultParameterSetName = "FromID",
    HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPDeviceDetails")
  ]
  param(
    [ValidatePattern("^[a-fA-F0-9]{4}$")]
    [string][Parameter(Mandatory = $false, Position = 0, ParameterSetName = "FromID")]
    $platform,

    [string][Parameter(Mandatory = $true, Position = 1, ParameterSetName = "FromName")]
    $name,

    [switch][Parameter(Mandatory = $false, Position = 1, ParameterSetName = "FromName")]
    $match,

    [switch][Parameter(Mandatory = $false, Position = 2)]
    [Parameter(ParameterSetName = "FromName")]
    [Parameter(ParameterSetName = "FromID")]
    $oslist
  )

  if(Test-WinPE){
    Throw "Getting HP Device details is not supported in WinPE"
  }

  $url = "https://ftp.hp.com/pub/caps-softpaq/cmit/imagepal/ref/platformList.cab"
  $filename = "platformList.cab"
  $file = Get-HPPrivateOfflineCacheFiles -url $url -filename $filename -expand

  if (-not $platform) {
    try { $platform = Get-HPDeviceProductID }
    catch { Write-Verbose "No platform found." }
  }
  if ($platform) {
    $platform = $platform.ToLower() 
    Write-Verbose "Searching for $platform in $file"
  }
  if ($PSCmdlet.ParameterSetName -eq "FromID") {
    $data = Select-Xml -Path "$file" -XPath "/ImagePal/Platform/SystemID[normalize-space(.)=`"$platform`"]/parent::*"
  }
  else {
    if ($match.IsPresent) {
      $data = Select-Xml -Path "$file" -XPath "/ImagePal/Platform/ProductName[translate(substring(`"$($name.ToLower())`",0), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')]/parent::*"
    }
    else {
      $data = Select-Xml -Path "$file" -XPath "/ImagePal/Platform/ProductName[translate(normalize-space(.), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = `"$($name.ToLower())`"]/parent::*"
    }
  }

  if (-not $data) { return }
  $data.Node | ForEach-Object {
    $__ = $_
    if ($oslist.IsPresent) {
      [array]$r = ($__.OS | ForEach-Object {
          if (($PSCmdlet.ParameterSetName -eq "FromID") -or
            (($__.ProductName. "#text" -ieq $name) -or ($match.IsPresent -and $__.ProductName. "#text".trim() -match $name))) {
            $rid = $Null
            if ("OSReleaseID" -in $_.PSobject.Properties.Name) {
              $rid = $_.OSReleaseID
            }

            $obj = New-Object -TypeName PSCustomObject -Property @{
              SystemID               = $__.SystemID.ToUpper()
              OperatingSystem        = $_.OSDescription
              OperatingSystemVersion = $_.OSVersion
              OperatingSystemRelease = $rid
              Architecture           = $_.OSArchitecture
            }
            $obj
          }
        })
    }
    else {
      [array]$r = ($__.ProductName | ForEach-Object {
          if (($PSCmdlet.ParameterSetName -eq "FromID") -or
            (($_. "#text" -ieq $name) -or ($match.IsPresent -and $_. "#text".trim() -match $name))) {

            New-Object -TypeName PSCustomObject -Property @{
              SystemID          = $__.SystemID.ToUpper()
              Name              = $_. "#text"
              DriverPackSupport = $result = [System.Convert]::ToBoolean($_.DPBCompliant)
            }
          }
        })
    }
    return $r
  }
}





##
## private functions below here
##


function getFormattedBiosSettingValue {
  [CmdletBinding()]
  param($obj)
  switch ($obj.CimClass.CimClassName) {
    { $_ -eq 'HPBIOS_BIOSString' } {
      $result = $obj.Value

    }
    { $_ -eq 'HPBIOS_BIOSInteger' } {
      $result = $obj.Value
    }
    { $_ -eq 'HPBIOS_BIOSEnumeration' } {
      $result = $obj.CurrentValue
    }
    { $_ -eq 'HPBIOS_BIOSPassword' } {
       throw [System.InvalidOperationException]"Password values cannot be retrieved, it will always result in an empty string"
    }
    { $_ -eq 'HPBIOS_BIOSOrderedList' } {
      $result = $obj.Value
    }
  }
  return $result
}

function getWmiField ($obj, $fn) { $obj.$fn }


# format a setting using BCU (custom) format
function convertSettingToBCU ($setting) {
  #if ($setting.DisplayInUI -eq 0) { return }
  switch ($setting.CimClass.CimClassName) {
    { $_ -eq 'HPBIOS_BIOSString' } {
      Write-Output $setting.Name

      if ($setting.Value.contains("`n")) {
        $setting.Value.split("`n") | ForEach-Object {
          $c = $_.trim()
          Write-Output "`t$c" }
      }
      else {
        Write-Output "`t$($setting.Value)"
      }

    }
    { $_ -eq 'HPBIOS_BIOSInteger' } {
      Write-Output $setting.Name
      Write-Output "`t$($setting.Value)"
    }
    { $_ -eq 'HPBIOS_BIOSPassword' } {
      Write-Output $setting.Name
      Write-Output ""
    }
    { $_ -eq 'HPBIOS_BIOSEnumeration' } {
      Write-Output $setting.Name
      $fields = $setting.Value.split(",")
      foreach ($f in $fields) {
        Write-Output "`t$f"
      }
    }
    { $_ -eq 'HPBIOS_BIOSOrderedList' } {
      Write-Output $setting.Name
      $fields = $setting.Value.split(",")
      foreach ($f in $fields) {
        Write-Output "`t$f"
      }
    }
  }
}

function formatBiosVersionsOutputList ($doc) {
  switch ($format) {
    "json" { return $doc | ConvertTo-Json }
    "xml" {
      Write-Output "<bios id=`"$platform`">"
      if ($all)
      {
      $doc | ForEach-Object { Write-Output "<item><ver>$($_.Ver)</ver><bin>$($_.bin)</bin><date>$($_.date)</date><rollback_allowed>$($_.RollbackAllowed)</rollback_allowed><importance>$($_.Importance)</importance></item>" }
      }
      else {
        $doc | ForEach-Object { Write-Output "<item><ver>$($_.Ver)</ver><bin>$($_.bin)</bin><date>$($_.date)</date></item>" }
      }
      Write-Output "</bios>"
      return
    }
    "csv" {
      return $doc | ConvertTo-Csv -NoTypeInformation 
    }
    "list" { $doc | ForEach-Object { Write-Output "$($_.Bin) version $($_.Ver.TrimStart("0")), released $($_.Date)" } }
    default { return $doc }
  }
}


# format a setting using HPIA (xml) format
function convertSettingToXML ($setting) {
  #if ($setting.DIsplayInUI -eq 0) { return }
  Write-Output " <BIOSSetting>"
  Write-Output " <Name>$([System.Web.HttpUtility]::HtmlEncode($setting.Name))</Name>"
  Write-Output " <Class>$($setting.CimClass.CimClassName)</Class>"
  Write-Output " <DisplayInUI>$($setting.DisplayInUI)</DisplayInUI>"
  Write-Output " <IsReadOnly>$($setting.IsReadOnly)</IsReadOnly>"
  Write-Output " <RequiresPhysicalPresence>$($setting.RequiresPhysicalPresence)</RequiresPhysicalPresence>"
  Write-Output " <Sequence>$($setting.Sequence)</Sequence>"

  switch ($setting.CimClass.CimClassName) {
    { $_ -eq 'HPBIOS_BIOSPassword' } {
      Write-Output " <Value></Value>"
      Write-Output " <Min>$($setting.MinLength)</Min>"
      Write-Output " <Max>$($setting.MaxLength)</Max>"

      Write-Output " <SupportedEncodings Count=""$($setting.SupportedEncoding.Count)"">"
      foreach ($e in $setting.SupportedEncoding) {
        Write-Output " <Encoding>$e</Encoding>"
      }
      Write-Output " </SupportedEncodings>"
    }

    { $_ -eq 'HPBIOS_BIOSString' } {
      Write-Output " <Value>$([System.Web.HttpUtility]::HtmlEncode($setting.Value))</Value>"
      Write-Output " <Min>$($setting.MinLength)</Min>"
      Write-Output " <Max>$($setting.MaxLength)</Max>"
    }

    { $_ -eq 'HPBIOS_BIOSInteger' } {
      Write-Output " <Value>$($setting.Value)</Value>"
      #Write-Output " <DisplayInUI>$($setting.DisplayInUI)</DisplayInUI>"
      Write-Output " <Min>$($setting.LowerBound)</Min>"
      Write-Output " <Max>$($setting.UpperBound)</Max>"
    }

    { $_ -eq 'HPBIOS_BIOSEnumeration' } {
      Write-Output " <Value>$([System.Web.HttpUtility]::HtmlEncode($setting.CurrentValue))</Value>"
      Write-Output " <ValueList Count=""$($setting.Size)"">"
      foreach ($e in $setting.PossibleValues) {
        Write-Output " <Value>$([System.Web.HttpUtility]::HtmlEncode($e))</Value>"
      }
      Write-Output " </ValueList>"
    }

    { $_ -eq 'HPBIOS_BIOSOrderedList' } {
      Write-Output " <Value>$([System.Web.HttpUtility]::HtmlEncode($setting.Value))</Value>"
      Write-Output " <ValueList Count=""$($setting.Size)"">"
      foreach ($e in $setting.Elements) {
        Write-Output " <Value>$([System.Web.HttpUtility]::HtmlEncode($e))</Value>"
      }
      Write-Output " </ValueList>"
    }
  }
  Write-Output " </BIOSSetting>"
}

function convertSettingToJSON ($original_setting) {
 
  $setting = $original_setting | select-object *
  
  if ($setting.CimClass.CimClassName -eq "HPBIOS_BIOSInteger") {
    $min = $setting.LowerBound
    $max = $setting.UpperBound
    Add-Member -InputObject $setting -Name "Min" -Value $min -MemberType NoteProperty
    Add-Member -InputObject $setting -Name "Max" -Value $max -MemberType NoteProperty
    
    $d = $setting | Select-Object -Property  Class, DisplayInUI, InstanceName, IsReadOnly, Min, Max, Name, Path, Prerequisites, PrerequisiteSize, RequiresPhysicalPresence, SecurityLevel, Sequence, Value
  }

  if (($setting.CimClass.CimClassName -eq "HPBIOS_BIOSString") -or ($setting.CimClass.CimClassName -eq "HPBIOS_BIOSPassword")) {
    $min = $setting.MinLength
    $max = $setting.MaxLength
    Add-Member -InputObject $setting -Name "Min" -Value $min -MemberType NoteProperty -Force
    Add-Member -InputObject $setting -Name "Max" -Value $max -MemberType NoteProperty -Force
    $d = $setting | Select-Object -Property Class, DisplayInUI, InstanceName, IsReadOnly, Min, Max, Name, Path, Prerequisites, PrerequisiteSize, RequiresPhysicalPresence, SecurityLevel, Sequence, Value
  }

  if ($setting.CimClass.CimClassName -eq "HPBIOS_BIOSEnumeration") {
    $min = $setting.Size
    $max = $setting.Size
    #Add-Member -InputObject $setting -Name "Min" -Value $min -MemberType NoteProperty
    #Add-Member -InputObject $setting -Name "Max" -Value $max -MemberType NoteProperty
    $setting.Value = $setting.CurrentValue
    $d = $setting | Select-Object -Property Class, DisplayInUI, InstanceName, IsReadOnly, Min, Max, Name, Path, Prerequisites, PrerequisiteSize, RequiresPhysicalPresence, SecurityLevel, Sequence, Value, PossibleValues
  }

  if ($setting.CimClass.CimClassName -eq "HPBIOS_BIOSOrderedList") {
    $min = $setting.Elements.Count
    $max = $setting.Elements.Count
    Add-Member -InputObject $setting -Name "Min" -Value $min -MemberType NoteProperty
    Add-Member -InputObject $setting -Name "Max" -Value $max -MemberType NoteProperty
    Add-Member -InputObject $setting -Name "PossibleValues" -Value $setting.Elements -MemberType NoteProperty
    $d = $setting | Select-Object -Property Class, DisplayInUI, InstanceName, IsReadOnly, Min, Max, Name, Path, Prerequisites, PrerequisiteSize, RequiresPhysicalPresence, SecurityLevel, Sequence, Value, Elements
  }
  

  
  $d | ConvertTo-Json -Depth 5 | Write-Output
}

# format a setting as a CSV entry
function convertSettingToCSV ($setting) {
  switch ($setting.CimClass.CimClassName) {
    { $_ -eq 'HPBIOS_BIOSEnumeration' } {
      Write-Output "`"$($setting.Name)`",`"$($setting.value)`",$($setting.IsReadOnly),`"picklist`",$($setting.RequiresPhysicalPresence),$($setting.Size),$($setting.Size)"
    }
    { $_ -eq 'HPBIOS_BIOSString' } {
      Write-Output "`"$($setting.Name)`",`"$($setting.value)`",$($setting.IsReadOnly),`"string`",$($setting.RequiresPhysicalPresence),$($setting.MinLength),$($setting.MaxLength)"
    }
    { $_ -eq 'HPBIOS_BIOSPassword' } {
      Write-Output "`"$($setting.Name)`",`"`",$($setting.IsReadOnly),`"password`",$($setting.RequiresPhysicalPresence),$($setting.MinLength),$($setting.MaxLength)"
    }
    { $_ -eq 'HPBIOS_BIOSInteger' } {
      Write-Output "`"$($setting.Name)`",`"$($setting.value)`",$($setting.IsReadOnly),`"integer`",$($setting.RequiresPhysicalPresence),$($setting.LowerBound),$($setting.UpperBound)"
    }
    { $_ -eq 'HPBIOS_BIOSOrderedList' } {
      Write-Output "`"$($setting.Name)`",`"$($setting.value)`",$($setting.IsReadOnly),`"orderedlist`",$($setting.RequiresPhysicalPresence),$($setting.Size),$($setting.Size)"
    }
  }
}

function biosErrorCodesToString ($code) {
  switch ($code) {
    0 { return "OK" }
    1 { return "Not Supported" }
    2 { return "Unspecified error" }
    3 { return "Operation timed out" }
    4 { return "Operation failed or setting name is invalid" }
    5 { return "Invalid parameter" }
    6 { return "Access denied or incorrect password" }
    7 { return "Bios user already exists" }
    8 { return "Bios user not present" }
    9 { return "Bios user name too long" }
    10 { return "Password policy not met" }
    11 { return "Invalid keyboard layout" }
    12 { return "Too many users" }
    32768 { return "Security or password policy not met" }
    default { return "Unknown error: $code" }
  }
}

function getBiosSettingInterface {
  [CmdletBinding(DefaultParameterSetName = 'nNwSession')]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $false)] 
    [string]$Target = ".",
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [CimSession]$CimSession
  )
  $defaultAction = $ErrorActionPreference
  $ns = getNamespace
  $ErrorActionPreference = "Stop";

  try {
    Write-Verbose "Getting BIOS interface from '$target' for namespace '$ns'"
    $params = @{
      Namespace = $ns   
      Class     = "HPBIOS_BIOSSettingInterface"   
    }

    if ($CimSession) {
      $params.add("CimSession", $CimSession)
    }

    if ($Target -and ($target -ne ".") -and -not $CimSession) {
      $params.add("ComputerName", $Target)
    }


    $result = Get-CimInstance @params -ErrorAction stop
    if (-not $result) { throw [System.EntryPointNotFoundException]"Setting interface not found" }
  }
  catch {
    Write-Error "Method failed: $($_.Exception.Message)" -ErrorAction stop
  }
  finally {
    $ErrorActionPreference = $defaultAction
  }
  $result
}

function getNamespace {
  [CmdletBinding()]
  param()
  [string]$c = [environment]::GetEnvironmentVariable("HP_BIOS_NAMESPACE", "User")
  if (-not $c) {
    return "root\HP\InstrumentedBIOS"
  }
  Write-Verbose ("Default BIOS namespace is overwritten via HP_BIOS_NAMESPACE Variable, to $c. This should only happen during development.")
  return $c
}

function setWriteableSetting {
  [CmdletBinding(DefaultParameterSetName = 'NewSession')]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $true)] 
    $Name,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $true)] 
    [AllowEmptyString()]
    $Value,
    [Parameter(ParameterSetName = 'NewSession', Position = 2, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 2, Mandatory = $false)]    
    $Password,
    [Parameter(ParameterSetName = 'NewSession', Position = 3, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 3, Mandatory = $false)]    
    $ErrorHandling = 0,
    [Parameter(ParameterSetName = 'NewSession', Position = 4, Mandatory = $false)]     
    [string]$Target = ".",
    [Parameter(ParameterSetName = 'NewSession', Position = 5, Mandatory = $true)]     
    [CimSession]$CimSession
  )
  $readonly = 0
  $notfound = 0
  $alreadyset = 0

  $setting = $null
  try {

    $params = @{ Name = $Name }
    if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
    if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }
  
    $setting = Get-HPBIOSSetting @params -ErrorAction stop
  }
  catch {
    $notfound = 1
    $err = $PSItem.ToString()

    Write-Verbose "'$name': $err"
    switch ($ErrorHandling) {
      0 { throw $PSItem }
      1 { Write-Host -ForegroundColor Yellow $err }
      2 { Write-Verbose "Setting '$Name' could not be set, but ErrorHandling was set to 2 so error is quietly ignored" }
    }
    return $readonly, $notfound, $alreadyset
  }

  if ($setting) {
    switch ($setting.CimClass.CimClassName) {
      "HPBIOS_BIOSEnumeration" {
        if ($setting.CurrentValue -eq $Value) { $alreadyset = 1 } 
      }
      default { if ($setting.Value -eq $Value) { $alreadyset = 1 } }
    }

    if ($alreadyset -eq $false) {
      if ($setting.IsReadOnly -eq 1) { $readonly = 1 }
      else { 
        
        $params = @{ Name = $Name; Value = $Value; Password = $Password }
        if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $params.CimSession = newCimSession -target $ComputerName }
        if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $params.CimSession = $CimSession }      
        Set-HPBIOSSettingValue @params
      }
    }
  }

  return $readonly, $notfound, $alreadyset
}


function setSettingsFromJson {
  [CmdletBinding(DefaultParameterSetName = 'NewSession')]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $true)] 
    $File,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $false)] 
    $Password,
    [Parameter(ParameterSetName = 'NewSession', Position = 2, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 2, Mandatory = $false)] 
    $ErrorHandling = 0,
    [Parameter(ParameterSetName = 'NewSession', Position = 3, Mandatory = $false)] 
    [string]$Target = ".",
    [Parameter(ParameterSetName = 'NewSession', Position = 4, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 4, Mandatory = $false)] 
    [switch]$PassThru,
    [Parameter(ParameterSetName = 'ReuseSession', Position = 5, Mandatory = $true)] 
    [CimSession]$CimSession    
  )
  if (-not $PassThru.IsPresent) { $ctr = @(0, 0, 0, 0) }
  else { $ctr = New-Object System.Collections.ArrayList }
  Write-Verbose "Reading from file JSON: $File"
  $settings = Get-Content -Raw -Path $File | ConvertFrom-Json

  foreach ($setting in $settings) {
    if ($Passthru.IsPresent) {
      $ctr.Add( (New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $setting.Name; Value = $setting.Value })) | Out-Null
    }
    else {
      $ctr[0]++
      $set = @{
        Name          = $setting.Name
        Value         = $setting.Value
        Password      = $Password
        ErrorHandling = $ErrorHandling
      }
      if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $set.CimSession = newCimSession -target $ComputerName }
      if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $set.CimSession = $CimSession }   
      $c = setWriteableSetting @set
      $ctr[1] += $c[0]
      $ctr[2] += $c[1]
      $ctr[3] += $c[2]  
    }
  }
  return $ctr
}
function setSettingsFromCsv {
  [CmdletBinding(DefaultParameterSetName = 'NewSession')]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $true)] 
    $File,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $false)] 
    $Password,
    [Parameter(ParameterSetName = 'NewSession', Position = 2, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 2, Mandatory = $false)] 
    $ErrorHandling = 0,
    [Parameter(ParameterSetName = 'NewSession', Position = 3, Mandatory = $false)] 
    [string]$Target = ".",
    [Parameter(ParameterSetName = 'NewSession', Position = 4, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 4, Mandatory = $false)] 
    [switch]$PassThru,
    [Parameter(ParameterSetName = 'ReuseSession', Position = 5, Mandatory = $true)] 
    [CimSession]$CimSession    
  )
  if (-not $PassThru.IsPresent) { $ctr = @(0, 0, 0, 0) }
  else { $ctr = New-Object System.Collections.ArrayList }
  
  Write-Verbose "Reading from CSV file: $File"
  $settings = Get-Content -Raw -Path $File | ConvertFrom-Csv
  
  foreach ($setting in $settings) {
    if ($Passthru.IsPresent) {
      $ctr.Add( (New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $setting.Name; Value = $setting.CURRENT_VALUE })) | Out-Null
    }
    else {
      $ctr[0]++
      $set = @{
        Name          = $setting.Name
        Value         = $setting.CURRENT_VALUE
        Password      = $Password
        ErrorHandling = $ErrorHandling
      }
      if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $set.CimSession = newCimSession -target $ComputerName }
      if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $set.CimSession = $CimSession }   
      $c = setWriteableSetting @set
      $ctr[1] += $c[0]
      $ctr[2] += $c[1]
      $ctr[3] += $c[2]  
    }
  }
  return $ctr

}


function setSettingsFromXml {
  [CmdletBinding(DefaultParameterSetName = 'NewSession')]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $true)] 
    $File,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $false)] 
    $Password,
    [Parameter(ParameterSetName = 'NewSession', Position = 2, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 2, Mandatory = $false)] 
    $ErrorHandling = 0,
    [Parameter(ParameterSetName = 'NewSession', Position = 3, Mandatory = $false)] 
    [string]$Target = ".",
    [Parameter(ParameterSetName = 'NewSession', Position = 4, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 4, Mandatory = $false)] 
    [switch]$PassThru,
    [Parameter(ParameterSetName = 'ReuseSession', Position = 5, Mandatory = $true)] 
    [CimSession]$CimSession    
  )


  if (-not $PassThru.IsPresent) { $ctr = @(0, 0, 0, 0) }
  else { $ctr = New-Object System.Collections.ArrayList }
  
  Write-Verbose "Reading from XML file: $File"
  [xml]$settings = Get-Content -Path $File


  try {
    foreach ($setting in $settings.ImagePal.BIOSsettings.BIOSsetting) {
      if ($Passthru.IsPresent) {
        $ctr.Add( (New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $setting.Name; Value = $setting.Value })) | Out-Null
      }
      else {
        $ctr[0]++
        $set = @{
          Name          = $setting.Name
          Value         = $setting.Value
          Password      = $Password
          ErrorHandling = $ErrorHandling
        }
        if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $set.CimSession = newCimSession -target $ComputerName }
        if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $set.CimSession = $CimSession }   
        $c = setWriteableSetting @set
        $ctr[1] += $c[0]
        $ctr[2] += $c[1]
        $ctr[3] += $c[2]  
      }
    }
  }
  catch [System.Management.Automation.PropertyNotFoundException] {
    throw [System.FormatException]'Invalid XML file.'
  }
  return $ctr
}

function setSettingsFromBcu {
  [CmdletBinding(DefaultParameterSetName = 'NewSession')]
  param(
    [Parameter(ParameterSetName = 'NewSession', Position = 0, Mandatory = $true)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 0, Mandatory = $true)] 
    $File,
    [Parameter(ParameterSetName = 'NewSession', Position = 1, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 1, Mandatory = $false)] 
    $Password,
    [Parameter(ParameterSetName = 'NewSession', Position = 2, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 2, Mandatory = $false)] 
    $ErrorHandling = 0,
    [Parameter(ParameterSetName = 'NewSession', Position = 3, Mandatory = $false)] 
    [string]$Target = ".",
    [Parameter(ParameterSetName = 'NewSession', Position = 4, Mandatory = $false)] 
    [Parameter(ParameterSetName = 'ReuseSession', Position = 4, Mandatory = $false)] 
    [switch]$PassThru,
    [Parameter(ParameterSetName = 'ReuseSession', Position = 5, Mandatory = $true)] 
    [CimSession]$CimSession    
  )

  if (-not $PassThru.IsPresent) { $ctr = @(0, 0, 0, 0) }
  else { $ctr = New-Object System.Collections.ArrayList }


  $list = @{ }
  $currset = ""

  Write-Verbose "Reading from file: $File"
  switch -regex -File $File {
    '^\S.*$' {

      $currset = $matches[0].trim()
      if ($currset -ne "BIOSConfig 1.0") {
        if (-not $currset.StartsWith(";")) {
          $list[$currset] = New-Object System.Collections.Generic.List[System.String]
        }
      }
    }

    '^\s.*$' {
      # value (indented)
      $c = $matches[0].trim()

      if (-not $c.StartsWith(";")) {
        $list[$currset].Add($c)
      }

    }
  }

  foreach ($setting in $list.keys) {

    ## string or int
    $desired = $null

    foreach ($v in $list[$setting]) {
      if ($v.StartsWith("*")) {
        # enum
        $desired = $v.substring(1)
        break
      }
    }

    if (-not $desired) {
      # not an enum
      if ($list[$setting].Count -eq 1) {
        $desired = $list[$setting] # a string or int
      }
      else {
        $desired = $list[$setting] -join ',' # an ordered list
      }
    }

    if ($Passthru.IsPresent) {
      $ctr.Add( (New-Object PSObject -Property @{ Type = "hp:sureadmin:bios_setting"; Name = $setting; Value = $desired[0] })) | Out-Null

    }
    else {
      $ctr[0]++
            
      $set = @{
        Name          = $setting
        Value         = $desired[0]
        Password      = $Password
        ErrorHandling = $ErrorHandling
      }
      if ($PSCmdlet.ParameterSetName -eq 'NewSession' ) { $set.CimSession = newCimSession -target $ComputerName }
      if ($PSCmdlet.ParameterSetName -eq 'ReuseSession' ) { $set.CimSession = $CimSession }   
      $c = setWriteableSetting @set
      $ctr[1] += $c[0]
      $ctr[2] += $c[1]
      $ctr[3] += $c[2]  
    }

  }

  return $ctr
}

function extractBIOSVersion {
  [CmdletBinding()]
  param
  (
    [Parameter(Position = 0, Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string]$BIOSVersion

  )
  [string]$ver = $null

  # Does the BIOS version string contains x.xx[.xx]?
  [bool]$found = $BIOSVersion -match '(\d+(\.\d+){1,2})'
  if ($found) {
    $ver = $matches[1]
    Write-Verbose "BIOS version extracted=[$ver]"
  }

  $ver
}

function newCimSession() {
  [CmdletBinding()]
  param
  (
    [Parameter(Position = 0)] $SkipTestConnection = $true,
    [Parameter(Position = 1)] $Protocol = 'DCOM',
    [Parameter(Position = 2)] $target = '.',
    [Parameter(Position = 3)] $SessionName = 'CMSLCimSession'
  )
  
  Write-Verbose "Creating new CimSession (Protocol= $Protocol, Computer=$Target)"
  $opts = New-CimSessionOption -Protocol $Protocol

  $params = @{
    Name               = $SessionName
    SkipTestConnection = $SkipTestConnection
    SessionOption      = $opts
  }
  if ($Target -and ($Target -ne ".")) {
    $params.add("ComputerName", $target)
  }
  New-CimSession @params  

}




# SIG # Begin signature block
# MIIcOAYJKoZIhvcNAQcCoIIcKTCCHCUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAv4ndVKiIfTwDW
# IOdXvQYPf0+gt70MZFdaWFvwT8TlPqCCCo0wggU2MIIEHqADAgECAhAM1s71mz4i
# 3j/UnuaI4vzeMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xNTAzBgNV
# BAMTLERpZ2lDZXJ0IFNIQTIgSGlnaCBBc3N1cmFuY2UgQ29kZSBTaWduaW5nIENB
# MB4XDTE5MDQyMjAwMDAwMFoXDTIwMDQyOTEyMDAwMFowdTELMAkGA1UEBhMCVVMx
# EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEQMA4GA1UE
# ChMHSFAgSW5jLjEZMBcGA1UECxMQSFAgQ3liZXJzZWN1cml0eTEQMA4GA1UEAxMH
# SFAgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANEwuTFpw7fQ
# 3Ds5fvexal46Gg9TNMvdiJu7qMqDZnDJNl7ECdEPyLxsioGS7/yomOS9RXdXMJOm
# tyV4/wIPbBaGC8E2tbLTbQQ4IJbgvC+Vc46vbo+sI8YTG6qBICOovFw9VhUNXXEy
# SwHMoBNk8JS8R1slPpJKmNGB10HSatMGaHja0Lbqos0QuEx/tx2OXe+mzepIo66T
# dtSv2MfPy2tcVcXIdiJGn7f4otxoj6T9X7hVIl78r5Y2XWHYtDK8KaV1E/qkiNXK
# 1Xw5S53zv2VsZl6i1LZwt3d1Q9pUmm1AZe2YdhSGvwMP2LYBJGXIBbyLYnxS4HKB
# R7MYZyz7H2kCAwEAAaOCAb8wggG7MB8GA1UdIwQYMBaAFGedDyAJDMyKOuWCRnJi
# /PHMkOVAMB0GA1UdDgQWBBSnSAWgK15kcBLxsg4XNsT7ncH29zAOBgNVHQ8BAf8E
# BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwbQYDVR0fBGYwZDAwoC6gLIYqaHR0
# cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItaGEtY3MtZzEuY3JsMDCgLqAshipo
# dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1jcy1nMS5jcmwwTAYDVR0g
# BEUwQzA3BglghkgBhv1sAwswKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln
# aWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYgGCCsGAQUFBwEBBHwwejAkBggrBgEF
# BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFIGCCsGAQUFBzAChkZodHRw
# Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5j
# ZUNvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD
# ggEBAJQblkFw+UYKYSY2M/CIEpJxZDnf+cDhodKAy+goI3XfExRHhyLu3Gc2ibFB
# Y4wyz/sJSfHehtNPYckXxR9k/FB/GfYtEACug9xXxJ+iLxWUNQ4KPt3bXY/kmDxW
# D1QXJFLbW5Dop3w/K0DL3fxnjOfYCcxsYodbeEiCJprCdNi3zd6x/J8Y35GDbLA5
# p7RfIAzKrmBLPHFGDWr/jWTfwPfUNz6jYJ51m0Ba9j81kzpxNUD0yBIZXBkVvSkx
# A09KxzMSSvxvV9DSqSezQBVgWnl9TbElouYUQwk64i0GzL4lTsphK4rQJJ2uuKtH
# wN4E0ibpm0uIqbLhgk+3ic8fHTIwggVPMIIEN6ADAgECAhALfhCQPDhJD/ovZ5qH
# oae5MA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp
# Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzApBgNVBAMTIkRp
# Z2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIEVWIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAw
# WhcNMjgxMDIyMTIwMDAwWjB2MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl
# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTUwMwYDVQQDEyxEaWdp
# Q2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIENvZGUgU2lnbmluZyBDQTCCASIwDQYJ
# KoZIhvcNAQEBBQADggEPADCCAQoCggEBALRKXn0HD0HexPV2Fja9cf/PP09zS5zR
# Df5Ky1dYXoUW3QIVVJnwjzwvTQJ4EGjI2DVLP8H3Z86YHK4zuS0dpApUk8SFot81
# sfXxPKezNPtdSMlGyWJEvEiZ6yhJU8M9j8AO3jWY6WJR3z1rQGHuBEHaz6dcVpbR
# +Uy3RISHmGnlgrkT5lW/yJJwkgoxb3+LMqvPa1qfYsQ+7r7tWaRTfwvxUoiKewpn
# JMuQzezSTTRMsOG1n5zG9m8szebKU3QBn2c13jhJLc7tOUSCGXlOGrK1+7t48Elm
# p8/6XJZ1kosactn/UJJTzD7CQzIJGoYTaTz7gTIzMmR1cygmHQgwOwcCAwEAAaOC
# AeEwggHdMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMDMH8GCCsGAQUFBwEBBHMwcTAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuZGlnaWNlcnQuY29tMEkGCCsGAQUFBzAChj1odHRwOi8vY2FjZXJ0
# cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0
# MIGPBgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9j
# cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5j
# cmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBz
# Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYDVR0OBBYEFGed
# DyAJDMyKOuWCRnJi/PHMkOVAMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9j
# ZCvDMA0GCSqGSIb3DQEBCwUAA4IBAQBqDv9+E3wGpUvALoz5U2QJ4rpYkTBQ7Myf
# 4dOoL0hGNhgp0HgoX5hWQA8eur2xO4dc3FvYIA3tGhZN1REkIUvxJ2mQE+sRoQHa
# /bVOeVl1vTgqasP2jkEriqKL1yxRUdmcoMjjTrpsqEfSTtFoH4wCVzuzKWqOaiAq
# ufIAYmS6yOkA+cyk1LqaNdivLGVsFnxYId5KMND66yRdBsmdFretSkXTJeIM8ECq
# XE2sfs0Ggrl2RmkI2DK2gv7jqVg0QxuOZ2eXP2gxFjY4lT6H98fDr516dxnZ3pO1
# /W4r/JT5PbdMEjUsML7ojZ4FcJpIE/SM1ucerDjnqPOtDLd67GftMYIRATCCEP0C
# AQEwgYowdjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG
# A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTE1MDMGA1UEAxMsRGlnaUNlcnQgU0hBMiBI
# aWdoIEFzc3VyYW5jZSBDb2RlIFNpZ25pbmcgQ0ECEAzWzvWbPiLeP9Se5oji/N4w
# DQYJYIZIAWUDBAIBBQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMx
# DAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkq
# hkiG9w0BCQQxIgQgJ4oyyQQbxnGv5TWifUcw3nbf/EJrZCLdlbWVgbByQa4wDQYJ
# KoZIhvcNAQEBBQAEggEAfdpFS/K1XMuzk2np3rR20qwxrVS4T471hwMfu3JLKtxC
# bqH2awhfSRUdLhKe86Kx6Hv0mW9C7M+fleKPvoUM93vaqIlPbLwhe01qCmTRlQv0
# JeOERKjmsoXcrRcH7o0iXSl49VU54q3AclrX5CvkzGFW6xUqpD7XJfFWvWWq9XQD
# g0EmG5XqtdIe3pljuec2jjHQ3TjvoWlmSijI44Q6T3qaIzQYbR7Bob28m26YwHgk
# +f2CBuqnMRtQ9iHf/uPQAp77VpL3YFvSoNY9pqrMq54OtZks0qX/RqJWdpoql9X8
# QWMO3s9JJvgqFVcS9xyePAwm+IaoIMerrEOtA4V3MqGCDskwgg7FBgorBgEEAYI3
# AwMBMYIOtTCCDrEGCSqGSIb3DQEHAqCCDqIwgg6eAgEDMQ8wDQYJYIZIAWUDBAIB
# BQAweAYLKoZIhvcNAQkQAQSgaQRnMGUCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFl
# AwQCAQUABCDbaRjsmw97LZ/AoDEwxejbix70tNRcYkMbMfZLcXFPKgIRAIdgx39U
# uDAhK+3p5SykmQ4YDzIwMjAwMjE0MjI0OTE1WqCCC7swggaCMIIFaqADAgECAhAE
# zT+FaK52xhuw/nFgzKdtMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUw
# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
# MTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcg
# Q0EwHhcNMTkxMDAxMDAwMDAwWhcNMzAxMDE3MDAwMDAwWjBMMQswCQYDVQQGEwJV
# UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJDAiBgNVBAMTG1RJTUVTVEFNUC1T
# SEEyNTYtMjAxOS0xMC0xNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
# AOlkNZz6qZhlZBvkF9y4KTbMZwlYhU0w4Mn/5Ts8EShQrwcx4l0JGML2iYxpCAQj
# 4HctnRXluOihao7/1K7Sehbv+EG1HTl1wc8vp6xFfpRtrAMBmTxiPn56/UWXMbT6
# t9lCPqdVm99aT1gCqDJpIhO+i4Itxpira5u0yfJlEQx0DbLwCJZ0xOiySKKhFKX4
# +uGJcEQ7je/7pPTDub0ULOsMKCclgKsQSxYSYAtpIoxOzcbVsmVZIeB8LBKNcA6P
# isrg09ezOXdQ0EIsLnrOnGd6OHdUQP9PlQQg1OvIzocUCP4dgN3Q5yt46r8fcMbu
# QhZTNkWbUxlJYp16ApuVFKMCAwEAAaOCAzgwggM0MA4GA1UdDwEB/wQEAwIHgDAM
# BgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIB
# tjCCAbIwggGhBglghkgBhv1sBwEwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3
# dy5kaWdpY2VydC5jb20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAg
# AHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAg
# AGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABv
# AGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBu
# AGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBl
# AGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBs
# AGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBk
# ACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCG
# SAGG/WwDFTAfBgNVHSMEGDAWgBT0tuEgHf4prtLkYaWyoiWyyBc1bjAdBgNVHQ4E
# FgQUVlMPwcYHp03X2G5XcoBQTOTsnsEwcQYDVR0fBGowaDAyoDCgLoYsaHR0cDov
# L2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmwwMqAwoC6GLGh0
# dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtdHMuY3JsMIGFBggr
# BgEFBQcBAQR5MHcwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv
# bTBPBggrBgEFBQcwAoZDaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lD
# ZXJ0U0hBMkFzc3VyZWRJRFRpbWVzdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsF
# AAOCAQEALoOhRAVKBOO5MlL62YHwGrv4CY0juT3YkqHmRhxKL256PGNuNxejGr9Y
# I7JDnJSDTjkJsCzox+HizO3LeWvO3iMBR+2VVIHggHsSsa8Chqk6c2r++J/BjdEh
# jOQpgsOKC2AAAp0fR8SftApoU39aEKb4Iub4U5IxX9iCgy1tE0Kug8EQTqQk9Eec
# 3g8icndcf0/pOZgrV5JE1+9uk9lDxwQzY1E3Vp5HBBHDo1hUIdjijlbXST9X/Aqf
# I1579JSN3Z0au996KqbSRaZVDI/2TIryls+JRtwxspGQo18zMGBV9fxrMKyh7eRH
# TjOeZ2ootU3C7VuXgvjLqQhsUwm09zCCBTEwggQZoAMCAQICEAqhJdbWMht+QeQF
# 2jaXwhUwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERp
# Z2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMb
# RGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTE2MDEwNzEyMDAwMFoXDTMx
# MDEwNzEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu
# YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQg
# U0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQTCCASIwDQYJKoZIhvcNAQEB
# BQADggEPADCCAQoCggEBAL3QMu5LzY9/3am6gpnFOVQoV7YjSsQOB0UzURB90Pl9
# TWh+57ag9I2ziOSXv2MhkJi/E7xX08PhfgjWahQAOPcuHjvuzKb2Mln+X2U/4Jvr
# 40ZHBhpVfgsnfsCi9aDg3iI/Dv9+lfvzo7oiPhisEeTwmQNtO4V8CdPuXciaC1Tj
# qAlxa+DPIhAPdc9xck4Krd9AOly3UeGheRTGTSQjMF287DxgaqwvB8z98OpH2YhQ
# Xv1mblZhJymJhFHmgudGUP2UKiyn5HU+upgPhH+fMRTWrdXyZMt7HgXQhBlyF/EX
# Bu89zdZN7wZC/aJTKk+FHcQdPK/P2qwQ9d2srOlW/5MCAwEAAaOCAc4wggHKMB0G
# A1UdDgQWBBT0tuEgHf4prtLkYaWyoiWyyBc1bjAfBgNVHSMEGDAWgBRF66Kv9JLL
# gjEtUYunpyGd823IDzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIB
# hjATBgNVHSUEDDAKBggrBgEFBQcDCDB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUH
# MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDov
# L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNy
# dDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBQBgNVHSAESTBH
# MDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl
# cnQuY29tL0NQUzALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggEBAHGVEulR
# h1Zpze/d2nyqY3qzeM8GN0CE70uEv8rPAwL9xafDDiBCLK938ysfDCFaKrcFNB1q
# rpn4J6JmvwmqYN92pDqTD/iy0dh8GWLoXoIlHsS6HHssIeLWWywUNUMEaLLbdQLg
# cseY1jxk5R9IEBhfiThhTWJGJIdjjJFSLK8pieV4H9YLFKWA1xJHcLN11ZOFk362
# kmf7U2GJqPVrlsD0WGkNfMgBsbkodbeZY4UijGHKeZR+WfyMD+NvtQEmtmyl7odR
# IeRYYJu6DC0rbaLEfrvEJStHAgh8Sa4TtuF8QkIoxhhWz0E0tmZdtnR79VYzIi8i
# NrJLokqV2PWmjlIxggJNMIICSQIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYD
# VQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBAhAE
# zT+FaK52xhuw/nFgzKdtMA0GCWCGSAFlAwQCAQUAoIGYMBoGCSqGSIb3DQEJAzEN
# BgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjAwMjE0MjI0OTE1WjArBgsq
# hkiG9w0BCRACDDEcMBowGDAWBBQDJb1QXtqWMC3CL0+gHkwovig0xTAvBgkqhkiG
# 9w0BCQQxIgQgjvMY5Qute2lFibOl1AIUX8w8/5+qngXjzYKfpQKUne8wDQYJKoZI
# hvcNAQEBBQAEggEA4zXCCocrPkE0T3LxfTA8vJCVR9OJcY4nczfFqEn3egsTSty4
# QVhHW5/0WUYhli1X526wSdyrSOc6xefhPELcmwn4b1txYNOqhE+zn/DvalLAQC21
# qsY/8UFV1OlYYaIZ4gYlUdjUTGDtN6VheTttuwdYpcf7rHmPwyweXL/Dk5qY1hjJ
# vKpREql7xKaiVG+6qv3C/T7705dSXwJuZorJTM6ZRPUV2HgbBHKrz4qU6iRU9R3R
# bqWPAJjUzfJ9qtIYzZQxmFTZgtkLAjmhFjwo+9wPAq/kOgIbxQmMt6qdfpD+Qk2L
# KRg3irXmr2y7wvMRq5Q/XgBGHyw1mDR6hPGD4Q==
# SIG # End signature block