Subnet Monitoring Events

To access subnet monitoring events:

  1. On the Admin page, select Configuration in the upper-left corner.

  2. Select Event Hooks in the filtering sidebar.

Enabling Subnet Monitoring

Subnet monitoring is enabled in the System Settings. Click the Settings button in the upper-right corner to go to the System Settings where you can enable subnet monitoring in the system and configure email notifications.

When enabled, the system monitors the free addresses in DHCP address pools and subnets and acts if the number of free addresses goes below a user-definable threshold.

When subnet monitoring is enabled, a new column, Monitoring, is added when viewing the subnet list. To filter the view by this column and quickly see all subnets that are monitored, you can enter “Monitor: Yes” in the Quick Filter search box.

SMTP Server

The mail server from which notification emails will be sent when the number of addresses goes below a certain threshold.

Mail from

The email address from which notification emails will be sent when the number of addresses goes below a certain threshold.

Subnet Monitoring Defaults

The Subnet monitoring events section lists the current defaults. To change the default values, click Set Defaults and make the desired changes in the dialog box.


When selected, all subnets are monitored by default. If you only want to monitor a subset of the subnets in the system, clear the checkbox and enable monitoring for the individual subnets instead by selecting the subnet on the IPAM page, and then selecting Set subnet monitoring on the Action menu.

Script to invoke

Select the script to run when the number of free addresses goes below the set threshold.

Email address

The email address that should be the recipient of notification when the number of free addresses goes below the set threshold.

Dynamic threshold

Enter the threshold for the free addresses in a DHCP scope address pool.


For split scopes and scopes in a superscope (on MS DHCP servers) and address pools using the shared-network feature on ISC DHCP servers, the total number of free addresses in all of the scope instances is used when calculating the number of free addresses.

Static threshold

Enter the threshold for the free addresses in a subnet.

Only perform action once (until resolved)

When selected, the action is performed only once when the number of free addresses goes below the threshold.

Perform action when resolved

When selected, the action is performed when the number of free addresses is no longer below the threshold.


The global subnet monitoring setting can be overridden for individual subnets by changing the setting explicitly for the subnet. For information on how to change monitoring settings for individual subnets, see IPAM, Set Subnet Monitoring.

Subnet Monitoring Script Interface

The XML schema for a subnet monitoring script is as follows:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema targetNamespace="" elementFormDefault="qualified" xmlns="" xmlns:mstns="" xmlns:xs="">
<xs:element name="scopeMonitor">
<xs:element name="scope" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="server" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="superscope" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="threshold" type="xs:integer" minOccurs="1" maxOccurs="1" />
<xs:element name="available" type="xs:integer" minOccurs="1" maxOccurs="1" />
<xs:element name="fixed" type="xs:boolean" minOccurs="1" maxOccurs="1" />
<xs:element name="thresholdType" type="xs:string" minOccurs="1" maxOccurs="1" />

The value of the thresholdType element will be either static or dynamic depending on whether the threshold being crossed is one of the dynamically allocatable addresses (that is, available addresses in address pools) or if it is a threshold set for static addresses (that is, available addresses outside of address pools).


The global subnet monitor, set through the System Settings, is the only one that takes superscopes into account. When the global subnet monitor actions are performed, due to the conditions being met for a superscope, the XML generated will contain a <server> tag and a <superscope> tag.

An example XML structure for a subnet monitoring script might look as follows for scope:

<?xml version="1.0" encoding="ISO-8859-1"?>
<customField customFieldID="1" customFieldName="Title" objectID="526" objectType="6" value="Your subnet title"></customField>
<customField customFieldID="2" customFieldName="Description" objectID="526" objectType="6" value="You subnet description"></customField>

The XML structure is slightly different if a superscope (MS DHCP) or a shared-network (ISC DHCP) configuration is used. An example XML structure for a scope monitoring script might look as follows for a superscope / shared-network configuration:

<?xml version="1.0" encoding="ISO-8859-1"?>

A subnet monitoring script does not have any return value.

Example PowerShell Script


Powershell scripts (.ps1 extension) are run natively by Men&Mice on Windows with powershell. The script can then read the stdin with [Console]::In.ReadToEnd().


  1. Copy the ScopeMonScript.ps1 to C:\\ProgramData\\Men and Mice\\Central\scripts (the scripts folder).

  2. In Admin > Configuration > Event Hooks, under Subnet monitoring events, click Set Defaults.

  3. Select ScopeMonScript.ps1 in the Script to invoke field.

  4. Configure a dynamic threshold.

The monitor will be executed every 10 minutes during the DHCP synchronization interval.

param([Parameter(Mandatory=$false,ValueFromPipeLine=$false)]$UserName = "",
[Parameter(Mandatory=$false,ValueFromPipeLine=$false)]$Password = "",
[Parameter(Mandatory=$false,ValueFromPipeLine=$false)]$xmlFileName = "")
$strInput = get-content $xmlFileName
#$strInput = $args
# write output for troubleshooting in file:
#Add-Content -Path .\monitoroutput.xml $strInput

$strXML = [string]::Join(" ", $strInput)
$objXML = [xml]$strXML
$subnetMonitor = (Select-Xml -XML $objXML -XPath "/subnetMonitor").Node

# Check if it's an alert or fixed message
# The script only cares about alerts
if ($subnetMonitor.fixed -eq "0")
    $strAlert = "Alert:  The following scope or subnet has fewer IPs available than the configured threshold."

    # We could send here an email or generate a trap or...
    #Send-MailMessage -SmtpServer "" -From "[email protected]" -To "[email protected];[email protected]" -Subject "Subnet Monitor Message" -Body $strOutput

    # First handle the superscopes
    if ($subnetMonitor.superscope -ne $null -and $subnetMonitor.superscope -ne "")
    $strOutput = @"

    Superscope: $($subnetMonitor.superscope)
    Alert Date:    $(Get-Date -Format G)
    Server:        $($subnetMonitor.server)
    Threshold:    $($subnetMonitor.threshold)
    IPs Available:    $($subnetMonitor.available)
    Subnet Type:    $($subnetMonitor.thresholdType)
        New-EventLog -Source SubnetMonitor -LogName Application
        Write-EventLog -LogName Application -Source SubnetMonitor -EventID 1063 -EntryType Warning -message "$strOutput"
        #Add-Content -Path .\superscopemonitor_msg.txt $strOutput
    # then in the else clause the normal scopes

    $strOutput = @"

      Alert Date:    $(Get-Date -Format G)
      Scope:        $($subnetMonitor.subnet)
      Threshold:    $($subnetMonitor.threshold)
      IPs Available:    $($subnetMonitor.available)
      Subnet Type:    $($subnetMonitor.thresholdType)
        New-EventLog -Source SubnetMonitor -LogName Application
        Write-EventLog -LogName Application -Source SubnetMonitor -EventID 1064 -EntryType Warning -message "$strOutput"
        #Add-Content -Path .\scopemonitor_msg.txt $strOutput
  # possible issue fixed message

Example Python Script

The following example script, written in Python, shows how a script could return different values depending on the input of custom fields. The script is called when an object property changes and it queries for country and city using a location code. The intended use here is to mark the locations of servers.

import sys
import xml.etree.ElementTree as ET

def get_custom_field_element(custom_fields, name):
 element = custom_fields.find(f"./customField[@customFieldName='{name}']")
 if element is None:
     raise KeyError(f"Custom property '{name}' was not found.")
 return element

def get_result(root):
 # username variable is not used but this is how to get the username
 username = root.get('userName')
 custom_fields = root.find("./customFields")

 result = ET.Element("result", {"success": "0"})
     location_element = get_custom_field_element(custom_fields, 'Location')
     country_element = get_custom_field_element(custom_fields, 'Country')
     city_element = get_custom_field_element(custom_fields, 'City')
 except KeyError as e:
     ET.SubElement(result, "error", {"code": "1", "message": str(e)})
     return result
 location = location_element.get('value')

 # A database could be queried instead here
     'l1': ('USA', 'Washington'),
     'l2': ('UK', 'London')
 if location not in LOCATION_MAP:
     ET.SubElement(result, "error", {"code": "1", "message": "Unknown location."})
     return result

 result.set("success", "1")
 country, city = LOCATION_MAP[location]
 country_element.set('value', country)
 city_element.set('value', city)
 return result

# Read all input and parse as XML
root = ET.fromstring(
result = get_result(root)

print('<?xml version="1.0"?>')
# This will write the generated result xml to standard output