Tag Archives: DHCP

Automating DHCP Scope Option Removal with PowerShell

If you’re managing a large network with multiple DHCP servers, you know how tedious it can be to manually remove DHCP scope options. Fortunately, PowerShell can help automate the process and make network management much more efficient. In this post, we’ll walk you through a PowerShell function that can remove DHCP scope options with just a few lines of code.

The “Remove-DhcpScopeOptions” Function

The “Remove-DhcpScopeOptions” function takes two parameters: the name of the DHCP server and a switch for the “-WhatIf” parameter. The “-WhatIf” parameter allows you to see what the function would do without actually making any changes.

function Remove-DhcpScopeOptions {
  param (

  # Get all DHCP scopes on the server
  $scopes = Get-DhcpServerv4Scope -ComputerName $ComputerName

  # Get all options for the DHCP server
  $serverOptions = Get-DhcpServerv4OptionValue -ComputerName $ComputerName

  # For each scope, get the options and compare them to the server-level options
  foreach ($scope in $scopes) {
    $scopeOptions = Get-DhcpServerv4OptionValue -ScopeId $scope.ScopeId -ComputerName $ComputerName

    # For each option in the scope, check if it exists at the server level with the same value
    foreach ($option in $scopeOptions) {
      $serverOption = $serverOptions | Where-Object { $_.OptionId -eq $option.OptionId }
      if ($serverOption -ne $null -and $serverOption.Value -eq $option.Value) {
        # If the option exists at the server level with the same value, remove it from the scope
        if ($WhatIf) {
          Write-Host "What if: Removing option $($option.OptionId) from scope $($scope.ScopeId) on DHCP server $ComputerName."
        } else {
          Remove-DhcpServerv4OptionValue -ScopeId $scope.ScopeId -OptionId $option.OptionId -ComputerName $ComputerName -Confirm:$false

  # Replicate the scopes to all DHCP servers in the enterprise
  if (!$WhatIf) {
    Invoke-DhcpServerv4ReplicateScopes -ComputerName $ComputerName

How it Works

The “Remove-DhcpScopeOptions” function works by first getting all DHCP scopes on the server using the “Get-DhcpServerv4Scope” cmdlet. It stores the results in the $scopes variable. It then gets all options for the DHCP server using the “Get-DhcpServerv4OptionValue” cmdlet and stores the results in the $serverOptions variable.

For each DHCP scope, the function gets the options using the “Get-DhcpServerv4OptionValue” cmdlet and stores the results in the $scopeOptions variable. It then compares the options in each scope to the server-level options and removes any options that exist at the server level with the same value. Finally, the function replicates the scopes to all DHCP servers in the enterprise.


Remove-DhcpScopeOptions -ComputerName "dhcpserver01" -WhatIf

How to Convert DHCP Leases to Reservations Using PowerShell

As a system administrator, you might have to manage a Windows DHCP server and convert DHCP leases to reservations at some point. However, this can be a tedious task if you have many leases to convert. Fortunately, PowerShell can automate this process, making it much easier and faster. This post provides a step-by-step guide on how to convert DHCP leases to reservations using PowerShell.

Step 1: Open PowerShell

The first step is to open PowerShell with administrative privileges on the Windows DHCP server. You can do this by right-clicking on the PowerShell icon and selecting “Run as administrator.”

Step 2: Define the Functions

Copy and paste the following functions into PowerShell:

function Convert-DhcpLeasesToReservations
    param (


    $leases = Get-DhcpServerv4Lease -ComputerName localhost -ScopeId $ScopeId

    foreach ($lease in $leases)
        $reservation = New-DhcpServerv4Reservation -IPAddress $lease.IPAddress -ClientId $lease.ClientId -ScopeId $lease.ScopeId -Description "Converted from DHCP lease"
        if (!$WhatIf) {
            Add-DhcpServerv4Reservation -ComputerName localhost -Reservation $reservation

    Write-Host "All DHCP leases within scope $ScopeId have been converted to reservations"

function Convert-DhcpLeasesToReservationsByFilter
    param (


    $scopes = Get-DhcpServerv4Scope -ComputerName localhost | Where-Object { $_.Name -like $Filter }

    foreach ($scope in $scopes)
        Convert-DhcpLeasesToReservations -ScopeId $scope.ScopeId -WhatIf:$WhatIf

Step 3: Run the Functions

To use these functions, you need to run Convert-DhcpLeasesToReservationsByFilter and specify the filter to select the DHCP scopes you want to convert DHCP leases to reservations. For instance, you can run:

Convert-DhcpLeasesToReservationsByFilter -Filter "192.168.*"

This command will convert all DHCP leases within the scopes that match the filter “192.168.*” to reservations.

You can also use the -WhatIf parameter to simulate the execution of the function without making any changes. This helps you to see what the function will do before actually running it. For instance, you can run:

Convert-DhcpLeasesToReservationsByFilter -Filter "192.168.*" -WhatIf

This command will display the details of the actions the function will perform, but it will not execute them.


Using PowerShell to convert DHCP leases to reservations can save you time and effort. The functions provided in this blog post simplify the process, allowing you to automate the conversion of DHCP leases to reservations in a few simple steps. By following the steps outlined above, you can easily and quickly convert DHCP leases to reservations on your Windows DHCP server.

SCCM PXE Booting with NSX-T


PXE boot stuck at “Waiting for Approval”

If you’re experiencing a “Waiting for Approval” message when attempting to PXE boot in SCCM, it’s likely due to a common issue with NSX-T. When virtualizing a Distribution Point in SCCM and attempting to use it for PXE booting, you need to make some changes in NSX-T to allow it to function properly.

By default, NSX-T blocks servers from receiving or replying to DHCP requests, which PXE booting relies on heavily. To enable PXE booting for specific servers, you’ll need to create a “Segment Security Policy” profile in NSX-T and disable DHCP Server Block. Once you’ve done this, create a new network segment with the appropriate VLAN and assign the policy you just created to it.

Finally, move your Distribution Points to the newly created segment in VCenter. This should resolve the “Waiting for Approval” issue and allow you to PXE boot successfully.

By following these steps, you’ll be able to use virtualized Distribution Points in SCCM for PXE booting without any further issues. Don’t let a simple configuration issue hold you back from taking advantage of all SCCM has to offer!

Setting a DHCP Option Value to Hex Bytes

So sometimes, some annoying times, you have a Vendor scoped DHCP option that you need to set and it is hex bytes. This can be quite frustrating as the GUI doesn’t provide an option to set the value (at least I haven’t found a way) and even when it does, you have to set it using the hex value. The second problem being, I don’t speak Hex.

The way I’d always done it before, and that comes up when I search for it right now uses netsh.

netsh dhcp server scope set optionvalue 125 ENCAPSULATED 000003045669643A697070686F6E652E6D6974656C2E636F6D3B73775F746674703D3139322E3136382E312E313B63616C6C5F7372763D3139322E3136382E312E312C3139322E3136382E312E323B

This is fine if you already have the hex value, or the way to get it. It just isn’t idea if you want to do it for a ton of scopes, or if you don’t have the hex value.

Format-Hex will take a string and make it into an array of hex bytes nicely, so you can either use Powershell to produce that hex string

$hex  = [convert]::ToChar(0) + [convert]::ToChar(0)+ [convert]::ToChar(3) +  [convert]::ToChar(4) + "Vid:ipphone.mitel.com;sw_tftp=;call_srv=,;"  | Format-Hex
$string = ($hex.Bytes|ForEach-Object ToString X2) -join ''

and Set-DhcpServerv4OptionValue will take that array and save it into the DHCP server for us, so you can then bulk setup scopes:

$hex  = [convert]::ToChar(0) + [convert]::ToChar(0)+ [convert]::ToChar(3) +  [convert]::ToChar(4) + "Vid:ipphone.mitel.com;sw_tftp=;call_srv=,;"  | Format-Hex
Set-DhcpServerv4OptionValue -ComputerName dhcpserver -ScopeId -OptionID 125 -Value $hex.Bytes

Replace the dchpserver with your actual dhcp server name, the scope ID would be the IP of the scope, etc… The nice thing in powershell is we can then script this and loop over scopes. Building the string per scope and setting it, which would be more complicated with the netsh version. Also sense it is in plain text instead of HEX it is far easier to read and update in the future.

We can reverse the process though it is slightly messier

$value = Get-DhcpServerv4OptionValue -computername dhcpserver -scopeid -OptionId 125 
($value.value|ForEach-Object {[char][byte]"$_"}) -join ''

This will grab the value as an array of strings, in the form of “0x00”, convert that to bytes, then convert that to chars, then join it all back together into a string for viewing.

Collecting DHCP Scope Data with Grafana

In order to collect my DHCP scope statistics data into Grafana I turned to PowerShell.  We can use Get-DhcpServerv4Scope to list our all our scopes, Get-DhcpServerv4ScopeStatistics to get the stats for each, and then a little bit of regex and math to add some additional stats that we then bring into an InfluxDB, which then ultimately gets mapped be Grafana.

I have multiple sites, with multiple scopes, which ends up with tons and tones of data.  I already have Nagios alerts that tell me if individual scopes are in danger ranges of available IP’s etc, so for Grafana I was more interested in aggregated data about groups of scopes and how users in my network were changing.  In our case, the actual scope names are contained inside the parenthesis, so I used some regex to match scope names between parenthesis and then build a hash table of stats with those scope names and total up the free and used IPs in each range.

Enough chatter, here is the script:

Function Get-DHCPStatistics {
    Process {
        # retrieve all scopes
        $scopes = Get-DhcpServerv4Scope -ComputerName $ComputerName -ErrorAction:SilentlyContinue 

        # setup all variables we are going to use
        $report = @{}
        $totalScopes = 0
        $totalFree =  0
        $totalInUse = 0

        ForEach ($scope In $scopes) {
            # We have multiple sites and include the scope name inside () at each scope
            # this aggregates scope data by name
            if ($scope.Name -match '.*\((.*)\).*') {
                $ScopeName = $Matches[1]
            } else {
                $ScopeName = $scope.Name

            # initials a named scope if it doens't exist already
            if (!($report.keys -contains $ScopeName )) {
                $report[$ScopeName] = @{
                    Free = 0
                    InUse = 0
                    Scopes = 0

            $ScopeStatistics = Get-DhcpServerv4ScopeStatistics -ScopeID $scope.ScopeID -ComputerName $ComputerName -ErrorAction:SilentlyContinue
            $report[$ScopeName].Free += $ScopeStatistics.Free
            $report[$ScopeName].InUse += $ScopeStatistics.InUse
            $report[$ScopeName].Scopes += 1

            $totalFree += $ScopeStatistics.Free
            $totalInUse += $ScopeStatistics.InUse
            $totalScopes += 1

        ForEach ($scope in $report.keys) {
            if ($report[$scope].InUse -gt 0) {
                    Name = $scope
                    Free = $report[$scope].Free
                    InUse = $report[$scope].InUse
                    Scopes = $report[$scope].Scopes
                    PercentFull = [math]::Round(100 *  $report[$scope].InUse / $report[$scope].Free , 2)
                    PercentOfTotal = [math]::Round( 100 * $report[$scope].InUse / $totalInUse, 2)

        #Return one last summary object
            Name = "Total"
            Free = $totalFree
            InUse = $totalInUse
            Scopes = $totalScopes
            PercentFull = [math]::Round(100 *  $totalInUse / $totalFree , 2)
            PercentOfTotal = 0



Get-DHCPStatistics | ConvertTo-JSon

I then place that script on my DHCP server and use a telegraf service to run it and send data to InfluxDB. That config is pretty straightforward, aside from all the normal configuration to send it off, I just setup inputs.exec:

  name_suffix = "_dhcp"
  commands = ['powershell c:\\GetDHCPStats.ps1']
  timeout = "60s"
  data_format = "json"
  tag_keys = ["Name"]

This is pretty easy, I tell it to expect JSON and the PowerShell was set up to output JSON. I also let it know that each record in the JSON will have one key labeled “Name” that will have the scope name in it. Honestly, this should probably be ScopeName and the PowerShell should be updated to reflect that as now my tags in InfluxDB are a bit polluted if anything else ever uses a tag of Name.

Once this is all done and configured, now my DHCP server is reporting statistics about our server into InfluxDB.

I then setup a graph in Grafana using this data. I just did a pretty straight forward graph that mapped each scopes percent of the total IPs that we use. It gives a nice easy way to see how the users on my network are moving around.  The source for the query ends up being something like:

SELECT mean("PercentOfTotal") FROM "exec_dhcp" WHERE ("Name" != 'Total') AND $timeFilter GROUP BY time($__interval), "Name" fill(linear)

This gives me a graph like the following (cropped to leave off some sensitive data):

DHCP Stats

Looks a little boring overall, but individual scope graphs can be kinda interesting and informative as to how the system in performing:


DHCP Stats1

This gives a fun view of one scope as devices join and then as lease are cleaned up, and new devices join again.

Hope this helps!