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.


Prerequisites

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.


Code

GitHub

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 = "
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
<title>DHCP Report</title>
<STYLE TYPE='text/css'>
</style>
</head>
<body>
<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>
</tr>
</table>
<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>
</tr>
</table>
<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>
    </tr>
</table>
"
$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>
            $htmlbgcolor
            <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>
            $htmlScopeState
            <td width='8%' align='center'>$($DHCP_Scope_Stats.InUse)</td>
            <td width='8%' align='center'>$($DHCP_Scope_Stats.Free)</td>
            $htmlpercentinuse
            <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>
            </tr>
        </table>
        "
        $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:

Leave a Reply

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

WordPress.com Logo

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

Google photo

You are commenting using your Google 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