如何在曾联域的离线Windows 10中获取用户姓与名
I feel your pain—trying to use UserPrincipal when offline throws that frustrating LDAP-related PrincipalException because it’s hardwired to reach out to the domain controller. Since the machine was once joined to the domain, the system has cached user data locally, so we can tap into that instead. Here are several reliable approaches:
1. Use WMI to Query Local Cached User Data
WMI exposes the Win32_NetworkLoginProfile class which holds cached domain user info, including full name. You can split the full name into first and last (adjust the split logic if your naming convention differs):
using System.Management; public static (string FirstName, string LastName) GetCachedUserNames(string username) { var firstName = string.Empty; var lastName = string.Empty; var query = $"SELECT FullName FROM Win32_NetworkLoginProfile WHERE Name = '{username}'"; using (var searcher = new ManagementObjectSearcher(query)) { foreach (ManagementObject profile in searcher.Get()) { var fullName = profile["FullName"]?.ToString(); if (!string.IsNullOrWhiteSpace(fullName)) { var nameParts = fullName.Split(new[] {' '}, 2); firstName = nameParts[0]; lastName = nameParts.Length > 1 ? nameParts[1] : string.Empty; } break; } } return (firstName, lastName); }
2. Try Local PrincipalContext (Bypasses DC Check)
Even though UserPrincipal fails for domain contexts offline, switching to a machine context can pull cached domain user attributes like GivenName and Surname:
using System.DirectoryServices.AccountManagement; public static (string FirstName, string LastName) GetUserFromLocalCache(string username) { try { using (var localContext = new PrincipalContext(ContextType.Machine)) { var user = UserPrincipal.FindByIdentity(localContext, IdentityType.SamAccountName, username); if (user != null) { return (user.GivenName ?? string.Empty, user.Surname ?? string.Empty); } } } catch (Exception ex) { // Handle cases where the user isn't cached or permissions are missing Console.WriteLine($"Failed to retrieve user: {ex.Message}"); } return (string.Empty, string.Empty); }
This works if the domain user's profile was cached during their last login. If it returns null, fall back to other methods.
3. Call Windows API with NetUserGetInfo
The native NetUserGetInfo API directly accesses local user cache, including full names for domain users who've logged on before. Here's a P/Invoke implementation:
using System; using System.Runtime.InteropServices; public static class UserInfoHelper { [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int NetUserGetInfo( string serverName, string username, int level, out IntPtr bufferPtr); [DllImport("netapi32.dll")] private static extern void NetApiBufferFree(IntPtr bufferPtr); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct USER_INFO_2 { public string Username; public string Password; public int PasswordAge; public int PrivilegeLevel; public string HomeDirectory; public string Comment; public int Flags; public string ScriptPath; public int AuthFlags; public string FullName; // Other fields omitted for brevity } public static (string FirstName, string LastName) GetUserFullName(string username) { IntPtr buffer = IntPtr.Zero; try { var result = NetUserGetInfo(null, username, 2, out buffer); if (result == 0) { var userInfo = Marshal.PtrToStructure<USER_INFO_2>(buffer); if (!string.IsNullOrWhiteSpace(userInfo.FullName)) { var nameParts = userInfo.FullName.Split(new[] {' '}, 2); return (nameParts[0], nameParts.Length > 1 ? nameParts[1] : string.Empty); } } } finally { if (buffer != IntPtr.Zero) NetApiBufferFree(buffer); } return (string.Empty, string.Empty); } }
This is a lower-level approach but highly reliable for offline scenarios.
Quick Recommendation
Start with method 2 (local PrincipalContext) since it’s cleanest and uses the same API family you were originally trying. If that fails, method 1 or 3 will almost always work as long as the user has logged into the machine before.
内容的提问来源于stack exchange,提问作者Nethanek

