Microsoft Graph API allows you to work with all the Microsoft 365 content – including search through Exchange e-mail messages, Yammer (Viva Engage) and Teams chat messages and surely OneDrive and SharePoint content (please refer to the MS’s original doc). After we got a registered Azure app configured correctly, including Authentication and API permissions provided (more on this) – we should be ready to authenticate and call Graph API on behalf of a user.
Let me focus on searching in SharePoint Online and OD here but you can use the same technique to search through other Microsoft 365 services. I will use PowerShell but same ideas should work for other platforms/languages – Python, C#, node.js etc.
Let us authenticate first. We’d need a MSAL.PS module for that.
# Ensure we have MSAL.PS module installed
Get-Module MSAL.PS -ListAvailable | ft name, Version, Path
# Install-Module MSAL.PS -Force -Scope CurrentUser -AcceptLicense
Import-Module MSAL.PS
# Authenticate to Microsoft Interactively
$clientid = 'd82858e0-ed99-424f-a00f-cef64125e49c' # your client id
$TenantId = '7ddc7314-9f01-45d5-b012-71665bb1c544' # your tenant id
$token = Get-MsalToken -TenantId $TenantId -ClientId $clientid -Interactive
$headers = @{Authorization = "Bearer $($token.AccessToken)" }
Below is how I search Microsoft 365 content programmatically from PowerShell using MS Graph API being authenticates as user:
# Search
# MS Graph Search API url (beta or v1.0):
$apiUrl = "https://graph.microsoft.com/beta/search/query"
# specify where to search - entity types
$entityTypes = "['driveItem','listItem','list','drive','site']"
$entityTypes = "['driveItem','listItem']"
# query
$query = "test*"
# build a simple request body
$body = @"
{
"requests": [
{
"entityTypes": $entityTypes,
"query": {
"queryString": "$query"
}
}
]
}
"@
# call Graph API:
$res = Invoke-RestMethod -Headers $Headers -Uri $apiUrl -Body $Body -Method Post -ContentType 'application/json'
# explore returned object
$res.value[0].searchTerms
$res.value[0].hitsContainers[0].hits
$res.value[0].hitsContainers[0].hits.Count
$res.value[0].hitsContainers[0].moreResultsAvailable
I used “beta” search API to research or make demos, but in production code youd stick with “v1.0”.
You can scope search down using entity types – ‘driveItem’,’listItem’,’list’,’drive’,’site’. “driveitem” here represents document library.
In query you can use KQL.
Always check if more results available with “$res.value[0].hitsContainers[0].moreResultsAvailable”. If there are more results and you need them – consider looping using paging technique.
Pingback: Search Microsoft 365 content programmatically ⋆ Microsoft 365 engineering
I keep getting a bad request and am using your code verbatim. Any suggestions? I have all the correct app permissions and other details needed are correct as well (tenant, client, secret).
$apiUrl = “https://graph.microsoft.com/beta/search/query”
$entityTypes = “[‘driveItem’,’listItem’,’list’,’drive’,’site’]”
$query = “test*”
$body = @”
{
“requests”: [
{
“entityTypes”: $entityTypes,
“query”: {
“queryString”: “$query”
},
“region”: “NAM”
}
]
}
“@
$res = Invoke-RestMethod -Headers $Headers -Uri $apiUrl -Body $body -Method Post -ContentType ‘application/json’
Results in:
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
Using the same authentication method and header, I’m able to list out all of the sites with the following code:
$URI = “https://graph.microsoft.com/v1.0/sites”
$WebRequest = Invoke-WebRequest -Headers $headers -Uri $URI
$Result = ($WebRequest.Content | ConvertFrom-Json).Value
write-host $result
That said, I don’t believe its the headers, but perhaps the body?
Yes, please refer to https://github.com/VladilenK/m365-PowerShell/tree/main/KBA/Search
and do not reformat the body part… also ensure your region code…