The new Windows 10 Peer 2 Peer feature Delivery Optimization was enhanced by the setting to query DHCP option ID 234 to get a Group ID (DOGroupIdSource). It was implemented into the latest Windows 10 version 1803 based on my feedback. I’m a little proud that the idea was well received and my product feedback was implemented as new option within six month.
It was officially announced with Windows Insider Preview 17063. It can be read here: https://blogs.windows.com/windowsexperience/2017/12/19/announcing-windows-10-insider-preview-build-17063-pc/#zluZyU1FMlLMzU6h.97 in the section New features for IT Pros in Delivery Optimization.
I’ve written a blog post how Delivery Optimization works and how to use this feature with new Windows versions 1803+, see here: Configure Delivery Optimization with Intune for Windows Update for Business. It’s really great to have it with Windows 10 version 1803+ but I need to provide this functionality to older Windows 10 versions (1703 and 1709) also. I want to use this very good and flexible grouping capability from now on for all devices even pre-version 1803.
Therefore I have designed a solution to provide this functionality to older versions of Windows 10 and switch over to the native Windows 10 implemented solution as soon as the device gets upgraded to 1803.
First problem is to get the DHCP option from the DHCP server. Luckily I’ve written a small C++ program to do that in the past. I’ve written it to even work with a WinPE environment. The small binary can be used to send the DHCP option ID x request. When executed the binary expects a result as a string value. Below an example:
DhcpOption.exe <OptionID>

It’s even possible to specify a debug switch
DhcpOption.exe <OptionID> [debug]
to get debug output for troubleshooting:

The C++ solution can be found on my GitHub here:
https://github.com/okieselbach/Helpers/tree/master/DhcpOption
The compiled x64 binary DhcpOption.exe can be found here:
https://github.com/okieselbach/Intune/tree/master/ManagementExtension-Samples/DOScript
With this little helper we can use the Intune Management Extension and design a PowerShell script to:
- query DHCP server for the Option ID 234
- write result (Group ID) to the registry
Prerequisite is an available Option ID 234 on the DHCP server. See Configure Delivery Optimization with Intune for Windows Update for Business how to configure the DHCP server for this.
To support travelling users we need to make sure the device will query the DHCP server from time to time to get the group ID belonging to the current DHCP scope the client is using. For this we schedule the script as a scheduled task and run it at logon and on every unlock of the workstation.
The Delivery Optimization service will query the registry value for every new request and this makes sure a client uses the Group ID delivered by DHCP from the particular site.
To make sure we do not interfere with the native implementation starting with 1803 I implemented a logic to disable the scheduled task and remove the registry key as soon as Windows 10 version 1803, a build greater than 16299 is found.
The DhcpOption.exe will be provided from an Azure Blob Storage account. We need to create a Storage account as type Blob storage and a container to store the DhcpOption.exe. Then we use the provided download link in the script to get the binary during install. A guide how to create the Azure storage account is included in my article Gather Windows 10 AutoPilot info in Azure Blob Storage during wipe and reload. You don’t need the SAS token, just the container and upload DhcpOption.exe. The SAS token is only needed to support POSTS methods for uploading new files to the blob storage. The DhcpOption.exe is uploaded once and then provided for download only.
With this solution we can use the DHCP option for all Windows 10 version until 1803 and as soon as we get upgraded we disable and remove our self and the native implementation takes over. To make sure the native implementation is used as soon 1803 is found we need to implement the new DO settings (DOGroupIdSource). Follow my guide in my previous post for this Configure Delivery Optimization with Intune for Windows Update for Business.
Source Code of the full custom DO install script Register-DOScript.ps1 can be found on my GitHub Gist here:
<# | |
Version: 1.1 | |
Author: Oliver Kieselbach | |
Script: Register-DOScript.ps1 | |
Description: | |
Register a PS script as scheduled task to query DHCP for option 234 to get Group ID GUID | |
Release notes: | |
Version 1.0: Original published version. | |
Version 1.1: Fix, removed null terminator at the end of DHCP option value provided by DHCPOption.exe | |
The script is provided "AS IS" with no warranties. | |
#> | |
$exitCode = 0 | |
if (![System.Environment]::Is64BitProcess) { | |
# start new PowerShell as x64 bit process, wait for it and gather exit code and standard error output | |
$sysNativePowerShell = "$($PSHOME.ToLower().Replace("syswow64", "sysnative"))\powershell.exe" | |
$pinfo = New-Object System.Diagnostics.ProcessStartInfo | |
$pinfo.FileName = $sysNativePowerShell | |
$pinfo.Arguments = "-ex bypass -file `"$PSCommandPath`"" | |
$pinfo.RedirectStandardError = $true | |
$pinfo.RedirectStandardOutput = $true | |
$pinfo.CreateNoWindow = $true | |
$pinfo.UseShellExecute = $false | |
$p = New-Object System.Diagnostics.Process | |
$p.StartInfo = $pinfo | |
$p.Start() | Out-Null | |
$exitCode = $p.ExitCode | |
$stderr = $p.StandardError.ReadToEnd() | |
if ($stderr) { Write-Error -Message $stderr } | |
} | |
else { | |
# start logging to TEMP in file "scriptname".log | |
Start-Transcript -Path "$env:TEMP\$($(Split-Path $PSCommandPath -Leaf).ToLower().Replace(".ps1",".log"))" | Out-Null | |
# definition of PS script to query DHCP option ID 234 and write result to registry | |
$scriptContent = @' | |
# With Windows 10 version 1803+ DOGroupIDSource can be set by MDM and Option ID 234 is queried natively by Windows! | |
# Due to this a version check is done to disable the solution when Windows 10 version 1803 is found. | |
# REMEMBER: as soon as 1803 is used the DOGroupIDSource must be set! | |
# | |
# https://docs.microsoft.com/en-us/windows/client-management/mdm/policy-csp-deliveryoptimization#deliveryoptimization-dogroupidsource | |
# DOGroupIDSource = 3 (DHCP Option ID) | |
$registryPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DeliveryOptimization" | |
if ([int][Environment]::OSVersion.Version.Build -gt 16299) { | |
Disable-ScheduledTask -TaskName "RunCustomDOScript" | Out-Null | |
if (Test-Path $registryPath) { | |
Remove-Item -Path $registryPath -Force -Confirm:$false | |
} | |
} | |
else { | |
$dhcpOptionTool = "DhcpOption.exe" | |
$customScriptsPath = $(Join-Path $env:ProgramData CustomScripts) | |
$filePath = "$customScriptsPath\$dhcpOptionTool" | |
$optionId = 234 | |
$optionIdValue = Invoke-Expression -Command "$filePath $optionId" | |
if (-not [string]::IsNullOrWhiteSpace($optionIdValue)) { | |
if (!(Test-Path $registryPath)) { | |
New-Item -Type String -Path $registryPath | Out-Null | |
} | |
$Name = "DOGroupId" | |
$value = $optionIdValue.SubString(0, $optionIdValue.Length - 1) | |
New-ItemProperty -Path $registryPath -Name $name -Value $value -PropertyType string -Force | Out-Null | |
} | |
} | |
'@ | |
# Scheduled task XMl definition. Trigger on Logon and Workstation unlock | |
$xmlTask = @' | |
<?xml version="1.0" encoding="UTF-16"?> | |
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> | |
<RegistrationInfo> | |
<Author>Admin</Author> | |
<Description>This script receives DO Group ID from DHCP Option ID 234 and writes value to registry.</Description> | |
<URI>\RunCustomDOScript</URI> | |
</RegistrationInfo> | |
<Triggers> | |
<LogonTrigger> | |
<Enabled>true</Enabled> | |
</LogonTrigger> | |
<SessionStateChangeTrigger> | |
<Enabled>true</Enabled> | |
<StateChange>SessionUnlock</StateChange> | |
</SessionStateChangeTrigger> | |
</Triggers> | |
<Principals> | |
<Principal id="Author"> | |
<UserId>S-1-5-18</UserId> | |
<RunLevel>LeastPrivilege</RunLevel> | |
</Principal> | |
</Principals> | |
<Settings> | |
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> | |
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> | |
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries> | |
<AllowHardTerminate>true</AllowHardTerminate> | |
<StartWhenAvailable>true</StartWhenAvailable> | |
<RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable> | |
<IdleSettings> | |
<StopOnIdleEnd>true</StopOnIdleEnd> | |
<RestartOnIdle>false</RestartOnIdle> | |
</IdleSettings> | |
<AllowStartOnDemand>true</AllowStartOnDemand> | |
<Enabled>true</Enabled> | |
<Hidden>false</Hidden> | |
<RunOnlyIfIdle>false</RunOnlyIfIdle> | |
<DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession> | |
<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine> | |
<WakeToRun>false</WakeToRun> | |
<ExecutionTimeLimit>PT1H</ExecutionTimeLimit> | |
<Priority>7</Priority> | |
</Settings> | |
<Actions Context="Author"> | |
<Exec> | |
<Command>powershell.exe</Command> | |
<Arguments>-ex bypass -file "C:\ProgramData\CustomScripts\DOScript.ps1"</Arguments> | |
</Exec> | |
</Actions> | |
</Task> | |
'@ | |
# we register the script only on pre 1803 Windows 10 versions. | |
if ([int][Environment]::OSVersion.Version.Build -le 16299) { | |
# create custom script folder and write PS script and dhcp option helper binary | |
$customScriptsPath = $(Join-Path $env:ProgramData CustomScripts) | |
if (!(Test-Path $customScriptsPath)) { | |
New-Item -Path $customScriptsPath -ItemType Directory -Force -Confirm:$false | |
} | |
Out-File -FilePath "$customScriptsPath\DOScript.ps1" -InputObject $scriptContent -Encoding unicode -Force -Confirm:$false | |
$dhcpOptionTool = "DhcpOption.exe" | |
$dhcpOptionToolPath = "$customScriptsPath\$dhcpOptionTool" | |
if (Test-Path $dhcpOptionToolPath) { | |
Remove-Item -Path $dhcpOptionToolPath -Force -Confirm:$false | |
} | |
try { | |
# get DhcpOption.exe from Azure Blob storage | |
$url = "https://REPLACE-ME-WITH-YOUR-ACCOUNT.blob.core.windows.net/REPLACE-ME-WITH-YOUR-CONTAINER/DhcpOption.exe" | |
$ProgressPreference = 0 | |
Invoke-WebRequest $url -OutFile $dhcpOptionToolPath -UseBasicParsing | |
$taskName = "RunCustomDOScript" | |
Register-ScheduledTask -TaskName $taskName -Xml $xmlTask -Force | |
Start-ScheduledTask -TaskName $taskName | Out-Null | |
} | |
catch { | |
Write-Error -Message "Could not write regsitry value" -Category OperationStopped | |
} | |
} | |
Stop-Transcript | Out-Null | |
} | |
exit $exitCode |
Make sure to replace the Azure blob storage URL with your own one!
The uninstall script Unregister-DOScript.ps1 is also available via my GitHub Gist:
<# | |
Version: 1.0 | |
Author: Oliver Kieselbach | |
Script: Unregister-DOScript.ps1 | |
Description: | |
Unregister the scheduled task and delete DO registry key | |
Release notes: | |
Version 1.0: Original published version. | |
The script is provided "AS IS" with no warranties. | |
#> | |
$exitCode = 0 | |
if (![System.Environment]::Is64BitProcess) { | |
# start new PowerShell as x64 bit process, wait for it and gather exit code and standard error output | |
$sysNativePowerShell = "$($PSHOME.ToLower().Replace("syswow64", "sysnative"))\powershell.exe" | |
$pinfo = New-Object System.Diagnostics.ProcessStartInfo | |
$pinfo.FileName = $sysNativePowerShell | |
$pinfo.Arguments = "-ex bypass -file `"$PSCommandPath`"" | |
$pinfo.RedirectStandardError = $true | |
$pinfo.RedirectStandardOutput = $true | |
$pinfo.CreateNoWindow = $true | |
$pinfo.UseShellExecute = $false | |
$p = New-Object System.Diagnostics.Process | |
$p.StartInfo = $pinfo | |
$p.Start() | Out-Null | |
$exitCode = $p.ExitCode | |
$stderr = $p.StandardError.ReadToEnd() | |
if ($stderr) { Write-Error -Message $stderr } | |
} | |
else { | |
# start logging to TEMP in file "scriptname".log | |
Start-Transcript -Path "$env:TEMP\$($(Split-Path $PSCommandPath -Leaf).ToLower().Replace(".ps1",".log"))" | Out-Null | |
$taskName = "RunCustomDOScript" | |
Stop-ScheduledTask -TaskName $taskName | Out-Null | |
if (Get-ScheduledTask -TaskName $taskName) { | |
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false | |
} | |
$customScriptsPath = $(Join-Path $env:ProgramData CustomScripts) | |
$dhcpOptionPath = "$customScriptsPath\DhcpOption.exe" | |
$doScriptPath = "$customScriptsPath\DOScript.ps1" | |
$registryPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DeliveryOptimization" | |
if (Test-Path $dhcpOptionPath) { | |
Remove-Item -Path $dhcpOptionPath -Force -Confirm:$false | |
} | |
if (Test-Path $doScriptPath) { | |
Remove-Item -Path $doScriptPath -Force -Confirm:$false | |
} | |
if (Test-Path $registryPath) { | |
Remove-Item -Path $registryPath -Force -Confirm:$false | |
} | |
Stop-Transcript | Out-Null | |
} | |
exit $exitCode |
If we combine the script with Intune Management Extension we can easily deploy this solution to our Azure AD joined modern managed Windows 10 pre-version 1803 devices.
We will get the files for scheduling at C:\ProgramData\CustomScripts

and the scheduled task RunCustomDOscript

with task trigger logon or unlock of workstation

when executed we will get the Group ID from the DHCP server

and the received string is written to the registry

for me this bridges the time until all devices are upgraded to Windows 10 version 1803 and gives me enough flexibility to group my devices to achieve maximum Delivery Optimization benefits.
Happy caching!
Awesome to see your idea being implemented into Windows. Something to be proud of! A little bird also told me that they are cutting down Windows 10 upgrade time to a new build (like rs5) in a couple of minutes.
Keep up the Nice blog Posts
Thank you very much for the nice words! I will try to find good stuff to blog about :-). Regarding lower upgrade times it would be a great enhancement of the upgrade process as a lot of customers complaining about long upgrade procedure especially when using older devices with HDD instead of SSD. One advantage will be the new Universal Update Platform (UUP) and the greatly reduced file sizes with the upcoming releases as they fully support differential upgrade. I’m eager to see how the next upgrade will perform.
Nice work Oliver 😉
Thank you!
Really good work Oliver….
Thank you Thomas!
Hi, Oliver
Can you please clarify…can we find the value of the DHCP Option for 1803 or newer devices within the registry?
We were able to locate the DHCP Options on the actual interface, but we are struggling to confirm that the value is being used by Delivery Optimization.
Hi Angela,
yes I know this is a pain as it is not really logged. The only way to verify it is to check if they actually do use DO and have the same group ID by using Windows Analytics – Update Compliance. Follow my guide https://oliverkieselbach.com/2019/03/28/windows-analytics-onboarding-with-intune/ and onboard the devices to the Update Compliance solution. the other solutions will be deprecated on january 2020. As soon as they are onboarded wait for 24h-48h to see them appearing in the portal. Then you can look at the device entries and there is a group ID (Log analytics > WUDOStatus > entries have GroupID). Sadly it is a encoded GroupID so you need to find a way to see if they are using all the same encoded ID and other not configured with the DHCP option using a differnet Group ID, this was you can make sure they are using the one you configured.
best,
Oliver