Monday, February 24, 2020

The Complete Guide to Using for Microsoft Teams Direct Routing

Seasoned veterans of my dusty, long-dormant blog will remember I did a comprehensive post (in 2012! EIGHT YEARS AGO!!!!) on how to use the Lync Optimizer to automatically create dialplans for your Lync deployments. That guide is still useful for every on-prem version of Lync and Skype for Business since then.  I did a similar guide for Skype for Business Online 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 in Direct Routing scenarios.
Who could forget the 2012 Hoff masterpiece Piranha 3DD? I didn't know this existed until just now. I know what I'm watching tonight!

A Milestone

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 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!

Who should use this guide?

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):

If you're using Teams Direct Routing (using your own SBCs to provide dialtone), then you should definitely 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.

If you're using Microsoft Phone System (where Microsoft is your telephony provider), then I suggest you read my blog post on Tenant Dialplans in Skype for Business Online. It will tell you why is still useful when your entire telephony infrastructure is managed by Microsoft. Even though it was written for SfBO, it still applies to Teams.

What can do for me?

In a Direct Routing environment, will automatically create the following:
  • Dialplans with normalization rules appropriate for your country, so users can dial phone numbers as they are accustomed.
  • Voice routing policies so you can selectively control who can dial locally, nationally and internationally.
  • Voice routes, which determine where calls are routed
  • PSTN usages, which are the glue between voice routing policies and voice routes
In a Microsoft Phone System environment, will automatically create the following:
  • Dialplans with normalization rules appropriate for your country, so users can dial phone numbers as they are accustomed.

What won't do for me?

If you're using Direct Routing, the "only" thing 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 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. 

To get familiar with what's required, read the excellent documentation on Microsoft's site starting with the Overview, then Plan Direct Routing, followed by Configure Direct Routing, but stop when you get to the section listed Configure Voice Routing. This is the point where takes over.

Getting Started

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. PowerShell scripts will check for the existence of at least one SBC via Get-CsOnlinePSTNGateway. If one isn't found, then the script will stop after creating a dialplan.

Generate your customized dialplan script

Go to and sign in with a Microsoft account. Once validated, you will see the webform for creating your dialplan become visible.

  1. Select Microsoft Teams as your gateway type
  2. Select the country and city/region where your SBCs are located.
  3. Some countries require special prefixes/suffixes for certain phone calls. Enter any prefixes in the provided boxes.
  4. If your SBCs are connected to the PSTN via SIP trunk, select SIP Trunk. 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 T1/E1/ISDN/Analog. NOTE: 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. 
  5. If you are connecting to a legacy PBX that requires adding a prefix to external numbers, enter one here. 
  6. 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 Assign internal dialing rules to the local or Global dialplan? question during script execution (see a few sections lower down for details).
  7. 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.
  8. If you don't want to control who can make local/national/international calls, you can select Simple Ruleset. 
  9. 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. 
  10. Once you're satisfied with the configuration, press GENERATE RULES
UCDialplans will start whipping its army of trained monkeys and in no time flat, you will have a customized PowerShell script ready for download.
Notice the Donate button? Not many people see this. :)

Click the DOWNLOAD RULESET HERE 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 Properties. Click Unblock, and then OK.

Backup your existing Teams EV config

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, see this post, or go to Github to download the latest version directly.

Run the script via PowerShell

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:
Set-ExecutionPolicy RemoteSigned
Or you can open your kimono and use Unrestricted in place of RemoteSigned.

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 address), then use the -OverrideAdminDomain switch.

You can also use the -PSTNGateway 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 .\US-Chicago-MSTeams.ps1 -PSTNGateway ",". If you're using Microsoft "Super Trunks", you'll need to use the -PSTNGateway switch because the script won't detect any PSTN gateways installed in your tenant.

When the script starts, you'll be presented with several questions:

Create global or user-level dialplan?

You can either assign the dialplan (which controls how users can dial phone numbers) to everyone by default via the Global dialplan or a user-level dialplan (the default selection). If the majority of your users are in the same location, you can use the Global 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 User. The script will create normalization rules as desired.

Assign internal dialing rules to the local or Global dialplan?

If you entered extension ranges via the UCDialplans UI, you will be prompted with this question. If you say Global, 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. This takes advantage of an undocumented feature described in this post. If you don't want to take advantage of this, select Local.

Assign PSTN usages to Global Voice Policy?

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 Local, National, or International. Local means that users will only be able to dial local numbers. National means they can dial any number within the country, and International has no restrictions.  If you do not assign anything at the global level, you will have to manually assign voice policies to all users.

Select primary/secondary PSTN gateway to apply routes

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 -PSTNGateway switch.

Configure voice policies for least-cost/failover routing

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. See this post for more info (was written for Lync, but still applies to MS Teams)

Final Steps

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):
Get-CsOnlineUser | Where {$_.TenantDialplan -eq $NULL  -and $_.EnterpriseVoiceEnabled -eq $TRUE} | Grant-CsTenantDialPlan -PolicyName BR-SaoPaulo
Get-CsOnlineUser | Where {$_.VoiceRoutingPolicy -eq $NULL  -and $_.EnterpriseVoiceEnabled -eq $TRUE} | Grant-CsOnlineVoiceRoutingPolicy -PolicyName BR-SaoPaulo-National
It will take some time for these to take effect, and will probably require users to restart Teams at some point.

Oooops! I screwed up!

If you accidentally screw up applying a 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.
Get-CsTenantDialPlan | Remove-CsTenantDialPlan
Get-CsOnlineVoiceRoute | Remove-CsOnlineVoiceRoute
Get-CsOnlineVoiceRoutingPolicy | Remove-CsOnlineVoiceRoutingPolicy
Set-CsOnlinePstnUsage Global -Usage $NULL
$GWList = Get-CsOnlinePSTNGateway
ForEach ($GW in $GWList) { Set-CsOnlinePSTNGateway -Identity $GW.FQDN -OutboundTeamsNumberTranslationRules $NULL -OutboundPSTNNumberTranslationRules $NULL -InboundTeamsNumberTranslationRules $NULL -InboundPSTNNumberTranslationRules $NULL }
Get-CsTeamsTranslationRule | Remove-CsTeamsTranslationRule 

Additional Tips and Tricks 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.

In this case, you can generate a UK-based script from and run it against your deployment using the -DPOnly 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.


  1. What when you have phone nummers from Micosoft so no sip trunk?

    1. If Microsoft is your telephony provider, will create customized normalization rules appropriate for your country, so users can dial phone numbers as they are accustomed. There is no need for voice policies/routes etc.

    2. Ken, long time, hope you're well. If I am using Microsoft Calling Plans, do I select the option for SIP trunk? If I do, how does the app know to drop the voice policies, etc?

    3. It doesn't really matter if you select SIP trunk or the other option. The script will see there aren't any PSTN gateways, and will just apply the dialplans. Easy peasy!

  2. Hey Ken, I am new to Teams Voice, and wondering when we connect the SBC's to our tenant, how do we assign phone numbers that the SBC manages?

    1. You assign phone numbers to users/call queues/auto attendants. The calls will route to the SBC according to the voice routes that have been assigned to that SBC.

  3. For Canada, your script sets up a dial plan for 7-digit 310 service numbers (CA-310Numbers), but I do not see a voice route to allow these to flow to the SBC. In my testing they were not reaching the SBC, even though I had International access, so I added a "310Numbers" voice route with ^\+(310\d{4})$ as the pattern (I placed it after TollFree routes and before Premium routes), and once that propagated I was able to get those calls to reach the SBC.

    1. You're right. It works for SfB, but not Teams dialrules. I will investigate.

    2. And the issue is now fixed. Thanks for bringing it to my attention!

    3. Awesome! I adjusted my route priorities to match your update (310Numbers at the bottom).

  4. This one is not a script issue, but one you may be interested in nonetheless. To secure our Audio Conferencing dial-out policies (as our meeting policies are very open), and to limit any Microsoft Calling Plan users to Domestic calling, which according to the MS docs is supposed to be Canada+US for both Canada and US-based users, I set CSDialOutPolicy as follows for all our users:

    Grant-CsDialoutPolicy -Identity $identity -PolicyName "DialoutCPCZoneAPSTNDomestic"

    Another reason I did this is by default many users had no policy, but some users, who had never had voice, but have moved through various E bundles plus add-ons over the years before getting to E5, had a policy applied (I forget which was most prevalent now but all were not the same).

    The result I have found though, is that this limits Direct Routed users to calling within their home country only, even though the National voice route is your Canada/US policy. The calls to the other country never reach the SBC. I verified this behaviour across a Canada and a US-based user, and I A-B tested it by enabling a user to be Direct Route International (made no difference), and a user left on National but changed to DialoutCPCZoneAPSTNInternational (user could then call both Canada and the US).

    This seems like a bug to me! The Microsoft docs are clear US and Canada are supposed to be treated as Domestic, yet Microsoft is restricting to in-country only, and that is evaluating even when the user is Direct Routed. I will open a case with Microsoft on this when I get time, but for now I am just setting the users we are activating to DialoutCPCZoneAPSTNInternational.

    Related docs:

    1. Well this one took a while to work its way through Premier Support all the way to to the product group. This is acknowledged as a bug (or at least behaviour that does not match the documentation) and it is reproduceable across tenants. We were told they are working on it but that it will take months to fix.

  5. Can your dial plans handle commas in phone numbers (for pauses to dial extensions)? I have gotten into the habit of structuring all my phone numbers in Outlook this way as iOS and Android recognize the comma as a pause. Microsoft even uses this format itself on tel: URLs for Microsoft Teams meeting dial-in numbers. In my testing, tel: links with commas return an error in Teams ("There was an issue with finding the person you were trying to reach"), and when putting commas in a dialed manually in Teams, they are ignored (the number itself gets dialed).

    This may be a feature request for Microsoft Teams instead?

    1. I've never considered adding comma support to They never seemed to work in SfB, and from your testing, they don't seem to work in Teams either.

    2. I found the Teams User Voice for commas support:

    3. Do you know if a dial plan rule could help here (i.e., ignore everything after a comma)? All the numbers with extensions I've added to my address book over the years to dial easily while on-the-go on my mobile phone can't be dialed from Teams. The Copy function is even greyed out in Teams, so I have to go back to Outlook to copy the number. Very annoying.

  6. Hi , how you route inbound calls < did> from PSTN via SBC to MS Teams DR - to users/teams
    Is the routing done via GUI or PowerShell

    1. Your SBC has to be configured to send incoming PSTN calls to Teams. If Teams is the only platform you're routing calls to, then its pretty straightforward. Refer to your SBC docs for details. Once it gets to Teams, it should all work (assuming the number is formatted to E.164 standards, and you're using my dialplans to get there.

  7. hi Ken, I ran you script for teams at the end of last year and im sure i did a month or 2 ago as well. Today i created 2 scripts for Teams and both of them has come up with this error - Cannot find specified online pstn usage "ZA-Durban-Local"
    +Category InvalidArgument: (Microsoft.Rtc.M...ceRoutingPolicy:OnlineVoiceRoutingPolicy) [Set-CsOnlineVoiceRoutingPolicy], ArgumentException
    + FullyQualifiedErrorId : CustomValidationFailed,Microsoft.Rtc.Management.Internal.SetOnlineVoiceRoutingPolicyCmdlet

    1. I see the same thing. It works fine on a clean system, but as soon as there are a set of existing PSTN usages, the command fails. Looking into it.

    2. It appears that O365 is being slow in making the PSTN usage available for adding to voice policies. If I run the commands a few minutes later, it works fine. I may have to add some delay to the script to allow for this.

    3. Further tests show that it takes up to 10 minutes before the Set-CsOnlineVoiceRoutingPolicy command recognizes there are valid PSTN usages, even though (Get-CsOnlinePstnUsage).Usage shows them right away.

    4. Trying to run the script now and it seems to be stuck on the delay, it's on round 55 and still PSTN usage not ready, any suggestions what could be wrong?

    5. Some people are reporting multi-hour delays. Just let it go and see if it works. It might time out on the connection after some point. Please report back with what finally happened.

    6. I had the same issue and I confirm, it took around 15 minutes before my platform accepts my creation of "Voice Routing Policy".

  8. Hi Ken. Great work.

    I'm in Australia and when I produce a ruleset (Does not matter which region and if it's simple) it creates a Normalization rule called 'AU-Service'.

    The regex in this rule is failing when getting added via the PS1 script.

    Here is the regex: ^(000|1[0125]\d{1,8}|(13(\d{4}|00\d{6}))$

    It fails on some online regex checks as it is missing a closing bracket. Can I presume that the closing bracket should go after the 000 or should it be added to the end, just before the $?

  9. In response to my own query about the AU-ruleset, the closing bracket goes at the end.

    1. Yes, you're right. I've corrected the defect. Thanks for telling me!

  10. We were testing emergency calling about a month ago, and I ended up modifying the Teams service number dial plan and service number voice routes as a result.

    1) Teams voice sometimes sends +911 instead of 911 (see I say sometimes because we found that dialing from different clients (e.g., desktop versus mobile) had different results.

    2) An increasing number of SIP providers offer 933 to test 911, so we needed that number treated the same as a real emergency call.

    This is what I did:

    Dial plan: ^([2-9]11|933)$
    Voice route: ^([2-9]11|933)$

    Session Border Controllers:
    Emergency IP route to look for either format: [911,+911,933,+933]#
    Outbound manipulation to look for + formatted and strip one character from the left if so: +[911,933]#

    Microsoft does mention in the docs that the 911 behaviour "will be modified in the coming months so that Teams emergency calls will no longer be sending a '+' preceding the number", but as that is not the case now, and I don't ever want to take any chances with emergency call routing, I plan to leave the above configuration in place for the foreseeable future.

  11. Hi Ken.

    In our environments an incoming mobile call is identified in the team client as 61 400 XXX XXX - with 61 being the country code here in Australia.

    When attempting to return the call, the teams client appears to try and dial +61 61 400 XXX XXX - ie the 61 is doubled, causing the call to fail.

    Can you advise of a way to modify the rules so it identifies if a country code is present and only add the + symbol?

    Thanks in advance for your terrific scripts.

    1. Did you use to generate your dialplans? My dialplan for AU won't normalize that number.

      Either way, if you change your mobile rule to the following, it should work fine. I may consider incorporating this into all my dialplans:

      Pattern: ^(?:0|61)(([45]\d{8}))$
      Translation: +61$1

    2. Yup we did use UCDialPlans - they're great!

      So changing the AU-Mobile from ^0(([45]\d{8}))$ to ^(?:0|61)(([45]\d{8}))$ did the trick for outgoing calls to mobile, but I've just discovered the same issue occurs when responding to landline calls also as they are identified in the teams client as:
      61 8 XXXX XXXX.

      I guess the same could also occur for calls that come in via toll free etc similar (eg 1800 XXX XXX) but we won't know until that occurs.

      Is making the above change to all calls types (Toll free, premium, mobile, national), and then repeating this for all zones the way to go, or is they are 'cleaner' method of creating a global type rule that, for example, detects if there's a 61 without the +, and just adds the + prefix?

      Thanks again,

  12. I'm wondering also whether we should perhaps be looking at doing translations on the way *in* to add the +prefix, or perhaps check with the telco or SBC .

    I imagine we might run into reverse number lookup issues as well if the incoming format doesn't match contact records - staff would complain that Teams isn't identifying the contact correctly and it comes in with unknown number all the time..

    1. Yes, I think it would be best to handle this at the SBC side. If all numbers are coming in like this, it should be pretty straightforward.

  13. Hi Ken, what is Significance of "Area Code" while creating Dial plan for UK? We have Tenancy in UK and SBC in London Data Centre. so what is the relevence of Area Code in genrating Dial plan, Also for Emergency is there any separate routes to be define such as detailed in Service, National etc..

    1. The area code is used to generate local dialing rules for a given location. It would allow people to dial numbers using the local dialing rules (say, by just dialing the subscriber number instead of having to include the area code). UCDialplans will create separate routes for service/emergency numbers.

  14. Hi Ken, Need your help in creating 7 digit dial for various states of US. For example below are few sample DID's & their extensions

    510-408-2189; 1012189
    510-408-2675; 1012675
    510-741-3953; 1013953
    510-741-4060; 1014060

    Now in above how can I create rules for 7 digit extension dialing? Problem is that I have no idea whether I need to add +510-408 or +510-741 as prefix.

    Below is how we are configuring 7 digit extensions here. first 3 digits are site codes followed by last 4 digits of DID

    (101xxxx) : Hercules / Benicia +1
    (102xxxx) : Woodinville / Maltby / Redmond +1
    (103xxxx) : Pleasanton +1

    1. If there isn't a unique pattern, then you'll be forced to create rules like this, using your examples:
      ^101(2189|2675|etc)$ -> +1510408$1
      ^101(3953|4060|etc)$ -> +1510741$1

  15. Hi Ken,

    I've ran the script already this morning after round 90 at Assigning PSTN usages to voice policies I've canceled the script. I've restarted it again and now at round 130 it won't go any further on assigning the PSTN usage.

    Can I just assign the PSTN usages records to voice routing policy thru the Teams Admin center and than run the script again?

    Thank you!
    Best regards,


    1. Yes you can, although you'll likely run into the same waiting game. Either way, it will eventually sort itself out.

    2. Ok, so just wait until forever and at some time it will finish? At about round 75 I need to login again to the tenant isn't that a problem?

    3. Yeah, pretty much. For whatever reason, its taking longer and longer for new PSTN usages to be recognized by the system.

    4. Hi, After assigning the PSTN Usage record manually in the admin portal and restarting the script it failed after about 120 rounds with the following error.

      Starting a command on the remote server failed with the following error message : The I/O operation has been aborted be
      cause of either a thread exit or an application request. For more information, see the about_Remote_Troubleshooting Hel
      p topic.
      + CategoryInfo : OperationStopped: ( [], PSRemotingTransportException
      + FullyQualifiedErrorId : JobFailure
      + PSComputerName :

      The rest of the script finished afterward successfully. Can I assume that it went fine or do I need to check anything?

    5. Check to make sure there are routes assigned to the usages and the usages are assigned to voice routing policies.

    6. All looks good and when I assign the dial plan en voice routing policy to a test user I can make calls, and for example normalization works.
      So I think assigning the PSTN Usage record manually to the Voice Routing policy did the trick eventually. Now I need to do this 3 more times for additional countries.

    7. Hi, It looks like there's something wrong in the PowerShell script. I've created a simple ruleset, but it's trying to connect the PSTN to a national voice policy that doesn't excist. See below example for this. Also have this on 3 other PS scripts for Germany and Belgium?

      Write-Host 'Assigning PSTN usages to voice policies'
      # It seems to take a while for PSTN usages to become available for usage, so if we get an error, wait a minute and try again.
      $Iteration = 0
      Do {
      Try {
      $PSTNUsageSetError = $False
      Set-CsOnlineVoiceRoutingPolicy -Identity "NL-Valkenswaard-040-National" -OnlinePstnUsages @{Add=$NL_NationalList} -ErrorAction Stop
      Catch {
      $PSTNUsageSetError = $True
      $Time = 60
      ForEach($i in (1..$Time)) {
      $Percentage = $i / $Time
      $Remaining = New-TimeSpan -Seconds ($Time - $i)
      $Message = "Round $Iteration`: PSTN usages not ready. Waiting for {1} before trying again. This may 10 minutes or longer." -f $Percentage, $Remaining
      Write-Progress -Activity $Message -PercentComplete ($Percentage * 100) -Status 'Waiting...'
      Start-Sleep 1
      } While ($PSTNUsageSetError)

      Set-CsOnlineVoiceRoutingPolicy -Identity "NL-Valkenswaard-040-AllCalls" -OnlinePstnUsages @{Replace=$NL_AllCallsList} | Out-Null
      If ($Int_AllCallsList -ne $NULL) {Set-CsOnlineVoiceRoutingPolicy -Identity "NL-Valkenswaard-040-AllCalls" -OnlinePstnUsages @{Add=$Int_AllCallsList} | Out-Null}

    8. I don't suppose you're using the -LocalOnly switch on the PS script?

    9. No I don't use the -LocalOnly switch

    10. I've used the simple ruleset because everybody is allowed to call to anywhere. So the scriptname is in this example "NL-Valkenswaard-040-AllCalls.ps1" so I start it with .\NL-Valkenswaard-040-AllCalls.ps1,
      So it's strange it refers to ""Set-CsOnlineVoiceRoutingPolicy -Identity "NL-Valkenswaard-040-National" -OnlinePstnUsages @{Add=$NL_NationalList} -ErrorAction Stop"" in the script.

    11. Ah, I see the problem. The simple ruleset doesn't create the -National ruleset, which is what I am using for the timer. I will get a fix out ASAP.

    12. Aaaand, its fixed. If you use the Simple Ruleset option, you should no longer be forced to wait forever. You will still have to wait for SOME period of time, but it won't be forever anymore.

    13. I've creaded a new script and running it over the existing settings (so routing policy and PSTN usage etc. already exist for a few days) but already runnning again for almost 35 rounds.

      The "Set-CsOnlineVoiceRoutingPolicy -Identity" is now ok, but the "-OnlinePstnUsages @{Add=$NL_NationalList} -ErrorAction Stop" still mentions something about national, should that be ok!

      Maybe contact me thru e-mail: jeroens[@] might be a bit more easy than over here.

  16. Hi Ken,

    I can also confirm the PSTN Usage issue (delay) from above. It never seems to go beyond that point and the O365 connection timesout.

  17. Sorry needed to wait just a bit longer, after the timeout and logging in again in PowerShell it continued and finished!

  18. I've got a minor issue, writing normalisation rules for MS Teams, and attaching them in a dial-plan is working fine. Except the sort-order; the new rules are added at the bottom sequentially.

    How to I add re-sort the rules?
    $NR = @()
    # +442072449500-99
    $NR += New-CsVoiceNormalizationRule -Name "EXT-DIALING 442072449500xx" -Parent $_.Identity -Pattern '^([5][0]\d{2})$' -Translation '+442072449500$1' -InMemory -Description "Extension number normalization for $siteName - Created by $($env:username) $(Get-Date -format yyyy-MM-dd)"
    # several lines redacted
    Set-CsTenantDialPlan -Identity $_.Identity -NormalizationRules @{replace=$NR)

    1. You can sort them using the -Priority switch in the New-CsVoiceNormalizationRule command. You can also re-sort via the Teams Admin UI.

  19. Has any additional updates been made to help address the recent US changes for 10-digits?
    Beginning October 24, 2021, any local calls made in the following area codes must dial 10-digits, area code + phone number, or the call will not go through:
    New Jersey: 856, 908
    New York: 516, 845, 914

    1. assumes 10-digit dialing is default for North American rulesets. Its relatively rare to see 7-digit dialing. To allow 7-digit dialing in, you have to explicitly select a checkbox for it.

    2. Thanks Ken. Will check what I used in our tenant

  20. I also notice that the script\Tool worked fine with Skype Ps but now that it needs Teams Ps does not work anymore. Are there plans to update script to use Teams Ps with ModernAuth?

    1. I don't know what you mean by Skype Ps and Teams Ps

    2. I guess using the module 'MicrosoftTeams' instead of the obsolete module 'SkypeOnlineConnector'.

    3. Ah, that makes sense. Yes, I do need to do that.

  21. Good Morning , Is the tool still working as I cannot sign in on your page UCDIALPLANS as there is no hyperlink to sign in with my MS credentials and start using the the tool. I see the Sign in With your Microsoft ID to get started but it is just a banner with no Hyperlink

    1. It seems that the certificate protecting the MS login service expired yesterday. Chrome won't show the login button, but Edge does. It just says that some parts of the site isn't secure.

  22. Hi Ken, I was looking on your UC Dial Plans site and had a question about Australian dialplans...
    AUS users dial 8 digits and they need to apply their area code. but if I have Teams users in multiple AUS regions, do they all need a bespoke dial plan per region? eg 02 region always adds 02 before 8-digit numbers, and 07 region always adds 02 before ?

    1. If users are accustomed to always adding the area code, then you can do a single dialplan. But if they expect to dial only 8-digits for numbers within their area code, you should do separate dialplans per region.

    2. thanks for your reply. Is there any method that Teams could 'know' their region code based on their DID?

    3. That would be nice, but that feature doesn't exist.

  23. Hi Ken, Love your work.
    Could you please add commentary where necessary for tenants using native Teams Call Plans and not Direct Route or possible hybrid of both.
    Keep well. Many Thanks

  24. Hi Ken! We can't choose to block premium rate numbers for the UK (09 numbers) for Teams.The option is only available for SFB on your site. What regex rule would we need to use to effectively have users open unrestricted with just premium numbers blocked?

    1. The "Block Premium Numbers" feature for SfB uses the SfB Announcement service to not only block premium numbers but will play back a custom message to the caller. See for more information.

      In Teams, this feature isn't available, but the voice policies generated by allow for blocking premium number calling. The default National voice policy does not allow premium dialing. The International voice policy does allow it, but you can simply remove the Premium PSTN usage from the policy to block premium dialing for all.

  25. Hi Ken,

    We generated our dial plans from We recently had a request to open up a number from a cellular provider, the number 082 1946. We then created a new rule to allow this. It shows as working when testing from powershell and using the correct rule.

    Our normal rules:

    $NR += New-CsVoiceNormalizationRule -Name 'ZA-TollFree' -Parent $DPParent -Pattern '^0(80\d{7})\d*$' -Translation '+27$1' -InMemory -Description "TollFree number normalization for South Africa"
    $NR += New-CsVoiceNormalizationRule -Name 'ZA-Premium' -Parent $DPParent -Pattern '^0(86[24-9]\d{6})$' -Translation '+27$1' -InMemory -Description "Premium number normalization for South Africa"
    $NR += New-CsVoiceNormalizationRule -Name 'ZA-Mobile' -Parent $DPParent -Pattern '^0(([67]\d{8}|8[1-5]\d{7}))$' -Translation '+27$1' -InMemory -Description "Mobile number normalization for South Africa"
    $NR += New-CsVoiceNormalizationRule -Name 'ZA-National' -Parent $DPParent -Pattern '^0(([1-5]\d\d|8[789]\d|86[01])\d{6})\d*(\D+\d+)?$' -Translation '+27$1' -InMemory -Description "National number normalization for South Africa"
    $NR += New-CsVoiceNormalizationRule -Name 'ZA-Service' -Parent $DPParent -Pattern '^(1\d{2,4})$' -Translation '$1' -InMemory -Description "Service number normalization for South Africa"
    $NR += New-CsVoiceNormalizationRule -Name 'ZA-International' -Parent $DPParent -Pattern '^(?:\+|00)(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\d|5[09]\d|6[789]\d|8[035789]\d|9[679]\d)(?:0)?(\d{6,14})(\D+\d+)?$' -Translation '+$1$2' -InMemory -Description "International number normalization for South Africa"

    The new rule we added to allow this number is:

    $NR += New-CsVoiceNormalizationRule -Name 'Vodacom' -Parent $DPParent -Pattern '^\d{1}(\d{6})$' -Translation '+27$1' -InMemory -Description "Vodacom"

    You can see it makes use of this rule when testing, but it only states, sorry we could not connect you.

    Another number that belongs to the same company does work, the number is 082 135.
    Any other number 082 1946 does not work.
    The 082 135 number can be dialed internationaly +2782 135.
    If you belong to the same cellular provider all the numbers are free, if not you will be charged for the call.

    Thank you.

  26. Are you sure those short phone numbers are dialable from outside of Vodacom's network? I tried dialing +2782135 and I got a "Could not be completed as dialed"

    1. Hi Ken,

      Yes the numbers can be dialed from any other network provider. We have a Direct routing configuration setup. DO you think it could be an issue on the SBC side?

    2. No, its a rule issue. I've updated the mobile rule to include these Vodacom special numbers

  27. Hi Ken nice blog just to ask. do you have a permanent solution on the delay for the adding pstn usage to voice policy? I notice the command is Set-CsOnlineVoiceRoutingPolicy -Identity "MY-XXX-National" -OnlinePstnUsages @{Add=$MY_NationalList} -ErrorAction Stop. will removing the erroraction stop will resolve this issue? i can assign this manually in TAC

  28. Is ucdialplans site down indefinitely? Currently can’t access it anymore. Kindly check.

  29. Hi Ken, your Site Ucdialplans is down.
    It’s every MS Teams implementer’s guide.
    Please let us know when this will be online again.

  30. Hi Ken,

    is it supported to add ^(\d{4})$(\+9714\d{7})$ in Voice Route dial pattern using single PSTN Usage.

    I want to allow 4 Digit number & +9714 on the same route