Tag Archives: Office 365

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

Hide User Accounts from Microsoft 365 People Search

Update from Mar 5, 2023: Microsoft confirmed this as valid solution.

Scenario

You want specific users do not appear in Microsoft 365 SharePoint, Teams or Delve search results.

Solution

Set “ShowInAddressList” Azure AD User object property to false. If users are synchronized from local AD – set AD property instead.

Detailed

In many cases we do not need some accounts appear in Microsoft 365 Search. Examples of are:

a) secondary/admin accounts
e.g. a person have several roles and several accounts under the same name, e.g.
regular user: John Smith John.Smith@contoso.com
administrative account: John Smith John.Smith.2@contoso.com
b) role, shared or service accounts
c) non-mail-enabled objects
d) disabled accounts

Getting multiple results for the same one person might confuse users and even lead to miscommunication and broken processes.

There is a good article by Tania Menice (Microsoft): Exclude Users From Delve and SharePoint Online People Search with the latest updates explaining how it is done for classic search and stating that currently it is not possible for modern search, but Microsoft is working on it.

Basically, the article says:

  • Set the profiles AD property msExchHideFromAddressLists to True or Yes,
  • Sync/wait, so finally SharePoint UPA service SPS-HideFromAddressLists property will be set (msExchHideFromAddressLists AD property is mapped to the UPA SPS-HideFromAddressLists)
  • Under SharePoint classic search – update query:
    {searchboxquery} to {searchboxquery} -“SPS-HideFromAddressLists”:1

It works perfect for classic search. The problem is it does not work as expected in modern Microsoft Search.

“People” vertical is not customizable so far. So we cannot change query in Microsoft 365 search to do the same trick. But… it seems like Microsoft is working on it so finally it should be done by ootb means.

Here is the current situation on how different services or search entry points respect SPS-HideFromAddressLists property:

Microsoft 365 Service or Search Entry pointrespect SPS-HideFromAddressLists
(msExchHideFromAddressLists)
web Outlook “New message” user pickerYes
web Outlook “Contacts”Yes
Office.com “All” verticalYes
Office.com “People” verticalNo
SharePoint landing page “All” verticalYes
SharePoint landing page “People” verticalNo
Bing Work All VerticalYes
Bing Work People VerticalYes

So only “People” vertical in Microsoft search does not respect SPS-HideFromAddressLists (msExchHideFromAddressLists).

What about cloud-based accounts (not synchronized from local AD)?

There is a configuration setting “Show in global address list” that does the same job. It’s under Microsoft 365 admin center -> Active Users -> User – Edit -> Mail -> Show in global address list:

And another configuration settings “Hide from global address list (GAL)” under Exchange Admin Center:

Here are experiment results:

User Account12345
EnabledYesNoYesYesYes
Licensed (E5)NoYesYesYesYes
m365 Admin Center: Show in Global Address Listn/aNoNoYesNo
Exchange Admin Center: Hide from global address list (GAL)n/aYesYesNoYes
Get-AzADUser -UserPrincipalName <upn> -Select ShowInAddressList -AppendSelected | Select-Object UserPrincipalName, ShowInAddressListnullnullnullnullFalse
SPO UPA ‘SPS-HideFromAddressLists‘ valueFalseFalseFalseFalseTrue
Outlook Address List “All Users” Shown
Office.com Search: Vertical “All”Shown
Office.com Search: Vertical “People”ShownShownShownShown
Bing Work Search: All/People verticalsShownShown
Teams Search: “All” VerticalShownShown
Teams Search: “People” verticalShownShownShownShown
Microsoft 365 Profile card – OrganizationShownShown
Teams Profile card – OrganizationShownShownShownShown
Teams People PickerShownShownShownShown
SharePoint People PickerShown
Outlook People Picker:Shown
* – some users can see changes after hours, for some it takes days

It seems confusing we have properties:

  • “Show in Global Address List” under m365 Admin Center
  • “Hide from global address list (GAL)” under Exchange Admin Center
  • “ShowInAddressList” Azure AD User object property
  • “SPS-HideFromAddressLists” SharePoint User Profile property

Are these properties related to each other?

Let’s test it:

Action-Consequences
(immediate reaction – minutes if not other mentioned)
“Show in Global Address List”
under m365 Admin Center
“Hide from global address list (GAL)”
under Exchange Admin Center
“ShowInAddressList”
Azure AD User object property
“SPS-HideFromAddressLists”
SharePoint User Profile property
New user created, license assignedYesOffnullFalse
Uncheck “Show in my organization address list” under Microsoft 365 admin centerNoOnafter one minute: null
after 24 hours:
null
after one minute:
False
after 24 hours:
False
Set “ShowInAddressList”
Azure AD User object property to “True”
YesOffTrueFalse
Set “ShowInAddressList”
Azure AD User object property to “False”
NoOnFalseTrue

Note: Az module works fine too. I.e. Get-AzADUser instead of Get-AzureADUser and Set-AzADUser instead of Set-AzureADUser.

Findings:

  • “Show in Global Address List” under m365 Admin Center and “Hide from global address list (GAL)” under Exchange Admin Center – same switch, i.e. if you change one – another is updated automatically
    Neither of them affect “ShowInAddressList” Azure AD User object property or “SPS-HideFromAddressLists” SharePoint User Profile property
    and vise versa (???)
  • “SPS-HideFromAddressLists” SharePoint User Profile property is not changeable.
    If you try to change the property value you get an error message:
    Set-PnPUserProfileProperty : Property Not Editable: This property can not be modified.
  • “ShowInAddressList” Azure AD User object property is editable and synchronized to “SPS-HideFromAddressLists” SharePoint User Profile property (takes minutes)
    but then search crawler must pick this change up (takes hours) to hide/show the user
  • here Microsoft says: regarding showInAddressList – Do not use in Microsoft Graph. Manage this property through the Microsoft 365 admin center instead. Represents whether the user should be included in the Outlook global address list. See Known issue.
  • Known issue (Microsoft): showInAddressList property is out of sync with Microsoft Exchange. When querying users through Microsoft Graph, the showInAddressList property may not indicate the same status shown in Microsoft Exchange. We recommend you manage this functionality directly with Microsoft Exchange through the Microsoft 365 admin center and not to use this property in Microsoft Graph.

Bottom line

Setting “ShowInAddressList” Azure AD User object property to “false” is the most effective way to hide user account from search, but it could be changed only through API e.g. via PowerShell and Microsoft’s vision is unclear.

References

Testing Sites.Selected SharePoint and MS Graph API

Sites.Selected MS Graph API permissions were introduced by Microsoft in March 2021. One year later, in 2022 they added SharePoint Sites.Selected API permissions.

Azure registered app with SharePoint and MS Graph API Sites.Selected permissions

Why is this so important? Because MS Graph API for SharePoint is still limited and cannot cover all possible needs. I’d estimate: 90% of applications use SharePoint CSOM, so developers have to use AppInv.aspx to provide permissions for their applications to SharePoint API.

But from this moment – having SharePoint API permissions in MS Graph – in theory – we can fully rely on permissions provided in Azure and – in theory – this should allow us disable SharePoint-Apps only principal:

Set-SPOTenant -DisableCustomAppAuthentication $true

My math professor taught me: “before trying to find a solution – ensure the solution exists.” So let us test:

Are we really able to work with a specific SharePoint site using MS Graph and SharePoint API Sites.Selected permissions provided via Microsoft Azure?

What will happen with our new/legacy applications if we disable SharePoint app-only SPNs (DisableCustomAppAuthentication)?

I’m getting controversial test results… maybe PnP.PowerShell 1.10 is not fully support SharePoint Sites.Selected API.

Tech Wizard (Sukhija Vikas) on March 20, 2022 in the article “SharePoint and Graph API APP only permissions for Selected Sites” suggests using pre-release (AllowPrerelease).

So please ignore the following for a while.

Meantime I’ll test providing SharePoint Sites.Selected API permissions via Graph API call.

(wip) Test set #1: Certificate vs Secret

DisableCustomAppAuthentication: $false (SP-app-only spns are enabled).
All applications have “write” access provided to a specific site only.
Connecting with Connect-PnPOnline and then test access with Get-PnPSite

App / Get-PnPSiteSecretCertificate
ACS based (Azure+AppInv)OKThe remote server returned an error: (401) Unauthorized.
MS Graph API Sites.SelectedThe remote server returned an error: (403) Forbidden.The remote server returned an error: (401) Unauthorized.
SharePoint API Sites.SelectedOKOK
MS Graph API + SharePoint API Sites.SelectedAccess is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))OK
App with no permissionsThe remote server returned an error: (403) ForbiddenThe remote server returned an error: (401) Unauthorized

(wip) Test set #2: Sites.Selected SharePoint vs MS Graph (secret)

  • DisableCustomAppAuthentication = $false
    (SP-app-only spns are enabled).
  • All applications have “write” access provided to a specific site only.
  • Using Client Secret (not a certificate)
  • Using PnP.PowerShell
Action/ViaSharePoint + MS Graph
Sites.Selected
“secret”
SharePoint
Sites.Selected
“secret”
MS Graph
Sites.Selected
“secret”
Connect-PnPOnlineWARNING: Connecting with Client Secret uses legacy authentication and provides limited functionality. We can for instance not execute requests towards the Microsoft Graph, which limits cmdlets related to Microsoft Teams, Microsoft Planner, Microsoft Flow and Microsoft 365 Groups.WARNING: Connecting with Client Secret uses legacy authentication and provides limited functionality. We can for instance not execute requests towards the Microsoft Graph, which limits cmdlets related to Microsoft Teams, Microsoft Planner, Microsoft Flow and Microsoft 365 Groups.WARNING: Connecting with Client Secret uses legacy authentication and provides limited functionality. We can for instance not execute requests towards the Microsoft Graph, which limits cmdlets related to Microsoft Teams, Microsoft Planner, Microsoft Flow and Microsoft 365 Groups.
Get-PnPSiteOKOKThe remote server returned an error: (403) Forbidden.
Get-PnPListOKOK
Get-PnPListItemOKOK
Set-PnPSiteAttempted to perform an unauthorized operation.
Set-PnPListAttempted to perform an unauthorized operation.
Set-PnPListItemOKOK
New-PnPListAccess is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
Add-PnPListItemOK

(wip) Test set #3: Read vs Write vs FullControl

DisableCustomAppAuthentication = $false
(SP-app-only spns are enabled).
All applications have Sites.Selected SharePoint and MS Graph API permissions.
Using Client Secret (not a certificate)
Using PnP.PowerShell

ReadWriteFullControl
Connect-PnPOnlineWARNING: Connecting with Client Secret uses legacy authentication and provides limited functionality. We can for instance not execute requests towards the Microsoft Graph, which limits cmdlets related to Microsoft Teams, Microsoft Planner, Microsoft Flow and Microsoft 365 Groups.WARNING: Connecting with Client Secret uses legacy authentication and provides limited functionality. We can for instance not execute requests towards the Microsoft Graph, which limits cmdlets related to Microsoft Teams, Microsoft Planner, Microsoft Flow and Microsoft 365 Groups.WARNING: Connecting with Client Secret uses legacy authentication and provides limited functionality. We can for instance not execute requests towards the Microsoft Graph, which limits cmdlets related to Microsoft Teams, Microsoft Planner, Microsoft Flow and Microsoft 365 Groups.
Get-PnPSiteAccess is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
Get-PnPListAccess is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
Get-PnPListItem
Set-PnPSite
Set-PnPList
Set-PnPListItem
New-PnPList
Add-PnPListItem

(wip) Test set #5: Certificate vs Secret

C#, SharePoint CSOM, PnP.Framework

Findings

PnP.PowerShell Get-, Grant-, Set- and Revoke-PnPAzureADAppSitePermission cmdlets require Azure App with MS Graph Sites.FullControl.All app permissions (otherwise it says “Access denied”) and authentication via certificate (otherwise it says “This cmdlet does not work with a ACS based connection towards SharePoint.”)

The same actions – managing permissions for the client app to the specific site collections – could be done via Microsoft Graph Sites Permissions API using just secret-based authentication.

If an azure app does not have Sites.Selected API permissions configured – “Grant-PnPAzureADAppSitePermission” works as expected – no error messages – the output is normal – as if Sites.Selected API permissions were configured in the app. The same for Get-, -Set and Revoke-. Permissions provided for the app to the site are not effective though: Connect-PnPOnline works well, but all other commands – starting from Get-PnPSite – returns “The remote server returned an error: (403) Forbidden.”

If an app have no permissions to SharePoint – “Connect-PnPOnline” works ok, but “Get-PnPSite” return an error: “The remote server returned an error: (403) Forbidden.”

Set-PnPAzureADAppSitePermission gives an error message “code”:”generalException”,”message”:”General exception while processing”
if the site is not specified.

AppInv is not working?

Error: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

References

Testing environment

  • Microsoft 365 E5 Dev environment
  • PowerShell 7.2.2
  • PnP.PowerShell 1.10
  • “write” permissions to the specific sites for client apps were assigned via PnP.PowerShell

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

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 “spo_service@support.onmicrosoft.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.

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

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 two 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 )
  • Azure App with a certificate (Client Id + Certificate) and permissions provided via Azure (Microsoft Graph and/or SharePoint)

Error 401 while accessing SharePoint Online with PnP

(Get-PnPTenant, Get-PnPTenantSite)

Get list of new SPO sites with PowerShell

Scenario

Let say you administer Microsoft 365 SharePoint Online and you want to get a list of new SharePoint sites (e.g. sites created recently – during last day/week/month).

With GUI it’s done easily: SharePoint Admin Center -> Active Sites -> sort based on “Date Created” – done.

With PowerShell – not so simple.
“Get-PnPTenantSite” cmdlet returns a site object but the object does not have “Created” field. It’s a web property. But to get a web object – you have to connect separately to each site and get root web object to check when the web was created. For small environments it is possible, for large environments it can take days… And still not nice.
“Get-PnPTenantSite” with “-Filter” option would help, but “…Currently, you can filter by these properties: Owner, Template, LockState, Url.”

Get-SPOSite – similar experience.

Solution

Microsoft Graph API helps. It returns result in seconds and you can sort or filter results based on created date . Below are two methods: Option 1 is based on Search and filtering and Option 2 is based on Sites Search and sorting. So there are some pros and cons for each method.

Option #1: Microsoft Graph Search API.

Entry point: https://graph.microsoft.com/v1.0/search/query

Microsoft Graph Search API allows KQL in queries. So we can form a query with something like “created>=1/1/2021” and use entity type = ‘[“site”]’. Search should return only sites created after Jan 01, 2021.

Check PowerShell script sample here: Get-NewSites.ps1
https://github.com/VladilenK/PowerShell/blob/main/reports/SharePoint/Get-NewSites.ps1

If you are getting more than 500 results – think of paging.

Option #2: Microsoft Graph Sites API

Entry point: https://graph.microsoft.com/v1.0/sites

This option is also based on Microsoft Graph API, but sites entry point, which allows search too and sort results by property “createdDateTime”. So we will just search for everything and select how many results we need based on createdDateTime property.

Check PowerShell script sample here: Get-NewSites.ps1
https://github.com/VladilenK/PowerShell/blob/main/reports/SharePoint/Get-NewSites.ps1

References

Working with Yammer API from code

Post messages, read messages, get groups (communities) details and membership – etc. – all that you can do with Classic Yammer API. Here are steps:

  • register Yammer Application and generate access token
  • call API

Register Yammer Application

Navigate to the page: https://www.yammer.com/client_applications

Click “Register new application”:

Fill all the fields:

Client ID and Client secret will be generated automatically:

I’m not sure – how to get access token from Client ID and Client secret, so I use link “Generate a developer token for this application”. When you click this link, a token will be generated, and it says “Here is your personal token for testing. Please copy it somewhere safe as it will disappear when you leave the page:”

Calling Yammer API

Once you get the toke – you can use it in your code (consider vaulting or other save methods). Here is an example based on powershell, but surely you can do the same with programming language you comfortable with:

$baererToken = "Put your token here"

$headers = @{ Authorization = ("Bearer " + $baererToken) }

# get messages
$webRequest = Invoke-WebRequest –Uri "https://www.yammer.com/api/v1/messages.json" –Method Get -Headers $headers
$results = $webRequest.Content | ConvertFrom-Json

$results.messages | ForEach-Object {
    $message = $_ 
    Write-Host "Message Id:" $message.id
    Write-Host "Message body:" $message.body.parsed
}

# get users
Invoke-WebRequest –Uri "https://www.yammer.com/api/v1/users.json" –Method Get -Headers $headers | ConvertFrom-Json | select email
  

References

DepartmentId for Enterprise Intranet Portal – Home Site and Search Scope and Relevance

Scenario

Your organization use Microsoft 365. You are implementing or configuring an Intranet Portal (Home Site). Search plays an important role here – you want search be relevant to the context – i.e.

  • Official Results – if a user searches something on a company’s intranet portal – user expect “official” results, not a something from somebody’s OneDrive or Yammer chat
  • Promoted Results – so information management team can adjust search with search answers – Bookmarks, Acronyms and Q&As

Problem

Microsoft Bookmarks are working only at tenant level search – i.e. if you want bookmarks work on site level search – you need to set up site search scope as tenant.

So if you configure the Intranet Portal site (Home site) search scope to “site” or “hub” to limit results with site/hub content – you will loose “answers” functionality.

Solution

The solution is very simple:

  • Keep site search scope as tenant-wide to use answers (boormarks), and
  • Configure search verticals and query to limit results to “official” sites only

Update Query field with KQL – e.g., with something like

(path:http//contoso.sharepoint.com/sites/IntranetPortal/ OR path:http//contoso.sharepoint.com/sites/CompanyNews/ OR path:http//contoso.sharepoint.com/sites/Onboarding)/)

to get results only from “Intranet Portal” and “Company News” sites.

Keep in mind that this will affect all other SharePoint search entry points – SharePoint landing page, Office.com etc. – so although you can configure All (and Files) verticals, but it’s not recommended. It will confuse users – they expect to search for everything under “All” vertical. Instead, consider custom vertical – e.g. “Official” scope.

After configuring – It might take 1-24 hours for the change to take effect, depending on tenant size.

Service vs Site search

If you configure that 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.
Teams search will not be affected as from Teams you only search for teams content. Same for Onedrive and Yammer.

If you want the “official” search results only under Intranet Portal and leave other search entry points unaffected – then
you need to configure the same at Home (Intranet Portal) site level: Site Settings -> Microsoft Search -> Configure search settings -> Verticals
and configure site search scope to site or hub scope. But in this case you will loose answers functionality.

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

Home site is a root site

There might be two problems with that:

  1. if a home site configured as a root site – you KQL will look like(path:http//contoso.sharepoint.com/ OR path:http//contoso.sharepoint.com/sites/CompanyNews)and that query will not work as any site Url will match the root site Url.
  2. if you need to mention many sites in KQL – like 50 sites with an Official Information – you might hit the “number of allowed character” limit

The solution is DepartmentId property:

DepartmentId

Use DepartmentId={<Hub Site ID>} in the KQL qury and your search results will be limited to your hub content while answers will still be working too. You can even combine DepartmentId with other conditions to add more sites (that are not in hub) to search scope:

(DepartmentId={4965d9be-929b-411a-9281-5662f5e09d49} OR path:http//contoso.sharepoint.com/sites/Onboarding OR path:http//contoso.sharepoint.com/sites/CompanyNews)

It worth to mention, that DepartmentId is the property that propagated from the root of the hub site to all associated sites and their content – list items, documents and pages.

Site Property Bag

Another possible option would be – site property bag…
The ultimate goal is to provide users with “Official” results only. But official sites might not be all part of one Home site hub. We can include in All search vertical query 10, 50, 100 sites, but what if we have 10k official sites in enterprise – e.g. operated by different departments – and all of them might want to be present in search results.
So, how about – if the site is considered official – we create an indexed site property, e.g. “SiteIsOfficial” with a value “Yes”. Then we map the crawled property to a managed property – e.g. RefinableString89 – and use this managed search property in query – e.g. (SiteIsOfficial=Yes).

This is actually clever idea, but this does not work… This query would only return sites, not sites content. E.g. what was indexed as site object – will be included (including home page). But site items – i.a. documents, lists, other pages – all site content – will not be included…

So let’s get back to DepartmentId…

Rename All Vertical

Again – the ultimate goal is to give users option to have “Official” results. But they still might want to be able to search through all content.
What if we rename the default “All” vertical to “Home Site” and configure query for official results only.
Then we can create a custom vertical called “Everything” or “All” with no query limitations to give users all reasults

Update: not a good idea either… If the home site search scope is tenant – so verticals are configured and be visible at tenant level – i.e. everywhere…

Separate Official Vertical

My personal preference is to keep All vertical as real All, and create a custom Vertical “Official” for official results only where we would use query trick.

In addition, it would be nice to highlight results from official sources by using custom result type – check “Manage result layouts for SharePoint results in Microsoft Search

Resources: