Uncategorized

Managing BIOS/UEFI Settings from Configuration Manager Part 3

February 4, 2021

This is a multipart post:
Part 1: The code underneath
Part 2: Using as Configuration Items
Part 3: Using as Applications – You are here
Part 4: Using in a task sequence

This topic has no doubt been covered many times before. My work on it started when I stumbled upon Damien Van Robaeys’ post a couple weeks ago. I wanted to take Damien’s work and apply it to deploying with Configuration Manager.

Using our UEFI PowerShell in Applications

If we want to reduce possible reboots and enforce those reboots via an officially supported method, we can use the application model. The trade off is our reporting is not going to be as granular.

If using an application, we can combine all settings we want to set in one script per vendor. Then we create a deployment type for each brand. Let’s see what that would look like.

Let’s start with our detection method for Dell.

Function Confirm-DellUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Category,
    [Parameter(Position = 1,mandatory = $true)]$Setting,
    [Parameter(Position = 2,mandatory = $true)]$Value
    ) 
    (get-item "Dellsmbios:\$($Category)\$($Setting)").CurrentValue -eq $Value
}

$Manufacturer = (get-ciminstance -ClassName Win32_ComputerSystem).Manufacturer
if($Manufacturer -like "Dell*") {
    if(
        (Confirm-DellUEFISetting BootSequence BootList UEFI) -and`
        (Confirm-DellUEFISetting AdvancedBootOptions LegacyOrom Disabled) -and`
        (Confirm-DellUEFISetting SecureBoot SecureBoot Enabled) -and`
        (Confirm-DellUEFISetting TpmSecurity TpmSecurity Enabled) -and`
        (Confirm-DellUEFISetting VirtualizationSupport Virtualization Enabled) -and`
        (Confirm-DellUEFISetting VirtualizationSupport VtForDirectIo Enabled) -and`
        (Confirm-DellUEFISetting VirtualizationSupport TrustExecution Enabled)`
    ){$TRUE}
}
else{}

We then build our actual “install” script. One thing we didn’t talk about when looking at using Configuration Items is the setting for UEFI vs Legacy boot. If we change that, we force the requirement for GPT based disks instead of MBR. Let’s add logic to catch that scenario and convert the disk if needed too.

$Password = ""

Function Confirm-DellUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Category,
    [Parameter(Position = 1,mandatory = $true)]$Setting,
    [Parameter(Position = 2,mandatory = $true)]$Value
    ) 
    (get-item "Dellsmbios:\$($Category)\$($Setting)").CurrentValue -eq $Value
}

Function Set-DellUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Category,
    [Parameter(Position = 1,mandatory = $true)]$Setting,
    [Parameter(Position = 2,mandatory = $true)]$Value,
    [Parameter(Position = 3)]$Password
    )
    $PWReq = (Get-Item -Path DellSmbios:\Security\IsAdminPasswordSet).currentvalue -eq $TRUE
    if($PWReq -and ($password -eq $NULL -or $password -eq "")){Write-error "Password is set but no password was provided"}
    elseif($PWReq -and !($password -eq $NULL -or $password -eq "")){
        Set-Item -Path "DellSmbios:\$($Category)\$($Setting)" $Value -password $password
    }
    else{
        Set-Item -Path "DellSmbios:\$($Category)\$($Setting)" $Value
    }
}

get-command -module DellBIOSProvider | out-null

if(!(Confirm-DellUEFISetting BootSequence BootList UEFI)){Set-DellUEFISetting BootSequence BootList UEFI $password}
if(!(Confirm-DellUEFISetting AdvancedBootOptions LegacyOrom Disabled)){Set-DellUEFISetting AdvancedBootOptions LegacyOrom Disabled $password}
if(!(Confirm-DellUEFISetting SecureBoot SecureBoot Enabled)){Set-DellUEFISetting SecureBoot SecureBoot Enabled $password}
if(!(Confirm-DellUEFISetting TpmSecurity TpmSecurity Enabled)){Set-DellUEFISetting TpmSecurity	TpmSecurity Enabled $password}
if(!(Confirm-DellUEFISetting VirtualizationSupport Virtualization Enabled)){Set-DellUEFISetting VirtualizationSupport Virtualization Enabled $password}
if(!(Confirm-DellUEFISetting VirtualizationSupport VtForDirectIo Enabled)){Set-DellUEFISetting VirtualizationSupport VtForDirectIo Enabled $password}
if(!(Confirm-DellUEFISetting VirtualizationSupport TrustExecution Enabled)){Set-DellUEFISetting VirtualizationSupport TrustExecution Enabled $password}

if(!(get-ciminstance Win32_DiskPartition -Filter 'Type = "GPT: System"') -and (Confirm-DellUEFISetting BootSequence BootList UEFI)){
    Start-Process -FilePath "$ENV:WINDIR\System32\mbr2gpt.exe" -ArgumentList "/convert /allowfullos" -wait
}

We set the deployment type’s install program to “powershell -ExecutionPolicy Bypass -File “.\DellApp.ps1″” and make sure to set the DPCC as a dependency.

We’ll also want to add a requirement based on manufacturer to ensure this DT only runs on Dells.

Finally, make sure to go to the User Experience tab and set the DT to always reboot when run.

Now we repeat for HPs less the dependency. We build our detection.

Function Confirm-HPUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Setting,
    [Parameter(Position = 1,mandatory = $true)]$Value
    ) 
    (get-ciminstance -classname hp_biosEnumeration -namespace root/hp/instrumentedBIOS | Where-Object{$_.Name -eq "$($Setting)"} | select-object -ExpandProperty currentValue) -eq $Value
}

$Manufacturer = (get-ciminstance -ClassName Win32_ComputerSystem).Manufacturer
if($Manufacturer -like "Hewlitt*" -or $Manufacturer -like "HP*"){
    if(
        (Confirm-HPUEFISetting "TPM Activation Policy" "No prompts") -and`
        (Confirm-HPUEFISetting "TPM State" Enable) -and`
        (Confirm-HPUEFISetting "Configure Legacy Support and Secure Boot" "Legacy Support Disable and Secure Boot Enable") -and`
        (Confirm-HPUEFISetting "Legacy Boot Options" Disable) -and`
        (Confirm-HPUEFISetting "Virtualization Technology (VTx)" Enable) -and`
        (Confirm-HPUEFISetting "Virtualization Technology for Directed I/O (VTd)" Enable)
    ){$TRUE}
}
else{}

Then our “install script”

Function Confirm-HPUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Setting,
    [Parameter(Position = 1,mandatory = $true)]$Value
    ) 
    (get-ciminstance -classname hp_biosEnumeration -namespace root/hp/instrumentedBIOS | Where-Object{$_.Name -eq "$($Setting)"} | select-object -ExpandProperty currentValue) -eq $Value
}

Function Set-HPUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Setting,
    [Parameter(Position = 1,mandatory = $true)]$Value,
    [Parameter(Position = 2)]$Password
    )
    $codes = @{
    0 = "Success"
    1 = "Not Supported"
    2 = "Unspecified Error"
    3 = "Timeout"
    4 = "Failed"
    5 = "Invalid Parameter"
    6 = "Access Denied"
    }
    $PWReq = (Get-CIMInstance -Namespace root/hp/instrumentedBIOS -ClassName HP_BIOSSettingInterface) -eq 1
    if($PWReq -and ($password -eq $NULL -or $password -eq "")){Write-error "Password is set but no password was provided"}
    else{
        if($password){$formattedpassword = '<utf-16/>' + $Password} else{$formattedpassword = ""}
        $ReturnValue = (Invoke-CimMethod -InputObject (Get-CimInstance -classname HP_BIOSSettingInterface -namespace root/hp/instrumentedBIOS) -MethodName setbiossetting -Arguments @{ Name = $Setting; Value = $value; Password = $formattedpassword }).Return
        if($ReturnValue -ne 0){Write-error "Setting failed to apply. $($Codes.item($ReturnValue))"}
    }
}

$TS = New-Object -ComObject Microsoft.SMS.TSEnvironment
$password=$TS.Value('UEFIPassword')

if(!(Confirm-HPUEFISetting "TPM Activation Policy" "No prompts")){Set-HPUEFISetting "TPM Activation Policy" "No prompts" $Password}
if(!(Confirm-HPUEFISetting "TPM Device" Available)){Set-HPUEFISetting "TPM Device" Available $Password}
if(!(Confirm-HPUEFISetting "TPM State" Enable)){Set-HPUEFISetting "TPM State" Enable $Password}

if(!(Confirm-HPUEFISetting "UEFI Boot Options" Enable)){Set-HPUEFISetting "UEFI Boot Options" Enable $Password}
if(!(Confirm-HPUEFISetting "Legacy Boot Options" Disable)){Set-HPUEFISetting "Legacy Boot Options" Disable $Password}
if(!(Confirm-HPUEFISetting "Configure Legacy Support and Secure Boot" "Legacy Support Disable and Secure Boot Enable")){Set-HPUEFISetting "Configure Legacy Support and Secure Boot" "Legacy Support Disable and Secure Boot Enable" $Password}

if(!(Confirm-HPUEFISetting "Virtualization Technology (VTx)" Enable)){Set-HPUEFISetting "Virtualization Technology (VTx)" Enable $Password}
if(!(Confirm-HPUEFISetting "Virtualization Technology for Directed I/O (VTd)" Enable)){Set-HPUEFISetting "Virtualization Technology for Directed I/O (VTd)" Enable $Password}

if(!(get-ciminstance Win32_DiskPartition -Filter 'Type = "GPT: System"') -and (Confirm-HPUEFISetting "UEFI Boot Options" Enable)){
    Start-Process -FilePath "$ENV:WINDIR\System32\mbr2gpt.exe" -ArgumentList "/convert /allowfullos" -wait
}

Then Lenovo deployment type, again starting with the detection script.

Function Confirm-LenovoUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Setting,
    [Parameter(Position = 1,mandatory = $true)]$Value
    ) 
    (get-ciminstance -classname Lenovo_BiosSetting -namespace root\wmi | Where-Object{$_.CurrentSetting -like "$($Setting),*"} | select-object -ExpandProperty CurrentSetting).split(',')[-1] -eq $Value
}

$Manufacturer = (get-ciminstance -ClassName Win32_ComputerSystem).Manufacturer
if($Manufacturer -eq "Lenovo"){
    if(
        (Confirm-LenovoUEFISetting SecureBoot Enable) -and`
        (Confirm-LenovoUEFISetting SecurityChip Enable) -and`
        (Confirm-LenovoUEFISetting VirtualizationTechnology Enable) -and`
        (Confirm-LenovoUEFISetting VTdFeature Enable) -and`
        (Confirm-LenovoUEFISetting TXTFeature Enable)
    ){$TRUE}
}
else{}

Then our Lenovo “Install script”.

$password = ""

Function Confirm-LenovoUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Setting,
    [Parameter(Position = 1,mandatory = $true)]$Value
    ) 
    (get-ciminstance -classname Lenovo_BiosSetting -namespace root\wmi | Where-Object{$_.CurrentSetting -like "$($Setting),*"} | select-object -ExpandProperty CurrentSetting).split(',')[-1] -eq $Value
}

Function Set-LenovoUEFISetting{
    param(
    [Parameter(Position = 0,mandatory = $true)]$Setting,
    [Parameter(Position = 1,mandatory = $true)]$Value,
    [Parameter(Position = 2)]$Password
    )
    $PWReq = ((Get-CIMInstance -Namespace root\wmi -ClassName Lenovo_BiosPasswordSettings).PasswordState -in @(2,3,6,7))
    if($PWReq -and ($password -eq $NULL -or $password -eq "")){Write-error "Password is set but no password was provided"}
    elseif($PWReq -and $password){
        $R1 = (Invoke-CimMethod -InputObject (Get-CimInstance -classname Lenovo_SetBiosSetting -namespace root\wmi) -MethodName SetBiosSetting -Arguments @{ parameter = "$Setting,$value,$password,ascii,us" }).Return
        $R2 = (Invoke-CimMethod -InputObject (get-ciminstance -classname Lenovo_SaveBiosSettings -namespace root\wmi) -MethodName SaveBiosSettings  -Arguments @{ parameter = "$Password,ascii,us" }).Return
    }
    else{
        $R1 = (Invoke-CimMethod -InputObject (Get-CimInstance -classname Lenovo_SetBiosSetting -namespace root\wmi) -MethodName SetBiosSetting -Arguments @{ parameter = "$($Setting),$($Value)" }).Return
        $R2 = (Invoke-CimMethod -InputObject (get-ciminstance -classname Lenovo_SaveBiosSettings -namespace root\wmi) -MethodName SaveBiosSettings).Return
    }
    if(($R1 -ne "SUCCESS") -or ($R2 -ne "SUCCESS")){Write-error "Setting failed to apply."}
}

if(!(Confirm-LenovoUEFISetting SecureBoot Enable)){Set-LenovoUEFISetting SecureBoot Enable $password}
if(!(Confirm-LenovoUEFISetting SecurityChip Enable)){Set-LenovoUEFISetting SecurityChip Enable $password}
if(!(Confirm-LenovoUEFISetting VirtualizationTechnology Enable)){Set-LenovoUEFISetting VirtualizationTechnology Enable $password}
if(!(Confirm-LenovoUEFISetting VTdFeature Enable)){Set-LenovoUEFISetting "VTdFeature" "Enable" $password}
if(!(Confirm-LenovoUEFISetting TXTFeature Enable)){Set-LenovoUEFISetting TXTFeature Enable $password}

if(!(get-ciminstance Win32_DiskPartition -Filter 'Type = "GPT: System"') -and (Confirm-LenovoUEFISetting SecureBoot Enable)){
    Start-Process -FilePath "$ENV:WINDIR\System32\mbr2gpt.exe" -ArgumentList "/convert /allowfullos" -wait
}

We end up with our application and a deployment type per vendor that you choose to include. It is possible you’d have to create multiple DTs per vendor if there are differences in the setting names or values.

Now we deploy as desired.

I have included the UEFI application I created as an example, but you will need to put the scripts together from above as I did not include content.

Next: Part 4 – Using in Task Sequences