Modality Systems CustomInvite tool AD/GPO deployment an (almost) step by step

Working for Modality Systems has been a blast for the last 18 months and for the last few I was helping to look after internal IT while we recruited for a new IT Manager (Welcome Dan!) PS - we're always on the look out for top talent to join us.

One of the reasons that we are Partner of Year (Communications) is our vibrant dev team who have publically released some brilliant tools over the years such as SuperToast (which I was pushing back in 2012!!), and the Business Applications suite. This is alongside the tons of custom development work that they do for customers (I'd love to blog about this but our Dev MVP Tom Morgan will have beaten me to it!).

Our newest public release is CustomInvite. This is not a post about how good the software is (it is very cool), instead this is about how I deploy versions to staff machines so we can dogfood drink the champagne of our award winning tool.

As yet we are not using System Centre Configuration Manager to deploy software through the Modality estate so I had to go back to good old system startup scripts (advantage - FREE!). Our users have domain joined machines in the main with Direct Access back to the corp network so this method would work for the majority of users. We have a mixed estate of both Office 2013 and 2016 and a mixed "bitness" of Office of both 32 and 64 bit. Most third party addins like CustomInvite are only designed for 32 bit Office but our dev team have made sure 64 bit is treated like a first class citizen too!

First part of the deployment is to get the files into AD. We have 4 files that come from CustomInvite and then another two files that we are going to create manually.

The first two files to deploy are the GroupPolicy Template files that need do be dropped onto a domain controller:

File Location
CustomInvite.admx C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions
CustomInvite.adml C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions\en-US

Now we have these files in AD (wait for replication) its time to setup your policy for your templates. The pre-requisites for this is that you have your RTF templates stored on a UNC share somewhere (or you know where that will be). Now you can create a Group Policy Object like so:

  1. The name of the default template that CustomInvite should load
  2. Your license code
  3. How often CustomInvite should look for new templates in.....
  4. ......this UNC location
Note that this is a Computer Configuration and that the User Configuration is disabled.

Next part is to create the GPO that installs CustomInvite. I separate this out into a second GPO so that I can have multiple versions of the GPO to target different teams with different installs.

This GPO simply has a Computer Startup Script that does the actual install:

  1. The script file that will run
  2. Forcing the PC to wait for the network (otherwise the script may not be found).
Note that this is a Computer Configuration and that the User Configuration is again disabled.

Note that the script is a simple batch file and the run time for a PC connected over home broadband is about ~5 seconds:

The contents to the batch file is as follows:


REM --------------------------------------------------------------------------------------------------------------------
REM  Installs CustomInvite
REM --------------------------------------------------------------------------------------------------------------------

REM --------------------------------------------------------------------------------------------------------------------
REM  Changelog
REM 20170130 - DLL looked for changed from "Modality.LyncAppointmentAddin.dll" to "Modality.CustomInvite.dll"
REM 20170207 - Added in variable names to make future updates easier
REM --------------------------------------------------------------------------------------------------------------------

REM --------------------------------------------------------------------------------------------------------------------
REM  How to use
REM  Ensure you have the two install files in the same directory as this script file.
REM  Install files need to have the name "CustomInvite_Outlookx##_?.??.msi"
REM  Where "#" is the bitness of the version file (86 or 64)
REM  and ?.?? is the version number.
REM  Once you have these then you can amend the variables below

REM --------------------------------------------------------------------------------------------------------------------
REM  Variables

Set _CustomInviteVersion=2.20
Set _32BitCustomInviteVersion=2.20.6247.28084
Set _64BitCustomInviteVersion=2.20.6247.28179
Set _OUFolderName={C0B66EA0-1F62-4977-A716-8AAEE5996CF8}

REM --------------------------------------------------------------------------------------------------------------------
REM   Seriously - here be dragons!
REM --------------------------------------------------------------------------------------------------------------------

SET WMICCommand="WMIC Path CIM_DataFile WHERE Name='C:\\Program Files (x86)\\Modality Systems\\CustomInvite\\Modality.CustomInvite.dll' Get Version"
FOR /F "skip=1" %%X IN ('%WMICCommand%') DO (
IF %%X == %_32BitCustomInviteVersion% GOTO :foundCustomInviteX86

SET WMICCommand="WMIC Path CIM_DataFile WHERE Name='C:\\Program Files\\Modality Systems\\CustomInvite\\Modality.CustomInvite.dll' Get Version"
FOR /F "skip=1" %%X IN ('%WMICCommand%') DO (
IF %%X == %_64BitCustomInviteVersion% GOTO :foundCustomInviteX64
echo %date% %time% - WARN - CustomInvite %_CustomInviteVersion% NOT found on %computername% >> \\mk-dc-01\SoftwareDistribution\CustomInvite\log\Install.txt

REM --------------------------------------------------------------------------------------------------------------------
REM  Check Registry for Outlook Bitness
REM --------------------------------------------------------------------------------------------------------------------

FOR /F "TOKENS=3 SKIP=2" %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\Software\Microsoft\Office\ClickToRun\Configuration" /v Platform') DO (SET BN_VALUE=%%A)
if %BN_VALUE% EQU x64 goto x64CTR
if %BN_VALUE% EQU x86 goto x86CTR

FOR /F "TOKENS=3 SKIP=2" %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\Software\Microsoft\Office\16.0\Outlook" /v Bitness') DO (SET BN_VALUE=%%A)
if %BN_VALUE% EQU x64 goto x64Office2016
if %BN_VALUE% EQU x86 goto x86Office2016

FOR /F "TOKENS=3 SKIP=2" %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\Software\Microsoft\Office\15.0\Outlook" /v Bitness') DO (SET BN_VALUE=%%A)
if %BN_VALUE% EQU x64 goto x64Office2013
if %BN_VALUE% EQU x86 goto x86Office2013

if %BN_VALUE% EQU "?" goto OutlookNotFound

REM --------------------------------------------------------------------------------------------------------------------
REM  Log Outlook Bitness
REM --------------------------------------------------------------------------------------------------------------------

echo %date% %time% - INFO - Office ClickToRun x86 found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto InstallX86

echo %date% %time% - INFO - Office ClickToRun x64 found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto InstallX64

echo %date% %time% - INFO - Office 2016 x86 found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto InstallX86

echo %date% %time% - INFO - Office 2016 x64 found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto InstallX64

echo %date% %time% - INFO - Office 2013 x86 found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto InstallX86

echo %date% %time% - INFO - Office 2013 x64 found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto InstallX64

REM --------------------------------------------------------------------------------------------------------------------
REM  Install X86 Version
REM --------------------------------------------------------------------------------------------------------------------

Echo %date% %time% - INFO - Attempting install of CustomInvite %_CustomInviteVersion% x86 on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
MD c:\ModalityCustomInvite
CD c:\ModalityCustomInvite
Copy \\DOMAINNAME\SysVol\DOMAINNAME\Policies\%_OUFolderName%\Machine\Scripts\Startup\CustomInvite_Outlookx86_%_CustomInviteVersion%.msi c:\ModalityCustomInvite
MSIEXEC /passive /i CustomInvite_Outlookx86_%_CustomInviteVersion%.msi 
del CustomInvite_Outlookx86_%_CustomInviteVersion%.msi
SET WMICCommand="WMIC Path CIM_DataFile WHERE Name='C:\\Program Files (x86)\\Modality Systems\\CustomInvite\\Modality.CustomInvite.dll' Get Version"
FOR /F "skip=1" %%X IN ('%WMICCommand%') DO (
IF %%X == %_32BitCustomInviteVersion% GOTO :InstalledCustomInviteX86 
Echo %date% %time% - FAIL - CustomInvite %_CustomInviteVersion% x86 Failed to install on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto End

REM --------------------------------------------------------------------------------------------------------------------
REM  Install X64 Version
REM --------------------------------------------------------------------------------------------------------------------

Echo %date% %time% - INFO - Attempting install of CustomInvite %_CustomInviteVersion% x64 on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
MD c:\ModalityCustomInvite
CD c:\ModalityCustomInvite
Copy \\DOMAINNAME\SysVol\DOMAINNAME\Policies\%_OUFolderName%\Machine\Scripts\Startup\CustomInvite_Outlookx64_%_CustomInviteVersion%.msi c:\ModalityCustomInvite
MSIEXEC /passive /i CustomInvite_Outlookx64_%_CustomInviteVersion%.msi 
del CustomInvite_Outlookx64_%_CustomInviteVersion%.msi
SET WMICCommand="WMIC Path CIM_DataFile WHERE Name='C:\\Program Files\\Modality Systems\\CustomInvite\\Modality.CustomInvite.dll' Get Version"
FOR /F "skip=1" %%X IN ('%WMICCommand%') DO (
IF %%X == %_64BitCustomInviteVersion% GOTO :InstalledCustomInviteX64
Echo %date% %time% - FAIL - CustomInvite %_CustomInviteVersion% x64 Failed to install on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto End

REM --------------------------------------------------------------------------------------------------------------------
REM  Found Correct Custom Invite x86 Version
REM --------------------------------------------------------------------------------------------------------------------
echo %date% %time% - INFO - CustomInvite %_CustomInviteVersion% x86 found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto end

REM --------------------------------------------------------------------------------------------------------------------
REM  Found Correct Custom Invite x64 Version
REM --------------------------------------------------------------------------------------------------------------------
echo %date% %time% - INFO - CustomInvite %_CustomInviteVersion% x64 found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto end

REM --------------------------------------------------------------------------------------------------------------------
REM  Installed Correct Custom Invite X86 Version
REM --------------------------------------------------------------------------------------------------------------------
echo %date% %time% - GOOD - CustomInvite %_CustomInviteVersion% X86 Installed on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto end

REM --------------------------------------------------------------------------------------------------------------------
REM  Installed Correct Custom Invite X64 Version
REM --------------------------------------------------------------------------------------------------------------------
echo %date% %time% - GOOD - CustomInvite %_CustomInviteVersion% X64 Installed on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto end

REM --------------------------------------------------------------------------------------------------------------------
REM  Outlook not found
REM --------------------------------------------------------------------------------------------------------------------
echo %date% %time% - FAIL - Outlook not found on %computername% >> \\SERVERNAME\SoftwareDistribution\CustomInvite\log\Install.txt
goto end

REM --------------------------------------------------------------------------------------------------------------------
REM  Finish
REM --------------------------------------------------------------------------------------------------------------------


NOTE: Even thought the script says "SHOULDN'T NEED TO AMEND ANYTHING PAST THIS LINE" you'll need to change "DOMAINNAME" to your domain name and "SERVERNAME" to the server name where the log file is going to be written too.

In essence the script does the following:

  1. Sets some variables for the version of CustomInvite we are installing
  2. Checks to see if that version is installed (first 32 then 64 bit) - if found > LOG > END
  3. Checks the bitness of the installed version of Outlook > LOG (if not found LOG > END)
  4. Installs (or updates) the correct bitness of CustomInvite and tests if installed > LOG (if install fails LOG > END)

In future when a new version of CustomInvite is released you can simply update this one script file or copy the GPO and create a new version for each install (that's the "Variables" bit in the script!)

A copy of the script file is hosted here too.

Once you have amended the file to fit your environment and downloaded the files you should end up with a Group Policy Object folder that looks like the following:

You'll also need a network share that has READ/WRITE access for the log file to be written too:

Hopefully this is enough to help you get up and running with CustomInvite. If you would like some adhoc support on this process please comment and I'll do my best to reply :-)

18 Months at Modality Systems

Wow, time does fly when you are having fun, I’ve now been at the multi-award winning Modality Systems for 18 months after a flippant tweet:

landed me a job interview.

And that’s the thing. There is no way I would ever have applied to work here, these guys are the Lync Skype for Business rockstars!

Tom A, Ben Lee, Tom Morgan, Justin Morris, etc etc

why would little ol’ me working for a housing association with my limited experience of Gateways and Contact Centres ever get considered for a job there?

It turns out that the main reason is attitude. I fit into the organisation as someone who champions (what I think) is the second best bit of software Microsoft produce - first for me is the killer combination of Exchange and Outlook – that tool runs my life - anyway, back on topic:

I love to learn about features, bugs, and finding things out about the underlying fabric (geek joke). And as my long suffering wife will attest, I’m usually reading Twitter and catching up on blogs most evenings (“put that phone away and watch the film” – Valentines 2015).

So what am I trying to say here?

In short – we're always on the lookout for new faces and we’ve got some jobs going here right now:

If you have experience with voice in Lync or Skype for Business (or even if you don't!) please throw your hat into the ring. Even if you think your experience with that Sonus and a single Front End its not going to be enough. Even if you think why would we need someone who only supports 50 people but you are excited for the technology. YOU are that person we are looking for. We can teach all the other stuff, but attitude and the eagerness to learn is what we prize here.

So what does Modality Systems offer in return?

Good salary, pension, healthcare. Cracking team events. Top notch Summer and Christmas parties.

Check out Glassdoor for some reviews of us. Staff turnover is very low so we must be doing something right. :-)

You can't join a meeting from outside Lync 2013, Lync 2010, or Skype for Business on iOS

Every time Apple updates the IOS operating system it appears to break the meeting join functionality for the Lync/Skype for Business app. I'm tracking here when the Server CU comes out that fixes this, when and with what CU:

Last updated: 17th November 2016

Version KB Skype for Business 2015 Lync 2013 Lync 2010
IOS 10
3204849 - Nov 2016
3204546 - Nov 2016
IOS 9.2 - 9.x

IOS 9.0 - 9.1

CloudPBX Voicemail Play on Phone strangeness....

A little quirk that has been thrown up as we've been moving more of our internal staff to "THE CLOUD" is that voicemail playback seems inconsistent in its delivery.


Voicemail left for me. I can see it in my Outlook inbox:

And its showing up as an MP3 attachment in IOS:

I decide that I want to listen to the voicemail discreetly as it may contain sensitive content so instead of just pressing the play button so that it comes out of my speakers I press the Play on Phone in the Outlook message.....

Outlook asks where I want to play the message, I leave this as the default as I want it to ring my SfB client.....

Call connects and I get "End of message, press 1 to replay message" In an British accent. Strange I think, maybe the call didn't connect in time. So I press 1 on the keypad and the ever helpful Microsoft lady again says "End of message, press 1 to replay message" Its almost like she can't deal with the encoding of the file.

After hanging up I confirm I can listen to the message on both the play icon in Outlook and the MP3 file on the iPhone. Both succeed.

Moving over the Sfb Client (Office 2016 MSI), I can see the voicemail and pressing the play icon plays the voicemail locally via my default communication device - result, the whole office hasn't heard that message.

At this stage I think it must be a problem with Office365 not being able to deal with the message.

For fun I then try via Call Voice Mail feature in the client expecting it to not work....

But it does..... Announced by a nice American accented lady.....


I then move back to the Play on Phone and notice that all of the voice prompts are in British English. At this point I'm assuming that somehow using local Outlook I'm being forced via the old on-prem Exchange Server that can't handle the cloud mailbox (this assumption is 'cause of the British accent).

For fun I move over to Outlook on the Web for Business ( I remember the days of Outlook Web Access) and get that to call me, assuming that I'll have the American lady again and she'll be able to play me the message.

And the Brit starts speaking to me...... I navigate the voice tree and she says she'll play the message (telling me the time the VM arrives and also who it is from "Plus fourty four, seven seven seven five....." etc)......

.....and there's no content again . So at this point in time its like the American lady can understand the MP3 file but the British one can't - and that's probably as its an American invention:  ;-) 

I've raised a ticket with Microsoft and will update this post when I get a response.

Update: 21st November 2016

On the ongoing ticket we have confirmed that a user who is homed on-prem for SfB but on Office365 for Exchange can consistently hear the message. Still no word on why though.

Sonus SBA now with Skype for Business.

If your Sonus Survivable Branch Appliance is still sitting as a 2010 or 2013 Lync Branch Site then from today you can  grab the ASM image to move to a SFB Branch Site :-)

File is:

And you'll need to patch it to CU3 (June 2016 - 6.0.9319.259) straight away which is:


For the above you'll probably need to upgrade your licensing on the gateway by getting in touch with your local re-seller and obtaining new license keys and stickers (!)

Office 365 SfB Migration - phone weirdness

Have been moving users from on-prem Skype for Business to Office 365 over the last few weeks 

The users will be homed on Office 365 with voice breakout remaining on-prem for the moment.

After moving one user saw the following strangeness:

Usually the number will normalizes nicely to E164 format but for Jo it hadn't. When drilling down into the user account had the following message:

"The country/region codes of the online dial plan and the telephone number don't match so international calling might not work as expected"

Interestingly Jo could make and receive PSTN calls with no issue (in region, didn't try international) so it just seemed cosmetic.

On looking at the account in the on-prem SfB control panel the only difference from other users who had been moved correctly was that the Tel had an upper case "T":

I changed this to a lower case "t", forced a sync to O365 and this did not solve the problem. I'm making a stab that the sync process did not see this as a change worthy of uploading.

To fix I changed the on-prem number in the SfB Control Panel to not have the ext attribute and forced a sync:

The changed back to the correct lineuri:
After one final sync all was showing up correctly:

Need to add a shed load of contacts to Skype for Business - AutoHotKey to the rescue!

A customer had the need to add approx 200 external contacts to a single Skype for Business user where there was no access to the backend database or PowerShell.

To do this I went back in the mists of time and cracked open a copy of AutoHotKey....

.....well, I did once I disabled Windows Defender:

So now I've got it downloaded and installed lets get on with the show:

We have two files:

  • Adds.txt which contains the sipuri's of all people you want to add (these can be people in your organisation and external).
  • ContactsAdd.ahk which is the actual code.

You can download these both from my DropBox (no love for OneDrive now they have curtailed the amount of free space!), but the code is here if you want to play with it by hand.

Note that this is very rough and ready code so probably could be tidied up considerably. Usual warranties apply, test in a lab, not for production use, YMMV, don't eat yellow snow. etc. etc.

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

;start SfB/Lync
run, Lync.exe

;bring SfB to the foregroud - change this if using Lync 2010 or 2013 in "classic" mode
winwaitactive, Skype for Business 

;start a loop and open adds.txt for reading
loop, read, adds.txt
;read the first line of the file and fill a variable called A-LoopReadLine with the file
loop, parse, A_LoopReadLine, %A_Tab%
;send some tabs, spaces, down keys etc to get to "add a contact not in my organisation"
send, {Tab}{Tab}{Tab}{Tab}{Tab}{Space}{Down}{Enter}{Enter}
;send the contents of the variable to SfB
Send, %A_LoopReadLine%
;Hit enter
send, {Enter}
;Move from Contacts tab to next tab....
Send, {Control Down} 2 {control Up}
;....and back again
Send, {Control Down} 1 {control Up}
;Loops round until the end of the file