Category Archives: Software

Who is Microsoft forms form owner

It is a very common situation in Microsoft 365 when someone creates a form and the form works perfectly, but then the form stopped working and nobody knows who was (or who is) this Microsoft form owner. Below is how to detect the form owner based only on existing form link. You can find out is it a group or a user.

How to find Microsoft forms form owner

the steps are:

  1. Use form link

You can use collaborator form link that looks like:
https://forms.office.com/Pages/DesignPage.aspx?FormId=<formId>
or responder form link that looks like: https://forms.office.com/Pages/ResponsePage.aspx?id=<formId>
(or short one: https://forms.office.com/r/kDKaHDauj7)

so just follow the link (use it in your browser)

2. Open browser developers tool – just hit F12 in browser or select “open developer tool” from menu. Inspect the network traces.
You need to find a request Url that starts with
https://forms.office.com/formapi/api/…
(you can use filter as below for “formapi”).
You’d refresh your page, or complete and submit the form until this url appears under network traces like this:

Then copy request Url to notepad as text. Bingo!
In the url example below:
https://forms.office.com/formapi/api/tc05faac-c82a-5b9d-b0c5-1f64b6755421/groups/f28f8c19-52cb-435c-948c-4c5619c943b7/forms…

The “tc05faac-c82a-5b9d-b0c5-1f64b6755421” id is the form owner’s tenant id
“/groups/” indicates that this specific form is owned by group, and
the “f28f8c19-52cb-435c-948c-4c5619c943b7” is the owner group id in EntraId

In case the form is owned by user, the Url would look like
https://forms.office.com/formapi/api/tc05faac-c82a-5b9d-b0c5-1f64b6755421/users/f6351c57-e247-528e-90ab-5i3d50c235b6
where
“/users/” indicates that the form belongs to a user and
“f6351c57-e247-528e-90ab-5i3d50c235b6” is the id of the user who owns the form

This hack works also for users who already left the company (account is disabled).

Note:
If you have an SSO in your org and cannot find this call under network – try different browser or incognito mode or logging out before the call – as what you need appears at early stages – even before authentication or when you submit the form

Some other tricks:

Having a collaborator or long responder link – I can say the form is owned by a person if the form id is 80 characters length, and the form is owned by group – if the form id is 88 characters length

References

Microsoft 365 SharePoint Archive: deep dive

Microsoft announced SharePoint Archive in 2023 and make the feature generally available in Apr 2024. Though there are good Microsoft’s articles on how to enable and configure SharePoint Archive, as well as some FAQ pages, there are still a lot of questions regarding behavior details, e.g.

  • what happens with Team content if the group-based site is Archived
  • is there an API or how do we archive/restore sites programmatically
  • would MS Graph Search API work for archived sites

I have just activated the feature and I’m planning updating this page with my gotchas and findings…

Reactivation fee

How much is to restore a site from Archive?
In the example below Microsoft charges me $1 to restore a simple OotB site with no documents:

This amount is based on the retail price for reactivations. Your actual charges may be lower, and can be seen in Microsoft 365 Archive bill

Microsoft says “This amount is based on the retail price for reactivations. Your actual charges may be lower, and can be seen in Microsoft 365 Archive bill.”

Reactivate site. 

You'll be charged a reactivation fee. This reactivation fee is based on the retail price for reactivations. Your actual charges may be lower, and can be seen in Microsoft 365 Archive bill.

The site will move back to Active sites page and start consuming active storage. This action can't be cancelled once it starts.
Estimated reactivation fee
$1

Another confirmation is requested:

Reactivate site.

You’ll be charged a reactivation fee. This reactivation fee is based on the retail price for reactivations. Your actual charges may be lower, and can be seen in Microsoft 365 Archive bill.

The site will move back to Active sites page and start consuming active storage. This action can’t be cancelled once it starts.
Estimated reactivation fee
$1

Reactivation request submitted
It will take up to 24 hours for the site to reactivate and move to the active sites page

===========

To be continued…

The site is archived

Microsoft recently (Apr 2024) announced general availability for it’s new SharePoint Archive feature (learn more). So if you are seeing “The site is archived” and “A SharePoint Administrator archived this site. If you need access, ask an admin to reactivate it.” error message and the page in your browser is “sharepointerror.aspx?scenario=SiteArchived” then… guess what… your site was archived.

And if you need this site – please reach your SharePoint admin as soon as possible, as reactivating the site within 7 days is free, otherwise it might cost your company some dollars.

Though the page Url is “https://yourtenant.sharepoint.com/_layouts/15/sharepointerror.aspx?scenario=SiteArchived” and the page title is “Error”:

this is not an error but just a new SharePoint feature 🙂

Dealing with Ownerless Groups in large Microsoft 365 environments

WIP

Scenario

Let say you administer a large Microsoft 365 environment (e.g. ~100k+ users and/or ~50K+ sites) and after some years you have a lot of ownerless groups and sites (around 5k probably), and a lot of inactive groups and sites (maybe 15k). You are getting more and more ownerless groups – dozens each week. You are thinking of stopping bleeding and cleaning this up…

Out-of-the-box we have Microsoft 365 groups expiration policy and Microsoft 365 ownerless groups policy. You might also have some 3-rd party tools implemented – e.g. ShareGate, SysKit Point.

If you do not care – you might just activate both OotB Microsoft policies – via GUI – they are simple to activate. But once you activated policies – they will trigger thousands of emails. Now imagine a person is getting dozens of emails asking him/her to be an owner or to renew the group that probably he/she has no idea about… What will happen next? People will probably ignore these alerts. Then? Groups and sites will be automatically deleted. And then? Right, there will be a huge noise and many angry users and high-priority tickets and you will have to restore sites/teams and finally you’ll have to deal with all that mess manually.

So, what is the right way to clean-up a large Microsoft 365 environment from ownerless and inactive teams, groups sites? Not a trivial question, hah?

Solution

Disclaimer: I’m sharing here my personal opinion with no obligations or warranty etc., so you’d dig into all the technologies used and based on your particular situation build your own plan. But my personal opinion is based on my 15+ years experience with SharePoint, including really large environments.

Note: It is always a good idea to discuss your plans with you org’s communication team and helpdesk/service-desk to adjust clean-up activities with other initiatives and let other people be prepared.

High-level steps for group-based Sites:

  • consider implementing Minimum 2 owners per group policy to stop bleeding. Currently Microsoft 365 does not have such functionality, so consider 3-rd party tool like SysKit Point or custom PowerShell script that sends notifications
    • apply this policy to groups where you already have 2+ owners – it’ll be safe
    • apply this policy to all other groups by chanks
  • consider custom PowerShell clean-up, e.g. you can simply delete groups with no owners and no members and/or inactive groups with no content and/or groups that are inactive for a long time (this must be aligned with business and legal)
  • implement Microsoft’s Ownerless groups policy in “Clean-Up” configuration; there are some tricks and gotchas worth a separate post, but in short
    • avoid scoping down this policy via people (security groups)
    • implement it for all groups all users with 6-7 weeks and custom e-mail template
  • implement Microsoft groups expiration policy in “Clean-Up” configuration… again, there are a few different strategies – see this article
  • change Microsoft Ownerless groups policy configuration to a “Permanent” mode configuration set
  • change Microsoft 365 groups expiration policy with a “Permanent” mode configuration

Note: There will always be ownerless groups in large environment. We have to live with it.

All above was mostly about group-based sites (as we have OotB Microsoft policies for groups), but we probably have the same problem (or even worth) with standalone sites (that would be a separate topic).

You cannot use Power BI to visualize this list issue

If you are working with SharePoint Online list and select Integrate – Power BI – Visualize the list, but it gives you error message “You cannot use Power BI to visualize this list”, “Looks like the feature for visualizing lists is turned off. Please contact your admin to enable this feature”:

You cannot use Power BI to visualize this list

The issue appears to be not in SharePoint, but in Power BI. Note it says “You cannot use Power BI to visualize this list” and “Looks like the feature for visualizing lists is turned off. Please contact your admin to enable this feature.”

Also the url of this page is Power BI Url:
“https://app.powerbi.com/sharepointlist?spListId=%7Bd3b56”, so you’d need contact Power Platform Administrators, not SharePoint administrators.

Power BI administrator would go to Microsoft Fabric Admin portal

and ensure “Integration with SharePoint and Microsoft Lists” is Enabled for the entire organization or for specific security groups. In the last case – ensure user who is getting “You cannot use Power BI to visualize this list” is added to at least one of the groups but not added to “Except specific groups”.

If the user is allowed under “Integration with SharePoint and Microsoft Lists” so “Users in the organization can launch Power BI from SharePoint lists and Microsoft Lists. Then they can build Power BI reports on the data in those lists and publish them back to the lists.” then, normally, user would see:

and something like:

Calling Microsoft Graph API from Python

Below is how I authenticate and call Microsoft Graph API to work with SharePoint from Python application.

Plain

no MSAL or Azure libraries used:

import requests
import json
from secrets import clientSc 

clientId = "7e60c372-ec15-4069-a4df-0ab47912da46"
# clientSc = "<imported>" 
tenantId = "7ddc7314-9f01-45d5-b012-71665bb1c544"

apiUri = "https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/token"

body = {
    "client_id"     : clientId,
    "client_secret" : clientSc,
    "scope"         : "https://graph.microsoft.com/.default",
    "grant_type"    : "client_credentials" 
}

response = requests.post(apiUri, data=body)
token = json.loads(response.content)["access_token"]

graph_url = 'https://graph.microsoft.com/v1.0/sites/root'
site = requests.get(
    graph_url,
    headers={'Authorization': 'Bearer {0}'.format(token)}
)

print(site.content)
print(json.loads(site.content)["webUrl"])

secrets is a Python file where I assign client secret to variable clientSc (so my secret is not shared on github). This is ok for demo purposes but generally, you should not hard-code secrets but keep secrets somewhere safe (Vault).

MSAL

Using MSAL library to get bearer token:
https://github.com/VladilenK/m365-with-Python/tree/main/Graph-API-MSAL

References

Using Microsoft.Graph PowerShell to Search in Microsoft 365

There is a Microsoft.Graph PowerShell module provided by Microsoft which simplifies usage of Microsoft Graph API. Below is how to authenticate to MS Graph and how to search within SharePoint and Teams Microsoft 365 content using Microsoft.Graph PowerShell module.

Authentication

Interactive authentication code sample:

# Prerequisites
Get-Module Microsoft.Graph.Authentication -ListAvailable 
Get-Module Microsoft.Graph.Search -ListAvailable 

# Interactive Authentication
$clientid = '31359c7f-bd7e-475c-86db-fdb8c937548e'
$clientid = 'd82858e0-ed99-424f-a00f-cef64125e49c'
$TenantId = '7ddc7314-9f01-45d5-b012-71665bb1c544'
Connect-MgGraph -ClientId $clientid -TenantId $TenantId

For daemon app authentication we need a certificate configured in Azure App and installed on the user machine. Daemon app authentication code sample (please specify your tenant id, app (client) id and certificate thumbprint:

# App Authentication
$TenantId = ""
$clientID = ""
$certThumbprint = ""
Connect-MgGraph -ClientId $clientid -TenantId $TenantId -CertificateThumbprint $certThumbprint

Search with Microsoft.Graph

# Search
$params = @{
	requests = @(
		@{
			entityTypes = @(
				"driveItem"
			)
			query = @{
				queryString = "test*"
			}
			from = 0
			size = 50
			fields = @(
				"title"
				"description"
			)
                        region = "NAM"
		}
	)
}

$res = Invoke-MgQuerySearch -Body $params
$res.HitsContainers[0].Hits

Note: when you are calling MS Graph Search API authenticated as user – you need to remove “region” parameter.

Code samples: https://github.com/VladilenK/m365-PowerShell/tree/main/KBA/Search

Search Microsoft 365 content programmatically: all articles index

Video tutorial:

Using SharePoint REST API from Python code

Using Microsoft Graph API is a preferred and recommended way to connect to SharePoint Online and other Microsoft 365 resources programmatically from Python code. But if by some reason you are required to use classic SharePoint REST API, here is how it is done.

Prerequisites:

  • Azure Registered Application
    you must register your application in Azure and configure it properly
    • Authentication blade must be configured for authenticate as current user
    • Certificates and/or secrets must be configured for daemon app (unattended access)
  • API permissions
    your Azure app registration must have API permissions configured based on resources you need access to and authentication method chosen
    here is how to configure API permissions for your app
  • Office365-REST-Python-Client library installed

Using client Id and client secret to access SharePoint REST API from Python

Errors

Possible errors and diagnostic messages

HTTPError: 401 Client Error: Unauthorized for url…
The provided client secret keys for app … are expired. Visit the Azure portal to create new keys for your app or consider using certificate credentials for added security

Code samples at GitHub

WIP…

References