Inserting QoS markings into your Teams meetings

Microsoft have now enabled the ability for administrators to mark Teams meeting traffic with QoS markings.

This setting can be found in the Teams admin portal (https://admin.teams.microsoft.com/meetings/settings) or by using the PowerShell commandlet Get-CsTeamsMeetingConfiguration.

It looks like this:

meetingsqosclimeetingsqosgui

 

Advertisements

Microsoft Teams interface change when you’re added as a guest to another Team

For the life of me, I could not figure out how Microsoft had implemented their counterpart to Slack’s workspaces.. I personally found the lack of this feature (I thought) to be a deal breaker for my use of the platform, as I use Slack for personal use and really, REALLY wanted to move this functionality to Teams.

With the launch of FREE (yes, FREE) Teams, I was able to set up a free tenant and a Team for the club I belong to and really get to playing with how this feature would appear within Teams.

The Rub:

A feature of Microsoft’s Skype for Business that has been carried over to Teams is the hiding of features the user doesn’t have access to, keeping the interface nice and clean (I like this). The challenge here is that the drop down does not automatically appear when you’re added as a guest in another Tenant’s Team. When I browse to the Web Client, I see the following:

Teams Guest

However, in the Windows Client, nothing appears, even after a 10 minute wait…

Team No Guest

To resolve this, I had to click on the Teams Client logo in the notification bar, quit Teams and relaunch. After my client signed back in, I could see the drop down in the Windows client.

Teams Win Guest

I would like to see this appear without having to kill the application. Maybe we’ll get an update soon that fixes this…

Remove old Monitoring Service from SfB

Occasionally, normally after an upgrade or decommission, I come across a reporting service in the Skype for Business control panel that is no longer valid.

It doesn’t cause anyone (except my OCD) any pain, but I don’t want that sucker there any more..

Capture1

Here’s how we make my OCD’s pain go away 🙂

First, run Get-CsReportingConfiguration to get a list of what the topology believes are the reporting servers in your environment.

Capture2

From the output, we can see the nicely named version we’re expecting, as well as the now defunct configuration. We can usually identify this by the fact it has a service id and not a nice name. In this case Service:2-MonitoringStore-1.

Being extra careful (we don’t want to accidentally remove the wrong configuration), I run Get-CsReportingConfiguration -Identity <identity>. In this example, I ran:

Get-CsReportingConfiguration -Identity Service:2-MonitoringStore-1

Once I confirm that I have isolated the Reporting Configuration I want deleted, I proceed with:

Get-CsReportingConfiguration -Identity Service:2-MonitoringStore-1 | Remove-CsReportingConfiguration

Close and re-open the control panel and your pain should be relieved.

 

 

Test User or Common Area Phone Extension/Pin Sign-in with 2 Parameters

I recently came across a project that involved the migration of a large number of endpoints from an unmanaged state to a managed state.

 

As happens with these projects, a number of devices did not cut across cleanly for a multitude of reasons and manual intervention was required.

The first step in ensuring everything was as it was supposed to be was validating that the SfB account was able to successfully authenticate using the extension and pin combination we thought were set for that account.

I have to say, I love the fact that there are a multitude of test command within Skype for Business, but man, the use of them sometimes could do with a slightly more user friendly interface.

I wrote up this script to allow you to test the extension and pin signin without having to remember the full Test-CsPhoneBootstrap command and parameters.

 

P.S. We were testing this from the server in an environment with everything nicely isolated from everything else, so DHCP discovery was a no-go for this one…

 

Running the script:

1) Download and save the script to the folder of your choice
2) Execute as follow:

.\Test-CsPhoneSignin.ps1 -UserExtension 1234 -UserPin 123456

The script will ensure a pin has been set and that the user is not locked out, then retrieve the confiured pools and web service locations and test against them..

 

I hope this saves you some time 🙂

(Sad face emoji) It’s broken..

And when I say it’s broken, I’m talking about the emojis in Skype for Business.

As far as I know, this only affects the Click-2-Run version, and it’s not everyone that’s getting affected.

Luckily, there is a fairly quick way to fix this, which I share below. I make the presumption that you want to fix this for all of your policies, if that is not the case, please edit the script before you run it on your environment. 🙂 <- Happy face emoji (just in case)

Run this little beauty to fix your emojis, then have your clients exit and restart their SfB clients (some need a cache clean out, results may vary)

$emojifix = New-CsClientPolicyEntry -Name “DisableRicherEditCanSetReadOnly” -Value “true”
Get-CsClientPolicy | % {Set-CsClientPolicy -Identity $_.Identity -PolicyEntry @{Add=$emojifix}}

Get-CsClientPolicy | fl Identity, PolicyEntry

CQM Reporting made easy

A while back I posted a script that automated the majority of the CQM reporting process, but was reliant on prerequisites being present on the server (download CQM, extract to c:\temp etc)

Forwarded on to some of my colleagues and immediately realised that there was quite a lot to do to actually get CQM data out of SfB and that it could be quite daunting if you hadn’t done it before.

I decided to modify the script to automate the download and deployment of the CQM (v1.5) tools and extract to c:\temp\cqm (a configurable variable in the script) before then running the rest of the script to gather data.

I also added the option to run the script with a switch parameter “ThisMonthToDate” which allows you to gather data for this calendar month (from the 1st until today) – the default is to gather data for the previous calendar month.

Hope this helps you give your customers insight into the performance of their SfB stack.

Script below:

[CmdletBinding()]
Param (
[Parameter(Mandatory=$False,Position=0)]
[switch]$ThisMonthToDate
)

if($ThisMonthToDate){
Write-Host “Retrieving CQM Data for this month to date:” -ForegroundColor Yellow;
$thisMonth = (get-date)

$startdate = get-date -year $thisMonth.Year -month $thisMonth.Month -day 1
$enddate = $(Get-Date).adddays(-1)

}else{
Write-Host “Retrieving CQM Data for previous calendar month:” -ForegroundColor Yellow;
$lastMonth = (get-date).AddMonths(-1)
$startdate = get-date -year $lastMonth.Year -month $lastMonth.Month -day 1
$enddate = ($startdate.AddMonths(1)).AddDays(-1)
}

 

$cqmdownloadurl = “http://download.microsoft.com/download/4/3/2/43252959-AA20-4C3C-819D-55A64F49EFB3/Microsoft%20Call%20Quality%20Methodology.zip&#8221;
$cqmextractlocation = “c:\temp”
$cqmpath = “$cqmextractlocation\cqm”
$cqmdatapath = “$cqmpath\Data”

if(-not(test-path $cqmextractlocation)){New-Item -Path $cqmextractlocation -ItemType Directory;}
if(-not(test-path $cqmpath)){New-Item -Path $cqmpath -ItemType Directory;}
if(-not(test-path $cqmdatapath)){New-Item -Path $cqmdatapath -ItemType Directory;}

(New-Object Net.WebClient).DownloadFile($cqmdownloadurl,”$cqmextractlocation\cqm15.zip”);
(new-object -com shell.application).namespace(“$cqmextractlocation\CQM”).CopyHere((new-object -com shell.application).namespace(“$cqmextractlocation\cqm15.zip”).Items(),16)

function GetSQLDateFormat($QoECdrInstance){

#Defined Connection String
$connstring = “server=$QoECdrInstance;trusted_connection=true;”

#Define SQL Command
$command = New-Object System.Data.SqlClient.SqlCommand
$command.CommandText = “SELECT date_format FROM sys.dm_exec_sessions WHERE session_id = @@spid”
$command.CommandTimeout = 3600

#Make the connection to Server
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connstring
$connection.Open()
$command.Connection = $connection

#Get the results
$sqladapter = New-Object System.Data.SqlClient.SqlDataAdapter
$sqladapter.SelectCommand = $command
$results = New-Object System.Data.Dataset
$recordcount=$sqladapter.Fill($results)

#Close the connection
$connection.Close()

$dateformat = $results.Tables[0].Rows[0].date_format

if ($dateformat -eq “mdy”) {
return “MM/dd/yyyy”
}
if ($dateformat -eq “dmy”) {
return “Use date format dd/MM/yyyy”
}
if ($dateformat -eq “ymd”) {
return “Use date format yyyy/MM/dd”
}
if ($dateformat -eq “ydm”) {
return “Use date format yyyy/dd/MM”
}
if ($dateformat -eq “myd”) {
return “Use date format MM/yyyy/dd”
}
if ($dateformat -eq “dym”) {
return “Use date format dd/yyyy/MM”
}
}

$MonSQLServer = get-csservice| where {$_.Identity -match “monitoring”} | select poolfqdn, sqlinstancename
if($($monsqlserver.sqlinstancename).length -gt 0){
$MonSQLInstance = “$($monsqlserver.poolfqdn)\$($monsqlserver.sqlinstancename)”
}else{
$MonSQLInstance = “$($monsqlserver.poolfqdn)”
}

cls

$dateformat = GetSQLDateFormat $MonSQLInstance

Write-Host “Using date format of: $($dateformat)” -ForegroundColor Green
$startdatestring = $startdate.ToString($dateformat)
$enddatestring = $enddate.ToString($dateformat)

 

Write-Host(“Running CQM Report from $startdatestring until $enddatestring”)
cd $cqmpath

Invoke-Expression “$cqmpath\CQM.ps1 -StartTime $startdatestring -EndTime $enddatestring -QoECdrInstance $MonSQLInstance -QoECdrVersion SfB2015 -DataRoot $cqmdatapath”

Reporting on used and available DDIs with Skype for Business

One of the questions that often gets raised is how to manage DDIs, free and allocated, within a Skype for Business environment. There are numerous tools out there that give you a listing of what has been assigned and with the use of Get-CsUnassignedNumber we can find out what out number ranges are (assuming this has been set up, of course (if it hasn’t, I recommend you do 🙂 ))

I’ve had this little snippet in the back of my head for a while, and I’ve finally been able to sit down and write it up. And…. I LIKE IT!

A couple of prerequisites for this script:

  1. You must have Unassigned Number Ranges configured and the numbers must be in E.164 format (i.e. “tel:+641234567”)
  2. The script outputs to c:\temp by default. If you don’t change that, you will need the c:\temp path to exist.

Hope you find it as useful as I think it will be.

$ReplaceValue = “tel:+”;
$UnassignedDDIs = @()
$table = New-Object system.Data.DataTable “NumberAssignments”;
#Define Columns
$col1 = New-Object system.Data.DataColumn “SipAddress”,([string])
$col2 = New-Object system.Data.DataColumn “LineURI”,([string])
$col3 = New-Object system.Data.DataColumn “Number”,([string])
$col4 = New-Object system.Data.DataColumn “Extension”,([string])
$col5 = New-Object system.Data.DataColumn “DisplayName”,([string])
$col6 = New-Object system.Data.DataColumn “RegistrarPool”,([string])
$col7 = New-Object system.Data.DataColumn “UsedFor”,([string])
$col8 = New-Object system.Data.DataColumn “DialPlan”,([string])
$col9 = New-Object system.Data.DataColumn “ClientPolicy”,([string])
$col10 = New-Object system.Data.DataColumn “VoicePolicy”,([string])
$col11 = New-Object system.Data.DataColumn “ExternalAccessPolicy”,([string])
$col12 = New-Object system.Data.DataColumn “ConferencingPolicy”,([string])

#Add the Columns
$table.columns.add($col1)
$table.columns.add($col2)
$table.columns.add($col3)
$table.columns.add($col4)
$table.columns.add($col5)
$table.columns.add($col6)
$table.columns.add($col7)
$table.columns.add($col8)
$table.columns.add($col9)
$table.columns.add($col10)
$table.columns.add($col11)
$table.columns.add($col12)

function AddNumber($SipAddress, $LineURI, $Number, $Extension, $DisplayName, $RegistrarPool, $UsedFor, $DialPlan, $ClientPolicy, $VoicePolicy, $ExternalAccessPolicy, $ConferencingPolicy){

#Create a row
$row = $table.NewRow()

#Enter data in the row
$row.SipAddress = $SipAddress
$row.LineURI = $LineURI
$row.Number = $Number
$row.Extension = $Extension
$row.DisplayName = $DisplayName
$row.RegistrarPool = $RegistrarPool
$row.UsedFor = $UsedFor
$row.DialPlan = $DialPlan
$row.ClientPolicy = $ClientPolicy
$row.VoicePolicy = $VoicePolicy
$row.ExternalAccessPolicy = $ExternalAccessPolicy
$row.ConferencingPolicy = $ConferencingPolicy

#Add the row to the table
$table.Rows.Add($row)

}

 

if((Get-CsUnassignedNumber) -eq $Null){
Write-Host “You do not have any Unassigned Numbers defined”
Write-Host
Write-Host “Go to this TechNet article to see how-to:”
Write-Host “http://technet.microsoft.com/en-us/library/gg412748.aspx&#8221;
Write-Host
Write-Host “Also see how to configure the announcement service:”
Write-Host “http://technet.microsoft.com/en-us/library/gg412783.aspx&#8221;
Write-Host
[System.Console]::ForegroundColor = [System.ConsoleColor]::Gray

}
else {$UnassignedNumRanges=(Get-CsUnassignedNumber)}

foreach($UnassignedNumRange in $UnassignedNumRanges){
#Check to see if Unassigned Numbers are in E.164 format, if its not, continue to the next number serie
if ($UnassignedNumRange.NumberRangeStart.Substring(0,5).ToLower() -ne “tel:+” -and $UnassignedNumRange.NumberRangeEnd.Substring(0,5).ToLower() -ne “tel:+”){
Write-Host “The script requires that Unassigned Numbers are populated in E.164 format” -Foregroundcolor Yellow
Write-Host “It appears that the number range ” -nonewline
Write-Host $UnassignedNumRange.Identity -nonewline -Foregroundcolor Green
Write-Host ” is not in this format”
Write-Host
Continue
}
else{
$NumberStart=$UnassignedNumRange.NumberRangeStart | ForEach-Object {$_.Replace($ReplaceValue, “”)}
$NumberEnd=$UnassignedNumRange.NumberRangeEnd | ForEach-Object {$_.Replace($ReplaceValue, “”)}

#Convert the range to a Int64 to be able to manager numbers with more than 10 digits
$NumberStartInt64=[System.Convert]::ToInt64($NumberStart)
$NumberEndInt64=[System.Convert]::ToInt64($NumberEnd)

$i = $numberstartint64
Do {$UnassignedDDIs += $i; $i +=1 } While ($i -le $NumberEndInt64)

}

 

}

$UnassignedDDIs = $UnassignedDDIs | Get-Unique | sort

#Get Assigned Numbers
$AssignedDDIs = @()
$AssignedDDIs += get-csuser | where {-not($_.lineuri -eq “”)} |sort DisplayName | select SipAddress, LineUri, @{e={$($_.LineUri.Split(“;”)[0].Replace(“tel:+”, “”))}; l=”Number”}, @{e={$($_.LineUri.Split(“;”)[1].Replace(“ext=”, “”))}; l=”Extension”}, DisplayName, RegistrarPool, @{e={“User”}; l=”UsedFor”}, DialPlan, ClientPolicy, VoicePolicy, ExternalAccessPolicy, ConferencingPolicy
$AssignedDDIs += Get-CsCommonAreaPhone | where {-not($_.lineuri -eq “”)} |sort DisplayName | select SipAddress, LineUri, @{e={$($_.LineUri.Split(“;”)[0].Replace(“tel:+”, “”))}; l=”Number”}, @{e={$($_.LineUri.Split(“;”)[1].Replace(“ext=”, “”))}; l=”Extension”}, DisplayName, RegistrarPool, @{e={“Common Area Phone”}; l=”UsedFor”}, DialPlan, ClientPolicy, VoicePolicy, ExternalAccessPolicy, ConferencingPolicy
$AssignedDDIs += Get-CsRgsWorkflow | where {-not($_.lineuri -eq “”)} |sort DisplayName | select SipAddress, LineUri, @{e={$($_.LineUri.Split(“;”)[0].Replace(“tel:+”, “”))}; l=”Number”}, @{e={$($_.LineUri.Split(“;”)[1].Replace(“ext=”, “”))}; l=”Extension”}, @{e={$_.Name}; l=”DisplayName”}, @{e={$_.OwnerPool}; l=”RegistrarPool”}, @{e={“Response Group”}; l=”UsedFor”}, DialPlan, ClientPolicy, VoicePolicy, ExternalAccessPolicy, ConferencingPolicy
$AssignedDDIs += Get-CsExUmContact | where {-not($_.lineuri -eq “”)} |sort DisplayName | select SipAddress, LineUri, @{e={$($_.LineUri.Split(“;”)[0].Replace(“tel:+”, “”))}; l=”Number”}, @{e={$($_.LineUri.Split(“;”)[1].Replace(“ext=”, “”))}; l=”Extension”}, DisplayName, RegistrarPool, @{e={“Exchange UM Contact”}; l=”UsedFor”}, DialPlan, ClientPolicy, VoicePolicy, ExternalAccessPolicy, ConferencingPolicy
$AssignedDDIs += Get-CsDialInConferencingAccessNumber | where {-not($_.lineuri -eq “”)} |sort DisplayName | select SipAddress, LineUri, @{e={$($_.LineUri.Split(“;”)[0].Replace(“tel:+”, “”))}; l=”Number”}, @{e={$($_.LineUri.Split(“;”)[1].Replace(“ext=”, “”))}; l=”Extension”}, DisplayName, @{e={$_.Pool}; l=”RegistrarPool”}, @{e={“Dial In Conferencing”}; l=”UsedFor”}, DialPlan, ClientPolicy, VoicePolicy, ExternalAccessPolicy, ConferencingPolicy

 

foreach($num in $UnassignedDDIs){
$numinuse = $AssignedDDIs | where {$_.Number -eq $num}
if($numinuse){
AddNumber $numinuse.SipAddress $numinuse.LineURI $numinuse.Number $numinuse.Extension $numinuse.DisplayName $numinuse.RegistrarPool $numinuse.UsedFor $numinuse.DialPlan $numinuse.ClientPolicy $numinuse.VoicePolicy $numinuse.ExternalAccessPolicy $numinuse.ConferencingPolicy $numinuse.ExternalAccessPolicy $numinuse.ConferencingPolicy
}else{
AddNumber “” “tel:+$num” $num
}
}

$table | export-csv c:\temp\DDIAssignmentTable.csv -NoTypeInformation