HP.Firmware.SureAdmin.psm1
# # Copyright 2018-2021 HP Development Company, L.P. # All Rights Reserved. # # NOTICE: All information contained herein is, and remains the property of HP Development Company, L.P. # # The intellectual and technical concepts contained herein are proprietary to HP Development Company, L.P # and may be covered by U.S. and Foreign Patents, patents in process, and are protected by # trade secret or copyright law. Dissemination of this information or reproduction of this material # is strictly forbidden unless prior written permission is obtained from HP Development Company, L.P. Set-StrictMode -Version 3.0 $ErrorActionPreference = 'Stop' #requires -Modules "HP.Private" #requires -Modules "HP.ClientManagement" <# .SYNOPSIS Get the current state of the HP Sure Admin feature .DESCRIPTION This function returns the current state of the HP Sure Admin feature .NOTES - Requires HP P21 enabled. - Supported on Windows 10. - Requires HP BIOS with HP Sure Admin support. - This command requires elevated privileges. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) #> function Get-HPSureAdminState { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/get%e2%80%90hpsureadminstate")] param() $mode = "Disable" $sk = "" $signingKeyID = "" $ver = "" $lak1 = "" $sarc = 0 $aarc = 0 $local_access = "" $lak1_keyID = "" $lak1_key_enrollment_data = "" if ((Get-HPPrivateIsSureAdminSupported) -eq $true) { try { $mode = Get-HPBIOSSettingValue -Name "Enhanced BIOS Authentication Mode" } catch {} try { $sk = Get-HPBIOSSettingValue -Name "Secure Platform Management Signing Key" } catch {} try { $ver = Get-HPBIOSSettingValue -Name "Enhanced BIOS Authentication Mode Version" } catch {} try { $lak1 = Get-HPBIOSSettingValue -Name "Enhanced BIOS Authentication Mode Local Access Key 1" } catch {} try { $sarc = Get-HPBIOSSettingValue -Name "Enhanced BIOS Authentication Mode Settings Anti-Replay Counter" } catch {} try { $aarc = Get-HPBIOSSettingValue -Name "Enhanced BIOS Authentication Mode Actions Anti-Replay Counter" } catch {} #modify signingKeyID if ($sk) { #decode the base64 encoded string $sk_decoded = [Convert]::FromBase64String($sk) # hash the decoded string $sk_hash = Get-HPPrivateHash -Data $sk_decoded #encode the hashed value $signingKeyID = [System.Convert]::ToBase64String($sk_hash) } #calculate local access, lak1_keyID and lak1_key_enrollment_data values from lak1 if ((-not $lak1) -and ((Get-HPBIOSSetupPasswordIsSet) -eq $true) -and ($mode -eq "Enable")) { $local_access = "BIOS Password Protection only" $lak1_keyID = "Not Configured" } elseif ((-not $lak1) -and ((Get-HPBIOSSetupPasswordIsSet) -eq $false) -and ($mode -eq "Enable")) { $local_access = "Not Protected" $lak1_keyID = "Not Configured" } elseif ($lak1 -and ($mode -eq "Enable")) { $local_access = "Configured" try { $lak1_length = $lak1.Length $lak1_substring = $lak1.Substring(0, 344) #decode the base64 encoded string $lak1_decoded = [Convert]::FromBase64String($lak1_substring) # hash the decoded string $lak1_hash = Get-HPPrivateHash -Data $lak1_decoded #encode the hashed value $lak1_keyID = [System.Convert]::ToBase64String($lak1_hash) if ($lak1_length -gt 344) { $pos = $lak1.IndexOf("==") $ked_substring = $lak1.Substring($pos+2) if ($ked_substring) { $lak1_key_enrollment_data = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($ked_substring)) } } } catch { $lak1_keyID = "" $lak1_key_enrollment_data = "" } } else { $local_access = "" $lak1_keyID = "" $lak1_key_enrollment_data = "" } $result = [ordered]@{ SureAdminMode = if ($mode -eq "Enable") {"On"} else { "Off" } SigningKeyID = $signingKeyID EnhancedAuthenticationVersion = $ver SettingsCounter = $sarc ActionsCounter = $aarc LocalAccess = $local_access LocalAccessKey1 = $lak1 LAK1_KeyID = $lak1_keyID LAK1_KeyEnrollmentData = $lak1_key_enrollment_data } New-Object -TypeName PSObject -Property $result } } function Get-HPSecurePlatformIsProvisioned { [boolean]$status = $false try { $c = 'Get-HPSecurePlatformState' $result = Invoke-Expression -Command $c if ($result.State -eq "Provisioned") { $status = $true } } catch {} return $status } <# .SYNOPSIS Generate a payload for authorizing a firmware update .DESCRIPTION This function uses the provided key to sign and authorize a firmware update only to the specified file. On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter. This payload can then be passed to the [Update-HPFirmware](https://developers.hp.com/cmsl-staging/doc/update%E2%80%90hpfirmware) function. Security note: Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the Update-HPFirmware. .PARAMETER File The firmware update binary (.BIN) file. .PARAMETER SigningKeyFile The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended), the SigningKeyPassword parameter should also be provided. .PARAMETER SigningKeyPassword The secure platform signing key file password, if required. .PARAMETER SigningKeyCertificate The secure platform signing key certificate, as an X509Certificate object. .PARAMETER Nonce The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a nonce greater or equal to the last nonce sent. If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds, so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller should use its own nonce derivation and provide it through this parameter. .PARAMETER TargetUUID The computer UUID on which to perform this operation. If not specified the payload generated will work on any computer. .PARAMETER SingleUse If specified, the payload cannot be replayed. This happens because the nonce must be higher than ActionsCounter and this counter is updated and incremented every time a command generated with SingleUse flag is accepted by the BIOS. If not specified, the payload can be replayed as many times as desired until a payload generated with a nonce higher than SettingsCounter is received. This happens because SettingsCounter is not incremented by the BIOS when accepting commands. .PARAMETER OutputFile Write the resulting output to the specified file, instead of writing it to the pipeline. .PARAMETER Quiet Suppress non-essential messages .PARAMETER Bitlocker Provide an answer to the Bitlocker check prompt (if any). The value may be one of: stop - stop if Bitlocker is detected but not suspended, and prompt. stop is default when Bitlocker switch is provided. ignore - skip the Bitlocker check suspend - suspend Bitlocker if active, and continue .PARAMETER Force Force the BIOS update, even if the target BIOS is already installed. .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP BIOS with HP Sure Admin support is required for applying the payloads generated by this function. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) .EXAMPLE New-HPSureAdminFirmwareUpdatePayload -File bios.bin -SigningKeyFile "$path\signing_key.pfx" -SigningKeyPassword "s3cr3t" -OutputFile PayloadFile.dat Update-HPFirmware -File bios.bin -PayloadFile PayloadFile.dat #> function New-HPSureAdminFirmwareUpdatePayload { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/new%e2%80%90hpsureadminfirmwareupdatepayload")] param( [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 1)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 1)] [System.IO.FileInfo]$File, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 2)] [System.IO.FileInfo]$SigningKeyFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 3)] [string]$SigningKeyPassword, [Parameter(ValueFromPipeline = $true,ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 2)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 4)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 3)] [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s").Replace(',','.')), [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 5)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 4)] [guid]$TargetUUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff', [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 6)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 5)] [switch]$SingleUse, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 7)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 6)] [System.IO.FileInfo]$OutputFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 8)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 7)] [switch]$Quiet, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 9)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 8)] [ValidateSet('stop','ignore','suspend')] [string]$Bitlocker = 'stop', [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 10)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 9)] [switch]$Force ) $signingKey = (Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -Password $SigningKeyPassword -cert $SigningKeycertificate -Verbose:$VerbosePreference).Full $params = @{ File = $File SingleUse = $SingleUse Nonce = $Nonce TargetUUID = $TargetUUID SigningKey = $signingKey } [byte[]]$authorization = New-HPPrivateSureAdminFirmwareUpdateAuthorization @params $data = @{ Authorization = $authorization FileName = $File.Name Quiet = $Quiet.IsPresent Bitlocker = $Bitlocker Force = $Force.IsPresent } | ConvertTo-Json New-HPPrivatePortablePayload -Data $data -Purpose "hp:sureadmin:firmwareupdate" -OutputFile $OutputFile -Verbose:$VerbosePreference } function New-HPPrivateSureAdminFirmwareUpdateAuthorization { param( [System.IO.FileInfo]$File, [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKey, [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s").Replace(',','.')), [guid]$TargetUUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff', [switch]$SingleUse ) Write-Verbose "Creating authentication payload" $name = "Allowed BIOS Update Hash" $fileHash = (Get-FileHash -Path $File -Algorithm SHA256).hash # set value using raw bytes [byte[]]$valuebytes = [byte[]] -split ($fileHash -replace '..', '0x$& ') $setting = New-Object -TypeName SureAdminSetting $setting.Name = $Name $setting.Value = $fileHash $nameLen = [System.Text.Encoding]::Unicode.GetByteCount($Name) $valueLen = $valuebytes.Length $params = @{ NameLen = $nameLen ValueLen = $valueLen SingleUse = $SingleUse Nonce = $Nonce TargetUUID = $TargetUUID } [byte[]]$header = Invoke-HPPrivateConstructHeader @params -Verbose:$VerbosePreference [byte[]]$payload = New-Object byte[] ($Header.Count + $nameLen + $valueLen) $namebytes = [System.Text.Encoding]::Unicode.GetBytes($Name) [System.Array]::Copy($Header,0,$payload,0,$Header.Length) [System.Array]::Copy($namebytes,0,$payload,$Header.Length,$namebytes.Length) [System.Array]::Copy($valuebytes,0,$payload,$Header.Length + $namebytes.Length,$valuebytes.Length) [byte[]]$signature = Invoke-HPPrivateSignData -data $payload -Certificate $SigningKey $tag = "<BEAM/>" $tagBytes = [System.Text.Encoding]::Unicode.GetBytes($tag) [byte[]]$authorization = New-Object byte[] ($namebytes.Length + $valuebytes.Length + $tagBytes.Length + $Header.Length + $Signature.Length) $offset = 0 [System.Array]::Copy($namebytes,0,$authorization,$offset,$namebytes.Length) $offset += $namebytes.Length [System.Array]::Copy($valuebytes,0,$authorization,$offset,$valuebytes.Length) $offset += $valuebytes.Length [System.Array]::Copy($tagBytes,0,$authorization,$offset,$tagBytes.Length) $offset += $tagBytes.Length [System.Array]::Copy($Header,0,$authorization,$offset,$Header.Length) $offset += $Header.Length [System.Array]::Copy($Signature,0,$authorization,$offset,$Signature.Length) #($authorization | Format-Hex) return $authorization } <# .SYNOPSIS Generate a payload for authorizing multiple BIOS setting changes .DESCRIPTION This function uses the provided key to sign and authorize multiple BIOS setting changes. On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter. This payload can then be passed to the [Set-HPSecurePlatformPayload](https://developers.hp.com/cmsl-staging/doc/set%E2%80%90hpsecureplatformpayload) function. Security note: Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the Set-HPSecurePlatformPayload. Creating the payload and passing it to the Set-HPSecurePlatformPayload function via the pipeline is not a recommended production pattern. .PARAMETER SigningKeyFile The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended), the SigningKeyPassword parameter should also be provided. .PARAMETER SigningKeyPassword The secure platform signing key file password, if required. .PARAMETER SigningKeyCertificate The secure platform signing key certificate, as an X509Certificate object. .PARAMETER Nonce The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a nonce greater or equal to the last nonce sent. If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds, so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller should use its own nonce derivation and provide it through this parameter. .PARAMETER InputFile The file (relative or absolute path) to the file to process containing one or more BIOS settings. .PARAMETER Format The file format (XML, Json, CSV, or BCU). .PARAMETER TargetUUID The computer UUID on which to perform this operation. If not specified the payload generated will work on any computer. .PARAMETER OutputFile Write the resulting output to the specified file, instead of writing it to the pipeline. .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP BIOS with HP Sure Admin support is required for applying the payloads generated by this function. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) .EXAMPLE $payload = New-HPSureAdminBIOSSettingsListPayload -SigningKeyFile "$path\signing_key.pfx" -InputFile "settings.BCU" -Format BCU $payload | Set-HPSecurePlatformPayload .EXAMPLE New-HPSureAdminBIOSSettingsListPayload -SigningKeyFile "$path\signing_key.pfx" -SigningKeyPassword "s3cr3t" -InputFile "settings.BCU" -Format BCU -OutputFile PayloadFile.dat Set-HPSecurePlatformPayload -PayloadFile PayloadFile.dat #> function New-HPSureAdminBIOSSettingsListPayload { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/new%e2%80%90hpsureadminbiossettingslistpayload")] param( [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 0)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 0)] [System.IO.FileInfo]$InputFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 1)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 1)] [ValidateSet('Xml','Json','BCU','CSV')] [string]$Format = $null, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 2)] [System.IO.FileInfo]$SigningKeyFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 3)] [string]$SigningKeyPassword, [Parameter(ValueFromPipeline = $true,ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 3)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 5)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 5)] [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s").Replace(',','.')), [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 6)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 6)] [guid]$TargetUUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff', [System.IO.FileInfo]$OutputFile ) Write-Verbose "Format specified: '$Format'. Reading file..." [System.Collections.Generic.List[SureAdminSetting]]$settingsList = $null $settingsList = Get-HPPrivateSettingsFromFile -FileName $InputFile -Format $Format $signingKey = (Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -Password $SigningKeyPassword -cert $SigningKeycertificate -Verbose:$VerbosePreference).Full $params = @{ SettingsList = $settingsList Nonce = $Nonce TargetUUID = $TargetUUID SigningKey = $signingKey SigningKeyPassword = $SigningKeyPassword } $settingsList = New-HPPrivateSureAdminBIOSSettingsObject @params $data = $settingsList | ConvertTo-Json New-HPPrivatePortablePayload -Data $data -Purpose "hp:sureadmin:biossettingslist" -OutputFile $OutputFile } function New-HPPrivatePortablePayload { param( [string]$Data, [string]$Purpose, [System.IO.FileInfo]$OutputFile ) $output = New-Object -TypeName PortableFileFormat $output.timestamp = Get-Date $output.purpose = $Purpose $output.Data = [System.Text.Encoding]::UTF8.GetBytes($Data) if ($OutputFile) { Write-Verbose 'Will output to file $OutputFile' $f = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputFile) $output | ConvertTo-Json -Compress | Out-File -FilePath $f -Encoding utf8 } else { $output | ConvertTo-Json -Compress } } function New-HPPrivateSureAdminBIOSSettingsObject { param( [System.Collections.Generic.List[SureAdminSetting]]$SettingsList, [switch]$SingleUse, [uint32]$Nonce, [guid]$TargetUUID, [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKey, [string]$SigningKeyPassword ) Write-Verbose "Signing settings list" for ($i = 0; $i -lt $SettingsList.Count; $i++) { $setting = $SettingsList[$i] $params = @{ Name = $setting.Name Value = $setting.Value Nonce = $Nonce TargetUUID = $TargetUUID SigningKey = $SigningKey SigningKeyPassword = $SigningKeyPassword } if ($setting.AuthString -eq $null) { $SettingsList[$i] = New-HPPrivateSureAdminBIOSSettingObject @params -Verbose:$VerbosePreference } } return $SettingsList } function New-HPPrivateSureAdminBIOSSettingObject { param( [string]$Name, [string]$Value, [switch]$SingleUse, [uint32]$Nonce, [guid]$TargetUUID, [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKey ) [SureAdminSetting]$setting = New-Object -TypeName SureAdminSetting $setting.Name = $Name $setting.Value = $Value if ($Name -eq "Setup Password" -or $Name -eq "Power-On Password") { $SettingValueForSigning = "<utf-16/>" + $Value } else { $SettingValueForSigning = $Value } $nameLen = [System.Text.Encoding]::Unicode.GetByteCount($setting.Name) $valueLen = [System.Text.Encoding]::Unicode.GetByteCount($SettingValueForSigning) $params = @{ NameLen = $nameLen ValueLen = $valueLen SingleUse = $SingleUse Nonce = $Nonce TargetUUID = $TargetUUID } [byte[]]$header = Invoke-HPPrivateConstructHeader @params -Verbose:$VerbosePreference [byte[]]$payload = Invoke-HPPrivateConstructPayload -Header $header -Name $setting.Name -Value $SettingValueForSigning -Verbose:$VerbosePreference [byte[]]$signature = Invoke-HPPrivateSignData -data $payload -Certificate $SigningKey -Verbose:$VerbosePreference $setting.AuthString = Invoke-HPPrivateConstructAuthorization -Header $header -Signature $signature -Verbose:$VerbosePreference return $setting } <# .SYNOPSIS Generate a payload for resetting BIOS settings to default values .DESCRIPTION This function uses the provided key to sign and authorize resetting BIOS settings to default values. On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter. This payload can then be passed to the [Set-HPSecurePlatformPayload](https://developers.hp.com/cmsl-staging/doc/set%E2%80%90hpsecureplatformpayload) function. Security note: Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the Set-HPSecurePlatformPayload. Creating the payload and passing it to the Set-HPSecurePlatformPayload function via the pipeline is not a recommended production pattern. .PARAMETER SigningKeyFile The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended), the SigningKeyPassword parameter should also be provided. .PARAMETER SigningKeyPassword The secure platform signing key file password, if required. .PARAMETER SigningKeyCertificate The secure platform signing key certificate, as an X509Certificate object. .PARAMETER Nonce The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a nonce greater or equal to the last nonce sent. If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds, so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller should use its own nonce derivation and provide it through this parameter. .PARAMETER TargetUUID The computer UUID on which to perform this operation. If not specified the payload generated will work on any computer. .PARAMETER OutputFile Write the resulting output to the specified file, instead of writing it to the pipeline. .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP BIOS with HP Sure Admin support is required for applying the payloads generated by this function. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) .EXAMPLE $payload = New-HPSureAdminSettingDefaultsPayload -SigningKeyFile "$path\signing_key.pfx" $payload | Set-HPSecurePlatformPayload .EXAMPLE New-HPSureAdminSettingDefaultsPayload -SigningKeyFile "$path\signing_key.pfx" -SigningKeyPassword "s3cr3t" -OutputFile PayloadFile.dat Set-HPSecurePlatformPayload -PayloadFile PayloadFile.dat #> function New-HPSureAdminSettingDefaultsPayload { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/new%e2%80%90hpsureadminsettingdefaultspayload")] param( [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 0)] [System.IO.FileInfo]$SigningKeyFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 1)] [string]$SigningKeyPassword, [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 0)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 2)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 1)] [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s").Replace(',','.')), [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 3)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 2)] [guid]$TargetUUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff', [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 4)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 3)] [System.IO.FileInfo]$OutputFile ) $signingKey = (Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -Password $SigningKeyPassword -cert $SigningKeycertificate -Verbose:$VerbosePreference).Full $params = @{ Nonce = $Nonce TargetUUID = $TargetUUID SigningKey = $signingKey } [SureAdminSetting]$setting = New-HPPrivateSureAdminResetSetting @params -Verbose:$VerbosePreference $data = $setting | ConvertTo-Json New-HPPrivatePortablePayload -Data $data -Purpose "hp:sureadmin:resetsettings" -OutputFile $OutputFile } <# .SYNOPSIS Generate a payload for enabling the HP Sure Admin feature .DESCRIPTION This function uses the provided key to sign and authorize the operation of enabling HP Sure Admin. On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter. This payload can then be passed to the [Set-HPSecurePlatformPayload](https://developers.hp.com/cmsl-staging/doc/set%E2%80%90hpsecureplatformpayload) function. Security note: Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the Set-HPSecurePlatformPayload. Creating the payload and passing it to the Set-HPSecurePlatformPayload function via the pipeline is not a recommended production pattern. .PARAMETER SigningKeyFile The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended), the SigningKeyPassword parameter should also be provided. .PARAMETER SigningKeyPassword The secure platform signing key file password, if required. .PARAMETER SigningKeyCertificate The secure platform signing key certificate, as an X509Certificate object. .PARAMETER Nonce The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a nonce greater or equal to the last nonce sent. If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds, so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller should use its own nonce derivation and provide it through this parameter. .PARAMETER TargetUUID The computer UUID on which to perform this operation. If not specified the payload generated will work on any computer. .PARAMETER SingleUse If specified, the payload cannot be replayed. This happens because the nonce must be higher than ActionsCounter and this counter is updated and incremented every time a command generated with SingleUse flag is accepted by the BIOS. If not specified, the payload can be replayed as many times as desired until a payload generated with a nonce higher than SettingsCounter is received. This happens because SettingsCounter is not incremented by the BIOS when accepting commands. .PARAMETER OutputFile Write the resulting output to the specified file, instead of writing it to the pipeline. .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP BIOS with HP Sure Admin support is required for applying the payloads generated by this function. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) .EXAMPLE $payload = New-HPSureAdminEnablePayload -SigningKeyFile "$path\signing_key.pfx" $payload | Set-HPSecurePlatformPayload .EXAMPLE New-HPSureAdminEnablePayload -SigningKeyFile "$path\signing_key.pfx" -SigningKeyPassword "s3cr3t" -OutputFile PayloadFile.dat Set-HPSecurePlatformPayload -PayloadFile PayloadFile.dat #> function New-HPSureAdminEnablePayload { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/new%e2%80%90hpsureadminenablepayload")] param( [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 1)] [System.IO.FileInfo]$SigningKeyFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 2)] [string]$SigningKeyPassword, [Parameter(ValueFromPipeline = $true,ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 1)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 3)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 2)] [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s").Replace(',','.')), [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 4)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 3)] [guid]$TargetUUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff', [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 5)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 4)] [switch]$SingleUse, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 6)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 5)] [System.IO.FileInfo]$OutputFile ) $params = @{ Name = "Enhanced BIOS Authentication Mode" Value = "Enable" SingleUse = $SingleUse Nonce = $Nonce TargetUUID = $TargetUUID OutputFile = $OutputFile } if ($PSCmdlet.ParameterSetName -eq "SigningKeyFile") { $params.SigningKeyFile = $SigningKeyFile $params.SigningKeyPassword = $SigningKeyPassword } else { $params.SigningKeyCertificate = $SigningKeyCertificate } New-HPSureAdminBIOSSettingValuePayload @params -Verbose:$VerbosePreference } <# .SYNOPSIS Generate a payload for disabling the HP Sure Admin feature .DESCRIPTION This function uses the provided key to sign and authorize the operation of disabling HP Sure Admin. On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter. This payload can then be passed to the [Set-HPSecurePlatformPayload](https://developers.hp.com/cmsl-staging/doc/set%E2%80%90hpsecureplatformpayload) function. Security note: Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the Set-HPSecurePlatformPayload. Creating the payload and passing it to the Set-HPSecurePlatformPayload function via the pipeline is not a recommended production pattern. .PARAMETER SigningKeyFile The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended), the SigningKeyPassword parameter should also be provided. .PARAMETER SigningKeyPassword The secure platform signing key file password, if required. .PARAMETER SigningKeyCertificate The secure platform signing key certificate, as an X509Certificate object. .PARAMETER Nonce The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a nonce greater or equal to the last nonce sent. If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds, so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller should use its own nonce derivation and provide it through this parameter. .PARAMETER TargetUUID The computer UUID on which to perform this operation. If not specified the payload generated will work on any computer. .PARAMETER SingleUse If specified, the payload cannot be replayed. This happens because the nonce must be higher than ActionsCounter and this counter is updated and incremented every time a command generated with SingleUse flag is accepted by the BIOS. If not specified, the payload can be replayed as many times as desired until a payload generated with a nonce higher than SettingsCounter is received. This happens because SettingsCounter is not incremented by the BIOS when accepting commands. .PARAMETER OutputFile Write the resulting output to the specified file, instead of writing it to the pipeline. .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP BIOS with HP Sure Admin support is required for applying the payloads generated by this function. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) .EXAMPLE $payload = New-HPSureAdminDisablePayload -SigningKeyFile "$path\signing_key.pfx" $payload | Set-HPSecurePlatformPayload .EXAMPLE New-HPSureAdminDisablePayload -SigningKeyFile "$path\signing_key.pfx" -SigningKeyPassword "s3cr3t" -OutputFile PayloadFile.dat Set-HPSecurePlatformPayload -PayloadFile PayloadFile.dat #> function New-HPSureAdminDisablePayload { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/new%e2%80%90hpsureadmindisablepayload")] param( [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 1)] [System.IO.FileInfo]$SigningKeyFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 2)] [string]$SigningKeyPassword, [Parameter(ValueFromPipeline = $true,ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 1)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 3)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 2)] [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s").Replace(',','.')), [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 4)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 3)] [guid]$TargetUUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff', [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 5)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 4)] [switch]$SingleUse, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 6)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 5)] [System.IO.FileInfo]$OutputFile ) $params = @{ Name = "Enhanced BIOS Authentication Mode" Value = "Disable" SingleUse = $SingleUse Nonce = $Nonce TargetUUID = $TargetUUID OutputFile = $OutputFile } if ($PSCmdlet.ParameterSetName -eq "SigningKeyFile") { $params.SigningKeyFile = $SigningKeyFile $params.SigningKeyPassword = $SigningKeyPassword } else { $params.SigningKeyCertificate = $SigningKeyCertificate } New-HPSureAdminBIOSSettingValuePayload @params -Verbose:$VerbosePreference } <# .SYNOPSIS Generate a payload for provisioning a local access key .DESCRIPTION This function uses the provided key to sign and authorize updating HP Sure Admin local access keys. Setting a local access key allows system administrators to authorize commands locally with the HP Sure Admin phone app. Check the function [Convert-HPSureAdminCertToQRCode](https://developers.hp.com/cmsl-staging/doc/convert%E2%80%90hpsureadmincerttoqrcode) to know how to transferring a local access key to the HP Sure Admin phone app. On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter. This payload can then be passed to the [Set-HPSecurePlatformPayload](https://developers.hp.com/cmsl-staging/doc/set%E2%80%90hpsecureplatformpayload) function. Security note: Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the Set-HPSecurePlatformPayload. Creating the payload and passing it to the Set-HPSecurePlatformPayload function via the pipeline is not a recommended production pattern. .PARAMETER SigningKeyFile The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended), the SigningKeyPassword parameter should also be provided. .PARAMETER SigningKeyPassword The secure platform signing key file password, if required. .PARAMETER LocalAccessKeyFile The path to the local access key, as a PFX file. If the PFX file is protected by a password (recommended), the LocalAccessKeyPassword parameter should also be provided. .PARAMETER LocalAccessKeyPassword The local access key file password, if required. .PARAMETER SigningKeyCertificate The secure platform signing key certificate, as an X509Certificate object. .PARAMETER Nonce The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a nonce greater or equal to the last nonce sent. If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds, so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller should use its own nonce derivation and provide it through this parameter. .PARAMETER TargetUUID The computer UUID on which to perform this operation. If not specified the payload generated will work on any computer. .PARAMETER SingleUse If specified, the payload cannot be replayed. This happens because the nonce must be higher than ActionsCounter and this counter is updated and incremented every time a command generated with SingleUse flag is accepted by the BIOS. If not specified, the payload can be replayed as many times as desired until a payload generated with a nonce higher than SettingsCounter is received. This happens because SettingsCounter is not incremented by the BIOS when accepting commands. .PARAMETER OutputFile Write the resulting output to the specified file, instead of writing it to the pipeline. .PARAMETER Id Int Id from 1,2 or 3 that gets appended to the setting name. .PARAMETER KeyEnrollmentData KeyEnrollmentData to use to get Sure Admin Local Access key from certificate .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP BIOS with HP Sure Admin support is required for applying the payloads generated by this function. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) .EXAMPLE $payload = New-HPSureAdminLocalAccessKeyProvisioningPayload -SigningKeyFile "$path\signing_key.pfx" -LocalAccessKeyFile "$path\local_access_key.pfx" $payload | Set-HPSecurePlatformPayload .EXAMPLE New-HPSureAdminLocalAccessKeyProvisioningPayload -SigningKeyFile "$path\signing_key.pfx" -SigningKeyPassword "s3cr3t" -LocalAccessKeyFile "$path\local_access_key.pfx" -LocalAccessKeyPassword "lak_s3cr3t" -OutputFile PayloadFile.dat Set-HPSecurePlatformPayload -PayloadFile PayloadFile.dat #> function New-HPSureAdminLocalAccessKeyProvisioningPayload { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/new%e2%80%90hpsureadminlocalaccesskeyprovisioningpayload")] param( [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 1)] [System.IO.FileInfo]$SigningKeyFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 2)] [string]$SigningKeyPassword, [Parameter(ValueFromPipeline = $true,ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 1)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 3)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 2)] [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s").Replace(',','.')), [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 4)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 3)] [guid]$TargetUUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff', [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 5)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 4)] [switch]$SingleUse, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 6)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 6)] [System.IO.FileInfo]$LocalAccessKeyFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 7)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 7)] [string]$LocalAccessKeyPassword, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 8)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 8)] [ValidateSet(1, 2, 3)] [int]$Id = 1, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 9)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 9)] [string]$KeyEnrollmentData, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 6)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 5)] [System.IO.FileInfo]$OutputFile ) $localAccessKey = (Get-HPPrivateX509CertCoalesce -File $LocalAccessKeyFile -Password $LocalAccessKeyPassword -cert $null -Verbose:$VerbosePreference).Full [string]$pubKeyBase64 = Get-HPPrivateSureAdminLocalAccessKeyFromCert -LocalAccessKey $localAccessKey -KeyEnrollmentData $KeyEnrollmentData $params = @{ Name = "Enhanced BIOS Authentication Mode Local Access Key " + $Id Value = $pubKeyBase64 SingleUse = $SingleUse Nonce = $Nonce TargetUUID = $TargetUUID OutputFile = $OutputFile } if ($PSCmdlet.ParameterSetName -eq "SigningKeyFile") { $params.SigningKeyFile = $SigningKeyFile $params.SigningKeyPassword = $SigningKeyPassword } else { $params.SigningKeyCertificate = $SigningKeyCertificate } New-HPSureAdminBIOSSettingValuePayload @params -Verbose:$VerbosePreference } <# .SYNOPSIS Generate a payload for authorizing a single BIOS setting change .DESCRIPTION This function uses the provided key to sign and authorize a single BIOS setting change. On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter. This payload can then be passed to the [Set-HPSecurePlatformPayload](https://developers.hp.com/cmsl-staging/doc/set%E2%80%90hpsecureplatformpayload) function. Security note: Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the Set-HPSecurePlatformPayload. Creating the payload and passing it to the Set-HPSecurePlatformPayload function via the pipeline is not a recommended production pattern. .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 SigningKeyFile The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended), the SigningKeyPassword parameter should also be provided. .PARAMETER SigningKeyPassword The secure platform signing key file password, if required. .PARAMETER SigningKeyCertificate The secure platform signing key certificate, as an X509Certificate object. .PARAMETER Nonce The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a nonce greater or equal to the last nonce sent. If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds, so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller should use its own nonce derivation and provide it through this parameter. .PARAMETER TargetUUID The computer UUID on which to perform this operation. If not specified the payload generated will work on any computer. .PARAMETER SingleUse If specified, the payload cannot be replayed. This happens because the nonce must be higher than ActionsCounter and this counter is updated and incremented every time a command generated with SingleUse flag is accepted by the BIOS. If not specified, the payload can be replayed as many times as desired until a payload generated with a nonce higher than SettingsCounter is received. This happens because SettingsCounter is not incremented by the BIOS when accepting commands. .PARAMETER OutputFile Write the resulting output to the specified file, instead of writing it to the pipeline. .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP BIOS with HP Sure Admin support is required for applying the payloads generated by this function. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) .EXAMPLE $payload = New-HPSureAdminBIOSSettingValuePayload -Name "Setting Name" -Value "New Setting Value" -SigningKeyFile "$path\signing_key.pfx" $payload | Set-HPSecurePlatformPayload .EXAMPLE New-HPSureAdminBIOSSettingValuePayload -Name "Setting Name" -Value "New Setting Value" -SigningKeyFile "$path\signing_key.pfx" -SigningKeyPassword "s3cr3t" -OutputFile PayloadFile.dat Set-HPSecurePlatformPayload -PayloadFile PayloadFile.dat #> function New-HPSureAdminBIOSSettingValuePayload { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/new%e2%80%90hpsureadminbiossettingvaluepayload")] param( [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 0)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 0)] [string]$Name, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 1)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 1)] [AllowEmptyString()] [string]$Value, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $true,Position = 2)] [System.IO.FileInfo]$SigningKeyFile, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 3)] [string]$SigningKeyPassword, [Parameter(ValueFromPipeline = $true,ParameterSetName = "SigningKeyCert",Mandatory = $true,Position = 2)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 4)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 3)] [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s").Replace(',','.')), [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 5)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 4)] [guid]$TargetUUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff', [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 6)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 5)] [switch]$SingleUse, [Parameter(ParameterSetName = "SigningKeyFile",Mandatory = $false,Position = 7)] [Parameter(ParameterSetName = "SigningKeyCert",Mandatory = $false,Position = 6)] [System.IO.FileInfo]$OutputFile ) $signingKey = (Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -Password $SigningKeyPassword -cert $SigningKeycertificate -Verbose:$VerbosePreference).Full $params = @{ Name = $Name Value = $Value SingleUse = $SingleUse Nonce = $Nonce TargetUUID = $TargetUUID SigningKey = $signingKey } [SureAdminSetting]$setting = New-HPPrivateSureAdminBIOSSettingObject @params -Verbose:$VerbosePreference $data = $setting | ConvertTo-Json New-HPPrivatePortablePayload -Data $data -Purpose "hp:sureadmin:biossetting" -OutputFile $OutputFile -Verbose:$VerbosePreference } function Invoke-HPPrivateConstructHeader { param( [uint32]$NameLen, [uint32]$ValueLen, [switch]$SingleUse, [uint32]$Nonce, [guid]$TargetUUID ) $data = New-Object -TypeName SureAdminSignatureBlockHeader $data.Version = 1 $data.NameLength = $NameLen $data.ValueLength = $ValueLen $data.OneTimeUse = [byte]($SingleUse.IsPresent) $data.Nonce = $Nonce $data.Reserved = 1 $data.Target = [byte[]]((([string]$TargetUUID).Replace('-','')) -replace '..','0x$&,' -split ',' -ne '') [byte[]]$header = (Convert-HPPrivateObjectToBytes -obj $data -Verbose:$VerbosePreference)[0] return $header } function Invoke-HPPrivateConstructPayload { param( [byte[]]$Header, [string]$Name, [string]$Value ) $nameLen = [System.Text.Encoding]::Unicode.GetByteCount($Name) $valueLen = [System.Text.Encoding]::Unicode.GetByteCount($Value) [byte[]]$payload = New-Object byte[] ($Header.Count + $nameLen + $valueLen) $namebytes = [System.Text.Encoding]::Unicode.GetBytes($Name) [System.Array]::Copy($Header,0,$payload,0,$Header.Length) [System.Array]::Copy($namebytes,0,$payload,$Header.Length,$namebytes.Length) if ($valueLen -ne 0) { Write-Verbose "Copying value to payload" $valuebytes = [System.Text.Encoding]::Unicode.GetBytes($Value) [System.Array]::Copy($valuebytes,0,$payload,$Header.Length + $namebytes.Length,$valuebytes.Length) } else { Write-Verbose "No value was specified for this setting" } return $payload } function Invoke-HPPrivateConstructAuthorization { param( [byte[]]$Header, [byte[]]$Signature ) [byte[]]$authorization = New-Object byte[] ($Header.Length + $Signature.Length) [System.Array]::Copy($Header,0,$authorization,0,$Header.Length) [System.Array]::Copy($Signature,0,$authorization,$Header.Length,$Signature.Length) [string]$encodedAuth = "<BEAM/>"+[Convert]::ToBase64String($authorization) return $encodedAuth } function Get-HPPrivatePublicKeyModulus($cert) { $key = $cert.PublicKey.Key $parameters = $key.ExportParameters($false); return $parameters.Modulus } function Get-HPPrivateKeyNameFromCert($cert) { return $cert.Subject -replace "(CN=)(.*?),.*",'$2' } function Get-HPPrivatePrimesFromCert($Certificate) { $rsaPrivate = [xml]$Certificate.PrivateKey.ToXmlString($true) $p = [System.Convert]::FromBase64String($rsaPrivate.RSAKeyValue.P) $q = [System.Convert]::FromBase64String($rsaPrivate.RSAKeyValue.Q) $primes = [System.Byte[]]::new(256) for ($i = 0; $i -lt 128; $i++) { $primes[$i] = $p[$i] } for ($i = 0; $i -lt 128; $i++) { $primes[128 + $i] = $q[$i] } return $primes } function Get-HPPrivateRandomByteArray($Length) { $RandomBytes = New-Object Byte[]($Length) $RNG = [Security.Cryptography.RNGCryptoServiceProvider]::Create() $RNG.GetBytes($RandomBytes) return $RandomBytes } function Get-HPPrivateRandomIV() { return Get-HPPrivateRandomByteArray 16 } function Get-HPPrivateRandomSalt() { return Get-HPPrivateRandomByteArray 8 } function Get-HPPrivatePbkdf2Bytes($Passphrase, $Salt, $Iterations, $Length, $Metadata = $null) { $Passphrase += $Metadata $PBKDF2 = New-Object System.Security.Cryptography.Rfc2898DeriveBytes($Passphrase, $Salt, $Iterations) return $PBKDF2.GetBytes($Length) } function Get-HPPrivateDataEncryption([byte[]]$AESKey, [byte[]]$Data, [byte[]]$IV) { $aesManaged = New-Object System.Security.Cryptography.AesManaged $aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC $aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7 $aesManaged.KeySize = 256 $aesManaged.IV = $IV $aesManaged.Key = $AESKey $encryptor = $aesManaged.CreateEncryptor() [byte[]]$encryptedData = $encryptor.TransformFinalBlock($Data, 0, $Data.Length); $aesManaged.Dispose() return $encryptedData } function Get-HPPrivateKeyFromCert { param ( [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, [string]$Metadata, [string]$Passphrase ) $iv = Get-HPPrivateRandomIV $salt = Get-HPPrivateRandomSalt $iterations = 100000 $keysize = 32 $aesKey = Get-HPPrivatePbkdf2Bytes $Passphrase $salt $iterations $keysize $Metadata $primes = Get-HPPrivatePrimesFromCert $Certificate $cipher = Get-HPPrivateDataEncryption $aesKey $primes $iv $encryptedPrimes = $salt + $iv + $cipher return [System.Convert]::ToBase64String($encryptedPrimes) } function Get-HPPrivateSureAdminLocalAccessKeyFromCert { param ( [System.Security.Cryptography.X509Certificates.X509Certificate2]$LocalAccessKey, [string]$KeyEnrollmentData ) $modulus = Get-HPPrivatePublicKeyModulus $LocalAccessKey $pubKeyBase64 = [System.Convert]::ToBase64String($modulus) if ($KeyEnrollmentData) { $KeyEnrollmentDataBytes = [System.Text.Encoding]::UTF8.GetBytes($KeyEnrollmentData) $pubKeyBase64 += [System.Convert]::ToBase64String($KeyEnrollmentDataBytes) } return $pubKeyBase64 } function New-HPPrivateSureAdminEnrollmentJson { param ( [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, [string]$Model, [string]$SerialNumber, [string]$Passphrase, [string]$AADRevocation ) # Get the pub key $modulus = Get-HPPrivatePublicKeyModulus $Certificate $hashMod = Get-HPPrivateHash -Data $modulus $hashModBase64 = [System.Convert]::ToBase64String($hashMod) # Get the private key $keyName = Get-HPPrivateKeyNameFromCert $Certificate if ("" -eq $Passphrase) { $keyAlgo = "006" $ver = "002" } else { $keyAlgo = "007" $ver = "002" } $data = [ordered]@{ Ver = $ver Type = "001" KeyId = $hashModBase64 KeyAlgo = $keyAlgo PvtKey = $null KeyExp = "00000000" KeyName = $keyName KeyBkupEn = "0" Model = $Model SerNum = $SerialNumber CanModKeyBkup = "0" CanExport = "0" AADRevocation = $AADRevocation } $json = $data | ConvertTo-Json -Compress $pvtKeyBase64 = Get-HPPrivateKeyFromCert -Certificate $Certificate -Metadata $json -Passphrase $Passphrase $data.PvtKey = $pvtKeyBase64 $json = $data | ConvertTo-Json -Compress return $json } <# .SYNOPSIS Generate a QR-Code for transferring the private key from a certificate file to the HP Sure Admin phone app .DESCRIPTION This function extracts a private key from the provided certificate file and presents it in a form of QR-Code, which can be scanned with the HP Sure Admin phone app. Once scanned the app can be used for authorizing commands and BIOS setting changes. Security note: It is recommended to delete the QR-Code file once it is scanned with the app. Keeping the QR-Code stored locally in your computer is not a recommended production pattern since it contains sensitive information that can be used to authorize commands. .PARAMETER LocalAccessKeyFile The path to the local access key, as a PFX file. If the PFX file is protected by a password (recommended), the LocalAccessKeyPassword parameter should also be provided. .PARAMETER LocalAccessKeyPassword The local access key file password, if required. .PARAMETER Model The computer model to be stored with the key in the phone app. .PARAMETER SerialNumber The serial number to be stored with the key in the phone app. .PARAMETER OutputFile Write the image to a specific file. .PARAMETER Format The format of your preference to save the QR-Code image file: Jpeg, Bmp, Png, Svg. .PARAMETER ViewAs The 'Default' option creates a local file in your system and starts the default image viewer for presenting the QR-Code image. If 'Text' is provided, the QR-Code is displayed by using text characters in your console. If 'Image' is provided, the QR-Code image is displayed in the console temporary and once enter is pressed it disappears. If 'None' is provided, the QR-Code is not presented to the user. You may want to specify an OutputFile when using this option. .PARAMETER Passphrase The password to protect QR-Code content. .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP BIOS with HP Sure Admin support is required for applying the payloads generated by this function. .LINK [Blog post: HP Secure Platform Management with the HP Client Management Script Library](https://developers.hp.com/hp-client-management/blog/hp-secure-platform-management-hp-client-management-script-library) .EXAMPLE Convert-HPSureAdminCertToQRCode -LocalAccessKeyFile "$path\signing_key.pfx" .EXAMPLE Convert-HPSureAdminCertToQRCode -Model "PC-Model" -SerialNumber "SN-1234" -LocalAccessKeyFile "$path\signing_key.pfx" -LocalAccessKeyPassword "s3cr3t" .EXAMPLE Convert-HPSureAdminCertToQRCode -Model "PC-Model" -SerialNumber "SN-1234" -LocalAccessKeyFile "$path\signing_key.pfx" -Passphrase "s3cr3t" -ViewAs Image .EXAMPLE Convert-HPSureAdminCertToQRCode -LocalAccessKeyFile "$path\signing_key.pfx" -Passphrase "s3cr3t" -Format "Svg" #> function Convert-HPSureAdminCertToQRCode { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/convert%e2%80%90hpsureadmincerttoqrcode")] param ( [Parameter(Mandatory = $true,Position = 0)] [System.IO.FileInfo]$LocalAccessKeyFile, [Parameter(Mandatory = $false,Position = 1)] [string]$LocalAccessKeyPassword, [Parameter(Mandatory = $false,Position = 2)] [string]$Model, [Parameter(Mandatory = $false,Position = 3)] [string]$SerialNumber, [Parameter(Mandatory = $false,Position = 4)] [System.IO.FileInfo]$OutputFile, [Parameter(Mandatory = $false,Position = 5)] [ValidateSet('Jpeg', 'Bmp', 'Png', 'Svg')] [string]$Format = "Jpeg", [Parameter(Mandatory = $false,Position = 6)] [ValidateSet('None', 'Text', 'Image', 'Default')] [string]$ViewAs = "Default", [Parameter(Mandatory = $false,Position = 7)] [String]$Passphrase ) if (-not $Model) { $Model = Get-HPBIOSSettingValue -Name "Product Name" } if (-not $SerialNumber) { $SerialNumber = Get-HPBIOSSettingValue -Name "Serial Number" } if ($LocalAccessKeyPassword) { [securestring]$LocalAccessKeyPassword = ConvertTo-SecureString -AsPlainText -Force $LocalAccessKeyPassword $cert = (Get-HPPrivatePublicKeyCertificateFromPFX -FileName $LocalAccessKeyFile -Password $LocalAccessKeyPassword).Full } else { $cert = (Get-HPPrivatePublicKeyCertificateFromPFX -FileName $LocalAccessKeyFile).Full } $data = New-HPPrivateSureAdminEnrollmentJson -Certificate $cert -Model $Model -SerialNumber $SerialNumber -Passphrase $Passphrase New-HPPrivateQRCode -Data $data -OutputFile $OutputFile -Format $Format -ViewAs $ViewAs } <# .SYNOPSIS Send a local access key in PFX format to HP Sure Admin Key Management Service (KMS) .DESCRIPTION This function extracts a private key from the provided certificate file, generates a json for the central-managed enrollment process and sends it to the HP Sure Admin Key Management Service (KMS). The connection with KMS server requires to the user to authenticate with a valid Microsoft account. .PARAMETER LocalAccessKeyFile The path to the local access key, as a PFX file. If the PFX file is protected by a password (recommended), the LocalAccessKeyPassword parameter should also be provided. .PARAMETER LocalAccessKeyPassword The local access key file password, if required. .PARAMETER Model The computer model to be stored with the key in the phone app. .PARAMETER SerialNumber The serial number to be stored with the key in the phone app. .PARAMETER KMSAppName The application name on Azure KMS server that will be used to compose the URI for uploading the key .PARAMETER KMSUri The complete URI for uploading the key (I.e.: https://<KMSAppName>.azurewebsites.net/api/UploadKey) .PARAMETER AADGroup The group name in Azure Active Directory that will have access to the key .PARAMETER CacheAccessToken This parameter should be specified when uploading multiple keys if the user don't want to re-enter credentials on each call of this function. If specified, the access token is cached in msalcache.dat file and won't be asked until it expires. .NOTES - Supported on Windows 10. - Supported on Windows Power Shell v5. - An HP Sure Admin KMS server is required for using this feature. .EXAMPLE Send-HPSureAdminLocalAccessKeyToKMS -LocalAccessKeyFile "$path\signing_key.pfx" -KMSUri "https://MyKMSURI.azurewebsites.net/api/UploadKey" -AADGroup "MyAADGroupName" .EXAMPLE Send-HPSureAdminLocalAccessKeyToKMS -LocalAccessKeyFile "$path\signing_key.pfx" -LocalAccessKeyPassword "pass" -KMSAppName "MyAppName" -AADGroup "MyAADGroupName" #> function Send-HPSureAdminLocalAccessKeyToKMS { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/send%e2%80%90hpsureadminlocalaccesskeytokms")] param ( [Parameter(ParameterSetName = "KMSUri",Mandatory = $true,Position = 0)] [Parameter(ParameterSetName = "KMSAppName",Mandatory = $true,Position = 0)] [System.IO.FileInfo]$LocalAccessKeyFile, [Parameter(ParameterSetName = "KMSUri",Mandatory = $false,Position = 1)] [Parameter(ParameterSetName = "KMSAppName",Mandatory = $false,Position = 1)] [string]$LocalAccessKeyPassword, [Parameter(ParameterSetName = "KMSUri",Mandatory = $false,Position = 2)] [Parameter(ParameterSetName = "KMSAppName",Mandatory = $false,Position = 2)] [string]$Model = "", [Parameter(ParameterSetName = "KMSUri",Mandatory = $false,Position = 3)] [Parameter(ParameterSetName = "KMSAppName",Mandatory = $false,Position = 3)] [string]$SerialNumber = "", [Parameter(ParameterSetName = "KMSUri",Mandatory = $true,Position = 4)] [string]$KMSUri = "", [Parameter(ParameterSetName = "KMSAppName",Mandatory = $true,Position = 4)] [string]$KMSAppName, [Parameter(ParameterSetName = "KMSUri",Mandatory = $true,Position = 5)] [Parameter(ParameterSetName = "KMSAppName",Mandatory = $true,Position = 5)] [string]$AADGroup, [Parameter(ParameterSetName = "KMSUri",Mandatory = $false,Position = 6)] [Parameter(ParameterSetName = "KMSAppName",Mandatory = $false,Position = 6)] [switch]$CacheAccessToken ) if ($LocalAccessKeyPassword) { [securestring]$LocalAccessKeyPassword = ConvertTo-SecureString -AsPlainText -Force $LocalAccessKeyPassword $cert = (Get-HPPrivatePublicKeyCertificateFromPFX -FileName $LocalAccessKeyFile -Password $LocalAccessKeyPassword).Full } else { $cert = (Get-HPPrivatePublicKeyCertificateFromPFX -FileName $LocalAccessKeyFile).Full } $jsonPayload = New-HPPrivateSureAdminEnrollmentJson -Certificate $cert -Model $Model -SerialNumber $SerialNumber -AADRevocation $AADGroup if ($PSCmdlet.ParameterSetName -eq "KMSAppName") { $KMSUri = "https://$KMSAppName.azurewebsites.net/api/UploadKey" } $cached = $false $accessToken = $null if ($CacheAccessToken.IsPresent) { $accessToken = Get-HPPrivateSureAdminCachedKMSAccessToken if ($null -ne $accessToken) { $cached = $true } } else { Clear-HPSureAdminKMSAccessToken } if ($null -eq $accessToken) { $accessToken = Get-HPPrivateSureAdminKMSAccessToken } $response = Send-HPPrivateKeyToSureAdminKMS -KMSUri $KMSUri -JsonPayload $jsonPayload -AccessToken $accessToken if ($cached -eq $true -and $response -eq "unauthorized") { Clear-HPSureAdminKMSAccessToken Send-HPSureAdminLocalAccessKeyToKMS @PSBoundParameters } elseif ($response -eq "OK") { if ($CacheAccessToken.IsPresent -eq $true -and $cached -eq $false) { Set-HPPrivateSureAdminKMSAccessToken -AccessToken $accessToken } } else { Clear-HPSureAdminKMSAccessToken throw "HTTP Request Error: " + $response } } function Set-HPPrivateSureAdminKMSAccessToken { param( [string]$AccessToken ) $path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("msalcache.dat") $AccessToken | Out-File -FilePath $path -Encoding utf8 Write-Verbose "Access token saved to cache" } <# .SYNOPSIS Clear the KMS access token .DESCRIPTION This function clears the access token that is used for sending keys to HP Sure Admin Key Management Service (KMS). The token is stored locally in msalcache.dat file when -CacheAccessToken parameter is specified in function Send-HPSureAdminLocalAccessKeyToKMS .EXAMPLE Clear-HPSureAdminKMSAccessToken #> function Clear-HPSureAdminKMSAccessToken { [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/clear%e2%80%90hpsureadminkmsaccesstoken")] param ( ) $path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("msalcache.dat") Remove-Item -path $path -ErrorAction Ignore } function Get-HPPrivateSureAdminCachedKMSAccessToken { $path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("msalcache.dat") $accessToken = $null if ([System.IO.File]::Exists($path)) { Write-Verbose "Access token loaded from cache" $accessToken = Get-Content -Encoding UTF8 -Path $path -ErrorAction Ignore } return $accessToken } function Get-HPPrivateSureAdminKMSAccessToken { [string]$clientId = "40ef700f-b021-4fe4-81fe-b2536e9701c3" [string]$redirectUri = "http://localhost" #[string]$redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient" [string[]]$scopes = ("https://graph.microsoft.com/Directory.Read.All") $clientApplicationBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($clientId) [void]$clientApplicationBuilder.WithRedirectUri($redirectUri) [void]$clientApplicationBuilder.WithClientId($clientId) $clientApplication = $clientApplicationBuilder.Build() $aquireToken = $clientApplication.AcquireTokenInteractive($scopes) $parentWindow = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle [void]$aquireToken.WithParentActivityOrWindow($parentWindow) try { $authenticationResult = $aquireToken.ExecuteAsync().GetAwaiter().GetResult() } catch { Write-Verbose $_.Exception throw "Could not retrieve a valid access token: " + $_.Exception.InnerException.Message } return $authenticationResult.AccessToken } function Send-HPPrivateKeyToSureAdminKMS { param( [string]$KMSUri, [string]$JsonPayload, [string]$AccessToken ) $request = [System.Net.HttpWebRequest]::Create($KMSUri) $request.Method = "POST" $request.Headers.Add("Authorization", "Bearer $AccessToken") $content = [System.Text.Encoding]::UTF8.GetBytes($JsonPayload) $request.ContentType = "application/json" $request.ContentLength = $content.Length $stream = $request.GetRequestStream() $stream.Write($content, 0, $content.Length) try { $response = $request.GetResponse().StatusDescription } catch [System.Net.WebException] { Write-Verbose $_.Exception $response = $_.Exception.Response.StatusDescription } return $response } function New-HPPrivateQRCode { param( [string]$Data, [System.IO.FileInfo]$OutputFile, [ValidateSet('Jpeg', 'Bmp', 'Png', 'Svg')] [string]$Format = "Jpeg", [ValidateSet('None', 'Text', 'Image', 'Default')] [string]$ViewAs = "Default" ) [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $QRCode = [System.Byte[]]::CreateInstance([System.Byte], 3918) switch (Test-OSBitness) { 32 { $result = [DfmNativeQRCode]::create_qrcode32($data, $QRCode) } 64 { $result = [DfmNativeQRCode]::create_qrcode64($data, $QRCode) } } $width = $height = $QRCode[0] $RGBBuffer = Convert-HPPrivateQRCodeToRGBBuffer -QRCode $QRCode [System.Drawing.Image]$img = New-HPPrivateImageFromRGBBuffer -RGBBuffer $RGBBuffer -Width $width -Height $height [System.Drawing.Image]$newImg = New-HPPrivateImageScale -Image $img -Width 250 -Height 250 -Border 10 $img.Dispose() $path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputFile) if ($ViewAs -eq "Default" -and $OutputFile -eq $null) { $path = $env:TEMP + "\" + [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s")) + "." + $Format } if ($OutputFile -or $ViewAs -eq "Default") { if ($Format -eq "Svg") { Invoke-HPPrivateWriteQRCodeToSvgFile -QRCode $QRCode -Path $path } else { $newImg.Save($path, [System.Drawing.Imaging.ImageFormat]::$Format) } } if ($ViewAs) { if ($ViewAs -eq "Text") { Invoke-HPPrivateWriteSmallQRCodeToConsole -QRCode $QRCode } elseif ($ViewAs -eq "Image") { Invoke-HPPrivateDisplayQRCodeForm -Image $newImg -Width $newImg.Width -Height $newImg.Height } elseif ($ViewAs -eq "Default") { Start-Process $path } } $newImg.Dispose() } function Get-HPPrivateQRCodeModule { param( [byte[]]$QRCode, [int]$X, [int]$Y ) $size = $QRCode[0] if (0 -le $X -and $X -lt $size -and 0 -le $Y -and $Y -lt $size) { $index = $Y * $size + $X; $k = $QRCode[(($index -shr 3) + 1)] $i = $index -band 7 if ((($k -shr $i) -band 1) -ne 0) { return $true } } return $false } function Convert-HPPrivateQRCodeToRGBBuffer { param( [byte[]]$QRCode ) $len = $QRCode[0] $channels = 3 $size = $len * $len * $channels #RGB color channels [byte[]] $RGBBuffer = [byte[]]::CreateInstance([byte], $size) for ($y = 0; $y -lt $len; $y++) { for ($x = 0; $x -lt $len; $x++) { $index = (($x * $len) + $y) * $channels if ((Get-HPPrivateQRCodeModule -QRCode $QRCode -X $x -Y $y) -eq $false) { $RGBBuffer[$index + 0] = 0xFF $RGBBuffer[$index + 1] = 0xFF $RGBBuffer[$index + 2] = 0xFF } } } return $RGBBuffer } function Invoke-HPPrivateWriteSmallQRCodeToConsole { param( [byte[]]$QRCode ) $white = ([char]0x2588) $black = ' ' $whiteBlack = ([char]0x2580) $blackWhite = ([char]0x2584) $size = $QRCode[0] Write-Host "`n" Write-Host -NoNewline " " for ($x = 0; $x -lt $size+2; $x++) { Write-Host -NoNewline $blackWhite } Write-Host "" for ($y = 0; $y -lt $size; $y += 2) { Write-Host -NoNewline " " for ($x = -1; $x -lt $size+1; $x++) { if (-not (Get-HPPrivateQRCodeModule -QRCode $QRCode -X $x -Y $y) -and -not (Get-HPPrivateQRCodeModule -QRCode $QRCode -X $x -Y ($y + 1)) ) { Write-Host -NoNewline $white } elseif (-not (Get-HPPrivateQRCodeModule -QRCode $QRCode -X $x -Y $y) -and (Get-HPPrivateQRCodeModule -QRCode $QRCode -X $x -Y ($y + 1)) ) { Write-Host -NoNewline $whiteBlack } elseif ( (Get-HPPrivateQRCodeModule -QRCode $QRCode -X $x -Y $y) -and -not (Get-HPPrivateQRCodeModule -QRCode $QRCode -X $x -Y ($y + 1)) ) { Write-Host -NoNewline $blackWhite } else { Write-Host -NoNewline $black } } Write-Host "" } Write-Host "`n" } function Invoke-HPPrivateWriteQRCodeToSvgFile { param( [byte[]]$QRCode, [string]$Path ) $border = 2 $size = $QRCode[0] $content = ('<?xml version="1.0" encoding="UTF-8"?>' + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-'+$border+' -'+$border+' '+($size+$border*2)+' '+($size+$border*2)+'" stroke="none">' + '<rect width="90%" height="90%" fill="#FFFFFF" dominant-baseline="central" />' + '<path d="') for ($y = 0; $y -lt $size; $y++) { for ($x = 0; $x -lt $size; $x++) { if ((Get-HPPrivateQRCodeModule -QRCode $QRCode -X $x -Y $y) -eq $true) { if ($x -ne 0 -or $y -ne 0) { $content += ' ' } $content += 'M'+$x+','+$y+'h1v1h-1z' } } } $content += ('" fill="#000000" />' + '</svg>') $content | Out-File -FilePath $Path -Encoding utf8 } function New-HPPrivateImageScale { param( [System.Drawing.Image]$Image, [int]$Width, [int]$Height, [int]$Border = 10 ) $newImage = New-Object System.Drawing.Bitmap(($Width + $border*2), ($Height + $border*2), [System.Drawing.Imaging.PixelFormat]::Format24bppRgb) $graphics = [System.Drawing.Graphics]::FromImage($newImage) $graphics.Clear([System.Drawing.Color]::White) $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::NearestNeighbor $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::Half $graphics.DrawImage($Image, $border, $border, $Width, $Height) $graphics.Flush() $graphics.Dispose() return $newImage } function New-HPPrivateImageFromRGBBuffer { param( [byte[]]$RGBBuffer, [int]$Width, [int]$Height, [int]$Border = 10 ) $img = New-Object System.Drawing.Bitmap($Width, $Height, [System.Drawing.Imaging.PixelFormat]::Format24bppRgb) $rect = New-Object System.Drawing.Rectangle(0, 0, $img.Width, $img.Height) $bmpData = $img.LockBits($rect, [System.Drawing.Imaging.ImageLockMode]::ReadWrite, $img.PixelFormat) $bufferStride = $img.Width * 3 $targetStride = $bmpData.Stride $imgPtr = $bmpData.Scan0.ToInt64() for ($y = 0; $y -lt $img.Height; $y++) { [System.Runtime.InteropServices.Marshal]::Copy($RGBBuffer, $y * $bufferStride, [IntPtr]($imgPtr + $y * $targetStride), $bufferStride) } $img.UnlockBits($bmpData) return $img } function Get-HPPrivateConsoleFontSize { param() $width = 0 switch (Test-OSBitness) { 32 { $width = [DfmNativeQRCode]::get_console_font_width32() } 64 { $width = [DfmNativeQRCode]::get_console_font_width64() } } $height = 0 switch (Test-OSBitness) { 32 { $height = [DfmNativeQRCode]::get_console_font_height32() } 64 { $height = [DfmNativeQRCode]::get_console_font_height64() } } return $width, $height } function Get-HPPrivateScreenScale { param() $result = 0 switch (Test-OSBitness) { 32 { $result = [DfmNativeQRCode]::get_screen_scale32() } 64 { $result = [DfmNativeQRCode]::get_screen_scale64() } } return $result } function Invoke-HPPrivateDisplayQRCodeForm { param( [System.Drawing.Image]$Image, [int]$Width, [int]$Height ) [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") $screenScale = Get-HPPrivateScreenScale $fontWidth, $fontHeight = (Get-HPPrivateConsoleFontSize) $cursorPosition = $host.UI.RawUI.CursorPosition.Y $windowHandle = [System.Diagnostics.Process]::GetCurrentProcess()[0].MainWindowHandle $imgSpace = $Height / $fontHeight for ($i=0; $i -lt $imgSpace + 3; $i++) { Write-Host "" } Write-Host "Press enter once you have scanned the QR-Code..." #Write-Host "Screen Scale:" $screenScale, "Width:" $Width, "Height:" $Height, "fontHeight:" $fontHeight $newWindowPosition = $host.UI.RawUI.WindowPosition.Y [System.Windows.Forms.Application]::EnableVisualStyles() $form = new-object System.Windows.Forms.Form $form.ControlBox = $false $form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedToolWindow $form.ShowInTaskbar = $false $form.Width = $Width $form.Height = $Height $form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual $form.Add_KeyDown({ if ($_.KeyCode -eq 'Escape' -Or $_.KeyCode -eq 'Enter') { $form.Close() } }) $pictureBox = new-object System.Windows.Forms.PictureBox $pictureBox.Width = $Width $pictureBox.Height = $Height $pictureBox.Image = $Image $pictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom $form.controls.add($pictureBox); $rect = new-object RECT $status = [Win32Window]::GetWindowRect($windowHandle, [ref]$rect) $windowWidth = $host.UI.RawUI.WindowSize.Width * $fontWidth $windowHeight = $host.UI.RawUI.WindowSize.Height * $fontHeight $topMargin = $fontHeight * (4 + ($cursorPosition-$newWindowPosition)) $leftMargin = $fontWidth * $screenScale if (($Width + $leftMargin) -gt $windowWidth) { $form.Width = $windowWidth } $top = [int]($rect.Top + $topMargin) $left = [int]($rect.Left + $leftMargin) $form.Location = New-Object System.Drawing.Point($left, $top) $caller = New-Object Win32Window -ArgumentList $windowHandle [void]$form.ShowDialog($caller) } # SIG # Begin signature block # MIIakQYJKoZIhvcNAQcCoIIagjCCGn4CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB7CcB1flzlfNGb # ZbKikONDrClwe5pnM5KHy164kUKkRaCCCm8wggUwMIIEGKADAgECAhAECRgbX9W7 # ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBa # Fw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lD # ZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3 # DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/l # qJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fT # eyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqH # CN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+ # bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLo # LFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIB # yTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK # BggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9v # Y3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHow # eDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl # ZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwA # AgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAK # BghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0j # BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7s # DVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGS # dQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6 # r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo # +MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qz # sIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHq # aGxEMrJmoecYpJpkUe8wggU3MIIEH6ADAgECAhAFUi3UAAgCGeslOwtVg52XMA0G # CSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0 # IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcNMjEwMzIyMDAwMDAw # WhcNMjIwMzMwMjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv # cm5pYTESMBAGA1UEBxMJUGFsbyBBbHRvMRAwDgYDVQQKEwdIUCBJbmMuMRkwFwYD # VQQLExBIUCBDeWJlcnNlY3VyaXR5MRAwDgYDVQQDEwdIUCBJbmMuMIIBIjANBgkq # hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtJ+rYUkseHcrB2M/GyomCEyKn9tCyfb+ # pByq/Jyf5kd3BGh+/ULRY7eWmR2cjXHa3qBAEHQQ1R7sX85kZ5sl2ukINGZv5jEM # 04ERNfPoO9+pDndLWnaGYxxZP9Y+Icla09VqE/jfunhpLYMgb2CuTJkY2tT2isWM # EMrKtKPKR5v6sfhsW6WOTtZZK+7dQ9aVrDqaIu+wQm/v4hjBYtqgrXT4cNZSPfcj # 8W/d7lFgF/UvUnZaLU5Z/+lYbPf+449tx+raR6GD1WJBAzHcOpV6tDOI5tQcwHTo # jJklvqBkPbL+XuS04IUK/Zqgh32YZvDnDohg0AEGilrKNiMes5wuAQIDAQABo4IB # xDCCAcAwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYE # FD4tECf7wE2l8kA6HTvOgkbo33MvMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK # BggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2Vy # dC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQu # ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwSwYDVR0gBEQwQjA2 # BglghkgBhv1sAwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5j # b20vQ1BTMAgGBmeBDAEEATCBhAYIKwYBBQUHAQEEeDB2MCQGCCsGAQUFBzABhhho # dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTgYIKwYBBQUHMAKGQmh0dHA6Ly9jYWNl # cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURDb2RlU2lnbmlu # Z0NBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQBZca1CZfgn # DucOwEDZk0RXqb8ECXukFiih/rPQ+T5Xvl3bZppGgPnyMyQXXC0fb94p1socJzJZ # fn7rEQ4tHxL1vpBvCepB3Jq+i3A8nnJFHSjY7aujglIphfGND97U8OUJKt2jwnni # EgsWZnFHRI9alEvfGEFyFrAuSo+uBz5oyZeOAF0lRqaRht6MtGTma4AEgq6Mk/iP # LYIIZ5hXmsGYWtIPyM8Yjf//kLNPRn2WeUFROlboU6EH4ZC0rLTMbSK5DV+xL/e8 # cRfWL76gd/qj7OzyJR7EsRPg92RQUC4RJhCrQqFFnmI/K84lPyHRgoctAMb8ie/4 # X6KaoyX0Z93PMYIPeDCCD3QCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoT # DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UE # AxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQBVIt # 1AAIAhnrJTsLVYOdlzANBglghkgBZQMEAgEFAKB8MBAGCisGAQQBgjcCAQwxAjAA # MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgor # BgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCAQ3XZVsCRfrAygWF1VJCKSeaoEx6lf # 0Vx3xX7Gi9lM+jANBgkqhkiG9w0BAQEFAASCAQBUY1IHg/sxujVkYrtqfpgh8vy7 # HOIs3rLCeqoT9HHV7iXKrP5aWU+Ohs4PdJ0bFlweWKysp+uqC30rTrKl2h392eBB # +j/Ud/cGjvMYUrOSMPedHGM1a8LkfJhWFkCTxHM97VgcM6LU1j9wyDyBHJCpF2Td # o65T0JhtdeMT+b1Q0ZrWmTit9rLvJmU9KZ1eqYJUZ4cGXMssgeU4in0ul2xZM3DT # BXYW/8CIQio1QNcRW5mWwlMjOhtGb5hpQD4qGk1aRne4fhwVJLuvh9R8NfjNgwU9 # 6VoGkAEZgRCItLrA6KeWw6JCHmmxyEy/fMr+Z9pOcU9DwEXpkoCYJCriqhSDoYIN # RDCCDUAGCisGAQQBgjcDAwExgg0wMIINLAYJKoZIhvcNAQcCoIINHTCCDRkCAQMx # DzANBglghkgBZQMEAgEFADB3BgsqhkiG9w0BCRABBKBoBGYwZAIBAQYJYIZIAYb9 # bAcBMDEwDQYJYIZIAWUDBAIBBQAEIIrhXYXMqBen856zam2WvlJ08ZAIB0eLVStP # vgxC8F5eAhBd5zOdj1YKgd0zRR15rfdUGA8yMDIxMDQxOTE3MDQzNFqgggo3MIIE # /jCCA+agAwIBAgIQDUJK4L46iP9gQCHOFADw3TANBgkqhkiG9w0BAQsFADByMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQg # VGltZXN0YW1waW5nIENBMB4XDTIxMDEwMTAwMDAwMFoXDTMxMDEwNjAwMDAwMFow # SDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSAwHgYDVQQD # ExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMTCCASIwDQYJKoZIhvcNAQEBBQADggEP # ADCCAQoCggEBAMLmYYRnxYr1DQikRcpja1HXOhFCvQp1dU2UtAxQtSYQ/h3Ib5Fr # DJbnGlxI70Tlv5thzRWRYlq4/2cLnGP9NmqB+in43Stwhd4CGPN4bbx9+cdtCT2+ # anaH6Yq9+IRdHnbJ5MZ2djpT0dHTWjaPxqPhLxs6t2HWc+xObTOKfF1FLUuxUOZB # OjdWhtyTI433UCXoZObd048vV7WHIOsOjizVI9r0TXhG4wODMSlKXAwxikqMiMX3 # MFr5FK8VX2xDSQn9JiNT9o1j6BqrW7EdMMKbaYK02/xWVLwfoYervnpbCiAvSwnJ # laeNsvrWY4tOpXIc7p96AXP4Gdb+DUmEvQECAwEAAaOCAbgwggG0MA4GA1UdDwEB # /wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMEEG # A1UdIAQ6MDgwNgYJYIZIAYb9bAcBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cu # ZGlnaWNlcnQuY29tL0NQUzAfBgNVHSMEGDAWgBT0tuEgHf4prtLkYaWyoiWyyBc1 # bjAdBgNVHQ4EFgQUNkSGjqS6sGa+vCgtHUQ23eNqerwwcQYDVR0fBGowaDAyoDCg # LoYsaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmww # MqAwoC6GLGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtdHMu # Y3JsMIGFBggrBgEFBQcBAQR5MHcwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBPBggrBgEFBQcwAoZDaHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRFRpbWVzdGFtcGluZ0NBLmNydDANBgkq # hkiG9w0BAQsFAAOCAQEASBzctemaI7znGucgDo5nRv1CclF0CiNHo6uS0iXEcFm+ # FKDlJ4GlTRQVGQd58NEEw4bZO73+RAJmTe1ppA/2uHDPYuj1UUp4eTZ6J7fz51Kf # k6ftQ55757TdQSKJ+4eiRgNO/PT+t2R3Y18jUmmDgvoaU+2QzI2hF3MN9PNlOXBL # 85zWenvaDLw9MtAby/Vh/HUIAHa8gQ74wOFcz8QRcucbZEnYIpp1FUL1LTI4gdr0 # YKK6tFL7XOBhJCVPst/JKahzQ1HavWPWH1ub9y4bTxMd90oNcX6Xt/Q/hOvB46NJ # ofrOp79Wz7pZdmGJX36ntI5nePk2mOHLKNpbh6aKLzCCBTEwggQZoAMCAQICEAqh # JdbWMht+QeQF2jaXwhUwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMxFTAT # BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEk # MCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTE2MDEwNzEy # MDAwMFoXDTMxMDEwNzEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERp # Z2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMo # RGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQTCCASIwDQYJ # KoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3QMu5LzY9/3am6gpnFOVQoV7YjSsQO # B0UzURB90Pl9TWh+57ag9I2ziOSXv2MhkJi/E7xX08PhfgjWahQAOPcuHjvuzKb2 # Mln+X2U/4Jvr40ZHBhpVfgsnfsCi9aDg3iI/Dv9+lfvzo7oiPhisEeTwmQNtO4V8 # CdPuXciaC1TjqAlxa+DPIhAPdc9xck4Krd9AOly3UeGheRTGTSQjMF287Dxgaqwv # B8z98OpH2YhQXv1mblZhJymJhFHmgudGUP2UKiyn5HU+upgPhH+fMRTWrdXyZMt7 # HgXQhBlyF/EXBu89zdZN7wZC/aJTKk+FHcQdPK/P2qwQ9d2srOlW/5MCAwEAAaOC # Ac4wggHKMB0GA1UdDgQWBBT0tuEgHf4prtLkYaWyoiWyyBc1bjAfBgNVHSMEGDAW # gBRF66Kv9JLLgjEtUYunpyGd823IDzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud # DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB5BggrBgEFBQcBAQRtMGsw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcw # AoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElE # Um9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNl # cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDov # L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBQ # BgNVHSAESTBHMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 # d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQAD # ggEBAHGVEulRh1Zpze/d2nyqY3qzeM8GN0CE70uEv8rPAwL9xafDDiBCLK938ysf # DCFaKrcFNB1qrpn4J6JmvwmqYN92pDqTD/iy0dh8GWLoXoIlHsS6HHssIeLWWywU # NUMEaLLbdQLgcseY1jxk5R9IEBhfiThhTWJGJIdjjJFSLK8pieV4H9YLFKWA1xJH # cLN11ZOFk362kmf7U2GJqPVrlsD0WGkNfMgBsbkodbeZY4UijGHKeZR+WfyMD+Nv # tQEmtmyl7odRIeRYYJu6DC0rbaLEfrvEJStHAgh8Sa4TtuF8QkIoxhhWz0E0tmZd # tnR79VYzIi8iNrJLokqV2PWmjlIxggJNMIICSQIBATCBhjByMQswCQYDVQQGEwJV # UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu # Y29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1w # aW5nIENBAhANQkrgvjqI/2BAIc4UAPDdMA0GCWCGSAFlAwQCAQUAoIGYMBoGCSqG # SIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjEwNDE5MTcw # NDM0WjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBTh14Ko4ZG+72vKFpG1qrSUpiSb # 8zAvBgkqhkiG9w0BCQQxIgQgKdDiDLUzrbcO8SWoeiWFEcndYOSQnItLPu4/ZolT # WZ8wDQYJKoZIhvcNAQEBBQAEggEAd/aKt6ZsC2P5N28VZfIThpjNjhxmmAv9khgr # BUTRbMJ+wdtGFBLKProj4TYOK5jyac7oxfoj0RNGeZ9OTtBXD/aVzAUi2p6kZ/W/ # /8S+qR9aAWNqupMSOqmYo4YfVDMIewxQRSqQ9GllDVYjUxYuRZeY7uck4qJ5oq5G # wiHKsLW58Ny7uH38YU/aGJsUKojG85RPWI6a9yoLeNERMTAgKtYWU09o+TSXbIb0 # Y4Z7WLslyvvy4k7MSfSGEvSgKTwiZ5TNmNr2H1ginJCEwVTN/MdC8D7VsPSjv6s4 # hKBZtc7aOZp04Rt+ejaUgF/n3RcDA7ImVjULixXcGlmA+BmvnA== # SIG # End signature block |