Friday, October 16, 2015

Capturing Network Traceroutes in Lync/Skype for Business

If you've ever trolled through the QoEMetrics database (a great way to while away a lazy Saturday afternoon) you may have come across a few tables that made you go "What the....?".  One table that might catch your eye is the TraceRoute table.  In all likelihood,  this table is probably empty, which might make you wonder what it's for.

Microsoft publishes pretty detailed information on the structure of the QoEMetrics database where you can find information about the TraceRoute table in this Technet article.

As you can surmise by the name, this table is meant to capture trace route information for calls. However, the table description gives no information on how to enable this feature.

You can enable this by adding a custom policy entry to a Lync/SfB client policy.  Custom policy entries are used to enable features that Microsoft has decided not to make too obvious for users for one reason or another.  If you've got custom policy entries, you'll see them at the top of the list when you run Get-CsClientPolicy.  If you have several of those, you can see it in a more readable format by typing (Get-CsClientPolicy policyname).PolicyEntry

The relevant policy entry for enabling tracerouting is called "EnableTraceRouteReporting", and you can add it to a client policy by running the following commands:
$x = New-CsClientPolicyEntry -Name "EnableTraceRouteReporting" -Value "TRUE"

$y = Get-CsClientPolicy -Identity policyname

Set-CsClientPolicy -Instance $y
Whoever has that policy applied to them will now publish trace route reports to the QoEMetrics database. However, the built-in Lync/SfB reports do not expose this anywhere, so you would only want to turn this setting on if you are using a 3rd party reporting and analytics tool such as Event Zero's UC Commander (FYI, if you don't already know, I work for them).

Sample screenshot of traceroute data as it appears in UC Commander

This can be very useful to help track down network issues in the call path. This won't necessarily point the finger at a specific switch or router in every circumstance, but it can help.

Be warned that enabling this will add a bit of size to your QoEMetrics database. The additional data isn't huge but its not negligible either.  You should carefully evaluate the impact before turning this on.

Monday, September 28, 2015

Response Groups Stop Responding

Our company (Event Zero - makers of the best Skype for Business analytics software out there BTW) relies on Skype for Business response groups for our sales and support queues.  Last week, I noticed that every single one of them on two separate pools were no longer accepting calls.  It wasn't a SIP trunk or mediation issue, because I couldn't get to them by directly entering in their SIP address in the Skype for Business client.  They appeared available (green presence) but would not accept calls. Snooper logs showed they were throwing 480 Temporarily Unavailable errors.

It was especially odd that it happened on two separate S4B pools at roughly the same time.  I tried numerous things, from restarting the RGS service on the affected servers to restarting the servers.  So, yeah, not a lot of tools in my RGS troubleshooting arsenal apparently.

What I found DID work, was to change the Tel URI of one of the workflows to a slightly different number, then changing it back.  Within a few minutes, that particular workflow started working again. 

Rather than doing the same thing to all 20-odd response groups (which would take a LOOONG time because the RGS Workflow web page is so slow), I created a Powershell script to do the same thing.

WARNING: Use script at your own risk. It worked fine for me, but hey I'm not a programmer. Also, this script will use the Description field of the workflow to store the original Tel URI of the response group.  Whatever is there now will get wiped out. You can do this script in other ways, but I was strapped for time and we weren't using the Description field for anything.
$Workflows = Get-CsRgsWorkflow 
Foreach ($WF in $Workflows)
 Write-Host "Adding dummy extension to " $WF.Name
 $WF.Description = $WF.LineURI
 $WF.LineURI = $WF.LineURI + ";ext=0"
 Set-CSRgsWorkflow -Instance $WF
Foreach ($WF in $Workflows)
 Write-Host "Reverting back to original number for " $WF.Name
 $WF.LineURI = $WF.Description
 Set-CSRgsWorkflow -Instance $WF

I don't know what caused the problem to start with, but at least this fixed it. Presumably, something happened to "break" the connection between RGS and the associated contact objects, and resetting the Tel URI re-linked them.

Hopefully, this might help others who come across the same thing. If anybody has any insight into why it broke, and why this fix worked, please enlighten me!

Friday, September 18, 2015

Testing Inbound PSTN Connectivity Directly from Lync/Skype for Business

File this one under "It's obvious once you think about it for even a second"...

I was recently attempting to get a SIP trunk working to a new Sonus gateway located in Event Zero's head office in Brisbane, Australia.  I wanted to test inbound calls to the gateway by calling one of our response group workflows.

Normally, I would pick up my mobile or home phone and dial the number to test, but since I was dialing Australia, and I'm a cheap bastard, I didn't want to do that.  It was also the middle of the night in Australia, so I couldn't get someone local to do it for me.  If I dialed the number from Skype for Business, then it would do a reverse-number lookup, find an internal match and route me to the response group internally without going through the PSTN, which wouldn't achieve my goal.

My goal was to route a call to our Australian response group via Skype for Business via the PSTN in the easiest, laziest, least-expensive-to-my-own-wallet way possible (this is sounding like an exam question).  Pick one of the following answers:
  1. Suck it up princess and eat the $2.05 it will cost to call Australia for a few seconds.
  2. Wake up someone in Australia at 2 in the morning, claiming its an emergency.
  3. Convince yourself that since outbound calls work fine, inbound should too.
  4. Use a trunk translation rule to route a dummy phone number to the correct destination.
  5. Give up and start drinking, because its Friday afternoon dammit!
The correct answer is #4 (although the judges will also accept #5).

If you've ever been at one of Doug Lawty's Enterprise Voice sessions at LyncConf or Ignite, you have probably seen his infamous diagram showing how a PSTN call works its way through the system.  To save you the pain, here the relevant details in a very small nutshell:
  1. Dialed number gets normalized to E.164
  2. Skype for Business does a reverse number lookup to see if there's an internal user or service that is assigned that number. 
  3. If there's a match, routes the call internally directly to the user/service.
  4. If there isn't an internal match, it finds a valid route through a PSTN trunk
  5. It applies any outbound number translation to make the number conform to local standards and sends it on its merry way out the gateway to the PSTN.
Since reverse number lookup happens before handing off the call to the routing engine, we can simply call a dummy PSTN number of our choosing, and once it reaches the trunk translation rule stage, change that dummy number back to the proper number assigned to the Response Group workflow.

In the above example, all I do is create a trunk translation rule to change the non-existent North American phone number +1 (555) 999-0000, and translate it to the proper number.  Once the call has progressed to the point where outbound translation is happening, Skype for Business won't be doing another reverse number lookup, so it will continue to route that number out to the PSTN, at which point it should route to the correct destination (which could be right back where it came from). 

So, a simple solution to overcome my unwillingness to waste money on stuff I don't have to.

Thursday, August 13, 2015

Selective Caller ID Blocking in Lync/Skype for Business

Once in a while, a customer asks how they can block caller ID on outgoing calls in Lync/Skype for Business. If they're interested in blocking caller ID on all calls, then the answer has always been simple: use the Alternate Caller ID field in Voice Routes.

Easy enough, right? But what if administrators want to give users the ability to selectively block caller ID at the individual call level?  When on the traditional PSTN, users in most places can enter a code prior to dialing the number if they want to block their caller ID.  In most North American markets, this code is usually *67.  So, a user could dial *6715552224444 and their caller ID would be blocked for that call.

In Lync/Skype for Business, you can replicate this functionality but it takes some work. Since the caller ID blocking feature is done at the route level, you will need to have a separate route for calls with an alternate caller ID.  For calls to use that route, you will need some unique signifier that would not occur in normal day-to-day dialing.

Since the caller ID block code you use on the PSTN should be unique, you can incorporate that into your dialplan, routes and trunk translation rules.  When I first tried this, I wanted to use *67 in my dialplan, but the Lync client didn't like the * so much. It threw up the virtual equivalent of giving me the finger and refused to work, so I had to go about it differently.  Thankfully, things have improved recently so that the Skype for Business client will happily accept the * (or # if you want).

My earlier version of this blog post simply put the *67 in front of the number and sent it through the system, stripping the *67 just before sending off to the PSTN.  Kevin Bingham from Cerium Networks suggested it might work by adding a custom parameter suffix, such as ;callerid=blocked (custom parameters are allowed by RFC3966).

So, after a bit of trial and error, I managed to make it work. This method is much nicer as it conforms to the standard RFCs and is fully E.164 compliant. Also, when someone types *67 and a number, it normalizes without showing the parameter suffix, which looks nicer to the user.

Here's a simplified example using the North American dialplan. First, you'll need a normalization rule in your dial plan that will accept the caller ID block code.
Pattern: ^\*67(\d{10})$
Translation Rule: +1$1;callerid=blocked

This will take any number that starts with *67 and is 10-digits long and translate it to +1 then the 10-digit number, followed by ;callerid=blocked. The client won't see this part of the normalization string.

Then you will need a special route that will accept numbers with that pattern and will apply the alternate caller ID:

Make sure you assign the appropriate PSTN gateway to the route and add the voice route to the appropriate PSTN Usages.

Finally, you will have to create a trunk translation rule on the selected trunk to strip the ;callerid=blocked from the dialed number before sending it out to the PSTN.

I've tested this using the latest Skype for Business server and client (as of August 2015), and the 5.4 firmware on a VVX 600 as well as a CX600 deskphone.  Let me know if this doesn't work on an older platform. I originally attempted this several years ago, and the Lync client (or server...can't recall), didn't deal with the *67 so well.

Incidentally, you might have issues with the alternate caller ID not being sent.  I've seen this on our own SIP provider.  Checking the SIP traces, I can see that I'm presenting the alternate caller ID as a P-Asserted-Identity, which is the way it should work, so my SIP provider seems to be ignoring it.

The example above used "callerid=blocked" as the custom parameter. You can name your custom parameter whatever you want as long as it is in lower case and uses the same format as ;parametername=value. Custom parameters have to also be placed after any ;ext= parameter.

As you might expect, I've incorporated this functionality into the Lync Optimizer.  Try it out and let me know how it works for you.

Wednesday, July 8, 2015

In-Call QoE Reports in Skype for Business

When a Lync or Skype for Business user is in a call, the client is continually capturing call quality data that is invaluable in helping diagnose call issues. There are lots of metrics that are recorded, like round-trip times, network jitter, packet loss and even things like "Insufficient CPU event ratio" that indicates the call quality was affected by a heavily loaded processor.

Prior to Skype for Business, all these call quality metrics were stored by the client until the end of the call, at which point it would send a summary report of this data via SIP.  This summary included minimum, maximums and averages for some metrics (such as round-trip times), and just an average for many others.  If you do a trace with OCSLogger, look for a SERVICE message after the final BYE message.  There will be one for each participant (assuming both users are in the same company). The SERVICE message body contains the quality report in XML format and looks something like this:
There's a LOT more than what I've shown here, but you get the idea
The Lync Server takes this information and sends it on to the monitoring database (QoEMetrics for those of you keeping track), at which point it's available for review.  It's because of this behaviour that you won't see any information about the call in Lync Monitoring Reports until the call is done.

For people who use Lync Monitoring Reports, having to wait for the end of the call before you see any data is a minor annoyance. For users of 3rd party tools such as Event Zero's UC Commander (full disclosure, I work for EZ), it's highly annoying. Tools such as UC Commander are able to see calls that are active at any given moment, which is great, but since the client holds the quality report tightly until the call is done, it is unable to provide much information about the call until the client sends off the report.  UC Commander makes sure to let you know this in a big red banner when you're looking at details on an active call (see below).

"Uh, yeah...I'm calling you about that.....accounting.....thing. It would be easier to explain in person."

Skype for Business changes things so that Skype for Business clients can report call quality while the call is active. You won't have to wait until the end of the call to see call quality data. The feature is off by default, but can be enabled via PowerShell using the following command:

Set-CsMediaConfiguration -Identity Global -EnableInCallQoS:$TRUE -InCallQoSIntervalSeconds x (where x is a digit from 1 to 65535).
You may have noticed the commands say QoS, when they really should say QoE. QoS is all about Quality of Service at the network layer, where QoE is Quality of Experience, which is what we're talking about here.  I flagged this during the beta, but was pretty much told to suck it up and live with it. 

Setting the interval to something like 1 second doesn't necessarily mean your network will be flooded with QoE reports every single second.  The client only sends this if there is a change detected.  So, in a stable network, you may not see many additional QoE reports. 

To turn this feature on, you require Skype for Business on the server-side, and the Office 2016 Skype for Business client (currently in beta at time of writing), NOT the Lync client with the Skype for Business UI patch.  I've heard that the Skype for Business patched version of Lync 2013 will eventually get this in a future patch.  Pretty much the only way to tell if you're running the Office 2016 version of Skype for Business is to look at the version number.  Patched Lync 2013 clients will have a version of 15.x.x.x, where the Office 2016 Skype for Business client will have a version of 16.x.x.x.

With this feature enabled, you can see call quality statistics while the call is active, which can be especially useful when the CEO is breathing down your neck complaining about the poor quality call he's on RIGHT THIS MINUTE.  Keep in mind that if you want to make good use of this, you have to use a 3rd party Skype for Business analytics tool that supports this feature, such as *cough cough* Event Zero's UC Commander.  

Thursday, June 18, 2015

Dealing with Overdialing in Lync/Skype for Business

If you've never heard the term "overdialing", you're not alone. I hadn't heard of the term either until Greig Sheridan mentioned the term to me one day. But after reading a few definitions on the web, I realized that I knew about it, but didn't know it had a name.  Granted, the definitions I found were all from Australian sites, so maybe its an Aussie thing. My Australian exposure has gone up dramatically since joining Event Zero back in February, so maybe it's to be expected, along with the increased incidents of me saying things like "mate", "throw another shrimp on the barbie", and "a dingo ate my baby."

Anyways..."overdialing" can be thought of as what happens when people try to dial a phone number with more digits than are actually allowed by the PSTN carrier.  This often pops up with numbers that are presented as words, like 1-800-BUYSTUFF, which has 1 too many digits/letters for the North American dial plan (all numbers are 11-digits long, including the 1).

A somewhat little known fact is that you can type the above example exactly like that in Lync/SfB and it will automagically translate the letters to the corresponding numbers and show the number 1-800-289-78333.  Again, notice its got one too many digits and hasn't normalized (note the lack of + sign at the beginning of the number).

The reason for this is because most typical normalization rules only match a very specific number of digits.  Take for example, this typical North American normalization rule and translation pattern for North American national numbers:

^1?(\d{10}) --> +1$1

For the uninitiated, this normalization rule will accept any 10-digit number, with or without a leading 1, and will translate it to a valid 11-digit North American national number.  So, if you dial 5552223333 or 15552223333, it will normalize it to +15552223333.

But if you dial one or more extra digits, it will no longer match the normalization rule and will just show the digits you typed. If you typed 55522233331, and try to dial that number in Lync/Skype for Business, it may or may not fail depending on how you created your route patterns. For example, if you've structured your route pattern to accept numbers without a leading plus sign, it would route through Lync/S4B (ie.  ^\+?\d+$ would accept any number of digits with or without a plus).  I don't advise this, because its messy and makes advanced routing decisions harder. Plus it goes against the general advice of E.164 EVERYWHERE.

If you allowed a number to get through to the PSTN with too many digits, the carrier will reject any extra digits and dial the number properly, but for systems like Lync/Skype for Business, you should take care to ensure you deal with overdialed numbers seamlessly.

To make sure any overdialed numbers are normalized correctly, a simple extra few characters added to the end of a normalization rule will fix the problem nicely. Using the first example, we simply add a \d* to signify "any number of digits", followed by a $ to signify the end of the string.  So, ultimately we have:

^1?(\d{10})\d*$ --> +1$1

Now, when we dial that same number with too many digits, we get the following properly formatted normalized result:

In the end, a simple change to an otherwise generic normalization rules can end up making your users' lives just a little bit easier.

Thanks to the aforementioned Greig Sheridan, who suggested I write a blog post around this esoteric topic. I owe you a Foster's, mate!

Friday, May 1, 2015

Address Book Normalization in Skype for Business

A constant problem with Enterprise Voice in Lync is the fact that phone numbers stored in Active Directory often are not stored in the E.164 format that Lync requires for proper functionality.  If the numbers aren't recognizable, then the Lync client won't show phone numbers like office, mobile or home numbers to other users. The best thing to do is to update all phone numbers in AD to conform to E.164 standards, but this is often not practical for many reasons.

In Lync Server 2013 and older, you could use a special oddly named text file called the Company_Phone_Number_Normalization_Rules.txt to normalize AD phone numbers to E.164 standards as they are being added to the Lync Address Book.  This saved administrators a lot of work, especially when they are unable to change the core numbers in AD.  However, the fact that you had to create this text file and place it in a certain folder on every Lync server was not the most effective way to manage address book normalization.

Thankfully, things have changed in Skype for Business to finally make address book normalization part of a new suite of PowerShell commands, *-CsAddressBookNormalizationConfiguration and *-CsAddressBookNormalizationRule (where * is the typical Get, Set, New).  The Company_Phone_Number_Normalization_Rules.txt is no longer necessary and is ignored in Skype for Business.

When you first install Skype for Business, it is populated by a default set of address book normalization rules, which you can see by typing:
You will get back the default set of rules stored in the Global config as below:
Description :
Pattern     : E164
Translation : null
Name        : Generic_E164
Description :
Pattern     : \++(\d+)[Xx]+(\d{1,15})
Translation : +$1;ext=$2
Name        : Generic_WithExtension
Description :
Pattern     : \++(\d+)ext[=]?(\d{1,15})
Translation : +$1;ext=$2
Name        : Generic_WithLongExtension
Description :
Pattern     : \++(\d+)EXT[=]?(\d{1,15})
Translation : +$1;ext=$2
Name        : Generic_WithLongExtensionUpper
Description :
Pattern     : \++(\d+)
Translation : +$1
Name        : Generic_All
In my opinion, these rules are not well-constructed.  Unless there is some hidden feature I'm not aware of, the E164 rule does absolutely nothing. (UPDATE 2015-Aug-13: Hany Elkady noted in the comments below that removing the E164 rule seemed to stop AD phone numbers already stored in E.164 format from appearing in the address book.  I personally haven't seen this occur but you might want to leave that rule in place.)  The other rules are oddly formatted. You can do the same in a much more flexible way with fewer rules. You can add/delete/modify rules to this by using:
To start with a clean slate, you might want to get rid of the default rules, by running Get-CsAddressBookNormalizationRule | Where {$_.Name -ne 'Generic_E164'} | Remove-CsAddressBookNormalizationRule.

For my typical North American address book file, I add the following rules (assumes North American numbers are stored as either 10 or 11 digits without the +):
New-CsAddressBookNormalizationRule -Parent Global -Name 'NANPA-10-Digit' -Pattern '1?([2-9]\d{9})' -Translation '+1$1' -Priority 0
New-CsAddressBookNormalizationRule -Parent Global -Name 'NANPA-10-Digit-Ext' -Pattern '1?([2-9]\d{9})\D+(\d+)' -Translation '+1$1;ext=$2' -Priority 1
For a more global approach, you might use something like:
New-CsAddressBookNormalizationRule -Parent Global -Name 'Global' -Pattern '((1[2-9]\d\d[2-9]\d{6})|([2-9]\d{6,14}))' -Translation '+$1' -Priority 0 
New-CsAddressBookNormalizationRule -Parent Global -Name 'Global-Ext' -Pattern '((1[2-9]\d\d[2-9]\d{6})|([2-9]\d{6,14}))\D+(\d+)' -Translation '+$1;ext=$2' -Priority 1
The rules you add will be determined by the format phone numbers are stored in Active Directory. It appears that the normalization rule engine hasn't changed since the older versions of Lync, which means that you will still have to enter your normalization rules exactly as you did with the old Company_Phone_Number_Normalization_Rules.txt.

As with older versions of Lync, you can force an update of the address book by running Update-CsAddressBook.  Any phone numbers that aren't normalized are stored in the Invalid_AD_Phone_Numbers.txt file in your address book share under \x-WebServices-x\ABFiles\00000000-0000-0000-0000-000000000000\00000000-0000-0000-0000-000000000000.

You can import existing rules from the Company_Phone_Number_Normalization_Rules.txt file by using the command Import-CsCompanyPhoneNormalizationRules.  The RTM upgrade process really should take care of this for you, but it doesn't appear to (at least for me, but I first did Skype for Business months ago).

With this post, I hope to never again have to type the oh-so-memorable filename Company_Phone_Number_Normalization_Rules.txt.

Thursday, February 12, 2015

Large Scale Extension Dialing in Lync

I was recently working a pretty large Enterprise Voice deployment that had more than a hundred sites located around the world. Every site used DIDs for their users phone numbers, but wanted to be able to reach every other site using a 3-digit site code, plus the last 4 digits of the user's phone number (total 7 digits). This would be pretty easy except for the following wrinkle: they wanted people within any one site to be able to dial just the last 4-digits of other people within that site, rather than the 7-digit "global" extension or full DID. To complicate matters, multiple sites had overlaps with the last 4 digits of their numbers.

Unfortunately, this meant that every single site would require their own dedicated Lync dial plan, with only one rule that is different from the other sites. Management of these sites can be a nightmare, especially when you consider what has to happen when a new site gets added. Not only do you have to add the other sites extension normalization rule to the new site, but every other site has to have their dial plans updated with the new site's extension normalization rule. With many sites, this can become difficult to manage.

Thankfully, Powershell can take a daunting task such as this and make it much easier. I've developed a process to manage large numbers of extension ranges that is scalable and easy to replicate at other sites. Of course, this being me, the core of it is based around Lync Optimizer generated rulesets, and the associated scripts assume you follow the same naming convention. So, without further ado....

For this particular company, I decided on a naming convention for 7-digit extension normalization rules that follow the format CountryID-StateProv-City-7Ext0x (eg. US-TX-Dallas-7Ext01, US-TX-Dallas-7Ext02 etc). 4-digit extension rules for specific sites use the format CountryID-StateProv-City-4Ext0x (eg. US-TX-Dallas-4Ext01).  Every site's dial plan would end up with a large number of 7Ext normalization rules, and a single 4Ext normalization rule specific to that site.

I kept a repository of 7-digit extension dialing rules for all sites, organized alphabetically in a manually created dialplan called ZZ-ExtensionList. This dialplan was only used for the scripts I used later to populate new site lists.

Each site used the Lync Dialing Rule Optimizer to generate rulesets for each site. I used the Extensions entry page to generate the local site's 7Ext0x normalization rule.  For this particular company, since we were using a 3-digit site code and the last 4-digits of the user's DID, the extension entry page looked something like this:

For the above example, the 3-digit site code is 350, and user's phone numbers are in the range +442055662000 to +442055662099.  The # of Ext Digits in DID field tells the Optimizer that only the last 4 digits of the 7-digit extension is actually part of the DID.

I ran the Optimizer generated script against the deployment as per usual, which generated the standard ruleset for the given site. Once complete, I opened the ZZ-ExtensionList dial plan and added the newly generated 7Ext0x rule(s) to the list, making sure to maintain alphabetical order.

I then ran the custom script AddExtensionsToDP.ps1 (see below) with the switch -DialPlan set to the name of the newly added dialplan (ie .\AddExtensionsToDP.ps1 -DialPlan UK-London) This script does two things. First, it adds all the extension dialing rules from ZZ-ExtensionList into the new dialplan. Secondly, it modifies the 7Ext0x rule(s) specific to the new site into a 4Ext0x rule(s). So, for the above example:
Original Pattern/Translation: ^350(20\d{2})$          -->    +44205566$1
New Pattern/Translation:       ^(?:350)?(20\d{2})$  -->    +44205566$1
The new pattern allows users within the site to either dial 20xx or 35020xx for other users within the site.


Once that script was done, then I ran the UpdateNormRules.ps1 script (shown below) with the -NormRuleBase switch to specify the name of the dial plan created at the beginning. (ie. .\UpdateNormRules.ps1 -NormRuleBase UK-London). This script adds the normalization rules for the new site to all the other site-specific dialplans, in the proper alphabetical order.


Once complete, the new site had all the existing site-level extension normalization rules for every other site, and all existing sites also had the new site's extension normalization rule inserted into their dial plans. This ensured that all sites could dial any other site using their site code and extension.

So, to summarize the workflow:
  1. Manually create an empty dialplan called ZZ-ExtensionList
  2. Generate a Lync Optimizer dialplan for your selected area, populating the Extensions using the appropriate format for your deployment. Make sure the Suffix is set to 7Ext01 (and 02 etc).
  3. Run the Lync Optimizer generated ruleset against your deployment.
  4. Copy the -7Ext0x rule(s) to the ZZ-ExtensionList dialplan ensuring proper alphabetical order.
  5. Run the AddExtensionsToDP.ps1 script to add all the extension rules in ZZ-ExtensionList to the new dialplan.
  6. Run the UpdateNormRules.ps1 to update all other dial plans with the newly created extension normalization rule.
  7. Repeat steps 2-6 as necessary.

Rinse and repeat for each new dial plan you want to add to your environment. This process along with the attached scripts should make managing large dial plans much simpler. As always, be cautious when running these scripts, as I can't be responsible for any issues this causes.  Always make a backup of your existing Lync EV environment before running these or any scripts provided by strange people who pretend they look like David Hasselhoff.

Monday, February 9, 2015

Out of the Gutter: The Ken Lasko Story, Part 3, Part II

One day in the late 1990's, I got a call from an old co-worker from my Microsoft days asking me if I wanted to help out on a 3-month long consulting job for the provincial government managing their Microsoft Mail 3.5 system. I told him that I've never even HEARD of MS-Mail, let alone know anything about it. He assured me that I'd be able to figure it out and strongly suggested that I give it a try. Since the pay I would get in three months was going to be as much as I was making at my current job in a year, I jumped at it.

So began my consulting career.

Working with this was as dirty as this package implies.
I started work with a third guy we both knew from Microsoft support and got a crash course in MS-Mail. Since there wasn't
all that much to it, it didn't take long. MS-Mail was a collection of "post offices" that worked more or less completely independently of any other post office.  There was no central management console, so you'd have to connect to each post office individually to do any maintenance or troubleshooting. The provincial government had more than 220 post offices in their deployment, so management was a nightmare. Since there was no central management to speak of, there was no way we could tell there was a problem unless we went and signed into every single post office to check the status of mail delivery, GAL synchronization and that sort of thing. Since that wasn't feasible, we operated in reactive mode, where we would wait for someone to call in to report an issue. We would then log into the affected post office, fix the issue and continue on.  We got pretty good at it, so our contract kept getting extended more and more.

The job proved to be both time-consuming and monotonous. We decided to figure out a way to make our job easier so we could free up time for web-surfing and game playing. My counterpart worked on developing a Windows service that would collect all the pertinent information from each post office and put it into a central repository.  I worked on a web-based front-end that would show us near real-time information from each post office.  Problems would be highlighted in red, and we got it to the point that you could just click on the red counter, and it would initiate the typically required fix for that issue.

After many months of development, we were at the point where we would show up to work, bring up the webpage, and quickly deal with any issues by literally clicking on a red button to trigger the required fixes on any number of post offices. Call volumes dropped dramatically, and we both realized we were sitting on a goldmine. We could have become rich if it weren't for an annoying software development from Microsoft called Exchange Server.

The provincial government had decided to start moving to Exchange Server 5.5 in 1999.  While we weren't directly involved in the design of the environment, we had our hands deep in the support and migration away from MS Mail. By the time the 21st century had arrived (well, not technically since it was still 2000), we were both pretty adept at working with Exchange Server 5.5.  Eventually, support moved to a central call centre far north of where we lived and our services were no longer needed. So 2.5 years after I left my previous job for that short, high-paying, 3-month consulting gig, I was looking for another job.

The same person who got me on the MS-Mail gig introduced me to the right people at what was then Software Spectrum, and I started work as a consultant. Soon after, Software Spectrum sold their consulting business to Buchanan Associates (now Buchanan Technologies). I primarily consulted on Active Directory and Exchange projects, and had my hand in quite a few of them over the years. I got to work in some pretty fun places, especially Bermuda, where I was on a Citrix and Exchange gig with our IBM partner for several months.

In 2007, my boss at the time said that he wanted me to become the company expert in Office Communications Server (OCS).  The first thing I said was "OK. What's OCS?". The second thing I said after I found out what OCS did was "You want me to be the instant messaging expert???" At the time, Exchange had flirted with including some IM capabilities, but it was never used by many in the corporate world.  IM was seen as something used by kids.  I had images of "OMG Ponies!!!" and "LOL" and thought my boss was trying to make me quit my job.

When I dug in deeper into OCS, I saw there was some telephony integration capabilities and became intrigued, mostly because I had no idea how you could use your computer to make telephone calls. When Office Communications Server 2007 R2 came out, we jumped aboard in a big way and moved a chunk of our users over to it for all their telephony.  OCS, and then Lync became my sole focus, and I moved entirely away from Exchange and AD consulting.

My first go at the Optimizer was a VBScript HTA program.
Around 2010, I thought it might be a good idea to start blogging some of the things I couldn't find answers for about Lync. At the time, I thought I was late to the blogging party. My first post was in fact titled "Late to the Party".  I also began work on a locally run version of what would become the Lync Dialing Rule Optimizer to deal with the odd local vs. long distance conundrum that exists in North America.

Fast-forward five years, and my blog is quite heavily read, I've spoken at numerous events and the Lync Optimizer now supports 100 countries. I became the Lync Practice Manager for Buchanan Technologies and was overseeing how we deliver Lync to our customers. I always felt that Buchanan took care of me, and made sure I was happy in my career. Life was busy, but good.

But along came David Tucker from Event Zero, riding in on a white stallion with the promise of greater things. After much whining and dining, I finally decided to make the jump from Buchanan Technologies, a consulting company with 500 people worldwide, where I spent 15 years of my life to the Event Zero team.

If you don't know Event Zero and their phenomenal Dossier product line, you really should check it out. The best way I can describe it is "Lync Monitoring Reports on 'roids, but without the rage". It extends the not-so-real-time, slow to respond, frustrating, and hard to use reports that comes with Lync, into something that provides real-time, useful and easy-to-get-to reports on all aspects of Lync activity. There are also numerous other add-ons that can really make your Lync deployment work better for you.

I've been brought on to help drive Event Zero Dossier deployments, and ensure clients are getting the most out of their Lync deployments through effective reporting.

For me to leave my Buchanan Technologies "family" after 15 years, you know that I must have seen something special in Event Zero, and no, it wasn't the fact that Dave loves to cuddle on cold winter nights (which don't happen often in Australia).

My big career switch made me somewhat nostalgic, which led me to doing this series. There weren't nearly as many explosions or top-secret espionage capers as I would have hoped to have achieved at this point in my life, but there is still time.  Maybe the next chapter in this series will deliver on that....

Until then......adios!

Monday, February 2, 2015

Out of the Gutter: The Ken Lasko Story, Part 3, Part I

Part 3, Part I - Tech Support Hijinks

In the spring of '94, I went to a local job fair to look for a summer job that was different than working at the 1 hour photo lab as I had done previous summers. After browsing a while, and leaving my resume at a few places, I came across the Microsoft booth. They were looking for technical support people for their Canadian office. I felt this was the perfect opportunity for me. I figured with my TA experience, I would be a shoe-in for the job. I excitedly explained all this to the people manning the booth, and I must have made a good enough impression, because in April of 1994, I got hired to work at Microsoft as a technical support engineer.

I was thrilled to get the opportunity to work for such a big company. When I got the job, I was told that I would be supporting MS Word 6.0. Having never used Word 6.0 before (I had always used WordPerfect), I was concerned. So, I did what any self-respecting computer guy in the 90's did, I found a copy of Windows and Word 6.0 on the still young Internet, installed these not-so-legal copies on my computer and gave myself a crash course in Word 6.0.

I saw variations of this pose from my managers all too often.
I didn't think I was ready by the time I started my first day at MS. Thankfully, instead of supporting Word, I was assigned to support MS-DOS 6.2. Having lots of experience with MS-DOS, I was relieved. For the next while, I supported MS-DOS 6.2, which consisted mostly of editing people's CONFIG.SYS and AUTOEXEC.BAT files so they could free up enough memory to run whatever program they needed. Keep in mind, there was no such thing as remote desktop back then. All this was done by coaching the user over the phone. Slow and time-consuming work to be sure, but I enjoyed the atmosphere. I had some great bosses and co-workers at the time, and the workplace was fun and lighthearted. You could often see other guys on calls popping up over their cubicle walls waving at one another. I moved around a lot, even while tethered to a desktop PC with an audio headset.  I would stand on my desk, lie on the floor, or wander as far from my cubicle as my headset cable (or was it a leash?) would allow.

As with most tech support jobs, it involved a lot of sitting.  At lunch, you'd go down to the cafeteria, eat and sit some more, then go back and sit at a desk again.  To keep fit during the summer, I decided to try rollerblading. Having never rollerbladed before, I strapped them on in the office and rolled around the cubicle farms to learn the basics. Soon afterwards, there was a "No Rollerblading" policy instituted, which may be my only legacy from those days.  Rather than spend my lunch hour sitting in the cafeteria, I would go out and rollerblade as far away as I could go in 30 minutes, turn around and head back. I'd grab a shower, which sometimes wouldn't "take" on some of those hot days, and I'd sweat my way through the next few calls.

I had so many CD-ROMs that I used a bunch of old ones as a Halloween
costume.  Meet CD-MAN!!!
I made sure I took full advantage of the employee purchase program, which allowed you to buy pretty much anything from Microsoft's catalog at greatly reduced prices. I ordered copies of just about every CD-ROM based product MS had at the time, including things like Encarta, Cinemania, World of Flight, even Julia Child's cooking guide at 1/10th the cost of retail. I recall an offer where you could buy Visual C++ for $50, and it would come with a SCSI CD-ROM drive, complete with SCSI interface card. I used the CD-ROM drive and SCSI card, but tossed the rest.

When fall of 1994 came around, my contract was extended. I decided to delay my final university year to continue working at Microsoft, since it was too good an opportunity to pass up. Over time, I got assigned to the Windows 3.1 queue, then the Windows for Workgroups 3.11 queue, where I got my first taste of working with TCP/IP (a nightmare at the time). We got introduced to early builds of "Chicago", which would become Windows 95, the biggest consumer OS play Microsoft had done up until then. I remember copying weekly builds onto 15 or more 1.44 MB floppy disks to install on my computer at home. It was pretty neat to see the progression of features and stability as time moved on.

All the OS support guys underwent extensive training on Windows 95 in preparation for what we
thought was going to be a very busy time when it was first released to the public. I can remember the excitement building as the release date inched closer. We once got involved in the media blitz by going to a local computer tradeshow where we offered to install betas of Windows 95 on any customer-facing PC that was available in a vendor's booth. At the time, IBM was pushing OS/2 Warp as an alternative to Windows 95, and IBM people were walking around doing the same thing. I remember installing Windows 95 on one PC at a vendor booth, while an IBM guy installed Warp on a PC beside it in a sort of geeky showdown. A small crowd gathered to watch as Windows 95 smoothly installed and worked flawlessly, while the poor IBM guy was sweating through issue after issue. I don't know if he ever got it going.

On the day Windows 95 finally released, I was sitting in my cubicle waiting for the onslaught of
Even the Hoff loved Windows 95
calls. We heard about the lines at stores snaking out the doors. At lunch we went out and marvelled at the sight of so many people buying Windows 95. I've never seen it before or since. Back at work, we twiddled our thumbs. The calls were trickling in at a slow rate, but most of us sat idle. We were all wondering if Windows 95 was so stable and easy to use, that nobody was having issues. At around 5pm, as people got home and presumably started installing Windows 95 in excitement, the call volume went up dramatically. Within 30 minutes, we went from idle to full tilt with long wait times for the large number of users waiting in the queues. We churned through the issues day after day, but it wasn't too long before call counts settled into a new level of "normal call volumes".

With fall of 1995 approaching, I debated whether to stay at Microsoft of return to university to finish my final semester. I didn't see the point since I felt that I had started a good career at Microsoft, and all I would get is a piece of paper. I confided to my boss, who had the absolute best advice ever: "What's 4 months out of the rest of your life?"  So, with that, I went back to university and got my bachelors degree. While I was at school, my MS boss was wonderful in that he let me work the queues the odd day or weekend, even though I was sure they didn't really need me.

When I finally finished university, I returned full-time to Microsoft, but I felt that something was different. I had my university degree, but here I was still doing the same technical support I was doing before. I needed a change, plus the commute was starting to wear on me.

In the spring of 1996, I decided to take a job as a "sales engineer" for a PC card company based out
of the my home city. If you were around laptops back then, things like built-in modems and network cards just weren't an option. You had to use credit card sized packages called PCMCIA cards (or simply 'PC Cards') to get these functions. Laptops of the era usually had 2 or more of these slots. Need a modem? Go buy a PCMCIA modem card. Need a network card? Buy a PCMCIA network card. Our company had an edge in that we had the world's first combination network/modem card. These playing-card sized devices had an interesting playing card-based motif that definitely caught people's attention.

My job was to travel the US and Canada helping the salespeople with the technical aspects of their PCMCIA cards. For a 20-something guy, this was a sweet gig. I got to go to some pretty cool places across the continent with some fun people. This company also had a 3-port networking hub dongle that you could use to create a simple ad-hoc network with other laptops. You could daisy-chain these things together to add more laptops to your network. Our favourite thing to do was to throw network cables between the seats on an airplane so we could play multiplayer Quake during cross-country trips.

I was at this particular job for a few years, when a chance call from an old colleague from my Microsoft days turned my career into another direction that led directly to where I am today.

Continue reading the dramatic conclusion - "You want me to be the expert on WHAT????"

Thursday, January 29, 2015

Out of the Gutter: The Ken Lasko Story, Part 2

Part 2 - Higher Learning

Through most of high school, I was a solid C student. I did the minimum effort required to get by without raising the ire of my parents or teachers. I was more focused on having fun without giving much thought to the future.

It was on a cool, cloudy spring day in 1989 when I made the decision to go along with a bunch of friends on a road trip to check out some universities in Southwestern Ontario. I was in Grade 12 and probably should have been thinking about what university to apply to, but I really wasn't. Our school system was on the verge of eliminating Grade 13, so there were some who would head off to college/university after Grade 12, and others who would wait another year and go through Grade 13.

So, we all piled into a few cars and made the 3 hour road trip down the 401 past Toronto to check out
Me and my car. KITT never liked being second-billed. I'm not
sure what I'm holding in my hand, but it looks large!
3 universities in one day. The first one was an arts focused university, which I knew I would never go to. The second was a university well-known for its math and computer departments. We did the campus tour, but I never got a good vibe from it. It felt cold and sterile. The third university was well-known for its veterinary and agricultural colleges. More importantly, it had a very warm and cozy feeling that made me instantly feel like I had found my match. We took a trip into the downtown core, where I felt even more at home. I had found where I wanted to go to university.

Now, you might be thinking that since I'm in IT now, and based on my familiarity with computers growing up, that I would have felt the math and computer science focused university was my place. Strangely enough, I never felt like I was a "computer guy" growing up. Sure I knew my way around a PC, but it was always with a goal of getting something to play. The computer was just a tool to do that. I hadn't really come to any conclusion on "what I wanted to be when I grew up". All I knew that it would be related to a science major, which my chosen university was a solid performer.

There was just one marks. Being a C student wasn't going to get me into a university of the calibre that I fell in love with. So, since I had a year to get my act together, I did just that. I was determined to get into my chosen university, so I hunkered down, applied myself, did the work, and turned myself from a C student to very close to an A+ student. Heh, my parents and teachers were right after all: "If you only applied yourself..."

I applied to 3 top sciences related universities in the province and got accepted to all of them. Which
one to choose? My criteria was simple: I had to be far enough away from home to keep my parents from dropping in all the time, but close enough to get home without too much difficulty should the need arise (ie. home-cooked meals, free laundry). My selection process was a bit dodgy though. I eliminated the one math/computer university solely on the campus atmosphere. I was left with two, both equally good. One was the university I fell in love with during a campus tour, and the other was one that I hadn't gotten the chance to see, but looked very promising. Decisions, decisions. My final choice came down to a simple thing not at all related to academics or career potential: I could get a pizza with my meal card at 2 in the morning at the university I toured and loved, but not at the other. Yeah, that was the clincher.

So, in the fall of 1990 I showed up at university and started off on a life sciences major with vague aspirations to be either a marine biologist or a kinesiologist. I partied a lot, and slipped back into solid C student territory. I was introduced to the concept of "email", where I was absolutely floored that I could send a message via computer to someone on the other side of the world, even though I didn't know anybody on the other side of the world. There were chat rooms, newsgroups and text-based games people would play. Since most people didn't have a computer, you would have to sign up to use one of a bank of computers in the library.

I had saved up some money during the summer and bought myself a computer, which was a 286 with probably 1 or 2 MB of RAM and a small hard drive (likely 20MB). Again, it was used for word-processing and as At some point, I managed to get it hooked up to the school network, probably via modem, but the details are fuzzy (it was nearly a quarter century ago.....damn, I'm getting old).

My 1st year roommate studying hard.
Early in second year, I took a introductory computer course geared towards science students. It offered BASIC programming, WordPerfect, Lotus 1-2-3 and basic DOS command line stuff.  I already knew WordPerfect, Lotus and DOS, so I figured it would be an easy A. Sadly, the course itself was terrible. The teacher was disorganized and the course materials (developed by the teacher) were hard to understand or flat out incorrect.

We had numerous labs where we had to create BASIC programs, make spreadsheets and that sort of thing. It turned out that I had a knack for programming, and I was always among the first to complete the labs. I would then go around and help others with their labs too. I had a lot of fun doing that and it definitely helped me meet the ladies, which wasn't hard since this particular university was known for its abnormally high percentage of women (as high as 75% by some estimates). I came out of that course with the highest mark of my university career.

Unfortunately, my marks in courses like Biochemistry did nothing to keep up a good average. I wasn't enjoying myself, and was struggling. I recalled how well I did in Intro to Computers, and thought that maybe I should switch to Computer Science instead. So I did.
My on-campus residence room in 2nd year, circa fall 1991. I had a thing for Marilyn Monroe...and Cindy Crawford.
Working at a photo lab allowed me to print out lots of the many party pictures I took, which I used as wallpaper.

If I chose this particular university because of the female to male ratio, then I completely undid that by going into Computer Science. The classes were 95% male, and I didn't have much in common with any of them, so didn't make many new friends. On any given evening, most of them were in the UNIX lab programming, while I focused on my alcohol consumption. I did alright, but nothing really set me on fire (figuratively or literally). There were many courses that bored me to tears, but in order to not lose any ground with the courses I already took, I kept Biology as a minor, so there was some variety.

It was during this time that someone introduced me to something called the World-Wide-Web. You could use a "mouse" (a new thing at the time) to click on text in a "browser", which would go to a server somewhere else in the world and show you a picture or something, all without using a keyboard. I recall the first thing I saw was a picture of the Earth from space. The picture took several seconds to draw, even over the dedicated Internet line. I was amazed. The possibilities seemed truly endless.

During a class in COBOL (why????), my teacher (not-so-interesting trivia: that teacher is now the
I excelled at Falconry 101
Minister of Education for my province) posted a notice about becoming a teaching assistant for the Introduction to Computers course I aced a few years back. I jumped at the chance. Not only would it give me some much needed extra cash, but I actually truly enjoyed it when I was helping others with their computer problems.

I applied for, and got, a teaching assistant position for that course. For the rest of my university career, I taught labs and helped people through the still awful course material. I hung out with some of the other TAs, who were a year ahead of me and weren't your typical 90's era computer-types at all.  Every night that I would go to the bar (which was usually every night), people would come up to me and say "Hey, you're my TA!!"  I felt like a minor celebrity.

I went through most of university like this. I took 4 or 5 courses a semester (usually 4, dropping whatever course had night classes or a too-early Friday morning class). I held down 3 jobs at the same time: I was a TA, worked at a 1-hour photo lab, and DJ'd at a local bar/restaurant every other Saturday night. With all these jobs, I had enough money to continue going out almost every night. I have no idea how I managed to do this, plus pass all my courses...maybe that's one of the best things I learned at university: work hard, play hard.

Join me next time as the TA job leads to something that starts me down the path that ultimately put me where I am today, in Part 3, Part I - Tech Support Hijinks.

Monday, January 26, 2015

Out of the Gutter: The Ken Lasko Story, Part 1

I've really gotten a kick out of reading people's IT backstories on their blogs, so I thought I'd add mine in.  This will be much like the Twilight and Hunger Games film series.  There will be 3 parts, but the third part will be broken up into Part I and Part II to drag things out and to maximize profits.

April 1941, London, UK. The Germans had been bombing London for more than 6 months, in what had been called "the Blitz".  I was a teenager wait. That wasn't me.

Part I - Boyhood, but not as good as the movie

I grew up in a farmhouse in the middle of nowhere in central Ontario, Canada during the 1970's and
You can almost see the sweat in this true-to-life simulation.
80's. Our nearest neighbour was nearly a kilometer away, and we had lots of land to entertain me and my younger brother. We rode our bikes, explored the forest, played in barns; very wholesome stuff. My very first exposure to anything computer-related would have been the seminal Atari Pong video game, which we had in our Grade 1 classroom when I was 6 years old. Even with the simple graphics of the time, it was something that we loved to play when allowed. A few years later, I started to waste as much time as my parents would let me playing the growing number of arcade games located at our local mall. I can still remember playing Space Invaders, Asteroids and all those early classics with the precious few quarters I got for an allowance. I was never the video game master that I imagined I was in my mind.

The possibilities were endless!
My first experience with a real computer was the Commodore PET computer that resided in our classroom. I think it was Grade 5, which would have been 1982. I remember inserting a cassette tape and waiting for sometimes up to 30 minutes for the program to load. The longer it took, the better we thought the game would be. The only game I remember was some variation of Lunar Lander, which I thought was awesome. This was also my very first exposure to programming, which usually consisted of the following extremely complex BASIC program:
10  PRINT "<InsertSwearWordHere>";
20  GOTO 10

This would endlessly scroll the chosen swear word, but with the added feature of filling the entire screen, instead of just a single column, thanks to the addition of the semi-colon. This alone differentiated me from the other students, and pegged me as a "computer genius" (or maybe nerd). From that moment forward, I knew computers were going to be an important part of my life....actually no. It was just a way to waste time with games and to irritate teachers.

Look familiar?
My parents brought home the Magnavox Odyssey2 gaming system sometime during the same period. This thing was a true piece of crap, with bad graphics even by the very low standards of the day. My parents thought the built-in touch keyboard would encourage us to take up programming, but we had very little interest in this. We only played the various terrible knock-off games that were available, like KC Munchkin (think Pac-Man). Despite the general awfulness of the Odyssey2 games, we played the hell out of that thing.

A few years later (probably 1984), my parents brought home an odd-looking beige box with a small, heavy 16-colour CGA monitor attached.  This was yet another attempt to get my brother and I to "learn about these new-fangled computer things".  This was the very first PC, an IBM clone.  It had no hard drive. It had 640K of memory. Its only storage media was a pair of 5 1/4" floppy disk drives. I remember inserting the DOS disk, listening to the floppy drive buzz and churn away until finally a single A:\ prompt flashed at me. Without any manual to read, I thrashed my way around until I figured out how to get things done. And by "get things done", I meant "play video games".

It's Sexytime! Imagine that "CENSORED" box moving up and down,
and you get the idea. Mass parental hysteria ensued.
I have no idea how I did it, but I managed to get illicit copies of all sorts of games. This was long before the Internet, and BBS's were still years away. My favourites were the adventure games of the era, starting with King's Quest, then Police Quest, Space Quest, and the infamous Leisure Suit Larry series, which was the first to have "are you an adult?" verification, which was extremely simple for a young, determined kid to get around.

I didn't realize this at the time of course, but this was my very first interaction with Microsoft via an early version of MS-DOS. Little did I know just how much of an effect this would have on my life, just not in exactly the way my parents intended.  I became familiar with computers, even though I didn't use them much more than a medium for playing games.

Later on, as I became older, I used the PC for more than just games. I used it in high school to write
My high school picture
papers with WordPerfect when others were still either writing them by hand or typing them on a typewriter (yes, a typewriter). I printed out my assignments on a dot-matrix printer, and my teachers were impressed by the neatness and lack of liquid paper normally required on most typical type-written papers to hide the mistakes.

We eventually got a 1200 or 2400 baud modem (can't recall which), which allowed us to dial-up to local Bulletin Board Systems (BBS), and download games at blistering speeds. (a 1 MB game would take about an hour at 2400 bps). If my mother picked up the phone while we were downloading (and that happened a lot), she would hear a nice screech, and our download would get interrupted, forcing us to start over. More screeching would happen from both me for the wasted DL time, and my mother who couldn't use the phone any more.

Other than dabbling with computer games and word processing, I lived life like a normal teenager. Rode bicycles all over the place (got into racing and did pretty well), chased girls (not so well), watched TV (yes, Knight Rider was on my 'Must-See' list), and got into typical teenage mischief (all too well).

This continued until one fateful day in 1988, when I encountered something that would change my life....forever. (Best read like a movie trailer voiceover).

Coming soon, the mid-point of this thrilling saga: Part 2 - Higher Learning

Thursday, January 22, 2015

Service Number Formatting in Lync

I recently had the distinct pleasure of engaging the Lync community via Twitter to ask how many people normalized their service and emergency numbers to include a plus sign (+). I asked this question because I had come across a couple of SIP providers in both the US and internationally that expected E.164 (global numbers starting with a plus sign) phone numbers for all except for emergency and service numbers. To put it another way, they wanted a plus in front of all phone numbers except for emergency/service numbers.

My very informal poll results were as follows:
Use + for everything: 6 votes
No + for emergency/service numbers: 4 votes
It depends: 1 vote
A "lively" discussion ensued between @ucomsgeek and @CAnthonyCaragol (the C stands for "Corky", in case you were wondering) on the validity of using a + sign in front of numbers that are not dialable from outside the originating country. The discussion got a little crazy and we very nearly came to blows on several occasions. @ucomsgeek had to be admitted to the hospital with what can only be described as an "RFC induced heart palpitation".

I had traditionally used a + in front of everything, adhering to my mantra of "E.164, E.164, E.164".  This included service numbers like 911 in North America, or 112 in Europe, so they would get normalized to +911 and +112.  My experiences with SIP providers not wanting a + in front of those numbers made me think, which is a rare occurrence, and is usually followed by being distracted by shiny things. If SIP providers don't want a + in front of those types of numbers, there must be a good reason for it.

So, whenever I'm faced with the great unknown, I turned to the trusty Interweb to find answers. I didn't have to look far. Phone number formatting is governed by the E.164 standard published by the Telecommunication Standardization Sector of the International Telecommunication Union or ITU-T for short (which is a good thing, because having to say "the Telecommunication Standardization Sector of the International Telecommunication Union" gets tiresome).  E.164 number representation within the Tel URI format used in SIP is governed by RFC3966 published by the Internet Engineering Task Force (IETF).

Reading these documents is an enlightening and mind-expanding experience. The E.164 standard takes a lot of pages to say that an E.164 number consists of the country code, followed by area code (national destination code or NDC) and the subscriber number.

Other than that, it doesn't say anything about plus signs or anything else other than just boring numbers, so we turn our attention to the much more interesting and relevant RFC3966.

RFC3966 has a lot to say about how to format numbers for use in computer/telecom equipment. The first thing that struck me was that the plus sign is reserved ONLY for global numbers, meaning numbers that are globally unique and adhere to the E.164 standard described above.

Section 5.1 says:
   The 'telephone-subscriber' part of the URI indicates the number.  The
   phone number can be represented in either global (E.164) or local
   notation.  All phone numbers MUST use the global form unless they
   cannot be represented as such.  Numbers from private numbering plans,
   emergency ("911", "112"), and some directory-assistance numbers
   (e.g., "411") and other "service codes" (numbers of the form N11 in
   the United States) cannot be represented in global (E.164) form and
   need to be represented as a local number with a context.  Local
   numbers MUST be tagged with a 'phone-context'

Section 5.1.4 describes how to format a global number:
   Globally unique numbers are identified by the leading "+" character.
   Global numbers MUST be composed with the country (CC) and national
   (NSN) numbers as specified in E.123 [E.123] and E.164 [E.164].
   Globally unique numbers are unambiguous everywhere in the world and
   SHOULD be used.

So, since numbers like 911 are not global numbers, they can't be referenced with a plus sign, but have to be formatted with a context, which is described a little bit later.

Section 5.1.5 describes how to format a local number (which includes service/emergency numbers by definition of not being global numbers):
   Local numbers are unique only within a certain geographical area or a
   certain part of the telephone network, e.g., a private branch
   exchange (PBX), a state or province, a particular local exchange
   carrier, or a particular country.  URIs with local phone numbers
   should only appear in environments where all local entities can
   successfully set up the call by passing the number to the dialling
   software.  Digits needed for accessing an outside line, for example,
   are not included in local numbers.  Local numbers SHOULD NOT be used
   unless there is no way to represent the number as a global number.

Section 5.1.5 goes on to say more about how to format local numbers:
   Local numbers MUST have a 'phone-context' parameter that identifies
   the scope of their validity.  The parameter MUST be chosen to
   identify the local context within which the number is unique
   unambiguously.  Thus, the combination of the descriptor in the
   'phone-context' parameter and local number is again globally unique.
   The parameter value is defined by the assignee of the local number.
   It does NOT indicate a prefix that turns the local number into a
   global (E.164) number.

What the above says is that local numbers must use a specific parameter called "phone-context" to ensure there is no ambiguity with global numbers. A little further reading brings up 911 number formatting as an example:
   A context consisting of the initial digits of a global number does
   not imply that adding these to the local number will generate a valid
   E.164 number.  It might do so by coincidence, but this cannot be
   relied upon.  (For example, "911" should be labeled with the context
   "+1", but "+1-911" is not a valid E.164 number.)

So, for example, 911 should be formatted as tel:911;phone-context=+1 for North America, but clearly says that +1911 is not acceptable.  However, Lync doesn't support phone-context in normalization rules or routing logic (trust me, I tried), so we're kinda stuck if we want to be fully RFC3966 compliant with regards to emergency and service numbers.

We're left with two options for service/emergency numbers really, either use the plus sign or don't. Since the plus sign is supposed to be reserved for global numbers, we probably shouldn't use it for emergency/service numbers. But on the other hand, people are generally used to seeing all their dialed numbers in Lync magically get formatted with a plus sign when it matches up with a normalization rule, which gets taken as a sign that you're good to go (at least that's the way I take it).

But consider this weird little thought experiment. If you normalize 911 to +911, you could think that this represents a really short number within India (country code 91). Yes, I know that a country of more than a billion people is likely going to have more than 9 phones, but you get the idea. What if India decided you could dial the Prime Minister of India by dialing "1"? Then anybody in North America trying to have an engaging conversation with Narendra Modi would end up talking to North American emergency services instead, which would be baffling for both sides.

Another possibility is that you could inadvertently route emergency calls to a global destination. Imagine you have a Lync server in India, and you decide to use least-cost routing to save on toll costs by routing any India-bound call to that Lync server. You configure a route and PSTN usage that sends any call starting with +91 to the India Lync gateway. You inadvertently put that PSTN usage above a PSTN usage meant for local service numbers. Now any call to 911 gets routed to India, and will most likely fail.

You could say the solution to the above scenario is just to make sure that service PSTN usages are above any international PSTN usage, but I'm a fan of engineering solutions that don't rely on someone setting things in exactly the proper order to get the desired results. I'm thinking of administrator/human fault tolerance here.

Rather than say the odds of any given service number conflicting with a real global number is vanishingly small (probably true, but you can't know for least until the Lync Optimizer has dial rules for every country in the world), I'd rather ensure with 100% certainty it won't happen, by not putting a plus in front of emergency/service numbers.

Lync will happily route numbers with or without a plus, as long as your routing logic allows for it. You could build your entire Lync Enterprise Voice deployment around not using plus signs at all if you wanted to, but I wouldn't advise it, mostly because of Lync federation. Published phone numbers from federated contacts with a plus sign would not route in a deployment built around not using the plus sign.

So, there you have it. This blog post has convinced me that not using a plus sign for non-global numbers is the way to go.  I've updated the Lync Optimizer code to follow this tweak in best practices. What are your thoughts?  Does this change your view?  Does this very long blog post on the topic of a plus sign make you fear for my sanity? Let me know in the comments.

Wednesday, January 21, 2015

Adventures in Normalization

One of the things that differentiate Lync from its competitors is its reliance on 3rd party peripherals like deskphones. This is often touted as a Good Thing, since you're not locked into a single vendor for phones. Phones from single-vendor solutions are often more expensive than an equivalent Lync phone simply because you can't get them from anywhere else, so competition is low and prices are higher.

Since Lync phones are provided by different vendors, there is naturally a lot of variation in the specific details on how things work. Microsoft has alleviated this somewhat by instituting a Lync-qualified devices program.  This is a fairly thorough program that puts devices through their paces to ensure they function properly within Lync. 

However rigorous the program, little details slip through the cracks. One of the details that I've noticed is how different phones (and even the Lync client) handle regular expressions in different ways. For anyone familiar with the minutiae (thanks Word of the Day Calendar) of Lync Enterprise Voice, regular expressions are used for phone number normalization and routing. 

All Lync-qualified devices handle basic regex in the same manner. For most people, this is not an issue, but sometimes you need to use lesser-known regex patterns to accomplish certain goals. When you try to get fancy with regex, things sometimes break down with disparate results between clients and phones. 

Over the years, I've heard about and personally experienced situations where Lync Optimizer-generated regex doesn't work on specific phones. The affected vendors have eventually fixed these issues, but I figured that I should do some hardcore 60 Minutes style investigation into just how well different devices handle some of the more esoteric regex patterns out there. 

To do this, I used my wide variety of Lync deskphones I have available for testing in my home lab.  (You should hear what it sounds like when someone phones me.  Everything is ringing and flashing, and I usually go "AAAAhhhhh" and run out of the room.)  I used a Polycom VVX 600, a Polycom CX600, a Snom 760, and an old LG-Nortel "Tanjay" series phone.  My AudioCodes 440HD wasn't connecting to our Lync server at the time, so it was left out of testing. Every phone was updated with the latest firmware available at testing time. 

For the first round of the Lync Normalization Olympics, I decided to keep it simple, using some of the rule formats commonly used by the Lync Optimizer.  I input the normalization rules into Lync via the Control Panel, and I used the "Create voice routing test case information" to see how Lync Control Panel would interpret the regex, and included that in the results too. For all the rulesets, I used a unique "identifier" for each rule to allow me to setup a series that I could test all at once.  


First off, I used a regex rule that included a comma, which I had heard caused normalization issues with one particular vendor. In the below example, I'm looking for a pattern of numbers that starts with 999 followed by 10 or 11 digits. The 999 gets stripped and puts a + in its place.

Pattern: ^999(\d{10,11})$
Translation: +$1
Input number: 99915552223333 then 9995552223333
Expected output: +15552223333 then +5552223333

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
Everything passed that one with flying colours, so rumours of a phone type not handling commas seem to no longer apply.

Dealing with Extensions, Part I

Another common rule used in the Optimizer is a rule to accept any dialed number, but strip out any extensions and leave it as an externally routable E.164 number. This rule was meant mostly for click-to-dial from the Lync client, but I did hear about a particular vendor's phone not being able to parse that particular rule. In the next example, I'm looking for a pattern of numbers that starts with 998 followed by 11 digits, followed by some regex that would strip anything else beyond the 11 digits. The 998 gets stripped and puts a + in its place.

Pattern: ^998(\d{11})\d*(\D+\d+)?$
Translation: +$1
Input number: 99815552223333
Expected output: +15552223333

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
Everything passed that one with flying colours, so rumours of a phone type not parsing those rules seem to no longer apply.

Dealing with Extensions, Part II

The next rule test is a variation on the first example above, using a slightly different regex pattern to strip any extension. This format was used a long time ago in the Lync Optimizer, but was replaced with the "cleaner" looking version above.  One person told me he used this format to get around an issue with a particular phone vendor's issue parsing the previous example's format.

Pattern: ^997(\d{11})(\s*\S*)*?$
Translation: +$1
Input number: 99715552223333
Expected output: +15552223333

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
Again, no issues on any platform.

Extensions with Optional Site Code

In companies with multiple sites that provide its users with extension dialing, its often necessary to use site codes to properly differentiate one site from another. This is especially true if there are overlapping extension ranges originating from legacy PBXs. So, for a company using 4-digit extensions, they may prepend a site code to ensure uniqueness. So, Site #101 could use 1015xxx for their extension range, and Site #102 could use 1025xxx for their extension range.

One particular company wanted to ensure that users within any given site could dial their own users by extension without the prepended site code, but still allow them to enter the site code if they wanted to. I did this in one rule by using a bit of fancy regex. In the below example, a user should be able to enter the extension with or without the 996 "site code".

Pattern: ^(?:996)?(5\d{3})$$
Translation: +1555222$1
Input number: 9965000 then 5000
Expected output: +15552225000

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
Sigh, once again, no issues on any platform.

OK, boooooring. All the phones passed the basic regex tests without issue. Not at all "exciting". I use "exciting" in quotes, because how exciting can the topic of normalization be?

Multiple Replacement Strings

Sometimes you need to use multiple replacement strings in a rule (ie $1, $2 etc). Rumour has it some phones have issues with this.

Pattern: ^996(\d{3})000(\d{7})$
Translation: +1$1$2
Input number: 9965550002223333
Expected output: +15552223333

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
Running out of ways to say "No issues".

Advanced Normalization Tests 

To really gauge how well a phones' regex engine functions, we have to throw at it some regex that would only be used in very specific circumstances. 

For example, let's say I have a need to translate a set of digits into a pattern where those digits are buried within other numbers.  For example, I want to take 92xx and translate it to +155592xx999.  So, 9201 translates to +15559201999.  If you try to create a pattern like ^(92\d{2})$ and translate it to +1555$1999, there is ambiguity on whether you mean +1555 $1 999 or +1555 $19 99. 

Normally, I would follow the .NET regex reference which has different ways of dealing with this, but none of them work in the Lync client.  I did stumble upon one that did work, even though it isn’t a valid .NET expression.  Not only that, but testing with other phones gave different results most of the time.

I tried various patterns, and plugged in 9100, 9200, 9300 etc to see the results in both Control Panel and Lync softclient and desk phones. The results proved interesting.

Pattern: ^(91\d{2})$
Translation: +1555$1999
Input number: 9100
Expected output: Expect failure, but want to see how various devices handle this situation.

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
No match
Seems as though the old Tanjay and CX-series phone work in this situation, but nothing else. No big deal, because I wouldn't expect any consistent behaviour here.

Pattern: ^(92\d{2})$
Translation: +1555${1}999
Input number: 9200
Expected output: +15559200999

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
No match
No match
Using ${1} is a valid way to prevent any ambiguity between $1 or $19 in this example. Sadly only the Lync client and the Snom don't respect this valid regex.

Pattern: ^(93\d{2})$
Translation: +1555$_999
Input number: 9300
Expected output: +15559300999

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
No match
No match
No match
No match
Using $_ is a way to substitute the entire string. Not ideal code-wise, but wanted to see if it would work.  Only the Control Panel and Polycom VVX phones properly parsed it.

Pattern: ^(?<1>94\d{2})$
Translation: +1555${1}999
Input number: 9400
Expected output: +15559400999

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
No match
No match
No match
No match
This is a valid .NET regex method to use named replacement strings instead of numeric. So, I could have easily used ^(?<DigItDude>94\d{2})$ -->  +1555${DigItDude}999.  Again, only the Control Panel and Polycom VVX phones properly parsed it.

Pattern: ^(95\d{2})$
Translation: +1555($1)999
Input number: 9500
Expected output: +15559500999

Control Panel
Lync Client
Tanjay Phone
Polycom CX
Polycom VVX
This is actually not a valid .NET regex method. Surprisingly, all the devices except for the Snom managed to parse it correctly.


As long as your phone number normalization requirements don't require any digit replacement buried within other digits, you can safely use just about any Lync-qualified device.  However, if you know in advance that you have such a requirement (and its very unlikely that you would), I would avoid Snom phones at this time, simply because they couldn't handle any of the advanced regex I threw at them in my attempts to solve that specific issue.

The way I see it, if I build a regex pattern in Lync Control Panel, I should be able to trust that every single device will parse that regex pattern the same way.  I find it rather annoying that there isn't any rigorous checking to see if vendors adhere to .NET regex standards. On that front, I feel Microsoft needs to be more diligent with their phone qualification process.  Its these little details that can lead to frustration for anybody deploying Lync Enterprise Voice.

If you got to the end of this post and are still not asleep.....congratulations!  This post has been entered in the "Most Boring Tech Post of the Year" for 2015. Yes, I know its early, but I think this is an early front-runner for the win.