CHUVASH.eu

CHunky Universe of Vigourous Astonishing SHarepoint :)

Tag Archives: office365

DIY: Integrating Trådfri lights with Teams presence

It seems that Work from Home (WFH) is here to stay, it’s okay. I’d say, Work from a Smart Home is even more okay. To me, Home Automation (HA) and Work from Home (WFH) are really two peas in a pod.

Today’s “guest” is a tiny application that I’ve set up on my raspberry pi to listen to my presence (status) in Teams and show it with colors of my smart RGB light (IKEA Trådfri).

The code

You can find the application on github:

I’ll try to provide the needed documentation on the github repo and focus more on the story part in this blog post.

The story

I stumbled upon Elio Struyf’s blog post and I was amazed:

Wow! I thought immediately: that would be a cool challenge, I wanted to set up this, too. Although, with some adjustments for my smart home:

  • I wanted to run the whole application on one raspberry pi only, because I don’t have the second one, neither I have HomeBridge installation (maybe something for future projects, though).
  • I wanted to have as little code as possible, maintenance should be kept to minimal.
  • I wanted to use python in order to learn more python and because python seems to be the most supported language on the pi.
  • I wanted to use IKEA Trådfri lights (with a gateway and a remote) that I already have invested into.

I omit the configuration steps for Trådfri lights and Raspberry Pi, you can see them in my previous blog post:

Why show Teams presence with a smart light

Elio wrote his blog post in April this year – in the times of the lockdown in Belgium. In Sweden, we hadn’t a real lockdown, but it seems that it might come times when my children would need to be at home more while I work. In that case a superclear system that shows when I have important meetings is just awesome. Maybe, with that I am prepared for such times.

But to be really honest, the main driving factor is the fact that it is very satisfying to tinker around with this DIY stuff 😜😎

Lessons learned

There is a python wrapper for MSGraph which is awesome, but it needs more contributors:

In your Azure AD App Registration you can specify auth flow type as public, with that you don’t need to store a client secret for delegated access. That was a kind of a new thing to me.

Presence endpoint in MSGraph is in beta, make sure you call the beta endpoint. The scope is ‘https://graph.microsoft.com/Presence.Read’ and you need an admin consent for that permission grant.

Is an M365 Group a Yammer Community

Nowadays a Yammer Community gets a corresponding Microsoft 365 Group (Office 365 Group, Unified Group). In your work as an SPO Admin, you might need to differentiate “ordinary” Modern Team Sites from those ones that were created for a Yammer Community.

They both have GROUP#0 as Template. On the actual SPO Site object, there is nothing that you can use to differentiate those. Neither you can use the Office 365 Group information. But there is a way: if you connect to Exchange Online and get the group from there, then there is something useful.

I’ll share a piece of code with you, as the rest of the posts and code snippets, it is “evergreen”, it changes all the time, maybe when you read this in future, there is a better way, but today I am using this code:

# Prerequisites
# AllowBasic as Admin, perhaps in a separate window
# Set-ItemProperty -path 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\WinRM\\Client' -Name AllowBasic -Value 1
# Connect to Exchange Online
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline
# you can get $groupId from the SPO object
$exogroup = Get-UnifiedGroup Identity $groupId
$isYammer = $exogroup.GroupSKU -eq "Yammer"
#Bonus: determine if Team is connected (if $isYammer is $false)
$hasTeam = "Team" -in $exogroup.ResourceProvisioningOptions

Deploying SPFx using Office 365 cli, custom AAD App and Azure Pipelines

In this post I would like to share some findings from setting a deployment of SPFx. In my work:

  • I need to deploy SPFx solutions using Azure Pipelines
  • I need to use the least privileges/permissions
  • I cannot use Legacy Authentication

First of all, big thanks to @waldekm and the whole community of @office365cli and @m365pnp for the quick help, and that outside working hours.

Let’s take a look at the setup piece by piece

Least Privileges

I followed this guide to set up a custom App Registration for Office 365 CLI in order to use the least privileges:

Custom Azure AD App

For uploading and deploying SPFx packages I found these permissions to be the bare minimum:

  • Delegated Microsoft Graph User.Read
  • Delegated SharePoint AllSites.FullControl

Service Account

The second part is the service account that just has access to one site collection – Tenant App Catalog. That plus Delegated AllSites.FullControl of the app registration narrows the access to just that site. To install apps the Uploader Account needs to be Site Collection Administrator.

Least privileges for SPFx Upload & Deploy

Azure Pipelines

In our project we use Azure Pipelines where we also define the release using .yml. The deployment consists of series of bash inline scripts.

I am not going to describe all the steps for setting up node, npm and installing the office 365 cli. If you already have used Office 365 CLI with the default AAD APP it might look like this:

task: Bash@3 # login
displayName: "Login to O365 spAppCatalogSiteUrl with user $(username)"
inputs:
targetType: "inline"
script: 'o365 login "${{ parameters.spAppCatalogSiteUrl }}" -t password -u $(username) -p $(password)'
task: Bash@3 #upload
displayName: "Upload web part ${{ parameters.spfxPackageName }} to catalog"
inputs:
targetType: "inline"
script: 'o365 spo app add -p "$(Pipeline.Workspace)/${{ parameters.environment }}/${{ parameters.spfxPackageName }}" –overwrite'
task: Bash@3 #deploy
displayName: "Deploy ${{ parameters.spfxPackageName }} web part"
inputs:
targetType: "inline"
script: 'o365 spo app deploy –name "${{ parameters.spfxPackageName }}" –appCatalogUrl "${{ parameters.spAppCatalogSiteUrl }}"'
view raw deploy-spfx.yml hosted with ❤ by GitHub

Now comes the tricky part! If you followed the guide mentioned above, you must have noticed the two environment variables that you need to have:

export OFFICE365CLI_AADAPPID=506af689-32aa-46c8-afb5-972ebf9d218a
export OFFICE365CLI_TENANT=e8954f17-a373-4b61-b54d-45c038fe3188
view raw deploy-spfx-env.sh hosted with ❤ by GitHub

That’s straight forward when you run the cli in your own console. But the fact is (or at least from what I can see), you cannot “export” variables to other pipeline tasks.

Instead of setting the variables in the inline script, we can take advantage of the Bash task parameter called env:.

Some other findings:

  • Office 365 CLI needs them in all three commands: login, spo app add, and spo app deploy
  • If you create and export a variable in a pipeline task, it won’t persist, because every task starts a new shell session.

That means that we need to provide environment variables in every task in the pipeline, that uses Office 365 CLI with a custom Azure AD App. Or is there a better way? Anyway, the version below (the same tasks plus `env`) will work:

task: Bash@3 # login
displayName: "Login to O365 spAppCatalogSiteUrl with user $(username)"
inputs:
targetType: "inline"
script: 'o365 login "${{ parameters.spAppCatalogSiteUrl }}" -t password -u $(username) -p $(password)'
env:
OFFICE365CLI_AADAPPID: "${{ parameters.o365cliAppId }}"
OFFICE365CLI_TENANT: "${{ parameters.tenantId }}"
task: Bash@3 #upload
displayName: "Upload web part ${{ parameters.spfxPackageName }} to catalog"
inputs:
targetType: "inline"
script: 'o365 spo app add -p "$(Pipeline.Workspace)/${{ parameters.environment }}/${{ parameters.spfxPackageName }}" –overwrite'
env:
OFFICE365CLI_AADAPPID: "${{ parameters.o365cliAppId }}"
OFFICE365CLI_TENANT: "${{ parameters.tenantId }}"
task: Bash@3 #deploy
displayName: "Deploy ${{ parameters.spfxPackageName }} web part"
inputs:
targetType: "inline"
script: 'o365 spo app deploy –name "${{ parameters.spfxPackageName }}" –appCatalogUrl "${{ parameters.spAppCatalogSiteUrl }}"'
env:
OFFICE365CLI_AADAPPID: "${{ parameters.o365cliAppId }}"
OFFICE365CLI_TENANT: "${{ parameters.tenantId }}"
view raw deploy-spfx-env.yml hosted with ❤ by GitHub

Eliminating Legacy Authentication

My goal is to remove the need of legacy authentication. Previously we installed spfx packages using PnP PowerShell. PnP PowerShell in Pipelines causes Legacy Authentication, it can be solved, though:

Using Office 365 CLI rather than PnP PowerShell with a certificate has some significant benefits:

  • Office 365 CLI is multi-platform, you can reuse the scripts. PnP PowerShell requires Windows (yet, but still).
  • Setting up certificates and using it in the deployment process is a bigger initial task.

Release Pipelines

Just for completeness, in a classic release pipeline, you can use a bash script to upload and deploy an app:

#runs in Ubuntu 20.04 Bash Task
sudo npm install -g @pnp/office365-cli
export OFFICE365CLI_AADAPPID="$(OFFICE365CLI_AADAPPID)"
export OFFICE365CLI_TENANT="$(OFFICE365CLI_TENANT)"
o365 login –authType password –userName $(AppCatalogUsername) –password "$(AppCatalogPassword)"
export filePath="$(System.DefaultWorkingDirectory)/dist/$(env)/$(fileName)"
o365 spo app add -p "$filePath" –overwrite
o365 spo app deploy –name "$(fileName)" –appCatalogUrl "$(AppCatalogSiteUrl)"
view raw release-bash.sh hosted with ❤ by GitHub

In our example we also send data to Azure CDN using Azure CLI:

az storage blob upload-batch \
–source $(sourceFolder)/bundledFiles \
–destination $(storageContainer)/$(toolPath) \
–account-name $(storageAccount)
view raw azure-cli.sh hosted with ❤ by GitHub

Modern Team Site without an Office 365 Group

These are my findings around Modern Sites without Office 365 Groups. It is, of course, a subject to change.

Today (2020-02-21) when you create a Modern Team Site without a group, you will get a site with the template STS#3. This oldie has been around for a while, hasn’t it?

I would always recommend creating Office 365 Group Connected sites.

How it is created

Through PowerShell/REST or from SharePoint Home, if your account is not allowed to create Office 365 Groups, it will automatically create a site without a group.

Site Creation Speed

It is really fast, much faster than the old STS#3, so something is different.

Custom Script

CustomScript is enabled. Which is the same as DenyAddAndCustomizePages=Disabled. CustomScript is a security risk, so I hope Microsoft will change that.

Groupifying

Yes, connecting to a new group is possible.

Listing Team Sites without Office 365 Groups

In SharePoint Admin you can filter them based on “Team Site (no Office 365 group)”

Multilingual MS Forms

Want to translate your MS Forms into other languages? Create a form, not a quiz. It is available in both Forms and Forms Pro licenses.

Today I want to share one of my findings. One of those that seem obvious once you know, but that take time to find out.

Unfortunately, there is no official comparison of what is included in MS Forms vs. MS Forms Pro. So I thought that the ability to have forms in multiple languages was connected to the license.

It showed after many tests, that it is up to the type of form. The Form has the “Multilingual” feature. The Quiz does not have. Why? I don’t know. 🙂

Lesson learned: If you want to have your form in different languages, create a form, not a quiz in MS Forms.

One of the reasons why it is confusing is also the translation into Swedish.

  • Form – Formulär
  • Quiz – Frågeformulär. You can say “Quiz” in Swedish, too. Frågeformulär is very confusing.
English interface of MS Forms
Mulilingual only availalbe in a form, not a quiz

Using Sway as a simple static site builder

Sometimes all you need is just a simple static web page: instructions, a landing page, a collection of links. I think I have a perfect use case for Sway. Consider a scenario similar to what Laura Kokkarinen writes in her blog post:

An external user invitation needs an inviteRedirectUrl. Usually it is myapps.microsoft.com. In Laura’s case it was a given extranet url.

In our case we don’t know where an external user will land. After the invitation the external user will be added to some team or a collaboration site.

The default myapps.microsoft.com is a tool where a user can administer his account and accesses, but it might be a confusing place to be sent to after the invitation acceptance process.

A simple static page with clear information is just enough in our case. Fortunately, there is Sway, a simple (but still great) web page builder.

An example of a landing page, defined in Sway.

Following alternatives were considered for our landing page:

  • An “extranet” page in SharePoint Online. It takes time to set up if you don’t have an extranet.
  • A page in a public portal. Comms and IT must be involved.
  • A static web page in a blob storage / Azure CDN. It requires some basic web development for design and IT-driven deployment.
  • Azure App or Azure Function. Actually here it would mean going beyond static. For the initial phase, serving a static page, would also mean basic development and deployment by IT.

Advantages of a Sway page

  • Easy to create a static web page
  • Beautiful templates and an easy way to alter the design
  • Can be driven by the business/comms completely. We only need the url (to put into the invitation call to MS Graph).
  • Does not require any development or deployment.
  • Videos, documents can be embedded easily
  • A sway can be shared with anyone using the link. It means no additional infrastructure steps for this to work (such as firewall, dns etc).

There are some disadvantages, too:

  • The domain is too generic: sway.office.com. It might look suspicious to some users. Maybe there is a way to use own domain?
  • A Sway cannot have different languages and switch them based on the user’s locale. It would be great to have something similar to the “Multilingual” functionality in Forms. But still, as a static web page, Sway is doing great, even without the “Multilinguality”.

Summary

Sway is an easy “business friendly”, no-code solution for simple, still good-looking web pages, that can be created and updated in no time and shared easily. Being a member of the bigger Microsoft 365 ecosystem, it fills a certain gap where the business can work together with IT and deliver solutions faster.

Permissions in SPFx apply to your whole tenant

Once you approve a permission request from an SPFx app, it will grant the same permission to all other apps in the same tenant.

Nothing new, but I want to emphasize that in that blog post only dedicated to that. You can read it here:

A simple sketch over the permissions.

Here is a simple FAQ to explain what it means:

  • I uploaded my app to two site collection app catalogs. Do I need to get approval for the app twice? – No.
  • I have got my approval for Delegated Groups.ReadWrite.All for App X. Now I want to use the same permissions in another app, do I need a new approval? – No.

The Path Length Limit of 400 chars in SharePoint Online

This post is my summary and my conclusions on the Path Length Limit in SharePoint Online and OneDrive.

How the path length is calculated

Path Length is not the same as the URL length. It is the relative Url.

/sites/site-url/documenlibrary/folder1/folder2/filename.fileextension

Calculations rules

  • Only the server relative url part is counted. The “https://%5Btenant%5D.sharepoin.com” has no impact on that. It starts from the foward slash: “/sites” (or /teams).
  • An encoded value such as a blankspace (%20) is treated as one character, not three.
  • A unicode character, and an emoji is treated as one character. Good news for Non-English Names.
  • Url Parameters, like “?Web=1” are not calculated.
  • The site url and the document library url is taken into account
  • All slashes are included
  • A file extension is also included, and even the dot, e.g. “.docx”

Other related information

  • A site url and a group name can only be 64 characters max.
  • The path in the “Copy Link” is much shorter than the “real” path
  • There is no limit (as of time of writing – 2019-10-30) on the folder name length (other than the bigger limit of 400 characters), I had no issues to add a folder name with 312 characters.
https://%5Btenant%5Dsharepoint.com
/:w:/s
/[long-site-ur]/ETWAEtIJiltJtW7uAND42doBeXOMCpxmHRws55m_nNlEcA

A calculation example

Those are parts that are counted in the Path Length

Recommendations for Folder-heavy document management

I don’t want to discuss whether to folder not to folder. On that topic, my favorite is the slide deck with the same name by Bobby Chang: To Folder or Not To Folder. For those who need to use folders I would recommend:

  • Try to have a short site url/group name
  • Try to have a short document library url. Why not creating just “docs” instead of “Our very important documents”? Note, that I am talking about the url, not the display name. The trick is to call it “docs” (or some other short word) initially (which will turn to the url), and then you can name it to whatever you please.
  • Even if you use folders, try to flatten the structure.
  • Use shorter folder names
  • Use shorter file names.

Further Reading

Renaming site urls

I saw a demo of it on the European SharePoint Conference in Copenhagen in 2018. Sebastian Fouillade, who showed this, compared this big change with brain surgery. All the urls, all the connections. But now it is possible. Today I have seen it even in my standard release tenant.

It is really appreciated. Soon it will be possible to rename misspelled sites, like “devlepment” to “development” etc.

To rename you need to go the SharePoint Admin, find your site among Active sites and click on “Edit” in the site url area.

I also can image, it will be very handy to change the url of a SharePoint site that was automatically created for a Team (through the Office 365 Group). The team might have some longer name, but a simpler url is often appreciated.

I have tried and seen that also the automatic redirects from an old site url to a new site url works.

Caveats and Limitations

mailNickname ≠ site url

Now it is even more important to not to rely on the fact that mailNickname of an Office 365 Group and Site url are the same. As Elio Struyf describes, it is not a good idea to compose a URL from the group name. I have used in PoCs the site url to get the group id:

GET https://graph.microsoft.com/v1.0/groups?$filter=mailNickname eq 'my-group' 

Now it the amount of cases where it will work, will be less.

Not all site types can change url

I have found that the App Catalog site cannot get a new url, neither sites with Publishing Features.

The official message from Microsoft

We’re making it possible for SharePoint administrators to change site URLs.

  • We’ll be gradually rolling this out to customers in mid-October.
  • The roll out will be completed worldwide by the end of October.

This roll out does not apply to Office 365 subscriptions for EDU tenants.

This message is associated with Microsoft 365 Roadmap ID 56205.How does this affect me?

As a global or SharePoint admin in your organization, you will be able to change the URL for the following types of sites (previously called “site collections”):

  • Classic team sites
  • Communication sites
  • Modern team sites that don’t belong to an Office 365 group
  • Office 365 group-connected team sites

For example, if you have a site named https://contoso.sharepoint.com/sites/Develpment, you can rename the site to correct the incorrect spelling of “development” via the SharePoint admin center.

Automatically-generated redirects will ensure that old links do not break.What do I need to do to prepare for this change?

There is nothing you need to do to prepare for this change, but you may consider updating your user training and notifying your help desk.

Learn more about changing a site address.

A user can only create 250 groups

A non-admin user can create no more than 250 resources in Azure AD. That is one of the many Azure AD service limits and restrictions. A “resource” can be an app registration, an Office 365 Group etc. But I would like to discuss Groups more in detail.

Imagine the following scenario: Your organization has disabled Office 365 Group Creation. Only IT can create new groups. A service account has been set up for creation of team sites. The application permissions are “binary”, either everything or nothing: Group.ReadWrite.All. This service account will hit the limit very soon.

To prove that, I have created a small script that creates 251 groups.

# This script will try to create 251 groups
# The last one should fail
# configuration:
# 1. create an account nonadmin@takana16.onmicrosoft.com
# 2. go to https://developer.microsoft.com/en-us/graph/graph-explorer, make a call and grab the access token
$token = "eyJ0eXAiOiJKV1QiLCJub25jZSI6Iko1WXU2MWRtR3FsR0JaaVJ0YTJsM0duUFdBLW5FY19yWk90aFNFNlg3MUEiLCJhbGciOiJSUzI1NiIsIng1dCI6ImFQY3R3X29kdlJPb0VOZzNWb09sSWgydGlFcyIsImtpZCI6ImFQY3R3X29kdlJPb0VOZzNWb09sSWgydGlFcyJ9.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMzRmOGFhOC01NTBiLTRjZmEtODZhNi03NWFkNTdmMTNkNDkvIiwiaWF0IjoxNTcxOTk3NzQ5LCJuYmYiOjE1NzE5OTc3NDksImV4cCI6MTU3MjAwMTY0OSwiYWNjdCI6MCwiYWNyIjoiMSIsImFpbyI6IkFTUUEyLzhOQUFBQWFmNDJjVjFMTUdZRzlmMFh4TDNCK0pLbTdrR2NNQ3FLcHI3TUtFVlNwdUU9IiwiYW1yIjpbInB3ZCJdLCJhcHBfZGlzcGxheW5hbWUiOiJHcmFwaCBleHBsb3JlciIsImFwcGlkIjoiZGU4YmM4YjUtZDlmOS00OGIxLWE4YWQtYjc0OGRhNzI1MDY0IiwiYXBwaWRhY3IiOiIwIiwiZmFtaWx5X25hbWUiOiJNaXJvbm92IiwiZ2l2ZW5fbmFtZSI6IkFuYXRvbHkiLCJpcGFkZHIiOiIyMTIuNzMuMTY0LjExIiwibmFtZSI6IkFuYXRvbHkgTWlyb25vdiIsIm9pZCI6IjI5OGU2MjNmLTg1M2MtNDcxYS1hODhkLWJkZjA3OTcxNzg5NSIsInBsYXRmIjoiMyIsInB1aWQiOiIxMDAzMjAwMDVFNEU5NDcyIiwic2NwIjoiQWNjZXNzUmV2aWV3LlJlYWQuQWxsIEFjY2Vzc1Jldmlldy5SZWFkV3JpdGUuQWxsIEFncmVlbWVudC5SZWFkLkFsbCBBZ3JlZW1lbnQuUmVhZFdyaXRlLkFsbCBBZ3JlZW1lbnRBY2NlcHRhbmNlLlJlYWQgQWdyZWVtZW50QWNjZXB0YW5jZS5SZWFkLkFsbCBBbmFseXRpY3MuUmVhZCBBcHBDYXRhbG9nLlJlYWRXcml0ZS5BbGwgQXVkaXRMb2cuUmVhZC5BbGwgQm9va2luZ3MuTWFuYWdlLkFsbCBCb29raW5ncy5SZWFkLkFsbCBCb29raW5ncy5SZWFkV3JpdGUuQWxsIEJvb2tpbmdzQXBwb2ludG1lbnQuUmVhZFdyaXRlLkFsbCBDYWxlbmRhcnMuUmVhZCBDYWxlbmRhcnMuUmVhZC5TaGFyZWQgQ2FsZW5kYXJzLlJlYWRXcml0ZS5TaGFyZWQgQ2hhdC5SZWFkIENoYXQuUmVhZFdyaXRlIENvbnRhY3RzLlJlYWQgQ29udGFjdHMuUmVhZC5TaGFyZWQgQ29udGFjdHMuUmVhZFdyaXRlLlNoYXJlZCBEZXZpY2UuQ29tbWFuZCBEZXZpY2UuUmVhZCBEZXZpY2VNYW5hZ2VtZW50QXBwcy5SZWFkLkFsbCBEZXZpY2VNYW5hZ2VtZW50QXBwcy5SZWFkV3JpdGUuQWxsIERldmljZU1hbmFnZW1lbnRDb25maWd1cmF0aW9uLlJlYWQuQWxsIERldmljZU1hbmFnZW1lbnRDb25maWd1cmF0aW9uLlJlYWRXcml0ZS5BbGwgRGV2aWNlTWFuYWdlbWVudE1hbmFnZWREZXZpY2VzLlByaXZpbGVnZWRPcGVyYXRpb25zLkFsbCBEZXZpY2VNYW5hZ2VtZW50TWFuYWdlZERldmljZXMuUmVhZC5BbGwgRGV2aWNlTWFuYWdlbWVudE1hbmFnZWREZXZpY2VzLlJlYWRXcml0ZS5BbGwgRGV2aWNlTWFuYWdlbWVudFJCQUMuUmVhZC5BbGwgRGV2aWNlTWFuYWdlbWVudFJCQUMuUmVhZFdyaXRlLkFsbCBEZXZpY2VNYW5hZ2VtZW50U2VydmljZUNvbmZpZy5SZWFkLkFsbCBEZXZpY2VNYW5hZ2VtZW50U2VydmljZUNvbmZpZy5SZWFkV3JpdGUuQWxsIERpcmVjdG9yeS5BY2Nlc3NBc1VzZXIuQWxsIERpcmVjdG9yeS5SZWFkLkFsbCBEaXJlY3RvcnkuUmVhZFdyaXRlLkFsbCBFZHVBZG1pbmlzdHJhdGlvbi5SZWFkIEVkdUFkbWluaXN0cmF0aW9uLlJlYWRXcml0ZSBFZHVBc3NpZ25tZW50cy5SZWFkIEVkdUFzc2lnbm1lbnRzLlJlYWRCYXNpYyBFZHVBc3NpZ25tZW50cy5SZWFkV3JpdGUgRWR1QXNzaWdubWVudHMuUmVhZFdyaXRlQmFzaWMgRWR1Um9zdGVyLlJlYWRCYXNpYyBGaWxlcy5SZWFkIEZpbGVzLlJlYWQuQWxsIEZpbGVzLlJlYWQuU2VsZWN0ZWQgRmlsZXMuUmVhZFdyaXRlIEZpbGVzLlJlYWRXcml0ZS5BcHBGb2xkZXIgRmlsZXMuUmVhZFdyaXRlLlNlbGVjdGVkIEZpbmFuY2lhbHMuUmVhZFdyaXRlLkFsbCBHcm91cC5SZWFkLkFsbCBHcm91cC5SZWFkV3JpdGUuQWxsIElkZW50aXR5UHJvdmlkZXIuUmVhZC5BbGwgSWRlbnRpdHlQcm92aWRlci5SZWFkV3JpdGUuQWxsIElkZW50aXR5Umlza0V2ZW50LlJlYWQuQWxsIElkZW50aXR5Umlza0V2ZW50LlJlYWRXcml0ZS5BbGwgSWRlbnRpdHlSaXNreVVzZXIuUmVhZC5BbGwgSWRlbnRpdHlSaXNreVVzZXIuUmVhZFdyaXRlLkFsbCBNYWlsLlJlYWQgTWFpbC5SZWFkLlNoYXJlZCBNYWlsLlJlYWRXcml0ZS5TaGFyZWQgTWFpbC5TZW5kIE1haWwuU2VuZC5TaGFyZWQgTWFpbGJveFNldHRpbmdzLlJlYWRXcml0ZSBOb3Rlcy5DcmVhdGUgTm90ZXMuUmVhZCBOb3Rlcy5SZWFkLkFsbCBOb3Rlcy5SZWFkV3JpdGUgTm90aWZpY2F0aW9ucy5SZWFkV3JpdGUuQ3JlYXRlZEJ5QXBwIFBlb3BsZS5SZWFkLkFsbCBQb2xpY3kuUmVhZC5BbGwgUG9saWN5LlJlYWRXcml0ZS5Db25kaXRpb25hbEFjY2VzcyBQb2xpY3kuUmVhZFdyaXRlLlRydXN0RnJhbWV3b3JrIFByaXZpbGVnZWRBY2Nlc3MuUmVhZFdyaXRlLkF6dXJlQUQgUHJpdmlsZWdlZEFjY2Vzcy5SZWFkV3JpdGUuQXp1cmVSZXNvdXJjZXMgUHJvZ3JhbUNvbnRyb2wuUmVhZC5BbGwgUHJvZ3JhbUNvbnRyb2wuUmVhZFdyaXRlLkFsbCBSZXBvcnRzLlJlYWQuQWxsIFNlY3VyaXR5RXZlbnRzLlJlYWQuQWxsIFNlY3VyaXR5RXZlbnRzLlJlYWRXcml0ZS5BbGwgU2l0ZXMuRnVsbENvbnRyb2wuQWxsIFNpdGVzLk1hbmFnZS5BbGwgU2l0ZXMuUmVhZC5BbGwgVGFza3MuUmVhZCBUYXNrcy5SZWFkLlNoYXJlZCBUYXNrcy5SZWFkV3JpdGUuU2hhcmVkIFRydXN0RnJhbWV3b3JrS2V5U2V0LlJlYWQuQWxsIFRydXN0RnJhbWV3b3JrS2V5U2V0LlJlYWRXcml0ZS5BbGwgVXNlci5SZWFkIFVzZXIuUmVhZC5BbGwgVXNlci5SZWFkV3JpdGUuQWxsIFVzZXJBY3Rpdml0eS5SZWFkV3JpdGUuQ3JlYXRlZEJ5QXBwIHByb2ZpbGUgb3BlbmlkIGVtYWlsIFVzZXIuUmVhZFdyaXRlIFVzZXIuUmVhZEJhc2ljLkFsbCBTaXRlcy5SZWFkV3JpdGUuQWxsIENvbnRhY3RzLlJlYWRXcml0ZSBQZW9wbGUuUmVhZCBOb3Rlcy5SZWFkV3JpdGUuQWxsIFRhc2tzLlJlYWRXcml0ZSBNYWlsLlJlYWRXcml0ZSBGaWxlcy5SZWFkV3JpdGUuQWxsIENhbGVuZGFycy5SZWFkV3JpdGUiLCJzaWduaW5fc3RhdGUiOlsia21zaSJdLCJzdWIiOiJaeVU3ajFXZC1qbVQycWVoT0xkcmZRLWpDOEJNWExpcDNKbHRjWjR4S2ZrIiwidGlkIjoiMDM0ZjhhYTgtNTUwYi00Y2ZhLTg2YTYtNzVhZDU3ZjEzZDQ5IiwidW5pcXVlX25hbWUiOiJhZG1pbkB0YWthbmExNi5vbm1pY3Jvc29mdC5jb20iLCJ1cG4iOiJhZG1pbkB0YWthbmExNi5vbm1pY3Jvc29mdC5jb20iLCJ1dGkiOiJwVjdxcFpNaVlrYXphTFdOZzU4N0FBIiwidmVyIjoiMS4wIiwid2lkcyI6WyI2MmU5MDM5NC02OWY1LTQyMzctOTE5MC0wMTIxNzcxNDVlMTAiXSwieG1zX3N0Ijp7InN1YiI6Ilp3N1NraGoxcG9wa0EySm1oV0Jta2hEdTlrTC1VUWdSY3QtM2FWYkM3djAifSwieG1zX3RjZHQiOjE1NjY1NzQ0OTR9.A7cmPDgKnGF2XsG5KqiRpTprtaEoMHzy7JdBgR0ZbNC6VjWEjGNoPfhLADaugOOXhzfT6EkD8t3KPcccFAxkAOZb7xZTnZXDnnDfh8GDMEOdiOZ2Ka-PrXCq-volPSJ_SWILi4D31rxE0oNJL_XbjMFZixcvnh8lWtMAyw6oxuQSkY8yahzVXfEH82HK8pi217OL-PPAjhDR7WH5Gc5sz2_-XlE7QbVktvmLS98nDtkXoMXbHox4TP6abta10onwlEXciPVJv_Gr1lyF490XJEyVZ7n_fOsW0rery5NRDsG9UtEFwvmLcOCi5OEYPkKMOq8eRRC0f_V-yW76JksUXQ"
$authorization = "Bearer " + $token;
$header = @{
"Accept" = "application/json"
"Authorization" = $authorization
"Content-Type" = "application/json"
}
function CallGraph($name) {
$body = @{
"displayName" = $name
"mailNickname" = $name
"mailEnabled" = $true
"securityEnabled" = $false
"groupTypes" = [string[]]"Unified"
"visibility" = "Private"
"resourceBehaviorOptions" = [string[]]"WelcomeEmailDisabled"
} | ConvertTo-Json
Invoke-RestMethod Uri "https://graph.microsoft.com/v1.0/groups/" Method 'Post' Body $body Headers $header
}
#$prefix = "try250-002-"
$prefix = "wel-"
$start = 5
$count = 1
$end = $start + $count
$tries = $start..$end
$results = $tries | ForEach-Object {
$name = "$prefix{0:d3}" -f $_
$percent = 100 * ($_ $start) / $count
Write-Progress Activity "Creating groups" Status "$_ of $count Complete:" PercentComplete $percent
CallGraph($name)
}

By the way, just for clarification, when create a new group, that will also create a SharePoint site.

Please don’t try this with your real account in production. The 251st request will fail:

Directory_QuotaExceeded

The directory object quota limit for the Principal has been exceeded. Please ask your ad
ministrator to increase the quota limit or delete objects to reduce the used quota.

Even if you remove, it will take time to get free slots in this limit:

Deleted Azure AD resources that are no longer available to restore count toward this quota at a value of one-quarter for 30 days.

There is not much to do about it. For App Registrations you can create and assign a custom role. But for groups there is no custom roles available.

Exceptions

It might be obvious, but still:

Admins

Admins do not have this limit. But not all “admin roles” are really admins. Those roles are excepted:

  • Global Admin
  • SharePoint Admin

Those roles are not excepted:

  • Message Center Reader

I don’t have time to try every admin role, but I suppose only admins that can change global configuration, are excepted, not the reader ones.

Communication Sites

Since communication sites do not have an Office 365 Group behind the scenes, a non-admin user will still be able to create such sites even after the limit is hit.

Workarounds and Solutions

Since my scenario for creating groups with a service account does not work, we need to seek workarounds and solutions.

Do not restrict Group Creation

That is the best one. If users can create groups/sites by themselves, then none of this would be a problem. But still, in my scenario, there is a business requirement to control the creation of groups.

Application Permissions Group.ReadWrite.All

That is exactly the opposite of my scenario. This gives that application full access to all groups and files (!). This means, that application can access all Group-Connected SharePoint Sites as well.

Microsoft creates permissions for groups

If we also had “groups” permissions for custom roles, then we could do the same way as with app registrations. Today (2019-10-25), there are only permissions for applications.

Microsoft creates new permission Group.Create.All

If there were a permission for only creating groups, that would solve the problem.

What we have today

There is a similar role: User.Invite.All, it allows only invitations, not editing All Users.

Microsoft allows exceptions per user

If there were a switch for the 250-limit per user, that would also solve the problem.

Granting the service account admin rights

Granting SharePoint Admin would solve the problem, but at what price? That is safer than Application Permissions Group.ReadWrite.All, since you need to actively add this account to the groups in order to read all the files, but this is still less secure than just a non-admin account.

Having multiple service accounts

If we had account 1..100 and we used every account 250 times. Theoretically it should work, but it is a cumbersome process. You need to keep track of how many groups an account as created, or having the right error handling. How should the password be kept safely. Should the accounts be removed when they have reached the 250 limit?

Group Creation Microservice

To overcome the limits and the ungranularity in the built-in permissions in Office 365, one way to solve it would be a tiny, but a dedicated, and secured service for creation of groups (and sites). It would still need the “hefty” Group.ReadWrite.All Application Permissions, but making it do the only thing and do it right, would mitigate the risks.

It could be a simple Azure Function that few have access to. That could be just a couple of lines of code.

Daniel Chronlund Cloud Tech Blog

News, tips and thoughts for Microsoft cloud fans

Вула Чăвашла

VulaCV - Чăвашла вулаттаракан сайт

Discovering SharePoint

And going crazy doing it

Bram de Jager - Architect, Speaker, Author

Microsoft 365, SharePoint and Azure

SharePoint Dragons

Nikander & Margriet on SharePoint

Mai Omar Desouki

PFE @ Microsoft

Cameron Dwyer

Office 365, SharePoint, Azure, OnePlace Solutions & Life's Other Little Wonders

paul.tavares

Me and My doings!

Share SharePoint Points !

By Mohit Vashishtha

Jimmy Janlén "Den Scrummande Konsulten"

Erfarenheter, synpunkter och raljerande om Scrum från Jimmy Janlén

Aryan Nava

DevOps, Cloud and Blockchain Consultant

SPJoel

SharePoint for everyone

SharePointRyan

Ryan Dennis is a SharePoint Solution Architect with a passion for SharePoint and PowerShell

SharePoint 2020

The Vision for a Future of Clarity

Aharoni in Unicode

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint

blksthl

Mostly what I know and share about...