Home > DHCP, Powershell Scripts, Windows Server > Export DHCP leases to html using powershell

Export DHCP leases to html using powershell

So I was in a need of having the active leases in my DHCP server exported to an web (html) page:

On the surface this would not present a problem, however as there is only one way to read the DHCP leases, netsh.exe, and the output format of this app is somewhat … I also got the chance to to play with regular expressions (love those) and <string> –replace

Just so everyone can share the pain, this is the netsh command:

netsh dhcp server 1.1.1.1 scope 1.1.1.0 show clients 1

And this is the output:

Changed the current scope context to 1.1.1.0 scope.

Type : N - NONE, D - DHCP B - BOOTP, U - UNSPECIFIED, R - RESERVATION IP
============================================================================================
IP Address      - Subnet Mask    - Unique ID           - Lease Expires        -Type -Name   
============================================================================================

1.1.1.5     - 255.255.0.0    - 00-ff-ff-ff-ff-ff   -10/13/2009 12:33:16 AM  -D-  host01.domain.com
:::
::: Lot of lines here
:::
1.1.1.227   - 255.255.0.0    - 00-ff-ff-ff-ff-ff   -10/13/2009 12:42:06 AM  -D-  host10.domain.com

No of Clients(version 4): 355 in the Scope : 1.1.1.0.

Command completed successfully.

So is there any logic here? Double tabs, single tabs from which I can split? No. only spaces…. and hyphens.. and useless data

As I only needed the IP and hostnames in a html table, this is what I ended up with in powershell:

$a = (netsh dhcp server 1.1.1.1 scope 1.1.1.0 show clients 1)

$lines = @()
#start by looking for lines where there is both IP and MAC present:
foreach ($i in $a){
    if ($i -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){
        If ($i -match "[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}"){    
            $lines += $i.Trim()
        }
    }
}
$csvfile = @()
#Trim the lines for uneeded stuff, leaving only IP, Subnet mask and hostname.
foreach ($l in $lines){
    $Row = "" | select Hostname,IP
    $l = $l -replace '[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}', ''
    $l = $l -replace ' - ',','
    $l = $l -replace '\s{4,}',''
    $l = $l -replace '--','-'
    $l = $l -replace '-D-','-'
    $l = $l -replace '[-]{1}\d{2}[/]\d{2}[/]\d{4}',''
    $l = $l -replace '\d{1,2}[:]\d{2}[:]\d{2}',''
    $l = $l -replace 'AM',''
    $l = $l -replace 'PM',''
    $l = $l -replace '\s{1}',''
    $l = $l + "`n"
    $l = $l -replace '[,][-]',','
    $Row.IP = ($l.Split(","))[0]
    #Subnet mask not used, but maybe in a later version, so let's leave it in there:
    #$Row.SubNetMask = ($l.Split(","))[1]
    $Row.Hostname = ($l.Split(","))[2]
    $csvfile += $Row
}

#let create a csv file, in case we need i later..
$csvfile | sort-object Hostname | Export-Csv "Out_List.csv"

#Create the HTML formating
$a = "<style>"
$a = $a + "body {margin: 10px; width: 600px; font-family:arial; font-size: 12px;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 2px;border-style: solid;border-color: black;background-color: rgb(179,179,179);align='left';}"
$a = $a + "TD{border-width: 1px;padding: 2px;border-style: solid;border-color: black;background-color: white;}"
$a = $a + "</style>"

#And create HTML file...
Write-Host "Please contact theadmin@void.null for support" | Out-File "DHCPLeases.html"
$csvfile | sort-object Hostname | ConvertTo-HTML -head $a | Out-File -Append "DHCPLeases.html"

The resulting output, then looks like this:

HostName IP
host01.domain.com 1.1.1.5
host10.domain.com 1.1.1.227

which is what I wanted. Another great job by powershell.

I hope that this might prove useful to someone else, and a my thanks goes out to the powershell community and all the people who might recognize some of the code, no one mentioned, no one forgotten.

Please do drop a line if you have comments or suggestions to how the script could be optimized. Life is a learning curve and I love climbing 🙂

  1. Paul Murrin
    22/10/2009 at 04:19

    Hi, This is exactly what I have been looking for. I have been trying to expand this script to also export the MAC address and be able to deal with multiple scope’s. I am very new to PowerShell and don’t seam to be making any headway. Can you help.

  2. viktor
  3. Maik
    30/10/2009 at 11:56

    Hi, it’s the perfect solution but the hostnames are mixed with the leasing dates. I’m using windows server 2008 R2.

    • The Admin Guy
      09/11/2009 at 00:52

      Yes, I have noticed that as well. In my environment the script has always run on W2k8 R2 before without the dates in the hostname field. Now after running it for a period, I have seen the same. I suspect that it one the may -replace regular expressions is not working. Luckily W2k8 R2 comes with the powershell ISE, so that makes it breeze to modify in production 🙂

  4. Miles
    07/12/2010 at 18:14

    I was re purposing your code to shutdown all dhcp clients and found a bug. When you are parsing your text, you are missing an exception for dates with ONE digit in the date field.

    This results in hostnames like 12/9/2010-lab1.test.net

    I added $l = $l -replace ‘[-]{1}\d{2}[/]\d{1}[/]\d{4}’,”
    after $l = $l -replace ‘[-]{1}\d{2}[/]\d{2}[/]\d{4}’,”

    Just thought I’d let you know, and thanks again for the code!

  5. JD
    09/02/2011 at 23:19

    A much neater solution to get all the DHCP leases into an array is to just use the substring and count from the start of each line. This works because each line output from netsh is formatted. I use the below to turn netsh output into an array.

    
    $results = @()
    
    foreach ($l in $lines){
        $Row = "" | select IP, Subnet, MAC, Lease, Hostname
        $Row.IP = ($l.substring(0,16)).replace(" ","")
        $Row.subnet = ($l.substring(18,15)).replace(" ","")
        $Row.MAC = ($l.substring(35,20)).replace(" ","")
        $Row.Lease = [datetime]($l.substring(56,23))
        $Row.Hostname = ($l.substring(84)).replace(" ","")    
        $results += $Row
    }
    
  6. Joe
    07/11/2011 at 17:05

    Doesn’t work on non-MS DHCP?

    Unable to determine the DHCP Server version for the Server xxx.xxx.xxx.xxx.
    Server may not function properly.

    • The Admin Guy
      08/11/2011 at 18:52

      The script relies on netsh.exe. I have not tested it, but I would assume that it would yield the same result as you have – error. However the netsh command is also only required because the DHCP leases are stored in an Jet DB, which cannot be directly accessed when the server is running. Again, I have not tested it, but I would think that the lease file for a *nix type DHCP server would be readable while the server is running.

  7. 26/03/2012 at 21:50

    I need mac address as well!
    How do I modify this script to get that?
    I know this is cheap just demanding an answer, but I’m rushing this.
    Any help would be appreciated!

    • The Admin Guy
      27/03/2012 at 00:37

      Hi Oliver
      Please see the updated script for your request

      Let me know if you have suggestions or comments.

      /Anders

  8. 13/10/2012 at 11:36

    Very nice post. I just stumbled upon your weblog and wished to say that I’ve really enjoyed surfing around your blog posts. In any case I’ll be
    subscribing to your feed and I hope you write again very soon!

  9. Rob K.
    12/02/2013 at 16:23

    A great post! Thank you.

    I turned this into a function that uses [RegEx]::Split to parse the leases into object properties then return the objects which can be piped to other cmdlets like select-object and convertto-html.

    function Get-DhcpLease{

    $leases = invoke-command -scriptblock {netsh dhcp server 1.1.1.1 scope 1.1.1.0 show clients 1} -ComputerName dhcpserver

    $headings = $leases[5].split(‘-‘)

    for ($i = 8; $i -lt ($leases.Count – 4) ;$i++){
    $props = @{}
    $vals = [RegEx]::Split($leases[$i],’\s{1}-|-\s{1}’)
    $props[$headings[0].Trim()] = $vals[0].Trim()
    $props[$headings[1].Trim()] = $vals[1].Trim()
    $props[$headings[2].Trim()] = $vals[2].Trim()
    $props[$headings[3].Trim()] = $vals[3].Trim()
    $props[$headings[4].Trim()] = $vals[4].Trim()
    if( $vals[5] -ne $null){
    $props[$headings[5].Trim()] = $vals[5].Trim()
    }else{
    $props[$headings[5].Trim()] = ”
    }

    $lease = New-Object -TypeName PSObject -Property $props
    write-output $lease
    }
    }

    Get-DhcpLease|select-object Name,’IP Address’|ConvertTo-Html

  10. 26/01/2014 at 11:52

    Can you help me …. I have a question… I want to get the mac & ip &hostname…
    But now i just got the hostname & ip… Please Help me … thanks u so much^^

  11. 05/03/2014 at 03:46

    First off I would like to say awesome blog! I had a quick question that I’d like
    to ask if you do not mind. I was interested to know how you center yourself and clear your
    mind before writing. I’ve had difficulty clearing my thoughts in getting my thoughts out.
    I truly do take pleasure in writing however it just seems like the
    first 10 to 15 minutes are wasted simply just trying to figure out how to begin.
    Any recommendations or hints? Many thanks!

  12. 30/07/2014 at 21:15

    If you have 2012 you can use this:
    Get-DhcpServerv4Scope -ComputerName $DHCPServer | Get-DhcpServerv4Lease -ComputerName $DHCPServer | Export-Csv -Path $LogPath

  13. 26/05/2015 at 23:50

    How about expanding this to retrieve a lease list from multiple dhcp servers AND scopes?

  1. 25/07/2011 at 09:32
  2. 05/09/2012 at 21:43
  3. 07/09/2012 at 12:44
  4. 12/09/2012 at 23:40
  5. 05/05/2013 at 21:24

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s

%d bloggers like this: