As Azure Active Directory (Azure AD) continues to deliver more capabilities and improvements in stability, availability, and performance, Microsoft Graph also continues to evolve and scale to efficiently access the data. One way is through Microsoft Graph's increasing support for advanced query capabilities on various Azure Active Directory (Azure AD) objects, also called directory objects, and their properties. For example, the addition of not (not), not equals (ne), and ends with (endsWith) operators on the $filter query parameter.
The Microsoft Graph query engine uses an index store to fulfill query requests. To add support for additional query capabilities on some properties, these properties are now indexed in a separate store. This separate indexing allows Azure AD to increase support and improve the performance of the query requests. However, these advanced query capabilities are not available by default but, the requestor must also set the ConsistencyLevel header to eventualand, with the exception of $search, use the $count query parameter. The ConsistencyLevel header and $count are referred to as advanced query parameters.
For example, to retrieve only inactive user accounts, you can run either of these queries that use the $filter query parameter.
Option 1: Use the $filter query parameter with the eq operator. This request will work by default, that is, the request does not require the advanced query parameters.
GET https://graph.microsoft.com/v1.0/users?$filter=accountEnabled eq false
// Code snippets are only available for the latest version. Current version is 5.x
var graphClient = new GraphServiceClient(requestAdapter);
var result = await graphClient.Users.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Filter = "accountEnabled eq false";
});
<?php
// THIS SNIPPET IS A PREVIEW FOR THE KIOTA BASED SDK. NON-PRODUCTION USE ONLY
$graphServiceClient = new GraphServiceClient($requestAdapter);
$requestConfiguration = new UsersRequestBuilderGetRequestConfiguration();
$queryParameters = UsersRequestBuilderGetRequestConfiguration::createQueryParameters();
$queryParameters->filter = "accountEnabled eq false";
$requestConfiguration->queryParameters = $queryParameters;
$result = $graphServiceClient->users()->get($requestConfiguration);
Option 2: Use the $filter query parameter with the ne operator. This request is not supported by default because the ne operator is only supported in advanced queries. Therefore, you must add the ConsistencyLevel header set to eventualand use the $count=true query string.
GET https://graph.microsoft.com/v1.0/users?$filter=accountEnabled ne true&$count=true
ConsistencyLevel: eventual
// Code snippets are only available for the latest version. Current version is 5.x
var graphClient = new GraphServiceClient(requestAdapter);
var result = await graphClient.Users.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Filter = "accountEnabled ne true";
requestConfiguration.QueryParameters.Count = true;
requestConfiguration.Headers.Add("ConsistencyLevel", "eventual");
});
<?php
// THIS SNIPPET IS A PREVIEW FOR THE KIOTA BASED SDK. NON-PRODUCTION USE ONLY
$graphServiceClient = new GraphServiceClient($requestAdapter);
$requestConfiguration = new UsersRequestBuilderGetRequestConfiguration();
$headers = [
'ConsistencyLevel' => 'eventual',
];
$requestConfiguration->headers = $headers;
$queryParameters = UsersRequestBuilderGetRequestConfiguration::createQueryParameters();
$queryParameters->filter = "accountEnabled ne true";
$queryParameters->count = true;
$requestConfiguration->queryParameters = $queryParameters;
$result = $graphServiceClient->users()->get($requestConfiguration);
Using $filter and $orderby together is supported only with advanced queries.
$expand is not currently supported with advanced queries.
The advanced query capabilities are currently not available for Azure AD B2C tenants.
To use advanced query capabilities in batch requests, specify the ConsistencyLevel header in the JSON body of the POST request.
Support for filter by properties of Azure AD (directory) objects
Properties of directory objects behave differently in their support for query parameters. The following are common scenarios for directory objects:
Queries that are supported by default will also work with advanced query parameters, but the response will be eventually consistent.
The in operator is supported by default whenever eq operator is supported by default.
The endsWith operator is supported only with advanced query parameters by mail, otherMails, userPrincipalName, and proxyAddresses properties.
Getting empty collections (/$count eq 0, /$count ne 0) and collections with less than one object (/$count eq 1, /$count ne 1) is supported only with advanced query parameters.
The not and ne negation operators are supported only with advanced query parameters.
All properties that support the eq operator also support the ne or not operators.
The following tables summarize support for $filter operators by properties of directory objects and indicates where querying is supported through advanced query capabilities.
Legend
The $filter operator works by default for that property.
The $filter operator requiresadvanced query parameters, which are:
ConsistencyLevel=eventual header
$count=true query string
The $filter operator is not supported on that property. Send us feedback to request that this property support $filter for your scenarios.
Blank cells indicate that the query is not valid for that property.
The null value column indicates that the property is nullable and filterable using null.
Properties that are not listed here do not support $filter at all.
Administrative unit properties
Property
eq
startsWith
eq Null
description
displayName
isMemberManagementRestricted
scopedRoleMembers/any(s:s/id)
Application properties
Property
eq
startsWith
ge/le
eq Null
appId
createdDateTime
createdOnBehalfOf/id
description
disabledByMicrosoftStatus
displayName
federatedIdentityCredentials/any(f:f/issuer)
federatedIdentityCredentials/any(f:f/name)
federatedIdentityCredentials/any(f:f/subject)
identifierUris/any(p:p)
info/logoUrl
info/termsOfServiceUrl
publicClient/redirectUris/any(p:p)
publisherDomain
requiredResourceAccess/any(r:r/resourceAppId)
serviceManagementReference
signInAudience
spa/redirectUris/any(p:p)
tags/any(p:p)
uniqueName
verifiedPublisher/displayName
web/homePageUrl
web/redirectUris/any(p:p)
The following properties of the application entity support $count of a collection in a filter expression.
Property
eq Count 0
eq Count 1
extensionProperties/$count
federatedIdentityCredentials/$count
owners/$count
Contract properties
Property
eq
startsWith
customerId
defaultDomainName
displayName
Device properties
Property
eq
startsWith
ge/le
eq Null
accountEnabled
alternativeSecurityIds/any(a:a/identityProvider)
alternativeSecurityIds/any(a:a/type)
approximateLastSignInDateTime
deviceId
displayName
extensionAttributes/extensionAttribute1
extensionAttributes/extensionAttribute10
extensionAttributes/extensionAttribute11
extensionAttributes/extensionAttribute12
extensionAttributes/extensionAttribute13
extensionAttributes/extensionAttribute14
extensionAttributes/extensionAttribute15
extensionAttributes/extensionAttribute2
extensionAttributes/extensionAttribute3
extensionAttributes/extensionAttribute4
extensionAttributes/extensionAttribute5
extensionAttributes/extensionAttribute6
extensionAttributes/extensionAttribute7
extensionAttributes/extensionAttribute8
extensionAttributes/extensionAttribute9
hostnames/any(p:p)
isCompliant
isManaged
mdmAppId
onPremisesLastSyncDateTime
onPremisesSyncEnabled
operatingSystem
operatingSystemVersion
physicalIds/any(p:p)
profileType
registrationDateTime
trustType
The following properties of the device entity support $count of a collection in a filter expression.
The following properties of the user entity support $count of a collection in a filter expression.
Property
eq Count 0
eq Count 1
assignedLicenses/$count
onPremisesProvisioningErrors/$count
otherMails/$count
ownedObjects/$count
proxyAddresses/$count
Support for sorting by properties of Azure AD (directory) objects
The following table summarizes support for $orderby by properties of directory objects and indicates where sorting is supported through advanced query capabilities.
Legend
The $orderby operator works by default for that property.
The $orderby operator requiresadvanced query parameters, which are:
Error handling for advanced queries on directory objects
Counting directory objects is only supported using the advanced queries parameters. If the ConsistencyLevel=eventual header is not specified, the request returns an error when the $count URL segment is used or silently ignores the $count query parameter (?$count=true) if it's used.
// Code snippets are only available for the latest version. Current version is 5.x
var graphClient = new GraphServiceClient(requestAdapter);
await graphClient.Users.Count.GetAsync();
<?php
// THIS SNIPPET IS A PREVIEW FOR THE KIOTA BASED SDK. NON-PRODUCTION USE ONLY
$graphServiceClient = new GraphServiceClient($requestAdapter);
$graphServiceClient->users()->count()->get();
GET https://graph.microsoft.com/v1.0/applications?$search="displayName:Browser"
// Code snippets are only available for the latest version. Current version is 5.x
var graphClient = new GraphServiceClient(requestAdapter);
var result = await graphClient.Applications.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Search = "\"displayName:Browser\"";
});
<?php
// THIS SNIPPET IS A PREVIEW FOR THE KIOTA BASED SDK. NON-PRODUCTION USE ONLY
$graphServiceClient = new GraphServiceClient($requestAdapter);
$requestConfiguration = new ApplicationsRequestBuilderGetRequestConfiguration();
$queryParameters = ApplicationsRequestBuilderGetRequestConfiguration::createQueryParameters();
$queryParameters->search = "\"displayName:Browser\"";
$requestConfiguration->queryParameters = $queryParameters;
$result = $graphServiceClient->applications()->get($requestConfiguration);
{
"error": {
"code": "Request_UnsupportedQuery",
"message": "Request with $search query parameter only works through MSGraph with a special request header: 'ConsistencyLevel: eventual'",
"innerError": {
"date": "2021-05-27T14:26:47",
"request-id": "9b600954-ba11-4899-8ce9-6abad341f299",
"client-request-id": "7964ef27-13a3-6ca4-ed7b-73c271110867"
}
}
}
If a property or query parameter in the URL is supported only in advanced queries but either the ConsistencyLevel header or the $count=true query string is missing, the request returns an error.
GET https://graph.microsoft.com/v1.0/users?$filter=endsWith(mail,'@outlook.com')
// Code snippets are only available for the latest version. Current version is 5.x
var graphClient = new GraphServiceClient(requestAdapter);
var result = await graphClient.Users.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Filter = "endsWith(mail,'@outlook.com')";
});
<?php
// THIS SNIPPET IS A PREVIEW FOR THE KIOTA BASED SDK. NON-PRODUCTION USE ONLY
$graphServiceClient = new GraphServiceClient($requestAdapter);
$requestConfiguration = new UsersRequestBuilderGetRequestConfiguration();
$queryParameters = UsersRequestBuilderGetRequestConfiguration::createQueryParameters();
$queryParameters->filter = "endsWith(mail,'@outlook.com')";
$requestConfiguration->queryParameters = $queryParameters;
$result = $graphServiceClient->users()->get($requestConfiguration);
GET https://graph.microsoft.com/beta/groups?$filter=createdDateTime ge 2021-11-01&$count=true
ConsistencyLevel: eventual
// Code snippets are only available for the latest version. Current version is 5.x
var graphClient = new GraphServiceClient(requestAdapter);
var result = await graphClient.Groups.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Filter = "createdDateTime ge 2021-11-01";
requestConfiguration.QueryParameters.Count = true;
requestConfiguration.Headers.Add("ConsistencyLevel", "eventual");
});
<?php
// THIS SNIPPET IS A PREVIEW FOR THE KIOTA BASED SDK. NON-PRODUCTION USE ONLY
$graphServiceClient = new GraphServiceClient($requestAdapter);
$requestConfiguration = new GroupsRequestBuilderGetRequestConfiguration();
$headers = [
'ConsistencyLevel' => 'eventual',
];
$requestConfiguration->headers = $headers;
$queryParameters = GroupsRequestBuilderGetRequestConfiguration::createQueryParameters();
$queryParameters->filter = "createdDateTime ge 2021-11-01";
$queryParameters->count = true;
$requestConfiguration->queryParameters = $queryParameters;
$result = $graphServiceClient->groups()->get($requestConfiguration);
{
"error": {
"code": "Request_UnsupportedQuery",
"message": "The request uses a filter property that is not indexed",
"innerError": {
"date": "2021-06-10T19:32:01",
"request-id": "5625ba13-0c9f-4fce-a853-4b52f3e0bd09",
"client-request-id": "76fe4cd8-df3a-f8c3-659b-594274b6bb31"
}
}
}
However, it is important to note that query parameters specified in a request might fail silently.
This can be true for unsupported query parameters as well as for unsupported combinations of query parameters.
In these cases, you should examine the data returned by the request to determine whether the query parameters you specified had the desired effect. For example, in the following example, the @odata.count parameter is missing even if the query is successful.
GET https://graph.microsoft.com/v1.0/users?$count=true
// Code snippets are only available for the latest version. Current version is 5.x
var graphClient = new GraphServiceClient(requestAdapter);
var result = await graphClient.Users.GetAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.Count = true;
});
<?php
// THIS SNIPPET IS A PREVIEW FOR THE KIOTA BASED SDK. NON-PRODUCTION USE ONLY
$graphServiceClient = new GraphServiceClient($requestAdapter);
$requestConfiguration = new UsersRequestBuilderGetRequestConfiguration();
$queryParameters = UsersRequestBuilderGetRequestConfiguration::createQueryParameters();
$queryParameters->count = true;
$requestConfiguration->queryParameters = $queryParameters;
$result = $graphServiceClient->users()->get($requestConfiguration);