DHCP Server 2000 - Scope Monitoring

DHCP_Server_2000___Scope_Monitoring (WriteActionModuleType)

Element properties:

TypeWriteActionModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
InputTypeSystem.BaseData
Comment{8471D03C-EF3F-435B-8282-1D2EC382B873}

Member Modules:

ID Module Type TypeId RunAs 
RunScriptAction WriteAction System.Mom.BackwardCompatibility.ScriptResponse Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
ExcludeScopesstring$Config/Parameters/ExcludeScopes$ExcludeScopesSemicolon delimited list of scopes to exclude from address alerting. The * may be used as a wildcard.
IncludeScopesstring$Config/Parameters/IncludeScopes$IncludeScopesSemicolon delimited list of scopes to include in address alerting. The * may be used as a wildcard.

Source Code:

<WriteActionModuleType ID="DHCP_Server_2000___Scope_Monitoring" Accessibility="Internal" Comment="{8471D03C-EF3F-435B-8282-1D2EC382B873}">
<Configuration>
<IncludeSchemaTypes>
<SchemaType>MomBackwardCompatibility!System.Mom.BackwardCompatibility.AlertGenerationSchema</SchemaType>
</IncludeSchemaTypes>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="AlertGeneration" type="AlertGenerationType"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="InvokerType" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Parameters" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ExcludeScopes" type="xsd:string" minOccurs="0"/>
<xsd:element name="IncludeScopes" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="ExcludeScopes" Selector="$Config/Parameters/ExcludeScopes$" ParameterType="string"/>
<OverrideableParameter ID="IncludeScopes" Selector="$Config/Parameters/IncludeScopes$" ParameterType="string"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<WriteAction ID="RunScriptAction" TypeID="MomBackwardCompatibility!System.Mom.BackwardCompatibility.ScriptResponse">
<AlertGeneration>$Config/AlertGeneration$</AlertGeneration>
<InvokerType>$Config/InvokerType$</InvokerType>
<Body><Script>
'-------------------------------------------------------------------
' &lt;company&gt;Microsoft Corporation&lt;/company&gt;
' &lt;copyright&gt;Copyright (c) Microsoft Corporation. All rights reserved.&lt;/copyright&gt;
' &lt;name&gt;
' DHCP Server 2000 - Scope Monitoring
' &lt;/name&gt;
' &lt;summary&gt;
'
' &lt;/summary&gt;
'-------------------------------------------------------------------

Option Explicit

Function GetSubMatches(ByVal aRegexes, ByVal sText, ByRef sRemainingText, ByRef aCapturedSubMatches)
Dim oRegex
Set oRegex = New RegExp
oRegex.Global = False
Dim oMatches
Dim oMatch
Dim sPattern
Dim aSubMatches()
aCapturedSubMatches = aSubMatches
GetSubMatches = False
Dim i
Dim lSubMatchCount
lSubMatchCount = 0
sRemainingText = sText
For i = 0 To UBound(aRegexes)
sPattern = aRegexes(i)
oRegex.Pattern = "^" &amp; sPattern
Set oMatches = oRegex.Execute(sRemainingText)
If oMatches.Count &lt;&gt; 1 Then
sRemainingText = sText
Exit Function
End If
Set oMatch = oMatches(0)
sRemainingText = Mid(sRemainingText, oMatch.Length + 1)
If i Mod 2 = 1 Then
lSubMatchCount = lSubMatchCount + 1
ReDim Preserve aSubMatches(lSubMatchCount - 1)
aSubMatches(lSubMatchCount - 1) = oMatch.Value
End If
Next

GetSubMatches = True
aCapturedSubMatches = aSubMatches
End Function



Function GenerateGUID()
Dim oTypeLib
Set oTypeLib = MomCreateObject("Scriptlet.TypeLib")

Dim sNewGUID
sNewGUID = oTypeLib.Guid

GenerateGUID = Left(sNewGUID, Len(sNewGUID)-2)
End Function


Function IsValidObject(ByVal oObject)
IsValidObject = False

If IsObject(oObject) Then
If Not oObject Is Nothing Then
IsValidObject = True
End If
End If
End Function


Sub RunCommand (ByVal sCommand, ByRef iErrCode, ByRef sOutput, ByRef sError)

Dim oShell, oFSO, oOut

Set oShell = MomCreateObject("WScript.Shell")
Set oFSO = MomCreateObject("Scripting.FileSystemObject")

sError = ""
sOutput = ""
Dim sOutputFileName
sOutputFileName = GenerateGUID() &amp; ".out"
Dim sErrorFileName
sErrorFileName = GenerateGUID() &amp; ".err"
Dim sFullCommand
sFullCommand = "cmd /c " &amp; sCommand &amp; " &gt; " &amp; sOutputFileName &amp; " 2&gt; " &amp; sErrorFileName
iErrCode = oShell.run(sFullCommand, 2, true)
On Error Resume Next
Set oOut = oFSO.OpenTextFile(sOutputFileName)
On Error Goto 0
If IsValidObject(oOut) Then
On Error Resume Next
sOutput = oOut.ReadAll()
On Error Goto 0
oOut.Close
Else
ThrowScriptError "Could not write to the folder [" &amp; oFSO.GetAbsolutePathName(".") &amp; "]. Make sure the action account has " &amp; _
"write access to this folder.", _
Err
End If
On Error Resume Next
oFSO.DeleteFile sOutputFileName
On Error Goto 0
If iErrCode &lt;&gt; 0 Then
Dim oErrorFile
On Error Resume Next
Set oErrorFile = oFSO.OpenTextFile(sErrorFileName)
On Error Goto 0
If IsValidObject(oErrorFile) Then
On Error Resume Next
sError = oErrorFile.ReadAll()
On Error Goto 0
oErrorFile.Close
End If
If sError = "" Then sError = sOutput
End If
On Error Resume Next
oFSO.DeleteFile sErrorFileName
On Error Goto 0
End Sub


Class Error
Private m_lNumber
Private m_sSource
Private m_sDescription
Private m_sHelpContext
Private m_sHelpFile
Public Sub Save()
m_lNumber = Err.number
m_sSource = Err.Source
m_sDescription = Err.Description
m_sHelpContext = Err.HelpContext
m_sHelpFile = Err.helpfile
End Sub
Public Sub Raise()
Err.Raise m_lNumber, m_sSource, m_sDescription, m_sHelpFile, m_sHelpContext
End Sub
Public Sub Clear()
m_lNumber = 0
m_sSource = ""
m_sDescription = ""
m_sHelpContext = ""
m_sHelpFile = ""
End Sub
Public Default Property Get Number()
Number = m_lNumber
End Property
Public Property Get Source()
Source = m_sSource
End Property
Public Property Get Description()
Description = m_sDescription
End Property
Public Property Get HelpContext()
HelpContext = m_sHelpContext
End Property
Public Property Get HelpFile()
HelpFile = m_sHelpFile
End Property
End Class

Function MomCreateObject(ByVal sProgramId)
Dim oError
Set oError = New Error

On Error Resume Next
Set MomCreateObject = CreateObject(sProgramId)
oError.Save
On Error Goto 0

If oError.Number &lt;&gt; 0 Then ThrowScriptError "Unable to create automation object '" &amp; sProgramId &amp; "'", oError
End Function

Const EVENT_TYPE_SUCCESS = 0
Const EVENT_TYPE_ERROR = 1
Const EVENT_TYPE_WARNING = 2
Const EVENT_TYPE_INFORMATION = 4
Const EVENT_TYPE_AUDITSUCCESS = 8
Const EVENT_TYPE_AUDITFAILURE = 16

Function ThrowScriptErrorNoAbort(ByVal sMessage, ByVal oErr)
'
' ThrowScriptError :: Creates an event and sends it back to the mom server
'
'

Dim sErrDescription, sErrNumber
sErrDescription = oErr.Description
sErrNumber = oErr.Number

On Error Resume Next

Dim oScriptErrorEvent

Set oScriptErrorEvent = ScriptContext.CreateEvent()
With oScriptErrorEvent
.EventNumber = 40000
.EventType = EVENT_TYPE_ERROR
.Message = sMessage
.SetEventParameter """Microsoft Windows DHCP Server"""
.SetEventParameter sMessage
.SetEventParameter sErrDescription
.SetEventParameter sErrNumber
End With
ScriptContext.Submit oScriptErrorEvent
ScriptContext.Echo "ThrowScriptError('" &amp; sMessage &amp; "')"
End Function

Function ThrowScriptError(Byval sMessage, ByVal oErr)
'
' ThrowScriptError :: Creates an event and sends it back to the mom server
'
'
On Error Resume Next
ThrowScriptErrorNoAbort sMessage, oErr
ScriptContext.Quit()
End Function


Sub FailedToParseOutput(ByVal sCommand, ByVal sOutput)
ThrowScriptError "Could not parse the output of [" &amp; sCommand &amp; "]" &amp; vbCrLf &amp; "Output: " &amp; sOutput, Err
End Sub


Sub ErrorRunningCommand(ByVal sCommand, ByVal sError)
ThrowScriptError "There was an error running [" &amp; sCommand &amp; "]" &amp; vbCrLf &amp; "Error: " &amp; sError, Err
End Sub

Dim DHCP2000_MIB_COUNT_REGEX
DHCP2000_MIB_COUNT_REGEX = Array( _
"\r\n" &amp; _
".*\r\n" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" _
)

Dim DHCP2000_SCOPE_COUNTERS_REGEX
DHCP2000_SCOPE_COUNTERS_REGEX = Array( _
"\t[^=]* = ", _
"\d+\.\d+\.\d+\.\d+", _
"\.\r\n\t\t[^=]* = ", _
"\d+", _
"\.\r\n\t\t[^=]* = ", _
"\d+", _
"\.\r\n\t\t[^=]* = ", _
"\d+", _
"\.\r\n" _
)

Dim DHCP2000_SCOPE_INFO_HEADER_REGEX
DHCP2000_SCOPE_INFO_HEADER_REGEX = Array( _
"\r\n" &amp; _
"==============================================================================\r\n" &amp; _
".*\r\n" &amp; _
"==============================================================================\r\n" &amp; _
"\r\n" _
)

Dim DHCP2000_SCOPE_INFO_REGEX
DHCP2000_SCOPE_INFO_REGEX = Array( _
" ", _
"\d+\.\d+\.\d+\.\d+", _
" *-.{16}-.{9}-", _
".{21}", _
"-.{14}\r\n" _
)

Dim DHCP2000_ZERO_SCOPE_INFO_FOOTER_REGEX
DHCP2000_ZERO_SCOPE_INFO_FOOTER_REGEX = Array( _
"\r\n" &amp; _
".* = 0 \r\n" &amp; _
".*\.\r\n" _
)

Class DHCP2000
Private m_sNetshPath
Private m_bInitialized
Private m_oScopes

Private Sub Class_Initialize()
m_bInitialized = False
End Sub

Public Property Let NetshPath(ByVal sPath)
Dim oShell
Set oShell = MomCreateObject("WScript.Shell")
m_sNetshPath = oShell.ExpandEnvironmentStrings(sPath)
End Property

Private Sub CollectData()
Dim iErrCode
Dim sOutput
Dim sError
Dim sCommand
Dim aSubMatches
sCommand = """""" &amp; m_sNetshPath &amp; """ dhcp server show all"""
RunCommand sCommand, iErrCode, sOutput, sError
If iErrCode = 0 Then
Set m_oScopes = MomCreateObject("Scripting.Dictionary")
If Not GetSubMatches(DHCP2000_MIB_COUNT_REGEX, sOutput, sOutput, aSubMatches) Then
FailedToParseOutput sCommand, sOutput
End If

Dim oScope
Do While GetSubMatches(DHCP2000_SCOPE_COUNTERS_REGEX, sOutput, sOutput, aSubMatches)
Set oScope = New DHCPScope2000
oScope.Initialize aSubMatches
Set m_oScopes.Item(oScope.Subnet) = oScope
Loop
Else
ErrorRunningCommand sCommand, sError
End If

sCommand = """""" &amp; m_sNetshPath &amp; """ dhcp server show scope"""
RunCommand sCommand, iErrCode, sOutput, sError
If iErrCode = 0 Then
If GetSubMatches(DHCP2000_SCOPE_INFO_HEADER_REGEX, sOutput, sOutput, aSubMatches) Then
Do While GetSubMatches(DHCP2000_SCOPE_INFO_REGEX, sOutput, sOutput, aSubMatches)
Set oScope = m_oScopes.Item(aSubMatches(0))
oScope.Name = Trim(aSubMatches(1))
Loop
ElseIf Not GetSubMatches(DHCP2000_ZERO_SCOPE_INFO_FOOTER_REGEX, sOutput, sOutput, aSubMatches) Then
FailedToParseOutput sCommand, sOutput
End If
Else
ErrorRunningCommand sCommand, sError
End If

m_bInitialized = True
End Sub

Public Property Get Scopes
If Not m_bInitialized Then CollectData
Scopes = m_oScopes.Items()
End Property
End Class

Class DHCPScope2000
Private m_lAddressesInUse
Private m_lFreeAddresses
Private m_lPendingOffers
Private m_sSubnet
Private m_lTotalAddresses
Private m_lPercentFree
Private m_sName

Public Sub Initialize(ByVal aSubMatches)
m_sSubnet = aSubMatches(0)
m_lAddressesInUse = CLng(aSubMatches(1))
m_lFreeAddresses = CLng(aSubMatches(2))
m_lPendingOffers = CLng(aSubMatches(3))
m_lTotalAddresses = m_lAddressesInUse + m_lFreeAddresses + m_lPendingOffers
m_lPercentFree = 0
If m_lTotalAddresses &lt;&gt; 0 Then m_lPercentFree = CLng(Round(100 * m_lFreeAddresses / m_lTotalAddresses, 0))
End Sub

Public Property Get Subnet
Subnet = m_sSubnet
End Property

Public Property Get AddressesInUse
AddressesInUse = m_lAddressesInUse
End Property

Public Property Get FreeAddresses
FreeAddresses = m_lFreeAddresses
End Property

Public Property Get PendingOffers
PendingOffers = m_lPendingOffers
End Property

Public Property Get TotalAddresses
TotalAddresses = m_lTotalAddresses
End Property

Public Property Get PercentFree
PercentFree = m_lPercentFree
End Property

Public Property Get DisplayName
DisplayName = "[" &amp; m_sSubnet &amp; "]"
If m_sName &lt;&gt; "" Then
DisplayName = DisplayName &amp; " " &amp; m_sName
End If
End Property

Public Property Let Name(ByVal sName)
m_sName = sName
End Property

Public Property Get IsMemberOfSuperscope
IsMemberOfSuperscope = False
End Property

Public Property Get PerfCounterInstanceName
PerfCounterInstanceName = Left(DisplayName, 255)
End Property
End Class



Const DHCP_SERVER_PERF_OBJECT_NAME = "DHCP Server"
Const SUPERSCOPE_FREE_ADDRESSES_PERF_COUNTER_NAME = "Superscope Free Addresses"
Const SUPERSCOPE_ADDRESSES_IN_USE_PERF_COUNTER_NAME = "Superscope Addresses In Use"
Const SCOPE_FREE_ADDRESSES_PERF_COUNTER_NAME = "Scope Free Addresses"
Const SCOPE_ADDRESSES_IN_USE_PERF_COUNTER_NAME = "Scope Addresses In Use"

Const NETSH_LOCATION_PARAMETER_NAME = "NetshLocation"
Const EXCLUDE_SCOPES_PARAMETER_NAME = "ExcludeScopes"
Const INCLUDE_SCOPES_PARAMETER_NAME = "IncludeScopes"
Const EXCLUDE_SUPERSCOPES_PARAMETER_NAME = "ExcludeSuperscopes"
Const INCLUDE_SUPERSCOPES_PARAMETER_NAME = "IncludeSuperscopes"

Sub SubmitPerfData(ByVal sObjectName, ByVal sCounterName, ByVal sInstanceName, ByVal dValue)
Dim oPerfData
Set oPerfData = ScriptContext.CreatePerfData()
With oPerfData
.ObjectName = sObjectName
.CounterName = sCounterName
.InstanceName = sInstanceName
.Value = dValue
End With
ScriptContext.Submit oPerfData
End Sub

Function FormatDHCP2000ScopeEventMessage(ByVal sName, ByVal lFreeAddresses, ByVal lAddressesInUse, ByVal lPercentFree)
Dim MESSAGE
MESSAGE = _
"The DHCP Scope named ""%1"" has the following address status:" &amp; vbCrLf &amp; _
"" &amp; vbCrLf &amp; _
"Free Addresses: %2" &amp; vbCrLf &amp; _
"Addresses In Use: %3" &amp; vbCrLf &amp; _
"Percent Addresses Free: %4"
Dim sResult
sResult = Replace(MESSAGE, "%1", sName)
sResult = Replace(sResult, "%2", FormatNumber(lFreeAddresses, 0, vbTrue, vbFalse, vbTrue))
sResult = Replace(sResult, "%3", FormatNumber(lAddressesInUse, 0, vbTrue, vbFalse, vbTrue))
sResult = Replace(sResult, "%4", lPercentFree)
FormatDHCP2000ScopeEventMessage = sResult
End Function

Const SCOPE_ADDRESS_STATUS_EVENT_ID = 1501
Const SUPERSCOPE_ADDRESS_STATUS_EVENT_ID = 1500

Sub SubmitDHCP2000ScopeEvent(ByVal oScope)
Dim oEvent
Set oEvent = ScriptContext.CreateEvent()
With oEvent
.EventNumber = SCOPE_ADDRESS_STATUS_EVENT_ID
.EventSource = "DHCP Server 2000 - Scope Monitoring"
.SetEventParameter oScope.DisplayName
.SetEventParameter oScope.FreeAddresses
.SetEventParameter oScope.AddressesInUse
.SetEventParameter oScope.PercentFree
.Message = FormatDHCP2000ScopeEventMessage(oScope.DisplayName, _
oScope.FreeAddresses, _
oScope.AddressesInUse, _
oScope.PercentFree _
)
End With
ScriptContext.Submit oEvent
End Sub

Function EscapeRegex(ByVal sText)
Const METACHARACTERS = "\*+?|{[()^$."
Dim sResult
Dim i
For i = 1 To Len(sText)
Dim sCurrentChar
sCurrentChar = Mid(sText, i, 1)
If InStr(METACHARACTERS, sCurrentChar) &lt;&gt; 0 Then
sResult = sResult &amp; "\"
End If
sResult = sResult &amp; sCurrentChar
Next
EscapeRegex = sResult
End Function

Function FindDelimitedItemWildcard(ByVal sItem, ByVal sList, ByVal sDelimiter, ByVal bCaseSensitive)
If sList = "" Then
FindDelimitedItemWildcard = False
Exit Function
End If

sList = EscapeRegex(sList)
sList = Replace(sList, EscapeRegex(sDelimiter), "|")
sList = Replace(sList, "\*", ".*")

Dim oRegex
Set oRegex = New RegExp
oRegex.IgnoreCase = Not bCaseSensitive
oRegex.Pattern = sList
FindDelimitedItemWildcard = oRegex.Test(sItem)
End Function



Function IsScopeIncluded(ByVal sScopeName, ByVal sIncludeList, ByVal sExcludeList)
Const LIST_DELIMITER = ";"
IsScopeIncluded = False
If FindDelimitedItemWildcard(sScopeName, sIncludeList, LIST_DELIMITER, False) Then
If Not FindDelimitedItemWildcard(sScopeName, sExcludeList, LIST_DELIMITER, False) Then
IsScopeIncluded = True
End If
End If
End Function

Const NETSH_PATH = "%SystemRoot%\system32\netsh.exe"

Sub Main()
Dim oDHCP
Set oDHCP = New DHCP2000
oDHCP.NetshPath = NETSH_PATH
Dim sExcludedScopes
sExcludedScopes = CStr(ScriptContext.Parameters.Get(EXCLUDE_SCOPES_PARAMETER_NAME))
Dim sIncludedScopes
sIncludedScopes = CStr(ScriptContext.Parameters.Get(INCLUDE_SCOPES_PARAMETER_NAME))

Dim oScope
For Each oScope In oDHCP.Scopes
SubmitPerfData DHCP_SERVER_PERF_OBJECT_NAME, SCOPE_FREE_ADDRESSES_PERF_COUNTER_NAME, oScope.PerfCounterInstanceName, oScope.FreeAddresses
SubmitPerfData DHCP_SERVER_PERF_OBJECT_NAME, SCOPE_ADDRESSES_IN_USE_PERF_COUNTER_NAME, oScope.PerfCounterInstanceName, oScope.AddressesInUse

If IsScopeIncluded(oScope.Subnet, sIncludedScopes, sExcludedScopes) Then
SubmitDHCP2000ScopeEvent oScope
End If
Next
End Sub</Script></Body>
<Language>VBScript</Language>
<Name>DHCP Server 2000 - Scope Monitoring</Name>
<Parameters>
<Parameter>
<Name>ExcludeScopes</Name>
<Value>$Config/Parameters/ExcludeScopes$</Value>
</Parameter>
<Parameter>
<Name>IncludeScopes</Name>
<Value>$Config/Parameters/IncludeScopes$</Value>
</Parameter>
</Parameters>
<ManagementPackId>[Microsoft.Windows.Server.DHCP,,1.0.0.1]</ManagementPackId>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="RunScriptAction"/>
</Composition>
</Composite>
</ModuleImplementation>
<InputType>SystemLibrary!System.BaseData</InputType>
</WriteActionModuleType>