skip to Main Content

I am trying to retrieve users orderby createdDateTime, but the Graph API doesn’t seem to like it

This fails with a (400) Bad Request:

https://graph.microsoft.com/beta/users?`$select=displayName,userPrincipalName,mail,id,createdDateTime,signInActivity,userType&`$top=100&`$orderby=createdDateTime desc

Whereas order by displayName works just fine:

https://graph.microsoft.com/beta/users?`$select=displayName,userPrincipalName,mail,id,createdDateTime,signInActivity,userType&`$top=100&`$orderby=displayName desc

My API permissions are fine in that i can see createdDateTime in the results of the secondary query.

If this is not possible via this method, what is the best way to get the last thousand users to sign up?

2

Answers


  1. It’s an advanced query which requires ConsistencyLevel:eventual request header and the query parameter $count set to true.

    GET https://graph.microsoft.com/beta/users?`$select=displayName,userPrincipalName,mail,id,createdDateTime,signInActivity,userType&`$top=100&`$orderby=createdDateTime desc&`$count=true
    ConsistencyLevel: eventual
    

    I suppose you are trying to make a request from PowerShell and you are escaping $ with `$

    Login or Signup to reply.
  2. There are two classifications of queries which you can make for directory objects using the Geaph API.

    Basic queries comprise standard functions, such as $filter, $select, $top and $orderby. However, there are a number if scenarios where a query may not be considered basic even when only using these.

    Advanced queries are deemed to be those which require a more complex approach to building results. This could be for queries which require aggregation, are a distributed transaction (requiring coordination across multiple systems) etc.

    As per this table you’ll see that sorting results on creationDateTime property for user objects renders your query an advanced query. From your perspective, it shouldn’t matter much whether the query is advanced or basic, but advanced queries require specification of a consistency level.

    Azure AD relies on a distributed datastore, due the nature of its global presence. With this distributed "database" [loosely defined] there are multiple copies of the same data, which are replicated, even across different continents, in most cases (with exception to government instances).

    Behind the scenes, a multi-master replication mechanism ensures that the separate copies of data are kept in alignment with eachother. Multi-master referred to the ability to write to either or any copy and the new or updated data will be replicated to the others.

    As of writing, the only published consistency level available in Graph is eventual. So, why are we required to specify it if there is only one available option? It is for developers and administrators to indicate their intent, and their awareness that the results provided by the API may not reflect the most up-to-date data across all instances of it. Some of these might be reading this answer now, figuring out the what and the why.

    Graph will typically query a copy of the data which is [relatively] local to it.

    Let’s say you are in the US, and your company has a branch in the UK. An admin in the UK creates a new user. You have an app or a script which queries Graph for the last 100 users created, shortly after. Due to replication latency, it is possible that your query will not return the user created in the UK.

    Unless you need to cater for some very niche or specific scenario, you’re unlikely to need to be concerned about this latency. Reports of layency-related issues are not very common.

    The $count=true query parameter basically instructs the API to include an @odata object in the response, in case Graph determines that pagination of the results (breaking down the response in to multiple accessible subsets) is deemed appropriate or necessary.

    Back to how you overcome this Bad Request (400) issue. I am assuming based on your inclusion of backticks in your quoted request URIs that you’re using PowerShell, so please see my example below on how to call Graph beta using the required query parameters and ConsistencyLevel header:

    # Token acquisition logic should go here. You may be using MSAL PowerShell module, or other. Adapt as necessary.
    $accessToken = "XXXXXXXX..."
    
    # Define Graph API endpoint and parameters
    $graphEndpoint = "https://graph.microsoft.com/v1.0/users"
    $queryParams = "?" `
        "`$select=displayName,userPrincipalName,mail,id,createdDateTime,signInActivity,userType&" `
        "`$top=100&" `
        "`$orderby=createdDateTime desc&" `
        "`$count=true"
    
    # Construct headers
    $headers = @{
        "Authorization" = "Bearer $accessToken"
        "ConsistencyLevel" = "eventual"
    }
    
    # Make the request to Graph API
    $response = Invoke-RestMethod -Uri "$($graphEndpoint)$($queryParams)" -Headers $headers -Method Get
    
    # Output the response
    $response
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search