Tuesday, May 24, 2005

Script to Copy Public folder contacts to a mailbox's Contacts folder using CDO 1.2

Somebody asked today about this script I posted a while ago about copying contacts between mailbox's using the vCard method in CDOEX. While this script works okay for simple contacts if you have rich contacts where you have lots of additionally information that CDOEX doesn't include in the vcard stream then it can be a lot of work going through and copying each one of these Mapi properties manually (which I've already done for a few props in this script). The other option if you want to do this in a script is to use MAPI via CDO 1.2. The big advantage of using MAPI is that you will retain all the MAPI properties as they are on the object and also you can run the script remotely where the CDOEX script must be run locally on the Exchange server. The actually question was about copying contacts from a public folder to a mailbox so I've come up with a script that will do this using MAPI via CDO 1.2. To use this script you need to know the entryID for the public folder where the contacts are stored .You can find the folder entryID using something like Outlookspy or Mdbvu32 (from the exchange support tools directory) or I've included a simple utility script that will output what the entryID of a store item is from the OWA URL. This simple utility script look like.

OWAURL = "http://server/public/folder"
set xmlobjreq = createobject("Microsoft.XMLHTTP")
xmlreqtxt = "<?xml version='1.0'?><a:propfind xmlns:a='DAV:'

xmlobjreq.open "PROPFIND", OWAURL, false, "", ""
xmlobjreq.setRequestHeader "Content-Type", "text/xml; charset=""UTF-8"""
xmlobjreq.setRequestHeader "Depth", "0"
xmlobjreq.setRequestHeader "Translate", "f"
xmlobjreq.send xmlreqtxt
set oResponseDoc = xmlobjreq.responseXML
set oNodeList = oResponseDoc.getElementsByTagName("d:x0FFF0102")
For i = 0 To (oNodeList.length -1)
set oNode = oNodeList.nextNode
wscript.echo Octenttohex(oNode.nodeTypedValue)

Function Octenttohex(OctenArry)
ReDim aOut(UBound(OctenArry))
For i = 1 to UBound(OctenArry) + 1
if len(hex(ascb(midb(OctenArry,i,1)))) = 1 then
aOut(i-1) = "0" & hex(ascb(midb(OctenArry,i,1)))
aOut(i-1) = hex(ascb(midb(OctenArry,i,1)))
end if
Octenttohex = join(aOUt,"")
End Function

The script that copies the contacts from a public folder to mailbox's contact folder looks like I've put a downloadable copy of both scripts here. Remember these scripts do a dumb copy so they will just copy or duplicate contacts with no intelligence so used inappropriately they could cause duplicate contact issues.

servername = "servername"
mailbox = "mailbox"
pubContactsfolderid = "00000....etc"
set objSession = CreateObject("MAPI.Session")
strProfile = servername & vbLf & mailbox
objSession.Logon "",,, False,, True, strProfile
Set objcontactfolder = objSession.getdefaultfolder(5)
Set objInfoStore = objSession.GetInfoStore(objSession.Inbox.StoreID)
Set objpubstore = objSession.InfoStores("Public Folders")
set objpubContactsfolder = objSession.getfolder(pubContactsfolderid,objpubstore.id)
for each objcontact in objpubContactsfolder.messages
set objCopyContact = objcontact.copyto(objcontactfolder.ID,objInfoStore.ID)
objCopyContact.Unread = false
Set objCopyContact = Nothing
wscript.echo objcontact.subject


Craig Humphrey said...

Hi Glen,

just came across you post as I'm trying to do something similar.

We want to extract all our users contacts, so that we can build a white-list for our 3rd party mail filter.

I've got a modified version of your code working against our Ex2003 server, but it only has access to the mailbox of the logged in user.

I'm not particularly ofey with impersonation, but is there a way I can use that to access other mailboxes?

Of if I use an account that has delegated authority (at least over contacts), would that be enough to do what I want?


Glen said...

To grant one account access to all other mailboxes on a store have a look at http://www.infinitec.de/articles/exchange/grantmailboxaccess.aspx which give a good method for doing so.

Delegation should also work it just a lot of more work to setup.


Anonymous said...

Thanks Glen. Much appreciated! Great work! Solves a big problem for us!

Gun said...

This's a nice tip. What if i want to create a new contact entry and save it?
I try making a new contact using CreateObject("CDO.Person") but it doesn't have the .copyto method

Nick Adams said...
This comment has been removed by the author.
Nick Adams said...

On exchange 2007+ you can use the exchange management shell to get the entryID:

get-publicfolder -identity \{publicfolder}\{contact folder} | format-list