Thursday, November 30, 2017

API rant at the end of the day about Office 365 Groups, Yammer and Graph

Sometimes pressure just builds and you need to vent. This is one of those days where I’ll gripe about O365 Groups with Yammer, and about retrieving an Office 365 Group Photo.
image

Self-service of Office 365 Groups with governance and Yammer

In the perfect anarchy world of Microsoft Corp. this is all good. Everyone can create everything from anywhere. I wouldn’t say it really works for Microsoft internally as I’m sure it’s all a big mess with no structure control at all.

The rest of the world like to have some control over the self-service (which I spoke about at ESPC). This is why a typical setup is:
  • Disable Office 365 Groups creation from the default UI for all users except a few in IT
  • Enable a self-service solution which allows approval, configuration, metadata and what not when a user want’s a new Office 36 Group for collaboration.
So far so good. This works just fine.

Then throw in Yammer. If you lock down the oob self-service, your Yammer groups will not get an Office 365 Group – and there are no easy ways to solve this today.
There is also no option to turn of creation of Yammer groups within Yammer itself and roll your own in-place solution.

Which leads to:
  • Users can create all the Yammer groups they want – but if they want them inside some structure we need to teach them to contact IT, so that IT can create the group and apply whatever metadata, configuration and what not.
I work with client which has a multitude of Yammer groups, but from an information architecture point of view they are not all the same. Some are more important than others – and the only way to classify them is to put magic names in the title or description – or if they are connected to an O365 Group we can put matedata in the Graph – but remember – we turned off self-service of Office 365 Groups.

The solution? Allow us to turn off self-service in Yammer, and allow us to create Groups with Yammer using app tokens – preferably via the MS Graph – not via the Yammer API.

Office 365 Group Logos

Fetching the logo data is possible via the Microsoft Graph – but you require a separate call for this. If I create a listing of Office 365 Groups and want to display the logo, I cannot simply add an <img> tag including the Group id and get the image. No, I need to fire off a REST call per image.

The only resource who got this right is Planner using the link:
https://tasks.office.com/tenant.onmicrosoft.com/Groups/GetGroupPhoto?groupId=<id>

..except you need to have logged in to Planner at least once for this URL to just work. If you’re in SharePoint context they have a nice URL:

/sites/groupname/_api/GroupService/GetGroupImage?id='c8ab4e69-a7a1-4f35-b3ba-96616976cd62'&hash=636476452763371703

..except the id in the above URL is not the Group id, but the id of __iconLogo_.jpg in SiteAssets. You need to fire off a REST call to either get the site url and then one to get the logo url – or hardcode to __iconLogo__ for just one extra call.

And then we have Outlook:

blob:https://outlook.office.com/a03b46be-10ad-469e-b5e6-709c34132353

where the id is something I have no idea what is – certainly not the Group id.

Which means dear users – when listing 100’s of Office 365 Groups, you have to live without the logo until I get smart – tough luck!

Or we have this one:
https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email=group@tenant.onmicrosoft.com – which also requires auth and is a REST call, not a direct image link.

Conclusion

Please Microsoft, give us proper and easy ways to create simple solutions! Or I need to go over all existing Groups and set custom metadata for the logo URL, ensuring all data is available on the intial Graph call. See my generic schema post for more info.

Wednesday, November 29, 2017

Retrieving Teams and Yammer endpoints for an Office 365 Group via the Microsoft Graph

image

I’m working on a solution listing all things Groups from Office 365. That be Office 365 Groups with Outlook, Office 365 Groups with Yammer, Office 365 Groups with Teams, or just plain old Yammer Groups standing by themselves. The last one you cannot do via the Graph so let’s just skip that one for now.

I recently wrote about how you can list all O365 Groups which have a Yammer association, but I did not cover how to get the link to Yammer – as I had no clue how. I have now clued myself in, and will share my findings.

Tuesday, November 21, 2017

Fixing DPI Scaling Issues in Skype for Business on Windows 10 and multiple monitors

image

I have a Surface Pro, and when travelling around I often hook up to a random second monitor. The default DPI scaling of the Surface monitor is 175%, while an external monitor in 1920x1200 resolution is set to 100%.

When running Skype for Business on the Surface monitor everything looks ok, but when I move a chat window over to the external screen, it all becomes super big.

I came across a post by Matt WoodWard which pointed me in the right direction but didn’t solve it for me.

I’m on Windows 10 Fall Creators Update (10.0.16299.19), and what did the trick for me was to open up the file C:\Program Files (x86)\Microsoft Office\root\Office16\LYNC.EXE.MANIFEST, and change dpiAwareness from PerMonitor to System. Remember to open the file as an administrator. If not you won’t be able to change it.

After quitting Skype for Business and restarting it, it all worked.

Monday, November 20, 2017

Modifying the query template for the Highlighted Content modern web part – a very brittle solution

image

The highlighted content web part in modern pages is the successor for the content search web part. It does a pretty decent job, but people like me who like to tune what we get back want some more expert settings, much like we had in the content search web part.

In the highlighted content web part you can add multiple filters today, which are then joined with an OR. This is useful for many scenarios, but often you want to have AND to limit results instead. For example all sites with a specific title, and not all sites OR all items with a specific title.

The above scenario is one I just looked at, and I didn’t want to roll my own web part. Elio Struyf has a PnP sample search web part, but it doesn’t support the same visuals – and I’ll probably end up modifying this in the end ;) But that’s not for this post.

I decided to dig into the properties of the highlighted content web part, and turns out it has a property named advancedQueryText, which is the query template. This property is not included in the UI, but using for example PnP PowerShell you can set this.

The below JSON has a couple of modifications. I have added SiteLogo as an extra managed property to use when showing the result preview, and I have added KQL in the advancedQueryText property.

image

You can download the properties file from my GitHub repo and modify as needed: https://github.com/wobba/RandomFiles/blob/master/searchprops.json

The below PnP powershell creates a new page, and adds a web part with the properties specified.

$pageName = "Awesome"
Connect-PnPOnline -Url https://contoso.sharepoint.com/sites/awesome
Add-PnPClientSidePage -Name $pageName
$searchProps = Get-Content -Path .\searchprops.json -Raw
Add-PnPClientSideWebPart -Page $pageName -DefaultWebPartType ContentRollup -WebPartProperties $searchProps

The caveat is of course that if you edit the web part properties in the UI, everything breaks ;) Which means this is not 100% production ready yet. Hopefully the advancedQueryText property will make it’s way to the UI soon.

References:

How to do “starts with” in KQL

image

When I wrote KQL – The basics back in 2014 I forgot to cover how you can achieve starts with for text property queries. It’s not an operator per say, as it combines equals with quotes and wildcard.

To find all items where title starts with Mikael, you can write:

title="mikael*"

Note that title="mik*" will not work, you need to type full terms before the wildcard for this to work, but still quite useful. I have also updated the original post to cover this.

Monday, November 13, 2017

How to list all Office 365 Groups which are Yammer enabled via the Microsoft Graph

image

Office 365 Groups are great, both from a user perspective, and they are also fun to work with as a developer. This time around I wanted to list all Office 365 Groups which have been created via Yammer, as a means to differentiate the type of Office 365 Groups for users.

I started to dig around on properties on the Group object at the /beta endpoint and found the following for a Yammer originating Office 365 Group.

"resourceBehaviorOptions": [
    "YammerProvisioning"
]

Turns out you can use above information in a filter on the /beta/groups endpoint. Using a GET query where you filter on both Unified groups and the YammerProvisioning attribute, will yield the list you are looking for. You can probably omit the groupTypes filter, but it sure doesn’t hurt.

https://graph.microsoft.com/beta/groups?$filter=groupTypes/any(g:g eq 'Unified') and resourceBehaviorOptions/any(r:r+eq+'YammerProvisioning')

There is still no API on the Microsoft Graph to create Yammer enabled Office 365 Groups, but at least we’re one step closer.

Permission wise you need Group.Read.All as either delegated or app only to query for Groups, which means you can easily do this using the GraphHttpClient for SharePoint Framework.

Wednesday, November 8, 2017

Programmatically enable Teams on an existing Office 365 Group via the Microsoft Graph

Microsoft recently released PowerShell commands to work with Microsoft Teams, which is something we’ve been longing for since Teams was released. We now get commandlets to create and manage teams and channels.

PowerShell is nice and all, but if you already have a lot of Office 365 Groups, or have your own provisioning solution for Office 365 Groups, enabling Teams on these groups is something you want to add into your existing process.

image

And turns out it’s quite easy. I fired off Fiddler to see what was happening when executing the PowerShell commands, and lo and behold, we see queries running against the Microsoft Graph. The creation of the group itself happens against the /edu/groups which I’ve never seen before, but that’s not interesting. The next call to create a Team on the group is the important one.

Run the below payload with a PUT to /beta/groups/<group id>/team and you’re all set. This command will effectively enable Teams on any group (not Yammer ones). Have existing or new Office 365 Groups? Use the above REST command to enable Teams.

Payload - documentation

  "memberSettings": {
    "allowCreateUpdateChannels": true
  },
  "messagingSettings": {
    "allowUserEditMessages": true,
    "allowUserDeleteMessages": true
  },
  "funSettings": {
    "allowGiphy": true,
    "giphyContentRating": "strict"
  }
}

I expect the documentation to be updated soon as this is pretty cool stuff, and guess this will move to the v1.0 endpoint in due time. You can read the docs at https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/group_put_team. Also note that app only takes seems not to be supported at this time.

See the complete listing of PowerShell functions to see what is possible in terms of modifying the team and channels. I didn’t have time to trace all the calls – but should be pretty easy to figure it out if needed until docs are updated. For me, enabling of Teams is the most important at the moment.

Tuesday, November 7, 2017

Fetching custom attributes from Azure Active Directory via the Microsoft Graph

This post was inspired by Juan Carlos González who asked a question about retrieving custom/extension attributes from Azure AD via the Microsoft Graph.

image

Custom or extension attributes in on-premises active directory is nothing new, and many have set up synchronizing these to Azure AD as well – which makes sense. Once the attributes are in place, you might want to use them in applications as well, and in todays day and age, using the Microsoft Graph API is the way we play.

Custom attributes are not retrievable directly by their name like for example userPrincipalName.

https://graph.microsoft.com/v1.0/me/?$select=userPrincipalName

Instead they are named with extension_<randomid>_attribute, which means we need to figure out what this random id is. As far as I know you cannot list it via the Graph, but using Azure AD PowerShell it’s doable. The below sample shows a custom attribute named division on my user object.

Connect-AzureAD
$aadUser = Get-AzureADUser -ObjectId me@madcow.dog
$aadUser|select -ExpandProperty ExtensionProperty

Key                                                     Value
---                                                     -----
extension_e96266002973421daef990ab9be89e86_division     64

By looking at the result we have the prefix we need which works just fine in a graph query.

https://graph.microsoft.com/v1.0/me/?$select=userPrincipalName,extension_e96266002973421daef990ab9be89e86_division

image