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

已加入Azure AD的Windows系统获取登录用户UPN失败问题

这个问题我之前帮人排查过,TranslateNameW在Azure AD环境下失效是有明确原因的,我来给你拆解并提供可行方案:

问题原因分析

你当前的代码里手动构造了SAM格式的用户名L"AAD\\naga",然后调用TranslateNameW尝试转成UPN,但这个API是为**本地Active Directory(on-premise AD)**设计的——它依赖域控制器的查询服务,而加入Azure AD的设备并没有传统的本地域控制器,L"AAD"也不是一个可被解析的合法域,所以会抛出错误:

The specified domain either does not exist or could not be contacted

在本地AD环境中,Domain\Username的格式是有效的SAM名称,但Azure AD的身份模型和本地AD完全不同,TranslateNameW无法处理这种云身份场景。

解决方案

针对Azure AD加入的设备,推荐两种Win32原生方案来获取用户UPN:

方案1:直接获取当前登录用户的UPN(最简便)

使用GetUserNameExWAPI,指定NameUserPrincipal格式,直接从系统身份缓存中读取当前登录用户的UPN,不需要手动构造SAM名称:

wchar_t user_upn[1024] = { 0 };
DWORD len = sizeof(user_upn) / sizeof(wchar_t); // 注意这里要按字符数计算长度

if (GetUserNameExW(NameUserPrincipal, user_upn, &len)) {
    wprintf(L"Successfully got UPN: %ws\n", user_upn);
} else {
    wprintf(L"Failed to get UPN: %ld\n", GetLastError());
}

这个API对Azure AD加入的设备兼容性很好,无论是Windows 10还是Windows Server 2012 R2都能正常工作。

方案2:获取系统中所有登录用户的UPN

如果需要枚举Windows Server 2012 R2上的所有登录用户的UPN,可以通过WMI查询Win32_UserAccount类,过滤Azure AD租户域名来获取目标用户信息:

#include <windows.h>
#include <wbemidl.h>
#include <comdef.h>

#pragma comment(lib, "wbemuuid.lib")

void GetAllAADUserUPNs(const wchar_t* tenantDomain) {
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (FAILED(hr)) {
        wprintf(L"CoInitializeEx failed: 0x%lx\n", hr);
        return;
    }

    IWbemLocator* pLoc = NULL;
    hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
    if (FAILED(hr)) {
        wprintf(L"CoCreateInstance failed: 0x%lx\n", hr);
        CoUninitialize();
        return;
    }

    IWbemServices* pSvc = NULL;
    hr = pLoc->ConnectServer(
        L"ROOT\\CIMV2",    // WMI命名空间
        NULL,               // 用户名
        NULL,               // 密码
        0,                  // 语言
        NULL,               // 标志
        0,                  // 授权
        0,                  // 上下文
        &pSvc               // 服务指针
    );
    if (FAILED(hr)) {
        wprintf(L"ConnectServer failed: 0x%lx\n", hr);
        pLoc->Release();
        CoUninitialize();
        return;
    }

    // 设置代理安全 blanket
    hr = CoSetProxyBlanket(
        pSvc,
        RPC_C_AUTHN_WINNT,
        RPC_C_AUTHZ_NONE,
        NULL,
        RPC_C_AUTHN_LEVEL_CALL,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        EOAC_NONE
    );
    if (FAILED(hr)) {
        wprintf(L"CoSetProxyBlanket failed: 0x%lx\n", hr);
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return;
    }

    IEnumWbemClassObject* pEnumerator = NULL;
    wchar_t query[512];
    swprintf_s(query, L"SELECT UserPrincipalName FROM Win32_UserAccount WHERE Domain='%ws'", tenantDomain);
    
    hr = pSvc->ExecQuery(
        L"WQL",
        query,
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator
    );
    if (FAILED(hr)) {
        wprintf(L"ExecQuery failed: 0x%lx\n", hr);
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return;
    }

    IWbemClassObject* pclsObj = NULL;
    ULONG uReturn = 0;
    while (pEnumerator) {
        hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
        if (uReturn == 0) break;

        VARIANT vtProp;
        VariantInit(&vtProp);
        hr = pclsObj->Get(L"UserPrincipalName", 0, &vtProp, 0, 0);
        if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
            wprintf(L"AAD User UPN: %ws\n", vtProp.bstrVal);
        } else {
            wprintf(L"Failed to retrieve UPN for user\n");
        }
        VariantClear(&vtProp);
        pclsObj->Release();
    }

    // 清理资源
    pEnumerator->Release();
    pSvc->Release();
    pLoc->Release();
    CoUninitialize();
}

// 调用示例:替换成你的Azure AD租户域名,比如"contoso.com"
// GetAllAADUserUPNs(L"contoso.com");

注意事项:

  1. 调用这个方法时,需要替换tenantDomain为你的实际Azure AD租户域名(比如contoso.com);
  2. 运行服务的账户需要有WMI查询权限,建议使用本地系统账户或具有管理员权限的账户。
额外提示

不要尝试手动构造Azure AD用户的SAM格式名称(比如AzureAD\username),这种格式是系统内部使用的,TranslateNameW等传统AD API无法解析它。优先使用上面推荐的现代API或WMI方案来适配云身份场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:54:50