tag:blogger.com,1999:blog-21565390953752239792024-03-15T21:10:00.560-04:00Ken's Unified Communications BlogMusings on Microsoft's Unified Communications offerings, such as Lync Server 2010 and Exchange Server 2010.Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.comBlogger141125tag:blogger.com,1999:blog-2156539095375223979.post-59239832456325499812020-03-11T09:59:00.002-04:002020-03-17T15:09:44.026-04:00Bug in UCDialplans North American Rulesets<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifSPp7cDGbwmMfWzF7PnqXzsEe0CcGIhzOs7nASjM76J3get8d_4UICJccybSIQLQV54SIk9gH3691FT0bWzkugK3Fh2hfi8jZdUBcjruvaAw2QMk5Xyl9LgveBLNNlPOXCgk7B02C0xY/s1600/SadHoff.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="413" data-original-width="500" height="526" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifSPp7cDGbwmMfWzF7PnqXzsEe0CcGIhzOs7nASjM76J3get8d_4UICJccybSIQLQV54SIk9gH3691FT0bWzkugK3Fh2hfi8jZdUBcjruvaAw2QMk5Xyl9LgveBLNNlPOXCgk7B02C0xY/s640/SadHoff.png" width="640" /></a></div>
<br />
I was troubleshooting an issue where people couldn't dial US/CA toll-free numbers in Teams the other day, when using Direct Routing. Initially, the root issue wasn't that easy to solve, due to the lack of a Voice Routing Test Case tester like we have in Skype for Business. Normally, one of the first things I do when troubleshooting issues like this, is to make sure the user is actually ALLOWED to make such phone calls, based on their assigned voice policy. Teams doesn't have an equivalent to the SfB voice route tester. If it did, I would have found it much sooner.<br />
<br />
The first thing that I did was look at the user's call history in the Teams Admin Centre. Sure enough, every toll-free call made by the user failed with the below error logged in Teams:<br />
<br />
<blockquote class="tr_bq" style="text-align: center;">
<span style="font-size: large;">"The destination failed because it doesn't exist"</span></blockquote>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyzD4Wb96XjaCVFU8zJTdoqMwy_WIIAlYS8F6Y4_wKro5DnLAuD6vS6DssIa3LIvTlBrI9dxfFK9Y4sT5t7kD8pB3ZvvSxSCTVgMXUyUt6NfSXh-r-4MUIrcoRbXGuUnG5gmxALKY4FhM/s1600/Annotation+2020-03-11+111817.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="230" data-original-width="219" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyzD4Wb96XjaCVFU8zJTdoqMwy_WIIAlYS8F6Y4_wKro5DnLAuD6vS6DssIa3LIvTlBrI9dxfFK9Y4sT5t7kD8pB3ZvvSxSCTVgMXUyUt6NfSXh-r-4MUIrcoRbXGuUnG5gmxALKY4FhM/s400/Annotation+2020-03-11+111817.png" width="380" /></a></div>
<br />
<br />
No information about this error came up in a search. Reviewing logs from the SBC showed the call never got to the SBC. Client logs didn't provide any usable information. Finally, I looked deeper into the applied dialplan. At this point, I saw the problem, and it was me.<br />
<br />
Of course, I had applied a ruleset generated by UCDialplans.com. Everybody was automatically assigned the global voice policy, which was set to allow dialing only within the US. This utilizes a feature in UCDialplans.com where you can decide exactly what constitutes a "National" call.<br />
<br />
If you're not familiar with the intricacies of the North American dialplan (NANPA), just know that the US, Canada and 26 Caribbean countries share the country code +1. Each country has its own set of one or more area codes. There is no way to distinguish whether a number is in the US, Canada or a Caribbean country just by looking at it.<br />
<br />
UCDialplans.com can configure your National voice policy so that a "National" call can include any number that starts with +1, limit to US/CA or limit it to US <b>OR</b> CA. When creating the ruleset, UCDialplans.com has a drop-down option where you decide what you want to "Treat as National".<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkoPnpEkE7iGUXb718QTgph0-bw0cOlT3lCOYvh8tHmgqqcb9JBYMMsiCw2AA_Irpn5-CsJ9ExmKtD5jZOkJMHuQduq8rm-F-reMQskuP9q0wn6-U5QUldlcFIs2jY9mlnLHIKHFJtVbM/s1600/Annotation+2020-03-10+204339.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="271" data-original-width="565" height="306" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkoPnpEkE7iGUXb718QTgph0-bw0cOlT3lCOYvh8tHmgqqcb9JBYMMsiCw2AA_Irpn5-CsJ9ExmKtD5jZOkJMHuQduq8rm-F-reMQskuP9q0wn6-U5QUldlcFIs2jY9mlnLHIKHFJtVbM/s640/Annotation+2020-03-10+204339.png" width="640" /></a></div>
<br />
<br />
If you select "In-Country Only" (which is the default option), UCDialplans.com will create a national voice route that only includes the area codes for the selected country. The current US example is below, which explicitly details every area code in the US, and is derived programmatically from the current list of area codes:<br />
<br />
<blockquote class="tr_bq">
^\+1(?!(900|976))(20[^04]|21[^1]|22[^1267]|23[149]|24[08]|25[12346]|26[0279]|27[0269]|30[^06]|31[^1]|32[0135]|33[^358]|34[0167]|35[12]|36[014]|38[056]|40[^03]|41[^168]|42[345]|43[0245]|44[0235]|46[39]|47[0589]|48[04]|50[^06]|51[^149]|53[0149]|54[01]|55[19]|56[12347]|57[01345]|58[056]|60[^04]|61[^13]|62[03689]|63[016]|64[016]|65[017]|66[01279]|67[018]|68[0124]|70[^059]|71[^01]|72[04567]|73[1247]|74[037]|75[47]|76[02359]|77[^1678]|78[1567]|80[^079]|81[^19]|83[0128]|84[3578]|85[^1235]|86[02345]|87[028]|90[^025]|91[^1]|92[0589]|93[^235]|94[0179]|95[12469]|97[^4567]|98[0459]|281|458|520|828)[2-9]\d{6}</blockquote>
<br />
For the US/Canada option, rather than explicitly including every area code, it EXCLUDES Caribbean area codes, which is a much smaller list. Similarly, for US/Canada/Caribbean there is no need to exclude any area code (except premium), so the list is even smaller.<br />
<br />
In an effort to reduce route selection time and processing overhead, the National voice policy doesn't explicitly include PSTN usages for local dialing, UNLESS least-cost routing is being used. For the US/Canada and US/Canada/Caribbean route options, toll-free numbers are captured by the route pattern because they're NOT in the exclusion list of Caribbean area codes. Unfortunately, I didn't account for toll-free numbers in the US or Canada Only route options, which means that toll-free numbers can't be dialed if you use the default options.<br />
<br />
You could fix this by adding the Local PSTN usage to your voice policies, but that adds unnecessary overhead. A better option is to explicitly include toll-free numbers in the computed route.<br />
<br />
<blockquote class="tr_bq">
^\+1(?!(900|976))(20[^04]|21[^1]|22[^1267]|23[149]|24[08]|25[12346]|26[0279]|27[0269]|30[^06]|31[^1]|32[0135]|33[^358]|34[0167]|35[12]|36[014]|38[056]|40[^03]|41[^168]|42[345]|43[0245]|44[0235]|46[39]|47[0589]|48[04]|50[^06]|51[^149]|53[0149]|54[01]|55[19]|56[12347]|57[01345]|58[056]|60[^04]|61[^13]|62[03689]|63[016]|64[016]|65[017]|66[01279]|67[018]|68[0124]|70[^059]|71[^01]|72[04567]|73[1247]|74[037]|75[47]|76[02359]|77[^1678]|78[1567]|80[^079]|81[^19]|83[0128]|84[3578]|85[^1235]|86[02345]|87[028]|90[^025]|91[^1]|92[0589]|93[^235]|94[0179]|95[12469]|97[^4567]|98[0459]|281|458|520|828<span style="background: yellow; mso-highlight: yellow;">|8(00|33|44|55|66|77|88)</span>)[2-9]\d{6}</blockquote>
<div class="MsoNormal">
<o:p></o:p></div>
<br />
The latest version of UCDialplans.com does this now, but if you've previously applied a UCDialplans.com ruleset using the "In-Country Only" option, you can either manually update your National voice route, or you can run one of the below scripts, which will seek out any US/CA-National voice route and apply the fix. If you use any of the other options, you aren't affected.<br />
<br />
<h3>
How can I tell which option was used?</h3>
Easily. The voice route for either of the other options are MUCH smaller in size. If your voice routes look like this, you are not affected.<br />
<br />
<b>US/Canada</b>: (?!(24[26]|26[48]|284|345|441|473|649|664|721|[67]58|767|784|8[024]9|86[89]|876|900|976))[2-9]\d\d[2-9]\d{6}<br />
<br />
<b>US/Canada/Caribbean</b>: (?!(900|976))[2-9]\d\d[2-9]\d{6}<br />
<br />
<br />
<h2>
The Fix is In</h2>
<h3>
</h3>
The below PS commands will append tollfree prefixes to the problematic voice route. Run whichever is appropriate for your environment, and BACKUP before you run this.<br />
<h3>
Skype for Business Fix</h3>
$Routes = Get-CsVoiceRoute | Where {($_.Identity -eq 'US-National' -or $_.Identity -eq 'CA-National') -and $_.NumberPattern -notlike '*[2-9]\d\d[2-9]\d{6}' -and $_.NumberPattern -notlike '*8(00|33|44|55|66|77|88)*'}; ForEach ($Route in $Routes) {Set-CsVoiceRoute -Identity $Route.Identity -NumberPattern $Route.NumberPattern.replace(")[2-9]\d{6}","|8(00|33|44|55|66|77|88))[2-9]\d{6}")}<br />
<br />
<h3>
</h3>
<h3>
Microsoft Teams Fix</h3>
$Routes = Get-CsOnlineVoiceRoute | Where {($_.Identity -eq 'US-National' -or $_.Identity -eq 'CA-National') -and $_.NumberPattern -notlike '*[2-9]\d\d[2-9]\d{6}' -and $_.NumberPattern -notlike '*8(00|33|44|55|66|77|88)*'}; ForEach ($Route in $Routes) {Set-CsOnlineVoiceRoute -Identity $Route.Identity -NumberPattern $Route.NumberPattern.replace(")[2-9]\d{6}","|8(00|33|44|55|66|77|88))[2-9]\d{6}")}<br />
<br />
<br />
My apologies to anyone caught up by this bug. If you see me in the streets, feel free to slap me.<br />
<br />
<div class="MsoNormal">
<o:p></o:p></div>
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-88034624717931620362020-03-09T09:21:00.000-04:002020-03-09T09:21:01.890-04:00"Have you tried turning it off and back on again?" for MS TeamsOne of the most powerful tools in a support professional's arsenal is the tried-tested-and-true method of restarting a computer to resolve strange issues. I can't tell you how many times this fixed the oddest issues over the years. Why does it work? You might as well ask where socks go once placed in the clothes dryer.<br />
<br />
I'm excited/sad to report that the same method works in Microsoft Teams to resolve strange issues that defy explanation. I'm not talking about client-side issues. I'm talking about issues at the Office 365 end of things. How does that work when there are no administrator-accessible servers to restart? You simply toggle the relevant setting off and back on again.<br />
<br />
We use Direct Routing for our PSTN services, and for the most part it works great. In the past few weeks, I've had some of our users experience strange issues with telephony in Teams.<br />
<ol>
<li>A few users were unable to receive any PSTN calls. Troubleshooting at the SBC would show <b>487 Request Terminated - Phone number not found</b>.</li>
<li>Another user's outbound PSTN calls were showing as Anonymous/Private. There weren't any <a href="https://docs.microsoft.com/en-us/microsoftteams/caller-id-policies" target="_blank">caller ID policies</a> being applied that would account for the behaviour.</li>
</ol>
<div>
For each of those issues, I verified that things were indeed setup properly in Teams via PowerShell. <b>Get-CsOnlineUser</b> showed that their <b>LineURI </b>and <b>OnpremLineURI </b>settings were correct, and Enterprise Voice was enabled. <b>Get-CsOnlineVoiceUser</b> showed they were all licensed, <b>PSTNConnectivity </b>was <b>OnPremises </b>and their <b>Number </b>was correct.</div>
<div>
<br /></div>
<div>
In short, there was nothing on the Teams side of things that indicated an issue. I decided to try the "Have you turned it off and back on again?" trick, which consisted of:</div>
<blockquote class="tr_bq">
<span style="font-family: "verdana" , sans-serif;">Set-CsUser -Identity UserID@contoso.com -EnterpriseVoiceEnabled:$FALSE<br />Set-CsUser -Identity UserID@contoso.com -EnterpriseVoiceEnabled:$TRUE</span></blockquote>
<div>
<br /></div>
<div>
I waited patiently all of 10 seconds between commands. I then instructed the users to log off and back onto Teams. Lo and behold, in each case, the problem went away.</div>
<div>
<br /></div>
<div>
Yeah, I know. I don't get it either, but whatever...it works.</div>
<div>
<br /></div>
<div>
<div style="text-align: center;">
<iframe allowfullscreen="" class="giphy-embed" frameborder="0" height="358" src="https://giphy.com/embed/xT8qBceOioKYTFQV8s" width="480"></iframe></div>
<a href="https://giphy.com/gifs/baywatch-xT8qBceOioKYTFQV8s">via GIPHY</a></div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com3tag:blogger.com,1999:blog-2156539095375223979.post-17219459561832229862020-02-24T11:37:00.001-05:002020-05-22T14:00:09.240-04:00The Complete Guide to Using UCDialplans.com for Microsoft Teams Direct RoutingSeasoned veterans of my dusty, long-dormant blog will remember I did a comprehensive post (in 2012! EIGHT YEARS AGO!!!!) on how to <a href="https://ucken.blogspot.com/2012/01/complete-guide-to-lync-optimizer.html" target="_blank">use the Lync Optimizer to automatically create dialplans for your Lync deployments</a>. That guide is still useful for every on-prem version of Lync and Skype for Business since then. I did a <a href="https://ucken.blogspot.com/2017/04/tenant-dial-plans-in-skype-for-business.html" target="_blank">similar guide for Skype for Business Online</a> in 2017 (a mere 3 years ago). With all the changes that Teams has brought (Direct Routing, and so much more!), I figure its about time I did an updated guide on how to use <a href="https://ucdialplans.com/" target="_blank">UCDialplans.com</a> in Direct Routing scenarios.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj12TTPmZuS0xYaJjNXWXydysZr8310lGUKQHRXE55MBudt0yAe3GopRU1kuX7a7vGantvdAKdxOZyAk4ZA2ltTGiYH3rgSMPKoXbQ78hAspAKGKbO5REGae35SltdoICgvRdAVNhu-3Rc/s1600/HoffPiranha3DD.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="359" data-original-width="639" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj12TTPmZuS0xYaJjNXWXydysZr8310lGUKQHRXE55MBudt0yAe3GopRU1kuX7a7vGantvdAKdxOZyAk4ZA2ltTGiYH3rgSMPKoXbQ78hAspAKGKbO5REGae35SltdoICgvRdAVNhu-3Rc/s640/HoffPiranha3DD.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Who could forget the 2012 Hoff masterpiece<b> Piranha 3DD</b>? I didn't know this existed until just now. I know what I'm watching tonight!</td></tr>
</tbody></table>
<h2>
A Milestone</h2>
Another reason why I'm doing this now (February 2020) is because for the first time, the monthly total number of S4BOnline/Teams rulesets generated by UCDialplans.com has surpassed the number of S4B On-prem rulesets. This is an unofficial barometer of which platform is more popular for Enterprise Voice deployments. I could go on about how many S4B On-prem deployments are at a mature state and generally don't require many net-new dialplans compared to Teams where many are just starting to move their voice loads to it, but SEMANTICS! Just look at the chart!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw09JDwBeadN8_n4QAHpLw0CetSSEjnfq5INbGq99jCjc2WRkKT161cBkDc4QJceunlegC8nQVJfE7ljLUbVsmgFzEPb1UUU0eEwwKWVWP0qb1zQPMF8JlDJf8Xi3QyqTnwBOPxFw8ZlM/s1600/Annotation+2020-03-09+111745.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="578" data-original-width="1019" height="362" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw09JDwBeadN8_n4QAHpLw0CetSSEjnfq5INbGq99jCjc2WRkKT161cBkDc4QJceunlegC8nQVJfE7ljLUbVsmgFzEPb1UUU0eEwwKWVWP0qb1zQPMF8JlDJf8Xi3QyqTnwBOPxFw8ZlM/s640/Annotation+2020-03-09+111745.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<h2>
Who should use this guide?</h2>
If you're on MS Teams and you are using Teams as your phone system, you'll be using it in one of two modes (or both in some cases):<br />
<br />
If you're using <b>Teams Direct Routing </b>(using your own SBCs to provide dialtone), then you should <b>definitely </b>use this guide. It makes the entire process of creating voice routing policies, routes, PSTN usages etc. so much easier. If you are already confused by the above terms, then I HIGHLY recommend you use this tool.<br />
<br />
If you're using <b>Microsoft Phone System</b> (where Microsoft is your telephony provider), then I suggest you read my blog post on <a href="https://ucken.blogspot.com/2017/04/tenant-dial-plans-in-skype-for-business.html" target="_blank">Tenant Dialplans in Skype for Business Online</a>. It will tell you why <a href="https://ucdialplans.com/" target="_blank">UCDialplans.com</a> is still useful when your entire telephony infrastructure is managed by Microsoft. Even though it was written for SfBO, it still applies to Teams.<br />
<br />
<h2>
What can UCDialplans.com do for me?</h2>
<div>
In a Direct Routing environment, <a href="https://ucdialplans.com/" target="_blank">UCDialplans.com</a> will automatically create the following:</div>
<div>
<ul>
<li>Dialplans with normalization rules appropriate for your country, so users can dial phone numbers as they are accustomed.</li>
<li>Voice routing policies so you can selectively control who can dial locally, nationally and internationally.</li>
<li>Voice routes, which determine where calls are routed</li>
<li>PSTN usages, which are the glue between voice routing policies and voice routes</li>
</ul>
<div>
In a Microsoft Phone System environment, <a href="https://ucdialplans.com/" target="_blank">UCDialplans.com</a> will automatically create the following:</div>
</div>
<div>
<ul>
<li>Dialplans with normalization rules appropriate for your country, so users can dial phone numbers as they are accustomed.</li>
</ul>
<div>
<br /></div>
<h2>
What won't UCDialplans.com do for me?</h2>
</div>
<div>
If you're using Direct Routing, the "only" thing UCDialplans.com can't do is setup your SBC infrastructure and configure the link between Teams and your SBC. That has to be done prior to applying a UCDialplans.com script to your environment. Its not a small task, and could take you a while. Don't worry, I'll be here when you're ready. </div>
<div>
<br /></div>
<div>
To get familiar with what's required, read the excellent documentation on Microsoft's site starting with the <a href="https://docs.microsoft.com/en-us/microsoftteams/direct-routing-landing-page" target="_blank">Overview</a>, then <a href="https://docs.microsoft.com/en-us/microsoftteams/direct-routing-plan" target="_blank">Plan Direct Routing</a>, followed by <a href="https://docs.microsoft.com/en-us/microsoftteams/direct-routing-configure" target="_blank">Configure Direct Routing</a>, but stop when you get to the section listed <b>Configure Voice Routing</b>. This is the point where UCDialplans.com takes over.</div>
<div>
<br /></div>
<h2>
Getting Started</h2>
<div>
For those using Direct Routing, I'm assuming you've already setup your SBC infrastructure and have paired your SBCs to your Office 365 tenant. UCDialplans.com PowerShell scripts will check for the existence of at least one SBC via <b>Get-CsOnlinePSTNGateway</b>. If one isn't found, then the script will stop after creating a dialplan.<br />
<br />
<h2>
Generate your customized dialplan script</h2>
Go to UCDialplans.com and sign in with a Microsoft account. Once validated, you will see the webform for creating your dialplan become visible.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOC5HLIgfmGriAwZJyGp9oQ4iAkr8freKj9uBKV1U2UonSjo1xopweh6VoYyOblPLlTa60sKuJdBz8fs684ttYcP6v7JaTKqcbYqZD0LgBFOtViis1QbyBowqyzRNqHUpmCNYFHRJyAOg/s1600/UCDialplansForm.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="561" data-original-width="1600" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOC5HLIgfmGriAwZJyGp9oQ4iAkr8freKj9uBKV1U2UonSjo1xopweh6VoYyOblPLlTa60sKuJdBz8fs684ttYcP6v7JaTKqcbYqZD0LgBFOtViis1QbyBowqyzRNqHUpmCNYFHRJyAOg/s640/UCDialplansForm.png" width="640" /></a></div>
<ol>
<li>Select <b>Microsoft Teams</b> as your gateway type</li>
<li>Select the country and city/region where your SBCs are located.</li>
<li>Some countries require special prefixes/suffixes for certain phone calls. Enter any prefixes in the provided boxes.</li>
<li>If your SBCs are connected to the PSTN via SIP trunk, select <b>SIP Trunk</b>. If you are connected via a legacy T1/E1/analog connection or you are required to send numbers formatted to the local number standards, select <b>T1/E1/ISDN/Analog</b>. <b>NOTE</b>: There is a bug in the Microsoft PS commands used to create outbound translation rules that limits rule length to 50 characters (every other PS command allows 1024 characters). This may have an adverse effect. </li>
<li>If you are connecting to a legacy PBX that requires adding a prefix to external numbers, enter one here. </li>
<li>Add up to 50 internal extension ranges. If it works for your deployment, add every extension range used across your deployment here. You will see why at the <b>Assign internal dialing rules to the local or Global dialplan?</b> question during script execution (see a few sections lower down for details).</li>
<li>If you don't like the auto-generated rulename example shown, you can change it here. Note that you can only control what's in the middle of the rulename. The country name and ruletype are fixed.</li>
<li>If you don't want to control who can make local/national/international calls, you can select Simple Ruleset. </li>
<li>If the ruleset is for a country where English isn't the first language, you can force English rulenames. It will also remove any non-English standard characters from city/region names and replace them with the English equivalent. </li>
<li>Once you're satisfied with the configuration, press <b>GENERATE RULES</b></li>
</ol>
<div>
UCDialplans will start whipping its army of trained monkeys and in no time flat, you will have a customized PowerShell script ready for download.</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga8B3J0Tt-4lro-41_pE0sgmeG62H4nJxgRLtDf8OjghcRkpX6idwpawR4bvRJy4KgoESpJUddaHAj4AaY40tBJe6keRs7GwL2Qy7dAZcCYnPeDweveMkDq2OOFnP3fYFuEPrgjNT0kcI/s1600/UCDialplansGen.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="360" data-original-width="714" height="322" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga8B3J0Tt-4lro-41_pE0sgmeG62H4nJxgRLtDf8OjghcRkpX6idwpawR4bvRJy4KgoESpJUddaHAj4AaY40tBJe6keRs7GwL2Qy7dAZcCYnPeDweveMkDq2OOFnP3fYFuEPrgjNT0kcI/s640/UCDialplansGen.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Notice the Donate button? Not many people see this. :)</td></tr>
</tbody></table>
<br />
Click the <b>DOWNLOAD RULESET HERE</b> button, and save the script as a .PS1 somewhere on your system. You will probably have to unblock it to make it usable without prompting. Right-click the file and select <b>Properties</b>. Click <b>Unblock</b>, and then <b>OK</b>.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZcgAdHntK6xG4NUH4v5a7H0WWtuGZfObLTfpOwaIgxRUhoDFkehqjPL41wqogNiS-hr1VravEPzYCi2dzFGXoiLCcnGBtamjmznZZibWQl5307PKI14mSTt1qjg6_BkajPCmikyPaDSQ/s1600/Unblock.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="505" data-original-width="361" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZcgAdHntK6xG4NUH4v5a7H0WWtuGZfObLTfpOwaIgxRUhoDFkehqjPL41wqogNiS-hr1VravEPzYCi2dzFGXoiLCcnGBtamjmznZZibWQl5307PKI14mSTt1qjg6_BkajPCmikyPaDSQ/s640/Unblock.png" width="456" /></a></div>
<br />
<br />
<h2>
Backup your existing Teams EV config</h2>
<div>
If you've already got a functional Teams EV environment, I strongly suggest you backup your EV details, by downloading and running my suite of Teams Backup/Restore scripts. For more details, <a href="https://ucken.blogspot.com/2020/02/backing-up-and-restoring-teams.html" target="_blank">see this post</a>, or <a href="https://github.com/kenlasko/BackupRestoreTeamsEV" target="_blank">go to Github to download the latest version directly</a>.<br />
<br /></div>
<h2>
Run the script via PowerShell</h2>
<div>
Open a PowerShell window, navigate to where the script is located and run the script. You might be blocked from running the script due to PowerShell policies. If this is the case, then run the following command from an elevated PowerShell prompt:</div>
<blockquote class="tr_bq">
<span style="font-family: "trebuchet ms", sans-serif; font-size: large;"><b>Set-ExecutionPolicy RemoteSigned</b></span></blockquote>
<div>
Or you can open your kimono and use <b>Unrestricted </b>in place of <b>RemoteSigned</b>.<br />
<br />
Run the script from a PowerShell prompt. If you are not already signed into your Office365 tenant, you will be prompted for credentials. If your admin account is not in the same domain as your tenant (ie. uses an @tenantname.onmicrosoft.com address), then use the <b>-OverrideAdminDomain</b> switch.<br />
<br />
You can also use the <b>-PSTNGateway</b> switch to enter the FQDNs of the SBCs you want to use. If using more than one, put them in quotes and separate by commas, like this <b>.\US-Chicago-MSTeams.ps1 -PSTNGateway "GW1.contoso.com, GW2.contoso.com"</b>. If you're using Microsoft "Super Trunks", you'll need to use the <b>-PSTNGateway</b> switch because the script won't detect any PSTN gateways installed in your tenant.<br />
<br />
When the script starts, you'll be presented with several questions:<br />
<br /></div>
<h3>
Create global or user-level dialplan?</h3>
You can either assign the dialplan (which controls how users can dial phone numbers) to everyone by default via the <b>Global </b>dialplan or a <b>user-level</b> dialplan (the default selection). If the majority of your users are in the same location, you can use the <b>Global </b>dialplan, which requires one less step when enabling new users for voice. If you will be creating multiple dialplans, then its probably best to select <b>User</b>. The script will create normalization rules as desired.<br />
<br />
<h3>
Assign internal dialing rules to the local or Global dialplan?</h3>
<div>
If you entered extension ranges via the UCDialplans UI, you will be prompted with this question. If you say <b>Global</b>, the extension ranges you entered will be added to the Global tenant dialplan. This means that any new dialplans created in the future will add those normalization rules to the top. <a href="https://ucken.blogspot.com/2020/02/undocumented-behaviour-teams-dialplans.html" target="_blank">This takes advantage of an undocumented feature described in this post</a>. If you don't want to take advantage of this, select <b>Local</b>.</div>
<div>
<br /></div>
<h3>
Assign PSTN usages to Global Voice Policy?</h3>
A voice policy defines exactly what numbers a user can dial. You can use voice policies to allow only certain users to dial internationally, or set common-area phones to only dial local numbers (as examples). If you have a simple deployment where the majority of users will be assigned the same voice policy, you can set this globally by selecting either <b>Local</b>, <b>National</b>, or <b>International</b>. <b>Local </b>means that users will only be able to dial local numbers. <b>National </b>means they can dial any number within the country, and I<b>nternational </b>has no restrictions. If you do not assign anything at the global level, you will have to manually assign voice policies to all users.<br />
<br />
<h3>
Select primary/secondary PSTN gateway to apply routes</h3>
<div>
If there is a single PSTN gateway defined, the script will automatically use this for all defined routes. If there is more than one, the script will prompt you for which will be the primary gateway and which will be the secondary (if desired). This question will not be asked if you used the <b>-PSTNGateway </b>switch.</div>
<div>
<br /></div>
<h3>
Configure voice policies for least-cost/failover routing</h3>
<div>
If the script detects the presence of existing voice policies created with UCDialplans, it will ask if you want to leverage least-cost/failover routing for these voice policies. If you say Yes, the script will assign the existing voice policies in a way that will route calls using the cheapest path possible, as well as ensure that calls can still work if the main PSTN gateways are down. <a href="https://ucken.blogspot.com/2013/01/least-cost-failover-routing-in-optimizer.html" target="_blank">See this post for more info</a> (was written for Lync, but still applies to MS Teams)</div>
<div>
<br /></div>
<h2>
Final Steps</h2>
<div>
Once done, you should have a fully functional voice infrastructure in MS Teams. If you didn't use the Global options for the dialplan and/or voice policy, you'll have to assign policies to your users. A simple example is as follows (assumes you're assigning to all EV-enabled users):</div>
<blockquote class="tr_bq">
<span style="font-family: "trebuchet ms", sans-serif;">Get-CsOnlineUser | Where {$_.TenantDialplan -eq $NULL -and $_.EnterpriseVoiceEnabled -eq $TRUE} | Grant-CsTenantDialPlan -PolicyName BR-SaoPaulo<br />Get-CsOnlineUser | Where {$_.VoiceRoutingPolicy -eq $NULL -and $_.EnterpriseVoiceEnabled -eq $TRUE} | Grant-CsOnlineVoiceRoutingPolicy -PolicyName BR-SaoPaulo-National</span></blockquote>
It will take some time for these to take effect, and will probably require users to restart Teams at some point.<br />
<br />
<h2>
Oooops! I screwed up!</h2>
If you accidentally screw up applying a UCDialplans.com script and want to revert to a "clean" setup, you can run the following commands, which will wipe out all custom dialplans, voice policies etc. Don't run this if you've already got a working system.<br />
<blockquote class="tr_bq" style="line-height: 1;"><blockquote class="tr_bq" style="line-height: 1;"><font face="courier" style="line-height: 1;">Get-CsTenantDialPlan | Remove-CsTenantDialPlan</font></blockquote><blockquote class="tr_bq" style="line-height: 1;"><font face="courier" style="line-height: 1;">Get-CsOnlineVoiceRoute | Remove-CsOnlineVoiceRoute</font></blockquote><blockquote class="tr_bq" style="line-height: 1;"><font face="courier" style="line-height: 1;">Get-CsOnlineVoiceRoutingPolicy | Remove-CsOnlineVoiceRoutingPolicy</font></blockquote><blockquote class="tr_bq" style="line-height: 1;"><font face="courier" style="line-height: 1;">Set-CsOnlinePstnUsage Global -Usage $NULL</font></blockquote><blockquote class="tr_bq" style="line-height: 1;"><font face="courier" style="line-height: 1;">$GWList = Get-CsOnlinePSTNGateway</font></blockquote><blockquote class="tr_bq" style="line-height: 1;"><font face="courier" style="line-height: 1;">ForEach ($GW in $GWList) { Set-CsOnlinePSTNGateway -Identity $GW.FQDN -OutboundTeamsNumberTranslationRules $NULL -OutboundPSTNNumberTranslationRules $NULL -InboundTeamsNumberTranslationRules $NULL -InboundPSTNNumberTranslationRules $NULL }</font></blockquote><blockquote class="tr_bq" style="line-height: 1;"><font face="courier" style="line-height: 1;">Get-CsTeamsTranslationRule | Remove-CsTeamsTranslationRule </font></blockquote></blockquote>
<br />
<h2>
Additional Tips and Tricks</h2>
UCDialplans.com scripts can be used for some interesting use-cases. For example, assume you're a company that has a single SIP trunk infrastructure that is homed in a single country. For this example, we'll assume its in Canada. Now also assume that you have some users in other countries such as the UK, that have Canadian numbers assigned to them. Those UK users would normally be forced to dial phone numbers as if they were in Canada, which is not something they would be used to.<br />
<br />
In this case, you can generate a UK-based script from UCDialplans.com and run it against your deployment using the <b>-DPOnly</b> switch. This will force the script to only create a dialplan for the UK and it won't create extraneous routes/policies etc. You then assign the resulting UK-based dialplan to your UK users and they can dial numbers as they are accustomed to in the UK.<br />
<br />
<br />
<br />
<br /></div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com83tag:blogger.com,1999:blog-2156539095375223979.post-29517931621702930192020-02-09T20:04:00.001-05:002020-02-09T20:04:31.776-05:00Migrating SfB Enterprise Voice Configs to MS Teams<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPUu-f6aryOpJk7Rx6PoqCBKR4mfv2jqUy4nZ3ttqSPgigco9c76epKw8M-H-RQXqyeUJo3x_CNvIOdhRlv1j48CZ4vizP_dFUZE2HdhZ7l-JifaTE_g4Va24iZcc6kOmXLsmeIgz2oLs/s1600/HoffFlying.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="290" data-original-width="518" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPUu-f6aryOpJk7Rx6PoqCBKR4mfv2jqUy4nZ3ttqSPgigco9c76epKw8M-H-RQXqyeUJo3x_CNvIOdhRlv1j48CZ4vizP_dFUZE2HdhZ7l-JifaTE_g4Va24iZcc6kOmXLsmeIgz2oLs/s640/HoffFlying.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">I'm flyyyyyyiiiing through the cloud.....get it? Cloud? Teams is in the cloud. Got it? Good.</td></tr>
</tbody></table>
<br />
The UCDialplans.com Winter of Code continues at a torrid pace!<br />
<br />
Hot on the heels of the <a href="https://ucken.blogspot.com/2020/02/backing-up-and-restoring-teams.html" target="_blank">MS Teams EV Backup/Restore scripts</a> is another script that I can't believe someone hasn't already cooked up.<br />
<br />
Say that you have a well-oiled Skype for Business Enterprise Voice deployment that you carefully cultivated over the years into a perfectly tuned beast. You're considering migrating to Teams, but aren't terribly enthusiastic about having to recreate all that magic in Teams.<br />
<br />
Well, worry no more! I've created a script that will copy all of your Skype for Business Enterprise Voice settings into MS Teams. It will handle the following:<br />
<ul>
<li>SfB dialplans into Teams dialplans (along with all normalization rules, of course)</li>
<li>SfB PSTN usages into Teams PSTN usages</li>
<li>SfB voice routes into Teams voice routes</li>
<li>SfB voice policies into Teams voice routing policies</li>
<li>SfB trunk translation rules into Teams translation rules</li>
<li>SfB PSTN gateways into Teams PSTN gateways</li>
</ul>
<div>
Most of this is completely automatic, except for the PSTN gateway part. Teams PSTN gateways have to be publicly accessible via FQDN, and that FQDN's domain name has to be registered in the O365 tenant. Chances are pretty good that the SfB PSTN gateways won't conform to those requirements. The script will first look for an existing Teams gateway that matches each SfB gateway. If one isn't found, the user will be prompted to do one of the following:</div>
<div>
<ul>
<li>match the SfB gateway to an existing Teams gateway with a different FQDN</li>
<li>create a new Teams gateway with the same FQDN as the SfB gateway (only works if the SfB gateway already meets the Teams FQDN requirements)</li>
<li>create an entirely new Teams gateway</li>
<li>don't match the SfB gateway</li>
</ul>
<div>
All this is presented to the user in a straightforward menu. Once all the selections are complete, the selected matches are shown before erasing any existing Teams EV configs and migrating the SfB EV configuration:</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI0R8obiTYWtt27ttRYGM5FO8vgX31z6dc9Q9xQPTEaIPfLuCPXuo6Zrrc1VRrymJrH0sWAvk5mvG1_-_CjEN8ZswFHxSetyWIhWnonGS7X_8ubpco4yzpwnpfW40XKDgdRQitnY9stwM/s1600/CopyCMD.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="396" data-original-width="749" height="338" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI0R8obiTYWtt27ttRYGM5FO8vgX31z6dc9Q9xQPTEaIPfLuCPXuo6Zrrc1VRrymJrH0sWAvk5mvG1_-_CjEN8ZswFHxSetyWIhWnonGS7X_8ubpco4yzpwnpfW40XKDgdRQitnY9stwM/s640/CopyCMD.png" width="640" /></a></div>
<div>
<br /></div>
<div>
The usual trained monkeys will then migrate all the SfB EV settings to Teams, with a few caveats:</div>
<div>
<ul>
<li>Since Teams doesn't have "sites", site-level SfB dialplans will be converted to user-level dialplans</li>
<li>Same deal with site-level voice policies</li>
<li>If there are duplicate translation rules, they will be merged into one, but translation rules with the same name, but different patterns/translations will be changed to include the PSTN gateway name to avoid conflicts.</li>
</ul>
<div>
If all goes well, the script should progress like this:</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyxxC2QiUjiS7DBG0vFxAMJwduIEa8P_JHvWnsa8aPoXn2yJ97kr4P4KRtpalT_2qJWeN8pRpD_rgmKhiIK_9c583Ag_I7Pg5rb7Vq-Mpy9lQWRlFB7uChOUiVF7GzcEwf37ESSGQBhXw/s1600/NotVerbose.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="169" data-original-width="792" height="136" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyxxC2QiUjiS7DBG0vFxAMJwduIEa8P_JHvWnsa8aPoXn2yJ97kr4P4KRtpalT_2qJWeN8pRpD_rgmKhiIK_9c583Ag_I7Pg5rb7Vq-Mpy9lQWRlFB7uChOUiVF7GzcEwf37ESSGQBhXw/s640/NotVerbose.png" width="640" /></a></div>
<br />
If you want to see more details around how the secret sauce is made, run the script with the -Verbose switch:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEq50KvzwzR7CYTQ3biAPYN77x4_57v2CDjy5b0SPl0Jsod5kJf6_GmpGtvt8JaYJGzGo_A8gwC8egXmrNoc6Nhb8MixcG5ISBo1Jrk-14G-jWMyMhABcan5V_3r3rYujyvvMK9rYd5oY/s1600/Verbose.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="571" data-original-width="813" height="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEq50KvzwzR7CYTQ3biAPYN77x4_57v2CDjy5b0SPl0Jsod5kJf6_GmpGtvt8JaYJGzGo_A8gwC8egXmrNoc6Nhb8MixcG5ISBo1Jrk-14G-jWMyMhABcan5V_3r3rYujyvvMK9rYd5oY/s640/Verbose.png" width="640" /></a></div>
<div>
<br /></div>
<div>
Once complete, your SfB Enterprise Voice config should be completely migrated to Teams. Check things over to be sure. If you elected to create Teams PSTN gateways, you will have to revisit them using <b>Set-CsOnlinePSTNGateway</b> to make sure they're configured correctly. </div>
<div>
<br /></div>
<div>
Hopefully, this script will help make your transition to Teams that much simpler!</div>
<div>
<br /></div>
<div>
To get the script, go on over to my <a href="https://github.com/kenlasko/SfBEV2TeamsEV" target="_blank">Github page to get the latest version</a>. If you experience any issues, you can create an bug report through there.<br />
<br />
<h2 style="text-align: center;">
<a href="https://github.com/kenlasko/SfBEV2TeamsEV" target="_blank">https://github.com/kenlasko/SfBEV2TeamsEV</a></h2>
<br /></div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com17tag:blogger.com,1999:blog-2156539095375223979.post-75159621088265164202020-02-04T15:36:00.000-05:002020-02-06T21:43:51.222-05:00Backing up and restoring Teams Enterprise Voice configs<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKg6S_mgTkesw_ul2w67G4l6pZuTYuQcuByVhJgYzl1vGJWAH5Pb3gkBH1p2gilHFEMEKE2Zh2C2ObqGOcib7P9Z6xaQQ5cStjjO9EOV68ZMaxDRwRmq-K2W-1BBJfmnnsAbuArWcrSYA/s1600/HoffCloud.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="485" data-original-width="870" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKg6S_mgTkesw_ul2w67G4l6pZuTYuQcuByVhJgYzl1vGJWAH5Pb3gkBH1p2gilHFEMEKE2Zh2C2ObqGOcib7P9Z6xaQQ5cStjjO9EOV68ZMaxDRwRmq-K2W-1BBJfmnnsAbuArWcrSYA/s640/HoffCloud.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">In the cloud....get it?</td></tr>
</tbody></table>
<br />
Whenever I made changes to a Skype for Business Enterprise Voice configuration, either via a UCDialplans.com script or manually, I got into the habit of making a backup of the Enterprise Voice configuration. Skype for Business made this easy with an option directly in the UI that allowed you to backup and, more importantly, restore. I've made use of both options on more occasions than I can think of.<br />
<br />
In the MS Teams world, there are a few scripts out there that help you backup your Teams Enterprise Voice configuration as part of a larger backup of the entire environment. However, I haven't found one that will let you restore that backup. Now there is!<br />
<br />
I've published two PowerShell scripts that allow you to backup and then restore an MS Teams Enterprise Voice configuration in a few minutes. Slide on over to my Github page for the latest version.<br />
<br />
<h2 style="text-align: center;">
<a href="https://github.com/kenlasko/BackupRestoreTeamsEV" target="_blank">https://github.com/kenlasko/BackupRestoreTeamsEV</a></h2>
<div>
<br /></div>
<div>
<br /></div>
<h1 style="background-color: white; border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; line-height: 1.25; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em;">
BackupRestoreTeamsEV</h1>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 16px;">
PowerShell scripts that allow you to easily backup and restore your Microsoft Teams Enterprise Voice configuration</div>
<h2 style="background-color: white; border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;">
<a aria-hidden="true" class="anchor" href="https://github.com/kenlasko/BackupRestoreTeamsEV#getting-started" id="user-content-getting-started" style="background-color: initial; box-sizing: border-box; color: #0366d6; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"></path></svg></a>Getting Started</h2>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 16px;">
Download the scripts onto your local Windows machine where you normally connect to your MS Teams tenant.</div>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
<a aria-hidden="true" class="anchor" href="https://github.com/kenlasko/BackupRestoreTeamsEV#prerequisites" id="user-content-prerequisites" style="background-color: initial; box-sizing: border-box; color: #0366d6; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"></path></svg></a>Prerequisites</h3>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 16px;">
Requires that you have the Office 365 PowerShell module installed, and that you have a Microsoft Teams Enterprise Voice configuration that you are interested in backing up/restoring. You may have to set your execution policy to unrestricted to run this script:</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 16px;">
Set-ExecutionPolicy Unrestricted</div>
<h2 style="background-color: white; border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;">
<a aria-hidden="true" class="anchor" href="https://github.com/kenlasko/BackupRestoreTeamsEV#running-a-backup" id="user-content-running-a-backup" style="background-color: initial; box-sizing: border-box; color: #0366d6; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"></path></svg></a>Running a backup</h2>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 16px;">
Simply run <span style="box-sizing: border-box; font-weight: 600;">.\Backup-TeamsEV.ps1</span> from a PowerShell prompt. If you are not already connected to your Teams tenant, the script will prompt for authentication. If your admin account is not a @tenantname.onmicrosoft.com account, then you should use the <span style="box-sizing: border-box; font-weight: 600;">-OverrideAdminDomain</span> switch.</div>
<h2 style="background-color: white; border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;">
<a aria-hidden="true" class="anchor" href="https://github.com/kenlasko/BackupRestoreTeamsEV#restoring-a-backup" id="user-content-restoring-a-backup" style="background-color: initial; box-sizing: border-box; color: #0366d6; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"></path></svg></a>Restoring a backup</h2>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 16px;">
Run <span style="box-sizing: border-box; font-weight: 600;">.\Restore-TeamsEV.ps1</span> with the path to the backup file to restore. If you are not already connected to your Teams tenant, the script will prompt for authentication. If your admin account is not a @tenantname.onmicrosoft.com account, then you should use the <span style="box-sizing: border-box; font-weight: 600;">-OverrideAdminDomain</span> switch.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 16px;">
By default, the script will clean out any existing config, including dialplans, voice routes, voice routing policies, PSTN usages and translation rules. You can override this behaviour by using the <span style="box-sizing: border-box; font-weight: 600;">-KeepExisting</span> switch.</div>
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com4tag:blogger.com,1999:blog-2156539095375223979.post-8382459572206459742020-02-03T10:12:00.000-05:002020-02-04T09:46:45.113-05:00Undocumented behaviour with dialplans on MS Teams<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK1rEnRD6EFpxknpEKS_ag1XAMyiBwHnReCQSzWwvU_HHDksrHw-ggNXmjHZyaIWtewL-9WIvQ8o005oatIp2m5Id8ZqLbvrLFgQMGZV2aUwv2Y5BtDvQkTdjNTwoRC9dWdSOVM3-4zQs/s1600/HoffPhone.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="389" data-original-width="585" height="424" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK1rEnRD6EFpxknpEKS_ag1XAMyiBwHnReCQSzWwvU_HHDksrHw-ggNXmjHZyaIWtewL-9WIvQ8o005oatIp2m5Id8ZqLbvrLFgQMGZV2aUwv2Y5BtDvQkTdjNTwoRC9dWdSOVM3-4zQs/s640/HoffPhone.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Who am I talking to? Eartha Kitt? Sorry, wrong number. I was trying to call my car.</td></tr>
</tbody></table>
I've been spending a lot of time recently messing around with MS Teams dialplans thanks to the recent release of SBC-specific translation rules. For the most part, the overall structure is the same as with Skype for Business on-prem. Some PowerShell commands are different, but most of what you already know is usable in Teams.<br />
<br />
The biggest issue with Teams is that there hasn't been a UI for managing your Teams Enterprise Voice layout. This can be an issue if you are big into Direct Routing. Thankfully, Microsoft recently made available what is hopefully the first round of UI enhancements to the Teams Admin Center. You can now create and manage dialplans in the UI. Microsoft has dutifully updated their documentation to help people navigate these new features.<br />
<br />
However, there are some undocumented features that open up some interesting scenarios. Along with these are some extremely frustrating bugs that you should be aware of.<br />
<br />
<h2>
The Hidden Feature</h2>
<div>
In Skype for Business on-prem, there is a global dialplan that applies to users when there isn't an appropriate site or user-level dialplan. In the <a href="https://docs.microsoft.com/en-us/microsoftteams/what-are-dial-plans" target="_blank">Teams documentation</a>, the <b>tenant Global dialplan</b> serves a similar purpose, but there are additional features outside of what can be done on-prem. </div>
<div>
<br /></div>
<div>
In Teams, Microsoft has published a series of very simple pre-defined dialplans called <b>service country dialplans </b>that apply to nearly every country in the world. You can see these by running <b>Get-CsDialPlan</b> and <b>Get-CsVoiceNormalizationRule</b>. They do the bare minimum, and don't do any real validation. These dialplans cannot be modified. </div>
<div>
<br /></div>
<div>
The documentation goes on to say that you can define normalization rules in the <b>tenant global dialplan</b> or any number of <b>tenant user dialplans</b>. If a user tenant dialplan isn't assigned to a user, they will be assigned an effective dialplan of whatever is in the tenant global dialplan and the default service country dialplan for that user. Similarly, if a user is assigned to a tenant user dialplan, their effective dialplan will consist of the contents of the assigned tenant user dialplan along with the user's service country dialplan. The tenant dialplans have higher priority than the service country ones. </div>
<div>
<br /></div>
<div>
The hidden feature is that if you have defined any normalization rules in the tenant global dialplan, those normalization rules will appear at the top of the list of any new tenant user dialplans created afterwards. This can be very useful in large organizations with many sites, but have a common set of extension dial rules. You simply have to define the rules once in the tenant global dialplan, and they will show up in every new tenant user dialplan created from that point forward. This applies to dialplans created in both PowerShell and the Teams Admin Center.</div>
<div>
<br /></div>
<div>
Unfortunately, there isn't a real link between the tenant global and tenant user dialplans. They are simply copies of the original. If you make a change to the tenant global dialplan, it won't be reflected in all your other dialplans. As with Skype for Business, you're still stuck with using PowerShell to manage bulk changes. Overall, it might make deploying new dialplans just a little bit simpler if you choose to take advantage of this undocumented feature.<br />
<br />
<h2>
The Bugs</h2>
Unfortunately, there are also a number of annoying bugs/oversights with the new UI. Some are cosmetic, but some will force you to re-create your dialplan if you accidentally encounter one.<br />
<br />
<h3>
Description Discrepancies</h3>
<div>
If you've used UCDialplans.com to create your dialplans, you may have noticed that I make extensive use of the Description field to let people know where the rules came along with a copyright notice. I even put in linebreaks to make it readable in the SfB Control Panel UI. These descriptions are rather lengthy and go well beyond 255 characters (sorry, not sorry).</div>
<div>
<br /></div>
<div>
Here are my grievances with the Description field in the MAIN dialplan UI:</div>
<div>
<ol>
<li>The Teams admin center dialplan UI doesn't respect the linebreaks and just renders a wall of text.</li>
<li>The UI throws an error that you can only have up to 255 characters, when PowerShell allows a much higher number.</li>
<li>The UI also throws errors about "invalid characters", such as !@#$%^*()=/\[]{}:;?<>+' Again, PowerShell has no issue with any of these characters.</li>
</ol>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggagLrfb7ffqe6aTo6eElk-qip7WAmYVTjepLoTYgiX2pXKXvESdhDHA-gVDk27PXFHYDHeOJq217cRalGsdQR2j7zgrnHc4Is_WenUtGSOU76epqtcLLOFXtxReEgM6vsBp55nYnjKPo/s1600/CharacterLimit.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="82" data-original-width="238" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggagLrfb7ffqe6aTo6eElk-qip7WAmYVTjepLoTYgiX2pXKXvESdhDHA-gVDk27PXFHYDHeOJq217cRalGsdQR2j7zgrnHc4Is_WenUtGSOU76epqtcLLOFXtxReEgM6vsBp55nYnjKPo/s640/CharacterLimit.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjOL-c6MNsLs6et8d9PGTTY7nfd8rnu9_JuMTmxpz4QDZtyR1P5Jyvzn5NJsLF7WiFMxORhtPGYUO2690SPSZ0ps93dnsca6-0azq2jlmCOIVPgsL1qCWuXvIoyvxhrLdY6UPBkhI0Qd8/s1600/InvalidCharacters.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="51" data-original-width="748" height="42" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjOL-c6MNsLs6et8d9PGTTY7nfd8rnu9_JuMTmxpz4QDZtyR1P5Jyvzn5NJsLF7WiFMxORhtPGYUO2690SPSZ0ps93dnsca6-0azq2jlmCOIVPgsL1qCWuXvIoyvxhrLdY6UPBkhI0Qd8/s640/InvalidCharacters.png" width="640" /></a></div>
<br /></div>
<div>
<br /></div>
<div>
What makes this even more odd, is that the UI for the individual normalization rules exhibits <b>NONE </b>of these issues. It renders the linebreaks properly, and doesn't complain when the description is longer than 255 characters and includes "special" characters.<br />
<br />
<h3>
The External Dialing Prefix Bug</h3>
This is a big bug, and am quite surprised it made it through QA. For a bit of background, you can configure Teams so that users can dial an external access prefix (like 9), before dialing an external number. For users coming from a legacy PBX, this is undoubtedly a boon and doesn't force them to retrain years of muscle memory. It also makes off-hook dialing more reliable. For an extended explanation of this feature, <a href="https://ucken.blogspot.com/2011/03/internal-extension-dialing-in-lync.html" target="_blank">go waaay back to one of my posts from 2011 on the topic</a>. I haven't tested it myself, but the details should still apply to Teams.<br />
<br />
Most customers don't bother with this feature, and have been happily creating dialplans in Teams/Skype for Business Online for years via PowerShell without defining an external dialing prefix. However, if you create a new dialplan or edit an existing one in the UI, you will not be able to save your changes unless you set an external dialing prefix.<br />
<br />
Also, this seems to have found itself into the PowerShell commands themselves, but not completely. You can create a new dialplan with New-CsTenantDialplan without an external dialing prefix, and you can make changes to an existing dialplan with Set-CsTenantDialplan, but if you try to remove an external dialing prefix via PowerShell by setting it to either $NULL or "", you will be denied.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijCqFpfj3yA1Xl1JBVRgnqC3PS40c07FdcvfE_4rum_oQo4o5NKtegvcF1zupIFIfDp4exSr4CPySS-cEqasFfASRTEwFNd9AW7hTt9vj7ooTXVzFa6Kvh4vsdY1-Zz7piI99qO6pj-p4/s1600/BadDog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="229" data-original-width="837" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijCqFpfj3yA1Xl1JBVRgnqC3PS40c07FdcvfE_4rum_oQo4o5NKtegvcF1zupIFIfDp4exSr4CPySS-cEqasFfASRTEwFNd9AW7hTt9vj7ooTXVzFa6Kvh4vsdY1-Zz7piI99qO6pj-p4/s640/BadDog.png" width="640" /></a></div>
<br />
As long as you don't set a prefix, you should be fine. Don't do what I did and set a prefix in the UI to see what happens, and expect to be able to remove it in PowerShell. This forced me to redo my entire dialplan from scratch. Thankfully, UCDialplans.com took care of that in a minute.<br />
<br />
<h3>
Spelling Mistakes</h3>
A minor quibble, but one that will force me to keep a close eye on (boo hoo me). The New/Get/Set-CsOnlinePSTNGateway command has options for setting inbound and outbound translation rules:<br />
<br />
<ul>
<li>InboundPstnNumberTranslationRules</li>
<li>InboundTeamsNumberTranslationRules</li>
<li>OutboundPstnNumberTranslationRules</li>
<li><b>Outbund</b>TeamsNumberTranslationRules</li>
</ul>
<br />
Do you see the problem?<br /><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZNv24gRx8JytP3kMZaJbiKVwnlqxCUZEv3VSvES8fpMJUitMr7vqTzyGpVoA8TwUPVj2IBpVr1-foytmXoyoQSD8CfUcOhUYQtXhtX7plJF6mPEimZRmCmIGQwtf3vOM5qe-xr-PiwJI/s1600/SpellingFU.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="135" data-original-width="321" height="167" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZNv24gRx8JytP3kMZaJbiKVwnlqxCUZEv3VSvES8fpMJUitMr7vqTzyGpVoA8TwUPVj2IBpVr1-foytmXoyoQSD8CfUcOhUYQtXhtX7plJF6mPEimZRmCmIGQwtf3vOM5qe-xr-PiwJI/s400/SpellingFU.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Someone's spellcheck didn't work.</td></tr>
</tbody></table>
<h2>
Conclusion</h2>
<br />
I'm trying to get this in front of the right people at Microsoft to get them to fix. Hopefully, this half of my post will have a limited shelf life. Have any of you experienced any of these issues or come across any others? Let me know in the comments.</div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com11tag:blogger.com,1999:blog-2156539095375223979.post-21714840177058079492019-05-22T14:11:00.000-04:002020-03-10T08:48:58.497-04:00Useful Teams PowerShell CommandsBack in the day, <a href="https://ucken.blogspot.com/2012/07/useful-lync-powershell-scripts.html" target="_blank">I compiled a shortish list of Lync/Skype for Business PowerShell commands</a> that did some reasonably useful stuff. With my shift to Teams, I figure now is a good time to start compiling a list of semi-useful PowerShell scripts for Teams. I will add to this list as I think of them.<br />
<br />
<h2>
Getting Started</h2>
For now, there are TWO PowerShell modules for Teams-related tasks. Both require at least <a href="https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell" target="_blank">PowerShell version 5.x</a> (run <span style="background-color: #eff0f1; color: #242729; font-family: "consolas" , "menlo" , "monaco" , "lucida console" , "liberation mono" , "dejavu sans mono" , "bitstream vera sans mono" , "courier new" , monospace , sans-serif; font-size: 13px; white-space: pre-wrap;">$PSVersionTable.PSVersion</span> to check):<br />
<br />
<h3>
Skype for Business Online PS Module</h3>
The OG. You install it via <a href="https://www.microsoft.com/en-us/download/details.aspx?id=39366" target="_blank">https://www.microsoft.com/en-us/download/details.aspx?id=39366</a>. You typically connect to your tenant via some variation of the below:<br />
<blockquote class="tr_bq">
<span style="font-family: "verdana" , sans-serif;"><b>$s = New-CsOnlineSession -Credential (Get-Credential)<br />Import-PSSession $s -AllowClobber</b></span></blockquote>
<br />
<h3>
Teams PowerShell module</h3>
To install, simply run the following in an elevated PowerShell prompt:<br />
<blockquote class="tr_bq">
<b><span style="font-family: "verdana" , sans-serif;">Install-Module -Name
MicrosoftTeams -Repository PSGallery</span><span style="font-family: "calibri" , sans-serif;"> </span><span style="font-family: "calibri" , sans-serif; font-size: 11.0pt;"> </span></b></blockquote>
<br />
You then connect to your Teams tenant by running:<br />
<blockquote class="tr_bq">
<b><span style="font-family: "verdana" , sans-serif;">Connect-MicrosoftTeams</span></b></blockquote>
<br />
You will be prompted for admin credentials. Enter those, and you'll be all set!<br />
<br />
<h2>
Count All Teams Users in your Tenant (Teams PS)</h2>
<div>
There isn't a direct way to count every Teams user across your tenant. However, you can get a list of users in a specific team. Thanks to PowerShell pipelining, you can string multiple commands together to get the desired result.</div>
<blockquote class="tr_bq">
<b><span style="font-family: "verdana" , sans-serif;">(Get-Team | Get-TeamUser | Sort-Object User -Unique).Count</span></b></blockquote>
<div>
If you want to exclude external accounts who you've granted guest access to Teams, modify the command accordingly:</div>
<blockquote class="tr_bq">
<b><span style="font-family: "verdana" , sans-serif;">(Get-Team |
Get-TeamUser | Where {$_.User -notlike "*#EXT#*"} | Sort-Object User
-Unique).Count</span></b></blockquote>
You can get a count of all Skype for Business (on-prem) and Teams users, excluding duplicates by running this from a Skype for Business PS prompt:<br />
<br />
<blockquote class="tr_bq">
<b><span style="font-family: "verdana" , sans-serif;">$SfBUsers =
(Get-CsUser).SipAddress -Replace "sip:", ""</span></b> </blockquote>
<blockquote class="tr_bq">
<b><span style="mso-fareast-language: EN-US;"><span style="font-family: "verdana" , sans-serif;">Connect-MicrosoftTeams</span></span></b> </blockquote>
<blockquote class="tr_bq">
<b><span style="mso-fareast-language: EN-US;"><span style="font-family: "verdana" , sans-serif;">$TeamsUsers =
(Get-Team | Get-TeamUser | Where {$_.User -notlike "*#EXT#*"} |
Sort-Object User -Unique).User</span></span></b> </blockquote>
<blockquote class="tr_bq">
<b><span style="mso-fareast-language: EN-US;"><span style="font-family: "verdana" , sans-serif;">$CombinedUsers =
$SfBUsers + $TeamsUsers | Sort-Object -Unique</span></span></b></blockquote>
<blockquote class="tr_bq">
<b><span style="mso-fareast-language: EN-US;"><span style="font-family: "verdana" , sans-serif;">$CombinedUsers.Count</span></span></b></blockquote>
<br />
<h2>
List All Cloud Auto-Attendants and Associated Numbers (Skype PS)</h2>
Can't get a list of just the AA phone number from Get-CsAutoAttendant. You have to parse the resource account list for this.<br />
<blockquote class="tr_bq">
<span style="font-family: "verdana" , sans-serif;"><b>$AAList = Get-CsAutoAttendant<br />New-Item -Path AAPhoneNum.csv -Value "Name,PhoneNumber`r`n" -Force | Out-Null<br />ForEach ($AA in $AAList) {<br /><span style="white-space: pre;"> </span>ForEach ($AppInstance in $AA.ApplicationInstances) {<br /><span style="white-space: pre;"> </span>$AAName = $AA.Name<br /><span style="white-space: pre;"> </span>$AppPhoneNum = (Get-CsOnlineApplicationInstance -Identity $AppInstance).PhoneNumber<br /><span style="white-space: pre;"> </span>Write-Host "$AAName $AppPhoneNum"<br /><span style="white-space: pre;"> </span>Add-Content -Path AAPhoneNum.csv -Value "$AAName,$AppPhoneNum"<br /><span style="white-space: pre;"> </span>}<br />}</b></span></blockquote>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com2tag:blogger.com,1999:blog-2156539095375223979.post-78998911959356321762019-02-21T12:30:00.000-05:002019-02-21T12:30:32.742-05:00Can You Install an SDN Listener in a SfB CCE Environment?<div>
As part of my job at <a href="https://www.nectarcorp.com/" target="_blank">Nectar Corp</a>, I'm always looking at ways to get call detail information from various Microsoft-based UC telephony components. It's easy to get a wealth of detail from an on-prem deployment of Skype for Business, using either direct access to the SfB monitoring databases (for historical info) or via the Skype for Business SDN dialog listeners (for realtime call data). <a href="https://ucken.blogspot.com/2019/02/ms-cloud-analytics-current-state.html" target="_blank">As mentioned in my recent blog post</a>, the same cannot be said for Office 365 UC workloads such as SfB Online and Teams.<br />
<br />
Nectar has a tool that relies on knowing when a call starts and stops in realtime so we can gather information from various network components as the call is happening. Nectar uses the SfB SDN interface for this realtime info. Since both SfBO and Teams lack ANY sort of call data API, we have to resort to other methods to learn about realtime calls.<br />
<br />
A Nectar customer has deployed several <a href="https://docs.microsoft.com/en-us/skypeforbusiness/skype-for-business-hybrid-solutions/plan-your-phone-system-cloud-pbx-solution/plan-skype-for-business-cloud-connector-edition" target="_blank">Skype for Business Cloud Connector Edition (CCE) instances</a> to provide on-prem PSTN call routing for SfB Online users. CCE is the precursor of Teams Direct Routing, and it does essentially the same thing but in a WAAAAAAY more complex manner. It consists of several pre-packaged VMs running a vastly slimmed down Skype for Business environment.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXBaNeuzi0f1MoyowTqd-YGfGcLz7FX-kDcX8_UjAZ_1XDApC5hMvnCd8iXw9bs8Zp69e5kualfVGHAMvdKVUy025X0T2dJiT4Bcq-49jR6mJla9Bo-QYdmQvSyE7gyO6i03nzqp-azVM/s1600/CCEVMs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="351" data-original-width="222" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXBaNeuzi0f1MoyowTqd-YGfGcLz7FX-kDcX8_UjAZ_1XDApC5hMvnCd8iXw9bs8Zp69e5kualfVGHAMvdKVUy025X0T2dJiT4Bcq-49jR6mJla9Bo-QYdmQvSyE7gyO6i03nzqp-azVM/s400/CCEVMs.png" width="252" /></a></div>
<br />
We were in discussions with the customer to see if there was any way we could get realtime call info from the CCE instances, by installing the Microsoft SDN Dialog Listener on any of the CCE VMs. Nobody seemed to know for certain, so I elected to setup a CCE instance of my own to run some tests. The question I was trying to answer was:<br />
<h2 style="text-align: center;">
Can you get call data out of a CCE instance using the MS SDN Listener service??? </h2>
<b>TL;DR:</b> No.</div>
<div>
<br />
I had built myself a fancy new work PC at home that I figured would be ideal for this test. I put in 32GB of RAM so I could spin up VMs as needed for my tests, and this would be an excellent test <b>OR SO I THOUGHT!</b><br />
<b><br /></b>
My first hurdle was that I needed a virtual machine host that would host the VMs required for CCE. In other words, I needed to run VMs from within a VM.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgead9zrtHFgFxGbYIPaUY60G3fJ2kDkT2j8HkmQTTpXcABoz1ehwaBVq8AUgAIrZROoYsfT7y27Mf8msQmtLJOncuvQE_gmbBHbVMKUzDhyPrskOZJrsioAWULv-fIYzucR1v9ZC1AbQU/s1600/Inception.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="500" data-original-width="338" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgead9zrtHFgFxGbYIPaUY60G3fJ2kDkT2j8HkmQTTpXcABoz1ehwaBVq8AUgAIrZROoYsfT7y27Mf8msQmtLJOncuvQE_gmbBHbVMKUzDhyPrskOZJrsioAWULv-fIYzucR1v9ZC1AbQU/s640/Inception.jpg" width="432" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Just like the movie, except much more boring.</td></tr>
</tbody></table>
CCE only supports Windows 2012 R2 as the VM host OS, so I started with that as my VM host for my VMs, but it blocked me from installing the Hyper-V components, since it was already a VM. A bit of research showed that I could use Windows Server 2019, which had no such limitation. I spun up my Hyper-V host VM, gave it 24 GB of RAM, all the processor cores I had, and off I went.<br />
<br />
<b>...OR SO I THOUGHT (AGAIN)</b>. I ran into issues right off the bat when installing the CCE components, where most of the CCE PowerShell commands were available. Thanks to a <a href="https://shawnharry.co.uk/2017/07/18/installing-skype-for-business-cloud-connector-edition-cce-on-a-windows-server-2016-hyper-v-host/" target="_blank">workaround from Shawn Harry</a>, I was soon off to the races and installing CCE.<br />
<br />
...BUT NO! FOILED AGAIN!!! There are a number of steps to deploy a CCE instance, most of which require running various CCE PowerShell commands. One of these commands performed a hardware check to make sure the Hyper-V host had enough resources to run the required VMs. I was rudely informed that my <b>super-awesome, brand-new workstation PC </b>did not have enough memory, processor cores or disk space to run CCE.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDGyi5HkUzyYo-EIX8ZQ7KXYNSrXOtjtFH7-jaqEu4CS5VeArjrVsdlFnbE49lxc6jYQyyXuxSygeUnjzS7s3JWuZi_F_c1FSES9DTKwVdMK-EfNv40E4ywJ4TX2qJFvc9Xu3nOR3lFkM/s1600/SadKeanu.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="720" data-original-width="1280" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDGyi5HkUzyYo-EIX8ZQ7KXYNSrXOtjtFH7-jaqEu4CS5VeArjrVsdlFnbE49lxc6jYQyyXuxSygeUnjzS7s3JWuZi_F_c1FSES9DTKwVdMK-EfNv40E4ywJ4TX2qJFvc9Xu3nOR3lFkM/s640/SadKeanu.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Keanu is sad, and so am I</td></tr>
</tbody></table>
Time to implement my hacker skilz.<br />
<br />
The big red, failure message that PowerShell spit out at me helpfully included the path to the script that did the hardware check:<br />
<br />
<div style="text-align: center;">
<b>C:\Program Files\WindowsPowerShell\Modules\CloudConnector\Internal\MtCommon.ps1</b></div>
<br /></div>
<div>
A quick review of that script, and a few edits to the <b>$logicalProcessorsCount</b>, <b>TotalPhysicalMemory</b>, <b>FreePhysicalMemory</b>, and <b>FreeDiskSize </b>variables and the script was convinced that I had a super-server with 999999999999 MB of memory, diskspace and processor cores.<br />
<br />
With a few more tweaks here and there, I was finally able to get a full Skype for Business Cloud Connector Edition instance running in my modest home lab. Since the CCE environment consists of several standard Windows VMs, I was able to login to them and attempt to install the SDN Listener on what I hoped would be possible candidates: the CMS or the Mediation VM.<br />
<br />
Neither of those were running as a full front-end server, but I still held out hope. The CMS VM was running the Centralized Logging Service Agent, File Transfer Agent and Master/Replica Replicator Agents. The Mediation VM was running the Centralized Logging Service Agent, Mediation service and Replica Replicator Agents.<br />
<br />
I attempted to install the SDN Listener on both those VMs and got the following message:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvf4AouNX4KSh66ssahNzq2WN6HsY6KfWA_NvlUqiSee3odbvvEbw0HW0gkKDTe2ztbSAIHmkcmIi4Xn7dwdQGZWPdR31ZjicJtqe2SLTJDKSlUYgz_atbXr5Fl72_Ym8PCrn0HxF2dDU/s1600/Denied.png.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="400" data-original-width="509" height="502" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvf4AouNX4KSh66ssahNzq2WN6HsY6KfWA_NvlUqiSee3odbvvEbw0HW0gkKDTe2ztbSAIHmkcmIi4Xn7dwdQGZWPdR31ZjicJtqe2SLTJDKSlUYgz_atbXr5Fl72_Ym8PCrn0HxF2dDU/s640/Denied.png.jpg" width="640" /></a></div>
<br />
And there you go. The answer to a question that nobody else was looking for. <b>No, you can't run SDN on any CCE VM role.</b><br />
<br />
Hope you're happy <a href="https://twitter.com/ucomsgeek/status/1098298381699432453" target="_blank">@ucomsgeek</a>.<br />
<br /></div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-4119366356039413872019-02-20T13:58:00.003-05:002019-02-20T14:14:06.828-05:00The Current State of Microsoft Cloud-Based Call AnalyticsMicrosoft Teams continues to evolve at a rapid pace, and
nearly every company who currently runs on-prem Microsoft Skype for Business
deployments are investigating the feasibility of moving their UC infrastructure
to the cloud.<br />
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
While moving UC workloads to the cloud eliminates the need
for most (if not all) customer-owned server hardware, UC media still must
traverse the customer network. Since the network is one of the major causes of
poor call quality, customers still require advanced troubleshooting capabilities.<o:p></o:p></div>
<div class="MsoNormal">
Microsoft does provide some basic call analytics in Office
365, but there is much room for improvement. As such, many 3<sup>rd</sup> party
vendors (including Nectar, the company I work for) are keen to fill the gaps. Unfortunately,
there is a lot of confusion and misdirection in the marketplace about what is
possible with 3<sup>rd</sup> party call analytics in Office 365 UC platforms. <o:p></o:p></div>
<h2>
Skype for Business Online<o:p></o:p></h2>
<div class="MsoNormal">
Even though Skype for Business Online is being deprecated in
favour of Microsoft Teams, there are still many customers who have not made the
transition. As mentioned previously, Microsoft does provide some limited call
analytics and reporting capabilities for both SfBO and Teams at no extra cost,
but the available tools only show a subset of the available information, presented
in limited ways. A dedicated person can customize the tools to meet some of
their needs, but this takes time, effort and deep knowledge. <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
This is the ideal place for other companies to provide
additional value. Unfortunately, the only way to access detailed call analytics
is to use the <span class="MsoHyperlink"><b style="mso-bidi-font-weight: normal;"><a href="https://docs.microsoft.com/en-us/powershell/module/skype/get-csusersession?view=skype-ps" target="_blank">Get-CsUserSession<span style="font-weight: normal;"> PowerShell command</span></a></b></span> (included
as part of the <span class="MsoHyperlink"><a href="https://www.microsoft.com/en-us/download/details.aspx?id=39366" target="_blank">Skype forBusiness Online PS Module</a></span>). <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The output of the <b style="mso-bidi-font-weight: normal;">Get-CsUserSession</b>
command provides detailed CDR and quality information for a specified user over
a specified timeframe in JSON format. Much of the detail is not available in
the existing O365 dashboards. At first blush, this appears to be a fantastic
way to import detailed call data into 3<sup>rd</sup> party call analytics
platforms, but there are some significant limitations:</div>
<div class="MsoNormal">
</div>
<ul>
<li><span style="text-indent: -18pt;">The </span><b style="text-indent: -18pt;">Get-CsUserSession</b><span style="text-indent: -18pt;">
command only returns data for a single user</span></li>
<li><span style="text-indent: -18pt;">No built-in delta mechanism, so no way to return
only new/updated information since the last time the command was run</span></li>
<li><span style="text-indent: -18pt;">Data is only available for 30 days</span></li>
</ul>
<br />
<div class="MsoListParagraphCxSpFirst" style="mso-list: l1 level1 lfo1; text-indent: -18.0pt;">
<!--[if !supportLists]--><o:p></o:p></div>
<div class="MsoListParagraphCxSpMiddle" style="mso-list: l1 level1 lfo1; text-indent: -18.0pt;">
<o:p></o:p></div>
<div class="MsoListParagraphCxSpLast" style="mso-list: l1 level1 lfo1; text-indent: -18.0pt;">
<o:p></o:p></div>
<div class="MsoNormal">
Theoretically, a tool could constantly run the <b style="mso-bidi-font-weight: normal;">Get-CsUserSession</b> command for every
user in the enterprise, but this is not an approach that scales to the
enterprise-level.<span style="mso-spacerun: yes;"> </span>Nectar looked at this
but discarded it after early tests showed inherent scalability issues.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Another approach would be to provide a GUI front-end that
simply runs the <b style="mso-bidi-font-weight: normal;">Get-CsUserSession</b> in
the background on demand for a specified user. This avoids any scalability
issues and can provide some useful information on a given user’s call quality.
However, this approach doesn’t allow for any enterprise-level reporting or
trending data, since data for all users is never downloaded. <o:p></o:p></div>
<h2>
Microsoft Teams</h2>
<h2>
<o:p></o:p></h2>
<div class="MsoNormal">
As mentioned in the previous section, customers have access
to a limited portfolio of Teams call analytics tools through their Office 365
subscription. There is room for improvement and vendors are anxious to show
value in this area.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
At the time of writing, there is absolutely no way to access
detailed call analytics about Microsoft Teams calls or conferences. The <b style="mso-bidi-font-weight: normal;">Get-CsUserSession</b> command discussed in
the previous section only returns call data for SfBO calls.<span style="mso-spacerun: yes;"> </span>Some Teams PSTN calls may show up in <b style="mso-bidi-font-weight: normal;">Get-CsUserSession</b> results, but that’s
because it appears PSTN calls are routed through SfBO infrastructure. Detailed
call data on P2P calls or conferences are not available.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Some vendors provide some great analytics about Teams <b style="mso-bidi-font-weight: normal;">usage</b> (channel members, activity etc).
These analytics are provided through the <span class="MsoHyperlink"><a href="https://docs.microsoft.com/en-us/graph/api/resources/teams-api-overview?view=graph-rest-1.0" target="_blank">Office365 Graph API</a></span> and does not provide any detailed call analytics.
Through misunderstanding or miscommunication, some customers end up confusing
this point and think they can get the same level of call quality
troubleshooting as they currently can from on-prem Skype for Business
deployments. <o:p></o:p></div>
<h2>
The Future of Microsoft’s Cloud-Based Analytics</h2>
<h2>
<o:p></o:p></h2>
<div class="MsoNormal">
Microsoft has not shared any information about when or if they
will release an API that will allow vendors to incorporate Teams call data into
their existing call analytics platforms. Rest assured that Nectar is keeping a
close eye on the situation and will be able to incorporate Office365 call
analytics into our call analytics platform as soon as something is available. <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
In the meantime, if a vendor is promising they can do
advanced analytics for Microsoft’s cloud platform, think of this and ask the
right questions:</div>
<div class="MsoNormal">
</div>
<ul>
<li><span style="text-indent: -18pt;">Exactly what kind of call data can the tool
retrieve? (MOS scores, jitter, packet loss etc)</span></li>
<li><span style="text-indent: -18pt;">How does the tool get data from Office365?</span></li>
<li><span style="text-indent: -18pt;">Does the tool provide detailed call quality reports
for the entire enterprise?</span></li>
</ul>
<br />
<div class="MsoListParagraphCxSpLast" style="mso-list: l0 level1 lfo2; text-indent: -18.0pt;">
<o:p></o:p></div>
<div class="MsoNormal">
If you get appropriate answers, then you can make a more
informed decision on purchasing a call analytics platform for your cloud-based UC
platforms.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
This article was also posted on <a href="https://www.nectarcorp.com/blog/the-current-state-of-microsoft-cloud-based-call-analytics/" target="_blank">Nectar's website</a> and <a href="https://telecomreseller.com/2019/02/19/the-current-state-of-microsoft-cloud-based-call-analytics/" target="_blank">Telecom Reseller</a></div>
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-67706389821261035662018-10-01T08:35:00.001-04:002020-06-10T08:52:13.232-04:00Run PowerShell Core in Docker on Raspberry PiI've recently started playing around with the latest <a href="https://www.raspberrypi.org/products/raspberry-pi-3-model-b-plus/" target="_blank">Raspberry Pi 3 B+</a> along with a <a href="https://www.raspberrypi.org/products/poe-hat/" target="_blank">PoE HAT</a>, which is an amazing little piece of kit. I've been trying to offload a bunch of workloads that are currently being served by an aging Windows 10 PC whose primary role is a media PC. This very same PC used to run <a href="https://en.wikipedia.org/wiki/Windows_Media_Center" target="_blank">Windows Media Center on Windows XP</a>, before I turned to XBMC/Kodi and then Plex. It's well over a decade old, but still going strong. Although, now that I think of it, the only thing that's probably still original is the case, since I've replaced the motherboard, videocard, disk drives, and power supply over the years.<br />
<br />
Since I've worked with Docker in the past (most recently with <a href="http://ucken.blogspot.com/2018/03/the-evolution-of-skype-optimizer.html" target="_blank">a failed attempt to move the Skype Optimizer to a Docker container</a>), I thought I'd try running Docker on the Raspberry Pi.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZTCxoKc4MTOZuy7opRUVi1ZkFHcP8S2Yojackvckn2ef5FAwghXMuZXzFFHGG2wGmf4qR50wpki6LdSv4wNfcIBQj-Uu6_Tt4wztuI5GJKz_pWI7oZavyDPcW43y00lex1_WoR8vcwpk/s1600/MVIMG_20180919_103052.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1600" data-original-width="1200" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZTCxoKc4MTOZuy7opRUVi1ZkFHcP8S2Yojackvckn2ef5FAwghXMuZXzFFHGG2wGmf4qR50wpki6LdSv4wNfcIBQj-Uu6_Tt4wztuI5GJKz_pWI7oZavyDPcW43y00lex1_WoR8vcwpk/s640/MVIMG_20180919_103052.jpg" width="480" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">My home networking setup in the basement furnace room. My Raspberry Pi is circled in red.</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
I've been pretty successful in getting things working efficiently on Docker. At the time of writing this post, I've got the following Docker containers running on my little Pi:<br />
<ul>
<li><a href="https://traefik.io/" target="_blank">Traefik</a> - an easy-to-use reverse proxy solution so that I can access the different container UIs by using https://<i>containername</i>.ucdialplans.com, instead of http://192.168.1.x:<i>somerandomport</i>. It also simplifies certificate management, since I only have to do it once in Traefik with a wildcard cert, rather than on every container.</li>
<li><a href="https://portainer.io/" target="_blank">Portainer</a> - a GUI for container management, so I don't have to remember specific commands</li>
<li><a href="https://pi-hole.net/" target="_blank">Pihole</a> - a DNS blackhole for ads. Blocks ads for all devices on my internal network. Tidbit: its currently blocking almost 50% of my total DNS queries!</li>
<li><a href="https://radarr.video/" target="_blank">Radarr</a>/<a href="https://sonarr.tv/" target="_blank">Sonarr</a>/<a href="https://github.com/Jackett/Jackett" target="_blank">Jackett</a> - *cough cough* media management</li>
<li><a href="https://www.ubnt.com/software/" target="_blank">Unifi Controller</a> - manages my amazing-how-did-I-live-before-this wifi infrastructure</li>
<li><a href="https://www.noip.com/" target="_blank">NOIP</a> - publishes my ever-changing public IP address to Noip.com.</li>
<li><a href="https://hub.docker.com/r/kenlasko/powershellpi/" target="_blank">PowerShellPi</a> - Runs PowerShell scripts</li>
</ul>
<div>
It was the last one that took me the most work to get going. While there are several published PowerShell Docker containers for Linux, there didn't seem to be any that would work with the ARM processors inside the Raspberry Pi. </div>
<div>
<br /></div>
<div>
After much trial-and-error (story of my life), I finally managed to build a working Docker image that works with the Raspberry Pi. I used some of the bits from <a href="https://blogs.technet.microsoft.com/stefan_stranger/2017/12/28/running-powershell-core-on-raspberry-pi-2/" target="_blank">this TechNet blog</a> to get the right commands, but had to make some modifications for it to work on the latest Raspberry Pi version. </div>
<div>
<br /></div>
<div>
I'm using this base image to build other images that run simple scripts on a schedule. For example, I've got one that checks my public IP, and updates an Azure DNS record when it changes. It does the same thing as the NOIP one, but its something that's fully under my control.</div>
<div>
<br /></div>
<div>
For those who are interested, the base image is available on <a href="https://hub.docker.com/">https://hub.docker.com</a> under <a href="https://hub.docker.com/r/kenlasko/powershellpi/" target="_blank"><b>kenlasko/powershellpi</b></a>. The DockerFile used to build this image is shown below (since I haven't figured out how to display it on Docker Hub yet).</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"># PowerShell on Raspberry Pi</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">#</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"># Version 1.0</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">FROM raspbian/stretch</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">LABEL maintainer="Ken.Lasko@gmail.com"</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">RUN sudo apt-get update</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"># Install libraries necessary for PowerShell</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">RUN sudo apt-get install --no-install-recommends -y libunwind8 libicu57 libcurl4-openssl-dev cron</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"># Get the latest released PS module</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">RUN wget https://github.com/PowerShell/PowerShell/releases/download/v6.0.4/powershell-6.0.4-linux-arm32.tar.gz</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"># Make PowerShell directory and install PS module</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">RUN mkdir ~/powershell && tar -xvf ./powershell-6.0.4-linux-arm32.tar.gz -C ~/powershell && sudo ln -s ~/powershell/pwsh /usr/bin/pwsh && sudo ln -s ~/powershell/pwsh /usr/local/bin/powershell</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"># Remove install files after completion</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">RUN sudo rm -rf /var/lib/apt/lists && rm powershell-6.0.4-linux-arm32.tar.gz</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"># Install PS modules (Azure auth and DNS modules shown as examples)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">#RUN ~/powershell/pwsh -Command Install-Module -Name AzureRM.Profile.Netcore -Force && ~/powershell/pwsh -Command Install-Module -Name AzureRM.Dns.Netcore -Force</span></div>
</div>
<div>
<br /></div>
<br />
My next move is to get a few more Raspberry Pis to create a <a href="https://docs.docker.com/engine/swarm/" target="_blank">Docker Swarm </a>to automatically load-balance my containers, just like a wee little datacenter!<br />
<br />
This is for you, <a href="https://www.ucunleashed.com/" target="_blank">Pat</a>!Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-84088194511587371922018-09-18T21:00:00.003-04:002019-06-11T08:59:18.739-04:00Skype Optimizer JSON Interface Now AvailableFor people who like to have more control over how dial rules are implemented but want to leverage my vast database of worldwide dial rules, I have implemented a JSON interface for the Skype Optimizer.<br />
<div>
<br /></div>
<div>
The interface will return all the dial rules for a given country in JSON format, which can then be used in your own scripts or application. </div>
<div>
<br /></div>
<div>
To access the API, you simply construct the URL to correspond to the correct representation for the desired country. The base URL for the JSON interface starts with:</div>
<div>
<br /></div>
<div>
<b>https://www.ucdialplans.com/queryapi/</b></div>
<div>
<br /></div>
<div>
You then add specific options as query strings. For NANPA countries like US, Canada and many Caribbean countries, use the following:</div>
<div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: none; margin-left: -0.4pt; text-align: center;"><tbody>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 180pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: left;">
<b>Query String</b>
</div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 180pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: left;">
<b>Data Value<o:p></o:p></b></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 180pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: left;">
<b>Required?<o:p></o:p></b>
</div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
countrycode
</div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
<span style="background-color: white;">1</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
Yes</div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">npa</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
<span style="background-color: white;">3-digit integer</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
Yes</div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">nxx</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
<span style="background-color: white;">3-digit integer</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
Yes</div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">natscope</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
national/uscan/all</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
No (defaults to <b>national</b>)</div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">sevendigit</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
<span style="background-color: white;">yes/no;1/0;true/false</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
No (defaults to <b>no</b>)</div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">apikey</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
<span style="background-color: white;">16-character alphanumeric</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
Yes</div>
</div>
</td></tr>
</tbody></table>
</div>
<div>
<br /></div>
<div>
For an example location in Chicago, where we want to treat both US and Canada numbers as national numbers, use the following:<br />
<blockquote class="tr_bq">
<span style="font-family: "arial" , "helvetica" , sans-serif;">https://www.ucdialplans.com/queryapi/?countrycode=1&npa=312&nxx=226&natscope=uscan&apikey=<i>yourapikeyhere</i></span></blockquote>
<br />
For any other country, the available query strings are as follows:<br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: none; margin-left: -0.4pt; text-align: center;"><tbody>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 180pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: left;">
<b>Query String</b></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 180pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: left;">
<b>Data Value<o:p></o:p></b></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 180pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: left;">
<b>Required?<o:p></o:p></b></div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
countrycode</div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
<span style="background-color: white;">1-3 digit integer value</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
Yes</div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">areacode</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
<span style="background-color: white;">1-6 digit integer value</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
Most countries</div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
carriercode</div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; text-align: left; width: 40pt;" valign="top" width="38">1-3 digit integer value</td><td style="border: 1pt solid; padding: 0cm 5.4pt; text-align: left;" valign="top" width="140">Some countries</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">apikey</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: left;">
<span style="background-color: white;">16-character alphanumeric</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: left;">
Yes</div>
</div>
</td></tr>
</tbody></table>
</div>
<div>
<br /></div>
<div>
For example, to return the dial rules for London, UK use the following URL:</div>
<div>
<blockquote class="tr_bq">
<span style="line-height: 106%;"><span style="color: black; font-family: "arial" , "helvetica" , sans-serif;">https://www.ucdialplans.com/queryapi/?countrycode=44&areacode=20&apikey=<i>yourapikeyhere</i></span></span></blockquote>
The results will look something like this, when you parse it through a JSON formatter:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDPBTd9lbl86VlvePrMy0zPlO_XogEEFeUBigwBrn2uedNwVdEysJWnSd8gUHKfXs_HK6_hcHj4YCUJvJW14I7m1p6ISzCpy50qLtxlhyphenhyphenvNgI6G3DqCU0swKEuS8VckeO4-msFfdYYn2E/s1600/JSONOutput.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1591" data-original-width="1600" height="636" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDPBTd9lbl86VlvePrMy0zPlO_XogEEFeUBigwBrn2uedNwVdEysJWnSd8gUHKfXs_HK6_hcHj4YCUJvJW14I7m1p6ISzCpy50qLtxlhyphenhyphenvNgI6G3DqCU0swKEuS8VckeO4-msFfdYYn2E/s640/JSONOutput.png" width="640" /></a></div>
<br />
One way to use this data is in your own personal PowerShell script. Below is an example that will pull down the dial rules for 312-226 in Chicago:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">$DialPlan = "https://www.ucdialplans.com/queryapi/?countrycode=1&npa=312&nxx=226&apikey=abc1234567890xyz"<br />$JSON = Invoke-RestMethod -Method Get -Uri $DialPlan</span></blockquote>
Once you've got the JSON data, you can return specific elements simply by "following the path", as it were:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">PS C:\> $JSON.data.routes</span><span style="font-family: "courier new" , "courier" , monospace;"><br /></span><span style="font-family: "courier new" , "courier" , monospace;"><br /></span><span style="font-family: "courier new" , "courier" , monospace;">local : {@{pattern=^\+1((872([^01]\d\d))|(847([^01]\d\d))...</span><span style="font-family: "courier new" , "courier" , monospace;"><br /></span><span style="font-family: "courier new" , "courier" , monospace;">tollfree : @{pattern=^\+18(00|8\d|77|66|55|44|33|22)\d{7}$}</span><span style="font-family: "courier new" , "courier" , monospace;">premium : @{pattern=^\+1(900|976)[2-9]\d{6}$}</span><span style="font-family: "courier new" , "courier" , monospace;">national : @{pattern=^\+1(?!(24[26]|26[48]|284|345|441|473|649|664|721|[67]58|767|784|8[024]9|86[89]|876|900|976))</span><span style="font-family: "courier new" , "courier" , monospace;"> [2-9]\d\d[2-9]\d{6}$}</span><span style="font-family: "courier new" , "courier" , monospace;">international : @{pattern=^\+((1(?!(900|976))[2-9]\d\d[2-9]\d{6})|([2-9]\d{6,14}))}</span><span style="font-family: "courier new" , "courier" , monospace;">service : @{pattern=^\+?([2-9]11)$}</span></blockquote>
<br />
You can get as specific as you want:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">PS C:\> $JSON.data.normrules.national.pattern</span><span style="font-family: "courier new" , "courier" , monospace;">^1?([2-9]\d\d[2-9]\d{6})\d*(\D+\d+)?$</span><span style="font-family: "courier new" , "courier" , monospace;">PS C:\> $JSON.data.routes.international.pattern</span><span style="font-family: "courier new" , "courier" , monospace;">^\+((1(?!(900|976))[2-9]\d\d[2-9]\d{6})|([2-9]\d{6,14}))</span></blockquote>
For elements that <b>could</b> have multiple values, such as local routes, you have to write it a little bit differently (note the square brackets):<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">PS C:\> $JSON.data.routes.local<b>[0]</b>.pattern</span><span style="font-family: "courier new" , "courier" , monospace;">^\+1((872([^01]\d\d))|(847([^01]\d\d))|(815(20[^189]|21[^1378]|22[01348]|23[067]|24[125]|25[02458]|26[^2469]|27[^035]|28[07]|29[0345]|30[^39]|31[03478]|32[^39]|33[^2569]|34[^0]|35[^089]|36[1346]|37[^5689]|38[23568]|40[^026]|41[^149]|42[^089....</span></blockquote>
You must also include a valid API key. For testing purposes, I've created a demo API key that anybody can use.<br />
<blockquote class="tr_bq">
<div style="text-align: center;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-large;">abc1234567890xyz</span></div>
</blockquote>
The output will be obfuscated to deter abuse, but is otherwise valid JSON. Please give it a try, and if you feel there is a place for this in your company or application, please contact me through the usual channels.<br />
<br />
The APIs have been documented on <a href="https://app.swaggerhub.com/apis-docs/kenlasko/UCDialplans/" target="_blank">SwaggerHub</a>, where you can check them out and even run tests to see what the output looks like.<br />
<br />
I have to give thanks to longtime <a href="http://blog.ucomsgeek.com/" target="_blank">SfB/Teams MVP Jonathan McKinney</a> for pushing me to do this, and to help test it along the way. Beers are inbound!</div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-60529145309026388852018-06-06T16:01:00.003-04:002020-06-10T08:52:14.894-04:00Teams Direct Routing Now Supported in the Skype OptimizerSince Microsoft made <a href="https://techcommunity.microsoft.com/t5/Microsoft-Teams-Blog/Direct-Routing-NOW-in-Public-Preview/ba-p/193915" target="_blank">Teams Direct Routing available as a preview</a>, I've been working to modify the <a href="https://www.ucdialplans.com/" target="_blank">Skype Optimizer</a> codebase to support it. Finally, after weeks of coding and testing, I'm pleased to announce that the Skype Optimizer now fully supports Teams Direct Routing.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6HqiEJXk8KPUhXbENwtLoMaL5nbTPMHBad8PdgBnQ8kWZeGtkUH-G0mB6W1OpRh0nsImT8wc0Jnto1TC7cHMMUY9dRKTGnQFFiQHLArZwIKXCjBIYZ1dRnS_XQnAtGATZh4aB2ZCSk8g/s1600/Teams-In-Skype+Optimizer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="920" data-original-width="1028" height="572" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6HqiEJXk8KPUhXbENwtLoMaL5nbTPMHBad8PdgBnQ8kWZeGtkUH-G0mB6W1OpRh0nsImT8wc0Jnto1TC7cHMMUY9dRKTGnQFFiQHLArZwIKXCjBIYZ1dRnS_XQnAtGATZh4aB2ZCSk8g/s640/Teams-In-Skype+Optimizer.png" width="640" /></a></div>
<br />
<br />
O365-native PSTN calling is only available for a small number of countries. A lot of companies have held off from migrating to the cloud until there was some way of allowing PSTN calling for users in the other countries that aren't supported in O365. Direct Routing allows customers basically anywhere in the world to move their users to Office 365 while allowing telephony connections to their provider of choice via on-premises PSTN gateways.<br />
<br />
Direct Routing in Teams works almost exactly the same as it does in Skype for Business on-premises. The only differences are in how normalization rules are handled (which I talked about in an <a href="http://ucken.blogspot.com/2017/04/tenant-dial-plans-in-skype-for-business.html" target="_blank">earlier post</a>), and there is no support for trunk translation rules. This means that if you have to do any manipulation of numbers before sending to another PBX or the PSTN, you will have to do it at the PSTN gateway level.<br />
<br />
There are still voice policies, routes and PSTN usages that are combined together to provide nearly limitless ways to control how phone calls are routed in your company. The difference is really just in the name of the PowerShell commands, as shown below.<br />
<br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: none; margin-left: -0.4pt; text-align: center;"><tbody>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 180pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: center;">
<b>Skype for Business<o:p></o:p></b></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 180pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: center;">
<b>Teams Direct Routing<o:p></o:p></b></div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt;" valign="top" width="140"><div class="MsoNormal">
<div style="text-align: center;">
<span style="background-color: white;">Get-CsVoicePolicy</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">Get-CsOnlineVoiceRoutingPolicy</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: center;">
<span style="background-color: white;">Get-CsVoiceRoute</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">Get-CsOnlineVoiceRoute</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: center;">
<span style="background-color: white;">Get-CsPstnUsage</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 40pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">Get-CsOnlinePstnUsage</span></div>
</td></tr>
</tbody></table>
<br />
Fortunately, since the underlying concepts are still the same, that means the Skype Optimizer can still provide many of the same features to Teams as with on-prem deployments. This includes:<br />
<br />
<ul>
<li>Class of Service</li>
<li>Least-cost/failover routing</li>
<li>Extension ranges</li>
</ul>
<div>
Skype Optimizer features not currently supported in Teams include:</div>
<div>
<ul>
<li>Location-based routing</li>
<li>Selective caller-ID blocking</li>
<li>Premium number blocking via Announcement service</li>
<li>Call Park</li>
</ul>
<div>
The PowerShell script generated by the Skype Optimizer builds on the same codebase used for Skype for Business Online scripts. The only prerequisite is that you have already paired one or more PSTN gateways to your Office 365 tenant using the <span style="background-color: #f9f9f9; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-size: 0.875rem;"><a href="https://docs.microsoft.com/en-us/SkypeForBusiness/skype-for-business-hybrid-solutions/plan-your-phone-system-cloud-pbx-solution/configure-direct-routing" target="_blank">New-CsOnlinePSTNGateway</a> </span>command. If you haven't done this step, the Skype Optimizer script will only create normalization rules that will apply to both Skype for Business Online and Teams. </div>
</div>
<div>
<br /></div>
<div>
Please try out the new functionality and let me know if you experience any issues.</div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-82264187672225248132018-03-12T22:41:00.003-04:002020-06-10T08:52:15.449-04:00The Evolution of the Skype Optimizer: From Locally-Run VBScript to Azure Web AppI was recently amazed when I realized the seeds of what is now the<a href="https://www.ucdialplans.com/" target="_blank"> Skype Optimizer</a> was created 10 YEARS AGO, back when Office Communications Server 2007 R2 was starting to make headway in the unified communications space.<br />
<br />
<h3>
The Beginning</h3>
The genesis of the program grew out of a need to know when to strip the +1 from a North American local number and when not to. Rather than rehash the creation myth, you can <a href="https://ucken.blogspot.com/2010/08/dialing-rule-optimizer-for-e164-phone.html" target="_blank">read all about it from one of my earliest blog posts where I announced the Dialing Rule Optimizer to the world</a> (at that time, the 30-odd subscribers to my blog).<br />
<br />
The very first version was a straight VBScript that I had to manually input the proper variables and run it by hand. Rather than give the code away, I told people to email me the phone numbers they wanted to get optimized dial rules for. I would run the script and send them the results, which was a simple text file with either a bunch of regex, or text formatted to be applied to AudioCodes or Dialogic gateways. Word got around within Microsoft, and I found myself busy sending stuff to various Microsoft consultants.<br />
<br />
When Lync 2010 came around, which was in its earliest days known as <b>Communications Server "14"</b>, I added the capability to create simple routing rules that consisted of a few lines of PowerShell code. I also wrapped the code around a simple UI in something called an HTA (short for HTML application). It made generating rulesets easier for me, but it was still something that I was running from my local machine.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj78F5Te1p8roR6JGKknsw1czKU4O1kJvEQ7Br07tzpJ7wp6uc7wIyYDaPVKvmzJxCOkhbN1R10htcxra0KMSDFmQ_ipmn8187QP2eHsMgmORYiSJ3-CIea-3aTpJZkaXUpGOWoqWjjJSg/s1600/OldVersion.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="820" data-original-width="800" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj78F5Te1p8roR6JGKknsw1czKU4O1kJvEQ7Br07tzpJ7wp6uc7wIyYDaPVKvmzJxCOkhbN1R10htcxra0KMSDFmQ_ipmn8187QP2eHsMgmORYiSJ3-CIea-3aTpJZkaXUpGOWoqWjjJSg/s640/OldVersion.png" width="624" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The earliest known copy of the original Dialing Rule Optimizer. I obtained this from the Smithsonian Museum. The text-only v1.0 has been lost to the sands of time.</td></tr>
</tbody></table>
I soon figured out that it would be relatively straightforward to move the HTA into an actual web page. I put the code on a web server hosted by the company I was working for at the time and opened up the tool to the entire world. I actually put this code on the computer that was running our OCS 2007 R2 server!<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixnJz_JTka0yEXtOBKWG0FXVa9rlk8beCUbyXzsudXrTXlXFxZXIveuWmQpJKHmad6OeC4OEunjLuFnK04GPCjpnI6ZWA5Fnmat7CoOnVq-6wKU3f3qWBSjqfpFvCyTvoxwsNiMVHNEi8/s1600/Website.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="885" data-original-width="1026" height="552" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixnJz_JTka0yEXtOBKWG0FXVa9rlk8beCUbyXzsudXrTXlXFxZXIveuWmQpJKHmad6OeC4OEunjLuFnK04GPCjpnI6ZWA5Fnmat7CoOnVq-6wKU3f3qWBSjqfpFvCyTvoxwsNiMVHNEi8/s640/Website.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The very first web-based iteration of the Dialing Rule Optimizer. Note the Communications Server "14" logo on the top-right.</td></tr>
</tbody></table>
<br />
Once Communications Server "14" became <b>Lync 2010</b>, I realized that I could go beyond simple optimized route creation, and modified the Optimizer to create everything required for a simple Enterprise Voice setup for US and Canada deployments.<br />
<br />
Shortly after, <a href="https://ucken.blogspot.com/2011/06/dialing-rule-optimizer-goes.html" target="_blank">I realized that I could do the same for other countries as well</a>. The Optimizer interface grew somewhat to accommodate the requirements for different countries.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5maSF1h2Km8e3_GbJB-OrxRgG6SEe2y1qof42U57Sl4-9jlxOn5LBOsD81bxiO20pZcqahjA65jyhATehoax2pL8lDGBoKd2IPd8POjMozGmvhERnNkEHkNqloU5kCCuVqNFVAEKSV9w/s1600/OptimizerUK.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="687" data-original-width="984" height="446" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5maSF1h2Km8e3_GbJB-OrxRgG6SEe2y1qof42U57Sl4-9jlxOn5LBOsD81bxiO20pZcqahjA65jyhATehoax2pL8lDGBoKd2IPd8POjMozGmvhERnNkEHkNqloU5kCCuVqNFVAEKSV9w/s640/OptimizerUK.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Dramatic differences abound! Communications Server "14" has changed to "Microsoft Lync". Also, UK dial plans!</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
I slowly added other countries to the Optimizer. I also added other features such as <a href="https://ucken.blogspot.com/2011/11/dialing-rule-optimizer-now-does.html" target="_blank">extension dialing rules</a>, l<a href="https://ucken.blogspot.com/2013/01/least-cost-failover-routing-in-optimizer.html" target="_blank">east-cost/failover routing</a>, among many others.<br />
<br />
Over time, the back-end code base was starting to become difficult to support. I was using a series of XML files to deal with languages and country-specific dialrules, and the sheer number of them was becoming cumbersome to manage. I decided to move everything from the company-hosted platform to Amazon Web Services. I built a single Windows VM with SQL Express and ported the XML files to a database. It worked well, but AWS was starting to cost a fair bit to run for a free service. Donations were not keeping pace with costs.<br />
<br />
I then discovered that Microsoft MVPs got a monthly allotment of funds in Azure. I immediately moved my infrastructure to Azure, where it ran mostly trouble-free for the next several years.<br />
<br />
The Optimizer featureset grew and grew, but the interface was still as ugly as the day I first created it. One person even suggested it looked like a GeoCities page. Hey, my argument was always that I was not (and am still not) a web developer.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpwRjsDZjQcBpoq2YA5ueTQliKH_aUrI5669TXvIyAiLDuHjA7LIBk_QWIu0-qYepjcQNq2txUHWvf6xsd37ASH3yFaM586-9TqWK8FBnQ-TvDPlOsZSmbrefhAL6bxRBfk_wgxPhhIuk/s1600/LyncOptimizer76.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="685" data-original-width="1084" height="403" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpwRjsDZjQcBpoq2YA5ueTQliKH_aUrI5669TXvIyAiLDuHjA7LIBk_QWIu0-qYepjcQNq2txUHWvf6xsd37ASH3yFaM586-9TqWK8FBnQ-TvDPlOsZSmbrefhAL6bxRBfk_wgxPhhIuk/s640/LyncOptimizer76.png" width="640" /></a></div>
<h3>
<br />The Modern Era</h3>
I decided to try to give the Optimizer a more modern look. I completely re-wrote the front-end code using Notepad++ as my trusty editor. I replaced the clunky extension builder with a better Javascript framework that emulated an Excel spreadsheet, and made other significant under-the-hood improvements. After much trial and error, I was pleased to unveil the new look.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsAnUFz8iSJfuqXhz5OZswMbZR_RSYtFbsjOkxYrCRliTdYjjJSC-UwZeI6ojrTdPQCxwoYCEPSy76Qwao-8jEfWEk6t-2Xc29hVGIK0KmtzquGTIxXxn0uIxV0WqsG-VsRo3wlHsfPNg/s1600/NewSkypeOptimizer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="908" height="960" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsAnUFz8iSJfuqXhz5OZswMbZR_RSYtFbsjOkxYrCRliTdYjjJSC-UwZeI6ojrTdPQCxwoYCEPSy76Qwao-8jEfWEk6t-2Xc29hVGIK0KmtzquGTIxXxn0uIxV0WqsG-VsRo3wlHsfPNg/s640/NewSkypeOptimizer.png" width="541.5" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The website looked modern, clean and easy-to-use. However, it bugged me that while the site was running in Azure, it was still just a single Windows VM with a local SQL Server instance. It was also costing most of my monthly Azure MVP credits with not a lot of headroom. I decided to try to make the Skype Optimizer simpler and cheaper to manage, figuring that there would probably come a day when I would not be a Microsoft MVP (the horror!!!) and I'd be expected to pay a monthly bill (Oh the humanity!!!).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
My first step was to dump the local SQL and move to <b><a href="https://azure.microsoft.com/en-ca/services/sql-database/" target="_blank">Azure SQL Database</a></b>. First, I had to copy the gigabytes of data to my SQL instance. I opted to use <a href="https://docs.microsoft.com/en-us/azure/sql-database/sql-database-cloud-migrate" target="_blank">transactional replication</a>, which would allow me to keep both my local and Azure-based SQL instances up-to-date while I tested things out. It turned out to be ridiculously easy. I had to modernize my code a bit to allow it to still read/write data to Azure SQL, but this was pretty straightforward as well.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
With that hurdle out of the way, I looked at a few different ways to further reduce my costs and administrative burden. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3 style="clear: both; text-align: left;">
Docker Containers</h3>
<div class="separator" style="clear: both; text-align: left;">
I'd heard about Docker containers and how it was an easy way to reduce the overall complexity and costs over a traditional virtual machine. I installed Docker on my home machine and started messing around with it. I used the <a href="https://blog.docker.com/2016/10/containerize-windows-workloads-image2docker/" target="_blank">Image2Docker </a>tool to make a copy of my Windows VM-based website and installed it locally. I had to do quite a bit of modifications to my dockerfile to support some of the added features that Image2Docker didn't capture, but after a while, I managed to make the Skype Optimizer work in a Docker container. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Moving my newly-created container to Azure wasn't too much work, but there was definitely a learning curve involved. It started up fine, and I pointed my DNS entries to the container and away we went! However, all was not perfect:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ol>
<li>My container stopped working a few times over the span of a few weeks. Troubleshooting this proved to be nearly impossible due to the nature of Docker containers and how you lose the previous state every time you restart it. Either that or I just don't know how these things really work.</li>
<li>Making code modifications wasn't simple either. I'd have to make the change in my local Docker image and publish that image to Azure. The startup process took 5-10 minutes, which was probably due to how I built my container. I looked at ways to improve the startup time, but it was already eating up lots of my time.</li>
<li>The costs to run the container wasn't much cheaper than a full VM</li>
</ol>
<div>
Because of those reasons, I decided that Docker containers weren't well-suited to my needs and I finally turned to....</div>
<div>
<br /></div>
<h3>
Azure Web App</h3>
<div>
All the back-end code changes I made to the Optimizer to support both Azure SQL Database and Docker containers actually had an unexpected side benefit: it allowed me to easily move the Optimizer to <a href="https://azure.microsoft.com/en-us/services/app-service/web/" target="_blank">Azure Web App</a>, which is Azure's web hosting framework.</div>
<div>
<br /></div>
<div>
To make the process of managing this easier, I finally moved away from Notepad++ as a development environment and embraced Visual Studio. Visual Studio made it trivial to take my entire website and migrate it to Azure. I had a few challenges with making my code-signing certificate work, but in the end it all worked flawlessly. </div>
<div>
<br /></div>
<div>
The Skype Optimizer has been running as an Azure Web App for several months now. Its extremely reliable, simple to manage, and about 3 times cheaper to run than the original Windows VM. </div>
<div>
<br /></div>
<h3>
The Future</h3>
<div>
So, there you have it. The entire history of the Skype Optimizer posted here for posterity. Where do things go from here? Well, with <a href="https://techcommunity.microsoft.com/t5/Microsoft-Teams-Blog/Direct-Routing-enables-new-enterprise-voice-options-in-Microsoft/ba-p/170450" target="_blank">Microsoft Teams eventually taking over the Enterprise Voice role from Skype for Business</a>, I may decide to look into what it would take to turn the Skype Optimizer into a Teams Direct Routing and Calling Plans management platform. </div>
<div>
<br /></div>
<div>
Until then, I will continue to keep updating the Skype Optimizer to make sure Skype and Teams administrators worldwide have a single place to get accurate, up-to-date dialing rules for every country in the world.</div>
<br />
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-54941682828082850502018-03-09T14:07:00.000-05:002018-03-10T08:39:23.071-05:00Edge Topology Replication Failures Caused by Mismatched Windows UpdatesWhile getting a new Skype for Business edge server ready for production, I generally make sure all the latest Windows Updates are applied. I was doing exactly this for the company I work for (Nectar Services Corp). Everything seemed to go just fine, but I noticed the edge server's replication status was showing as <b>False</b> when I ran <b>Get-CsManagementStoreReplicationStatus</b>. The usual procedure of running <b>Invoke-CsManagementStoreReplication -ReplicaFQDN </b><i style="font-weight: bold;">servername </i>did nothing. Even wiping out the <b>C:\RtcReplicaRoot\xds-replica</b> folder as described in <a href="https://ucken.blogspot.com/2012/04/resetting-lync-cms-replication.html" target="_blank">this dusty old blog post</a> didn't make a difference.<br />
<br />
The Event Logs on the front-end server that was the master replication partner showed these fairly frequent error events:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Log Name: Lync Server</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Source: LS File Transfer Agent Service</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Date: 2/22/2018 10:01:29 AM</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Event ID: 1046</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Task Category: (1121)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Level: Error</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Keywords: Classic</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">User: N/A</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Computer: FRONTENDSERVERNAME.contoso.com</span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Description:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Skype for Business Server 2015, File Transfer Agent cannot send replication data to Replica Replicator Agent on Edge</span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Edge machine: EDGESERVERNAME.contoso.com</span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Exception: System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at https://edgeservername.contoso.com:4443/ReplicationWebService that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it 192.168.1.2:4443</span></blockquote>
<div>
I could reach the edge server's replication web service URL via port 4443 as described in the event log, so there wasn't a firewall issue or an issue with the web service that I could determine.</div>
<br />
The edge server was also throwing errors, saying that it hadn't heard from any of the replication servers in a while and its feelings were very hurt.<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Log Name: Lync Server</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Source: LS Replica Replicator Agent Service</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Date: 2/22/2018 12:04:32 PM</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Event ID: 3045</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Task Category: (3003)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Level: Error</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Keywords: Classic</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">User: N/A</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Computer: EDGESERVERNAME.contoso.com</span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Description:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">The replication synthetic transaction has not been updated in a significant time period.</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Time since the last update: 01.03:43:09</span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Cause: </span><span style="font-family: "courier new", courier, monospace;">The Master Replicator Agent has not updated the replication transaction document in a significant time period.</span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Resolution:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">If other replicas are experiencing similar issues, check the Master Replicator Agent and File Transfer Agent service health. Verify access to the DFS files shares and replica file shares</span></blockquote>
The weird thing was that replication <b>WAS</b> working prior to me installing the final batch of Windows Updates. So, it seemed to make sense to uninstall each of the last Windows Update until things start working again. Unfortunately, after uninstalling those updates, along with a bunch of other ones in an increasingly desperate attempt to find the issue, the issue still persisted. Back to the drawing board.<br />
<br />
I noticed that I was unable to copy binary files to the edge server via RDP copy/paste. Text files would copy fine, but any other filetype would cause the RDP session to crash with "Unexpected Server Error". This seemed to be related to the replication issue, because this also worked fine prior to installing those updates. This is a good time to note that to access the edge server, I had to first RDP to a front-end server, then RDP to the edge from there, because the firewall was blocking all other access. This would prove to be relevant later.<br />
<br />
I went as far as uninstalling and reinstalling Skype for Business along with all the supporting components, but it <b>STILL</b> didn't work.<br />
<br />
Frustration level: <span style="color: red;">STRATOSPHERIC</span><br />
<br />
Finally, I nuked the entire edge server from orbit (It's the only way to be sure) and had the edge server rebuilt from scratch. Once again, replication worked.<br />
<br />
End of story, right? Wrong. I had to figure out what the issue was, so I re-applied each of the original suspected updates until the issue re-appeared. And re-appear it did, along with the RDP copy/paste issue. The offensive update that caused the issue was <a href="https://support.microsoft.com/en-ca/help/4072650/hyper-v-integration-components-update-for-windows-virtual-machines" target="_blank">4072650</a>, which is vaguely described as <b>Hyper-V integration components update for Windows virtual machines</b>. The description wasn't much help, but it certainly had an effect. Once again, removing that patch didn't make the issue disappear.<br />
<br />
Finally, I checked to see if the front-end servers had this truly despicable update, AND THEY DIDN'T. It was buried in Windows Update as an optional update, which weren't being automatically downloaded and installed. On a hunch, I installed the update (no restart required, thankfully), and VOILA, replication started working again, and I could copy/paste files between front-ends and edge via RDP.<br />
<br />
So, this vague Windows Update was the source of all my issues. Sigh... Presumably, this would only show up in the following circumstances:<br />
<br />
<ul>
<li>Using Hyper-V hosted virtual machines</li>
<li>Running Windows 2012 R2</li>
<li>Update 4072650 is installed on some VMs but not all</li>
</ul>
<br />
<h3>
TL;DR version</h3>
If you're having replication errors on your edge server, and are getting <b>LS File Transfer Agent Service error 1046</b> on your master replication server, then make sure that all front-end and edge servers have <b>Update 4072650</b> if you see it applied on any one server.<br />
<br />
<br />
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-54497915384033646252017-04-25T12:35:00.001-04:002020-06-10T08:52:16.062-04:00Tenant Dial Plans in Skype for Business OnlineAs others have noted, all Skype for Business Online tenants that are capable of PSTN calling are now able to create their own custom dial plans. This allows administrators to create custom normalization rules for local and extension dialing and other cases the default normalization rules don't handle.<br />
<br />
Dial plans work a bit differently in Skype Online than they do in on-premise deployments. In on-prem deployments, dial plans are completely independent of one another. Users assigned either a specific site or user-level dial plan will only use the normalization rules contained within that dial plan. Normalization rules assigned at the global level do not apply.<br />
<br />
In Skype Online, users can be assigned to either a tenant <b>global </b>dial plan or a tenant <b>user </b>dial plan. As with Skype for Business on-prem, users will get normalization rules from the global tenant dial plan, unless they are explicitly assigned to a user tenant dial plan. There is no inheritance from tenant global to tenant user dial plans.<br />
<br />
However, users WILL inherit dial plan normalization rules from a Skype Online global dial plan specific to the country where their phone numbers are hosted. This is the default dial plan that all users are assigned to in the absence of a tenant global or user dial plan.<br />
<br />
If you were to run Get-CsDialPlan on your tenant, you will see dial plans for most of the countries in the world (220 to be exact. 12 short of what's in the Skype Optimizer, but who's counting?). These dial plans are pretty basic, accounting for national and international dialing prefixes but not much else. The US and UK dial plan normalization rules are shown below:<br />
<br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: none; margin-left: -.4pt; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-yfti-tbllook: 1184;"><tbody>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="38"><div class="MsoNormal">
<b>Name<o:p></o:p></b></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 35pt;" valign="top" width="38"><div class="MsoNormal">
<div style="text-align: center;">
<b>Priority<o:p></o:p></b></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 250pt;" valign="top" width="18"><div class="MsoNormal">
<div style="text-align: center;">
<b>Pattern<o:p></o:p></b></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 35pt;" valign="top" width="18"><div class="MsoNormal">
<div style="text-align: center;">
<b>Translation</b></div>
</div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100t;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">US Intl Dialing</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">0</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">^011(\d+)$</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">+$1</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">US Long Distance</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">1</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">^1(\d+)$</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">+1$1</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">US Default</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">2</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">^(\d+)$</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">+1$1</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">US Extension Rule</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">3</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">^((\+)?(\d+))(;)?(ext|extn|EXT|EXTN|x|X)(=)?(\d+)$</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">$1;ext=$7</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">GB Intl Dialing</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">0</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">^00(\d+)$</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">+$1</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">GB Long Distance</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">1</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">^0(\d+)$</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">+44$1</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">GB Default</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="38"><div style="text-align: center;">
<span style="background-color: white;">2</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">^(\d+)$</span></div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
<span style="background-color: white;">+44$1</span></div>
</td></tr>
<tr><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 100pt;" valign="top" width="106"><div class="MsoNormal">
<div style="text-align: left;">
<span style="background-color: white;">GB Extension Rule</span></div>
</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="38"><div style="text-align: center;">
3</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
^((\+)?(\d+))(;)?(ext|extn|EXT|EXTN|x|X)(=)?(\d+)$</div>
</td><td style="border: 1pt solid; padding: 0cm 5.4pt; width: 33.8pt;" valign="top" width="18"><div style="text-align: center;">
$1;ext=$7</div>
</td></tr>
</tbody></table>
<br />
The rules are quite rudimentary, and don't allow for capturing and fixing user-initiated dialing errors such as overdialing, incorrect adding of national prefixes for international calls, or local calls. The extension rule is quite interesting because it appears to have been written by someone who really doesn't know how to use regular expressions. Unless your extension rule matches the very specific cases of ext, extn, EXT, EXT, x or X, then it won't work. If they used my standard for pattern and translation, it would be both simpler and would capture pretty much ANY style of writing phone numbers with extensions:<br />
<blockquote class="tr_bq">
Pattern: ^\+?(\d+)\D+(\d+)$<br />Translation: +$1;ext=$2</blockquote>
If you look at the dial rules for other countries, you'll see the only difference between them is the long distance and international dialing prefix and the country code. I get that it can be tricky to maintain dial rules for 230+ countries, but hey if one simple Canadian dude can do it, couldn't Microsoft???<br />
<br />
Aaaanyways, the global dial plan for your given country is applied along with any tenant level dial plans. It appears that the tenant dial plans are applied first, followed by the global dial plan for your country.<br />
<br />
This means you can use the Skype Optimizer to create more nuanced normalization rules that will work better than the default ones. You can't disable the global dial plan, so if a user dials a number not covered by your tenant dial plans, then the global ones will apply. So, even if someone tries to dial a completely nonsensical number such as 00000023423422348987987998770, it would get captured by the global Default normalization rule and would allow the user to dial that number. Of course, it wouldn't get far, but I would think that if you can prevent users from dialing invalid numbers at the client level, it would keep Skype Online servers from having to use precious system resources to parse that number and notify the user it is invalid.<br />
<br />
Thankfully, this means the <a href="https://www.ucdialplans.com/" target="_blank">Skype Optimizer</a> is still relevant in the Skype Online world. You can still use it to create dial plans and normalization rules that will make the user dialing experience better, including support for:<br />
<br />
<ul>
<li><a href="http://ucken.blogspot.com/2015/06/dealing-with-overdialing.html" target="_blank">Overdialing</a></li>
<li>Local number dialing patterns</li>
<li>Extensions</li>
<li><a href="http://ucken.blogspot.com/2016/03/trunk-prefixes-in-skype4b.html" target="_blank">Removing national prefixes from internationally dialed numbers</a></li>
<li>Slices, dices and makes julienne fries</li>
</ul>
<div>
Just select the desired options for your country, press the Generate Rules button, and run the script. It will ask for your credentials for your Skype Online tenant and will then ask if you want to create a tenant global or tenant user dial plan. It will then apply said normalization rules to your tenant. That's all it takes!</div>
<div>
<br /></div>
<div>
Buy now! Operators are standing by!</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLsdOCFxz6666_D7w-Jjfqngj9kHRZK0XR3giLE4vJlxUQzVknzRzIY-FQXff_fJr0GVQn28gwMtHPLpJxfT_PQGGCo1ANgNbzI5L2c07hB_MwozTTtcJ3mUJLMRYalGyVW2qwVkspQ-M/s1600/SkypeOnline.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="430" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLsdOCFxz6666_D7w-Jjfqngj9kHRZK0XR3giLE4vJlxUQzVknzRzIY-FQXff_fJr0GVQn28gwMtHPLpJxfT_PQGGCo1ANgNbzI5L2c07hB_MwozTTtcJ3mUJLMRYalGyVW2qwVkspQ-M/s640/SkypeOnline.png" width="640" /></a></div>
<div>
<br /></div>
<br />
<br />
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com7tag:blogger.com,1999:blog-2156539095375223979.post-75551420693319680492016-08-23T17:42:00.000-04:002016-08-25T11:25:41.930-04:00Lync/S4B Client Can Normalize Numbers with Plus Sign?!?!?One of my central tenets of number normalization in Lync/Skype for Business has always been:<br />
<blockquote class="tr_bq">
"Lync/Skype for Business will not attempt to normalize a number that already has a plus sign at the beginning"</blockquote>
There are signs that this is no longer true, at least for customers running Skype for Business Server 2015 and the Skype for Business 2016 client (and even the Lync 2010 client). I was messing around with normalization rules last night and realized that my Skype for Business 2016 client (version 16.0.7030.1021 32-bit) WAS normalizing numbers that started with a plus sign. I later validated this with a Lync 2010 client against the same Skype for Business 2016 server. And a commenter below said he's pretty sure he did this with Lync Server 2013. So this means that either it has ALWAYS worked this way and I never realized it, or its something relatively new on the server-side.<br />
<br />
I should clarify here and state that the normalization rule in question was specifically constructed to include a plus sign in the normalization pattern (as highlighted below):<br />
<blockquote class="tr_bq">
^<span style="background-color: yellow;"><b>\+?</b></span>(?:011)?(1|7|2[07]|3[0-46]|39\d|4[013-9]|5[1-8]|6[0-6]|8[1246]|9[0-58]|2[1-689]\d|3[578]\d|42|5[09]\d|6[789]\d|8[035789]\d|9[679]\d)(?:0)?(\d{6,14})(\D+\d+)?$</blockquote>
This DOES NOT mean that the Skype for Business client will suddenly normalize all numbers that start with a plus. If your normalization rules do not include a plus sign, it will not normalize a number with a plus sign.<br />
<br />
This has all sorts of ramifications, all of them positive. That means that <a href="http://ucken.blogspot.com/2016/03/trunk-prefixes-in-skype4b.html" target="_blank">dealing with improperly formatted click-to-dial numbers in Internet Explorer</a> is much simpler. We can now fix this with a simple normalization rule, instead of doing it in a trunk translation rule or route.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjInPtMdOFF-sQoXo2tVC97IB6SFwl4bCzk8XFB3sqvG5KhXnqEsH15k0PveUg6tmI7yPZJOm8ORZNvOPKwhA4e-Ul5Z3xgtap8dsOPvK-1W005t0hQ40XPNoxHDtn-7NKzMgmcFaPvTHw/s1600/NewNormalization.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjInPtMdOFF-sQoXo2tVC97IB6SFwl4bCzk8XFB3sqvG5KhXnqEsH15k0PveUg6tmI7yPZJOm8ORZNvOPKwhA4e-Ul5Z3xgtap8dsOPvK-1W005t0hQ40XPNoxHDtn-7NKzMgmcFaPvTHw/s640/NewNormalization.png" width="640" /></a></div>
<br />
<br />
This also means that dialing contact phone numbers from Outlook can also be much more reliable, especially if an extension is entered. Before, if a user entered a contact phone number with an extension in Outlook using the "Phone number builder", it would format the number like "+1 (212) 555-1212 x 345". If you clicked this number, Lync would parse the "x" as a "9" and the number would come out in Lync like "+121255512129345" and would likely fail.<br />
<br />
I have no idea how long this new behaviour has been available. It works on a Skype for Business Server 2015 environment with both Skype for Business 2016 clients and Lync 2010 clients. I don't have a Lync 2013 or older environment to test with. I tried to see if this behaviour extended to server-side normalization scenarios with no luck. I tried to change the destination phone number on an incoming call that started with a plus sign. It didn't work, which implies that this is a client-only thing. The <a href="http://ucken.blogspot.com/2012/02/re-routing-incoming-calls-to.html" target="_blank">MSPL workaround</a> is still required.<br />
<br />
If this is only new to me, then I apologize for wasting everybody's time. I've incorporated my new findings into the Lync Optimizer (as you would expect), because it does allow for several dialing scenarios to work better than before. <br />
<br />
If anybody has any information on this or can test other versions of Lync server/client, drop me a line.<br />
<br />
<b>UPDATE (2016-Aug-24):</b> Updated to clarify that a normalization rule has to explicitly look for a plus sign for this to work. Original post implied that any valid, matching normalization rule would be applied to a number that had a plus sign on the front. Also made changes based on further observations with older clients.Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-14901486163318623342016-08-10T11:32:00.001-04:002020-06-10T08:46:53.216-04:00North American Call Authorization Tricks<div>
Almost every country in the world has a dedicated country code assigned to it for telephony purposes (see <a href="https://countrycode.org/" target="_blank">countrycode.org</a> for a full list). There is one very large exception to this rule and that is countries in <a href="https://www.nationalnanpa.com/about_us/abt_nanp.html" target="_blank">North America (US and Canada) and a good portion of the Caribbean</a>. These countries all share the same country code of +1 and are collectively part of the <b>North American Numbering Plan</b> (NANP), which is managed by the <b>North American Numbering Plan Association</b> (NANPA).<br />
<br />
A NANP number consists of the country code +1, a 3-digit area code, and a 7-digit subscriber number, often formatted like +1 (212) 222-3333. You'll sometimes see the +1 omitted from the number on business cards and websites that don't think globally. <br />
<br />
Dialing numbers in North America is quite different from most places in the world. In the rest of the world, if you want to dial a long-distance or national number, you have to dial a national access code. In a lot of countries, this number is 0. However, in NANP countries, you have to dial 1 for long-distance/national numbers. That's right, you have to dial the <b>actual NANP country code</b> as the long-distance access code, which is unique among all other countries. Incidentally, the international access code is 011 (in many other countries, its 00).<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin1crAfOA7ZOKjcHcRy_6zIV2qD3GmUuzpW5oN-SreYX-rcZSAto2tauyc_9zshCt5ibBbSwjRnqbYbMPJB8woi6bI09qh1gNtAV_fMWS7AbXdJ6BnRZRrqYJhDBGrd0AmYDpmHZFxc1c/s1600/hoffphone.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin1crAfOA7ZOKjcHcRy_6zIV2qD3GmUuzpW5oN-SreYX-rcZSAto2tauyc_9zshCt5ibBbSwjRnqbYbMPJB8woi6bI09qh1gNtAV_fMWS7AbXdJ6BnRZRrqYJhDBGrd0AmYDpmHZFxc1c/s400/hoffphone.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">"Connect me with the German Chancellor immediately! I have an idea for a new album!"</td></tr>
</tbody></table>
If you want to dial Canada from the US, or the US from Canada, or any of the Caribbean countries in NANP, you don't dial the international access code 011, you just dial the number as you would any other long-distance number. So, if I want to dial Toronto, Canada from Vancouver, Canada I would dial +1 <b>416</b> 555 1111. If I wanted to dial New York City from Vancouver, I'd dial +1 <b>212</b> 555 1111.<br />
<br />
It gets even better. NANP area codes are allocated by a trio of over-caffeinated spider monkeys who press numbers on a giant keypad at random to assign a new area code (well, that's how it appears). There is no logical separation between area codes between any of the countries. For example, area code 646 is in New York, USA, 647 is in Ontario, Canada, and 649 is in the Turks & Caicos (Caribbean island nation). <a href="https://www.nationalnanpa.com/enas/geoAreaCodeNumberReport.do" target="_blank">Click here for a current list of area code allocations in NANP</a>.<br />
<br />
These days, calls between the US and Canada are often priced identically to a domestic long-distance call. But calls to the NANP Caribbean countries are usually priced much higher, akin to dialing some very remote international destinations. Continuing the previous example, a US user that has signed up for Microsoft's <a href="https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/REDTZ9" target="_blank">Skype for Business Online PSTN Calling Plan</a> can expect to pay $0.013 per minute (just over 1 cent a minute) to call area code 647 in Ontario, but would end up paying $0.583 (almost 45x more expensive) to $0.741 per minute to call area code 649 in the Turks & Caicos.<br />
<br />
Since it is nigh impossible for a regular person 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.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj29BZfvJnBeGi70mQ8CdFyzSLztHbTP1AOpRH-sDOoLGzlY87gSJE3UqQcUPYR21np_WdnKT8bQ8qsMRUqkgUkS-0o-PYT7_EENf07cZr4Sj6ElVtmEAowr7SL29XGtAY6rP5m8GTWKoo/s1600/HoffAppleWatch.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj29BZfvJnBeGi70mQ8CdFyzSLztHbTP1AOpRH-sDOoLGzlY87gSJE3UqQcUPYR21np_WdnKT8bQ8qsMRUqkgUkS-0o-PYT7_EENf07cZr4Sj6ElVtmEAowr7SL29XGtAY6rP5m8GTWKoo/s640/HoffAppleWatch.png" width="396" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">He had an Apple watch long before anybody else. True trendsetter, even if it took 30 years.</td></tr>
</tbody></table>
Skype for Business administrators often want to prevent certain users from dialing these Caribbean countries, and it can be easily done with some fancy routing rules. Assuming you've already configured voice polices for national and international access, then you just have to modify the National level voice route to block Caribbean destinations. You could do some research to determine the Caribbean area codes, and create your own regular expression to block them, but I figure I should do SOMETHING useful with this post and provide you with that information.<br />
<br />
This Skype for Business route number pattern will block all Caribbean countries that are part of NANP, except for the US Virgin Islands and Puerto Rico (which are often not priced much differently than US numbers, when calling from the US):<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">\+1(?!(24[26]|26[48]|284|345|441|473|649|664|721|758|767|784|8[024]9|86[89]|876|900|976))[2-9]\d\d[2-9]\d{6}$</span></blockquote>
If you want to also block US Virgin Islands and Puerto Rico, then use this one:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">^\+1(?!(24[26]|26[48]|284|34[05]|441|473|649|664|721|758|767|78[47]|8[024]9|86[89]|876|900|939|976))[2-9]\d\d[2-9]\d{6}$</span></blockquote>
You may note that I've also made sure to exclude premium area codes like 900 and 976.<br />
<br />
To make sure that people assigned an International voice policy can dial those Caribbean countries, your international route should include a pattern for North American numbers and look something like this:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">^\+((1(?!(900|976))[2-9]\d\d[2-9]\d{6})|([2-9]\d{6,14}))$</span></blockquote>
</div>
<div>
If you REALLY wanted to get draconian and block calls to Canada from the US, and vice versa, you could use the following rules:<br />
<br />
Block Canadian and Caribbean calls:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">^\+1(?!(900|976))(20[^04]|21[^1]|22[4589]|23[149]|24[08]|25[12346]|26[0279]|27[026]|30[^06]|31[^1]|32[0135]|33[^2358]|34[067]|35[12]|36[01]|38[056]|40[^03]|41[^168]|42[345]|43[0245]|44[023]|47[0589]|48[04]|50[^06]|51[^149]|53[0149]|54[01]|55[19]|56[12347]|57[01345]|58[056]|60[^04]|61[^13]|62[03689]|63[016]|64[16]|65[017]|66[01279]|67[018]|68[124]|70[^059]|71[^01]|72[0457]|73[1247]|74[037]|75[47]|76[02359]|77[^1678]|78[1567]|80[^079]|81[^19]|83[012]|84[3578]|85[^1235]|86[02345]|87[028]|90[^025]|91[^1]|92[0589]|93[16789]|94[0179]|95[12469]|97[^4567]|98[0459]|281|458|469|520|828)[2-9]\d{6}$</span></blockquote>
Block American and Caribbean calls:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">^\+1(?!(900|976))(41[68]|43[178]|51[49]|58[17]|70[59]|78[02]|90[25]|204|226|236|249|250|289|306|343|365|403|450|506|548|579|604|613|639|647|778|807|819|825|867|873)[2-9]\d{6}$</span></blockquote>
The above rules are formatted slightly differently from the ones that block Caribbean countries. The Caribbean rules show which area codes to BLOCK. The other rules show which area codes to ALLOW. Of course, I didn't roll these rules by hand, since there are tens of dozens of area codes allocated to each country, and do change from time to time. I used the super handy-dandy <a href="https://www.ucdialplans.com/" target="_blank">Lync Optimizer</a>. As you might expect, these options are available in the <a href="https://www.ucdialplans.com/" target="_blank">Lync Optimizer</a> via the "<b>Treat as National</b>" option (only shows for North American dial rules). You can select one of the following options with regards to dialing other countries within NANP:</div>
<ol>
<li><strong>In-Country Only</strong> - Treat all calls to NANP 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.</li>
<li><strong>US/Canada</strong> - 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.</li>
<li><strong>US/Canada/Caribbean</strong> - Treats calls to anywhere in NANPA (US/Canada/Caribbean) as national calls (along with the potentially higher call costs).</li>
</ol>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibJJWA3vhNLmhyphenhyphen4P3h0POJ1M_kZw2s72W5PSv3pLHhqTHod0dkee9L3hFqK4P5TulBCbBjj2sTwDrDewYXWSvbrzkrctgwb0gAjjz15WWkt8EGDYPJdYbD8ZBxSz-pq7GEQUxZNusGaBY/s1600/TreatasNational.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibJJWA3vhNLmhyphenhyphen4P3h0POJ1M_kZw2s72W5PSv3pLHhqTHod0dkee9L3hFqK4P5TulBCbBjj2sTwDrDewYXWSvbrzkrctgwb0gAjjz15WWkt8EGDYPJdYbD8ZBxSz-pq7GEQUxZNusGaBY/s640/TreatasNational.png" width="640" /></a></div>
<br />
If you are creating a ruleset for a Caribbean country that uses +1 as the country code, you won't be able to select <b>US/Canada</b>, since this would make dialing within that Caribbean country difficult.</div>
<br />
Selecting the <strong>Simple Ruleset</strong> option prevents usage of this feature, and will default to <b>US/Canada/Caribbean</b>. You won't be able to control how people dial other NANP countries when there is only a single simple routing rule.<br />
<br />
So, there you go. A lesson in the finer details of dialing numbers in North America that the rest of the world might not be aware of. Try to contain your excitement.Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-3289579917808880162016-07-18T09:45:00.001-04:002020-06-10T08:46:53.838-04:00Using the Lync Optimizer to Configure a Single Multi-Country SIP TrunkAs SIP trunking becomes more reliable and trusted, companies are taking advantage of the ability to consolidate standard PSTN phone lines from multiple office locations into a single SIP trunk. Most of the larger SIP providers can provide phone numbers for multiple countries, allowing for even further consolidation of telephony resources.<br />
<br />
Skype for Business is very well suited to this sort of consolidation. Typically, larger companies deploy large centralized Enterprise Edition pools in a few central datacentres that serve offices spread across entire continents. These centralized pools in turn connect to a SIP trunk over a trusted, secure connection.<br />
<br />
As mentioned, these SIP trunks can provide phone numbers for multiple countries, and price those calls as if they originated from those countries. So, if a company has a SIP trunk in London, UK, they can give out phone numbers to other countries. For example, users could have Germany-based phone numbers served out of the London SIP trunk, and calls from those numbers would be priced as if they originated from Germany. If a German user placed a call to another German phone number, they would be charged as a local or national call, even though the SIP trunk may physically reside outside of Germany. Conversely, if that same German user called a London phone number, the call would be charged as an international call.<br />
<br />
Setting up Skype for Business dial plans and voice policies in this situation can get tricky, but fortunately I've come up with a very clean and easy to execute plan on how this can be accomplished using the <a href="https://www.ucdialplans.com/" target="_blank">Lync (Skype) Dialing Rule Optimizer</a>.<br />
<br />
Let's use an example of a company with a central Skype for Business deployment in London, UK with a single SIP trunk assigned to that location. This company has offices in the following locations:<br />
<ul>
<li>London, UK</li>
<li>Berlin, Germany</li>
<li>Paris, France</li>
</ul>
<div>
All user phone numbers for all three locations are hosted out of the London SIP trunk.</div>
<div>
<br /></div>
<div>
The company has the following requirements:</div>
<div>
<ul>
<li>Users must be able to dial as they are accustomed to in their respective country</li>
<li>Must be able to limit dialing for certain groups to the local, national or international level for their respective country</li>
</ul>
<div>
Let's assume this is a greenfield deployment, and nothing has been done yet in terms of Enterprise Voice configuration outside of getting the London SIP trunk connected to Skype for Business.</div>
<div>
<br /></div>
<div>
The first thing to do is to generate rulesets for each of the three locations using the Dialing Rule Optimizer.</div>
<div>
<br /></div>
<div>
First, London:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1jPYjk6proKTYmzGMOWp2y764NkCrp0BKAqC_Pe93ryJm_CnnO0xMT0-DX3A2AaE3Bvl84EzpzI9V0BAZe7mWWJf1IZ-IjBkxB6KE3jMvUMNEgdlt2cKLOye1XwXxR27Bq6ox_x-vHsI/s1600/DRO-London.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="488" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1jPYjk6proKTYmzGMOWp2y764NkCrp0BKAqC_Pe93ryJm_CnnO0xMT0-DX3A2AaE3Bvl84EzpzI9V0BAZe7mWWJf1IZ-IjBkxB6KE3jMvUMNEgdlt2cKLOye1XwXxR27Bq6ox_x-vHsI/s640/DRO-London.png" width="640" /></a></div>
<div>
<br /></div>
<div>
Then Berlin:</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7b4QQFsy8BF62ifu8tkuHhzakQVf6WVFMxkmpHmazYG7Fi1gY0w7wT7inKkV2sdJ62PCU4DmvAuiNUQrMLRXCjqshS3c9OeHXWb68BMxxWk8HOB0IomDet85S-ini1oZXN94jAVAVGXs/s1600/DRO-Berlin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="554" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7b4QQFsy8BF62ifu8tkuHhzakQVf6WVFMxkmpHmazYG7Fi1gY0w7wT7inKkV2sdJ62PCU4DmvAuiNUQrMLRXCjqshS3c9OeHXWb68BMxxWk8HOB0IomDet85S-ini1oZXN94jAVAVGXs/s640/DRO-Berlin.png" width="640" /></a></div>
<div>
<br /></div>
<div>
Note that I selected the "Force English Rulenames", which I did just because I can't read German or French and would prefer English rule names and descriptions throughout my Skype for Business deployment.</div>
<div>
<br /></div>
<div>
And finally Paris...</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9EUtt1brnZ3RgyJJMXmxk20vmRzBwSSXCgqJ_A9X2-IxXgPFVp5iH_jiU6nQP3HkKnvggC6iDfgE8wZwtSdY3o_xSBGvJcp6LPhhBLS5zFaWlR5Mqz8qrl5gOw3R2vWwyIksnFh7iKEk/s1600/DRO-France.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="492" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9EUtt1brnZ3RgyJJMXmxk20vmRzBwSSXCgqJ_A9X2-IxXgPFVp5iH_jiU6nQP3HkKnvggC6iDfgE8wZwtSdY3o_xSBGvJcp6LPhhBLS5zFaWlR5Mqz8qrl5gOw3R2vWwyIksnFh7iKEk/s640/DRO-France.png" width="640" /></a></div>
<div>
<br /></div>
<div>
The resulting .PS1 rulesets are then copied to one of the Skype for Business servers. </div>
<div>
<br /></div>
<div>
First, the London ruleset is applied to the deployment, creating user-level dial plans and voice policies when prompted. When complete, there will be a single London dial plan and 3 voice policies. All routes use the single SIP trunk (as you would expect, since its the only one available).</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVNoNv3xj4Pu_ens61oRv_L_hCa8NRvT-47EEYRJJumEyetzYikCb1qYgbpYTr-knGwBe-kQK4IOh8mB9DXRUQhdcFjKMwwwWdQ_cMZ3HEurtr8-_kARo9P9jfyC0cbfz7SgNv16N0X2Q/s1600/Dialplan-London.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVNoNv3xj4Pu_ens61oRv_L_hCa8NRvT-47EEYRJJumEyetzYikCb1qYgbpYTr-knGwBe-kQK4IOh8mB9DXRUQhdcFjKMwwwWdQ_cMZ3HEurtr8-_kARo9P9jfyC0cbfz7SgNv16N0X2Q/s640/Dialplan-London.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Dial Plan page after running London ruleset</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGZE0eYR0mw1AvhLQEARmUT48LEB4uKwHhSoK8uj-nITChdlxeFIOMew_Q00lu3_A6kO2xJoIPcLy6vbZ1JS20vpco_vlEtqpdn8HhVDVssf7h1OPBRThfa686uQp8DuWqTuU8b_eAEkY/s1600/London-VoicePolicy.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGZE0eYR0mw1AvhLQEARmUT48LEB4uKwHhSoK8uj-nITChdlxeFIOMew_Q00lu3_A6kO2xJoIPcLy6vbZ1JS20vpco_vlEtqpdn8HhVDVssf7h1OPBRThfa686uQp8DuWqTuU8b_eAEkY/s640/London-VoicePolicy.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Voice Policy page after running London ruleset</td></tr>
</tbody></table>
<br />
In this state, we can easily assign a UK dial plan and voice policies to UK users as appropriate. <br />
<br />
Next, run the rulesets for Berlin and Paris. This is done for multiple reasons. Firstly, it will create German and French dial plans, so users in those countries can dial numbers as they do in those countries. Secondly, it will allow administrators to assign country-specific local, national and international policies. Someone assigned to a German national policy will only be able to dial phone numbers in Germany and nowhere else, regardless of the physical location of the SIP trunk.<br />
<br />
When running the rulesets, make sure NOT to select the option to use least-cost routing. Least-cost routing only works with multiple SIP trunks from different providers. With a single SIP trunk, as in this example, implementing least-cost routing adds unnecessary PSTN usages to voice policies that ultimately don't accomplish anything. If we make a call from a German number to London using a London route, the call will still be billed as an international call from Germany, as the SIP provider will see the German number as the source and bill accordingly.<br />
<br />
To make things easier and faster to run, I recommend the use of the multiple PowerShell command-line switches available with rulesets. It makes applying multiple rulesets faster and less prone to errors. For the rulesets in this example, I used the following switches (using the Paris ruleset as an example):<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;"> .\FR-Paris-Lync.ps1 -SiteID 1 -DialPlanType user -LeastCostRouting:$FALSE -OverwriteSiteVoicePolicy:$FALSE -LocationBasedRouting:$FALSE -PSTNGateway <i>gatewayname </i>-MediationPool <i>mediationpoolname</i></span></blockquote>
For a full listing of the available command-line options, use the command:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">Get-Help .\FR-Paris-Lync.ps1 -Full</span></blockquote>
<br />
Once done, the dial plans and voice policies will look as below.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQPs_okUtWvUYoO2jBPVSCOzXiAIznB9tiRq3OilI3JZRYDJDGmPx6s0Ncnt72fG8QWqZKEHoH-Z6UMi9QSRPprg-VbMmviOkY_pYq906zAQBebYdI_M-aGa1kFcY5owdhs9t-ow93lIo/s1600/Dialplan-All.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQPs_okUtWvUYoO2jBPVSCOzXiAIznB9tiRq3OilI3JZRYDJDGmPx6s0Ncnt72fG8QWqZKEHoH-Z6UMi9QSRPprg-VbMmviOkY_pYq906zAQBebYdI_M-aGa1kFcY5owdhs9t-ow93lIo/s640/Dialplan-All.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Dial Plan page after running Berlin and Paris rulesets</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaCxHWAWoy61cNamosru6hp5zxESgAN5nyErliWJoH8nqOHcbyLfvLudcQT70zs3nTd9NGv9fe3wtMlPX2SqCKwPZqLMFdK3MsPxHZ79Of8vipdvIsjHLui3O56A2DHpg8fjGAMBVR5dQ/s1600/VoicePolicy-All.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaCxHWAWoy61cNamosru6hp5zxESgAN5nyErliWJoH8nqOHcbyLfvLudcQT70zs3nTd9NGv9fe3wtMlPX2SqCKwPZqLMFdK3MsPxHZ79Of8vipdvIsjHLui3O56A2DHpg8fjGAMBVR5dQ/s640/VoicePolicy-All.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Voice Policy page after running Berlin and Paris rulesets</td></tr>
</tbody></table>
<br />
This might seem more complicated than absolutely necessary, and you would be right. You could certainly just use London-based rules for all locations, but it would limit your options severely.<br />
<br />
Setting up things in this way will allow users to dial numbers exactly as they do at home, and also allows administrators very granular control over dialing capabilities. Common area phones in Paris can be limited to local dialing in Paris. First level helpdesk employees in Germany can be limited to dialing only German numbers.<br />
<br />
This shows how easy it is to use the Dialing Rule Optimizer to quickly setup flexible dial plans and voice policies in even the largest voice deployments. If you have any questions about this method, please leave a comment.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<div>
<br /></div>
<div>
<br /></div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-60635827395332639332016-03-08T09:29:00.002-05:002020-06-10T08:46:54.459-04:00Dealing with Trunk Prefixes in Phone Numbers in Skype for BusinessFirst of all, I spend far too much time thinking about dial rules.<br />
<br />
For those who don't know, a trunk prefix is a number (or numbers) that typically has to be dialled prior to dialling a phone number within the subscriber's country, but outside the subscriber's home area code. The trunk prefix is a way to signal the telephone network that the dialed number is a long-distance or national-level call.<br />
<br />
For example, the trunk prefix for UK national calls is 0. If I were sitting in Liverpool and wanted to dial someone in London, I would have to dial 0, then the area code for London (20), then the subscriber phone number (say 3456 7890). For example, 02034567890.<br />
<br />
Not every country uses a trunk prefix, but those that do generally use 0 as a trunk prefix. The actual national trunk prefix usage breakdown (based on my research) is below:<br />
<ul>
<li>101 countries don't use a trunk prefix at all</li>
<li>95 countries use 0</li>
<li>26 countries use 1 (these are countries that are part of <a href="https://en.wikipedia.org/wiki/North_American_Numbering_Plan" target="_blank">NANPA</a>, like US/Canada and many Caribbean countries)</li>
<li>Russia and 5 other former USSR states use 8</li>
<li>Mexico uses 01</li>
<li>Hungary uses 06</li>
</ul>
<br />
NANPA countries are unique in that the country code 1 is also used as a sort of trunk prefix for long-distance calls. Italy is another unique case in that they don't have a national trunk prefix, but they DO use 0 as the beginning of the area code, which can confuse people.<br />
<br />
Trunk prefixes are NOT used outside of the country. Continuing my earlier example, dialling that same London, UK phone number from the US would start with my international call prefix (011), then the UK country code (44), the London area code (20), and finally the subscriber number (3456 7890), resulting in 011442034567890. If that US person tried to insert the UK national call prefix in the number (01144<b>0</b>2034567890), it would fail to connect because trunk prefixes<b> are not used</b> outside the home country.<br />
<br />
Now, the UK user shouldn't be expected to know the international trunk prefix for countries other than his own, so when presenting their number on business cards, web pages or emails, they should use the internationally recognized standard for phone number presentation, which is (DRUMROLL)......E.164!!!! Regular readers of my blog and anyone who knows Lync/Skype for Business should be intimately familiar with E.164 formatted numbers. If you need a refresher, look back at <a href="http://ucken.blogspot.com/2010/12/enterprise-voice-best-practices-in-lync.html" target="_blank">a very old (from 2010!), but still useful blog post on the subject</a>.<br />
<br />
The UK user should present their number like this:<br />
<div style="text-align: center;">
<span style="font-size: large;">+44 20 3456 7890</span></div>
<br />
However, in many cases the UK user presents their number with the trunk prefix, like this:<br />
<div style="text-align: center;">
<span style="font-size: large;">+44 (0) 20 3456 7890</span></div>
<div style="text-align: center;">
or</div>
<div style="text-align: center;">
<span style="font-size: large;">+44 (0) 203 456 7890</span></div>
<br />
People within the UK understand what the (0) represents, but people outside the UK would assume the 0 is part of the phone number and try to dial it as shown, resulting in call failure. This particular practice is very common in the UK, France and to a lesser extent, Australia. There are likely others (please let me know). Below are some screenshots from various webpages from GLOBAL companies that exhibit this problem:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2iMyUMn4WijcFFkna13vuZ8hCIS2IUb4CEIayGra55hO_fHS_U7tDdqMSiG0Wg_g0MOOhDN-q26xopBa91TKOZxgsDkwHVWXd6ooitWPsSd2Ebr0o2Ay3_wNekLGMRHNP2MdYxGCfpeY/s1600/AstraZeneca.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="262" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2iMyUMn4WijcFFkna13vuZ8hCIS2IUb4CEIayGra55hO_fHS_U7tDdqMSiG0Wg_g0MOOhDN-q26xopBa91TKOZxgsDkwHVWXd6ooitWPsSd2Ebr0o2Ay3_wNekLGMRHNP2MdYxGCfpeY/s640/AstraZeneca.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Astra Zeneca</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_6zVI1Dz-qNjdEhh3YWgTC65Lvbm5S_xpOck6xzEZaSFiF6jdLc1P3I42dnSpCM77BC7-5imCgrGZeYMBiTq1e15ZMkdpct6d8AccEEH1qAa50wpBUPSatDxX3KV6tlalxWPTpuQ6l6M/s1600/BAE.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_6zVI1Dz-qNjdEhh3YWgTC65Lvbm5S_xpOck6xzEZaSFiF6jdLc1P3I42dnSpCM77BC7-5imCgrGZeYMBiTq1e15ZMkdpct6d8AccEEH1qAa50wpBUPSatDxX3KV6tlalxWPTpuQ6l6M/s320/BAE.png" width="311" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">BAE Systems</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibw2BxmyZcXb4GvK8dJN83VbfQF48MOYv2gbdG-f81wpe9CYLWEr5zvVhK75dsWXHJYcdd7r2Dmyqkr_fbl1CinBuvZfzS3wSFvH9vZHaS9OivWf_hS9KUnrnajPKwRHwGyKSmaoYP6QQ/s1600/RollsRoyce.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibw2BxmyZcXb4GvK8dJN83VbfQF48MOYv2gbdG-f81wpe9CYLWEr5zvVhK75dsWXHJYcdd7r2Dmyqkr_fbl1CinBuvZfzS3wSFvH9vZHaS9OivWf_hS9KUnrnajPKwRHwGyKSmaoYP6QQ/s1600/RollsRoyce.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Rolls Royce</td></tr>
</tbody></table>
<br />
Since this blog sadly only reaches a very small percentage of the world's population, there's no way I can expect everyone to get their act together and format their phone numbers properly. <a href="http://www.revk.uk/2009/09/it-is-not-44-0207-123-4567.html" target="_blank">Others have ranted about this exact practice before</a>, and it hasn't seemed to help.<br />
<br />
As you may be aware, when you're using Internet Explorer with the Skype for Business/Lync client plug-in, many phone numbers on web pages can be directly dialled by clicking the wee little Skype/Lync icon beside the phone number on the right. You can see this on the Astra Zeneca and Rolls Royce page samples above. You can click those icons, and it will dial the phone number as its presented on the page. Clicking the number for Astra Zeneca's media department will give you this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglz7tskIi6UoN2bz95bV1j9cq_elyYyqR6JEhXYl8NIWEJ8Lv9MSBPSGYyC_UXG20NC1LKgRQViNd0VqT6Ekj4Fk15Ah1Il85STaeqEsmxPJaYSJCsxJpmfZnYkkMyaGlaOv7lb8K3bZI/s1600/ClicktoCall.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="622" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglz7tskIi6UoN2bz95bV1j9cq_elyYyqR6JEhXYl8NIWEJ8Lv9MSBPSGYyC_UXG20NC1LKgRQViNd0VqT6Ekj4Fk15Ah1Il85STaeqEsmxPJaYSJCsxJpmfZnYkkMyaGlaOv7lb8K3bZI/s640/ClicktoCall.png" width="640" /></a></div>
<br />
This is not going to work for anybody, since the trunk prefix 0 will be dialled as part of the number and will fail. You might be thinking that you could write a normalization rule that could deal with this, but Lync/Skype for Business will not normalize a number that has a + in front, because it assumes that any number starting with a + is already normalized. No matter what you do, a phone number that already has the + can't be modified at the source.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
If you're anywhere other than the UK, your international routes probably aren't so strict that it would "know" that putting the UK trunk prefix in the number is wrong, so Lync/SfB will happily send the call on through, only to get dumped by your PSTN carrier as an invalid number.<br />
<br />
What you <b>CAN </b>do, is create a trunk translation rule that will catch any instances where a 0 is immediately after the country code and strip it before sending it to the PSTN. There are only a few countries where 0 is actually a part of the phone number (land line numbers in Italy and mobile numbers in the Republic of the Congo), so the regular expression we create can deal with this.<br />
<br />
The below rule should work nicely:<br />
<blockquote class="tr_bq">
Pattern: ^\+(1|7|2[07]|3[0-46]|39\d|4[013-9]|5[1-8]|6[0-6]|8[1246]|9[0-58]|2[1235689]\d|24[013-9]|242\d|3[578]\d|42|5[09]\d|6[789]\d|8[035789]\d|9[679]\d)(?:0)?(\d{6,14})(;ext=\d+)?$</blockquote>
<blockquote class="tr_bq">
Translation: +$1$2</blockquote>
The first part of the expression with all the digits is the regex for every possible country code in the world. The <b>(?:0)</b> means that if 0 is present immediately after the country code, it will be dropped. Then we accept anything from 6 to 14 other digits. We separate out Italy (39\d), Republic of the Congo (242\d) to allow for 0 in the cases where they are allowed in those countries.<br />
<br />
If you are located in a country that is guilty of the crime of not using E.164 formatted numbers everywhere (I'm looking at you, United Kingdom), then there is the additional step of modifying the appropriate voice routes to allow for numbers coming through the system with a 0 in the wrong spot. Using UK's national route as an example:<br />
<br />
<blockquote class="tr_bq">
Old route pattern: ^\+44(1[1-9]\d{7,8}|2[03489]\d{8}|3[0347]\d{8}|5[56]\d{8}|8((4[2-5]|70)\d{7}|45464\d))$<br />New route pattern: ^\+44<b>0?</b>(1[1-9]\d{7,8}|2[03489]\d{8}|3[0347]\d{8}|5[56]\d{8}|8((4[2-5]|70)\d{7}|45464\d))$</blockquote>
<br />
Note the presence of the 0? after the +44, which indicates that 0 may or may not be present for the route pattern to match. As of right now, the Optimizer will create modified routes only for countries that I'm aware of that flaunt the E.164 rules on a regular basis:<br />
<br />
<ul>
<li>UK</li>
<li>France</li>
<li>Australia</li>
</ul>
<br />
If there are others, please let me know, either directly or via blog comments.<br />
<br />
All the above logic has been incorporated into the <a href="https://www.ucdialplans.com/" target="_blank">Lync/Skype4B Dialing Rule Optimizer</a>, so if you are using that tool for creating your EV dialplans/routing, then you'll be covered.Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-79756177243887707522015-10-16T11:41:00.000-04:002015-10-16T11:41:37.790-04:00Capturing Network Traceroutes in Lync/Skype for BusinessIf 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 <b>TraceRoute</b> table. In all likelihood, this table is probably empty, which might make you wonder what it's for. <br />
<br />
Microsoft<a href="https://technet.microsoft.com/en-us/library/gg398687(v=ocs.15).aspx" target="_blank"> publishes pretty detailed information on the structure of the QoEMetrics database</a> where you can find information about the TraceRoute table in <a href="https://technet.microsoft.com/en-us/library/jj205205" target="_blank">this Technet article</a>.<br />
<br />
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.<br />
<br />
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 <b>Get-CsClientPolicy</b>. If you have several of those, you can see it in a more readable format by typing <b>(Get-CsClientPolicy <i>policyname</i>).PolicyEntry</b><br />
<br />
The relevant policy entry for enabling tracerouting is called "EnableTraceRouteReporting", and you can add it to a client policy by running the following commands:<br />
<blockquote class="tr_bq">
<pre style="font-family: Consolas, Courier, monospace !important; font-size: 13px; line-height: 17.55px; overflow: auto; padding: 5px; word-wrap: normal;">$x = New-CsClientPolicyEntry -Name "EnableTraceRouteReporting" -Value "TRUE"
$y = Get-CsClientPolicy -Identity <i>policyname</i>
$y.PolicyEntry.Add($x)
Set-CsClientPolicy -Instance $y</pre>
</blockquote>
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 <a href="http://www.eventzero.com/" target="_blank">Event Zero's UC Commander</a> (FYI, if you don't already know, I work for them).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwCOx__tDAv7wDdcSIQ4GoMeNfcHSbuMD8WlmSZtA_Ocl0WAMHsHi_Ok3MTe7jjE5fDjj0eOuf2Nld-Hd-Ll7e2dBBrAcLiJg5SkTYXE80R7zmjphp64YK0gp-oBlqYDV57c8FhF5aKGc/s1600/UCCTraceroute.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwCOx__tDAv7wDdcSIQ4GoMeNfcHSbuMD8WlmSZtA_Ocl0WAMHsHi_Ok3MTe7jjE5fDjj0eOuf2Nld-Hd-Ll7e2dBBrAcLiJg5SkTYXE80R7zmjphp64YK0gp-oBlqYDV57c8FhF5aKGc/s640/UCCTraceroute.png" width="618" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Sample screenshot of traceroute data as it appears in UC Commander</td></tr>
</tbody></table>
<br />
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.<br />
<br />
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.<br />
<br />
<br />
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-88751185538177043652015-09-28T08:35:00.001-04:002015-09-28T08:35:24.029-04:00Response Groups Stop RespondingOur company (<a href="http://www.eventzero.com/" target="_blank">Event Zero - makers of the best Skype for Business analytics software out there BTW</a>) 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 <b>480 Temporarily Unavailable</b> errors.<br />
<div>
<br /></div>
<div>
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.</div>
<div>
<br /></div>
<div>
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. </div>
<div>
<br />
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.</div>
<div>
<br /></div>
<div>
<b>WARNING: </b>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 <b>Description</b> field for anything.</div>
<div>
<blockquote class="tr_bq">
$Workflows = Get-CsRgsWorkflow </blockquote>
<blockquote class="tr_bq">
Foreach ($WF in $Workflows)<br />
{<br />
Write-Host "Adding dummy extension to " $WF.Name<br />
$WF.Description = $WF.LineURI<br />
$WF.LineURI = $WF.LineURI + ";ext=0"<br />
Set-CSRgsWorkflow -Instance $WF<br />
}<br />
Foreach ($WF in $Workflows)<br />
{<br />
Write-Host "Reverting back to original number for " $WF.Name<br />
$WF.LineURI = $WF.Description<br />
Set-CSRgsWorkflow -Instance $WF<br />
}</blockquote>
</div>
<div>
<br /></div>
<div>
<div>
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. <br />
<br />
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!</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-7762438150045293932015-09-18T14:51:00.000-04:002015-09-18T14:52:16.275-04:00Testing Inbound PSTN Connectivity Directly from Lync/Skype for BusinessFile this one under "It's obvious once you think about it for even a second"...<br />
<br />
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.<br />
<br />
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.<br />
<br />
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:<br />
<ol>
<li>Suck it up princess and eat the $2.05 it will cost to call Australia for a few seconds.</li>
<li>Wake up someone in Australia at 2 in the morning, claiming its an emergency.</li>
<li>Convince yourself that since outbound calls work fine, inbound should too.</li>
<li>Use a trunk translation rule to route a dummy phone number to the correct destination.</li>
<li>Give up and start drinking, because its Friday afternoon dammit!</li>
</ol>
<div>
The correct answer is #4 (although the judges will also accept #5).</div>
<div>
<br /></div>
<div>
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:</div>
<div>
<ol>
<li>Dialed number gets normalized to E.164</li>
<li>Skype for Business does a reverse number lookup to see if there's an internal user or service that is assigned that number. </li>
<li>If there's a match, routes the call internally directly to the user/service.</li>
<li>If there isn't an internal match, it finds a valid route through a PSTN trunk</li>
<li>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.</li>
</ol>
<div>
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.</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-yOEIeqpYLZ4U7tnTC31rG64cmFCSlRiPFYLB4qjDfohXi382oMFVxJEMEopMyygCp7gl_idJco5BBmKvmgXiexZG3RmEa0Qj_hdbHComcOXUBEzS2X3ASPAYSTR8xYcp8ROninQIru0/s1600/FakeRedirect.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-yOEIeqpYLZ4U7tnTC31rG64cmFCSlRiPFYLB4qjDfohXi382oMFVxJEMEopMyygCp7gl_idJco5BBmKvmgXiexZG3RmEa0Qj_hdbHComcOXUBEzS2X3ASPAYSTR8xYcp8ROninQIru0/s640/FakeRedirect.png" width="596" /></a></div>
<div>
<br /></div>
<div>
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). </div>
<div>
<br /></div>
<div>
So, a simple solution to overcome my unwillingness to waste money on stuff I don't have to.</div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-46072320336035894302015-08-13T12:48:00.002-04:002020-06-10T08:46:56.154-04:00Selective Caller ID Blocking in Lync/Skype for BusinessOnce 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 <b>Alternate Caller ID</b> field in Voice Routes. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinZSGCC6xfFkdRiGCKcT7LBjGJOqWSRrcv7GbVzG-F2dimqfvWlgfaG9U3BXlGhpAjPYNC6-hZiCSQc6RHPm4LMhqA977FNbfpky2jNj7HE6qtz-UMDDriTP4qwSAHj87QuLN5GVQfLW8/s1600/AlternateCallerID.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="152" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinZSGCC6xfFkdRiGCKcT7LBjGJOqWSRrcv7GbVzG-F2dimqfvWlgfaG9U3BXlGhpAjPYNC6-hZiCSQc6RHPm4LMhqA977FNbfpky2jNj7HE6qtz-UMDDriTP4qwSAHj87QuLN5GVQfLW8/s640/AlternateCallerID.png" width="640" /></a></div>
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.<br />
<br />
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.<br />
<br />
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).<br />
<br />
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 <b>;callerid=blocked </b>(custom parameters are allowed by <a href="https://www.ietf.org/rfc/rfc3966.txt" target="_blank">RFC3966</a>).<br />
<br />
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.<br />
<br />
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.<br />
<blockquote class="tr_bq">
Pattern: ^\*67(\d{10})$<br />
Translation Rule: +1$1;callerid=blocked</blockquote>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIfNJ_FTwGy8bVxfH1UDCY4WbowrY-ameVnGYtoSRHJRe0AyDIryk3FDx8ZkbJpudvWdmqtm-lfU3NZltel6aYW_xpUfdWqQse5EhFzxp36fha1pDfichp-0ujWdTMPTD6hJG7iNgonDw/s1600/BlockNormRule.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIfNJ_FTwGy8bVxfH1UDCY4WbowrY-ameVnGYtoSRHJRe0AyDIryk3FDx8ZkbJpudvWdmqtm-lfU3NZltel6aYW_xpUfdWqQse5EhFzxp36fha1pDfichp-0ujWdTMPTD6hJG7iNgonDw/s640/BlockNormRule.png" width="492" /></a></div>
<br />
<br />
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 <b>;callerid=blocked</b>. The client won't see this part of the normalization string.<br />
<br />
Then you will need a special route that will accept numbers with that pattern and will apply the alternate caller ID:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJcd5hwYEBG4szFUWw14B7ShvAdzp8xo624YU3MxekcUkKZ_Fv_3acCtm9Sl6rtb5Iv46K-QqdD7BFta1vylIp0K4BDb13W6KFfl9k_ML8EWCj_jqoeTetLnBae8SDJuA4eIdjqciyBUQ/s1600/BlockRoute.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJcd5hwYEBG4szFUWw14B7ShvAdzp8xo624YU3MxekcUkKZ_Fv_3acCtm9Sl6rtb5Iv46K-QqdD7BFta1vylIp0K4BDb13W6KFfl9k_ML8EWCj_jqoeTetLnBae8SDJuA4eIdjqciyBUQ/s640/BlockRoute.png" width="594" /></a></div>
<br />
<br />
Make sure you assign the appropriate PSTN gateway to the route and add the voice route to the appropriate PSTN Usages.<br />
<br />
Finally, you will have to create a trunk translation rule on the selected trunk to strip the <b>;callerid=blocked</b> from the dialed number before sending it out to the PSTN.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3tsIpEdZbcq7Lveu9S4WZO4nbFYBC1RcgfJJw36N7Ej-pom2afeaLlA30Yv-az-IPNUsiWrzIXkdcGlb0-yCVWS0vjDjjFY7eHTCITBsNhfd5GRKSNQZyqrAd9HiBDnKvfaFRaIalxQA/s1600/BlockIDTrans.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3tsIpEdZbcq7Lveu9S4WZO4nbFYBC1RcgfJJw36N7Ej-pom2afeaLlA30Yv-az-IPNUsiWrzIXkdcGlb0-yCVWS0vjDjjFY7eHTCITBsNhfd5GRKSNQZyqrAd9HiBDnKvfaFRaIalxQA/s640/BlockIDTrans.png" width="486" /></a></div>
<br />
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.<br />
<br />
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 <b>P-Asserted-Identity</b>, which is the way it should work, so my SIP provider seems to be ignoring it.<br />
<br />
The example above used "<b>callerid=blocked</b>" 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 ;<i>parametername</i>=<i>value</i>. Custom parameters have to also be placed after any <b>;ext=</b> parameter.<br />
<br />
As you might expect, I've incorporated this functionality into the <a href="https://www.ucdialplans.com/" target="_blank">Lync Optimizer</a>. Try it out and let me know how it works for you.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpmn6XLdcqtpn7xVS8Tlp-GfLVTWjpoqqRzV08qaXCbfpDVuSetj5kjUm3l4Nu5_mPdJbWIru0p6vkQXH9lGTxucuuQYUWtEUWzrg-82St0isWIIzJa6UiiAvp6o92nyN_yCqcipjVogI/s1600/BlockIDOptimizer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="75" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpmn6XLdcqtpn7xVS8Tlp-GfLVTWjpoqqRzV08qaXCbfpDVuSetj5kjUm3l4Nu5_mPdJbWIru0p6vkQXH9lGTxucuuQYUWtEUWzrg-82St0isWIIzJa6UiiAvp6o92nyN_yCqcipjVogI/s640/BlockIDOptimizer.png" width="640" /></a></div>
<br />
<br />
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com4tag:blogger.com,1999:blog-2156539095375223979.post-38797512497595610122015-07-08T13:47:00.001-04:002015-07-20T17:02:29.697-04:00In-Call QoE Reports in Skype for BusinessWhen 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 "<span style="background-color: white; color: #686866; font-family: 'Segoe UI', 'Droid Sans', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;">Insufficient CPU event ratio</span>" that indicates the call quality was affected by a heavily loaded processor.<br />
<div>
<br /></div>
<div>
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 <b>SERVICE</b> message after the final <b>BYE</b> message. There will be one for each participant (assuming both users are in the same company). The <b>SERVICE</b> message body contains the quality report in XML format and looks something like this:</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfG4QtUSzptIqzKUPhyphenhyphenkgFJC594JP88OmwUulzi7zGBp5K44kBDar00s42lJiuOP-aObhbEaxCyVkffw66OD28mQO50UWnCbEgGQutzw3KSvdaoq_qTlW66dvIq5sfB6hPQhw8Ih_eFw8/s1600/QoEDataSample.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfG4QtUSzptIqzKUPhyphenhyphenkgFJC594JP88OmwUulzi7zGBp5K44kBDar00s42lJiuOP-aObhbEaxCyVkffw66OD28mQO50UWnCbEgGQutzw3KSvdaoq_qTlW66dvIq5sfB6hPQhw8Ih_eFw8/s640/QoEDataSample.png" width="528" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">There's a LOT more than what I've shown here, but you get the idea</td></tr>
</tbody></table>
<div>
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.</div>
<div>
<br /></div>
<div>
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 <a href="http://www.eventzero.com/" target="_blank">Event Zero's UC Commander</a> (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).</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhELP7gT8qkLzhZZfI-ro4K7oh56dDt921bdppZydvjfzFM-EAvyi8hjIJtx94nMnYVpkugORII6W05Xh-KsdUD0ve0ZMdLmNXOrp_9wSXho3WoJBFJR0YQg0NW_8JlJCyKByqm9rddLCQ/s1600/CallInProgress.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhELP7gT8qkLzhZZfI-ro4K7oh56dDt921bdppZydvjfzFM-EAvyi8hjIJtx94nMnYVpkugORII6W05Xh-KsdUD0ve0ZMdLmNXOrp_9wSXho3WoJBFJR0YQg0NW_8JlJCyKByqm9rddLCQ/s640/CallInProgress.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">"Uh, yeah...I'm calling you about that.....accounting.....thing. It would be easier to explain in person."</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
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:</div>
<div>
<br /></div>
<blockquote class="tr_bq">
<b>Set-CsMediaConfiguration -Identity Global -EnableInCallQoS:$TRUE -InCallQoSIntervalSeconds x</b> (where x is a digit from 1 to 65535).</blockquote>
<div>
You may have noticed the commands say <b>QoS</b>, when they really should say <b>QoE</b>. QoS is all about <i>Quality of Service </i>at the network layer, where QoE is <i>Quality of Experience</i>, 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. </div>
<div>
<br /></div>
<div>
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. </div>
<div>
<br /></div>
<div>
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), <b>NOT </b>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.</div>
<div>
<br /></div>
<div>
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* <a href="http://www.eventzero.com/" target="_blank">Event Zero's UC Commander</a>. </div>
<div>
<br /></div>
<div>
<br /></div>
Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0tag:blogger.com,1999:blog-2156539095375223979.post-68507574896545486722015-06-18T15:24:00.000-04:002015-06-18T15:24:40.849-04:00Dealing with Overdialing in Lync/Skype for BusinessIf you've never heard the term "overdialing", you're not alone. I hadn't heard of the term either until <a href="https://greiginsydney.com/about/" target="_blank">Greig Sheridan</a> 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."<br />
<br />
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 <b>1-800-BUYSTUFF</b>, which has 1 too many digits/letters for the North American dial plan (all numbers are 11-digits long, including the 1).<br />
<br />
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 <b>1-800-289-78333</b>.<b> </b>Again, notice its got one too many digits and hasn't normalized (note the lack of + sign at the beginning of the number).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZRrUYxhBIc9RF-RgmWQKeh1S3jiIDDPzs9Kc_oIbkdI8831QngiGlZjmcLCMP-SkEmFQ6aUdNhKOLFCM_I6pg25Rn1Ngv9ROh15DJfpP_XJ4hf1-ifF2snH1m3I5rPJwY6uCiiAew1Ss/s1600/BUYSTUFFNormWrong.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="135" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZRrUYxhBIc9RF-RgmWQKeh1S3jiIDDPzs9Kc_oIbkdI8831QngiGlZjmcLCMP-SkEmFQ6aUdNhKOLFCM_I6pg25Rn1Ngv9ROh15DJfpP_XJ4hf1-ifF2snH1m3I5rPJwY6uCiiAew1Ss/s400/BUYSTUFFNormWrong.png" width="400" /></a></div>
<br />
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:<br />
<br />
<div style="text-align: center;">
<b><span style="font-size: large;">^1?(\d{10}) --> +1$1</span></b></div>
<br />
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.<br />
<br />
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. <b>^\+?\d+$</b> 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 <b>E.164 EVERYWHERE</b>.<br />
<br />
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.<br />
<br />
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:<br />
<br />
<div style="text-align: center;">
<b><span style="font-size: large;">^1?(\d{10})\d*$ --> +1$1</span></b></div>
<br />
Now, when we dial that same number with too many digits, we get the following properly formatted normalized result:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUmefrVQhrgav8Z3iQpHVkpwBIpB1TwSJ0m3ZH3xlIg7lECFBtdZCUrcTdHsAzoWSt4cldODTQCWbemBTctLC8ai5Lvh62tCKMR0zAGXK-_EdOwha5zQUouocrTC6lZCOJtiXKeAQgykQ/s1600/BUYSTUFFNormRight.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="137" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUmefrVQhrgav8Z3iQpHVkpwBIpB1TwSJ0m3ZH3xlIg7lECFBtdZCUrcTdHsAzoWSt4cldODTQCWbemBTctLC8ai5Lvh62tCKMR0zAGXK-_EdOwha5zQUouocrTC6lZCOJtiXKeAQgykQ/s400/BUYSTUFFNormRight.png" width="400" /></a></div>
<br />
In the end, a simple change to an otherwise generic normalization rules can end up making your users' lives just a little bit easier.<br />
<br />
Thanks to the aforementioned Greig Sheridan, who suggested I write a blog post around this esoteric topic. I owe you a Foster's, mate!<br />
<br />
<br />
<br />Ken Laskohttp://www.blogger.com/profile/14298995806059683301noreply@blogger.com0