2

I'm using Microsoft Graph to retrieve the list of users in an organization that is using Azure AD. When I login to the Azure Portal as a global admin, and click on Azure AD-->Users it shows the list of users as follows where the last column (shown in red) is the Source column:

Question: How do you get the Source column from the list of users? By default, only a limited set of properties are returned (businessPhones, displayName, givenName, id, jobTitle, mail, mobilePhone, officeLocation, preferredLanguage, surname, and userPrincipalName).

enter image description here

nam
  • 21,967
  • 37
  • 158
  • 332

2 Answers2

2

As far as I know, there isn't the field source in the response of the graph api. We can see all of the properties of user in this page, and it doesn't exist a property source.

Azure portal request another api but not graph api(list user) to show the source. enter image description here

By the way, graph api list user(v1.0) just show a few fields. To show more fields, you can use $select in the api(such as https://graph.microsoft.com/v1.0/users?$select=displayName,userType). If you use graph api list user(beta), it will show all of the fields of the user.

Hope it helps~

Hury Shen
  • 14,948
  • 1
  • 9
  • 18
  • You wrote: `Azure portal request another api but not graph api(list user) to show the source`. Do you happen to know what that `anohter` api would be to get the `Source` value? I need to display that value (for example, to display whether user is an Azure AD user, MS Account User, Inivited User, etc (as your screenshot's Source column shows)? – nam Jul 15 '20 at 04:39
  • Hi @nam, the "another" api is `https://main.iam.ad.ext.azure.com/api/Users` as shown in the screenshot. But I think we can't request it because it seems not a api which provided for us to use. To request this api, we have to provide token but we don't have token and we can't get the token. – Hury Shen Jul 15 '20 at 04:45
  • @nam For your requirement, I think you can implement it by parse some other columns of the user. For example, if the `userType` column is `Member`, the user is Azure AD user. If `userType` is `Guest` and `externalUserState` is "Accepted", the user is `External Azure Active Directory`. `externalUserState` is "PendingAcceptance", it is `Invited user`....... – Hury Shen Jul 15 '20 at 04:58
  • This is a good suggestion. I implemented it and it worked (thank you). – nam Jul 15 '20 at 16:47
  • 1
    In a more complex case, I'm getting one incorrect result. I've posted the issue [here](https://stackoverflow.com/q/62926660/1232087) – nam Jul 16 '20 at 02:57
  • In case you have time for any suggestion, I have a similar issue that I have posted [here](https://stackoverflow.com/q/63182729/1232087). – nam Jul 31 '20 at 00:27
0

If you have not used it I would check out the graph explorer https://developer.microsoft.com/en-us/graph/graph-explorer

If I had to take a guess it is a dynamic column based on userPrincipalName. If the user is from an external system there will be #EXT# in the userPrincipalName. I would look at that and see if there is something different about them.

I was looking at the endpoint https://graph.microsoft.com/v1.0/users

As a comment from Hury mentions, you could use userType and externalUserState to probably determine the same thing.

if I was doing this in c# (This is from memory sorry if there is a typo)

public string Source { 
   get {
      return UserPrincipalName.Contains("#EXT#")?"Microsoft Account":"Azure Active Directory";
   }
}

For more complex processing

private string _source = null;
public string Source _source??(_source=GenerateSource());
}

protected string GenerateSource(){
   return UserPrincipalName.Contains("#EXT#")?"Microsoft Account":"Azure Active Directory";
}

If I was using code similar to what can be found here MS Graph - LINQ query returning incorrect results I would do it as extension class (not tested all from memory, but I should be close)


public static class UserExtension{
    
    public static UserSource(this User user){
        var userTypeUpper = _user.UserType.ToUpperCase();
        var userPrincipalNameUpper = user.UserPrincipalName.ToUpperCase();
        var externalUserStateUpper = user.ExternalUserState.ToUpperCase();
        
        return (_user.UserType == "MEMBER" && userPrincipalNameUpper.Contains("#EXT#") == false) ? "Azure Active Directory" :
                    (userTypeUpper == "MEMBER" && userPrincipalNameUpper.Contains("#EXT#")) ? "Microsoft Account" :
                    (userTypeUpper == "GUEST" && externalUserStateUpper == "ACCEPTED") ? "External Azure Active Directory" :
                    (userTypeUpper == "GUEST" && externalUserStateUpper == "PENDINGACCEPTANCE") ? "Invited user" : "Unknown";
    }
    
}

//sample code using it

Microsoft.Graph.IGraphServiceUsersCollectionPage users = await graphClient.Users.Request()
    .Select("displayName, userPrincipalName, userType")
    .GetAsync();

List<User> lstUsers = (List<User>)users.CurrentPage.ToList();

var source = lstUsers.First().UserSource()


Ron
  • 421
  • 3
  • 9
  • `userPrincipalName` is actually the second column (User Name) in the above image. The `Source` column in Azure Portal is showing (as in the image above) either `Active Directory` or `Microsoft Account` meaning user is either an Azure AD user or is a MS Personal Account user. The [Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer) with the `GET https://graph.microsoft.com/v1.0/users` request also returns only the default standard columns listed in my question (also with an official link there). – nam Jul 15 '20 at 04:30
  • Yup, my answer was more saying that the source column is probably a dynamic column based on other information to make it more readable. So in my example, if the userPrincipalName from the graph contained #EXT# I would know that the source is external and is a Microsoft account. I am presuming all the Azure AD users are internal users. Even in your example, the only user with Source Microsoft account has the userPrincipalName with #EXT# all the others do not. However externalUserState and userType together are doing the same thing – Ron Jul 15 '20 at 17:58
  • Thanks for further clarification and explanation. Your updated code that include the `Source` property is a good piece of code to implement if we are dealing with only two cases (i.e. `if UserPrincipalName contains #EXT# else .....). For more than two cases it may need more polishing (I think). For instance, if you look at the Hury's screenshot, a user may be external, invited, MS Account etc. – nam Jul 15 '20 at 20:48
  • I just updated my answer to include a way to increase the complexity. Could easily turn it into a function and use the attributes that Hury's message mentioned and do this as a fallback. Lots of options. – Ron Jul 15 '20 at 20:55
  • Can we apply your more complex case in [this](https://stackoverflow.com/q/62926660/1232087) scenario? – nam Jul 16 '20 at 02:59
  • Updated, I would probably use an extension class in C#. – Ron Jul 16 '20 at 04:21
  • For the record, the values of `externalUserState` and `userType` are identical for ALL users in my case, even though the sources are listed as "Azure AD", "External Azure AD", "Other", +3 other types. The only variation I see is in userPrincipalName, as already mentioned. In other words, they are NOT always "doing the same thing". – C Perkins Aug 20 '21 at 04:54