You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C#获取Azure AD用户全部属性(含空值)并同步至其他AD

获取Azure AD用户全部属性(含空属性)的C#实现

我之前做过Azure AD到第三方AD的同步需求,正好碰到过这个“获取所有属性包括空值”的问题,这里给你分享下实操思路和代码:

核心问题分析

Graph API默认只返回用户的常用属性,而且即使你用$select=*,那些从未设置过的空属性也不会被包含在返回结果里。要拿到所有属性(包括空的),关键是:

  1. 先明确Azure AD User实体有哪些属性
  2. 显式指定所有属性进行查询,这样空属性会以null的形式返回(或者在SDK对象中体现为默认值)

步骤1:获取User实体的所有属性名称

最可靠的方式是从Graph API的元数据中解析出User实体的全部属性,而不是手动枚举(避免遗漏新增属性)。下面是用C#解析元数据的代码:

using Microsoft.Graph;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml.Linq;

private async Task<List<string>> GetUserPropertyNamesAsync(GraphServiceClient graphClient)
{
    // 请求Graph元数据
    var metadataRequest = new HttpRequestMessage(HttpMethod.Get, "$metadata");
    var metadataResponse = await graphClient.HttpProvider.SendAsync(metadataRequest);
    metadataResponse.EnsureSuccessStatusCode();
    
    var metadataContent = await metadataResponse.Content.ReadAsStringAsync();
    var xDoc = XDocument.Parse(metadataContent);

    // 定义OData命名空间
    var edmxNs = "http://docs.oasis-open.org/odata/ns/edmx";
    var edmNs = "http://docs.oasis-open.org/odata/ns/edm";

    // 找到User实体类型
    var userEntity = xDoc.Descendants(XName.Get("EntityType", edmNs))
        .FirstOrDefault(e => e.Attribute("Name")?.Value == "User");
    
    if (userEntity == null)
        throw new System.Exception("未找到User实体元数据");

    // 提取所有属性名称
    var propertyNames = userEntity.Descendants(XName.Get("Property", edmNs))
        .Select(p => p.Attribute("Name")?.Value)
        .Where(name => !string.IsNullOrEmpty(name))
        .ToList();

    // 手动添加扩展属性(部分扩展属性可能不在元数据的直接属性列表中)
    for (int i = 1; i <= 15; i++)
    {
        var extAttrName = $"onPremisesExtensionAttributes{i}";
        if (!propertyNames.Contains(extAttrName))
            propertyNames.Add(extAttrName);
    }

    return propertyNames;
}

步骤2:批量获取所有用户(含全属性)

拿到属性列表后,构造$select参数,分页获取所有用户(Graph API单次最多返回999条):

public async Task<List<User>> GetAllUsersWithFullPropertiesAsync(GraphServiceClient graphClient)
{
    var allProperties = await GetUserPropertyNamesAsync(graphClient);
    var selectClause = string.Join(",", allProperties);

    var allUsers = new List<User>();
    // 首次请求,每页999条(Graph API最大页容量)
    var currentPage = await graphClient.Users
        .Request()
        .Select(selectClause)
        .Top(999)
        .GetAsync();

    allUsers.AddRange(currentPage.CurrentPage);

    // 处理分页
    while (currentPage.NextPageRequest != null)
    {
        currentPage = await currentPage.NextPageRequest.GetAsync();
        allUsers.AddRange(currentPage.CurrentPage);
    }

    return allUsers;
}

步骤3:处理空属性同步

当你拿到User对象后,那些从未设置过的属性会以null(引用类型)或默认值(值类型)的形式存在。同步到目标AD时,直接将这些值映射过去即可:

  • 比如user.MobilePhone如果为null,就给目标AD对应的字段设置为空字符串
  • 注意部分属性是只读的(如createdDateTime),或者需要特殊权限才能获取(如passwordProfile),同步时要跳过或做针对性处理

权限说明

确保你的Azure AD应用已授予Directory.Read.All应用权限(不是委托权限),并且已完成管理员同意,否则会出现权限不足的错误。

内容的提问来源于stack exchange,提问作者James Barnes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:11:18