Friday, January 14, 2011

Push contacts to exchange users

Hi All,

I'm using Exchange 2003, Outlook 2007/2003. Is there a way to push a set of contacts to users? I would prefer to not use the GAL and I really don't want to send csv files for them to import.

Any help is appreciated.

EDIT:

If someone has a great method of managing contacts with a mobile workforce, I'd love to hear that as well.

  • You could have somebody code up a script to copy all of the contacts from a public folder (CSV file, etc) into a "Contacts" folder in each user's mailbox as one possible method. (A script that accesses the mailboxes through WebDAV would be fairly easy to do this with.) I'm not aware of an off-the-shelf product that does that.

    If you don't want to go to that level of work, consider putting the contacts into a public folder and either asking the users to mark it a "Favorite" or asking them to copy the contacts into their mailboxes. Obviously, this isn't a "push".

    Dayton Brown : Option #1 might be the best solution. I'm trying to figure out if I really want to go to those lengths though.
  • What about just emailing the contacts to the users? I guess they would probably need to add them using Outlook, but it seems like it would be pretty easy to just email them to the users.

    Dayton Brown : In a normal environment that is exactly what I would do. Unfortunately, these users are mostly mobile, mostly non-technical, and need extreme assistance levels. Just trying to make it as easy as possible for them.
    Russ Warren : Ahh, my favorite kind.
  • I don't know if this is one would apply to your problem but you could set up a eGroupware system.

    This is free and open source. You can sync it with a lot of diffrent mobile phones and of course with any outlook or exchange. You then have to sync your system with the installation to get your contact online. Then every user needs to configure a client for syncing. As mentioned there are a lot of different plugins for mobile phones.

    All contacts then get pushed to your clients phones. You can group them and set global permissions. Maybe this would help. But be warned, it's still hard to get eGroupware running and set up correctly.

    From cb0
  • This is an extremely mangled vbscript I've been using to push a sub-folder of contacts from one user to a list of users provided in a text file:

    snServername = "exchange"
    mnMailboxname = "user.to.copy.from"
    mndestmailbox = ""
    
    Const ForReading = 1
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objTextFile = objFSO.OpenTextFile _
        ("c:\scripts\users.txt", ForReading)
    Do Until objTextFile.AtEndOfStream
        mndestmailbox = objTextFile.Readline
    
        wscript.echo ""
        wscript.echo mndestmailbox
    
    
    SourceURL = "http://" & snServername & "/exchange/" & mnMailboxname & "/contacts/folder to copy/"
    DestinURL = "http://" & snServername & "/exchange/" & mndestmailbox & "/contacts/folder to copy/"
    set req = createobject("microsoft.xmlhttp")
    
    set CDOSession = CreateObject("MAPI.Session")
    strProfile = snServername & vbLf & mnMailboxname
    CDOSession.Logon "",,, False,, True, strProfile
    set RDOSession = CreateObject("Redemption.RDOSession")
    RDOSession.MAPIOBJECT = CDOSession.MAPIOBJECT
    set cfCalendarFolder1 = RDOSession.GetSharedDefaultFolder(mndestmailbox, 10)
    For Each fld In cfCalendarFolder1.Folders
        If fld.name = "folder to copy" Then 
         Set cfCalendarFolder = fld 
        End if
    next
    
    colbblob = Collabblobget()
    wscript.echo colbblob
    QueryMailbox(colbblob)
    
    wscript.echo "Done"
    
    Loop
    
    
    Sub QueryMailbox(colbblob)
    
    strQuery = "<?xml version=""1.0""?><D:searchrequest xmlns:D = ""DAV:"" xmlns:R=""http://schemas.microsoft.com/repl/""><R:repl><R:collblob>" & colbblob & "</R:collblob></R:repl>"
    strQuery = strQuery & "<D:sql>SELECT ""DAV:href"", ""urn:schemas:httpmail:subject"", ""http://schemas.microsoft.com/mapi/proptag/x0fff0102"",""http://schemas.microsoft.com/repl/repl-uid"" "
    strQuery = strQuery & " FROM scope('shallow traversal of """
    strQuery = strQuery & SourceURL & """') Where NOT ""urn:schemas:calendar:instancetype"" = 2 AND NOT ""urn:schemas:calendar:instancetype"" = 3 AND ""DAV:ishidden"" = False AND ""DAV:isfolder"" = False "
    strQuery = strQuery & "</D:sql></D:searchrequest>"
    req.open "SEARCH", SourceURL, false, "", ""
    req.setrequestheader "Content-Type", "text/xml"
    req.setRequestHeader "Translate","f"
    req.send strQuery
    If req.status >= 500 Then
       wscript.echo "Status: " & req.status
       wscript.echo "Status text: An error occurred on the server."
    ElseIf req.status = 207 Then
       wscript.echo "Status: " & req.status
       wscript.echo "Status text:  " & req.statustext
       set oResponseDoc = req.responseXML
       set oNodeList = oResponseDoc.getElementsByTagName("d:collblob")
       For i = 0 To (oNodeList.length -1)
        set oNode = oNodeList.nextNode
            colblob =  oNode.Text
        Collabblobset(colblob)
       Next
       set idNodeList = oResponseDoc.getElementsByTagName("f:x0fff0102")
       set replidNodeList = oResponseDoc.getElementsByTagName("d:repl-uid")
       set replchangeType = oResponseDoc.getElementsByTagName("d:changetype")
       for id = 0 To (idNodeList.length -1)
        set oNode1 = idNodeList.nextNode
        set oNode2 = replidNodeList.nextNode
        set oNode3 = replchangeType.nextNode
        select case oNode3.text
         case "new" call Copyapt(Octenttohex(oNode1.nodeTypedValue),oNode2.text)
         case "delete" wscript.echo oNode3.text
                wscript.echo oNode2.text
                DeleteContact(oNode2.text)
         case "change" Wscript.echo "Change"
                call DeleteContact(oNode2.text)
                call Copyapt(Octenttohex(oNode1.nodeTypedValue),oNode2.text)
        end select
       next
    Else
       wscript.echo "Status: " & req.status
       wscript.echo "Status text: " & req.statustext
       wscript.echo "Response text: " & req.responsetext
    End If
    
    End Sub
    
    function Collabblobget()
    
    xmlreqtxt = "<?xml version='1.0'?><a:propfind xmlns:a='DAV:' xmlns:cp='" & SourceURL & "'><a:prop><cp:collblob/></a:prop></a:propfind>"
    req.open "PROPFIND", DestinURL, false, "", ""
    req.setRequestHeader "Content-Type", "text/xml; charset=""UTF-8"""
    req.setRequestHeader "Depth", "0"
    req.setRequestHeader "Translate", "f"
    req.send xmlreqtxt
    set oResponseDoc = req.responseXML
    set oCobNode = oResponseDoc.getElementsByTagName("d:collblob")
    For i1 = 0 To (oCobNode.length -1)
       set oNode = oCobNode.nextNode
       Collabblobget = oNode.Text   
    Next
    
    End function
    
    Sub Collabblobset(colblob)
    xmlstr = "<?xml version=""1.0""?>" _
    & "<g:propertyupdate " _
    & "    xmlns:g=""DAV:"" xmlns:e=""http://schemas.microsoft.com/exchange/""" _ 
    & "    xmlns:dt=""urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"" " _
    & "    xmlns:cp=""" & SourceURL & """ " _
    & "    xmlns:header=""urn:schemas:mailheader:"" " _
    & "    xmlns:mail=""urn:schemas:httpmail:"">  " _
    & "    <g:set>  " _
    & "        <g:prop>  " _
    & "            <cp:collblob>" & colblob & "</cp:collblob>  " _
    & "        </g:prop>  " _
    & "    </g:set>  " _ 
    & "</g:propertyupdate>" 
    
    req.open "PROPPATCH", DestinURL, False
    req.setRequestHeader "Content-Type", "text/xml;"
    req.setRequestHeader "Translate", "f"
    req.setRequestHeader "Content-Length:", Len(xmlstr)
    req.send(xmlstr)
    
    
    end sub
    
    Sub CopyApt(messageEntryID,ReplID)
    set objapt = CDOSession.GetMessage(messageEntryID)
    set objCopyapt = objapt.copyto(cfCalendarFolder.EntryID)
    objCopyapt.Unread = false
    objCopyapt.Fields.Add "0x8542", vbString, ReplID,"0820060000000000C000000000000046"
    objCopyapt.Update
    Set objCopyapt = Nothing
    wscript.echo objapt.subject
    
    end Sub
    
    Sub CopyContact(messageEntryID,ReplID)
    set objcontact = objSession.getmessage(messageEntryID)
    set objCopyContact = objcontact.copyto(pfPublicFolderID,objpubstore.ID)
    objCopyContact.Unread = false
    objCopyContact.Fields.Add "0x8542", vbString, ReplID,"0820060000000000C000000000000046"
    objCopyContact.Update
    Set objCopyContact = Nothing
    wscript.echo objcontact.subject
    
    end Sub
    
    Sub DeleteContact(replUID)
    
    strQuery = "<?xml version=""1.0""?><D:searchrequest xmlns:D = ""DAV:"">"
    strQuery = strQuery & "<D:sql>SELECT ""DAV:Displayname"""
    strQuery = strQuery & " FROM scope('shallow traversal of """
    strQuery = strQuery & DestinURL & """') Where ""http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/0x8542"" = '" & replUID & "' AND ""DAV:isfolder"" = False "
    strQuery = strQuery & "</D:sql></D:searchrequest>"
    req.open "SEARCH", DestinURL, false
    req.setrequestheader "Content-Type", "text/xml"
    req.setRequestHeader "Translate","f"
    req.send strQuery
    wscript.echo req.responsetext
    If req.status >= 500 Then
       wscript.echo "Status: " & req.status
       wscript.echo "Status text: An error occurred on the server."
    ElseIf req.status = 207 Then
       wscript.echo "Status: " & req.status
       wscript.echo "Status text:  " & req.statustext
       set oResponseDoc = req.responseXML
       set oNodeList = oResponseDoc.getElementsByTagName("a:href")
       For i = 0 To (oNodeList.length -1)
        set oNode = oNodeList.nextNode
        wscript.echo oNode.text
        req.open "DELETE", oNode.text, false
        req.send 
        wscript.echo "Status: " & req.status
       Next
    Else
       wscript.echo "Status: " & req.status
       wscript.echo "Status text: " & req.statustext
       wscript.echo "Response text: " & req.responsetext
    End If
    
    end Sub
    
    
    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)))
        else
        aOut(i-1) = hex(ascb(midb(OctenArry,i,1)))
        end if
      Next 
      Octenttohex = join(aOUt,"")
    End Function
    

    I can't remember where I found the initial script, but I will post if I find it. I think this one will only work on Exchange 2003. Also, for this to work properly, the user must have the folder to copy already in the correct place (but empty).

    Dayton Brown : I'll try this out and see if it works. This might do the trick.
    moshen : You only should need to edit some of the parameters at the beginning. Please forgive the messiness, this script sort of evolved over time and has not been reworked for distribution. Some parameters to edit: exchange server name, user to copy from, text file of users to copy to, the text file must have 1 username per line, and do a find/replace for "folder to copy".
    From moshen
  • Don't push them out, share them...

    I found this article that has a decent explanation of how to share contacts through a Public Folder. And this other article with a little more information, plus more on what can be done with public folders.

    Once it is setup works great.

0 comments:

Post a Comment