Write DHCP Log File with All DHCP Perfomance Data Collection

Microsoft.Windows.DHCPServer.Library.WriteAction.PerformanceData (WriteActionModuleType)

Element properties:

TypeWriteActionModuleType
IsolationAny
AccessibilityInternal
RunAsMicrosoft.Windows.DHCPServer.Library.ActionAccount
InputTypeSystem.BaseData
OutputTypeSystem.CommandOutput

Member Modules:

ID Module Type TypeId RunAs 
Script WriteAction Microsoft.Windows.ScriptWriteAction Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
TimeoutSecondsint$Config/TimeoutSeconds$Timeout Seconds

Source Code:

<WriteActionModuleType ID="Microsoft.Windows.DHCPServer.Library.WriteAction.PerformanceData" Accessibility="Internal" RunAs="Microsoft.Windows.DHCPServer.Library.ActionAccount" Batching="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Server" type="xsd:string"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<WriteAction TypeID="Windows!Microsoft.Windows.ScriptWriteAction" ID="Script">
<ScriptName>DHCPCollectAllPerfData.vbs</ScriptName>
<Arguments>"$Config/Server$"</Arguments>
<ScriptBody><Script>' Copyright (c) Microsoft Corporation. All rights reserved.
' Microsoft Windows DHCP Server Library Scope Collecting Values
'
' Returns a property bag containing the number of free, inuse, and pending IP addresses in the specified scope / superscope.
'
' Parameters - TargetComputer The FQDN of the computer targeted by the script.

Option Explicit

SetLocale("en-us")

Const SCOM_ERROR = 1
Const SCOM_WARNING = 2
Const SCOM_INFORMATIONAL = 4

' SCOM Property Bag Types
Const SCOM_PB_ALERT = 0
Const SCOM_PB_EVENT = 1
Const SCOM_PB_PERFDATA = 2
Const SCOM_PB_STATEDATA = 3

Const DHCP_SCRIPTNAME = "DHCPCollectAllPerfData.vbs"
Const HKEY_LOCAL_MACHINE = &amp;H80000002
Const DHCP_START_EVENTNUMBER = 1130
Const DHCP_EVENTNUMBER = 1131
Const DHCP_TRACEEVENTNUMBER = 1132
Const DHCP_ERROREVENTNUMBER = 1135
Const WIN2008VERSION = "6.0"

Const NETSH_PATH = "%SystemRoot%\system32\netsh.exe"
Dim oAPI, oShell
Dim oScope2008
Dim m_sNetshPath
Dim sOutput, sOutput2, sError, sCommand, aSubMatches, ierrCode
Dim bFailed, oReturnAllFlag, objSuperScopes
Dim oArgs, oDiscoveryData, oInst, SourceID, ManagedEntityId, TargetComputer
Dim oPropertyBag, sInvalidParams , sName, sSubnet
Dim boolOnlyDisabled
Dim IsSuperscope,iPending,iInuse,iFree
Dim oWMI
Dim OSVersion
Dim rc
Dim sOutput3, sOutput4, aSubMatches2
Dim boolIPV6Scope
Dim strIPV6InstanceName
Dim fso
Dim strLogFile

Dim DHCP2008_SUPERSCOPE_REGEX
DHCP2008_SUPERSCOPE_REGEX = Array( _
"\r\n[^:]*: ", _
"[^\r]*", _
"\r\n" _
)

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

Dim DHCP2008_MIB_COUNT_REGEX
DHCP2008_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" &amp;_
"\t.*\r\n" &amp;_
"\t.*\r\n" _
)

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

'New
Dim DHCP2003_SCOPE_INFO_HEADER_REGEX
DHCP2003_SCOPE_INFO_HEADER_REGEX = Array( _
"\r\n" &amp; _
"==============================================================================\r\n" &amp; _
".*\r\n" &amp; _
"==============================================================================\r\n" &amp; _
"\r\n" _
)

Dim DHCP2003_SCOPE_INFO_REGEX

' Parse Scope Address, Subnet Mask, Status, Scope Name
DHCP2003_SCOPE_INFO_REGEX = Array( _
" ", _
"\d+\.\d+\.\d+\.\d+", _
" *- ", _
"\d+\.\d+\.\d+\.\d+", _
" *-", _
".{6}", _
".{8}-", _
".{21}", _
"-.{14}\r\n" _
)

Dim DHCP2008_v6scope_REGEX
DHCP2008_v6scope_REGEX = Array("\r\n.*\r\n.*\r\n.*\r\n\r\n")


Dim DHCP2008_v6scope2_REGEX
DHCP2008_v6scope2_REGEX = Array( _
" ", _
"[^ ]*",_
"[ ]*-",_
"[^-]*", _
" *-", _
".{21}", _
".*\r\n" _
)

Dim DHCP2008_v6scope2_MIB_COUNT_REGEX
DHCP2008_v6scope2_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" &amp; _
"\t.*\r\n" &amp; _
"\t.*\r\n" _
)


Dim DHCP2008_V6SCOPE2_MIB_REGEX
DHCP2008_V6SCOPE2_MIB_REGEX = Array( _
"\t[^=]* = ", _
".{39}", _
"\.\r\n\t\t[^=]* = ", _
"\d+", _
"\.\r\n\t\t[^=]* = ", _
"\d+", _
"\.\r\n\t\t[^=]* = ", _
"\d+", _
"\.\r\n" _
)


Class DHCPScopes
Private m_oScopes
Private m_oSuperScopes
Private m_oV6Scopes
Public oPropertyBag
Private objSupScopes

Private Sub Class_Initialize()
set m_oScopes = CreateObject("Scripting.Dictionary")
set m_oSuperScopes = CreateObject("Scripting.Dictionary")
set m_oV6Scopes = CreateObject("Scripting.Dictionary")
CollectData
End Sub

Public Function GetScopes
Set GetScopes = m_oScopes
End Function

Public Function GetSuperScopes
Set GetSuperScopes = m_oSuperScopes
End Function

Public Function GetV6Scopes
Set GetV6Scopes = m_oV6Scopes
End Function

Private Sub CollectData()
Dim Superscopename
Dim oScope
boolIPV6Scope = false
Set oWMI = GetObject("winmgmts:\\" &amp; TargetComputer &amp; "\root\default:StdRegProv")
rc = oWMI.GetStringValue(HKEY_LOCAL_MACHINE, "SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", OSVersion)

sOutput = ExecuteCmd("dhcp server show superscope", NETSH_PATH, true)
sOutput2 = ExecuteCmd("dhcp server show scope", NETSH_PATH, true)

If LCase(sOutput) = "error" Then
ThrowErrorAndExit "Error-netsh dhcp server show superscope failed."
End If

Do While GetSubMatches(DHCP2008_SUPERSCOPE_REGEX, sOutput, sOutput, aSubMatches)
Superscopename = aSubMatches(0)
If Not(LCase(Superscopename) = "(null)") Then
Set objSupScopes = new SuperScope
objSupScopes.AddData Superscopename,0,0,0,0
Set m_oSuperScopes.Item(objSupScopes.Superscopename) = objSupScopes
End If

Do While GetSubMatches(DHCP2008_SUPERSCOPE_MEMBER_REGEX, sOutput, sOutput, aSubMatches)
Set oScope =new Scope
oScope.Initialize Superscopename,aSubMatches(1),aSubMatches(0), False
Set m_oScopes.Item(oScope.Subnet) = oScope
Loop
Loop

' Set enabled attribute for all scopes.
Dim i, boolEnabled
If GetSubMatches(DHCP2003_SCOPE_INFO_HEADER_REGEX, sOutput2, sOutput2, aSubMatches2) Then
Do While GetSubMatches(DHCP2003_SCOPE_INFO_REGEX, sOutput2, sOutput2, aSubMatches2)
If m_oScopes.Exists(Trim(aSubMatches2(0))) Then
boolEnabled = CBool(Trim(aSubMatches2(2))= "Active")
Set oScope = m_oScopes.Item(Trim(aSubMatches2(0)))
oScope.SetEnabled(boolEnabled)
End If
Loop
End If

' now calc free,inuse,pending using dhcp show all.
Dim tempsubnet,tempfree,tempinuse,temppend
Dim strScopeInfo, tempenabled

sOutput=ExecuteCmd("dhcp server show mibinfo", NETSH_PATH, True)
If LCase(sOutput) = "error" Then
ThrowErrorAndExit "Error-netsh dhcp server show all failed."
End If

If GetSubMatches(DHCP2008_MIB_COUNT_REGEX, sOutput, sOutput, aSubMatches) Then
Do While GetSubMatches(DHCP2008_SCOPE_REGEX, sOutput, sOutput, aSubMatches)
tempsubnet=aSubMatches(0)
tempfree=aSubMatches(2)
tempinuse=aSubMatches(1)
temppend=aSubMatches(3)

If m_oScopes.Exists(tempsubnet) Then
Set oScope = m_oScopes.Item(tempsubnet)
If Not(oScope.superscopename = "(null)") Then
m_oSuperScopes.Item(oscope.superscopename).SetFree CInt(m_oSuperScopes.Item(oscope.superscopename).Free ) + CInt(tempfree)
m_oSuperScopes.Item(oscope.superscopename).SetInUse CInt(m_oSuperScopes.Item(oscope.superscopename).InUse) + CInt(tempinuse)
m_oSuperScopes.Item(oscope.superscopename).SetPend CInt(m_oSuperScopes.Item(oscope.superscopename).Pend) + CInt(temppend)

' Mark that this SuperScope has disabled scopes
If oScope.Enabled = False Then
m_oSuperScopes.Item(oscope.superscopename).SetIncludeDisabled 1
End If
End If
oScope.AddData tempfree, tempinuse, temppend
End If
Loop
End If

If (osVersion = WIN2008VERSION) Then
'Getting IPV6 Scopes Data
sOutput3 = ExecuteCmd("dhcp server v6 show scope", NETSH_PATH, True)
sOutput4 = ExecuteCmd("dhcp server v6 show mibinfo", NETSH_PATH, True)

If (GetSubMatches(DHCP2008_v6scope_REGEX, sOutput3, sOutput3, aSubMatches2)) Then
Do While GetSubMatches(DHCP2008_v6scope2_REGEX, sOutput3, sOutput3, aSubMatches2)
tempsubnet=Trim(aSubMatches2(0))
strIPV6InstanceName = Trim(aSubMatches2(2))

Set oScope = new Scope
oScope.Initialize "", strIPV6InstanceName, tempsubnet, CBool(Trim(aSubMatches2(1))= "Active")
Set m_oV6Scopes.Item(oScope.Subnet) = oScope
Loop
End If

If GetSubMatches(DHCP2008_v6scope2_MIB_COUNT_REGEX, sOutput4, sOutput4, aSubMatches) Then
Do While GetSubMatches(DHCP2008_V6SCOPE2_MIB_REGEX, sOutput4, sOutput4, aSubMatches)
tempsubnet=Trim(aSubMatches(0))
tempfree = aSubMatches(2)
tempinuse=aSubMatches(1)
temppend=aSubMatches(3)

If m_oV6Scopes.Exists(tempsubnet) Then
Set oScope = m_oV6Scopes.Item(tempsubnet)
oScope.AddData tempfree, tempinuse, temppend
End If
Loop
End If
End If
End Sub
End Class

Class SuperScope
private mssuperscopename
private msincludedisabled
private msfree
private msinuse
private mspend

Private Sub Class_Initialize()
End Sub

Public Sub AddData(insuperscopename, infree, ininuse, inpend, inincludedisabled)
mssuperscopename=insuperscopename
msfree=infree
msinuse=ininuse
mspend=inpend
msincludedisabled=inincludedisabled
End Sub

Public Property Get Superscopename
SuperscopeName = mssuperscopename
End Property

Public Property Get IncludeDisabled
IncludeDisabled = msincludedisabled
End Property

Public Property Get Free
Free = msfree
End Property

Public Property Get InUse
InUse = msinuse
End Property

Public Property Get Pend
Pend = mspend
End Property

Public Sub SetIncludeDisabled(inincludedisabled)
msincludedisabled = inincludedisabled
End Sub

Public Sub SetFree(infree)
msfree = infree
End Sub

Public Sub SetInUse(ininuse)
msinuse = ininuse
End Sub

Public Sub SetPend(inpend)
mspend = inpend
End Sub
End Class

Class Scope
private msuperscopename
private mscopename
private msubnet
private menabled
private mfree
private minuse
private mpend

Public Sub Initialize(insuperscopename,inscopename,insubnet,inenabled)
If Len(RTrim(inscopename)) &gt; 21 Then
inscopename = Left(RTrim(inscopename),21)
End If

msuperscopename=insuperscopename
mscopename=inscopename
msubnet=insubnet
menabled=inenabled
End Sub

Public Sub AddData(infree, ininuse, inpend)
mfree=infree
minuse=ininuse
mpend=inpend
End Sub

Public Property Get Superscopename
SuperscopeName = msuperscopename
End Property

Public Property Get Scopename
Scopename = mscopename
End Property

Public Property Get Subnet
Subnet = msubnet
End Property

Public Property Get Enabled
Enabled = menabled
End Property

Public Property Get Free
Free = mfree
End Property

Public Property Get InUse
InUse = minuse
End Property

Public Property Get Pend
Pend = mpend
End Property

Public Sub SetEnabled(inenabled)
menabled = inenabled
End Sub
End Class

Sub ThrowErrorAndExit(Message)
Call oAPI.LogScriptEvent(DHCP_SCRIPTNAME, DHCP_ERROREVENTNUMBER, SCOM_ERROR, Message)
WScript.Quit
End Sub

Sub Trace(Message)
Call oAPI.LogScriptEvent(DHCP_SCRIPTNAME, DHCP_TRACEEVENTNUMBER, SCOM_INFORMATIONAL, Message)
End Sub

Function ExecuteCmd(strOptionToUse, strCmdToUse, boolReadOutput)
Dim ncControlcommand
Dim strExecOut
Dim strOutputFile, strErrrOutputFile, strGuid
strGuid = GetGUID()
strOutputFile = Replace(WScript.ScriptFullName, WScript.ScriptName, "Data-" + strGUID + ".txt")
strErrrOutputFile = Replace(WScript.ScriptFullName, WScript.ScriptName, "Error-" + strGUID + ".txt")

ncControlcommand = "cmd.exe /C """ &amp; QuoteWrap(strCmdToUse) &amp; " " &amp; strOptionToUse &amp; " &gt; " &amp; QuoteWrap(strOutputFile) &amp; " 2&gt; " &amp; QuoteWrap(strErrrOutputFile) &amp; " " &amp; """"

If boolReadOutput Then
strExecOut = RunCmd(ncControlcommand,strOutputFile, strErrrOutputFile, true)
Else
strExecOut = RunCmd(ncControlcommand,strOutputFile, strErrrOutputFile, false)
End If
ExecuteCmd = strExecOut
End Function

Function GetGUID()
Dim TypeLib, tg
Set TypeLib = CreateObject("Scriptlet.TypeLib")
tg = TypeLib.Guid
Set TypeLib = Nothing
GetGUID = left(tg, len(tg)-2)
End Function

Function RunCmd(CmdString, strOutputFile, strErrrOutputFile, boolGetOutPut)
Dim oExec
Dim output
Dim strOutPut
Dim objFile1, objFile2
Dim strStdOut, strStdErr
Dim ret

ret = oShell.Run(CmdString, 0, boolGetOutPut)

WScript.Sleep(100)

'Get StdOut and StdErr
strStdOut = ""
strStdErr = ""

Set objFile1 = fso.OpenTextFile(strOutputFile)
If Not(objFile1.AtEndOfStream) Then
strStdOut = objFile1.readAll()
End If
objFile1.close()
fso.DeleteFile strOutputFile,true
Set objFile1 = Nothing

Set objFile2 = fso.OpenTextFile(strErrrOutputFile)
If Not(objFile2.AtEndOfStream) Then
strStdErr = objFile2.readAll()
End If
objFile2.close()
fso.DeleteFile strErrrOutputFile,true
Set objFile2 = Nothing

If ret &lt;&gt; 0 Then
Call oAPI.LogScriptEvent(DHCP_SCRIPTNAME, DHCP_ERROREVENTNUMBER, SCOM_ERROR, "Command """ &amp; CmdString &amp; """ failed with the following output:" &amp; VbCrLf &amp; strStdOut &amp; VbCrLf &amp; strStdErr)
End If

If boolGetOutPut Then
strOutPut = strStdOut
Else
strOutPut = "1"
End If

If strStdErr &lt;&gt; "" Then
strOutPut = "Error: " &amp; strStdErr
End If

RunCmd = strOutPut
End Function

Function QuoteWrap(myString)
If (myString &lt;&gt; "") And (left(mySTring,1) &lt;&gt; Chr(34)) And (Right(myString,1) &lt;&gt; Chr(34)) Then
QuoteWrap = Chr(34) &amp; myString &amp; Chr(34)
Else
QuoteWrap = myString
End If
End Function

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

Call Main()

Sub Main()
boolOnlyDisabled = true
bFailed = False
IsSuperScope=false

iPending=0
iInuse=0
iFree=0

Set oShell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set oArgs = WScript.Arguments
Set oAPI = CreateObject("MOM.ScriptAPI")

' If the script is called without the required arguments, create an information event and Then quit.
If oArgs.Count &lt;&gt; 1 Then
ThrowErrorAndExit "Usage: " &amp; DHCP_SCRIPTNAME &amp; "&lt;target computer FQDN&gt;"
End If

TargetComputer = oArgs(0) ' The FQDN of the computer targeted by the script.

Dim oDHCP, ScopeColl, objSuper, objScope, strScopeInfo, strSuperScopeInfo, tempenabled
Set oDHCP = New DHCPScopes ' this calculates the values

' Write all data to the registry. GetScriptStateKeyPath returns a 'safe' registry path to write data to.
' Registry key is ACL'ed with 'Creator Owner' meaning if you create it you alone (plus Admins) can read it.

Dim sRegPath, sRegData
sRegPath = "HKLM\" &amp; oAPI.GetScriptStateKeyPath("DHCP") &amp; "\ScopePerfData"

' Write Scopes
For Each objScope In oDHCP.GetScopes.items()
If objScope.Enabled = True Then
tempenabled = "0"
Else
tempenabled = "1"
End If
strScopeInfo = objScope.Subnet &amp; vbTab &amp; CStr(objScope.Free) &amp; vbTab &amp; CStr(objScope.InUse) &amp; vbTab &amp; CStr(objScope.Pend) &amp; vbTab &amp; tempenabled
sRegData = sRegData &amp; strScopeInfo &amp; vbCrLf
Next

' Write SuperScopes
For Each objSuper In oDHCP.GetSuperScopes.items()
strSuperScopeInfo = objSuper.Superscopename &amp; vbTab &amp; objSuper.Free &amp; vbTab &amp; objSuper.InUse &amp; vbTab &amp; objSuper.Pend &amp; vbTab &amp; objSuper.IncludeDisabled
sRegData = sRegData &amp; strSuperScopeInfo &amp; vbCrLf
Next

' Write V6Scopes
For Each objScope In oDHCP.GetV6Scopes.items()
If objScope.Enabled = True Then
tempenabled = "0"
Else
tempenabled = "1"
End If
strScopeInfo = objScope.Subnet &amp; vbTab &amp; CStr(objScope.Free) &amp; vbTab &amp; CStr(objScope.InUse) &amp; vbTab &amp; CStr(objScope.Pend) &amp; vbTab &amp; tempenabled
sRegData = sRegData &amp; strScopeInfo &amp; vbCrLf
Next

Call oShell.RegWrite(sRegPath, sRegData)

Set oPropertyBag = oAPI.CreateTypedPropertyBag(SCOM_PB_EVENT)
oPropertyBag.AddValue "RegistryKey", sRegPath
oPropertyBag.AddValue "Error", Err.Description
oAPi.AddItem(oPropertyBag)
oAPi.ReturnItems
End Sub
</Script></ScriptBody>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="Script"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.CommandOutput</OutputType>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>