Category Archives: Microsoft 365

Configure Site Properties and Refinable Strings for Adaptive Scopes

Microsoft recently implemented “Adaptive Scopes” for retention policies”. Before that we had to use “static” scopes only, i.e. we could apply the policy to all sites or to specific selected sites we had to choose manually. With adaptive scopes we can use rules like “This adaptive scope must include all sites with Site Url starts with A or Site name starts with A” and so on. And then we’d apply the retention policy to all the sites in this adaptive scope. This is nice, but actually site Url and site name does not have much to do with sites categorization for the retention policies. How can we implement sites classification to apply different policies to different sites categories? Luckily, when you configure adaptive scopes, you can use Refinable Strings, and refinable strings is something you can configure to have values from custom site properties. So finally we can assign specific value to custom site property and the site would fall under this or that retention policy based on the value we dynamically assigned to the site.

Note: you can also use site properties like date site created or site last modified date in advanced query builder under adaptive scopes – please check “Microsoft 365 Retention Policies SharePoint Adaptive Scopes Advanced Query“.

How to configure SharePoint custom site properties the way the retention policies adaptive scopes can consume Refinable Strings?

The steps are:

  • Create an indexed site property with values
  • Map crawled property to a refinable string managed property

Detailed steps:

Indexed site property

Create an indexed site property or “Adaptive Scope Property” with some values. Ensure you property name (key) is unique, e.g.

PropertyValue
SiteRetentionCategoryY10

You can use PowerShell (with PnP.PowerShell module) commands:
Set-PnPAdaptiveScopeProperty or
Set-PnPPropertyBagValue -Indexed:$true. Examples:

Set-PnPAdaptiveScopeProperty -Key "SiteRetentionProperty" -Value "Y10"

Wait until search crawler picked up you site property. Now you have a crawled property.

Search schema mapping

As you know, Refinable Strings are just pre-created by Microsoft refinable managed properties. So you can select one that is not used(*) and map it to crawled property.
You can assign alias so you could easily identify what is the RefinableString55 about (but aliases do not work in advanced query).

(*) Notes

select one that is not used
select one that is not used is an important, bacause if you select refinable string that is already taken at the some site level – there is a conflict. So before configuring pre-created refinable properties at tenant level – I’d recommend to get report on managed properties taken at sites levels. It would be good idea if you arrange with sites owners on properties ranges (e.g. from 00 to 99 – reserved for tenant use, from 100 to 199 – available at sites level search customizations). And/or you can – after getting report on managed properties taken at sites levels – reserve all unused managed properties by assigning aliases e.g. “this-property-55-is-reserved-by-admin-for-tenant-level-config”.

site custom script
If site custom scripts are enabled (DenyAddAndCustomizePages = false), then site collection admin can change site properties. So if you do not want the property being altered at site level – ensure that noscript site property is enabled (DenyAddAndCustomizePages equals true)

If site custom scripts are disabled (DenyAddAndCustomizePages = true), then an admin must enable them before using “Set-PnPPropertyBagValue” cmdlet (then disable again).
“Set-PnPAdaptiveScopeProperty” cmdlet handles this automatically.

References

SharePoint Search: Site vs Tenant Scope, Placeholder Text, Answers and Verticals

Service vs Site search

If you configure Verticals Query at the tenant level – i.e., Microsoft 365 Administration -> Settings -> Search and intelligence ->  Customizations -> Verticals
then search results will be trimmed everywhere  – SharePoint Landing Page, Office landing page (Office.com), Office App, Bing search (but not other sites).

Teams search will not be affected as from Teams you only search for teams content. Same for Onedrive and Yammer. Sites with site or hub search scope will not be affected too.

If you configure verticals at site level: Site Settings -> Microsoft Search -> Configure search settings -> Verticals
and want this be in effect – ensure site search scope is set to site or hub scope. But in this case you will loose answers functionality.

Global search settings – like acronyms, bookmarks and verticals – works only at tenant level search or at site leve if the site search scope is set to tenant.
If site search scope is site or hub – then site-level search verticals will apply (and no answers functionality will be possible).

Token – SharePoint API compatibility matrix

If I get token with (Graph, MSAL, PnP) and use this token for (Graph API, SharePoint CSOM API, SharePoint REST API) matrix.

An App used in this tests has Sites.FullControl.All MS Graph API and SharePoint API permissions, as well as FullControl ACS based permissions to SharePoint (AppInv.aspx).

Token/APIMS Graph
/v1.0/sites
SharePoint CSOM
PnP.PowerShell
Get-PnPSite
Get-PnPTenantSite
SharePoint REST API
PnP.PowerShell
Invoke-PnPSPRestMethod
Invoke-RestMethod
MS Graph
/oauth2/v2.0/token
secret
OK(401) UnauthorizedAudienceUriValidationFailedException
MSAL.PS
Get-MsalToken
with secret
OK(401) UnauthorizedAudienceUriValidationFailedException
MSAL.PS
Get-MsalToken
with certificate
OK(401) UnauthorizedAudienceUriValidationFailedException
PnP.PowerShell
Get-PnPAccessToken
with Certificate
OKOK
OK
OK
AudienceUriValidationFailedException
PnP.PowerShell
Get-PnPGraphAccessToken
with Certificate
OKOK
OK
OK
AudienceUriValidationFailedException
PnP.PowerShell
Get-PnPAppAuthAccessToken
with Certificate or secret
InvalidAuthenticationTokenOK
OK
OK
OK
PnP.PowerShell
Request-PnPAccessToken
with Certificate
InvalidAuthenticationTokenOK
OK
OK
AudienceUriValidationFailedException
PnP.PowerShell
Request-PnPAccessToken
with Secret
InvalidAuthenticationTokenOK
OK
OK
OK
AudienceUriValidationFailedException = Exception of type ‘Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException’ was thrown

Providing Permissions to a Site for Sites.Selected App

How to provide permissions for an Azure registered application with MS Graph SharePoint Sites.Selected API permissions to a specific site via calling Microsoft Graph API from PowerShell.

We need an “admin” application – Azure registered application with with Sites.FullControl.All MS Graph API permissions. This method can use secret, so we need Client Id and Client Secret for this “admin” app.

We also need a Client Id and Application Display Name for an Azure application with Sites.Selected MS Graph and/or SharePoint API permissions provided.

And we need our “target” site Url.

With PowerShell scripts you can:

  1. Get Microsoft Graph Access Token with an “admin” app
  2. Get client (target) site Id
  3. Get current app permissions provided to client site
  4. Add read or write permissions for the client app to the client site
  5. Revoke one specific permission from site
  6. Revoke all app permissions provided to site

– please refer to the GitHub Repo Sites.Selected

References

Sites.Selected SharePoint API brief overview and history

Sites.Selected MS Graph API permissions were introduced by Microsoft in March 2021. It was a good move towards site-level access for non-interactive (daemon) applications, but still developers were limited with only what MS Graph API provides for SharePoint. SharePoint CSOM and REST API still provides much more than MS Graph API.

So developers had to use AppInv.aspx at site level to provide ACS-based permissions to their apps to be able to use SharePoint CSOM and REST APIs. The bad news is ACS-based permissions have some downsides so some SharePoint/m365/security engineers consider them legacy and deprecated. But if we decide to disable SharePoint App-only service principals – all apps with ACS-based permissions provided via AppInv.aspx will stop working.

2021: Microsoft Graph Sites.Selected API

Microsoft Graph Sites.Selected API

Recently Microsoft introduced Sites.Selected SharePoint API permissions for registered Azure Apps! So from now developers should be fully happy with API permissions provided in Azure (without SharePoint ACS-based permissions).

2022: SharePoint Sites.Selected API

SharePoint Sites.Selected API

Why is this so important? Because this should allow us to be able to switch from ACS based permissions provided in SharePoint via AppInv.aspx to Azure-provided permissions and as a consequence – disable SharePoint-Apps only principal (‘set-spotenant -DisableCustomAppAuthentication $true’).

Why we are eager to disable Custom App Authentication in SharePoint? Simply say, SharePoint App-only service principals are not trackable (they all appeared as a “app@sharepoint.com” id in all logs) and hard to manage (there is no way to get list of existing/registered SP app-only service principals, sites and their owners) – see more in this article. (Update: there are tools – check Azure ACS retirement: Track down ACS apps).

So, SharePoint Sites.Selected application API permissions provided in Azure is a significant step to make Microsoft 365 SharePoint environment more secure and manageable.

2024: Delegated Sites.Selected Permissions

Since Feb 2024 Microsoft supports also delegated Sites.Selected permissions. Delegated Sites.Selected permissions are assigned the same way as application Sites.selected permissions – through the /permissions endpoint. You still assign only the application id and role. When the call is made the permissions are calculated either as application or delegated, and assuming the request is authorized it will go through.

2024: Granular Sites.Selected Application Permissions

Microsoft implemented granular permissions ( e.g. to a list, item or file) alongside with Sites.Selected permissions. Original implementations of Sites.Selected allowed access to entire site collection only. With new ‘Lists.SelectedOperations.Selected’, ‘ListItems.SelectedOperations.Selected’ and ‘Files.SelectedOperations.Selected’ permissions it is possible to provide application permissions to list, library or list item or particular document (reference).

Details To Be Provided…

Delegated Sites.Selected API permissions

Since the beginning of 2024 Microsoft supports Delegated Sites.Selected API permissions. This is to support security best practices – the minimally possible access should be provided. I.e. the idea is: even Sites.FullControl.All delegated permissions allows access not to all sites, but to sites current user was provided access to, it would be a good idea to restrict access with only sites this specific app is required access to. That’s good.

More on the Sites.Selected:

References

Connecting to SharePoint Online programmatically: Secret vs Certificate

Update: Sites.Selected API MS Graph permissions was introduced by Microsoft in 2021. It was a good move towards site-level development, but still developers were limited with only what MS Graph API provides for SharePoint dev.
So devs had to use AppInv.aspx at site level to provide ACS permissions to their apps to be able to use SharePoint CSOM and REST APIs.
Recently Microsoft introduced Sites.Selected SharePoint API permissions for registered Azure Apps! So now devs should be fully happy without ACS-based permissions.

Scenario

You have an application that needs access to Microsoft 365 SharePoint Online site/list/documents. Application is running without interaction with users – e.g. unattended, as daemon job.

There are two options you can authenticate to Microsoft 365 – with the secret or with the certificate. Authenticating with certificate is considered more secure.

Questions

  • What happens if SharePoint-Apps only principal is disabled
    (i.e. ‘set-spotenant -DisableCustomAppAuthentication $true’ )?
  • Why I’m getting 401 error when authenticating to SPO?
  • Why I’m getting 403 error when authenticating to SPO with secret?
  • What permissions to I need to work with SPO?

Findings

Note: we will use PowerShell 7.2 and PnP.PowerShell 1.9 to illustrate it.

Disabled SharePoint-Apps only principal

If SharePoint-Apps only principal is disabled in your tenant
(i.e. ‘Get-PnPTenant | select DisableCustomAppAuthentication’ returns $true ), then the only way you work with SPO from code is:

  • an App registered in Azure
  • API permissions provided via Azure (MS Graph, SharePoint)
  • Certificate is used

In all other cases (even your Connect-PnPOnline command complete successfully) – you will be getting error 401 (unauthorized) when trying Get-PnPTenant or Get-PnPTenantSite or Get-PnPSite

Enabled SharePoint-Apps only principal

If SharePoint-Apps only principals are enabled in your tenant
(i.e. ‘Get-PnPTenant | select DisableCustomAppAuthentication’ returns $false ), then you have three options to work with SPO from code:

  • Azure App with a secret (Client Id + Client Secret) and permissions to SharePoint provided via SharePoint (AppInv.aspx) to access SharePoint REST API
  • Azure App with a certificate (Client Id + Certificate) and permissions provided via Azure to access SharePoint REST API
  • Azure App with a certificate or secret (Client Id + Secret or Certificate) and permissions provided via Azure to access SharePoint via Microsoft Graph API