WinLLDPService

WinLLDPService is free, open source and tiny Windows service. It sends Windows’ machine network information via LLDP so that network administrators can find computers with ease. See also SNMP as it’s often used to gather more detailed information from network devices.

WinLLDPService acts only as an announcer to the switch (sends packets to the switch). It will not query switches’ internal LLDP data.

Possible errors are logged to Windows Event Log.

Report possible bugs and feature requests to issues page.

Requirements:

  • Capture library supported by Sharppcap for example:
  • Microsoft PowerShell

Download from GitHub

Github All Releases

Sources can be found at GitHub.

See GitHub Releases page for downloads if list above failed to load.

Install with Chocolatey

choco install winlldpservice

See chocolatey site for additional information.

Screenshots

Tested with

  • Windows Server 2012 R2
  • Windows 10 Professional edition 64 bit
  • Windows 7 Ultimate edition 64 bit with Service Pack 1
  • Windows 7 Professional edition 64 bit with Service Pack 1

Configuring

WinLLDPService uses PowerShell for it’s configuration. PowerShell was chosen so that system administrators can add only the needed information. You must set PowerShell execution policy accordingly. See About Execution Policies @ Microsoft. Recommended ExecutionPolicy is AllSigned. See Help about_signing for how to sign PowerShell scripts.

Search paths are:

  • $Env:APPDATA\WinLLDPService\
  • $Env:LOCALAPPDATA\WinLLDPService\
  • Registry: HKLM:Software\WinLLDPService InstallPath value.
  • Current directory of WinLLDPService.exe

These are translated to:

  • C:\WINDOWS\system32\config\systemprofile\AppData\Local\WinLLDPService\
  • C:\WINDOWS\system32\config\systemprofile\AppData\Roaming\WinLLDPService\
  • C:\Program Files\WinLLDPService\ (default install path x64)
  • C:\Program Files (x86)\WinLLDPService\ (default install path x86)

Filenames that are searched:

  • Configuration.ps1
  • Configuration.default.ps1

If Configuration.ps1 is not found then Configuration.default.ps1 is used.

The search is run once after service starts. To rescan paths simply restart the service.

The configuration file is run each time before packet is sent.

Example deployment

There are 10 machines. Every machine has $Env:LOCALAPPDATA\WinLLDPService\Configuration.default.ps1. Let’s say 3 are virtual machines. For those machines you could create $Env:LOCALAPPDATA\WinLLDPService\Configuration.ps1 which reports additional information.

Writing configuration

You can test the configuration generation from PowerShell by simply opening PowerShell prompt. This allows using Tab for code completion.

PS C:\Users\raspi> Add-Type -Path 'C:\Program Files\WinLLDPService\LLDPBase.dll'
PS C:\Users\raspi> $config = New-Object WinLLDPService.Configuration
PS C:\Users\raspi> $config

Separator         :  |
ChassisType       : MacAddress
PortDescription   : {}
SystemName        : HASTUR
SystemDescription : {}

PS C:\Users\raspi> $config.PortDescription.Add("test")
PS C:\Users\raspi> $config

Separator         :  |
ChassisType       : MacAddress
PortDescription   : {test}
SystemName        : HASTUR
SystemDescription : {}

PS C:\Users\raspi> $config.ToString()
WinLLDPService.Configuration
Chassis type: 'MacAddress'
System name: 'MYPC'
Port description: 'test'
System description: ''

Example configuration file

To make your own custom configuration simply copy the Configuration.default.ps1 to one of the directories mentioned above. Do not modify the installed Configuration.default.ps1 as it may change when new version is released.

For information how to get details about machine see PowerShell Documentation.

Example C:\WINDOWS\system32\config\systemprofile\AppData\Roaming\WinLLDPService\Configuration.ps1:

# Fetch system specific information

# -- Get Operating system name such as "Win 10 Pro"
$replaceTable = @{
    "Microsoft" = ""
    "Windows" = "Win"
    "Professional" = "Pro"
    "Ultimate" = "Ult"
    "Enterprise" = "Ent"
    "Edition" = "Ed"
    "Service Pack" = "SP"
}

$operatingsystem = (Get-WmiObject Caption -Class Win32_OperatingSystem | Select-Object -ExpandProperty Caption)
$replaceTable.GetEnumerator() | ForEach-Object {
    $operatingsystem = $operatingsystem -replace $_.Key, $_.Value
}

$operatingsystem = $operatingsystem.Trim()

# -- Get serial number
$serialnumber = (Get-WmiObject SerialNumber -Class Win32_bios | Select-Object -ExpandProperty SerialNumber)

# -- Get processor ID
$processorid = (Get-WmiObject ProcessorId -Class Win32_Processor | Select-Object -ExpandProperty ProcessorId)

# -- Get logged in user list (not recommended for LLDP, see SNMP)
$explorerprocesses = @(Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name='explorer.exe'" -ErrorAction SilentlyContinue)

$logged_in_users_list = @{}

if ($explorerprocesses.Count -ne 0)
{
    foreach ($i in $explorerprocesses)
    {
        $username = $i.GetOwner().User
        $domain = $i.GetOwner().Domain.ToLower()
        if(!$logged_in_users_list.ContainsKey($domain)) {
            $logged_in_users_list.Add($domain, $username)
        }
    }
}

# change to <domain>: user1, user2, ..
$logged_in_users_list = $logged_in_users_list | Sort-Object
$logged_in_users = ""
foreach($dom in $logged_in_users_list.KEYS.GetEnumerator()) {
  $logged_in_users += $dom + ": "
  foreach($user in $logged_in_users_list[$dom]) {
    $logged_in_users += $user + ", "
  }
}
$logged_in_users = $logged_in_users.Trim().TrimEnd(',')

# -- Get uptime (not recommended for LLDP, see SNMP)
$up = (Get-Date) - [Management.ManagementDateTimeConverter]::ToDateTime((Get-WmiObject LastBootUpTime -Class Win32_OperatingSystem).LastBootUpTime)
# change to XXXdXXhXXmXXs
$uptime = "{0:D3}d{1:D2}h{2:D2}m{3:D2}s" -f $up.Days, $up.Hours, $up.Minutes, $up.Seconds


# Initialize WinLLDPService.Configuration object
$config = New-Object WinLLDPService.Configuration

$config.PortDescription.Add("my new port descr..")

# Add operating system
$config.SystemDescription.Add("OS: " + $operatingsystem)

# Add serial number
$config.SystemDescription.Add("SN: " + $serialnumber)

# Add processor ID
$config.SystemDescription.Add("ID: " + $processorid)

# Add users logged in
$config.SystemDescription.Add("U: " + $logged_in_users_list)

# Add uptime
$config.SystemDescription.Add("Up: " + $uptime)

$config.SystemName.Add("my machine")
$config.Separator = "|"

# Must always return WinLLDPService.Configuration object
Return $config

It is recommended to use PowerShell modules and caching non-realtime information such as operating system name.

So the above script becomes something like this with modules:

Import-Module MyCustomModule
Import-Module MyCustomModuleOther

# Initialize WinLLDPService.Configuration object
$config = New-Object WinLLDPService.Configuration

$config.PortDescription.Add("my new port descr..")

# Add operating system
$config.SystemDescription.Add(Get-OperatingSystem)

# Add serial number
$config.SystemDescription.Add(Get-SerialNumber)

# Add processor ID
$config.SystemDescription.Add(Get-ProcessorId)

# Add users logged in
$config.SystemDescription.Add(Get-LoggedInUsers)

# Add uptime
$config.SystemDescription.Add(Get-Uptime)

$config.SystemName.Add("my machine")
$config.Separator = "|"

# Must always return WinLLDPService.Configuration object
Return $config

This way you can simply just update the module(s)/script(s) and keep the configuration file the same for all machines.