onsdag den 13. juni 2018

Manage Tenant Dialplans in Microsoft Phone System (Denmark)

Ever since OCS/ LYNC server became Voice enabled we had the option to work with Normalization Rules - Normalization Rules is a way to enable users to maintain their existing dialing patterns, this could be 4 Digit shortnumbers within an organization, or simply the ability to type 8-digit numbers and see them "normalize" within the client to fully supported E.164 numbers with + and countrycode.
  • Hybrid with Skype for Business Server 2015 
    • Calls to/from users homed in Skype for Business Online route via an on-premises Skype for Business Server deployment to the PSTN network.
  • Hybrid with onprem or hosted CCE
    • Calls to/from users homed in Skype for Business Online route via on-premises CCE deployment to the PSTN network

If the Cloud PBX users is in Hybrid with an traditional on-premises Skype for Business Server, on-premises dial plans can be assigned to Cloud PBX users. This ensures that, when users are moved from on-premises to online, their dialing behavior remains unchanged.

If the Cloud PBX users utilize an on-premises Cloud Connector Edition, on-premises dial plans cannot be assigned. Instead, users are assigned a Tenant Country level dial plan from the Skype for Business Online tenant, which cannot be configured or customized. This presented some challenges, including:
Users that were moved from on-premises Skype for Business (Enterprise Voice), to Skype for Business Online (Cloud PBX) would experience a change in dialing behavior, as their dial plan would not move with them.
In Denmark, the dial plan is very basic. Only 2 normalization rules were contained within the dial plan See snooper trace below.
Some issues with this included incorrect normalization behavior when dialing emergency numbers, as well as no support for users dialing local 8 digit numbers,because users in one Denmark wanted +45 and users in other country with 8-digits had different requirement.

Snooper trace for standard Danish user with the Tenant wide default DK Dialplan - notice only two Normalization rules apply.

This means that normalizations for neither emergency or normal 8 digit numbers work at all. :(

Luckily this was the past, with TenantDialplans this is actually customizable to fit your organizations needs.

Worth mentioning is that the Online Dial Plan hierarchy (scope) is working differently if a Tenant Dial Plan is activated.
So theTenant Dial Plan hierarchy differs from On-Premise scopes. On-Premise you could define Dial Plan based on Global, Site, Pool and User level, where the lowest (closer to the effective user) Dial Plan will be effective. 
With Online Dial Plans you merge the Service Country with the Global or User applied Dial Plan. 
Note: The Tenant Dial Plan always comes first! 
Illustration is copyed from Thomas Poetts great article on the subject.:

Article found here: https://gallery.technet.microsoft.com/Tenant-Dial-Plans-in-Skype-c80a7dfd

So lets get configuring via powershell.

To find the tenant level dialplan

The following cmdlet will list default dial plan entries that apply to a region. In this example, the region is DK: (Get-CsDialPlan DK).NormalizationRules | FT Name,Description,Pattern,Translation
As you see only two rules.
If you only have users in one single country - the easiest way to achieve correct normalization is simply to modify this Service Level Dialplan

$NR1 = New-CsVoiceNormalizationRule -Name 'DK-TollFree' -Parent Global -Pattern '^(80\d{6})\d*$' -Translation '+45$1' -InMemory -Description "DK-TollFree"
$NR2 = New-CsVoiceNormalizationRule -Name 'DK-Premium' -Parent Global -Pattern '^(90\d{6})$' -Translation '+45$1' -InMemory -Description "DK-Premium"
$NR3 = New-CsVoiceNormalizationRule -Name 'DK-Mobile' -Parent Global -Pattern '^(((2\d|3[01]|4[0-2]|5[0-3]|6[01]|[78]1|9[1-3])\d{6}))$' -Translation '+45$1' -InMemory -Description "DK-Mobile"
$NR4 = New-CsVoiceNormalizationRule -Name 'DK-National' -Parent Global -Pattern '^((3[2-689]|4[3-9]|5[4-9]|6[2-69]|7[02-9]|8[26-9]|9[6-9])\d{6})\d*(\D+\d+)?$' -Translation '+45$1' -InMemory -Description "DK-8digit"
$NR5 = New-CsVoiceNormalizationRule -Name 'DK-Service' -Parent Global -Pattern '^(11[24]|1\d{3,5})$' -Translation '+45$1' -InMemory -Description "DK-service"
$NR6 = New-CsVoiceNormalizationRule -Name 'DK-International' -Parent Global -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 "DK-International"

Set-CsTenantDialPlan -Identity Global -NormalizationRules @{Add=$NR1,$NR2,$NR3,$NR4,$NR5,$NR6}

The same logic applyes when removing rules from Global - simply change ADD to Remove and put the rules you want to remove in a variable

Lets say you want to remove the DK-Service rules.

$NR1 = New-CsVoiceNormalizationRule -Name 'DK-Service' -Parent Global -Pattern '^(11[24]|1\d{3,5})$' -Translation '$1' -InMemory -Description "DK-service"
Set-CsTenantDialPlan -Identity Global -NormalizationRules @{Remove=$NR1}

 Most common is to create user level tenant dialplan - so we can manage pr site or country.
Theese are the rules and commands needed for Denmark.

$NR1 = New-CsVoiceNormalizationRule -Name 'DK-TollFree' -Parent Global -Pattern '^(80\d{6})\d*$' -Translation '+45$1' -InMemory -Description "DK-TollFree"
$NR2 = New-CsVoiceNormalizationRule -Name 'DK-Premium' -Parent Global -Pattern '^(90\d{6})$' -Translation '+45$1' -InMemory -Description "DK-Premium"
$NR3 = New-CsVoiceNormalizationRule -Name 'DK-Mobile' -Parent Global -Pattern '^(((2\d|3[01]|4[0-2]|5[0-3]|6[01]|[78]1|9[1-3])\d{6}))$' -Translation '+45$1' -InMemory -Description "DK-Mobile"
$NR4 = New-CsVoiceNormalizationRule -Name 'DK-National' -Parent Global -Pattern '^((3[2-689]|4[3-9]|5[4-9]|6[2-69]|7[02-9]|8[26-9]|9[6-9])\d{6})\d*(\D+\d+)?$' -Translation '+45$1' -InMemory -Description "DK-8digit"
$NR5 = New-CsVoiceNormalizationRule -Name 'DK-Service' -Parent Global -Pattern '^(11[24]|1\d{3,5})$' -Translation '$1' -InMemory -Description "DK-service"
$NR6 = New-CsVoiceNormalizationRule -Name 'DK-International' -Parent Global -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 "DK-International"

New-CsTenantDialPlan  -Identity DK -NormalizationRules @{Add=$NR1,$NR2,$NR3,$NR4,$NR5,$NR6}

Grant-CsTenantDialPlan -PolicyName DK -Identity tjo@xxx.dk

 Then after logging in we can see a clear change i numbers rules in the snooper trace.
And now we see the normalizations working perfectly

Now you just need to define and add custom rules for other contries

If you want to see which dialplan a certain user is affected by run this:
Get-CsEffectiveTenantDialPlan -Identity tjo@xxx.dk | Select-Object -ExpandProperty NormalizationRules

As always Happy SKYPE'ing

tirsdag den 22. maj 2018

Updated requirement for SKYPE4B Hybrid

On more than one occasion, when doing a Hybrid SKYPE for Business implementation, i have come across the need to do an, until now, undocumented DNS configuration.

Up until now i only saw this need in splitbrain DNS environments.

The end result being one-way presence - so internal users had no presence for neither federated, nor online users.
When on-prem users attempted to see presence we saw "Presence unkown" or ….."Updating"
From the federated user perspective everything was OK.

The fix is to create 2 internal DNS records, resolvable by both clients, and the internal interface of the EDGE server.
1.  Being an  exact copy of the public SRV record for federation.
_sipfederationtls._tcp.sipdomain.com pointing to external access edge FQDN on port 5061
2 DNS A record for the access edge FQDN resolving the PUBLIC IP of the access edge interface.
3 DNS A record(s) for Edge Web Conferencing Service FQDN also resolving external IP

Recently however this was added to the online planning documentation.
So i guess this is now to be considered a requirement, although in non splitbrain DNS scenarios you would never know you missed it :)
Thanks for this Microsoft :)

The Planning documentation can be found here:

As always happy SKYPE'ing

lørdag den 21. april 2018

LYNC 2013 End of Support

Time flies - and this April of 2018 - all LYNC 2013 server and client version are end of Mainstream Support.

Ending mainstream support for a product means Microsoft will no longer be enhancing that product. What it does NOT mean is there will no longer be fixes for security and reliability issues. Microsoft will continue to issue bug fixes and patches for security and reliability issues.

See lifecycle site here:

When mainstream support ends, this is what occurs:

· Microsoft no longer supplies non-security hotfixes unless you have an extended support agreement

· All warranty claims end

· Microsoft no long accepts requests for new features and design changes

When extended support ends, you can no longer count on any security patches or reliability patches.

Please note this also accounts for:

Exchange Server 2013 and Sharepoint server 2013
More info on this in the Lifecycle FAQ:


What should you do ?

If you are in the progress of migrating to SKYPE for Business, you should continue.

If not you have several options, depending on your situation and business needs.

1. Side by side migration to the upcoming Skype for Business Server 2019 will be supported both from LYNC server 2013 and obviously SFB Server 2015.

2. You could still choose to inplace upgrade your servers to SKYPE for Business 2015

3. To stay in Mainstream support and at the same time upgrade OS on servers to 2016 - do a side by side migration to SFB 2015.

Happy SKYPE'ing

mandag den 26. marts 2018

March CU for SKYPE for Business server released

Howdy Folks - and happy Easter.

A new cumulative patch has been released for SKYPE for Business server 2015.

Version number for Core components is 6.0.9319.516

To find your current patch level run this command on a SFB server

Get-WmiObject –query ‘select * from win32_product’ | where {$_.name –like “*SKYPE for business*”} | ft Name, Version –AutoSize

This Microsoft decided to make this patch only recommended if you actually struggles with one of the issues listed. Or if you wish to utilize Location based routing through mobile devices - which is the only real new feature in this patch.
However it is perfectly safe to install the patch in any case.

Read much more about Location Based Routing in this great article by MVP Mark Vale:

The fixes are theese:

  • 4036626 Missing ApplicationOptions attribute in user object created by New-CsHybridApplicationEndpoint cmdlet in Skype for Business Server 2015
  • 4078589 High memory usage on RtcHost.exe when you deploy Shared Line Appearance in Skype for Business Server 2015
  • 4078588 Can't sign in Skype for Business mobile apps after applying Skype for Business Server 2015 CU6
  • 4078590 Calls to Mac fail when enhanced presence privacy mode is enabled in Skype for Business Server 2015
  • 4078592 Push Notification not working for Skype for Business for iOS in Skype for Business Server 2015
  • 4078587 Voice settings are intermittently reset in Skype for Business on iOS and Android

To download the CU go to: https://support.microsoft.com/en-us/kb/3061064

For installation instructions go to:

As always Happy SKYPE'ing

mandag den 19. marts 2018

Managing Holidays in Response Groups - no problem

If you also find it frustrating to manage RGS Holidays - look no further.

I see alot of customers struggling to get this done, and look to different Powershell GUI's and unsupported addons - but often see issues when moving to a new server version.

So powershell should be your one-stop-shop for this task.

I therefore decided to publish some of the commands that i use, and please note that the below guides are for DANISH holidays, so adjust the dates accordingly :)

For Powershell tips on managing Response Groups in general look to this article:

When you work with the RGS cmd-lets you have to rely on variables.

The Set-CsRgsHolidaySet cmdlet provides a way for you to modify an existing holiday set. (For the most part, this means adding holidays to or removing holidays from the set.) Set-CsRgsHolidaySet is not directly used to make changes to a holiday set. Instead, an object reference is created to an existing holiday set by using the Get-CsRgsHolidaySet cmdlet. (An object reference is a variable that, in this case, refers to an existing holiday set). Changes to the set are made in memory, then the Set-CsRgsHolidaySet is used to write those changes to the actual holiday set. If you do not call Set-CsRgsHolidaySet, then the changes you make will exist in memory only and will disappear as soon as you close Windows PowerShell or delete the object reference.

Lets use this logic to create a new Holidayset containing all Danish holidays for 2018

Please note i sometimes create holidays that run from the previous full business day closing time.
So lets say Easter Thursday is created, the Holiday set could begin already the previous day at office closing hours, but this is individual.

The following examples all run from and to Midnight

First you create the variables by running theese:

$a = New-CsRgsHoliday -Name "Nytårsdag" -StartDate "1/1/2018 00:00:00 AM" -EndDate "1/1/2018 12:00:00 PM"
$b = New-CsRgsHoliday -Name "Påske" -StartDate "3/29/2018 00:00:00 AM" -EndDate "4/3/2018 12:00:00 PM"
$c = New-CsRgsHoliday -Name "St Bededag" -StartDate "4/27/2018 00:00:00 AM" -EndDate "4/27/2018 12:00:00 PM"
$d = New-CsRgsHoliday -Name "Kr Himmelfart" -StartDate "5/10/2018 00:00:00 AM" -EndDate "5/10/2018 12:00:00 PM"
$e = New-CsRgsHoliday -Name "Pinse" -StartDate "5/20/2018 00:00:00 AM" -EndDate "5/21/2018 12:00:00 PM"
$f = New-CsRgsHoliday -Name "Grundlovsdag" -StartDate "6/5/2018 00:00:00 AM" -EndDate "6/5/2018 12:00:00 PM"
$g = New-CsRgsHoliday -Name "Julen" -StartDate "12/24/2018 00:00:00 AM" -EndDate "12/26/2018 12:00:00 PM"

The you need to assign theese holidays to a new holiday set

New-CsRgsHolidaySet -Parent "ApplicationServer:poolname.domain.local" -Name "DK 2018" -HolidayList($a,$b,$c,$d,$e,$f,$g,)

Now you have a complete 2018 Danish Holiday Set ready to use in RGS.

So lets say you are in the middle of March and your boss ask you to make sure that holidays are in place for easter, and you already have your 2018 set in place - no problem - here is how to add an additional holiday to an existing set.
First we make a varialbe containing the new holiday, then we extract and modify the Holidaylist from en existing Holiday Set

$x = New-CsRgsHoliday -Name "Påske" -StartDate "3/29/2018 00:00:00 AM" -EndDate "4/3/2018 12:00:00 PM"
$y = Get-CsRgsHolidaySet -Identity "service:ApplicationServer:poolname.domain.local" -Name "DK 2018"
 $y.HolidayList.Add($x) Set-CsRgsHolidaySet -Instance $y

Same procedure it you wanted to remove a single holiday from the list - in the example i remove Påske from the DK 2018 set

$x = Get-CsRgsHolidaySet -Identity service:ApplicationServer:poolname.domain.local -Name "DK 2018" 
$y = $x.HolidayList | Where-Object {$_.Name -eq "Påske"} $x.HolidayList.Remove($y) Set-CsRgsHolidaySet -Instance $x

Also worth noting that the opening hours also can be created as sets that will selectable in the Repons Group creation process.

$a = New-csRgsTimeRange -Name "Business Hours" -OpenTime "07:00" -CloseTime "17:00"

New-CsRgsHoursOfBusiness -Parent "ApplicationServer:poolname.domain.local" -Name "Business Hours" -MondayHours1 $a -TuesdayHours1 $a -WednesdayHours1 $a -ThursdayHours1 $a -FridayHours1 $a

Thats it for know, hopefully the task of maintaining your company holidays will be less of a headache now.
Happy SKYPE'ing

fredag den 8. december 2017

Office365 Infographic

Kudos to  Matt Wade & icansharepoint.com for creating this EPIC Periodic Table, its really usefull for finding your way around the evergrowing bunch of app's included in your 365 subscription.

Go check it out at http://periodictableofoffice365.azureedge.net/#/periodictable/da

torsdag den 30. november 2017

Bypass prerequisite KB's on SFB2015

Hi all.

Yes i know the subject sounds a bit - well - tricky - however, recently I came to work with a customer that had updated their topology and thus were running the bootstrapper which failed, so something had to be done - for some strange reason the OS patchlevel somehow must have been modified since initial deployment, because the reason for the failure was down to missing prerequisites.

This was the error message

Allright, no problem, lets go and request this hotfix, that is actually a prerequisite for SFB2015 as described here: https://technet.microsoft.com/en-us/library/dn951388.aspx

 So now the fun started, running the downloading MSU file returned this lovely messagebox:

And when checking the Event viewer on the FrontEnd server, we found this:

Oh...2149842967 - I see.... or rather not - when recieving strange numbers always run them against a Hex converter for instance: http://www.binaryhexconverter.com/decimal-to-hex-converter
And then google the result:

This leaded to the site "Windows update agent result codes" Finally something usefull

Oh - i guess not, thanks for nothing. :)

So - what now, well after reading prerequisites for the Hotfix itself, we found this:
“To apply this hotfix, you must first install update 2919355 on Windows 8.1 or Windows Server 2012 R2. For more information, click the following article number to view the article in the Microsoft Knowledge Base: 2919355 Windows RT 8.1, Windows 8.1, and Windows Server 2012 R2 Update April, 2014 – https://support.microsoft.com/kb/2919355

This KB Also had prerequisites-
“To apply this update, you must have the following update installed on Windows RT 8.1, Windows 8.1, or Windows Server 2012 R2: 2919442 A servicing stack update is available for Windows RT 8.1, Windows 8.1, and Windows Server 2012 R2: March 2014″

Here we decided to make a shortcut, and utilize DISM's online servicing function.

DISM is built in to the operating system as documented here: https://technet.microsoft.com/en-gb/library/hh825236.aspx

Initially make sure that KB2919355 and KB2919442 are installed

In powershell, run: Get-Hotfix KB2919442,KB2919355,KB2982006

Then we have to expand the MSU file (the Hotfix downloaded above), because DISM does not support MSU files using online mode.

Create a folder (could be under c:\TEMP) called KB2982006
Now open CMD as administrator cd in c:\temp
and type Expand -F:* C:\temp\Windows8.1-KB2982006-x64.msu C:\temp\KB2982006

Now we can manually add the cab file to the OS using this command:

dism /Online /Add-Package /PackagePath:C:\temp\KB2982006\Windows8.1-KB2982006-x64.cab

Now verify that KB2982006 is in the list

In powershell, run: Get-Hotfix KB2919442,KB2919355,KB2982006

Now rerun Bootstrapper and Oh Joy - it finishes with success.

As always - Happy SKYPE'ing