原始代碼實際演示的是「建立 Windows 本地使用者」,而非解析 IP。本文釐清兩種常見需求並提供正確實作:
System.Net.Dns)。System.DirectoryServices)。
using System.Net;
public static class DnsResolver {
/// 取得主機名稱對應的所有 IPv4 位址
public static List GetIpv4Addresses(string hostName) {
var ips = new List();
try {
IPHostEntry entry = Dns.GetHostEntry(hostName);
foreach (IPAddress ip in entry.AddressList) {
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) // IPv4
ips.Add(ip.ToString());
}
} catch (SocketException ex) {
// 處理解析失敗:主機不存在、DNS 伺服器無回應等
Console.WriteLine($"DNS 解析失敗:{ex.Message}");
}
return ips;
}
/// 取得第一個 IPv4 位址(或 null)
public static string GetFirstIpv4(string hostName)
=> GetIpv4Addresses(hostName).FirstOrDefault();
}
public static async Task> GetIpv4AddressesAsync(string hostName) {
var ips = new List();
try {
IPHostEntry entry = await Dns.GetHostEntryAsync(hostName);
ips.AddRange(entry.AddressList
.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork)
.Select(ip => ip.ToString()));
} catch (SocketException ex) {
// 記錄錯誤
}
return ips;
}
public static string GetHostNameFromIp(string ipAddress) {
try {
IPHostEntry entry = Dns.GetHostEntry(ipAddress);
return entry.HostName; // 完整網域名稱 (FQDN)
} catch (SocketException) {
return string.Empty;
}
}
原代碼意圖在本機建立使用者,但方法名誤導。以下是正確、健壯的實作:
using System.DirectoryServices;
public class LocalUserManager {
/// 在本機建立使用者帳號
/// 空字串=成功,否則回傳錯誤訊息
public string CreateLocalUser(string userName, string password, string fullName = "") {
try {
using (var computer = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer"))
using (var users = computer.Children) {
// 檢查是否已存在
if (users.Cast().Any(u => u.Name.Equals(userName, StringComparison.OrdinalIgnoreCase)))
return $"使用者 [{userName}] 已存在";
using (var user = users.Add(userName, "user")) {
if (!string.IsNullOrEmpty(fullName))
user.Properties["FullName"].Value = fullName;
user.Invoke("SetPassword", new object[] { password });
user.CommitChanges();
}
}
return string.Empty; // 成功
} catch (Exception ex) {
return $"建立失敗:{ex.Message}";
}
}
/// 查詢本機使用者是否存在
public bool UserExists(string userName) {
using (var computer = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer")) {
return computer.Children.Cast()
.Any(u => u.SchemaClassName == "User" && u.Name.Equals(userName, StringComparison.OrdinalIgnoreCase));
}
}
}
AD 使用者物件不儲存 IP 位址。IP 屬於電腦/裝置層級(computer物件的ipHostNumber或 DHCP 租約),非使用者屬性。若需「某使用者登入過哪些 IP」,需查詢 DC 安全性事件日誌 (Event ID 4624) 或 RADIUS/VPN 登入記錄。
using System.Net.NetworkInformation;
public static List GetLocalIpv4Addresses() {
return NetworkInterface.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == OperationalStatus.Up
&& nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.SelectMany(nic => nic.GetIPProperties().UnicastAddresses)
.Where(addr => addr.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(addr => addr.Address.ToString())
.Distinct()
.ToList();
}
| 陷阱 | 對策 |
|---|---|
| Dns.GetHostEntry 可能回傳 IPv6 | 務必檢查 AddressFamily.InterNetwork 過濾 IPv4 |
| 同步 DNS 封鎖執行緒 | UI/高併發場景必須用 GetHostEntryAsync |
| 主機名稱大小寫 | DNS 不分大小寫,但最佳實踐統一 ToLower() |
| DirectoryEntry 路徑格式 | 本機:WinNT://MachineName,computer;AD:LDAP://DC=domain,DC=com |
| 建立使用者需管理員權限 | 應用程式需以 Administrator 執行,或配置 UAC 清單 |
| SetPassword 參數型別 | Invoke 需傳 object[] { password },非直接字串 |
Dns.GetHostEntry[Async],簡單、跨平台、標準。DirectoryEntry (WinNT:/LDAP:),需 Windows、管理員權限。釐清需求、選對 API,即可避免「方法名不符功能」的困擾,編寫正確且可維護的網路與身分管理代碼。