Building Compliant Team Sites

Companion article to my session at Microsoft Ignite 2017

Thanks to everyone who attended my session at Microsoft Ignite 2017, Building Compliant Team sites (THR2057). For those who missed it, here is the recording. This article provides links to resources and additional details.

The talk was about how enterprises can manage modern SharePoint team sites in a way that makes compliance easy.

Users are like water: they take the path of least resistance. That’s why you can’t have compliance without usability. If users have to work a little harder in order to comply with policies and governance rules, one day they’ll be busy and take a shortcut. Yet most organizations ask users to work a lot harder – to figure out the rules for the kind of information they want to share, create a site, and then learn SharePoint so they can configure it appropriately. It’s not realistic to think that users will comply. The key is to make it so the easy (and only) path to collaboration just happens to comply with regulations, policies, and governance rules.

It’s about Groups

Before going any further, let me point out that we’re not really talking about SharePoint team sites anymore. A modern team site is backed by an Office 365 Group; you can’t have a modern team site without a Group. An Office 365 Group associates a set of users with a set of collaboration resources, including a modern site and document library in SharePoint, a shared inbox and calendar in Exchange, a OneNote notebook, and a Planner plan. Fans of SharePoint calendars, discussion lists, and tasks will mourn the switch… if indeed there are any fans of those clunky old constructs. The beauty of Groups is that each collaboration resource is handled by the service that fits it best.

You can see this in modern SharePoint sites today: the calendar web part shows the Group calendar, not a list in SharePoint. You can also see it in Microsoft Teams, which also map 1:1 with Groups; among other things, Teams is a key user interface for Groups.

The bulk of the talk focused on how to set up an enterprise-wide environment for modern, compliant team sites (each with an Office 365 Group). Here are the steps:

  1. Set up policies
  2. Classify your sites
  3. Provision sites consistently
  4. Classify your documents

The sections which follow will provide the links to resources for each of these steps.

1. Set up Policies

The first step is to set up all the tenant-wide policy and compliance settings available in Office 365. This is a huge area and could consume a day full of sessions! For the purposes of this talk, I kept it simple and showed the Office 365 Security and Compliance Center. I specifically showed how to set up Office 365 Labels and use them with Data Loss Prevention policies. Labels can be used to classify content and set up retention rules; they work across SharePoint and Exchange.

Here are some other talks at Ignite that go deeper on this topic:

GS04 – Microsoft 365: Step up your protection with intelligent security – Julia White
HOL3105 – Configure and use Microsoft Office 365 security and compliance features
BRK3136 – Office 365 Security and Compliance Overview – Alym Rayani
THR2028 – Protect sensitive information with Office 365 Data Loss Prevention – Mas Libman
BRK3111 – Understanding advanced concepts in getting the most out of Office 365 Data Loss Prevention

2. Classify your sites

The next step is to classify your sites. Perhaps you’ve heard the old saying, “A place for everything and everything in its place” – well the idea here is to create places for each useful type of content in your enterprise.


Microsoft just shipped a new site classification feature which allows users to select a site classification when they create a site, and displays the site classification next to the site name in SharePoint. This is certainly a good start! Here are some key links to information on how to set it up:

Setup requires PowerShell 5.x and the Azure AD PowerShell V2 Preview. Site classifications are set up once for a whole tenant; here’s the code I used for my demo:

$me = Get-Credential
Import-Module AzureADPreview
Connect-AzureAD Credential $me
# Create the new setting
$template = Get-AzureADDirectorySettingTemplate | Where-Object {$_.DisplayName -eq "Group.Unified"}
$setting = $template.CreateDirectorySetting()
$setting["UsageGuidelinesUrl"] = ""
$setting["ClassificationList"] = "Secret, Confidential, Internal, Public"
$setting["DefaultClassification"] = "Confidential"
New-AzureADDirectorySetting DirectorySetting $setting
# View settings to check for success
Get-AzureADDirectorySetting All $true | % {$_.values}

Once these settings are in place, you can classify your sites and view the classification to the right of the site name in SharePoint online.

The thing about these site classifications is you only get to pick one. A lot of my clients want to classify sites in more than one way – for example they might want to track security classification, company division, location and project name for each site. So I showed a little web part that does just that.


This is written in SharePoint Framework, and can be provisioned along with each site. More on that in the next section!

3. Provision sites consistently

If you want to consistently create generic team sites, then you’re in luck! The built-in self service site creation does just that!

If you want something more tailored to your organization, then you need to work a little harder. Often an organization will want more than one kind of site – for example, a project site or a community of practice – and they’ll want to pre-configure the sites with lists, libraries, web parts, etc. This leads to consistency, and makes the sites useful to those who don’t know how to set up a SharePoint site.

Often sites will map to some kind of business entity; this is really handy if you want to keep all the information in one place, and even add web parts to display related line of business data. Here are some examples from projects I’ve done over the years:

  • For a consulting company: a site for every engagement
  • For an IT team: a site for every project
  • For an investment bank: a site for every fund or portfolio
  • For an insurance company: a site for every counterparty
  • For a manufacturing company: a site for every product
  • For a property management company: a site for every property
  • For a pharmaceutical company: a site for every compound

During the talk I showed how to provision a site collection using PnP PowerShell:

Connect-PnPMicrosoftGraph Scopes "Group.ReadWrite.All","User.Read.All"
$group = New-PnPUnifiedGroup DisplayName "xxx" Description "xxx" MailNickname "xxx"
Members "" IsPrivate
Connect-PnPOnline $group.SiteUrl
# Here you would normally apply a Provisioning Template to create lists, libraries, web parts etc.
# based on a "template" site. Instead, I just want to show placing a couple web parts in a
# 2-column section to show how that works:
Add-PnPClientSideSection Page "Home.aspx" SectionTemplate TwoColumnRight
Add-PnPClientSideWebPart DefaultWebPartType "NewsFeed" Page "Home.aspx" Section 1 Column 1
Add-PnPClientSideWebPart Component "SiteClassification" Section 1 Column 2 Page $p

Such a script would typically be run in an automated fashion by a “remote timer job” – that is, a background job that runs outside of SharePoint.


Users request sites by adding an item to a list in SharePoint. Any kind of workflow can be used for approval, such as a Microsoft Flow or Azure Logic App. When a request is approved, the workflow either uses the SharePoint approval mechanism or copies the request to a 2nd list where end users don’t have access – the idea is to prevent a clever user from approving his or her own request. I have one client who uses this both on premises and in SharePoint online; the workflow actually decides which list to copy the request to based on business rules, and timer jobs on prem and online create the site where it belongs.

Here a remote timer job looks for items which are approved and not yet provisioned, and it provisions them. An Azure Function or Web Job is a good place for it to run; it could be written in PowerShell or .NET.

Ultimately, the timer job calls the PowerShell script to provision the Office 365 Group and do other setup. The advantage of having the timer job call PowerShell is so it’s easy to test and update the script without changing the timer job or installing any code. There might be several different scripts which are run to create sites with different lists and web parts, depending on the uses needed.

If you’re going to automatically deploy your own SharePoint Framework solutions, you need to make them appear in all sites since there is no automated way to add an “app” to the site. This is accomplished by setting a flag in your package.json file, so “skipFeatureDeployment” is true. This tells SharePoint to automatically deploy your solution, but to skip running Feature Framework provisioning logic (which requires the app to be installed by a site administrator). That means that it’s your responsibility to deploy any lists, libraries, etc. in your provisioning code, or in the web part itself, rather than using the Feature Framework.

For more depth on site provisioning, see this session:

THR3025 – Eric Overfield – SharePoint provisioning success with PnP PowerShell

Here are the links to resources you need to get started:

4. Classify your documents

Office 365 labels are the 1st line for document classification. They work in Exchange and SharePoint, which is awesome because users can classify email and documents in exactly the same way, and enterprises can set up retention schedules for both, all in one place.

However sometimes companies need more than what labels can provide. In SharePoint, this has traditionally been provided by content types. Although content types can have attached policies, such as retention schedules, Microsoft now recommends using labels for this. Still, there are lots of reasons to use content types, not the least of which is to provide consistent metadata for documents across all sites.

There is a gap in Microsoft’s content type story, however. Content types can be managed centrally from a content type hub, which publishes them to every site. That’s a great start, but it’s left to end users to set each document library and list to include the needed content types! This is not especially intutitive – lots of clicks. And it can’t really be done during site provisioning because it takes a while for the content type hub publishing to work, so the content types aren’t available until well after the provisioning process ends.

The solution is to write a remote timer job that scans all sites, looks for document libraries and lists that need content types, and adds them in programatically. While this is inevitably a developer task, it is greatly facilitated by another great component of Patterns and Practices: the Remote Timer Job Framework.

This incredibly useful framework allows you to write a console application that does the work of the timer job. The Remote Timer Job Framework iterates through each site collection that matches a wildcard pattern – for example /sites/project*. It then hands your code an open, authenticated ClientContext object for each site, so you can focus on doing the work you need to do. It even handles multi-threading, so you can update several sites at the same time; this is really useful if you’re doing updates that take a while to run.

The Remote Timer Job Framework is your key to content curation of all kinds! Any kind of background processing you want to do on your SharePoint content is well addressed by the Framework. The only caveat is it only really applies when you’re going through a lot of sites; the site provisioning “remote timer job” from the previous section did not use this framework because it checks a single list in a single location, and wouldn’t benefit from the Remote Timer Job Framework’s ability to go through all your sites.

In this case, I showed a remote timer job that checks each site to see if the content types have been received from the Content Type Hub, and if they have, it pushes them into any document libraries that don’t already have them.

Once that’s done, it may be useful to facilitate the use of content types. It’s only 3 or 4 clicks in the modern document library UI, but it’s still likely to be confusing to end users who have no clue what a “content type” is. To that end, I showed a simple “Command set” SharePoint Framework extension which provides menu items for setting known content types. This reduces the number of clicks, and the need for end users to understand content types.


This is a project I’ve done several times along with my teammates at BlueMetal. Every one is a little different, based on the client’s industry, policies, and enterprise culture. However to date we’ve used classic team sites because it simply wasn’t possible with modern SharePoint. Now, with tenant-scoped SPFx solutions and additions to PnP PowerShell, we can build an entirely modern solution that makes compliance easy.

Every company in a highly regulated industry should go through these 4 steps. Some may find they can use “out of the box” features exclusively, but most will need more. The folks at Microsoft have provided the tools through the SharePoint Framework and PnP.

BlueMetal can help you make it happen! Please reach out to me in the comments and let me know how we can help – if you leave an email address and let me know it’s not a public comment, I’ll get back to you and won’t publish the comment. I’d also like to see comments about how to improve on this, or how you’ve addressed compliance in your team sites.

Thanks for reading and for attending (or watching) the session!





One thought on “Building Compliant Team Sites

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s