Update Lync Client Location with IP GeoLocation

Use IP geolocation data to keep you Lync client location up to date.
Use IP geolo­ca­tion data to keep you Lync client loca­tion up to date.

I reg­u­lar­ly bounce around on dif­fer­ent net­works and vpn con­nec­tions. I got tired of man­u­al­ly set­ting the loca­tion in Lync and found myself just ignor­ing it alto­geth­er. After doing some pok­ing around, I decid­ed to throw a pow­er­shell script togeth­er to just do the dirty work for me.

The script uses Telize for geoip data and DNSO­Mat­ic Telize for the exter­nal IP. The script requires the Microsoft.Lync.Model.dll from the Lync 2013 SDK (15.0.4603.1000 as of this post). You can find the Lync Client 2013 SDK here.

You can then add an event trig­ger to fire off the script when you con­nect to a net­work: On an event; On event - Log: Microsoft-Win­dows-Net­workPro­file/­Op­er­a­tional, Source: Microsoft-Win­dows-Net­workPro­file, Event ID: 10000

Note: I adjust­ed my per­son­al ver­sion to detect when I’m on my com­pa­ny’s net­work so it won’t inter­fere with Lync set­ting to loca­tion for our office. Always test and under­stand the ram­i­fi­ca­tions if using in a pro­duc­tion envi­ron­ment.

Gist on Github: Update-LyncLocation.ps1

#requires –Version 3.0
<#
.SYNOPSIS 
Updates Lync 2013 Client's location information with geolocation data based on internet ip address.

.DESCRIPTION
The Update-LyncLocation.ps1 script updates the Lync 2013 Client's location information. It uses the 
Telize web service to determine your external ip address and then queries Telize to collect publicly 
available geolocation information to determine your location. That data is then parsed into usable 
information and published to the Lync client.

****Requires Lync 2013 SDK.**** The SDK install requires Visual Studio 2010 SP1. To avoid installing 
Visual Studio, download the SDK, use 7-zip to extract the files from the install, and install the MSI 
relevant to your Lync Client build (x86/x64).

.INPUTS
None. You cannot pipe objects to Update-LyncLocation.ps1.

.OUTPUTS
None. Update-LyncLocation.ps1 does not generate any output.

.NOTES
Author Name:   Andrew Healey (@healeyio)
Creation Date: 2015-01-04
Version Date:  2015-01-26

.LINK
Author: https://www.healey.io/blog/update-lync-client-location-with-geolocation
Lync 2013 SDK: http://www.microsoft.com/en-us/download/details.aspx?id=36824
IP Geolocation Web Service: http://www.telize.com/

.EXAMPLE
PS C:\PS> .\Update-LyncLocation.ps1

#>


# Verify lync 2013 object model dll is either in script directory or SDK is installed
$lyncSDKPath = "Microsoft Office\Office15\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Model.dll"
$lyncSDKError = "Lync 2013 SDK is required. Download here and install: http://www.microsoft.com/en-us/download/details.aspx?id=36824"

if (-not (Get-Module -Name Microsoft.Lync.Model)) {
    if (Test-Path (Join-Path -Path ${env:ProgramFiles(x86)} -ChildPath $lyncSDKPath)) {
        $lyncPath = Join-Path -Path ${env:ProgramFiles(x86)} -ChildPath $lyncSDKPath
    }
    elseif (Test-Path (Join-Path -Path ${env:ProgramFiles} -ChildPath $lyncSDKPath)) {
        $lyncPath = Join-Path -Path ${env:ProgramFiles} -ChildPath $lyncSDKPath
    }
    else {
        $fileError = New-Object System.io.FileNotFoundException("SDK Not Found: $lyncSDKError")
        throw $fileError
    } # End SDK/DLL check
    try {
        Import-Module -Name $lyncPath -ErrorAction Stop
    }
    catch {
        $fileError = New-Object System.io.FileNotFoundException ("Import-Module Error: $lyncSDKError")
        throw $fileError
    } # End object model import
} # End dll check

# Check if Lync is signed in, otherwise, nothing to do
$Client = [Microsoft.Lync.Model.LyncClient]::GetClient()
if ($Client.State -eq "SignedIn") {
    # Get external ip address
    $WanIP = (Invoke-WebRequest -Uri "http://ip4.telize.com/" -UseBasicParsing).Content
    # Get geolocation data
    $data = Invoke-WebRequest -Uri "http://www.telize.com/geoip/$WanIP" -UseBasicParsing | ConvertFrom-Json
    $data
    ### Format the location from returned geolocation ###
    ###    More Info Here: http://www.telize.com/     ###
    # Deal with oddities like anonymous proxies
    if (($data.continent_code -eq "--") -or ($data.continent_code -eq $null)) {$location = "$($data.isp)"}
    # If the city and state are not null, make it City, State
    elseif (($data.region_code -ne $null) -and ($data.city -ne $null)) {$location = "$($data.city), $($data.region_code)"}
    # If the city is null but state/region has a value, make it Region, Country
    elseif (($data.region -ne $null) -and ($data.city -eq $null)) {$location = "$($data.region), $($data.country_code3)"}
    # Else, just output the Country
    else {$location = "$($data.country)"}

    # Update location in Lync
    $LyncInfo = New-Object 'System.Collections.Generic.Dictionary[Microsoft.Lync.Model.PublishableContactInformationType, object]'
    $LyncInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::LocationName, $location)
    $Self = $Client.Self
    $Publish = $Self.BeginPublishContactInformation($LyncInfo, $null, $null)
    $Self.EndPublishContactInformation($Publish)
}
else {
    Write-Warning "Lync must be signed in."
} # End client sign-in check