HP.ClientManagement.psm1
# # Copyright 2018-2022 HP Development Company, L.P. # All Rights Reserved. # # NOTICE: All information contained herein is, and remains the property of HP Development Company, L.P. # # The intellectual and technical concepts contained herein are proprietary to HP Development Company, L.P # and may be covered by U.S. and Foreign Patents, patents in process, and are protected by # trade secret or copyright law. Dissemination of this information or reproduction of this material # is strictly forbidden unless prior written permission is obtained from HP Development Company, L.P. Add-Type -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 not specified, the 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-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 Required HP BIOS. .EXAMPLE Get-HPBIOSSetting -Name "Serial Number" -Format BCU #> function Get-HPBIOSSetting { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPBIOSSetting")] 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 via standard OS providers .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-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-HPDeviceUUID #> function Get-HPDeviceUUID () { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPDeviceUUID")] 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 from the BIOS .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-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-HPBIOSUUID #> function Get-HPBIOSUUID { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPBIOSUUID")] 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] $raw[6],$raw[7] = $raw[7],$raw[6] 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-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-HPBIOSVersion #> function Get-HPBIOSVersion { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPBIOSVersion")] 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-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-HPBIOSAuthor #> function Get-HPBIOSAuthor { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPBIOSAuthor")] 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-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. .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-HPDeviceManufacturer")] 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-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-HPDeviceSerialNumber #> function Get-HPDeviceSerialNumber { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPDeviceSerialNumber")] 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. .DESCRIPTION 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-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-HPDeviceModel #> function Get-HPDeviceModel { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPDeviceModel")] 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-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. .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-HPDevicePartNumber")] 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-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-HPDeviceProductID #> function Get-HPDeviceProductID { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPDeviceProductID")] 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 pre-populated with the serial number value. .PARAMETER ComputerName Alias -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-HPDeviceAssetTag #> function Get-HPDeviceAssetTag { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPDeviceAssetTag")] 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 ComputerName Alias -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 'Asset Tracking Number' #> function Get-HPBIOSSettingValue { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPBIOSSettingValue")] 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 * JSON: format as JSON * 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, note 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-HPBIOSSettingsList")] 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 This is a private function for internal use only .DESCRIPTION This is a private function for internal use only .EXAMPLE .NOTES - This is a private function for internal use only #> function Set-HPPrivateBIOSSettingValuePayload { param( [Parameter(ParameterSetName = 'Payload',Position = 0,Mandatory = $true,ValueFromPipeline = $true)] [string]$Payload ) $portable = $Payload | ConvertFrom-Json if ($portable.purpose -ne "hp:sureadmin:biossetting") { throw "The payload should be generated by New-HPSureAdminBIOSSettingValuePayload function" } [SureAdminSetting]$setting = [System.Text.Encoding]::UTF8.GetString($portable.Data) | ConvertFrom-Json Set-HPPrivateBIOSSetting -Setting $setting } <# .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 constraints 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 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". .EXAMPLE Set-HPBIOSSettingValue -Name "Asset Tracking Number" -Value "Hello World" -password 's3cr3t' #> function Set-HPBIOSSettingValue { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Set-HPBIOSSettingValue")] param( [Parameter(ParameterSetName = "NewSession",Position = 0,Mandatory = $false)] [Parameter(ParameterSetName = "ReuseSession",Position = 0,Mandatory = $false)] [AllowEmptyString()] [string]$Password, [Parameter(ParameterSetName = "NewSession",Position = 1,Mandatory = $true)] [Parameter(ParameterSetName = "ReuseSession",Position = 1,Mandatory = $true)] [string]$Name, [Parameter(ParameterSetName = "NewSession",Position = 2,Mandatory = $true)] [Parameter(ParameterSetName = "ReuseSession",Position = 2,Mandatory = $true)] [AllowEmptyString()] [string]$Value, [Parameter(ParameterSetName = "NewSession",Position = 3,Mandatory = $false)] [Parameter(ParameterSetName = "ReuseSession",Position = 3,Mandatory = $false)] [switch]$SkipPrecheck, [Parameter(ParameterSetName = 'NewSession',Position = 4,Mandatory = $false)] [Alias('Target')] $ComputerName = ".", [Parameter(ParameterSetName = 'ReuseSession',Position = 4,Mandatory = $true)] [CimSession]$CimSession ) [SureAdminSetting]$setting = New-Object -TypeName SureAdminSetting $setting.Name = $Name $setting.Value = $Value $params = @{ Setting = $setting Password = $Password CimSession = $CimSession ComputerName = $ComputerName SkipPrecheck = $SkipPrecheck } Set-HPPrivateBIOSSetting @params } <# .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. .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-HPBIOSSetupPasswordIsSet")] 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 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-HPBIOSSetupPassword")] param( [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 0,Mandatory = $true)] [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 0,Mandatory = $true)] [string]$NewPassword, [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 1,Mandatory = $false)] [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 1,Mandatory = $false)] [string]$Password, [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 2,Mandatory = $false)] [Alias('Target')] [string]$ComputerName = ".", [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 3,Mandatory = $true)] [CimSession]$CimSession ) $params = @{} $settingName = 'Setup Password' 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 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 -Password '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-HPBIOSSetupPassword")] param( [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 0,Mandatory = $true)] [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 0,Mandatory = $true)] [string]$Password, [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 1,Mandatory = $false)] [Alias('Target')] $ComputerName = ".", [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 2,Mandatory = $true)] [CimSession]$CimSession ) $settingName = 'Setup Password' $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-HPBIOSPowerOnPasswordIsSet")] 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-HPBIOSPowerOnPassword")] param( [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 0,Mandatory = $true)] [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 0,Mandatory = $true)] [string]$NewPassword, [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 1,Mandatory = $false)] [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 1,Mandatory = $false)] [string]$Password, [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 3,Mandatory = $false)] [Alias('Target')] [string]$ComputerName = ".", [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 4,Mandatory = $true)] [CimSession]$CimSession ) $settingName = 'Power-On Password' $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. See important note regarding the BIOS Setup Password prerequisite below. .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 -Password 's3cr3t' .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. - If BIOS Setup Password is not set, it's required to be first set in order to clear the Power-On password. #> function Clear-HPBIOSPowerOnPassword { [CmdletBinding(DefaultParameterSetName = 'NoPassthruNewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Clear-HPBIOSPowerOnPassword")] param( [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 0,Mandatory = $false)] [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 0,Mandatory = $false)] [string]$Password, [Parameter(ParameterSetName = 'NoPassthruNewSession',Position = 1,Mandatory = $false)] [Alias('Target')] $ComputerName = ".", [Parameter(ParameterSetName = 'NoPassthruReuseSession',Position = 2,Mandatory = $true)] [CimSession]$CimSession ) $settingName = 'Power-On Password' $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 settings file (relative or absolute path) to process - Note that BIOS passwords are not encrypted in this file, so it is essential to protect its content until applied to the target system. .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. .EXAMPLE Set-HPBIOSSettingValuesFromFile -File .\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-HPBIOSSettingValuesFromFile")] param( [Parameter(ParameterSetName = "NotPassThruNewSession",Position = 0,Mandatory = $true)] [Parameter(ParameterSetName = "NotPassThruReuseSession",Position = 0,Mandatory = $true)] [System.IO.FileInfo]$File, [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 = "NotPassThruReuseSession",Position = 6,Mandatory = $true)] [CimSession]$CimSession ) if (-not $Format) { $Format = (Split-Path -Path $File -Leaf).Split(".")[1].ToLower() Write-Verbose "Format from file extension: $Format" } Write-Verbose "Format specified: '$Format'. Reading file..." [System.Collections.Generic.List[SureAdminSetting]]$settingsList = Get-HPPrivateSettingsFromFile -FileName $File -Format $Format $params = @{ SettingsList = $settingsList ErrorHandling = $ErrorHandling ComputerName = $ComputerName CimSession = $CimSession Password = $Password NoSummary = $NoSummary } Set-HPPrivateBIOSSettingsList @params -Verbose:$VerbosePreference } <# .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. .EXAMPLE Set-HPBIOSSettingDefaults -Password 's3cr3t' .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 = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Set-HPBIOSSettingDefaults")] param( [Parameter(ParameterSetName = "NewSession",Position = 0,Mandatory = $false)] [Parameter(ParameterSetName = "ReuseSession",Position = 0,Mandatory = $false)] [AllowEmptyString()] [string]$Password, [Parameter(ParameterSetName = 'NewSession',Position = 1,Mandatory = $false)] [Alias('Target')] $ComputerName = ".", [Parameter(ParameterSetName = 'ReuseSession',Position = 2,Mandatory = $true)] [CimSession]$CimSession ) $authorization = "<utf-16/>" + $Password Set-HPPrivateBIOSSettingDefaultsAuthorization -ComputerName $ComputerName -CimSession $CimSession -Authorization $authorization -Verbose:$VerbosePreference } function Set-HPPrivateBIOSSettingDefaultsAuthorization { param( [string]$Authorization, [string]$ComputerName, [CimSession]$CimSession ) Write-Verbose "Calling SetSystemDefaults() on $ComputerName" $params = @{} if ($CimSession) { $params.CimSession = $CimSession } else { $params.CimSession = newCimSession -Target $ComputerName } $iface = getBiosSettingInterface @params $r = $iface | Invoke-CimMethod -MethodName SetSystemDefaults -Arguments @{ Password = $Authorization; } if ($r.Return -ne 0) { $Err = "$(biosErrorCodesToString($r.Return))" throw $Err } } <# .SYNOPSIS This is a private function for internal use only .DESCRIPTION This is a private function for internal use only .EXAMPLE .NOTES - This is a private function for internal use only #> function Set-HPPrivateBIOSSettingDefaultsPayload { param( [Parameter(ParameterSetName = 'Payload',Position = 0,Mandatory = $true,ValueFromPipeline = $true)] [string]$Payload ) $portable = $Payload | ConvertFrom-Json if ($portable.purpose -ne "hp:sureadmin:resetsettings") { throw "The payload should be generated by New-HPSureAdminSettingDefaultsPayload function" } [SureAdminSetting]$setting = [System.Text.Encoding]::UTF8.GetString($portable.Data) | ConvertFrom-Json Set-HPPrivateBIOSSettingDefaultsAuthorization -Authorization $setting.AuthString } <# .SYNOPSIS Get system uptime .DESCRIPTION Get the system boot time and uptime .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 (Get-HPDeviceUptime).BootTime #> function Get-HPDeviceUptime { [CmdletBinding(DefaultParameterSetName = 'NewSession',HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPDeviceUptime")] 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-HPDeviceBootInformation")] param() $mode = @{} 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 Online Mode uses Seamless Firmware Update Service that can update the BIOS in the background while the operating system is running (no authentication needed). 2022 and newer HP computers with Intel processors support Seamless Firmware Update Service. Offline Mode updates the BIOS after reboot and this mode requires authentication (password or payload). .PARAMETER Platform The Platform ID to check. It can be obtained via Get-HPDeviceProductID. The Platform ID cannot be specified for a flash operation. If not specified, current Platform ID is checked. .PARAMETER Target Execute the command on specified target computer. If not specified, the command is executed on the local computer. .PARAMETER Format The file format (XML, JSON, CSV, list) to output. If not specified, a list of PowerShell objects is returned. .PARAMETER Latest If specified, only return or download the latest available BIOS version between remote and local. If -Platform is specified, local BIOS will not be read and the latest BIOS version available remotely will be returned. .PARAMETER Check If specified, return true if the latest version corresponds to the installed version or installed version is higher, 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. To prevent flashing the BIOS accidentally it is recommended to not specify Yes by default. .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 - (default option) stop if BitLocker is detected but not suspended, and prompt ignore - skip the BitLocker check suspend - suspend BitLocker if active, and continue .PARAMETER Url Alternate Url source to provide platform's BIOS update catalog (xml) .PARAMETER Offline This parameter selects the offline mode to flash the BIOS instead of the default online mode. If specified the actual flash will only occur after reboot at pre-OS environment. This mode is selected by default when downgrading the BIOS version and requires authentication so either a Password or a PayloadFile should be specified. .PARAMETER NoWait If specified, the script does not wait for the online flash background task to finish. If the user reboots the PC during the online flash it will complete only after reboot. .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. - The flash operation requires 64-bit PowerShell (not supported under 32-bit PowerShell). **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-HPBIOSUpdates")] 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','List')] [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 = "FlashSetPassword",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 = "FlashSetPassword",Position = 7,Mandatory = $true)] [switch]$Flash, [Parameter(ParameterSetName = 'FlashSetPassword',Position = 8,Mandatory = $false)] [string]$Password, [Parameter(ParameterSetName = "FlashSetPassword",Position = 9,Mandatory = $false)] [Parameter(ParameterSetName = "DownloadSet",Position = 9,Mandatory = $false)] [string]$Version, [Parameter(ParameterSetName = "FlashSetPassword",Position = 10,Mandatory = $false)] [Parameter(ParameterSetName = "DownloadSet",Position = 10,Mandatory = $false)] [string]$SaveAs, [Parameter(ParameterSetName = "FlashSetPassword",Position = 11,Mandatory = $false)] [Parameter(ParameterSetName = "DownloadSet",Position = 11,Mandatory = $false)] [switch]$Quiet, [Parameter(ParameterSetName = "FlashSetPassword",Position = 12,Mandatory = $false)] [Parameter(ParameterSetName = "DownloadSet",Position = 12,Mandatory = $false)] [switch]$Overwrite, [Parameter(ParameterSetName = 'FlashSetPassword',Position = 13,Mandatory = $false)] [switch]$Yes, [Parameter(ParameterSetName = 'FlashSetPassword',Position = 14,Mandatory = $false)] [ValidateSet('Stop','Ignore','Suspend')] [string]$BitLocker = 'Stop', [Parameter(ParameterSetName = 'FlashSetPassword',Position = 15,Mandatory = $false)] [switch]$Force, [Parameter(ParameterSetName = 'FlashSetPassword',Position = 16,Mandatory = $false)] [string]$Url = "https://ftp.hp.com/pub/pcbios", [Parameter(ParameterSetName = 'FlashSetPassword',Position = 17,Mandatory = $false)] [switch]$Offline, [Parameter(ParameterSetName = 'FlashSetPassword',Position = 18,Mandatory = $false)] [switch]$NoWait ) if ($PSCmdlet.ParameterSetName -eq "FlashSetPassword") { Test-HPFirmwareFlashSupported -CheckPlatform if ((Get-HPPrivateIsSureAdminEnabled) -eq $true) { throw "Sure Admin is enabled, you must use Update-HPFirmware with a payload instead of a password" } } if (-not $platform) { # if platform is not provided, $platform is current platform $platform = Get-HPDeviceProductID -Target $target } $platform = $platform.ToUpper() Write-Verbose "Using platform ID $platform" $uri = [string]"$Url/{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" } #reach to Rel nodes to find Bin entries in xml #ignore any entry not ending in *.bin e.g. *.tgz, *.cab $unwanted_nodes = $doc.SelectNodes("//BIOS/Rel") | Where-Object { -not ($_.Bin -like "*.bin") } $unwanted_nodes | Where-Object { $ignore = $_.ParentNode.RemoveChild($_) } #trim the 0 from the start of the version and then sort on the version value $refined_doc = $doc.SelectNodes("//BIOS/Rel") | Select-Object -Property @{ Name = 'Ver'; expr = { $_.Ver.TrimStart("0") } },'Date','Bin','RB','L','DP' ` | Sort-Object -Property Ver -Descending #latest version $latestVer = $refined_doc[0] 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 #check should return true if local BIOS is same or newer than the latest available remote BIOS. return ([string]$haveVer.TrimStart("0") -ge [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") } # for current platform: latest should return whichever is latest, between local and remote. # for any other platform specified: latest should return latest entry from SystemID.XML since we don't know local BIOSVersion if ($latest) { if ($PSBoundParameters.ContainsKey('Platform')) { # platform specified, do not read information from local system and return latest platform published $args.First = 1 } else { $retrieved = 0 # determine the local BIOS version [string]$haveVer = Get-HPBIOSVersion -Target $target # latest should return whichever is latest, between local and remote for current system. if ([string]$haveVer -ge [string]$latestVer[0].Ver) { # local is the latest. So, retrieve attributes other than BIOSVersion to print for latest for ($i = 0; $i -lt $refined_doc.Length; $i++) { if ($refined_doc[$i].Ver -eq $haveVer) { $haveVerFromDoc = $refined_doc[$i] $pso = [pscustomobject]@{ Ver = $haveVerFromDoc.Ver Date = $haveVerFromDoc.Date Bin = $haveVerFromDoc.Bin } if ($all) { $pso | Add-Member -MemberType ScriptProperty -Name RollbackAllowed -Value { [bool][int]$haveVerFromDoc.RB.trim() } $pso | Add-Member -MemberType ScriptProperty -Name Importance -Value { [Enum]::ToObject([BiosUpdateCriticality],[int]$haveVerFromDoc.L.trim()) } $pso | Add-Member -MemberType ScriptProperty -Name Dependency -Value { [string]$haveVerFromDoc.DP.trim } } $retrieved = 1 if ($pso) { formatBiosVersionsOutputList ($pso) return } } } if ($retrieved -eq 0) { Write-Verbose "Retrieving entry from XML failed, get the information from CIM class." # calculating date from Win32_BIOS $year = (Get-CimInstance Win32_BIOS).ReleaseDate.Year $month = (Get-CimInstance Win32_BIOS).ReleaseDate.Month $day = (Get-CimInstance Win32_BIOS).ReleaseDate.Day $date = $year.ToString() + '-' + $month.ToString() + '-' + $day.ToString() Write-Verbose "Date calculated from CIM Class is: $date" $currentVer = Get-HPBIOSVersion $pso = [pscustomobject]@{ Ver = $currentVer Date = $date Bin = $null } if ($all) { $pso | Add-Member -MemberType ScriptProperty -Name RollbackAllowed -Value { $null } $pso | Add-Member -MemberType ScriptProperty -Name Importance -Value { $null } $pso | Add-Member -MemberType ScriptProperty -Name Dependency -Value { $null } } if ($pso) { $retrieved = 1 formatBiosVersionsOutputList ($pso) return } } } else { # remote is the latest $args.First = 1 } } } formatBiosVersionsOutputList ($refined_doc | Sort-Object -Property ver -Descending | Select-Object @args) } else { $download_params = @{} if ($version) { $version = $version.TrimStart('0') $latestVer = $refined_doc ` | 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 "FlashSetPassword" -or $PSCmdlet.ParameterSetName -eq "FlashSetSigningKeyFile" -or $PSCmdlet.ParameterSetName -eq "FlashSetSigningKeyCert") { $running = Get-HPBIOSVersion $offlineMode = $false if ($running.TrimStart("0").trim() -ge $remote_ver.TrimStart("0").trim()) { if ($Force.IsPresent) { $offlineMode = $true Write-Verbose "Offline mode selected to downgrade BIOS" } else { Write-Host "This system is already running BIOS version $($remote_ver.TrimStart(`"0`").Trim()) or newer." Write-Host -ForegroundColor Cyan "You can specify -Force on the command line to proceed anyway." return } } if (-not $offlineMode -and $Offline.IsPresent) { $offlineMode = $true Write-Verbose "Offline mode selected" } } if ($saveAs) { $local_file = $saveAs } [Environment]::CurrentDirectory = $pwd #if (-not [System.IO.Path]::IsPathRooted($to)) { $to = ".\$to" } $download_params.url = [string]"$Url/{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 "FlashSetPassword" -or $PSCmdlet.ParameterSetName -eq "FlashSetSigningKeyFile" -or $PSCmdlet.ParameterSetName -eq "FlashSetSigningKeyCert") { 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 = @{ file = $download_params.Target bitlocker = $bitlocker Force = $Force Password = $password } Update-HPFirmware @update_params -Verbose:$VerbosePreference -Offline:$offlineMode -NoWait:$NoWait } } } function Get-HPPrivateBIOSFamilyNameAndVersion { [CmdletBinding()] param( ) $params = @{ ClassName = 'Win32_BIOS' Namespace = 'root\cimv2' } $params.CimSession = newCimSession -Target "." $obj = Get-CimInstance @params -ErrorAction stop $verfield = (getWmiField $obj "SMBIOSBIOSVersion").Split() return $verfield[0],$verfield[2] } <# .SYNOPSIS Check and apply available BIOS updates using Windows Update packages .DESCRIPTION This function uses an internet service to get the list of BIOS capsule updates available for a platform family, and optionally install the update in the current system. The versions available through this function may differ from Get-HPBIOSUpdate since this relies on the Microsoft capsules availability. This can be delayed due to the Windows Update in-flight processes. .PARAMETER Family The Platform Family to check. If not specified, check the current platform family. .PARAMETER Severity If specified, returns the available BIOS for the specified severity: Latest or LatestCritical. .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 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. In order to use the downloaded file with Add-HPBIOSWindowsUpdateScripts the name must follow the standard: platform family (3 digit) + underscore + BIOS version (6 digits) + .cab, for instance: R70_011200.cab .PARAMETER Yes Answer 'yes' to the 'Are you sure you want to flash' prompt. To prevent flashing the BIOS accidentally it is recommended to not specify Yes by default. .PARAMETER Force Force the BIOS to update, even if the target BIOS is already installed. .PARAMETER Url Alternate Url source to provide platform's BIOS update catalog (xml). .PARAMETER Quiet Do not display a progress bar during BIOS file download. .PARAMETER List Display a list with all BIOS versions available for the specified platform. .NOTES - Requires Windows group policy support .EXAMPLE Get-HPBIOSWindowsUpdate .EXAMPLE Get-HPBIOSWindowsUpdate -List -Family R70 .EXAMPLE Get-HPBIOSWindowsUpdate -Flash -Severity Latest .EXAMPLE Get-HPBIOSWindowsUpdate -Flash -Severity LatestCritical .EXAMPLE Get-HPBIOSWindowsUpdate -Flash -Severity LatestCritical -Family R70 .EXAMPLE Get-HPBIOSWindowsUpdate -Flash -Severity LatestCritical -Family R70 -Version "01.09.00" .EXAMPLE Get-HPBIOSWindowsUpdate -Flash -Severity LatestCritical -Family R70 -Version "01.09.00" -SaveAs "R70_010900.cab" #> function Get-HPBIOSWindowsUpdate { [CmdletBinding(DefaultParameterSetName = "Severity",HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPBIOSWindowsUpdate")] param( [Parameter(Mandatory = $false,Position = 0,ParameterSetName = "Severity")] [ValidateSet('Latest','LatestCritical')] [string]$Severity = 'Latest', [Parameter(Mandatory = $true,Position = 0,ParameterSetName = "Specific")] [string]$Version, [Parameter(Mandatory = $false,Position = 1,ParameterSetName = "Severity")] [Parameter(Mandatory = $false,Position = 1,ParameterSetName = "Specific")] [Parameter(Mandatory = $false,Position = 0,ParameterSetName = "List")] [string]$Family, [Parameter(Mandatory = $false,Position = 2,ParameterSetName = "Severity")] [Parameter(Mandatory = $false,Position = 2,ParameterSetName = "Specific")] [Parameter(Mandatory = $false,Position = 1,ParameterSetName = "List")] [string]$Url = "https://hpia.hpcloud.hp.com/downloads/capsule", [Parameter(Mandatory = $false,Position = 3,ParameterSetName = "Severity")] [Parameter(Mandatory = $false,Position = 3,ParameterSetName = "Specific")] [switch]$Quiet, [Parameter(Mandatory = $false,Position = 4,ParameterSetName = "Severity")] [Parameter(Mandatory = $false,Position = 4,ParameterSetName = "Specific")] [string]$SaveAs, [Parameter(Mandatory = $false,Position = 5,ParameterSetName = "Severity")] [Parameter(Mandatory = $false,Position = 5,ParameterSetName = "Specific")] [switch]$Download, [Parameter(Mandatory = $false,Position = 6,ParameterSetName = "Severity")] [Parameter(Mandatory = $false,Position = 6,ParameterSetName = "Specific")] [switch]$Flash, [Parameter(Mandatory = $false,Position = 7,ParameterSetName = "Severity")] [Parameter(Mandatory = $false,Position = 7,ParameterSetName = "Specific")] [switch]$Yes, [Parameter(Mandatory = $false,Position = 8,ParameterSetName = "Severity")] [Parameter(Mandatory = $false,Position = 8,ParameterSetName = "Specific")] [switch]$Force, [Parameter(Mandatory = $true,Position = 2,ParameterSetName = "List")] [switch]$List ) if ($Family -and -not $Version) { $_,$biosVersion = Get-HPPrivateBIOSFamilyNameAndVersion $biosFamily = $Family } elseif (-not $Family -and $Version) { $biosFamily,$_ = Get-HPPrivateBIOSFamilyNameAndVersion $biosVersion = $Version } elseif (-not $Version -and -not $Family) { $biosFamily,$biosVersion = Get-HPPrivateBIOSFamilyNameAndVersion } else { $biosFamily = $Family $biosVersion = $Version } [string]$uri = [string]"$Url/{0}/{0}.json" -f $biosFamily.ToUpper() Write-Verbose "Retrieving $biosFamily catalog $uri" Write-Verbose "BIOS Version: $biosVersion" $ua = Get-HPPrivateUserAgent [System.Net.ServicePointManager]::SecurityProtocol = Get-HPPrivateAllowedHttpsProtocols try { $data = Invoke-WebRequest -Uri $uri -UserAgent $ua -UseBasicParsing -ErrorAction Stop } catch { Write-Verbose $_.Exception Write-Host "Platform $biosFamily is not supported yet" throw [System.Management.Automation.ItemNotFoundException]"Unable to retrieve the BIOS update catalog for platform family $biosFamily." } $doc = [System.IO.StreamReader]::new($data.RawContentStream).ReadToEnd() | ConvertFrom-Json if ($List.IsPresent) { $data = $doc | Sort-Object -Property biosVersion -Descending return $data | Format-Table -Property biosFamily,biosVersion,severity,isLatest,IsLatestCritical } if ($PSCmdlet.ParameterSetName -eq "Specific") { $filter = $doc | Where-Object { $_.BiosVersion -eq $biosVersion } # specific Write-Verbose "Locating a specific version" if ($null -eq $filter) { throw "The version specified is not available on the $biosFamily catalog" } } elseif ($Severity -eq "LatestCritical") { $filter = $doc | Where-Object { $_.isLatestCritical -eq $true } # latest critical Write-Verbose "Locating the latest critical version available" } else { $filter = $doc | Where-Object { $_.isLatest -eq $true } # latest Write-Verbose "Locating the latest version available" } $sort = $filter | Sort-Object -Property biosVersion -Descending @{ Family = $sort[0].biosFamily Version = $sort[0].BiosVersion } if ($Flash.IsPresent) { $running = Get-HPBIOSVersion if (-not $Yes.IsPresent) { Write-Host -ForegroundColor Cyan "Are you sure you want to flash this system with version '$($sort[0].biosVersion)'?" Write-Host -ForegroundColor Cyan "Current BIOS version is $running." 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 } } if ((-not $Force.IsPresent) -and $running.TrimStart("0").trim() -ge $sort[0].BiosVersion.TrimStart("0").trim()) { Write-Host "This system is already running BIOS version $($sort[0].biosVersion) or newer." Write-Host -ForegroundColor Cyan "You can specify -Force on the command line to proceed anyway." return } } if ($Download.IsPresent -or $Flash.IsPresent) { Write-Verbose "Download from $($sort[0].url)" if ($SaveAs) { $localFile = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($SaveAs) } else { $extension = ($sort[0].url -split '\.')[-1] $SaveAs = Get-HPPrivateTemporaryFileName -FileName "$($sort[0].biosFamily)_$($sort[0].biosVersion -Replace '\.').$extension" $localFile = [IO.Path]::GetFullPath($SaveAs) } Write-Verbose "LocalFile: $localFile" $download_params = @{ NoClobber = "yes" url = $sort[0].url Target = $localFile progress = ($Quiet.IsPresent -eq $false) } try { Invoke-HPPrivateDownloadFile @download_params } catch { Write-Verbose $_.Exception throw [System.Management.Automation.ItemNotFoundException]"Unable to download the BIOS update archive from $($download_params.url)." } Write-Host "Saved as $localFile" $hash = (Get-FileHash $localFile -Algorithm SHA1).Hash $bytes = [byte[]] -split ($hash -replace '..','0x$& ') $base64 = [System.Convert]::ToBase64String($bytes) if ($base64 -eq $sort[0].digest) { Write-Verbose "Integrity check passed" } else { throw "Cab file integrity check failed" } } if ($Flash.IsPresent) { Add-HPBIOSWindowsUpdateScripts -WindowsUpdateFile $localFile } } function Get-HPPrivatePSScriptsEntries { [CmdletBinding()] param( [Parameter(Mandatory = $false,Position = 0)] [string]$Path = "${env:SystemRoot}\System32\GroupPolicy\Machine\Scripts\psscripts.ini" ) $types = '[Logon]','[Logoff]','[Startup]','[Shutdown]' $cmdLinesSet = @{} $parametersSet = @{} if ([System.IO.File]::Exists($Path)) { $contents = Get-Content $Path if ($contents) { for ($i = 0; $i -lt $contents.Length; $i++) { if ($types.contains($contents[$i])) { $t = $contents[$i] $cmdLinesSet[$t] = [System.Collections.ArrayList]@() $parametersSet[$t] = [System.Collections.ArrayList]@() continue } if ($contents[$i].Length -gt 0) { $cmdLinesSet[$t].Add($contents[$i].substring(1)) | Out-Null $parametersSet[$t].Add($contents[$i + 1].substring(1)) | Out-Null $i++ } } } } $cmdLinesSet,$parametersSet } function Set-HPPrivatePSScriptsEntries { [CmdletBinding()] param( [Parameter(Mandatory = $true,Position = 0)] $CmdLines, [Parameter(Mandatory = $true,Position = 1)] $Parameters, [Parameter(Mandatory = $false,Position = 2)] [string]$Path = "${env:SystemRoot}\System32\GroupPolicy\Machine\Scripts\psscripts.ini" ) $types = '[Logon]','[Logoff]','[Startup]','[Shutdown]' $contents = "" foreach ($type in $types) { if ($CmdLines.contains($type)) { for ($i = 0; $i -lt $CmdLines[$type].Count; $i++) { if ($i -eq 0) { $contents += "$type`n" } $contents += "$($i)$($CmdLines[$type][$i])`n" $contents += "$($i)$($Parameters[$type][$i])`n" } $contents += "`n" } } if (-not [System.IO.File]::Exists($Path)) { New-Item -Force -Path $Path -Type File } $contents | Set-Content -Path $Path -Force } <# .SYNOPSIS Add a PowerShell script to the group policy .DESCRIPTION This function adds a PowerShell script to the group policy that runs at Startup or Shutdown. This function is invoked by Add-HPBIOSWindowsUpdateScripts. .PARAMETER Type Type of the script, if it runs at Startup or Shutdown. .PARAMETER CmdLine The command line, it is also possible to specify as CmdLine a path to a PowerShell script. .PARAMETER Parameters The parameters to be passed to the script at the execution time. .PARAMETER Path If needed, a custom path can be specified. .EXAMPLE Add-PSScriptsEntry -Type 'Shutdown' -CmdLine 'myscript.ps1' .EXAMPLE Add-PSScriptsEntry -Type 'Startup' -CmdLine 'myscript.ps1' .EXAMPLE Add-PSScriptsEntry -Type 'Startup' -CmdLine 'myscript.ps1' -Parameters 'myparam' #> function Add-PSScriptsEntry { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Add-PSScriptsEntry")] param( [ValidateSet('Startup','Shutdown')] [Parameter(Mandatory = $true,Position = 0)] [string]$Type, [Parameter(Mandatory = $true,Position = 1)] [string]$CmdLine, [Parameter(Mandatory = $false,Position = 2)] [string]$Parameters, [Parameter(Mandatory = $false,Position = 3)] [string]$Path = "${env:SystemRoot}\System32\GroupPolicy\Machine\Scripts\psscripts.ini" ) $cmdLinesSet,$parametersSet = Get-HPPrivatePSScriptsEntries -Path $Path if (-not $cmdLinesSet.ContainsKey("[$Type]")) { $cmdLinesSet["[$Type]"] = [System.Collections.ArrayList]@() } if (-not $parametersSet.ContainsKey("[$Type]")) { $parametersSet["[$Type]"] = [System.Collections.ArrayList]@() } if (-not $cmdLinesSet["[$Type]"].contains("CmdLine=$CmdLine")) { $cmdLinesSet["[$Type]"].Add("CmdLine=$CmdLine") | Out-Null $parametersSet["[$Type]"].Add("Parameters=$Parameters") | Out-Null } Set-HPPrivatePSScriptsEntries -CmdLines $cmdLinesSet -Parameters $parametersSet -Path $Path } <# .SYNOPSIS Get HP-CMSL environment configuration .DESCRIPTION This function returns environment information to help debugging issues .EXAMPLE Get-HPCMSLEnvironment > MyEnvironment.txt #> function Get-HPCMSLEnvironment { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPCMSLEnvironment")] param() Get-ComputerInfo $psVersionTable try { $psISE } catch { 'Not running on Windows PowerShell ISE' } $modules = @( 'HP.Consent', 'HP.Private', 'HP.Utility', 'HP.ClientManagement', 'HP.Firmware', 'HP.Notifications', 'HP.Sinks', 'HP.Retail', 'HP.Softpaq', 'HP.Repo', 'HP.SmartExperiences' ) $modulesFullVersion = @{} foreach ($module in $modules) { $m = Get-Module -Name $module if ($null -eq $m) { $m = Get-Module -Name $module -ListAvailable } $path = "$($m.ModuleBase)\$module.psd1" $line = Select-String -Path $path -Pattern "FullModuleVersion = '(.+)'" if ($null -eq $line -or $line.PSobject.Properties.name -notcontains 'Matches') { $modulesFullVersion[$module] = $null continue } $lineMatch = $line.Matches.Value $lineMatch -match "'(.+)'" | Out-Null $fullModuleVersion = $Matches[1] $modulesFullVersion[$module] = $fullModuleVersion } $modulesFullVersion @{ SystemID = Get-HPDeviceProductID Os = Get-HPPrivateCurrentOs OsVer = Get-HPPrivateCurrentDisplayOSVer Bitness = Get-HPPrivateCurrentOsBitness } } <# .SYNOPSIS Remove a PowerShell script from the group policy .DESCRIPTION This function removes a PowerShell script from the group policy that runs at Startup or Shutdown. Returns true if some entry was removed. This function is invoked by Add-HPBIOSWindowsUpdateScripts. .PARAMETER Type Type of the script, if it runs at Startup or Shutdown. .PARAMETER CmdLine The command line, it is also possible to specify as CmdLine a path to a PowerShell script. .PARAMETER Parameters The parameters to be passed to the script at the execution time. .PARAMETER Path If needed, a custom path can be specified. .EXAMPLE Remove-PSScriptsEntry -Type 'Shutdown' -CmdLine 'myscript.ps1' .EXAMPLE Remove-PSScriptsEntry -Type 'Startup' -CmdLine 'myscript.ps1' .EXAMPLE Remove-PSScriptsEntry -Type 'Startup' -CmdLine 'myscript.ps1' -Parameters 'myparam' #> function Remove-PSScriptsEntry { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Remove-PSScriptsEntry")] param( [ValidateSet('Startup','Shutdown')] [Parameter(Mandatory = $true,Position = 0)] [string]$Type, [Parameter(Mandatory = $true,Position = 1)] [string]$CmdLine, [Parameter(Mandatory = $false,Position = 2)] [string]$Parameters, [Parameter(Mandatory = $false,Position = 3)] [string]$Path = "${env:SystemRoot}\System32\GroupPolicy\Machine\Scripts\psscripts.ini" ) $cmdLinesSet,$parametersSet = Get-HPPrivatePSScriptsEntries -Path $Path if (-not $cmdLinesSet.ContainsKey("[$Type]") -and -not $parametersSet.ContainsKey("[$Type]")) { # File doesn't contain the type specified. There is nothing to be removed return } $removed = $false # If a parameter is specified we remove only the scripts with the specified parameter from the file while ($cmdLinesSet["[$Type]"].contains("CmdLine=$CmdLine") -and (-not $Parameters -or $parametersSet["[$Type]"].item($cmdLinesSet["[$Type]"].IndexOf("CmdLine=$CmdLine")) -eq "Parameters=$Parameters") ) { $index = $cmdLinesSet["[$Type]"].IndexOf("CmdLine=$CmdLine") $cmdLinesSet["[$Type]"].RemoveAt($index) | Out-Null $parametersSet["[$Type]"].RemoveAt($index) | Out-Null $removed = $true } Set-HPPrivatePSScriptsEntries -CmdLines $cmdLinesSet -Parameters $parametersSet -Path $Path return $removed } <# .SYNOPSIS Apply BIOS updates using a Windows Update package .DESCRIPTION This function extracts the Windows Update file and prepares the system to receive a BIOS update. This function is invoked by Get-HPBIOSWindowsUpdate. .PARAMETER WindowsUpdateFile Absolute path to the compressed CAB file downloaded with Get-HPBIOSWindowsUpdate. The file name must follow the standard: platform family (3 digit) + underscore + BIOS version (6 digits) + .cab, for instance: R70_011200.cab .NOTES Requires Windows group policy support .EXAMPLE Add-HPBIOSWindowsUpdateScripts -WindowsUpdateFile C:\R70_011200.cab #> function Add-HPBIOSWindowsUpdateScripts { [CmdletBinding(DefaultParameterSetName = "Default",HelpUri = "https://developers.hp.com/hp-client-management/doc/Add-HPBIOSWindowsUpdateScripts")] param( [Parameter(Mandatory = $true,Position = 0,ParameterSetName = "Default")] [string]$WindowsUpdateFile ) $gpt = "${env:SystemRoot}\System32\GroupPolicy\gpt.ini" $scripts = "${env:SystemRoot}\System32\GroupPolicy\Machine" New-Item -ItemType Directory -Force -Path "$scripts\Scripts" | Out-Null New-Item -ItemType Directory -Force -Path "$scripts\Scripts\Startup" | Out-Null New-Item -ItemType Directory -Force -Path "$scripts\Scripts\Shutdown" | Out-Null $fileName = ($WindowsUpdateFile -split '\\')[-1] $directory = $WindowsUpdateFile -replace $fileName,'' $fileName = $fileName.substring(0,$fileName.Length - 4) $expectedDir = "$directory$fileName.cab.dir" Invoke-HPPrivateExpandCAB -cab $WindowsUpdateFile -expectedFile $WindowsUpdateFile $inf = Get-ChildItem -Path $expectedDir -File -Filter "$fileName*.inf" -Name if (-not $inf) { Remove-Item $expectedDir -Force -Recurse throw "Invalid cab file, did not find .inf in contents" } $infFileName = $inf.substring(0,$inf.Length - 4) Remove-Item $WindowsUpdateFile -Force Remove-Item -Recurse -Force "$scripts\Scripts\Shutdown\wu_image" -ErrorAction Ignore Move-Item $expectedDir "$scripts\Scripts\Shutdown\wu_image" -Force $log = ".\wu_bios_update.log" # CMSL modules should be included at startup to use Remove-PSScriptsEntry function $clientManagementModulePath = (Get-Module -Name HP.ClientManagement).Path $privateModulePath = (Get-Module -Name HP.Private).Path # Move DeviceInstall service to be notified after the Group Policy shutdown script $preshutdownOrder = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control" -Name "PreshutdownOrder").PreshutdownOrder | Where-Object { $_ -ne "DeviceInstall" } $preshutdownOrder += "DeviceInstall" Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control" -Name "PreshutdownOrder" -Value $preshutdownOrder -Force -ErrorAction SilentlyContinue | Out-Null # Startup script '$driver = Get-WmiObject Win32_PnPSignedDriver | ? DeviceClass -eq "Firmware" | Where Manufacturer -eq "HP Inc." $infName = $driver.InfName if ($infName) { Write-Host "INF name: $infName" *>> ' + $log + ' ' + ${env:SystemRoot} + '\System32\pnputil.exe /delete-driver $infName /uninstall /force *>> ' + $log + ' } else { Write-Host "No device to clean up" *>> ' + $log + ' } Write-Host "Clean EFI partition" *>> ' + $log + ' $volumes = Get-Partition | Select-Object ` @{ Name = "Path"; Expression = { (Get-Volume -Partition $_).Path } },` @{ Name = "Mount"; Expression = {(Get-Volume -Partition $_).DriveType } },` @{ Name = "Type"; Expression = { $_.Type } },` @{ Name = "Disk"; Expression = { $_.DiskNumber } } $volumes = $volumes | Where-Object Mount -EQ "Fixed" [array]$efi = $volumes | Where-Object { $_.type -eq "System" } [array]$efi = $efi | Where-Object { (Get-Disk -Number $_.Disk).OperationalStatus -eq "Online" } [array]$efi = $efi | Where-Object { (Get-Disk -Number $_.Disk).IsBoot -eq $true } Remove-Item "$($efi[0].Path)EFI\HP\DEVFW\*" -Recurse -Force -ErrorAction Ignore *>> ' + $log + ' Remove-Item -Force ' + ${env:SystemRoot} + '\System32\GroupPolicy\Machine\Scripts\Startup\wu_startup.ps1 *>> ' + $log + ' Remove-Item -Force ' + ${env:SystemRoot} + '\System32\GroupPolicy\Machine\Scripts\Shutdown\wu_shutdown.ps1 *>> ' + $log + ' Remove-Item -Recurse -Force ' + ${env:SystemRoot} + '\System32\GroupPolicy\Machine\Scripts\Shutdown\wu_image *>> ' + $log + ' if (Get-Module -Name HP.Private) {remove-module -force HP.Private } if (Get-Module -Name HP.ClientManagement) {remove-module -force HP.ClientManagement } Import-Module -Force ' + $privateModulePath + ' *>> ' + $log + ' Import-Module -Force ' + $clientManagementModulePath + ' -Function Remove-PSScriptsEntry *>> ' + $log + ' Remove-PSScriptsEntry -Type "Startup" -CmdLine wu_startup.ps1 *>> ' + $log + ' Remove-PSScriptsEntry -Type "Shutdown" -CmdLine wu_shutdown.ps1 *>> ' + $log + ' gpupdate /wait:0 /force /target:computer *>> ' + $log + ' ' | Out-File "$scripts\Scripts\Startup\wu_startup.ps1" # Shutdown script 'param($wu_inf_name) net start DeviceInstall *>> ' + $log + ' $driver = Get-WmiObject Win32_PnPSignedDriver | ? DeviceClass -eq "Firmware" | Where Manufacturer -eq "HP Inc." $infName = $driver.InfName if ($infName) { Write-Host "INF name: $infName" *>> ' + $log + ' ' + ${env:SystemRoot} + '\System32\pnputil.exe /delete-driver $infName /uninstall /force *>> ' + $log + ' } else { Write-Host "No device to clean up" *>> ' + $log + ' } Write-Host "Clean EFI partition" *>> ' + $log + ' $volumes = Get-Partition | Select-Object ` @{ Name = "Path"; Expression = { (Get-Volume -Partition $_).Path } },` @{ Name = "Mount"; Expression = {(Get-Volume -Partition $_).DriveType } },` @{ Name = "Type"; Expression = { $_.Type } },` @{ Name = "Disk"; Expression = { $_.DiskNumber } } $volumes = $volumes | Where-Object Mount -EQ "Fixed" [array]$efi = $volumes | Where-Object { $_.type -eq "System" } [array]$efi = $efi | Where-Object { (Get-Disk -Number $_.Disk).OperationalStatus -eq "Online" } [array]$efi = $efi | Where-Object { (Get-Disk -Number $_.Disk).IsBoot -eq $true } Remove-Item "$($efi[0].Path)EFI\HP\DEVFW\*" -Recurse -Force -ErrorAction Ignore *>> ' + $log + ' $volume = Get-BitLockerVolume | Where-Object VolumeType -EQ "OperatingSystem" if ($volume.ProtectionStatus -ne "Off") { Suspend-BitLocker -MountPoint $volume.MountPoint -RebootCount 1 *>> ' + $log + ' } Write-Host "Invoke PnPUtil to update the BIOS" *>> ' + $log + ' ' + ${env:SystemRoot} + '\System32\pnputil.exe /add-driver ' + ${env:SystemRoot} + '\System32\GroupPolicy\Machine\Scripts\Shutdown\wu_image\$wu_inf_name.inf /install *>> ' + $log + ' Write-Host "WU driver installed" *>> ' + $log + ' $volume = Get-BitLockerVolume | Where-Object VolumeType -EQ "OperatingSystem" if ($volume.ProtectionStatus -ne "Off") { Suspend-BitLocker -MountPoint $volume.MountPoint -RebootCount 1 *>> ' + $log + ' } ' | Out-File "$scripts\Scripts\Shutdown\wu_shutdown.ps1" "[General]`ngPCMachineExtensionNames=[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}]`nVersion=65537" | Set-Content -Path $gpt -Force Remove-PSScriptsEntry -Type "Startup" -CmdLine "wu_startup.ps1" | Out-Null Remove-PSScriptsEntry -Type "Shutdown" -CmdLine "wu_shutdown.ps1" | Out-Null Add-PSScriptsEntry -Type "Startup" -CmdLine "wu_startup.ps1" Add-PSScriptsEntry -Type "Shutdown" -CmdLine "wu_shutdown.ps1" -Parameters "$infFileName" gpupdate /wait:0 /force /target:computer Write-Host -ForegroundColor Cyan "Firmware image has been deployed. The process will continue after reboot." } <# .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 Like 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. This parameter can also be specified as Match, for backwards compatibility. This parameter is now obsolete and may be removed at a future time. You can simply pass wildcards in the name field instead of using the like parameter. The following two examples are identical: Get-HPDeviceDetails -name '\*EliteBook\*' is the same as: Get-HPDeviceDetails -like -name 'EliteBook' .PARAMETER OSList Return the list of supported operating systems for the specified platform. .PARAMETER Url Specify an alternate location for the HP Image Assistant (HPIA) platform list XML. This URL must be http or https. If not specified, https://hpia.hpcloud.hp.com/ref is used by default. .EXAMPLE Get-HPDeviceDetails -Platform 8100 .EXAMPLE Get-HPDeviceDetails -Name 'HP ProOne 400 G3 20-inch Touch All-in-One PC' .EXAMPLE Get-HPDeviceDetails -Like -Name '840 G5' #> function Get-HPDeviceDetails { [CmdletBinding( DefaultParameterSetName = "FromID", HelpUri = "https://developers.hp.com/hp-client-management/doc/Get-HPDeviceDetails") ] param( [ValidatePattern("^[a-fA-F0-9]{4}$")] [Parameter(Mandatory = $false,Position = 0,ParameterSetName = "FromID")] [string]$Platform, [Parameter(Mandatory = $true,Position = 1,ParameterSetName = "FromName")] [string]$Name, [Parameter(Mandatory = $false,Position = 2,ParameterSetName = "FromName")] [Alias('Match')] [switch]$Like, [Parameter(Mandatory = $false,ParameterSetName = "FromName")] [Parameter(Mandatory = $false,ParameterSetName = "FromID")] [switch]$OSList, [Parameter(Mandatory = $false,Position = 3,ParameterSetName = "FromName")] [Parameter(Mandatory = $false,Position = 1,ParameterSetName = "FromID")] [string]$Url = "https://hpia.hpcloud.hp.com/ref" ) if (Test-WinPE -Verbose:$VerbosePreference) { throw "Getting HP Device details is not supported in WinPE" } $filename = "platformList.cab" $Url = "$Url/$filename" $try_on_ftp = $false try { $file = Get-HPPrivateOfflineCacheFiles -url $Url -FileName $filename -Expand -Verbose:$VerbosePreference } catch { # platformList is not reachable on AWS, try to get it from FTP $try_on_ftp = $true } if ($try_on_ftp) { try { $url = "https://ftp.hp.com/pub/caps-softpaq/cmit/imagepal/ref/platformList.cab" $file = Get-HPPrivateOfflineCacheFiles -url $url -FileName $filename -Expand -Verbose:$VerbosePreference } catch { Write-Host -ForegroundColor Magenta "platformList is not available on AWS or FTP." throw [System.Net.WebException]"Could not find platformList." } } if (-not $platform -and -not $Name) { try { $platform = Get-HPDeviceProductID -Verbose:$VerbosePreference } catch { Write-Verbose "No platform found." } } if ($platform) { $platform = $platform.ToLower() } if ($PSCmdlet.ParameterSetName -eq "FromID") { $data = Select-Xml -Path "$file" -XPath "/ImagePal/Platform/SystemID[normalize-space(.)=`"$platform`"]/parent::*" } else { $data = Select-Xml -Path "$file" -XPath "/ImagePal/Platform/ProductName[translate(substring(`"$($name.ToLower())`",0), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')]/parent::*" } if (-not $data) { return } $searchName = $Name if ($Like.IsPresent) { if (-not ($searchName).StartsWith('*')) { $searchName = ("*$searchName") } if (-not ($searchName).EndsWith('*')) { $searchName = ("$searchName*") } } $data.Node | ForEach-Object { $__ = $_ $pn = $_.ProductName. "#text" if ($oslist.IsPresent) { [array]$r = ($__.OS | ForEach-Object { if (($PSCmdlet.ParameterSetName -eq "FromID") -or ($pn -like $searchName)) { $rid = $Null if ("OSReleaseId" -in $_.PSObject.Properties.Name) { $rid = $_.OSReleaseId } [string]$osv = $_.OSVersion if ("OSReleaseIdDisplay" -in $_.PSObject.Properties.Name -and $_.OSReleaseIdDisplay -ne '20H2') { $rid = $_.OSReleaseIdDisplay } $obj = New-Object -TypeName PSCustomObject -Property @{ SystemID = $__.SystemID.ToUpper() OperatingSystem = $_.OSDescription OperatingSystemVersion = $osv Architecture = $_.OSArchitecture } if ($rid) { $obj | Add-Member -NotePropertyName OperatingSystemRelease -NotePropertyValue $rid } if ("OSBuildId" -in $_.PSObject.Properties.Name) { $obj | Add-Member -NotePropertyName BuildNumber -NotePropertyValue $_.OSBuildId } $obj } }) } else { [array]$r = ($__.ProductName | ForEach-Object { if (($PSCmdlet.ParameterSetName -eq "FromID") -or ($_. "#text" -like $searchName)) { New-Object -TypeName PSCustomObject -Property @{ SystemID = $__.SystemID.ToUpper() Name = $_. "#text" DriverPackSupport = [System.Convert]::ToBoolean($_.DPBCompliant) UWPDriverPackSupport = [System.Convert]::ToBoolean($_.UDPCompliant) } } }) } return $r } } 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 if ($null -ne $setting.Value) { $fields = $setting.Value.Split(",") foreach ($f in $fields) { Write-Output "`t$f" } } else { Write-Output "`t$($setting.Value)" } } } } 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") { #if Elements is null, initialize it as an empty array else select the first object $Elements = $setting.Elements,@() | Select-Object -First 1 $min = $Elements.Count $max = $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 $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 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 } # SIG # Begin signature block # MIIt/gYJKoZIhvcNAQcCoIIt7zCCLesCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBJmlzcI0bk0tb+ # 9StpLrH3bEBH7tzfnwlk6gZ5/ulIfKCCE2wwggXAMIIEqKADAgECAhAP0bvKeWvX # +N1MguEKmpYxMA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzApBgNV # BAMTIkRpZ2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIEVWIFJvb3QgQ0EwHhcNMjIwMTEz # MDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQD # ExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4IC # DwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aa # za57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllV # cq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT # +CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd # 463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+ # EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92k # J7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5j # rubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 # f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJU # KSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+wh # X8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQAB # o4IBZjCCAWIwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5n # P+e6mK4cD08wHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDgYDVR0P # AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMH8GCCsGAQUFBwEBBHMwcTAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEkGCCsGAQUFBzAC # hj1odHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJh # bmNlRVZSb290Q0EuY3J0MEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwHAYD # VR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcNAQELBQADggEBAEHx # qRH0DxNHecllao3A7pgEpMbjDPKisedfYk/ak1k2zfIe4R7sD+EbP5HU5A/C5pg0 # /xkPZigfT2IxpCrhKhO61z7H0ZL+q93fqpgzRh9Onr3g7QdG64AupP2uU7SkwaT1 # IY1rzAGt9Rnu15ClMlIr28xzDxj4+87eg3Gn77tRWwR2L62t0+od/P1Tk+WMieNg # GbngLyOOLFxJy34riDkruQZhiPOuAnZ2dMFkkbiJUZflhX0901emWG4f7vtpYeJa # 3Cgh6GO6Ps9W7Zrk9wXqyvPsEt84zdp7PiuTUy9cUQBY3pBIowrHC/Q7bVUx8ALM # R3eWUaNetbxcyEMRoacwggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G # CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C # 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce # 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da # E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T # SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA # FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh # D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM # 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z # 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05 # huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY # mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP # /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T # AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD # VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV # HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN # BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry # sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL # IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf # Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh # OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh # dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV # 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j # wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH # Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC # XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l # /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW # eE4wggbwMIIE2KADAgECAhAI+qTPsJ3byDJ7SsgX0LBUMA0GCSqGSIb3DQEBCwUA # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwHhcNMjIwMzA5MDAwMDAwWhcNMjMwMzA5MjM1OTU5WjB1MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAGA1UEBxMJUGFsbyBB # bHRvMRAwDgYDVQQKEwdIUCBJbmMuMRkwFwYDVQQLExBIUCBDeWJlcnNlY3VyaXR5 # MRAwDgYDVQQDEwdIUCBJbmMuMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC # AYEA2KwFARbsSL8FnMdZ++xo7iVdqg+ZOY0S2KkvYQdNNcvrcfHTdNpNgf65RuIt # VQxdJXzmZcAOXJUPjRQRduvFf/I8jqR4UwBLsNoy/sEuQIDCfezNSQz8TPredjUG # Lr6Y9ie1vYryqJ110Mj6NtXZQidlytEneq3z73Ec7TRFKp8iiiwNpTcbhAq93pq6 # bjnc98ajFUBHJu9Gfk1Or3haR6m7YH0LRLVWm18I2OKrcPLk67hWRj6Aa7/heBkk # F8TfGCUwGBHhblrprBVECR3M4zTnMygBfxVEzYsdyAytPy0DgqzZ7+rHY0yvgDUx # Fi/d1SyqNDCf6FBBudNjzw7TULEBHlJjk96xhd1z4X5ctL1kW4duC7Mba6H8A1lI # qM5qa+8Fr88IJhnl21PlkBp+XAk3lBaeJ/DVpORIv3bhUV8OLae6ElQBGvqQoEY/ # AaNerghhFjiqAhaUG3z3Y7ruhVaCmuw/SMVS79dxESj/J1qHWVnF1tn2a4liq/RY # VeFTAgMBAAGjggIGMIICAjAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiIZfRO # QjAdBgNVHQ4EFgQUAjIiVx974XGZre7F5HqNCJiWZbowDgYDVR0PAQH/BAQDAgeA # MBMGA1UdJQQMMAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0dHA6 # Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5n # UlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEz # ODQyMDIxQ0ExLmNybDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIB # FhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQGCCsGAQUFBwEBBIGHMIGE # MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUH # MAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRH # NENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAwGA1UdEwEB/wQC # MAAwDQYJKoZIhvcNAQELBQADggIBAFrOPeL4ph8SmHwwcUQO7nPnapyOS0I50w70 # nVZ9CtrgyA7hiZmVm/CsC1JU8zg1dNyfH7wCDaoMAnqtybcdmhIXc4STwfcpiKOH # nL3fRQcZ2zCCXmX5lkWYWni9Nqx603JQ8yiUSl1sMyv0Cd4RasOBHnjQuekDDKNT # QvOiEA3NCZDGEjtIjE+TGqLW2kUEtjxzyr0mnhmidRaHry5C1GKu0mlKExwabOLW # xGrXj4FPtKmWXZh00lMbbdeHm1Zqn9CTsO6xt8CQXSemcpb7lXY80um71wQO23ub # tQGDe4QpShomqPmEIVxM5/B6Yih/0Lb8mt60SLfT5EOVS/Dhd86lSHcncL9JLxaq # WwbQhIwpEa4b3MiZqyemqb0+YIBn5yG43M4oLzRPTo2mPwG19OtnMVZsrcjGEzLz # EiBb9/YXsf8G5LAh86x2kRKDad35NNNojUJYVBtD7MGEsL37XF+6kWXsp92on2b2 # QLEL/5ZzJHmfrJ8m0TXMb4sMSI2KnHtCvEjG2MIAnjFEvNZ1ZFsKS78mwylDyHL0 # yTuv08JqDuommKgjmyvtLEeb6OYsOnSVQIcyV4XCY1kFA8mDuIsIlbWE3Nyv94Of # N+4jNKcDzniYb5LmKlXraIM8PjPpYb34DlNpzCDN7/tJuMFsy/NwArj1SiL630mg # Dm0fS5OgMYIZ6DCCGeQCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBT # aWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAI+qTPsJ3byDJ7SsgX0LBU # MA0GCWCGSAFlAwQCAQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkD # MQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJ # KoZIhvcNAQkEMSIEIEsE6A62XrFtUlu17zsHKEJK5IP9+Mvnp5lAQkBkCw52MA0G # CSqGSIb3DQEBAQUABIIBgCO9vrlhlcQ8Kpl5g/wfmGq2LN2WOsvOXLBhrDbNfGjH # NTblO0+WODfDyu/zzaG1zY14AGBBDVXuylXenw3t1qzLb1AUpuFgJzEvPYWx138D # L5p1t36jCWlUbqfrpDQPxkyTpYeW2z6dEoeA+GEGKhm0z6MhthWDl++UmHLUzjHA # bvTlxVabdEZIWnDWOZL3m/YYreNPZI+Uxco554acNRLsbZLla/sGN2rFtLJ1N5x3 # OOybc78CycX9bGqDimYzjEqbo4iKEPyV7TBfW9RRCZNPGHWD3ARYpj1BhAJDVz0n # ra+NMjrbfIJ4XXBGQCRXZyGNVcLlh/G5Zg5IsqDycwWOloAOBCt2GLkhijiqXXA9 # 95yOC2N2Ls7lLkGeCTmdiMSezVTxwd9UKxa14T+QKCNqEfdFB0+UYrsSprVV1sc0 # /ltIpzYM7YPwr0KxAMkbOXhbITj+8ccjb8ChPEmCZpIYyNEFt9reRV+w0zIiqsDo # etstouqKeVgbVr7bbq33/KGCFz4wghc6BgorBgEEAYI3AwMBMYIXKjCCFyYGCSqG # SIb3DQEHAqCCFxcwghcTAgEDMQ8wDQYJYIZIAWUDBAIBBQAweAYLKoZIhvcNAQkQ # AQSgaQRnMGUCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQCAQUABCCub9Ag4rXg # K7UFXedct4KMR7mV472J2hoAkIW+AyjBGgIRAIqrRFFNNAvCEoMi6P5VB1EYDzIw # MjIxMjAyMjAyODQ0WqCCEwcwggbAMIIEqKADAgECAhAMTWlyS5T6PCpKPSkHgD1a # MA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy # dCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNI # QTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjIwOTIxMDAwMDAwWhcNMzMxMTIxMjM1 # OTU5WjBGMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQxJDAiBgNVBAMT # G0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIyIC0gMjCCAiIwDQYJKoZIhvcNAQEBBQAD # ggIPADCCAgoCggIBAM/spSY6xqnya7uNwQ2a26HoFIV0MxomrNAcVR4eNm28klUM # YfSdCXc9FZYIL2tkpP0GgxbXkZI4HDEClvtysZc6Va8z7GGK6aYo25BjXL2JU+A6 # LYyHQq4mpOS7eHi5ehbhVsbAumRTuyoW51BIu4hpDIjG8b7gL307scpTjUCDHufL # ckkoHkyAHoVW54Xt8mG8qjoHffarbuVm3eJc9S/tjdRNlYRo44DLannR0hCRRinr # PibytIzNTLlmyLuqUDgN5YyUXRlav/V7QG5vFqianJVHhoV5PgxeZowaCiS+nKrS # nLb3T254xCg/oxwPUAY3ugjZNaa1Htp4WB056PhMkRCWfk3h3cKtpX74LRsf7CtG # GKMZ9jn39cFPcS6JAxGiS7uYv/pP5Hs27wZE5FX/NurlfDHn88JSxOYWe1p+pSVz # 28BqmSEtY+VZ9U0vkB8nt9KrFOU4ZodRCGv7U0M50GT6Vs/g9ArmFG1keLuY/ZTD # cyHzL8IuINeBrNPxB9ThvdldS24xlCmL5kGkZZTAWOXlLimQprdhZPrZIGwYUWC6 # poEPCSVT8b876asHDmoHOWIZydaFfxPZjXnPYsXs4Xu5zGcTB5rBeO3GiMiwbjJ5 # xwtZg43G7vUsfHuOy2SJ8bHEuOdTXl9V0n0ZKVkDTvpd6kVzHIR+187i1Dp3AgMB # AAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUB # Af8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1s # BwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0OBBYEFGKK # 3tBh/I8xFO2XC809KpQU31KcMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwz # LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1l # U3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUFBzABhhho # dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6Ly9jYWNl # cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZU # aW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAFWqKhrzRvN4Vzcw # /HXjT9aFI/H8+ZU5myXm93KKmMN31GT8Ffs2wklRLHiIY1UJRjkA/GnUypsp+6M/ # wMkAmxMdsJiJ3HjyzXyFzVOdr2LiYWajFCpFh0qYQitQ/Bu1nggwCfrkLdcJiXn5 # CeaIzn0buGqim8FTYAnoo7id160fHLjsmEHw9g6A++T/350Qp+sAul9Kjxo6UrTq # vwlJFTU2WZoPVNKyG39+XgmtdlSKdG3K0gVnK3br/5iyJpU4GYhEFOUKWaJr5yI+ # RCHSPxzAm+18SLLYkgyRTzxmlK9dAlPrnuKe5NMfhgFknADC6Vp0dQ094XmIvxwB # l8kZI4DXNlpflhaxYwzGRkA7zl011Fk+Q5oYrsPJy8P7mxNfarXH4PMFw1nfJ2Ir # 3kHJU7n/NBBn9iYymHv+XEKUgZSCnawKi8ZLFUrTmJBFYDOA4CPe+AOk9kVH5c64 # A0JH6EE2cXet/aLol3ROLtoeHYxayB6a1cLwxiKoT5u92ByaUcQvmvZfpyeXupYu # hVfAYOd4Vn9q78KVmksRAsiCnMkaBXy6cbVOepls9Oie1FqYyJ+/jbsYXEP10Cro # 4mLueATbvdH7WwqocH7wl4R44wgDXUcsY6glOJcB0j862uXl9uab3H4szP8XTE0A # otjWAQ64i+7m4HJViSwnGWH2dwGMMIIGrjCCBJagAwIBAgIQBzY3tyRUfNhHrP0o # ZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhE # aWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIwMzIzMDAwMDAwWhcNMzcwMzIy # MjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x # OzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGlt # ZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxoY1 # BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCwzIP5WvYRoUQVQl+kiPNo+n3z # nIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFzsbPuK4CEiiIY3+vaPcQXf6sZ # Kz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ7Gnf2ZCHRgB720RBidx8ald6 # 8Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7QKxfst5Kfc71ORJn7w6lY2zk # psUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/tePc5OsLDnipUjW8LAxE6lXKZYn # LvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCYOjgRs/b2nuY7W+yB3iIU2YIq # x5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9KoRxrOMUp88qqlnNCaJ+2RrOd # OqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6dSgkQe1CvwWcZklSUPRR8zZJ # TYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM1+mYSlg+0wOI/rOP015LdhJR # k8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbCdLI/Hgl27KtdRnXiYKNYCQEo # AA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbECAwEAAaOCAV0wggFZMBIGA1Ud # EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1NhS9zKXaaL3WMaiCPnshvMB8G # A1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjAT # BgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGG # GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2Nh # Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYD # VR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9 # bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7ZvmKlEIgF+ZtbYIULhsBguEE0T # zzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI2AvlXFvXbYf6hCAlNDFnzbYS # lm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/tydBTX/6tPiix6q4XNQ1/tYLaq # T5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVPulr3qRCyXen/KFSJ8NWKcXZl # 2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmBo1aGqwpFyd/EjaDnmPv7pp1y # r8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc6UsCUqc3fpNTrDsdCEkPlM05 # et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3cHXg65J6t5TRxktcma+Q4c6um # AU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0dKNPH+ejxmF/7K9h+8kaddSwe # Jywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZPJ/tgZxahZrrdVcA6KYawmKAr # 7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLeMt8EifAAzV3C+dAjfwAL5HYC # JtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDyDivl1vupL0QVSucTDh3bNzga # oSv27dZ8/DCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZIhvcN # AQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG # A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJl # ZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVowYjEL # MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 # LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0 # MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjwwIjBp # M+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J58soR # 0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMHhOZ0 # O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6Zu53 # yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQecN4 # x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4bA3Vd # eGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9WV1C # doeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCUtNJh # besz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvoZKYz # 0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/JvNNB # ERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCPorF+ # CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMBAf8w # HQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXroq/0 # ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRtMGsw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcw # AoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElE # Um9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2Vy # dC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgwBgYE # VR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cHvZqs # oYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8UgPI # TtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTnf+hZ # qPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxUjG/v # oVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8jLfR+ # cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDGCA3YwggNy # AgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTsw # OQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVT # dGFtcGluZyBDQQIQDE1pckuU+jwqSj0pB4A9WjANBglghkgBZQMEAgEFAKCB0TAa # BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIyMTIw # MjIwMjg0NFowKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQU84ciTYYzgpI1qZS8vY+W # 6f4cfHMwLwYJKoZIhvcNAQkEMSIEIEOzLgCQdZ8OVICA97KgofzC73U63EOeuUdc # Dat6bx3BMDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEIMf04b4yKIkgq+ImOr4axPxP # 5ngcLWTQTIB1V6Ajtbb6MA0GCSqGSIb3DQEBAQUABIICAKyJQJnADQI72J6Vrszx # 6zIwZQMVq/3+Ah3jzBx8RMPx/QRMuQwBkvUDx6v68+i76Bzy6g09HCPy+NN3j/Y9 # Ew3VeXE+08B/+dkBIK9GWnGgrBsHU0Ypcy0w5/a5UM6v4a/QZtsbV61vSEzrwLdO # tXuBaMpipF/KHj29HVpG7e88mzScJmw4OOk8R7x8PtKYO63BUzfGR0cGJ6/LQcIf # gGg5V4aBesJX+A56aDAgazxNr/hZR2wJEDzz4i2hNbg+zgdKCuHvK7EnW9iq/ZnW # Mws2Z2XTCi/8S8CqRJDGDcHexJ3HD9XsyrzT7JM5q0Z1dBRnq4HYvqcJTRB5sRFW # jDou7jZHiN3AHrke0veig2U4Ckgj8KKMVtu8iGi5NrDvLfnGIXL+f31RoEiblKWz # VyEfHyJK5Pben69DN6iYbO9gISdchpLEGC5/awDHC6WYT+MTX1xOzeDbVsZRCEqx # 92I3k5/yumJGJIiukYjGelG1HATOYBTJy6dLUH7VE2nc1hZ7LUyQkKQhVbCCgL/b # yMxseXO1VysCQTLviejGKQ/9GqYD58uFObqJylWykAK5bhQC5DpjRoinlmW2ks2a # hAB5h2flefqOELlhf/xSEvAbbkSWqsX6MaY5OXwEIuQrywwgd5gdGdallw8MdwIg # HDfM2hMfWtRUzEsxqy3LRBHf # SIG # End signature block |