Generate a DHCP Report Via PowerShell

Today we are going to look at how to generate a DHCP scope statistics HTML report by using PowerShell. This report will give you one location to see all of your DHCP scope statistics across all of your Windows DHCP servers. It will dynamically pull the DHCP servers and associated DHCP scopes within your Active Directory domain. This report will help you keep an eye on the usage of all of your DHCP scopes so you can prevent scopes from filling up. With this PowerShell script there is no need to import a list of DHCP servers or hard code them in a variable. I recommend setting this up as a recurring scheduled task so that the report runs without the need for manual intervention.


There are a few things needed in order to generate this report. The most obvious is the need for an Active Directory domain with at least one Windows DHCP server and one DHCP scope. If you plan on running this script from your DHCP server (I do not recommend), then you will already have the PowerShell modules needed. If you are going to utilize a dedicated server or desktop to run the report, then you will need to install the RSAT DHCP Server Tools. RSAT is now included directly from within Windows 10. In order to get it installed, search for “Manage optional features” from the start menu and then click on “Add a feature”. Check the box for “RSAT: DHCP Server Tools” and click “Install”. Once it’s finished installing, the DHCP PowerShell commands found in the script will run.



Let’s jump into the script that will generate the report. First, we need to specify where the HTML file will be written to. You can specify a UNC path or a local directory. In this example, I have a final HTML and a temporary HTML file, because I don’t want someone to view the final HTML file until it is completely finished. At the end of this script it will rename the temporary HTML to the final HTML.

$htmlfile = "\\server\full\path\to\file.html" ### The full path to the final HTML file
$htmlfile_temp = "\\server\full\path\to\file_temp.html" ### The full path to the temporary HTML file

### Checking to see if the temp file exists, if it does it will remove it
If (Test-Path $htmlfile_temp) { Remove-Item $htmlfile_temp -Force }

Now we will put together the HTML header and the columns for the table that will hold all the DHCP scope statistics. All of this will be written to the temporary HTML file.

$html_header = "
<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
<title>DHCP Report</title>
<STYLE TYPE='text/css'>
<table-layout: fixed>
<table width='100%'>
<tr bgcolor='#00B624'>
<td colspan='7' height='25' align='center'><strong><font color='#000000' size='4' face='tahoma'>DHCP Scope Statistics Report</font><font color='#000000' size='4' face='tahoma'> ($(Get-Date))</font><font color='#000000' size='2' face='tahoma'> <BR> Data Updates Every Day</font>
<table width='100%'>
<tr bgcolor='#CCCCCC'>
<td colspan='7' height='20' align='center'><strong><font color='#000000' size='2' face='tahoma'><span style=background-color:#FFF284>WARNING</span> at 80% In Use      <span style=background-color:#FF0000><font color=white>CRITICAL</font></span> at 95% In Use</font>
<table width='100%'><tbody>
    <tr bgcolor=black>
    <td width='10%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >DHCP Server</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >Scope ID</font></strong></td>
    <td width='10%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >Scope name</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >Scope State</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >In Use</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >Free</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >% In Use</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >Reserved</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >Subnet Mask</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >Start of Range</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >End of Range</font></strong></td>
    <td width='8%' height='15' align='center'> <strong> <font color='white' size='2' face='tahoma' >Lease Duration</font></strong></td>
$html_header | Out-File $htmlfile_temp ### Writing the HTML header to the temporary file

Next we will go into the DHCP PowerShell commands to gather the data for the report. The below code will dynamically pull all of the DHCP servers and their associated scopes for the Active Directory domain you are running the script from. There is no need to make any manual modifications of server or scope names. The percent used per scope will determine what color the “% In Use” cell is in the report. All of these thresholds can be modified to fit your environment, but here is what is configured in this example:

  • Greater than 95 percent used will result in a red cell color.
  • Greater than 80 percent used but less than 95 percent will result in a yellow cell color.
  • Less than 80 percent used will result in a green cell color.
$DHCP_Servers = Get-DhcpServerInDC | ForEach-Object {$_.DnsName} | Sort-Object -Property DnsName ### Dynamically pulling the DHCP servers in a Active Directory domain
Foreach ($DHCP_Server in $DHCP_Servers){ ### Going through the DHCP servers that were returned one at a time to pull statistics
    $DHCP_Scopes = Get-DhcpServerv4Scope –ComputerName $DHCP_Server | Select-Object ScopeId, Name, SubnetMask, StartRange, EndRange, LeaseDuration, State ### Getting all the dhcp scopes for the given server
    Foreach ($DHCP_Scope in $DHCP_Scopes){ ### Going through the scopes returned in a given server
        $DHCP_Scope_Stats = Get-DhcpServerv4ScopeStatistics -ComputerName $DHCP_Server -ScopeId $DHCP_Scope.ScopeId | Select-Object Free, InUse, Reserved, PercentageInUse, ScopeId ### Gathering the scope stats
        $percentinuserounded = ([math]::Round($DHCP_Scope_Stats.PercentageInUse,0)) ### Rounding the percent in use to have no decimals
        ### Color formatting based on how much a scope is in use
        If ($percentinuserounded -ge 95){$htmlpercentinuse = '<td width="8%" align="center" td bgcolor="#FF0000"> <font color="white">' + $percentinuserounded + '</font></td>'}
        If ($percentinuserounded -ge 80 -and $percentinuserounded -lt 95){$htmlpercentinuse = '<td width="8%" align="center" td bgcolor="#FFF284"> <font color="black">' + $percentinuserounded + '</font></td>'}
        If ($percentinuserounded -lt 80){$htmlpercentinuse = '<td width="8%" align="center" td bgcolor="#A6CAA9"> <font color="black">' + $percentinuserounded + '</font></td>'}
        ### Changing the cell color if the scope is inactive / active
        If ($DHCP_Scope.State -eq "Inactive"){$htmlScopeState = '<td width="8%" align="center" td bgcolor="#AAAAB2"> <font color="black">' + $DHCP_Scope.State  + '</font></td>'}
        If ($DHCP_Scope.State -eq "Active"){$htmlScopeState = '<td width="8%" align="center">' + $DHCP_Scope.State + '</td>'}
        ### Changing the background color on every other scope so the html is easy to read
        $htmlwrite_count | ForEach-Object {if($_ % 2 -eq 0 ) {$htmlbgcolor = '<tr bgcolor=#F5F5F5>'} } ## Even Number (off-white)
        $htmlwrite_count | ForEach-Object {if($_ % 2 -eq 1 ) {$htmlbgcolor = '<tr bgcolor=#CCCCCC>'} } ## Odd Number (gray)
        #### Creating the HTML row for the given DHCP scope with the detailed stats and information
        $current = "
        <table width='100%'><tbody>
            <td width='10%' align='center'>$($DHCP_Server.TrimEnd(".local.domain"))</td>
            <td width='8%' align='center'>$($DHCP_Scope.ScopeId)</td>
            <td width='10%' align='center'>$($DHCP_Scope.Name)</td>
            <td width='8%' align='center'>$($DHCP_Scope_Stats.InUse)</td>
            <td width='8%' align='center'>$($DHCP_Scope_Stats.Free)</td>
            <td width='8%' align='center'>$($DHCP_Scope_Stats.Reserved)</td>
            <td width='8%' align='center'>$($DHCP_Scope.SubnetMask)</td>
            <td width='8%' align='center'>$($DHCP_Scope.StartRange)</td>
            <td width='8%' align='center'>$($DHCP_Scope.EndRange)</td>
            <td width='8%' align='center'>$($DHCP_Scope.LeaseDuration)</td>
        $current  | Out-File $htmlfile_temp -Append ### Appending the HTML row to the tempory file

        $htmlwrite_count++ ### Incrementing the count by 1 so that the next HTML row is a different color
        Clear-Variable htmlScopeState, htmlpercentinuse, percentinuserounded, DHCP_Scope_Stats -ErrorAction SilentlyContinue
Clear-Variable htmlwrite_count

Finally, we will delete the final HTML file and rename the temporary HTML file to the final HTML file name.

If (Test-Path $htmlfile) { Remove-Item $htmlfile -Force } ### Removing the final html file if it exists
Rename-Item $htmlfile_temp $htmlfile -Force ### Renaming the temp file to the final file

That’s it for now, thanks for reading!

Check out my other blog posts:

Media Sync: Organize Your Photos and Videos with PowerShell

Do you have photos and videos that you have taken over the years that are scattered all over the place? Do you want to have all your photos and videos organized? Do you want all your photos and videos to have a standardized naming scheme? If you answered YES to these questions, then this is…

NetNeighbor Watch: The PowerShell Alternative To Arpwatch

In this post, we are going to setup NetNeighbor Watch on a Raspberry Pi. NetNeighbor Watch can keep an eye on your network and send you an email when a new host is discovered. NetNeighbor Watch is done completely in PowerShell. The results are very similar to those of arpwatch. NetNeighbor Watch is for anyone…

Generate a Citrix Desktop Report Based on Active Directory Users

In this post, we are going to merge data from two different sources to generate a report that can provide insight into your Citrix environment. I will show you how to combine Active Directory data for the users in your domain with Citrix data. This report will provide you with the following knowledge: Users that…

Creating a PowerShell Module to Improve Your Code

Do you have PowerShell code that you reuse in your scripts over and over? Do you have server names hard coded in variables? Are you using a text file or CSV file to import server names? Do you find yourself only utilizing one server out of a cluster of servers to make your PowerShell commands?…

Increase VMware VM Disk Size with PowerShell

In this post, I will cover how to use PowerShell to increase the disk size of a Windows 10 VM running in a VMware vCenter environment. Automating simple but time consuming tasks like this can save precious time for your support staff or yourself. There are two parts to accomplishing this task; first we need…

Manage Citrix Tags with PowerShell

In this post, we are going to cover how to manage Citrix tags with PowerShell. Citrix Studio is a great tool, but it can be very time consuming especially if you have to do bulk tag actions. Citrix tags can be used in several methods, but this post is focused on desktop tagging. This post…

Create a Text Box to Accept User Input for PowerShell GUI

Do you have a PowerShell GUI that needs to accept text input? Maybe you want to be able to copy and paste a list of computers, ip addresses, user names or some other data. I will show you how to add a text box into your PowerShell GUI to handle that input. If you haven’t…

Utilizing PowerShell Out-GridView as a GUI Alternative

In my previous post, I showed how you can build a simple menu driven PowerShell GUI; check it out here. To further improve upon that simple GUI, we will go over how to use Out-GridView. Out-GridView is a built-in powershell cmdlet that sends the output from a given command to an interactive window. This post…

How to Create a Simple PowerShell GUI

Have you ever wanted to create a menu driven PowerShell GUI to conduct a series of automated tasks? You are in luck, because that is exactly what we are going to cover in this post. This very simple PowerShell GUI will help you easily distribute your code to other team members or maybe you just…

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s