Link to home
Start Free TrialLog in
Avatar of John Darby
John DarbyFlag for United States of America

asked on

NO_CLIENT_SITE entries in netlogon.log

I am looking to find any straggling IP address ranges to configure as subnets in AD. To do this, I was thinking I could query each DC (30 of them) for NO_CLIENT_SITE entries in their netlogon.log files.

On a Unix system I could grep these values. How do I do this with an MS Windows app?

Thank you,
John
ASKER CERTIFIED SOLUTION
Avatar of Chris Dent
Chris Dent
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

This is the version written to run for a single domain. Does pretty much the same thing as before.



' ScanNetlogon-DomainOnly.vbs
'
' Script to Read the Netlogon log files from %SystemRoot%\Debug\netlogon.log for all Domain
' Controllers in the Forest and work out which subnets are missing from AD Configuration.
'
' Author: Chris Dent
' Last Modified: 14/06/2006

Option Explicit

Const WBEM_RETURN_IMMEDIATELY = &H10
Const WBEM_FORWARD_ONLY = &H20

Dim objFileSystem, objShell, objUnconfiguredIPs, objUnconfiguredSubnets, objRootDSE
Dim objConfiguredSubnets
Dim strDN
Dim arrDCs()
Dim i

'
' Functions
'

Function GetNetworkAddress(strIP, intMaskLength)

      Dim strOctet, strBinOctet, strBinIP, strBinMask, strIPBit, strMaskBit
      Dim strBinNetwork, strNetworkAddress
      Dim i, intTemp, intOctet, intBit
      Dim arrOctets

      arrOctets = Split(strIP, ".")
      For Each strOctet in arrOctets
            intTemp  = 0
            strBinOctet = ""
            For i = 0 To 7
                  If intTemp + 2^(7 - i) <= CInt(strOctet) Then
                        strBinOctet = strBinOctet & "1"
                        intTemp = intTemp + 2^(7 - i)
                  Else
                        strBinOctet = strBinOctet & "0"
                  End If
            Next
            strBinIP = strBinIP & "." & strBinOctet
      Next
      strBinIP = Right(strBinIP, Len(strBinIP) - 1)

      For i = 1 to 32
            If i <= intMaskLength Then
                  strBinMask = strBinMask & "1"
            Else
                  strBinMask = strBinMask & "0"
            End If
            If i = 8 Or i = 16 Or i = 24 Then
                  strBinMask = strBinMask & "."
            End If
      Next

      For i = 1 to Len(strBinIP)
            strIPBit = Mid(strBinIP, i, 1)
            strMaskBit = Mid(strBinMask, i, 1)
            If strIPBit = "1" And strMaskBit = "1" Then
                  strBinNetwork = strBinNetwork & "1"
            ElseIf strIPBit = "." Then
                  strBinNetwork = strBinNetwork & strIPBit
            Else
                  strBinNetwork = strBinNetwork & "0"
            End If
      Next

      arrOctets = Split(strBinNetwork, ".")
      For Each strOctet in arrOctets
            intOctet = 0
            For i = 0 to 7
                  intBit = CInt(Mid(strOctet, i + 1, 1))
                  If intBit = 1 Then
                        intOctet = intOctet + 2^(7 - i)
                  End If
            Next
            strNetworkAddress = strNetworkAddress & "." & CStr(intOctet)
      Next
      GetNetworkAddress = Right(strNetworkAddress, Len(strNetworkAddress) - 1)
End Function

'
' AD Subroutines
'

Sub GetDCs(strDN)

      ' Gets the DNS Host Name for each Domain Controller

      Dim objOU, objDC

      On Error Resume Next
      Set objOU = GetObject("LDAP://" & strDN)
      For Each objDC in objOU
            If objDC.Class = "organizationalUnit" Then
                  GetDCs objDC.Get("distinguishedName")
            ElseIf objDC.Class = "computer" Then
                  ReDim Preserve arrDCs(i)
                  arrDCs(i) = objDC.Get("dNSHostName")
                  i = i + 1
            End If
      Next
      On Error Goto 0
End Sub

Sub GetConfiguredSubnets

      Dim objRootDSE, objSubnets, objSubnet
      Dim strSubnets, strNetworkAddress
      Dim arrTemp
      Dim intMaskLength

      Set objRootDSE = GetObject("LDAP://RootDSE")
      strSubnets = "CN=Subnets,CN=Sites," & objRootDSE.GEt("configurationNamingContext")
      Set objRootDSE = Nothing

      Set objSubnets = GetObject("LDAP://" & strSubnets)
      For Each objSubnet in objSubnets
            arrTemp = Split(objSubnet.Get("name"), "/")
            strNetworkAddress = arrTemp(0)
            intMaskLength = CInt(arrTemp(1))
            strNetworkAddress = strNetworkAddress & "\" & CStr(intMaskLength)

            If Not objConfiguredSubnets.Exists(strNetworkAddress) Then
                  objConfiguredSubnets.Add strNetworkAddress, ""
            End If
      Next
      Set objSubnets = Nothing
End Sub

'
' Data Gathering & Handling Subroutines
'

Sub GatherLogs

      ' Gather Files. Copy the files to a local repository for parsing, just easier that way.

      Dim objFolder, objFile, objWMIService, objItem
      Dim colOS
      Dim strDC, strFolder, strFile

      If Not objFileSystem.FolderExists("NetLogon") Then
            objFileSystem.CreateFolder("NetLogon")
      End If
      
      Set objFolder = objFileSystem.GetFolder("NetLogon")
      For Each objFile in objFolder.Files
            objFile.Delete
      Next
      Set objFolder = Nothing

      For Each strDC in arrDCs
            On Error Resume Next
      
            strFolder = ""
            Set objWMIService = GetObject("winmgmts:\\" & strDC & "\root\CIMV2")
            Set colOS = objWMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem", "WQL", _
                        WBEM_RETURN_IMMEDIATELY + WBEM_FORWARD_ONLY)
                  
            For Each objItem in colOS
                  strFolder = objItem.WindowsDirectory
            Next
      
            On Error Goto 0

            If strFolder = "" Then
                  strFolder = "\\" & strDC & "\c$\Windows"
            Else
                  strFolder = Replace(LCase(strFolder), "c:", "\\" & strDC & "\c$")
            End If
            strFile = strFolder & "\debug\netlogon.log"

            If objFileSystem.FileExists(strFile) Then
                  Set objFile = objFileSystem.GetFile(strFile)
                  objFile.Copy "NetLogon\" & strDC & "." & objFile.Name
                  Set objFile = Nothing
            End If
      
            Set colOS = Nothing
            Set      objWMIService = Nothing
      Next
End Sub

Sub ParseLogs

      ' Checks through the Log Files

      Dim objFolder, objFile, objStream
      Dim strLine, strIP, strNetworkAddress, strServer, strHostName, strDate
      Dim intMaskLength
      Dim arrLine

      Set objFolder = objFileSystem.GetFolder("NetLogon")
      For Each objFile in objFolder.Files
            strServer = Replace(objFile.Name, ".Netlogon.log", "")
      
            Set objStream = objFile.OpenAsTextStream(1, 0)
            
            Do While Not objStream.AtEndOfStream
                  strLine = objStream.ReadLine
                  If InStr(strLine, "NO_CLIENT_SITE") Then
                        arrLine = Split(strLine, " ")
                        strDate = arrLine(0)
                        strHostName = arrLine(UBound(arrLine) - 1)
                        strIP = arrLine(UBound(arrLine))
                        
                        If Not objUnconfiguredIPs.Exists(strIP) Then
                              objUnconfiguredIPs.Add strIP, Array(strServer, strDate, strHostName)
                        End If
                        
                        If Left(strIP, 3) = "10." Then
                              intMaskLength = 18
                              strNetworkAddress = GetNetworkAddress(strIP, intMaskLength)
                              strNetworkAddress = strNetworkAddress & "\" & CStr(intMaskLength)
                        ElseIf Left(strIP, 8) = "192.168." Then
                              intMaskLength = 24
                              strNetworkAddress = GetNetworkAddress(strIP, intMaskLength)
                              strNetworkAddress = strNetworkAddress & "\" & CStr(intMaskLength)
                        End If
                        
                        If Not objUnconfiguredSubnets.Exists(strNetworkAddress) And _
                              Not objConfiguredSubnets.Exists(strNetworkAddress) Then
                                    objUnconfiguredSubnets.Add strNetworkAddress, strServer
                        End If
                  End If
            Loop
      Next
End Sub

'
' Reporting Subroutines
'

Sub WriteReports

      Dim objFile
      Dim strIP, strSubnet

      If Not objFileSystem.FolderExists("Reports") Then
            objFileSystem.CreateFolder("Reports")
      End If

      Set objFile = objFileSystem.OpenTextFile("Reports\IPReport.csv", 2, True, 0)
      For Each strIP in objUnconfiguredIPs
            objFile.WriteLine strIP & "," & objUnconfiguredIPs(strIP)(0) &_
                  "," & objUnconfiguredIPs(strIP)(1) & "," & objUnconfiguredIPs(strIP)(2)
      Next
      Set objFile = Nothing
      
      Set objFile = objFileSystem.OpenTextFile("Reports\SubnetReport.csv", 2, True, 0)
      For Each strSubnet in objUnconfiguredSubnets
            objFile.WriteLine strSubnet & "," & objUnconfiguredSubnets(strSubnet)
      Next
      Set objFile = Nothing
End Sub

'
' Main Code
'

Set objShell = CreateObject("WScript.Shell")
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
Set objConfiguredSubnets = CreateObject("Scripting.Dictionary")
Set objUnconfiguredSubnets = CreateObject("Scripting.Dictionary")
Set objUnconfiguredIPs = CreateObject("Scripting.Dictionary")
Set objRootDSE = GetObject("LDAP://RootDSE")

strDN = "OU=Domain Controllers," & objRootDSE.Get("defaultNamingContext")

i = 0
GetDCs strDN

GatherLogs
GetConfiguredSubnets
ParseLogs
WriteReports

Set objRootDSE = Nothing
Set objUnconfiguredIPs = Nothing
Set objUnconfiguredSubnets = Nothing
Set objConfiguredSubnets = Nothing
Set objFileSystem = Nothing
Set objShell = Nothing
Avatar of John Darby

ASKER

Chris, thanks for the most excellent script. Out-of-the-box I decided to do a test run on my home domain and it spit back a message about compiling error...

D:\notes\netlogon.log-scan\ScanNetlogon.vbs(441, 14) Microsoft VBScript compilat
ion error: Expected end of statement

Do I need to turn on my vs.net debugger and start looking for problems or is this a simple issue?

Thank you for your kind help!

Warm regards,
John

Line 441 is out of range on mine, only 439 lines there... it's probably something really simple though - could you possibly post line 441 and a few lines on either side?

Sorry it's got errors in it... thought I had rid of all of them.

Chris

Hmm just out of curiousity, you didn't end up with both scripts in there did you? There are two seperate scripts above; one works for every DC in a forest... the other for every DC in a single domain. If you don't have a Forest then the second would be more appropriate.

Chris
Chris...I grabbed the whole lot (two scripts) and wholesale plopped it into one file. My fault: I didn't read.

Okay, RTFM is still alive and well. I will try each script separately.

Thanks so much!
John

Phew, that makes a lot of sense :)

Chris