Tuesday, August 5, 2014

Command Line Options in Lync Optimizer Scripts

A lot of what drives development in the Lync Optimizer is my own personal needs. Every once in a while, I come across a deployment that has some requirement that the Optimizer doesn't cater to.  Most often, it's related to a country that isn't in the Optimizer, which is easy enough to remedy in most cases, with a lot of research and testing. Other times, its a quirk of the deployment that forces me to change how the Optimizer script runs.

On my latest project, there are over 100 sites that have to have their own routes/PSTN usages for places around the globe. Normally, I generate all the dial rules, and run the resulting scripts, answering the questions as they come up (Site ID? Least cost routing? Location based routing? Would you like fries with that?).  Until this past week, I was happy to press 1, Yes, No, No, Supersize me etc.  Not anymore.

Many of the finest PowerShell scripts out there (I'm looking at you, Lync Scriptboy) allow you to enter parameters as required for execution.  I figured it was time to add that feature to the Lync Optimizer generated scripts.

So, if you don't want to answer questions as the Lync Optimizer script is running, you can enter answers to those questions as parameters in the command line prior to execution. All parameters are optional. If you don't add the parameter in the command line, the script will ask you during execution as it always has.

An interesting new feature I enabled along with the command line options is the ability to control which sites are included as part of the least-cost/failover routing logic. Previously, if you have lots of sites with Enterprise Voice routes/policies etc. and you choose to enable least-cost/failover routing in the script, your resulting voice policy PSTN usage list would be very long.  This option now allows you to limit which sites to apply least-cost/failover routing to.  Just use the option -LCRSites followed by the ruleset prefix of the sites to apply least-cost failover routing enclosed with quotes.  For example:  Scriptname.ps1 -LeastCostRouting:$TRUE -LCRSites "CA-ON-Toronto, UK-London, SG-Singapore"

If you need to run a bunch of Optimizer-generated scripts, this can be a real timesaver, especially when you have to run the same script multiple times to account for multiple gateways, or applying least-cost routing and that sort of thing.

The Optimizer script also now has the proper syntax for getting help, so you can type HELP and it will spit out all the available options.

The available options are:

SiteID
The numeric identifier associated with the Lync site to apply the script to. If a value is not provided, script will ask during execution. To see a list of sites and the associated site IDs, run Get-CSSite

DialPlanType
Create a site-level or user-level dialplan. Site-level applies to all users at a site, while user-level have to be explicitly applied. Possible values are 'Site' or 'User'. If a value is not provided, script will ask during execution.

LeastCostRouting
Either apply or don't apply least cost routing to the given site. Only applies if multiple Lync Optimizer generated rulesets are detected. If a value is not provided (and multiple rulesets are detected), script will ask during execution.

LCRSites
Apply least-cost/failover routing only to rulesets defined in this list. Separate site names with commas. Input site names exactly the same as the prefix for the desired site (ie CA-ON-Toronto, UK-London etc).

OverwriteSiteVoicePolicy
Overwrite any existing site-level voice policy if values are already there. Only applies if a site-level voice policy exists. If a value is not provided, script will ask during execution, if necessary.

LocationBasedRouting
Apply location-based routing to a selected site. Only applies if Lync network sites have been created. If a value is not provided, script will ask during execution, if it detects Lync network sites.

LBRNetworkSite
The name of the Lync network site to apply location-based routing. Only applies if Lync network sites exist. For a list of Lync network sites, run Get-CSNetworkSite. Works in conjunction with LocationBasedRouting parameter. If a value is not provided, script will ask during execution, if network sites exist, and the user selects location-based routing.

LocalOnly
Creates only local routes and PSTN usages for the selected site. Useful when using a central SIP trunk for all dialing but want to have local-only voice policies for remote sites without their own local PSTN access. Assumes that the users at the remote site are assigned numbers appropriate to their site, and the SIP provider enforces the appropriate local dialing area for those numbers.

MediationPool
The FQDN of a mediation pool to apply the script to. Only applies if multiple mediation pools exist within the selected Lync site. If a value is not provided and multiple mediation pools exist, script will ask during execution.

PSTNGateway
The FQDN of a PSTN gateway/trunk to apply the script to. Only applies if multiple PSTN gateways/trunks are assigned to the selected mediation pool. If a value is not provided and multiple PSTN gateways/trunks exist, script will ask during execution.

ApplicationPool
The FQDN of an application pool to apply the script to. Only applies if multiple application pools exist within the selected Lync site, and call park or premium call blocking is being used. If a value is not provided and multiple application pools exist, and either call park or premium call blocking is being used,  script will ask during execution.

Enter any desired options on the command line using the following syntax:

ScriptName.ps1 -SiteID digit -DialPlanType user/site -LeastCostRouting true/false -LCRSites "sitename1,sitename2,sitename3-OverwriteSiteVoicePolicy true/false -LocationBasedRouting true/false -LBRNetworkSite NetworkSiteName -MediationPool MedPoolFQDN -PSTNGateway PSTNGatewayFQDN -ApplicationServer AppServerFQDN

Friday, July 11, 2014

Lync 2013 Edge server bug when adding new server pools

I had this happen to me a few weeks ago, and a co-worker had it happen to him today, so I figure it should be mentioned since nobody on the Internet seems to have a proper fix for it.

I installed a new Lync 2013 Standard Edition server in an existing Lync 2013 environment with an established edge server pool.  I created a test account on the new pool and began running through the usual testing scenarios.

All seemed well and fine until we tested federated communications.  An external party could establish an IM or A/V session with the internal user homed on the new pool and see their presence, but the internal user couldn't see presence nor establish a new IM or A/V session with anybody outside the company.

Puzzling to be sure, since everybody else in the company was OK.  I first checked to see if I could telnet to the typical ports required for edge functionality, and all was good. I then logged onto the edge to see if there were any relevant events.

Lo and behold, there was this interesting little warning:
LS Protocol Stack Event 14402
Multiple incoming connections on internal edge from non-internal servers.
In the past 289 minutes the server received 4 incoming connections on internal edge from non-internal servers. The last one was from host newlyncfe.contoso.com.
Cause: This can happen if an internal server is not present in the list of internal servers on the Access Edge Server.
Resolution:
If the server is a valid one, you need to add it to the list of internal servers on the Access Edge Server. If the server is invalid, you may be under an attack from that server.
This left me scratching my head.  How do you add a Lync 2013 server to the "list of internal servers"???  I recalled back to the olden times of OCS, where you had to manually add every valid server name to the edge, but you don't do that anymore, thanks to the wonder of the Topology Builder.

Internet searches brought up several cobweb-covered webpages from the late 2000's, all of them relating to OCS.  No good.  I re-ran Setup on the edge server, hoping that would trigger something and make things all good, but nope.

Finally, I decided to restart the Lync Server Access Edge service (during a period of low activity of course).  Once it restarted, all my troubles went away.  The user on the new front-end was able to initiate sessions to external users, and the 14402 errors on the edge went away.

My next step was going to be blindly restarting other services followed by a last-ditch server reboot. Since that turned out to be unnecessary, if this saves someone from doing a server restart (which would fix the problem too), that's awesome.

So, while Lync normally does an excellent job of detecting new servers and functioning fine without service restarts or server reboots, this is one situation where its not doing that.  It seems the Access Edge service caches the list of valid internal servers at service startup, and doesn't refresh that cache until the next service restart.

Because this seems to be one of the few instances where a service restart is required to maintain connectivity with a new downstream server, I would classify this behaviour as a...


Friday, May 9, 2014

Lync Address Book Weirdness

So, I'm at a fairly large client that's moved from Lync 2010 to 2013.  The server-side migration completed a while ago, and the client migration is in progress.  Enterprise Voice is enabled for a select group of people.

Some people have noticed that when they search for a specific Lync user, the only object that got returned was an object for their Active Directory administrative account that had only a phone number defined (not a Lync-enabled account).  The Lync-enabled "normal" Lync entry didn't show up in the search, even though it did appear in the GALContacts.db file (the Lync locally cached address book file).

The really weird thing was that the object showed up like a phone contact object, but one that had presence working.  The affected user could toggle their presence, and the contact object would dutifully change itself.  However, since it wasn't a Lync object, you couldn't start an IM (but you could call the associated number).

This user's first name isn't actually "Admin" in case you were wondering.


Another weird thing was that the very first time you pulled up that person's name from a search, it would briefly show the proper Lync-enabled account, but switch to the phone contact object view after a half-second or so.

Yet ANOTHER weird thing, was that after viewing the admin account object in Lync a few times, usually after viewing the contact card, the next time I did a search for the same name, only the phone number appeared.  However, I could still look at the contact object for the phone number and it would show the user's email address.

As mentioned previously, the address book had the correct contact information (verified by opening the GALContacts.db file in Notepad....the results ain't pretty, but it works), as well as the information from the AD admin account, but Lync was choosing to show the non-Lync enabled admin account in searches.

When I compared the affected admin accounts with others, I noted that some users showed up properly, but others didn't.  More comparisons showed that for the incorrect information to show up, the following had to be true:
  1. Both the Lync-enabled account and the AD admin account had a phone number defined
  2. Both the Lync-enabled account and the AD admin account had the same email address defined.
Removing the email address from the admin account, re-generating the Lync address book via Update-CSAddressBook, and re-downloading the updated address book file fixed the issue. 

So, what happened?  When you do a search, the Lync client will look at the address book, your own Outlook contacts, and any social connectors you may have associated with Outlook (like Facebook or LinkedIn).  If the same name shows up in multiple places, Lync will try to consolidate all the information and show only one contact object.

Sometimes, the process goes awry. In this case, it appears that Lync saw the same email address for both the Lync-enabled AD account, and the non-Lync enabled AD admin account, and incorrectly presented the non-Lync enabled account as the single object.

I'm guessing this is a bug, because Lync really should place priority on a Lync-enabled object over a non-Lync one for presentation.  

Monday, May 5, 2014

Lync Conference 2014 Content Online

If you weren't able to get to Las Vegas for Lync Conference 2014, you can now see all the content online at Microsoft's Channel 9 page.

I did two very well attended sessions on Enterprise Voice Best Practices.  You can see both of them online, if you're so inclined.  I recommend checking out the second one on Day 3 at 9am (BEST301-R).  For whatever reason, MS didn't have my most up-to-date slide deck for my first run-through, and there were technical difficulties which meant I almost wasn't able to demonstrate the Lync Optimizer.


And if you're going to be at TechEd 2014 in Houston on May 12-15, come see me perform the same session on Tuesday, May 13 at 10:15 AM (OFC-B339)

Thursday, May 1, 2014

March/April 2014 Lync Optimizer Updates

I'm always working to provide new features for the Lync Optimizer.  Some have been rolled out silently to fix an issue.  Others are related to country specific dialing rules.  Here are a few things I've done recently that you may or may not have noticed.

NANPA Dial Rule Updates

Recently, I was looking to implement dialing rules for Namibia, when I was faced with an issue I hadn't considered.  The country code for Namibia is the same code I use for all North American dial rules (NA).

To fix the issue meant I had to do something I've been meaning to do for a very long time: separate out dialing rules for the US, Canada and the other 20-odd Caribbean countries that are part of the North American Numbering Plan Administration dialing area (NANPA).  All the countries in NANPA use +1 as the country code, which makes it difficult to work with programatically.  To switch things so that US dial rules have a US- prefix, Canada dial rules have a CA- prefix and so on, required quite a bit of work. 

The end result is that no matter the country you select, the dial rule prefix will use the actual country name, so instead of NA-ON-Toronto-Local or NA-TX-Dallas-National, you'll get CA-ON-Toronto-Local or US-TX-Dallas-National.  You'll still select North America as the country name.  The Optimizer will be smart enough to know if the area code is in Texas, Ontario or the Dominican Republic (for example).

This change is effective as of May 1, 2014.  Anybody who signed up for rule updates prior to this will be unaffected. Your rule updates will still come to you using the old format.  However, if you've started building dial rules for multiple North American locations prior to May 1st, and are adding more dial rules after May 1st, things may not work as expected if you have a mix of US-, CA-, and NA- prefixes. If this does affect you, please let me know and I'll put up an option to use the "legacy" dial rule format, or give you access to the "old" code.

New North America Dialing Options

North America has an interesting situation regarding international dialing.  There are 26 countries that share the same country code: +1.  In the US and Canada, long distance charges to Caribbean countries that are part of NANPA are often the same price as international calls. Since it is difficult to distinguish a Caribbean country from US/Canada based solely on the area code, it is easy for people to accidentally incur high phone charges when calling these countries.

I've added a new option to prevent this by allowing users to select one of the following options with regards to dialing other countries within NANPA:
  1. In-Country Only - Treat all calls to NANPA countries other than your own as international, even though users don't have to dial 011 to reach them. As such, users will have to be a member of a voice policy that allows international dialing.
  2. US/Canada - Treat calls to anywhere in US/Canada as national calls, excluding the Caribbean. To dial Caribbean countries, users will have to be a member of a voice policy that allows international dialing. Not available for Caribbean rulesets.
  3. US/Canada/Caribbean - Treats calls to anywhere in NANPA (US/Canada/Caribbean) as national calls (along with the potentially higher call costs).

If you are creating a ruleset for a Caribbean country that uses +1 as the country code, you won't be able to select US/Canada, since this would make dialing within that Caribbean country difficult.

Selecting the Simple Ruleset option prevents usage of this feature, and will default to US/Canada/Caribbean. You won't be able to control how people dial other NANPA countries when there is only a single simple routing rule. 

New Extension Options

I had a request to create more flexibility around how extensions are used in the Optimizer. One addition is the ability to control how many digits of the extension are part of the associated DID. For example, a company might have an extension range of 2100-2199 that maps to a DID that matches up with the last 3-digits of the extension, like +12125558100 to +12125558199 (Note the extension starts with a 2, while the DID has an 8 in its place).

The Optimizer now supports this via the addition of a new column called "# of Ext Digits in DID". This will only appear when you select the DID option, and you can use the dropdown to select how many digits of the extension is part of the DID.


New Country Additions

I've added support for more countries, including Singapore and finally, Mexico.  Mexico has a very strange dial plan where you have to dial mobile numbers differently than land lines, but nothing about the number tells you in advance whether or not you should dial those additional digits.  If you use the Optimizer to generate dialing rules for Mexico, you should make sure your mobile numbers are stored in AD with 1 after the country code  (like +521331234567), and not with 044 or 045 as you would dial.  Lync will add the 044 or 045 as appropriate before it leaves Lync.

Conclusion

I hope you like the new additions to the Lync Optimizer.  If you require North American dial rules to follow the old format (NA-TX-Dallas-Local), please drop me a line and I'll help you out. 

Friday, April 25, 2014

Getting Creative with Lync Dial-in Conferencing Phone Numbers

I'm at a client who is moving their PSTN teleconferencing from one of your typical teleconferencing providers to an in-house Lync 2013 deployment.  In the old deployment, they configured an email message that got sent out every time one of the teleconferencing bridges had been booked. This email message contained a long list of both toll-free and locally dialable numbers for many countries around the world.  The client wanted something similar for the automatically generated Lync 2013 New Lync Meeting invitation from Outlook.

When you create a dial plan in the Lync Control Panel, you can set a value for Dial-in conferencing region.  This value is used to group dial-in conferencing phone numbers and present those to users assigned to that particular dial plan.


Dial-in conferencing phone numbers are assigned to the appropriate dial-in conferencing region as shown below.

When a user clicks New Online Meeting in Outlook, the values for dial-in conferencing numbers are automatically populated based on the numbers assigned to the dial-in conferencing region/dial plan associated with the user.  Notice that the region name shows up in brackets after the phone number.


The client wished to show all the available toll-free numbers by default, and order them so that the first one showing was specific to the region associated with the user booking the meeting.  When someone clicked on Find a local number, they would be shown all the local dialing numbers available.

The Lync Server environment consisted of two Enterprise Edition pools in two separate central sites: one in North America and one in South America.  We had configured two site-level dial plans: North America (English) and South America (Spanish).  The dial-in conferencing region names were the same as the central site name (North/South America).

To meet the requirements, we decided to change the dial-in conferencing region name to Toll Free for the North America site-level dial plan, and Llamada Gratuita (Spanish for Toll Free) for the South America site-level dial plan.  We also changed the default Global dial plan's dial-in conferencing region name to International.  You could use user-level dial plans just as effectively, if desired.

Then we created all the dial-in conferencing access numbers.  The Display Number field was set to include both the phone number and the location of that number.


All the toll-free numbers were assigned to both the Toll Free and Llamada Gratuita dial-in conferencing regions. All the local numbers were added to the International dial-in conferencing region.  To make sure the order was correct, we used the Set-CSDialInConferencingAccessNumber command to set the order appropriately:
Set-CSDialInConferencingAccessNumber -Identity AccessNumSIPAddress -Priority x -ReorderedRegion RegionName
Once complete, users would see only the toll-free numbers (ordered correctly for their region) when booking a meeting.  In the below example, a North American user is creating the meeting, so the North America toll-free number is shown first.  If a South American user created a meeting, the Chile number would appear first. Note that for North American users, the Toll-Free in brackets represents the region name, but users will be none the wiser.  South American users would see (Llamada Gratuita) instead. 

Clicking the Find a local number shows all the local numbers available.

The client was thrilled with the results. The only caveat with this method is that the links for clicking the phone numbers in the invite won't work because of the text added.  However, the reasoning is that nobody will ever click those links because they will normally just click Join Lync Meeting.  It would be nice if Lync would use the Line URI in place of the display number for the link, which would avoid the problem entirely.

In any case, this is definitely a creative way to get around some of the limitations of dial-in conferencing number display.  I hope you find it useful.

Tuesday, March 4, 2014

Meet URL Gives 404 error

I was recently at a company that did a big switchover from Lync 2010 to 2013.  The new environment consisted of 3 Enterprise Edition front-end servers with an F5 load balancer taking care of web services load balancing.

On the first business day of full Lync 2013 operations, some people were complaining they could not join meetings.  When some users clicked on the Join Lync Meeting link in the email, they were greeted with a 404 - File or directory not found error in IE.  If they tried several times, eventually they got in.  

Further analysis showed that one specific front-end server was serving up the 404 errors, while the others were working fine.  Thanks to the F5, we were able to easily remove that server from the load-balanced pool while we troubleshooted (troubleshot?) the problem. 

The first thing to note about troubleshooting issues with the meet URL on an Enterprise Edition pool is that you can't connect directly to a specific server in a pool and expect to get the proper meeting join experience.  For example, if your meet URL is meet.contoso.com and your Lync pool members are FE01.contoso.com, FE02.contoso.com etc, you would normally connect to a meeting via something like https://meet.contoso.com/user.name/FY3DFSE4.  You can't troubleshoot issues with a specific server by connecting to https://FE01.contoso.com/user.name/FY3DFSE4.  You'll get a 404 error, thanks to the way the URL Rewrite module processes URLs. 

To get around this, you need to add a temporary HOSTS entry to your testing workstation for meet.contoso.com pointing to the server having the issue. This will bypass the load balancer and allow you to connect directly to the server you want to test.

Back to the problem....

After setting my HOSTS file to point directly to the "bad" server, I found I could browse to https://meet.contoso.com successfully, but not to a specific meeting like https://meet.contoso.com/user.name/FY3DFSE4, which threw a 404.  Event logs didn't show anything wrong. 

I'll spare you the hours of dead ends I tried and just give you the solution (because that's why you're here, right?)

I went to Control Panel and removed the IIS URL Rewrite Module 2.  Then I re-ran Lync setup via the Lync 2013 Deployment Wizard, which re-added the URL Rewrite Module and reset the default URL rewrite rules Lync put in place.  All this was done without reboots or service interruption.  As soon as Lync setup completed, meeting joins happened without error. 

So, it appears that something went wrong with one or more of the URL rewrite rules, which wasn't cleaned up by simply re-running Lync setup, or Enable-CSComputer, which was things other people suggested in various places I looked. 

I hope this helps others who are having this issue.

Friday, February 21, 2014

Lync Conference 2014 Recap

Just got back from another amazing Lync Conference, this time at Aria in Las Vegas. It was great to see all my Lync buddies from around the world and to have the opportunity to participate in some very informative sessions given by Microsoft employees and many of my fellow Lync MVP friends.

There were several announcements, most of which I'm sure everyone has already heard about.
  • The next version of Lync is currently known as Lync vNext. Not sure if this is a codeword, or the final name
  • LyncvNext will include a new server role which will allow other video-conferencing systems (like Tandberg/Cisco) to join Lync-hosted video conferences. This server role can be either co-located on front-end or separate. 
  • Feature-parity on all mobile platforms, including Android tablets, which have not seen a Lync release as of yet.
  • Video calling between Lync and Skype. We all knew it was coming, but nice to see it finally show up. I think they're targetting go-live in June. 
  • A set of Javascript libraries called jLync, which will allow for all kinds of web development possibilities
  • The introduction of hosted-PSTN connectivity on Office365. No details on where it will be offered, but the US is a good bet.
Myself, I hosted two very popular sessions on Lync 2013 Enterprise Voice Best Practices to packed rooms. I had a lot of fun doing it, and look forward to doing more. The famous Jamie Stark even mentioned it on several occasions:

Feedback was very positive, including one fellow who threw a pair of underwear at me at the end of my second session as a joke.
I had a great time at this year's Lync conference. The venue was beautiful, the sessions were informative, and the after-hours parties were fun. I'm already looking forward to LyncConf15, hosted in Hawaii (I hope!).

Sunday, February 2, 2014

February 2014 Lync Optimizer Updates

Since moving the Optimizer back-end to a SQL database and enabling Microsoft authentication, its allowed me to explore adding new features not previously possible.

Ruleset History

The first feature I'm releasing is a ruleset history option. Every ruleset run by users is stored in SQL, so it was relatively easy to enable a history feature, so users can call up past rulesets (it was harder to make it secure). This can come in especially handy when working with extensions, as it is currently rather time consuming to enter extension details.

When you log in now, you'll see a View History button beside the Input heading.

Clicking it will bring up your entire ruleset history since the introduction of authentication and the SQL backend (late October 2013).  Clicking on any row will load that particular ruleset into the Optimizer.

Selective Caller-ID Block

Sometimes, users want the ability to block their outgoing caller ID, but not all the time.  Lync has a feature where you can do this at the voice route level, but it takes a bit of work to make this work "on-demand".  The Optimizer can now accomplish this for you, simply by checking the Allow Call ID Block checkbox and entering the desired caller ID block code (ie *67 in the US/Canada), and the replacement caller ID to use.

The Optimizer will change the default normalization rules to allow the entry of the caller ID block code.  Normalized numbers using this code will look something like: *67+12123334444.  The Optimizer then creates a route for that pattern that selects the Suppress caller ID option.  A trunk translation rule strips the block code before sending to the next hop.


Other Things

I've also included numerous tweaks to improve the overall experience and to ensure consistency. I've also nearly completed the data move from XML to SQL which gives me more options for the future.

I've been working behind the scenes trying to make these work as seamlessly and easy as possible. If you find the Optimizer helpful and a timesaver, think of the Hoff and send him a donation (this guy here, not the real Hoff....he doesn't need any more money).

Any new feature requests, please drop me a line.

Thursday, January 23, 2014

Presenting at LyncConf 2014!

I'm excited to say that I'll be presenting two sessions on Lync Enterprise Voice Best Practices at LyncConf14 in Las Vegas.

These sessions will focus on the WHYs behind the HOWs of Enterprise Voice in Lync 2013.  I'll talk about the best ways to manage your dialplans, voice policies, routes and trunk translation rules to provide a consistent, functional and manageable Lync EV deployment.

So, if you're at LyncConf, come check out my session. Otherwise, the only people who will be there will be my fellow Lync "friends" who just want to see me make a fool of myself, and are threatening to bring various fruits and vegetables to fling at me.

Session Details:

Setting up Enterprise Voice is a big project even for seasoned Lync experts. The interplay between dial plans, voice policies, routes, PSTN usages and trunk translation rules can make it complicated to figure out how to start. Come and join Lync MVP Ken Lasko, the creator of the Lync Dialing Rule Optimizer, and learn the WHYs behind the HOWs of configuring Lync Enterprise Voice – including E.164 numbering, extension dialing and least-cost routing - to provide the most flexibility and easiest migration path from legacy PBXs. And of course, this session wouldn’t be complete without a demonstration of the Lync Dialing Rule Optimizer and how it puts all these best practices into play.

Session Date/Time:

Tuesday, February 18 2014 2:00 PM - 3:15 PM
Room: Copperleaf 1
Thursday, February 20 2014 9:00 AM - 10:15 AM
Room: Copperleaf 1

If there's something you'd like to see me talk about in the session, leave a comment below.