Tuesday, August 23, 2005

Exporting and Importing Proxy addresses

We've been doing alot of modifications to the proxy addresses of our user accounts via scripts. We also had an ADC issue which caused roughly 1/3 of our mailboxes to become disconnected. This was especiallly problematic because when you reconnect a mailbox it's proxy addresses are re-generated and any custom/friendly addresses are lost. So, I think it's a good idea to document a simple way to export and import proxy addresses. This will also work for any other attribute.
Here's how:

Ldifde -d "DC=domain,DC=com" -s DC_Name -r "(&(mailnickname=*))" -l proxyAddresses -f proxies.txt

The query above will generate the following output to proxies.txt
----- Begin File: proxies.txt-----
dn: CN=Teo\, Heras,OU=Users,DC=lab,DC=microsoft,DC=com
changetype: add
proxyAddresses: X400:c=US;a= ;p=Microsoft;o=Lab;s=Heras;g=Teo;
proxyAddresses: SMTP:Teo_Heras@microsoft.com
----- End File-----

Additional attributes besides proxy addresses should be added next to "-l" (comma seperated).

Reimporting will require the manipulation of the output file as follows:
----- Begin File: proxies.txt -----
dn: CN=Teo Heras,OU=Users,OU=West Chester,OU=Corporate,DC=cablelab,DC=comcastlab,DC=com
changetype: modify <---- change from add to modify
replace: proxyAddresses <---- This was added
proxyAddresses: SMTP:Teo_Heras@Comcast.com
proxyAddresses: X500:/O=Comcastlaborg/OU=Lab-CDC/cn=Recipients/cn=theras0000
proxyAddresses: X400:c=US;a= ;p=Comcastlaborg;o=Lab-CDC;s=Heras;g=Teo;
- <---This is critical and the log file will tell you
----- End File -----

Finally, we'll import the file by doing the following:
c:\ldifde -i -f proxies.txt -s my_dc -j c:-i means import, -j c:\ is the path to log file


A large file may be hard to modiy, so I wrote a script that parses through the log file and writes the attributes back to AD. There are definately better alternatives (such as restoring AD to a lab and using VB to synchronize attributes), but it's useful to see how to parse through the output and use VBScript functions to pull the values you need.

----------SCRIPT----------
'This script will parse through the ldif export:
'and write back the proxy addresses

Option Explicit
Const ForReading = 1
Const ADS_PROPERTY_UPDATE = 2
'Define Proxy address Array
Dim arrProxyAddresses
Dim arrToWrite()
Dim objFSO, objDictionary, objTextFile, strTextfile, arrTextFile, strTextLine, objUser, strPriMail
Dim strUsrDN,strProxyAddresses, colKeys, strKey, intsize, strProxyAddress, intPriMailCount
Dim strUserDNLen, intFirstPipeLoc, intSecPipeLoc, intProxyLength, strProxyAddressArr, intFullProxyLen

set objFSO = CreateObject("Scripting.FileSystemObject")
Set objDictionary = CreateObject("Scripting.Dictionary")
set objTextFile = objFSO.OpenTextFile("c:\proxies.txt", ForReading)
strTextfile = objTextFile.ReadAll
'Fills each array entry with a line from the LDIF export.
arrTextfile = Split(strTextfile, VbCrLf)

'Loop through array and fill dictionary object
For Each strTextLine In arrTextfile
'The logic below leaves strUsrDN populated until a blank line is detected
'A blank line means the next entry is being read.
If InStr(strTextLine, "dn:") Then
strUsrDN = strTextLine
Elseif InStr(strTextLine, "proxyAddresses:") Then

'Ensure that the line doesn't just contain proxyaddress: I've seen notepad break this line placing the value on the line below.
If Len(strTextLine) = 16 Then
MsgBox "Error on " & strUsrDN
WScript.Quit
End If

'Check for a primay smtp address
If instr(strTextLine, "SMTP:") Then
intPriMailCount = 1
End If

'As long as a proxy address is detected, append all proxy addresses found
'The loop begins by checking whether or not the strProxyAddresses field is blank
If strProxyAddresses = "" Then
'Write the first proxy address without the delimeter. Otherwise when we call the split
'Function we will have a null value for the firs one.
strProxyAddresses = strTextLine
Else
strProxyAddresses = strProxyAddresses & "|" & strTextLine
End If
Elseif strTextLine = "" Then
'Check that the user object has a primary smtp address to apply
If intPriMailCount = 0 Then
MsgBox strUsrDN & " does not have a primary SMTP address."
WScript.Quit
End If
'When a blank line is detected it means the first LDIF entry has been read.
'write to the dictionary object and clear all variables
objDictionary.add strUsrDN, strProxyAddresses
'Clear out variables. When empty they are used for validation and they should be empty when the
'loop begins.
strProxyAddresses = ""
strUsrDN = ""
intPriMailCount = 0
End If

Next

'Loop through dictinary object, parse content, and write to user account.
colKeys = objDictionary.keys
For Each strKey In colKeys
'Parse through the userDN value
strUserDNLen = Len(strKey)
strUsrDN = Mid(strKey, 5, strUserDNLen)
strProxyAddresses = objDictionary.Item(strKey)
arrProxyAddresses = Split(strProxyAddresses, "|")
intsize = 0
For Each strProxyAddress In arrProxyAddresses
'Strip "proxyaddress:" - the length of proxyaddress: is 17
strProxyAddress = Mid(strProxyAddress, 17, Len(strProxyAddress))
'Proxy addresses have to be written as an array, so after stripping out the
'proxyaddress: string we'll create a new array with the values needed
ReDim Preserve arrToWrite(intsize)
arrToWrite(intsize) = strProxyAddress
'Keep track of the primary proxy address so that it can be written to the mail attribute later
If instr(strProxyAddress, "SMTP:") Then
'Use Mid to strip out SMTP:
strPriMail = Mid(strProxyAddress,6,Len(strProxyaddress))
End If
intsize = intsize + 1
Next

'Here's what I'll be writing to the user object
Set objUser = GetObject("LDAP://" & strUsrDN)
MsgBox "Writing to " & objUser.DistinguishedName
objUser.putex ADS_PROPERTY_UPDATE,"proxyAddresses", arrToWrite
objUser.SetInfo
objuser.put "mail", strPrimail
objUser.SetInfo
Next

----- End Script -----

KB Articles:
How to Modify a User's E-mail addresses by Using Ldifde
http://support.microsoft.com/?kbid=313823

How to import and Export Directory Objects to Active Directory
http://support.microsoft.com/kb/q237677/