Adding external contacts to the #Lync addressbook

There are some scenarios where it would be nice to be able to add external contacts to the Lync addresse so that they are searchable for everyone in the organization. Or at least external in the sence that the contact has a sip domain that isn’t supported in the Lync topology.

One such scenario could be an integration with an internal Cisco Telepresence solution.

The way to solve this is to add a contact object to AD that has the msRTCSIP-PrimaryUserAddress attribute populated, and the contact should be added to the address book on the next synchronization pass. I’ve made a script to create this kind of object:

Note that displayName is not required, but if you don’t add it the contact will only display the sipadress in the Lync client. I guess it’s also possible to append other AD attributes to the user such as telephoneNumber.

I got a question about telephoneNumber as well, so I’ve added it as an optional parameter in the script.
Download latest version here – Contains both versions and an example .csv

Or copy the sourcecode:


#####################################################################################
 # New-SipContact.ps1
 #
 # Creates a contact object in AD that will be included in Lync/OCS address books.
 #
 #
 # Passing parameters:
 # .New-SipContact.ps1 -cn "John Spencer" -OUpath "OU=SIPContacts,DC=contoso,DC=com" -sipaddress "john.spencer@litwareinc.com" -displayname "John Displayname Spencer"
 #
 # Written by Tom-Inge Larsen (http://www.codesalot.com)
 #
 #####################################################################################
 param($cn,$OUpath,$sipAddress,$displayName="",$telephoneNumber="")

$fullpath= "LDAP://" + $OUpath
 $SIPContactOU = [ADSI]$fullpath

$SIPContact = $SIPContactOU.create("contact", "cn=" + $cn)
 $SIPContact.Put("Description","SIP Contact Object")
 $SIPContact.Put("msRTCSIP-PrimaryUserAddress", "sip:" + $sipAddress)
 if ($displayName -ne "") {
 $SIPContact.Put("displayName", $displayName)
 }
 $SIPContact.Put("msRTCSIP-PrimaryUserAddress", "sip:" + $sipAddress)
 if ($telephoneNumber -ne "") {
 $SIPContact.Put("telephoneNumber", $telephoneNumber)
 }
 $SIPContact.setInfo()
 

I’ve also created one to bulk create contacts from a .csv file


#####################################################################################
 # New-SipContactBulk.ps1
 #
 # Creates a contact object in AD that will be included in Lync/OCS address books.
 #
 #
 # Passing parameters:
 # .New-SipContactBulk.ps1 -OUpath "OU=SIPContacts,DC=contoso,DC=com" -csv "c:newcontacts.csv"
 #
 #
 # Written by Tom-Inge Larsen (http://www.codesalot.com)
 #
 #####################################################################################
 param($OUpath,$csv)

$fullpath= "LDAP://" + $OUpath
 $SIPContactOU = [ADSI]$fullpath

$contacts = Import-Csv -path $csv -header "cn","displayName","sipaddress"

foreach ($contact in $contacts) {

$SIPContact = $SIPContactOU.create("contact", "cn=" + $contact.cn)
 $SIPContact.Put("Description","SIP Contact Object")
 $SIPContact.Put("msRTCSIP-PrimaryUserAddress", "sip:" + $contact.sipaddress)
 if ($contact.displayname -ne "") {
 $SIPContact.Put("displayName", $contact.displayName)
 }
 $SIPContact.setInfo()
 }

The example csv file contains this:

John Spencer,,john.spencer@litwareinc.com
Spencer John,Spencer Displayname John,spencer.john@litwareinc.com

24 thoughts on “Adding external contacts to the #Lync addressbook

  1. Good stuff Tom-Inge

    Had quite a hard time finding the msRTCSIP-PrimaryUserAddress information for getting Lync Client to pick up a “contact” object!

  2. Hey Tom, Good stuff. I need to get hold of the CSV file which doesn’t appear to be linked correctly, could you fix that so I can grab it?
    Thanks a bunch!

  3. Hey

    Seems that wordpress.com has disallowed .csv files in media libraries, so I’ve added the file as code in the post instead. Just paste the contents into a .csv file.

    TI

  4. How can I bulk edit existing contacts and add the msRTCSIP-PrimaryUserAddress? Another caveat is their SIP addresses do not match their email addresses.

  5. If it’s not that many I guess the easiest would be to just use ADSI edit. If it is a lot of them it probably would be better to script it.

    You won’t be able to use the .create() method, so something like this

    $objUser = [ADSI]”LDAP://localhost:389/cn=MyerKen,ou=HR,dc=NA,dc=fabrikam,dc=com”
    $objUser.Put(“msrtcsip-primaryuseraddress”, “newsipaddress@domain.com”)
    $objUser.SetInfo()

    So you would have to modify the script a bit to pull the entire object instead of creaing one in an OU.

    That sipaddrss and emailaddress isn’t equal is only an issue for users, not contacts.

  6. Hi Tom, We have made contacts like this, for all of our video endpoints, and it Works great. To make it easier for our users, I wanted to ad a picture of a videoconferencing system to the contact’s thumbnailphoto attribute, just like we do with all of our lync/Outlook users. However, I’m unable to make the picture show, when seaching from Lync.

    Any ideas?

    /Michael

  7. Great script!
    I did notice the the zip file there is a , missing from the param section but is correct in your post.
    File is
    param($cn,$OUpath,$sipAddress,$displayName=””$telephoneNumber=””)

    Needs to be
    param($cn,$OUpath,$sipAddress,$displayName=””,$telephoneNumber=””)

  8. Hi Tom,
    Gr8 article, but how about the conferencing scenario, if the phone number is listed in GAL , and the name is displayed for peer to peer PSTN call, but if the same guy joins the dial-in conference the name is not displayed but it shows Guest. is this expected behavior?

    Thanks,
    Satya Prakash

    1. Hi

      Yes, I believe that diailiners will be listed as “Guest” as long as they haven’t authenticated themselves as a leader using their PIN.

      Tom-Inge

  9. This works great for Lync clients, but the contact or an existing Exchange resource that includes the msRTCSIP-PrimaryUser attribute doesn’t show up in the address book on a Lync Room System. Is there another attribute we need to set for it to show up there? We have Lync Room System resource accounts that are Lync enabled show up in those contact lists.

      1. Ok thanks. Hoping some others on the thread may have some experience. So far, I’ve not had any success. I can see active Lync accounts associated with resource mailboxes (AD account enabled) in there, but not the contacts. Trying to figure out which bit makes it show up.

  10. Hi Tom,

    I hope you don’t mind, but I have extended your script in order to add a few different fields and provide some error feedback when importing a large number of contacts via a CSV. I have added different fields into our contacts that are of use to us, however, I don’t think Lync/SfB uses them as a method of search – I’m not sure if you can add additional fields for address book searches.

    We are integrating multiple Lync/SfB system via PEXIP so that user can dial their VC system across multiple research and education establishments. Still, this is what I have:

    #####################################################################################
    # Modified-SipContactBulk.ps1
    #
    # Creates a contact object in AD that will be included in Lync/OCS address books.
    #
    #
    # Passing parameters:
    # .\Modified-SipContactBulk.ps1 -OUpath “OU=Contacts,OU=Users and Groups,OU=My Business,DC=example,DC=com” -csv “Systems.csv”
    #
    #
    # Written by Tom-Inge Larsen (http://www.codesalot.com)
    # Modified by Chris Swinney (http://www.wvn.ac.uk)
    #
    #####################################################################################
    param($OUpath,$csv)

    $SIPDomain = “pexip.example.com”
    $fullpath= “LDAP://” + $OUpath
    $SIPContactOU = [ADSI]$fullpath

    $contacts = Import-Csv -path $csv # the header parameter is only required if there is NO header oin the CSV -header “OrganisationName”,”SystemName”,”Domain”,”School”,”VideoSystemAddress”,”PersonalOrShared”,”Notes”

    try {
    foreach ($contact in $contacts) {
    # Concatinates the ‘SystemName’ and ‘Domain’ form the CSV to form a Comman Name for a contact (CN)
    $cn = $contact.SystemName + “@” + $contact.Domain

    # Creates a new Contact instance based on the CN
    $NewContact = $cn

    # Checks is the Contact already exsist in AD
    $ContactCheck = Get-ADObject -Filter ‘cn -eq $NewContact’

    #If the contact dosn’t exsit, then create the contact
    if ($ContactCheck -eq $null) {

    #Setup ‘SystemType’ – Personal or Shared
    if ($contact.PersonalOrShared -eq “S”) {$SytemType = “Shared “}
    ElseIf ($contact.PersonalOrShared -eq “P”) {$SytemType = “Personal “}
    Else {$SytemType = “”}

    #Create the Contact in the relevant OU
    $SIPContact = $SIPContactOU.create(“contact”, “cn=” + $cn)

    #Add Description based on System Type.
    $SIPContact.Put(“Description”,$SytemType + “Videoconferncing (VC) Endpoint Contact”)

    #Note – for each field that may be black, its we need an IF statement otherwise the import will fail.
    #Add notes – usefull for IP address or somesuch
    if ($contact.notes -ne “”) {$SIPContact.Put(“notes”, $contact.notes)}

    #Add SIP Address
    $SIPContact.Put(“msRTCSIP-PrimaryUserAddress”, “sip:” + $contact.VideoSystemAddress + “@” + $SIPDomain)

    #Set Display Name
    if ($contact.displayname -ne “”) {$SIPContact.Put(“displayName”, $contact.displayName)}
    Else {$SIPContact.Put(“displayName”, $contact.SystemName + ” – ” + $contact.Domain)}

    #Set Name and Organsiation, for easier searching
    #$SIPContact.Put(“name”, $contact.SystemName)
    $SIPContact.Put(“givenName”, $contact.SystemName)
    $SIPContact.Put(“sn”, $contact.Domain)
    $SIPContact.Put(“company”, $contact.OrganisationName)

    #If the School field is filled, the add the School to the Department property
    if ($contact.School -ne “”) {$SIPContact.Put(“department”, $contact.School)}

    $SIPContact.setInfo()
    }
    }
    }
    Catch {
    write-host “Caught an exception:” -ForegroundColor Red
    write-host “Exception Type: $($_.Exception.GetType().FullName)” -ForegroundColor Red
    write-host “Exception Message: $($_.Exception.Message)” -ForegroundColor Red
    write-host “Problem with ” + $cn
    }

    The CSV then looks like this (with Headers):
    OrganisationName,SystemName,Domain,School,VideoSystemAddress,PersonalOrShared,Notes,displayName,,,
    Organisation 1,room123,example.com,,004411111111,S,192.168.1.1,,,,
    Organisation 2,roomABC,fobar.com,,004422222222,S,172.16.1.1,Room ABC – Foobar,,,

  11. Ok, here is the sanitised script with modifications:

    #####################################################################################
    # Modified-SipContactBulk.ps1
    #
    # Creates a contact object in AD that will be included in Lync/OCS address books.
    #
    #
    # Passing parameters:
    # .\Modified-SipContactBulk.ps1 -OUpath “OU=Contacts,OU=Users and Groups,OU=My Business,DC=example,DC=com” -csv “Systems.csv”
    #
    #
    # Written by Tom-Inge Larsen (http://www.codesalot.com)
    # Modified by Chris Swinney (http://www.wvn.ac.uk)
    #
    #####################################################################################
    param($OUpath,$csv)

    $SIPDomain = “pexip.example.com”
    $fullpath= “LDAP://” + $OUpath
    $SIPContactOU = [ADSI]$fullpath

    $contacts = Import-Csv -path $csv # the header parameter is only required if there is NO header oin the CSV -header “OrganisationName”,”SystemName”,”Domain”,”School”,”VideoSystemAddress”,”PersonalOrShared”,”Notes”

    try {
    foreach ($contact in $contacts) {
    # Concatinates the ‘SystemName’ and ‘Domain’ form the CSV to form a Comman Name for a contact (CN)
    $cn = $contact.SystemName + “@” + $contact.Domain

    # Creates a new Contact instance based on the CN
    $NewContact = $cn

    # Checks is the Contact already exsist in AD
    $ContactCheck = Get-ADObject -Filter ‘cn -eq $NewContact’

    #Setup ‘SystemType’ – Personal or Shared
    if ($contact.PersonalOrShared -eq “S”) {$SytemType = “Shared Videoconferencing (VC) Endpoint Contact”}
    ElseIf ($contact.PersonalOrShared -eq “P”) {$SytemType = “Personal Videoconferencing (VC) Endpoint Contact”}
    Else {$SytemType = “”}

    #Setup Display Name
    if ($contact.displayname -eq “”) {$contact.displayname = $contact.SystemName + ” – ” + $contact.Domain}

    #Setup SIP Address
    $SIPAddress = “sip:” + $contact.VideoSystemAddress + “@” + $SIPDomain

    #If the contact dosn’t exsit, then create the contact
    if ($ContactCheck -eq $null) {

    #Create the Contact in the relevant OU
    $SIPContact = $SIPContactOU.create(“contact”, “cn=” + $cn)

    #Add Description based on System Type.
    $SIPContact.Put(“Description”,$SytemType)

    #Add notes – usefull for IP address or somesuch
    if ($contact.notes -ne “”) {$SIPContact.Put(“notes”, $contact.notes)}

    #Add SIP Address
    $SIPContact.Put(“msRTCSIP-PrimaryUserAddress”, $SIPAddress)

    #Set Display Name
    $SIPContact.Put(“displayName”, $contact.displayName)

    #Set Name and Organsiation, for easier searching
    #$SIPContact.Put(“name”, $contact.SystemName)
    $SIPContact.Put(“givenName”, $contact.SystemName)
    $SIPContact.Put(“sn”, $contact.Domain)
    $SIPContact.Put(“company”, $contact.OrganisationName)

    #If the School field is filled, the add the School to the Department property
    if ($contact.School -ne “”) {$SIPContact.Put(“department”, $contact.School)}

    #Write back the Contact info to the AD object
    $SIPContact.setInfo()
    }

    Else {
    #Modify the local instace of the AD Contact Object
    $ContactCheck.DisplayName = $contact.displayname
    $ContactCheck.Description = $SytemType
    $ContactCheck.givenName = $contact.SystemName
    $ContactCheck.sn = $contact.Domain
    $ContactCheck.company = $contact.OrganisationName

    if ($contact.School -ne “”) {$ContactCheck.department = $contact.School}
    if ($contact.notes -ne “”) {$ContactCheck.department = $contact.notes}

    Set-ADObject -Instance $ContactCheck
    Set-ADObject -Identity $ContactCheck -Add @{“msRTCSIP-PrimaryUserAddress”=$SIPAddress}

    }
    }
    }
    Catch {
    write-host “Caught an exception:” -ForegroundColor Red
    write-host “Exception Type: $($_.Exception.GetType().FullName)” -ForegroundColor Red
    write-host “Exception Message: $($_.Exception.Message)” -ForegroundColor Red
    write-host “Problem with ” $cn
    }

  12. Hey Tom/All,

    Has anyone tried this with O365? We are importing into AD, and DIrSync see the change, but make no updates to the Tenants? Are there addition filed that need to be added as a minimum for on-line contacts (O365 is not my bag)?

    Cheers

    CHris

  13. How did you create the CSV? I dont know how to create the CSV 😦

    I tried >>> get-mailbox -resultsize unlimited | fl Name, Name, UserPrincapalName | export-csv myListOfAdUsers.csv

    but it didnt work

    1. I think this is something you will have to do manually. There is an example CSV in Toms zip, but depending on what information you want to import, will depend on the headings you have in the CSV.
      I would assume that this info does NOT exist in active directory already, that’s the point of the script. I personally used multiple data sources, including TMS, and our custom booking system, then manually modified the file to ensure that the data was in the correct format. For this is used Excel.

  14. FWIW, I this is supported in O365 or Hybrid models, which is a shame. You can, of course, create new “fake” AD users, but this might not be considered ideal. If anyone know any different, please let me know.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s