# encoding: ascii
# api: csharp
# title: List DHCP Clients
# description: Function to list all clients in a Microsoft DHCP server database. The script Uses P/Invoke function signatures, structs & ports the DhcpEnumSubnetClients() C# code example to PowerShell from PInvoke.net. There is no other (nice!) way to get this information in an object form, other than scraping the output from netsh.exe.
# version: 0.1
# type: function
# author: christian bellee
# license: CC0
# x-poshcode-id: 1477
# x-archived: 2017-04-14T01:41:25
# x-published: 2010-11-19T19:33:00
#
#
$DHCP_EnumSubnetClients = @'
[DllImport("dhcpsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint DhcpEnumSubnetClients(
string ServerIpAddress,
uint SubnetAddress,
ref uint ResumeHandle,
uint PreferredMaximum,
out IntPtr ClientInfo,
ref uint ElementsRead,
ref uint ElementsTotal);
'@
$DHCP_Structs = @'
namespace mystruct {
using System;
using System.Runtime.InteropServices;
public struct CUSTOM_CLIENT_INFO
{
public string ClientName;
public string IpAddress;
public string MacAddress;
}
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_CLIENT_INFO_ARRAY
{
public uint NumElements;
public IntPtr Clients;
}
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_CLIENT_UID
{
public uint DataLength;
public IntPtr Data;
}
[StructLayout(LayoutKind.Sequential)]
public struct DATE_TIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
public DateTime Convert()
{
if (dwHighDateTime== 0 && dwLowDateTime == 0)
{
return DateTime.MinValue;
}
if (dwHighDateTime == int.MaxValue && dwLowDateTime == UInt32.MaxValue)
{
return DateTime.MaxValue;
}
return DateTime.FromFileTime((((long) dwHighDateTime) << 32) | (UInt32) dwLowDateTime);
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DHCP_HOST_INFO
{
public uint IpAddress;
public string NetBiosName;
public string HostName;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DHCP_CLIENT_INFO
{
public uint ClientIpAddress;
public uint SubnetMask;
public DHCP_CLIENT_UID ClientHardwareAddress;
[MarshalAs(UnmanagedType.LPWStr)]
public string ClientName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ClientComment;
public DATE_TIME ClientLeaseExpires;
public DHCP_HOST_INFO OwnerHost;
}
}
'@
$resumeHandle = 0
$clientInfo = 0
$ElementsRead = 0
$ElementsTotal = 0
Add-Type $DHCP_Structs
Add-Type -MemberDefinition $DHCP_EnumSubnetClients -Name GetDHCPInfo -Namespace Win32DHCP
$DHCPServerIP = "192.168.1.100" # change this to match your DHCP server IP
[void][Win32DHCP.GetDHCPInfo]::DhcpEnumSubnetClients($DHCPServerIP,0,[ref]$resumeHandle,0,[ref]$clientInfo,[ref]$ElementsRead,[ref]$ElementsTotal)
$clients = [system.runtime.interopservices.marshal]::PtrToStructure($clientInfo,[mystruct.DHCP_CLIENT_INFO_ARRAY])
[int]$size = $clients.NumElements
[int]$current = $clients.Clients
$ptr_array = new-object system.intptr[]($size)
$current = new-object system.intptr($current)
for ($i=0;$i -lt $size;$i++)
{
$ptr_array[$i] = [system.runtime.interopservices.marshal]::ReadIntPtr($current)
$current = $current + [system.runtime.interopservices.marshal]::SizeOf([system.IntPtr])
}
function uIntToIP {
param ($intIP)
$objIP = new-object system.net.ipaddress($intIP)
$arrIP = $objIP.IPAddressToString.split(".")
return $arrIP[3] + "." + $arrIP[2] + "." + $arrIP[1] + "." + $arrIP[0]
}
[array]$clients_array = new-object mystruct.CUSTOM_CLIENT_INFO
for ($i=0;$i -lt $size;$i++)
{
$objDHCPInfo = New-Object psobject
$current_element = [system.runtime.interopservices.marshal]::PtrToStructure($ptr_array[$i],[mystruct.DHCP_CLIENT_INFO])
add-member -inputobject $objDHCPInfo -memberType noteproperty -name ClientIP -value $(uIntToIP $current_element.ClientIpAddress)
add-member -inputobject $objDHCPInfo -memberType noteproperty -name ClientName -value $current_element.ClientName
add-member -inputobject $objDHCPInfo -memberType noteproperty -name OwnerIP -value $(uIntToIP $current_element.Ownerhost.IpAddress)
add-member -inputobject $objDHCPInfo -memberType noteproperty -name OwnerName -value $current_element.Ownerhost.NetBiosName
add-member -inputobject $objDHCPInfo -memberType noteproperty -name SubnetMask -value $(uIntToIP $current_element.SubnetMask)
add-member -inputobject $objDHCPInfo -memberType noteproperty -name LeaseExpires -value $current_element.ClientLeaseExpires.Convert()
$mac = [System.String]::Format(
"{0:x2}-{1:x2}-{2:x2}-{3:x2}-{4:x2}-{5:x2}",
[system.runtime.interopservices.marshal]::ReadByte($current_element.ClientHardwareAddress.Data),
[system.runtime.interopservices.marshal]::ReadByte($current_element.ClientHardwareAddress.Data, 1),
[system.runtime.interopservices.marshal]::ReadByte($current_element.ClientHardwareAddress.Data, 2),
[system.runtime.interopservices.marshal]::ReadByte($current_element.ClientHardwareAddress.Data, 3),
[system.runtime.interopservices.marshal]::ReadByte($current_element.ClientHardwareAddress.Data, 4),
[system.runtime.interopservices.marshal]::ReadByte($current_element.ClientHardwareAddress.Data, 5)
)
add-member -inputobject $objDHCPInfo -memberType noteproperty -name MacAddress -value $mac
$objDHCPInfo
}