Skip to main content

Update Lync Client Location with IP GeoLocation

·3 mins

I regularly bounce around on different networks and vpn connections. I got tired of manually setting the location in Lync and found myself just ignoring it altogether. After doing some poking around, I decided to throw a powershell script together to just do the dirty work for me.

The script uses Telize for geoip data and DNSOMatic Telize for the external 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 trigger to fire off the script when you connect to a network: On an event; On event - Log: Microsoft-Windows-NetworkProfile/Operational, Source: Microsoft-Windows-NetworkProfile, vent ID: 10000

Note: I adjusted my personal version to detect when I’m on my company’s network so it won’t interfere with Lync setting to location for our office. Always test and understand the ramifications if using in a production environment.

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://healey.io/writing/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

Related

C# Express - Create a Dummy or Placeholder Windows Service for Monitoring

The IT ecosystem is rich with network monitoring systems (NMS). Each NMS has different capabilities, costs, and purposes in life. It is commonplace for me to come into a business that has invested in an NMS that doesn’t fit all their needs. You might ask, “What does this have to do with creating a Windows service?” Here is the scenario that brought this up. A client has a monitoring solution for their Windows servers and some basic network up/down stats. Their internet connection had been flaky for a month or two. As we worked with their ISP, their connection continued to stay up but latency would spike and often drop packets. The monitoring never sees the link as down but the level of service is degraded and mostly unusable. The ISP can quickly reset the ports and fix the issue, but we want to know right when this happens to minimize downtime.

Installing Exchange 2010 Service Pack 1 Fails At Mailbox Role: Database is mandatory on UserMailbox.

In a recent incident, an Exchange server had a complete volume failure during testing. Exchange 2010 was reinstalled but when installing Service Pack 1, it failed upgrading the Mailbox Role. Upon reviewing the log, I found the following line: Database is mandatory on UserMailbox. Property Name: Database The error doesn’t explain the problem very well but it is basically saying that there is a UserMailbox without a database, which should never happen. The failure of the volume and subsequent reinstall of 2010 left the arbitration mailboxes (and one or two user mailboxes) orphaned. Most of the suggestions to resolve this problem list doing things like deleting the system mailboxes and running “setup.com /PrepareAD”. After looking around, I was able to parse together a few other options and find a fix.

Exchange 2007+: Aliases have invalid data

Twice in the past two weeks, I have come across Exchange 2003 to Exchange 2007 migrations which went uncompleted. In both cases, I received the following error(s) when trying to view the properties of a recipient with spaces in its alias or when viewing the properties of the offline address book: The properties on have invalid data. If you click OK, default values will be used instead and will be saved if you do not change them before hitting Apply or OK on the property page. If you click cancel, the object will be displayed read-only and corrupted values will be retained. The following values have invalid data: Alias. WARNING: Object has been corrupted and it is in an inconsistent state. The following validation errors have been encountered: WARNING: is not valid for Alias. Set- : is not valid for Alias. Exchange 2003 would allow an administrator to put spaces in the Alias attribute. That poses a problem for 2007 which is strict about the characters it allows in this attribute. In Exchange 2007 the following characters are considered valid: Strings formed with characters from a to z (uppercase or lowercase), digits from 0 to 9, !, #, $, %, &, ‘, *, +, -, /, =, ?, ^, _, `, {, |, } or ~. But, no spaces.