Identifying and Counting Office 365 Cloud vs On Premise Users

How do you easily identify Cloud and On Premise users in your Office 365/Azure AD instance? With PowerShell of course!

Prerequisite – Windows Azure Active Directory Module

Using the ‘get-msoluser -all’ command, you can find all your users in Office 365/Azure AD. Getting the results of which users are cloud only based, or synced via an on-premise LDAP such as Active Directory may not be easy at first glance.

If you expand out all the details possible from a user, the fields are as follows:


None of these are obvious to indicate where the account is primarily located.

After a quick comparison of an on-premise account and a cloud account, I noticed the ‘ImmutableId’ was blank for the cloud users. I found a great blog post about what the value was for here, which proved my guess – the value corresponds to the ‘objectGUID’ of the account, which cloud-only accounts don’t use.

Based on that, the rest is simple. Here’s some example commands:

get-msoluser -all | where immutableid -eq $null
Get a list of all cloud only accounts

get-msoluser -all | where immutableid -eq $null |fl
Get all cloud only accounts with all values

get-msoluser -all | where immutableid -ne $null
Get all synced on-premise accounts (e.g. DirSync, Azure AD Connect, ADFS)

get-msoluser -all | where immutableid -eq $null |measure
Show a count of how many cloud only accounts

get-msoluser -all | where immutableid -eq $null | export-csv cloudusers.csv
Export the list of cloud only accounts to a csv file

7 thoughts on “Identifying and Counting Office 365 Cloud vs On Premise Users

  1. Hey Adam,

    Good post, but unfortunately there’s one small issue – if an account was synced with DirSync or a derivative, and DirSync is then turned off, the ImmutableId remains. Thus, an account can be In Cloud but still have an ImmutableId value.


  2. Hi Chris,
    Thanks for that extra info. I guess if that was potentially the case, you could then compare your results against an on-prem get-aduser list and check for differences too.

    Worth being aware of!


  3. Hey I have a question does the -all parameter just allow get-msoluser to DISPLAY all or to GET all? Meaning if you don’t use -all but pipe the command do you get an object that contains all the users?

    1. I believe it’s a get – you can’t just run get-msoluser because it requires either the -all or -maxresults paramaters. You can then pipe this to do something else with all the records that come back as an object.

      1. I’m not quite clear on your meaning. You can run Get-MsolUser with no parameters, it just had a default of 500 records. I guess what I’m asking is if you had an environment with 1000 users and you ran Get-MsolUser | Set-MsolUser {some command} would the Set-MsolUser statement only apply to the first 500 returned or is the object returned all users, but -all and -maxusers only govern how many are displayed.

  4. Ah sorry, yes I have > 500 so can’t do the vanilla command. You won’t get any results back in that scenario, just the “Warning: More results are available. Please specify one of the All or MaxResults paramaters.”. It doesn’t get the first 500 and then drop off, it gets nothing from what I just tested.

Leave a Reply