Location: Articles

Articles

Articles

Vbscript to determine domain and forest functional levels

By Alexei Segundo on Wednesday, April 08, 2009 7:09 PM

This script was created to help when raising domain and forest functional levels, especially in larger environments. The script uses an authoritative DC to enumerate all the DCs in the forest. Each DC is then contacted in turn to determine what it thinks is the current domain and forest functional level. The goal is to ensure that the information is consistent across DCs before raising the functional level, and to ensure that replication distributes the changes successfully after raising the functional level.

The syntax to run the script is:

c:\cscript fl.vbs <authoritative_dc_name>

 

'File Name: fl.vbs

Option Explicit

'Global constants
Const LINK_PINGCOUNT = 1
const ERROR_SUCCESS = 0

'Main

GetDCList

'End Main

'=============================================================

Function GetDCList
Dim objRootDSE, strConfig, adoConnection, adoCommand, strQuery
Dim adoRecordset, objDC, objSite
Dim strAuthDC, strDC, strSite

' We need a DC that can give us authoritative information

If WScript.Arguments.Count = 1 Then
 strAuthDC = WScript.Arguments.Item(0)
Else
 Wscript.Echo "Usage: fl.vbs <DCName>"
 Wscript.Quit
End If


Wscript.Echo "Using " & strAuthDC & " as the authoritative DC...." & vbCrLf

' Determine configuration context from RootDSE object.
Set objRootDSE = GetObject("
LDAP://RootDSE")
strConfig = objRootDSE.Get("configurationNamingContext")

' Use ADO to search Active Directory for ObjectClass nTDSDSA.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection

strQuery = "<LDAP://" & strAuthDC & "/" & strConfig _
    & ">;(ObjectClass=nTDSDSA);AdsPath;subtree"

adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False

Set adoRecordset = adoCommand.Execute

Do Until adoRecordset.EOF
    Set objDC = GetObject( _
        GetObject(adoRecordset.Fields("AdsPath").Value).Parent)
    Set objSite = GetObject(GetObject(objDC.Parent).Parent)
     strDC = objDC.DNSHostName
    strSite = objSite.cn
 
    If VerifyHostPing(strDC) Then
     Call ProcessDCList(strDC,strSite)
    End If
    adoRecordset.MoveNext
Loop
adoRecordset.Close

' Clean up.
adoConnection.Close
Set objRootDSE = Nothing
Set adoCommand = Nothing
Set adoConnection = Nothing
Set adoRecordset = Nothing
Set objDC = Nothing
Set objSite = Nothing

Wscript.Echo "Done"

End Function
'==================================================================

Function VerifyHostPing(ByRef strComputer)
    Dim objWMI, strQuery, i, objPings, objStatus

    Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\root\cimv2")

    VerifyHostPing = False
    strQuery = "Select * From Win32_PingStatus where Address = '" & strComputer & "' AND BufferSize = 32 and Timeout = 300"

    For i = 1 to LINK_PINGCOUNT
        Set objPings = objWMI.ExecQuery(strQuery)

        For Each objStatus in objPings
            If IsNull(objStatus.StatusCode) OR objStatus.StatusCode <> ERROR_SUCCESS Then
                wscript.echo "Warning: " & strComputer & " not contactable."  & vbCrLf     
                VerifyHostPing = False
            Else
                'wscript.echo "Successfully pinged " & strComputer
                VerifyHostPing = True
            End If
        Next
    Next

    Set objPings = Nothing
    Set objStatus = Nothing
    Set objWMI = Nothing
End Function

'==================================================================

Sub ProcessDCList(varDC,varSite)
 Dim Domain, strDomain, objRootDSE, strDFL, Forest, strFFL
 Const ADS_PROPERTY_NOT_FOUND = &h8000500D

 Wscript.Echo "Checking DC: " & varDC & " in site: " & varSite

 Set objRootDSE = GetObject("LDAP://" & varDC & "/RootDSE")
 strDomain = objRootDSE.Get("DefaultNamingContext")
 
  
 On Error Resume Next
 set Domain = GetObject("LDAP://" & varDC & "/" & strDomain)
 strDFL = Domain.Get("msDS-Behavior-Version")
 
 If Err.Number <>  ADS_PROPERTY_NOT_FOUND Then
         WScript.Echo "Domain Functional Level is " & strDFL
        Else
         WScript.Echo "Domain Functional Level is 0"
        Err.Clear
 End If

 On Error Resume Next
 set Forest = GetObject("LDAP://" & varDC & "/cn=partitions," & _
                           objRootDSE.Get("configurationNamingContext"))
 strFFL = Forest.Get("msDS-Behavior-Version")
 
 If Err.Number <>  ADS_PROPERTY_NOT_FOUND Then
         WScript.Echo "Forest Functional Level is " & strFFL
        Else
         WScript.Echo "Forest Functional Level is 0"
        Err.Clear
 End If

 Wscript.Echo vbCrLf

End Sub
'==================================================================

 

Alexei

8th April 2009

Comments

By Aitch @ Thursday, June 11, 2009 7:01 PM

This is great, but what does it mean?

My domain level is 2 and my forest level is 0.


By thedacman @ Friday, June 26, 2009 9:05 PM

modify Sub ProcessDCList(varDC,varSite) like this:
dim strDFLdesc, strFFLdesc

strDFL = Domain.Get("msDS-Behavior-Version")
wscript.echo "msDS-Behavior-Version equals " & strDFL

If Err.Number <> ADS_PROPERTY_NOT_FOUND Then
select case strDFL
case 0
strDFLdesc = "2000 mixed"
case 1
strDFLdesc = "2000"
case 2
strDFLdesc = "2003"
case 3
strDFLdesc = "2008"
case else
strDFLdesc = "unknown"
End Select
WScript.Echo "Domain Functional Level is " & strDFLdesc

Err.Clear
End If

On Error Resume Next
set Forest = GetObject("LDAP://" & varDC & "/cn=partitions," & _
objRootDSE.Get("configurationNamingContext"))
strFFL = Forest.Get("msDS-Behavior-Version")

If Err.Number <> ADS_PROPERTY_NOT_FOUND Then
select case strFFL
case 0
strFFLdesc = "2000 mixed"
case 1
strFFLdesc = "2000"
case 2
strFFLdesc = "2003"
case 3
strFFLdesc = "2008"
case else
strFFLdesc = "unknown"
End Select
WScript.Echo "Forest Functional Level is " & strFFLdesc

Err.Clear
End If


By Ceiling Fans @ Monday, July 26, 2010 9:37 PM

This seems like a great script and one that I would be interested in using. Is there any server requirements for running this? Any more info would be greatly appreciated.


You must be logged in to post a comment. You can login here
Copyright 2009 ActiveDir.org
Terms Of Use