Script for Bulk Import of Active Directory Site Links

I wrote this script when I was frequently deploying replication topologies for large geographies. Rather than manually creating them one at a time, I would set everything up in a spreadsheet and then import the spreadsheet. There are a few assumptions made in this script. You may need to modify it a bit if the assumptions don’t work for you.

  • Site links only contain two sites
  • The replication schedule will be copied from another site link

The input file is expected to be in tab separated format which you can export from Excel (it’s one of the options under File>Save As). The order of the fields is documented at the top of the script. The Hub Site and Spoke Site fields should contain the common name (CN) of the relevant site objects. The Schedule field should contain the common name (CN) of the site link to duplicate the schedule from.

Note: I typically recommend creating template site links for each unique schedule which are only used for scripting. When you create the site link with Active Directory Sites & Services, the tool will require you to pick sites to include in that site link. Once you’re done configuring the template, use a tool like ADSI Edit to remove the sites from the siteList attribute of the template site link. It is fine to have site links with no sites in Active Directory – they simply won’t do anything.
'==========================================================================
' NAME: Import Site Links from TSV
'
' AUTHOR: Brian Desmond, brian@briandesmond.com
' DATE  : 3/13/2008
'
' COMMENT: 
'
' TEMPLATE FILE FORMAT (tab delimited):
' Hub Site	Spoke Site	Cost	Frequency	Schedule
'==========================================================================

Option Explicit

If WScript.Arguments.Count < 1 Then
	WScript.Echo "Specify an input file name as an argument to this script."
	WScript.Quit(1)
End If 

Dim fso
Set fso = WScript.CreateObject("Scripting.FileSystemObject")

Dim importFile
importFile = Trim(WScript.Arguments(0))

If Not fso.FileExists(importFile) Then
	WScript.Echo "Input file not found"
	WScript.Quit(1)
End If 

Dim configNcDn
configNcDn = GetConfigNc()

Dim inputReader
Set inputReader = fso.OpenTextFile(importFile)

Dim line
While Not inputReader.AtEndOfStream
	line = inputReader.ReadLine
	
	Dim tokens
	tokens = Split(line, vbtab)
	
	Dim hubSite
	Dim spokeSite
	Dim cost
	cost = -1
	Dim frequency
	frequency = -1
	Dim templateSchedule
		
	hubSite = tokens(0)
	spokeSite = tokens(1)
	cost = tokens(2)
	frequency = tokens(3)
	templateSchedule = tokens(4)
	
	Dim hubSiteDn
	Dim spokeSiteDn
	
	hubSiteDn = GetSiteDn(configNcDn, hubSite)
	spokeSiteDn = GetSiteDn(configNcDn, spokeSite)
	
	If hubSiteDn = "" Or spokeSiteDn = "" Or templateSchedule = "" Or cost = -1 Or frequency = -1 Then
		WScript.Echo "FAIL: " & line
	Else
		Dim siteLinkName
		siteLinkName = hubSite & " - " & spokeSite

		On Error Resume Next 		
		Dim siteLinkObj
		Set siteLinkObj = GetObject("LDAP://" & GetSiteLinkDn(configNcDn, siteLinkName))
		
		Dim siteLinkExists 
		
		If Err.Number <> 0 Then 
			siteLinkExists = False 
			Err.Clear
		Else
			siteLinkExists = True 	
		End If 
		On Error GoTo 0 

		On Error Resume Next 
		Dim templateLinkObj
		Set templateLinkObj = GetObject("LDAP://" & GetSiteLinkDn(configNcDn, templateSchedule))
		Dim schedule
		
		If Err.Number <> 0 Then
			WScript.Echo "Template " & templateSchedule & " not found"
			Err.Clear
			On Error GoTo 0 
		Else
			On Error GoTo 0 
			schedule = templateLinkObj.get("schedule")
		End If
	
		If siteLinkExists = False Then ' we are making a new one not updating an existing one
			Dim transports
			Set transports = GetObject("LDAP://CN=IP,CN=Inter-Site Transports,CN=Sites," & configNcDn)
			
			Dim newObj
			Set newObj = transports.Create("siteLink", "cn=" & siteLinkName)
			
			newObj.Put "cost", cost
			newObj.Put "replInterval", frequency
			
			newObj.PutEx 2, "siteList", Array(hubSiteDn, spokeSiteDn)
			newObj.put "schedule", schedule
			
			newObj.SetInfo
			
			WScript.Echo "SUCCEED: " & siteLinkName
		Else
			siteLinkObj.Put "cost", cost
			siteLinkObj.Put "replInterval", frequency
			
			siteLinkObj.PutEx 2, "siteList", Array(hubSiteDn, spokeSiteDn)
			siteLinkObj.put "schedule", schedule
			
			siteLinkObj.SetInfo
			
			WScript.Echo "SUCCEED: " & siteLinkName
		End If 
	End If 
Wend

inputReader.Close
WScript.Echo "Complete"

Function GetConfigNc()
	Dim rootDse
	Set rootDse = GetObject("LDAP://RootDSE")
	
	Dim configNc
	configNc = rootDse.get("configurationNamingContext")
	
	Set rootDse = Nothing
	
	GetConfigNc = configNc
End Function

Function GetSiteDn(configNc, siteName)
	Dim cnxn
	Set cnxn = WScript.CreateObject("ADODB.Connection")
	cnxn.Provider = "ADsDSOObject"
	cnxn.Open "Active Directory Provider"
	
	Dim cmd
	Set cmd = WScript.CreateObject("ADODB.Command")
	cmd.ActiveConnection = cnxn
	
	cmd.CommandText = "<LDAP://" & configNc & ">;(&(objectcategory=site)(cn=" & siteName & "));distinguishedName;subtree"
	cmd.Properties("Page Size") = 100
	cmd.Properties("Timeout") = 30
	cmd.Properties("Cache Results") = False
	
	Dim rs
	Set rs = cmd.Execute
	
	While Not rs.eof 
		GetSiteDn = rs.fields("distinguishedName").Value
		
		rs.MoveNext
	Wend 
	
	rs.close
	cnxn.Close
	
	Set rs = Nothing
	Set cmd = Nothing
	Set cnxn = Nothing 
End Function 

Function GetSiteLinkDn(configNc, siteLinkName)
	Dim cnxn
	Set cnxn = WScript.CreateObject("ADODB.Connection")
	cnxn.Provider = "ADsDSOObject"
	cnxn.Open "Active Directory Provider"
	
	Dim cmd
	Set cmd = WScript.CreateObject("ADODB.Command")
	cmd.ActiveConnection = cnxn
	
	cmd.CommandText = "<LDAP://" & configNc & ">;(&(objectcategory=siteLink)(cn=" & siteLinkName & "));distinguishedName;subtree"
	cmd.Properties("Page Size") = 100
	cmd.Properties("Timeout") = 30
	cmd.Properties("Cache Results") = False
	
	Dim rs
	Set rs = cmd.Execute
	
	While Not rs.eof 
		GetSiteLinkDn = rs.fields("distinguishedName").Value
		
		rs.MoveNext
	Wend 
	
	rs.close
	cnxn.Close
	
	Set rs = Nothing
	Set cmd = Nothing
	Set cnxn = Nothing 
End Function

Leave a Reply

Your email address will not be published. Required fields are marked *