Friday, January 11, 2019

Create a Microsoft Teams Group Calendar tab application using the Graph API and FullCalendar JavaScript library

Group calendars have always been one of the big asks for in any group collaboration programs back from Lotus Notes to Microsoft Exchange and now Microsoft Teams. There are a few ways of getting a Group calendar working in Teams, one is hosting the OWA web apps see or some other people advocate using a SharePoint calendar and hosting that similarly.

Here is a different method you can use by taking advantage of being able to call the Graph API in a  Tab application.The getSchedule Graph action (still currently in beta) allows you to query up to 62 days of Freebusy information on up to 100 calendars in a single call this makes it a good option for this type of application. So as long as users can view each others calendars or have detailed freebusy permissions the action should return the level of detail required for a Group calendar.   The other thing you can do with the Graph API is get the users photo and build a nice legend for the Group calendar also. To make this visually appealing you need a good calendar display library which there has been a few over the years but a recent one that is really nice is FullCalendar https://fullcalendar.io/ . It ticks all the boxes it looks great, its easy to use and its free to use. To make the calendar appointments from graph appear in the calendar is as easy as building and array from the return JSON from the graph and throwing in a little random color code to break this up and then stitching in the user photos as they are returned asynchronously from the server to build the legend.


 Here are some screenshots of the Tab in action using Graph data




    Daily view


Weekly view


List view


I've put together a separate GitHub repository for all the code that is required for this app https://github.com/gscales/TeamsGroupCalendar and put some detailed install instruction in the Readme in Github.

I'm currently looking for work either contract or fulltime so if you need a creative developer with lots of energy to write C#,JS, NodeJS, Azure or Lambda functions, Messaging DevOps or PowerShell scripts then please contact me  at gscales@msgdevelop.com

Tuesday, January 08, 2019

Converting Folder and ItemIds from the Exchange Management Shell and Audit Log entries using PowerShell and the Graph API in Exchange Online

First a little news about Exchange Identifiers that you may have missed (its not often that something like this changes so its rather exciting)

When you access an item in an Exchange Mailbox store whether its OnPrem or in the Cloud you use the Identifier of the particular item which will vary across whatever API your using. Eg

MAPI - PR_EntryId eg NameSpace.GetItemFromID(EntryId)
EWS -  EWSId eg EmailMessage.Bind(service,ewsid)
Rest -   RestId  eg https://graph.microsoft.com/v1.0/me/messages('restid')
The advice over the years has always been its not a good idea to store these Id's in something like a database because they change whenever and Item is moved. Eg if an Item is moved from the Inbox to a Subfolder in the Inbox it will received a different Id so whatever you have stored in your database suddenly becomes invalid and its not easy to reconcile this. However a new feature that has appeared in Exchange Online in Beta with the Graph API is immutableId's see https://docs.microsoft.com/en-us/graph/outlook-immutable-id the idea behind this is that this Id doesn't change regardless of which folder the item is moved to (or even if its deleted). While it still in Beta at the moment this is a good feature to use going forward if your building synchronization code. Along with immutableId's an operation to Translate Id's between the EntryId, EWS and REST formats is now available in beta in the Graph which is great if your looking to Migrate your MAPI or EWS apps to use the Graph API https://github.com/microsoftgraph/microsoft-graph-docs/blob/master/api-reference/beta/api/user-translateexchangeids.md 

As Audit records are a hot topic of discussion this week with this post from Microsoft another Identifier format you see when using the Exchange Management Shell cmdlets like Get-MailboxFolderStatics is something like



or in an ItemId in a  AuditLog Record like



With these Id's there are just a base64 encoded version of the EntrydId with a leading and trailing byte. So to get back to the Hex version of the Entryid you might be familiar with from a Mapi Editor you can use something like the following



$HexEntryId = [System.BitConverter]::ToString([Convert]::FromBase64String($_.FolderId.ToString())).Replace("-","").Substring(2)  
$HexEntryId =  $HexEntryId.SubString(0,($HexEntryId.Length-2))

This would turn something like

RgAAAAC+HN09lgYnSJDz3kt9375JBwB1EEf9GOowTZ1AsUKLrCDQAAAAAAENAAB1EEf9GOowTZ1AsUKLrCDQAALbJe1qAAAP

Into

00000000BE1CDD3D9606274890F3DE4B7DDFBE490700751047FD18EA304D9D40B1428BAC20D000000000010D0000751047FD18EA304D9D40B1428BAC20D00002DB25ED6A0000

Just having the Id in whatever format isn't much good unless you can do something with it, so I've created a simple Graph script that uses the new user-translateexchangeids.md operation to allow you to translate this Id into an Id that would be useable in other Graph requests. I've create a basic ADAL script version an posted it here on my GitHub https://github.com/gscales/Powershell-Scripts/blob/master/translateEI.ps1

A quick Demo of it in use eg Translate a RestId into an EntryId


Invoke-TranslateExchangeIds -SourceId "AQMkADczNDE4YWE..." -SourceFormat restid -TargetFormat entryid
By default the operation returns a urlsafe base64 encoded results (with padding) so in the script I decode this to the HexEntryId which I find the most useful.

I've also cater for allowing you to post a HexEntryId and the script will automatically encode that for the operations eg


Invoke-TranslateExchangeIds -SourceHexId "00000000BE1CDD3D9606274890F3DE4B7DDFBE49..." -SourceFormat entryid -TargetFormat restid
And it also caters for the encoded EMS format and will strip the extra bytes and covert that eg

Invoke-TranslateExchangeIds -SourceEMSId  $_.FolderId.ToString() -SourceFormat entryid -TargetFormat restid
I've also added this to my Exch-Rest module which is available from the PowerShell Gallery and GitHub which is useful if you want to do some following type things. eg if you wanted to bind to the folder in question you could use


$folderId = Invoke-EXRTranslateExchangeIds -SourceEMSId  $_.FolderId.ToString() -SourceFormat entryid -TargetFormat restid
Get-EXRFolderFromId -FolderId $folderId
Need help with anything I've talked about in this post or need somebody to write C#,JS, NodeJS, Azure or Lambda functions, Messaging DevOps or PowerShell scripts then I'm available now for freelance/contract or fulltime work so please drop me an Email at gscales@msgdevelop.com

Friday, January 04, 2019

Using the Skype for Business UCWA API in a Microsoft Teams Tab application to show the Skype Conversation history

One of the things you maybe considering in the new year is migrating from Skype for Business to Microsoft Teams. In this post I'm going to demonstrate how you can use the UCWA api (which is the REST API you can use to talk to a Skype for Business server either in Office365 or OnPrem) to access Skype for Business from within the Teams Client via a Teams Tab application. (For those unacquainted with UCWA this the API that is used to Access Skype within OWA).
Why would you want to do this ? its one way of easing migration friction by providing a different level of interoperability (outside of using both clients) and also a way of adding functionality into the Teams client that isn't there currently.  In this post I'm going to look at showing the users Skype conversation history, while this information is also stored in a users Mailbox and also accessible via the Graph API, in this app I'm going to use the UCWA API to access the conversation logs via the Skype for Business Online servers and also the conversation transcripts. What you end up with is a Teams  tab that looks like the following



and the Transcripts like (this is POC so mind the formatting)



Using UCWA from a Teams Tab Application

There isn't much difference between using the UCWA API in a Teams Tab application then  from using it in any other application, however UCWA does present some challenges around authentication because of the way the discovery process works.  For a quick recap for those unacquainted please read https://docs.microsoft.com/en-us/skype-sdk/ucwa/developingucwaapplicationsforsfbonline . As part of that process you need to get an AccessToken to make a discovery request to find the SK4B pool server to use and then get another AccessToken for the pool server. So when using the Teams Tab Silent authentication flow you need to execute this twice (which is different and more time consuming then say a normal Graph type application)

Getting the Conversation History in UCWA

Once you have logged into UCWA you need to configured the session to enabled the conversation history as its disabled by default.  This involves doing a Put request against the application resource. with the if/match header set to the ETag. You then need to acknowledge the event this will generate and once that is done your UCWA session will be ready to go, you then just need to query the communication resource to get the links required to access the ConversationLogs from the server. In the sample app I'm only accessing the last 50 items from the server as this is only a POC anyway. When it comes to access the conversation transcripts this requires a Batch request to make it efficient (the max batch size in SK4B in 100) so using a page size of 50 keeps this all working okay. A brief overview of the requests required to access the Conversation history.

  • 1 Get request to get the Conversation Logs which is a list with a link to each of the Conversation Entries
  • Batch Get Request for each of the Conversation Entries which gives back a detail history of each conversation (minus the actual Transcript of the conversation but you do get limited Message preview).
  • If you want the full conversation transcript you use the link from the conversation history to access the Transcript. (in the sample when you click the transcript Cell in the Table it makes this request to the SK4B server to get the Transcript and presents that in a separate Div on the page),
Installing and using this Tab Application 

Like any Teams Tab application it must be hosted somewhere, I'm hosting it out of my GitHub site so the configuration file located in https://github.com/gscales/gscales.github.io/blob/master/TeamsUCWA/app/Config/appconfig.js has the following configuration to ensure it point to the hosted location

const getConfig = () => {
   var config = {
        clientId : "eed5c282-249f-46f3-9e18-bde1d0091716",
        redirectUri : "/TeamsUCWA/app/silent-end.html",
        authwindow :  "/TeamsUCWA/app/auth.html",
 hostRoot: "https://gscales.github.io",
   };
   return config;
}

Also the manifest file https://github.com/gscales/gscales.github.io/blob/master/TeamsUCWA/TabPackage/manifest.json  has setting that point to hosted that need to be changed if its hosted elsewhere (just search and replace gscales.github.io)

Application Registration 

To use the UCWA API you need to create an application registration with the following oAuth grants



the applicationId for this registration should then be used to replace the clientid in the appconfig.js . The application registration should use the silent-end.html page as the redirect for authentication. Then the last thing you need to do is make sure that the ApplicationId has been consented to in your Organization eg 


https://login.microsoftonline.com/common/adminconsent?client_id=08401c36-6179-4bbe-9bcc-d34ff51d828f
  
Side Loading - To use custom tab applications you first need to enable side loading of Apps in the Office365 Admin portal ref .The important part is  "Sideloading is how you add an app to Teams by uploading a zip file directly to a team. Sideloading lets you test an app as it's being developed. It also lets you build an app for internal use only and share it with your team without submitting it to the Teams app catalog in the Office Store. "

As this is a custom application you need to use the "upload a custom app" link which is available when you click ManageTeam-Apps tab see

(Note if you don't see  the "upload a custom app" check that you have side loading of apps enabled in your tenant config)

What you upload here is a Zip file containing your manifest file and two images that you manifest refers to for eg
{
   "icons": {
    "outline": "Outline32.png",
    "color": "Colour192.png"
  },

For this sample this is located in https://github.com/gscales/gscales.github.io/blob/master/TeamsUCWA/TabPackage/manifest.json

All the code for this post is located in GitHub https://github.com/gscales/gscales.github.io/tree/master/TeamsUCWA

Need help with anything I've talked about in this post or need somebody to write C#,JS, NodeJS, Azure or Lambda functions or PowerShell scripts then I'm available now for freelance/contract or fulltime work so drop me an Email at gscales@msgdevelop.com