Using DHCP to Boot WDS to BIOS & UEFI with SCCM

Chris NienaberNetwork Analyst
CERTIFIED EXPERT
IT is my life...SCCM my passion! I work full time with SCCM, Exchange, and Windows Server. I have a beautiful family and love Star Trek!
Published:
Learn how to PXE Boot both BIOS & UEFI machines with DHCP Policies and Custom Vendor Classes


One of the challenges that an IT deployment administrator may face in the field is the ability to boot both BIOS and UEFI machines from the same WDS environment. This is exactly the issue I faced when our organization decided to purchase a number of new Surface devices. These were the first set of devices that were configured to natively boot to UEFI. This leaves you to decide from an organization standpoint whether you wish to boot all your devices using UEFI or the legacy BIOS…or does it.
 
I am a strong believer that finding a workaround to a problem is not a fix to the problem. To that end modern devices such as the surface are meant to be booted using the native UEFI boot. However, many organizations may also still have legacy BIOS devices that do not support UEFI boot or just work better booting from BIOS. Whatever the reasoning behind this it is actually quite easy to setup DHCP to provide the BIOS or UEFI boot file depending on what is used.

The solution!
By using DHCP policies and custom vendor classes for the following DHCP Options:
 
Option 60
Option 66
Option 67
 
The below assumes that you have SCCM configured with a PXE enabled distribution point and a valid and configured DHCP server. You should therefore be at a configured state where you are able to PXE boot BIOS based devices.
 
Create Custom Vendor Classes for Use with your DHCP Policy
 
Think Custom Vendor Classes as Detection Method’s used to determine how devices are requesting a boot image from the DHCP server.
 
  • Open the DHCP Console and expand the IPv4 Node
  • Right-Click on ‘IPv4 Node’ and select ‘Define Vendor Classes’
  • Click ‘Add’
  • Create the UEFI 64-Bit Vendor class first by entering the following information
  • Enter the following information for the respective fields:
    • DisplayName: PXEClient (UEFI x64)
    • Description: PXEClient:Arch:00007
    • ASCII: PXEClient:Arch:00007
  • Click ‘OK’
  • Click ‘Add’
    • DisplayName: PXEClient (UEFI x86)
    • Description: PXEClient:Arch:00006
    • ASCII: PXEClient:Arch:00006
  • Click ‘OK’
  • Click ‘Add’
    • DisplayName: PXEClient (BIOS x86 & x64)
    • Description: PXEClient:Arch:00000
    • ASCII: PXEClient:Arch:00000
  • Click ‘OK’
 
Creating Custom DHCP Policies
 
UEFI 64-Bit DHCP Policy
 
  • Right-Click ‘Policies’ and click ‘New Policy’
  • Give the policy a friendly name that coincides with the your vendor class naming scheme:
    • PolicyName: PXEClient (UEFI x64)
    • Description: Delivers the correct bootfile for (UEFI x64)
  • Click ‘Next’
  • On the ‘Configure Conditions for the policy’ page click ‘add’
  • Select the ‘Value’ drop-down box and select the PXEClient (UEFI x64) vendor class that you created in previous steps
  • Ensure that you check the box ‘Append wildcard(*)’
  • Select ‘Add’
  • Select ‘Ok’
  • Click ‘Next’
  • If you want the policy to affect only a specific range within your scope configure it, otherwise select no and click ‘next’
  • On the Configure settings for the policy page ensure that ‘DHCP Standard Options’ is selected from the drop down box
  • Configure the following scope options:
    • 060: PXEClient
    • 066IP Address of the SCCM or WDS Service
    • 067: smsboot\x64\wdsmgfw.efi
  • Cick ‘Next’
  • On the Summary page click ‘Finish’
 
BIOS 32-Bit & 64-Bit DHCP Policy
 
  • Right-Click ‘Policies’ and click ‘New Policy’
  • Give the policy a friendly name that coincides with the your vendor class naming scheme:
    • PolicyName: PXEClient (BIOS x86 & x64)
    • Description: Delivers the correct bootfile for BIOS machines
  • Click ‘Next’
  • On the ‘Configure Conditions for the policy’ page click ‘add’
  • Select the ‘Value’ drop-down box and select the PXEClient (BIOS x86 & x64) vendor class that you created in previous steps
  • Ensure that you check the box ‘Append wildcard(*)’
  • Select ‘Add’
  • Select ‘Ok’
  • Click ‘Next’
  • If you want the policy to affect only a specific range within your scope configure it, otherwise select no and click ‘next’
  • On the Configure settings for the policy page ensure that ‘DHCP Standard Options’ is selected from the drop down box
  • Configure the following scope options:
    • 060: PXEClient
    • 066IP Address of the SCCM or WDS Service
    • 067: smsboot\x64\wdsnbp.com
  • Cick ‘Next’
  • On the Summary page click ‘Finish’
 
UEFI 32-Bit DHCP Policy

  • Right-Click ‘Policies’ and click ‘New Policy’
  • Give the policy a friendly name that coincides with the your vendor class naming scheme:
    • PolicyName: PXEClient (UEFI x86)
    • Description: Delivers the correct bootfile for (UEFI x86) machines
  • Click ‘Next’
  • On the ‘Configure Conditions for the policy’ page click ‘add’
  • Select the ‘Value’ drop-down box and select the PXEClient (UEFI x86) vendor class that you created in previous steps
  • Ensure that you check the box ‘Append wildcard(*)’
  • Select ‘Add’
  • Select ‘Ok’
  • Click ‘Next’
  • If you want the policy to affect only a specific range within your scope configure it, otherwise select no and click ‘next’
  • On the Configure settings for the policy page ensure that ‘DHCP Standard Options’ is selected from the drop down box
  • Configure the following scope options:
    • 060: PXEClient
    • 066IP Address of the SCCM or WDS Service
    • 067: smsboot\x86\wdsmgfw.efi
  • Cick ‘Next’
  • On the Summary page click ‘Finish’
 
Remove Default PXE Options
 
  • Ensure that you have removed the 067, 066, 060 options from the default scope options to ensure that the Policies take precedence otherwise you will end up with conflict
 
As long as you have configured everything correctly you should now have the ability to boot machines from  BIOS or UEFI. Hopefully this helps alleviate some of the stress surrounding your PXE deployments. This has worked great on all of our distribution points since implementation and has allowed our deployments to be much more flexible.
1
66,437 Views
Chris NienaberNetwork Analyst
CERTIFIED EXPERT
IT is my life...SCCM my passion! I work full time with SCCM, Exchange, and Windows Server. I have a beautiful family and love Star Trek!

Comments (9)

Well... couldn't figure out how to set the inner "Option" on the policy, but everything else is here.

Remember to run this in an administrative powershell prompt on the DHCP server.
You need to restart the DHCPServer service after running this and set the PXEClient settings in the 3 policies.  The BIOS policy is blank, the UEFI polcies are the default of "PXEClient".

The command to run is "Set-DHCPPXEOptions"

Enjoy!


<# 
.Synopsis
	Receives user input, gets the list of DHCP options, classes and policies, then sets them if they don't exist.
.DESCRIPTION 
	Enter the option number, class name or policy name where approporiate.
.NOTES 
	Author: Derek Bannard
.EXAMPLE
	Import-Module .\DHCPPXEOptions.psm1
	Loads the modules to perform the DHCP functions.
.EXAMPLE
	Get-DHCPOptions
	Lists missing options for use with Set-DHCPPXEOptions function.
.EXAMPLE
	Get-DHCPClasses
	Lists missing classes for use with Set-DHCPPXEOptions function.
.EXAMPLE
	Get-DHCPPolicies
	Lists missing policies for use with Set-DHCPPXEOptions function.
.EXAMPLE
	Set-DHCPPXEOptions
	Creates all missing options, classes and policies for BIOS/UEFI PXE co-existance.
#>

<#
=================================================
Error Preferences
=================================================
#>
$errpref = $ErrorActionPreference
$ErrorActionPreference = "SilentlyContinue"


<#
=================================================
Script Variables, comma separated
=================================================
#>
[string[]]$DHCPOptions = 060,066,067
[string[]]$DHCPClasses = "PXEClient:Arch:00000","PXEClient:Arch:00006","PXEClient:Arch:00007"
[string[]]$DHCPPolicies = "PXEClient (BIOS x86 & x64)","UEFI 32-Bit DHCP Policy","UEFI 64-Bit DHCP Policy"

[string[]]$rtnDHCPOptions = @()
[string[]]$rtnDHCPClasses = @()
[string[]]$rtnDHCPPolicies = @()


<#
=================================================
Script Get Functions
=================================================
#>
Function Get-DHCPOptions{
	$arrayOptions = New-Object System.Collections.ArrayList

	ForEach ($DHCPOption in $DHCPOptions){
		Try{
			If((Get-DhcpServerv4OptionDefinition -OptionId $DHCPOption) -eq $null){
				Write-Verbose "OptionId $DHCPOption is not present."
				$arrayOptions.Add($DHCPOption) | Out-Null
				}
			Else{
				Write-Verbose "OptionId $DHCPOption is already present."
				}
		}
		Catch{
		}
	}
	$global:rtnDHCPOptions = $arrayOptions
}


Function Get-DHCPClasses{
	$arrayClasses = New-Object System.Collections.ArrayList

	ForEach ($DHCPClass in $DHCPClasses){
		Try{
			If((Get-DhcpServerv4Class -Type Vendor | Where {$_.AsciiData -eq $DHCPClass}) -eq $null){
				Write-Verbose "OptionId $DHCPClass is not present."
				$arrayClasses.Add($DHCPClass) | Out-Null
				}
			Else{
				Write-Verbose "OptionId $DHCPClass is already present."
				}
		}
		Catch{
		}
	}
	$global:rtnDHCPClasses = $arrayClasses
}


Function Get-DHCPPolicies{
	$arrayPolicies = New-Object System.Collections.ArrayList

	ForEach ($DHCPPolicy in $DHCPPolicies){
		Try{
			If((Get-DhcpServerv4Policy -Name $DHCPPolicy) -eq $null){
				Write-Verbose "OptionId $DHCPPolicy is not present."
				$arrayPolicies.Add($DHCPPolicy) | Out-Null
				}
			Else{
				Write-Verbose "OptionId $DHCPPolicy is already present."
				}
		}
		Catch{
		}
	}
	$global:rtnDHCPPolicies = $arrayPolicies
}


<#
=================================================
Script Set Function
=================================================
#>
Function Set-DHCPPXEOptions{
	If($rtnDHCPOptions){
		ForEach ($rtnDHCPOption in $rtnDHCPOptions){
			If($rtnDHCPOption -eq "060"){
				Try{
					Write-Output "Adding OptionId 060..."
					Add-DhcpServerv4OptionDefinition -Name "PXEClient" -Description "PXE Support" -DefaultValue "PXEClient" -OptionId 060 -Type String
				}
				Catch{
				}
			}
			ElseIf($rtnDHCPOption -eq "066"){
				Try{
					Write-Output "Adding OptionId 066..."
					Add-DhcpServerv4OptionDefinition -Name "Boot Server Host Name" -Description "TFTP boot server host name" -OptionId 066 -Type String
				}
				Catch{
				}
			}
			ElseIf($rtnDHCPOption -eq "067"){
				Try{
					Write-Output "Adding OptionId 067..."
					Add-DhcpServerv4OptionDefinition -Name "Bootfile Name" -Description "Bootfile Name" -OptionId 067 -Type String
				}
				Catch{
				}
			}
			Else{
				Write-Output "Undefined options cannot be added!"
			}
		}
	}
	Else{
		Write-Output "No Options are required to be added."
	}


	If($rtnDHCPClasses){
		ForEach ($rtnDHCPClass in $rtnDHCPClasses){
			If($rtnDHCPClass -eq "PXEClient:Arch:00000"){
				Try{
					Write-Output "Adding PXEClient (BIOS x86 & x64) Class..."
					Add-DhcpServerv4Class -Name "PXEClient (BIOS x86 & x64)" -Type Vendor -Data "0x505845436c69656e743a417263683a3030303030" -Description "PXEClient:Arch:00000"
				}
				Catch{
				}
			}
			ElseIf($rtnDHCPClass -eq "PXEClient:Arch:00006"){
				Try{
					Write-Output "Adding UEFI 32-Bit DHCP Class..."
					Add-DhcpServerv4Class -Name "PXEClient (UEFI x86)" -Type Vendor -Data "0x505845436c69656e743a417263683a3030303036" -Description "PXEClient:Arch:00006"
				}
				Catch{
				}
			}
			ElseIf($rtnDHCPClass -eq "PXEClient:Arch:00007"){
				Try{
					Write-Output "Adding UEFI 64-Bit DHCP Class..."
					Add-DhcpServerv4Class -Name "PXEClient (UEFI x64)" -Type Vendor -Data "0x505845436c69656e743a417263683a3030303037" -Description "PXEClient:Arch:00007"
				}
				Catch{
				}
			}
			Else{
				Write-Output "Undefined classes cannot be added!"
			}
		}
	}
	Else{
		Write-Output "No Classes are required to be added."
	}


	If($rtnDHCPPolicies){
		ForEach ($rtnDHCPPolicy in $rtnDHCPPolicies){
			If($rtnDHCPPolicy -eq "PXEClient (BIOS x86 & x64)"){
				Try{
					Write-Output "Adding PXEClient (BIOS x86 & x64) Policy..."
					Add-DhcpServerv4Policy -Name "PXEClient (BIOS x86 & x64)" -Description "Delivers the correct bootfile for BIOS machines" -Condition OR -VendorClass EQ,"PXEClient (BIOS x86 & x64)*" -ProcessingOrder 1 -Enabled $True -Confirm:$False
				}
				Catch{
				}
			}
			ElseIf($rtnDHCPPolicy -eq "UEFI 32-Bit DHCP Policy"){
				Try{
					Write-Output "Adding UEFI 32-Bit DHCP Policy..."
					Add-DhcpServerv4Policy -Name "UEFI 32-Bit DHCP Policy" -Description "Delivers the correct bootfile for (UEFI x86) machines" -Condition OR -VendorClass EQ,"PXEClient (UEFI x86)*" -ProcessingOrder 3 -Enabled $True -Confirm:$False
				}
				Catch{
				}
			}
			ElseIf($rtnDHCPPolicy -eq "UEFI 64-Bit DHCP Policy"){
				Try{
					Write-Output "Adding UEFI 64-Bit DHCP Policy..."
					Add-DhcpServerv4Policy -Name "UEFI 64-Bit DHCP Policy" -Description "Delivers the correct bootfile for (UEFI x64) machines" -Condition OR -VendorClass EQ,"PXEClient (UEFI x64)*" -ProcessingOrder 2 -Enabled $True -Confirm:$False
				}
				Catch{
				}
			}
			Else{
				Write-Output "Undefined policies cannot be added!"
			}
		}
	}
	Else{
		Write-Output "No Policies are required to be added."
	}
	
	#Restart-Service "DHCPServer"
}

Get-DHCPOptions
Get-DHCPClasses
Get-DHCPPolicies

Open in new window

Many Thanks.

One more question:
I also deploy BIOS x86, but the policy covers (x86 & x64).  I will set up two 'Define Vendor Classes' for x86 and x64? But ASCII, could I set as PXEClient:Arch:00000 for both?
Hello
this wont work if WDS and DHCP are on same server
Chris NienaberNetwork Analyst
CERTIFIED EXPERT

Author

Commented:
@Hyoin Wang

There is no need to seperate these out into seperate vendor classes for x86 and x64 respectively as they both use the same architecture flag

That is why mine is combined in the article

Thanks
Chris NienaberNetwork Analyst
CERTIFIED EXPERT

Author

Commented:
@Saeid Ansaripour

I'm not sure how your infrastructure is configured however in our school division we deploy DHCP and WDS on the same VM and it works fine. We do use this script when configuring DHCP and WDS in a coexistence scenario, if my memory serves me i believe it sets the flags necessary for this scenario:

#ENSURE THE I: DRIVE IS COMPLETELY WIPED BEFORE RUNNING THE PROCEDING SCRIPT

Install-WindowsFeature WDS

wdsutil /initialize-server /REMINST:I:\RemoteInstall

Start-Sleep -Seconds 2

Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\WDSServer\Providers\WDSPXE -Name UseDhcpPorts -Value 0

Start-Sleep -Seconds 2

WDSUTIL /Set-Server /UseDHCPPorts:No /DHCPOption60:Yes

Start-Sleep -Seconds 2

Write-Host "The Server will now restart to finish configuring...Press <enter> to Continue!" -ForegroundColor Green
Pause

Shutdown -r -t 1

Open in new window


*EDIT: I should add that we only run the above if the built in Distribution Point install mechanism of the SCCM role installer fail us

View More

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.