在企業級應用開發中,常需以程式化方式管理 DNS 記錄(如自動部署、動態更新 IP)。本文介紹如何使用 C# 搭配 WMI (Windows Management Instrumentation) 操作 Windows DNS 服務(專為 Windows Server 2003 設計,亦適用於更新版本),實現 DNS 區域與記錄的完整增、刪、改、查功能,並支援遠程管理。
專案需加入 System.Management.dll 參考,並引用以下命名空間:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Management; // 核心 WMI 命名空間
透過 ManagementScope 連接至目標伺服器的 root\MicrosoftDNS 命名空間。若為遠端操作,需提供具備 DNS 管理權限的帳號密碼(ConnectionOptions)。
// 連線路徑格式:\\{ServerIP_or_Name}\root\MicrosoftDNS
// 預設連接本機
string sServerPath = @"\\localhost\root\MicrosoftDNS";
// 遠端連線需驗證
ConnectionOptions conn = new ConnectionOptions();
conn.Username = "Administrator";
conn.Password = "password";
ManagementScope scope = new ManagementScope(sServerPath, conn);
scope.Connect();
封裝所有 DNS 操作邏輯,主要屬性與方法如下:
Create(string DnsType):初始化 ManagementClass(如 MicrosoftDNS_Zone, MicrosoftDNS_AType 等)並建立連線。QueryDNS(string query, string DnsType):執行 WQL 查詢並回傳 ManagementObjectCollection。支援建立主區域、次要區域、存根區域及轉送區域,並可修改類型與刪除。
// 判斷區域是否存在
public bool IsExistsZone(string domain) { ... }
// 建立區域 (簡易版,預設主區域 Type=0)
public bool CreateZone(string domain) { ... }
// 建立區域 (完整參數:類型、資料檔、主伺服器 IP、管理員信箱)
public bool CreateZone(string domain, uint ZoneType, string DataFileName, string[] IpAddr, string AdminEmailName) { ... }
// 修改區域類型
public bool ChangeZoneType(string domain, uint ZoneType, string DataFileName, string[] IpAddr, string AdminEmailName) { ... }
// 刪除區域
public bool DelZone(string domain) { ... }
核心操作針對 MicrosoftDNS_AType 類別。
// 檢查 A 記錄是否存在
public bool IsExistsAType(string domain, string ownerName) { ... }
// 建立 A 記錄 (簡易版,TTL 選填預設 3600)
public bool CreateAType(string containerName, string hostName, string ipAddress, string ttl) { ... }
// 建立 A 記錄 (完整參數含 RecordClass)
public bool CreateAType(string dnsServerName, string containerName, string hostName, uint recordClass, uint ttl, string ipAddress) { ... }
// 修改 A 記錄 (需變更 IP 才算有效修改)
public bool ModifyAType(string containerName, string hostName, string ipAddress, string ttl) { ... }
// 刪除 A 記錄
public bool DelAType(string containerName, string hostName) { ... }
// 列出區域所有 A 記錄 (回傳 DataTable)
public DataTable ListExistsAType(string containerName) { ... }
操作 MicrosoftDNS_MXType,需指定優先權與目標主機。
public bool IsExistsMXType(string containerName, string ownerName) { ... }
public bool CreateMXType(string hostName, string containerName, string mailExchange, string preference, string ttl) { ... }
public bool ModifyMXType(string hostName, string containerName, string ttl, string mailExchange, string preference) { ... }
public bool DelMXType(string hostName, string containerName) { ... }
public DataTable ListExistsMXType(string containerName) { ... }
操作 MicrosoftDNS_CNAMEType,將別名指向標準主機名。
public bool IsExistsCNAMEType(string containerName, string ownerName) { ... }
public bool CreateCNAMEType(string hostName, string containerName, string primaryName, string ttl) { ... }
public bool ModifyCNAMEType(string hostName, string containerName, string ttl, string primaryName) { ... }
public bool DelCNAMEType(string hostName, string containerName) { ... }
public DataTable ListExistsCNAMEType(string containerName) { ... }
// 移除 FQDN 結尾的點號 (例如 "www.example.com." -> "www.example.com")
private string ClearEndDot(string str) { ... }
以下為可直接編譯執行的完整類別庫碼(已整理格式、修正編碼問題):
namespace Yaosansi.Net
{
using System;
using System.Management;
using System.Data;
///
/// C# 利用 WMI 操作 DNS 服務器 (可遠程操作,需相應權限)
/// 適用版本:Windows Server 2003 及以上
/// 作者:yaosansi
///
public class MYDNS
{
#region 私有欄位
private string sServerPath;
private string username = null;
private string passWord = null;
private string DNSName = null;
private ManagementScope DNS;
private ManagementObjectCollection Q;
private ManagementClass DnsClass;
private ManagementBaseObject MI;
private string errMessage = null;
#endregion
#region 公開屬性
public string ErrMessage { get { return errMessage; } }
public string ServerName
{
set
{
this.sServerPath = string.Format(@"\\{0}\root\MicrosoftDNS", value);
this.DNSName = value;
}
}
public string userName { set { this.username = value; } }
public string passWord { set { this.passWord = value; } }
#endregion
#region 建構函式
public MYDNS()
{
sServerPath = @"\\localhost\root\MicrosoftDNS";
DNSName = "localhost";
}
#endregion
#region 核心連線與查詢
private void Create(string DnsType)
{
if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(passWord))
{
ConnectionOptions Conn = new ConnectionOptions();
Conn.Username = username;
Conn.Password = passWord;
DNS = new ManagementScope(sServerPath, Conn);
}
else
{
DNS = new ManagementScope(sServerPath);
}
if (!DNS.IsConnected) DNS.Connect();
ManagementPath Path = new ManagementPath(DnsType);
this.DnsClass = new ManagementClass(DNS, Path, null);
}
public ManagementObjectCollection QueryDNS(string query, string DnsType)
{
this.Create(DnsType);
ManagementObjectSearcher QS = new ManagementObjectSearcher(DNS, new ObjectQuery(query));
QS.Scope = DNS;
return QS.Get();
}
public ManagementObjectCollection QueryDNS(string query)
{
if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(passWord))
{
ConnectionOptions Conn = new ConnectionOptions();
Conn.Username = username;
Conn.Password = passWord;
DNS = new ManagementScope(sServerPath, Conn);
}
else
{
DNS = new ManagementScope(sServerPath);
}
if (!DNS.IsConnected) DNS.Connect();
ManagementObjectSearcher QS = new ManagementObjectSearcher(DNS, new ObjectQuery(query));
QS.Scope = DNS;
return QS.Get();
}
#endregion
#region 區域操作
public bool IsExistsZone(string domain)
{
try
{
Q = QueryDNS("SELECT * FROM MicrosoftDNS_ZONE WHERE ContainerName='" + domain + "'");
foreach (ManagementObject obj in Q) return true;
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool CreateZone(string domain)
{
try
{
this.Create("MicrosoftDNS_Zone");
if (IsExistsZone(domain)) { errMessage = "域:" + domain + "已經存在."; return false; }
MI = DnsClass.GetMethodParameters("CreateZone");
MI["ZoneName"] = domain;
MI["ZoneType"] = 0; // Primary
DnsClass.InvokeMethod("CreateZone", MI, null);
errMessage = "域:" + domain + "創建成功.";
return true;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool DelZone(string domain)
{
try
{
Q = QueryDNS("SELECT * FROM MicrosoftDNS_ZONE WHERE ContainerName='" + domain + "'", "MicrosoftDNS_Zone");
foreach (ManagementObject obj in Q) { obj.Delete(); errMessage = "域:" + domain + "刪除成功."; return true; }
errMessage = "未找到域:" + domain; return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
#endregion
#region A 記錄操作
private string BuildOwnerName(string containerName, string hostName)
{
return string.IsNullOrEmpty(hostName) ? containerName : hostName + "." + containerName;
}
public bool IsExistsAType(string domain, string ownerName)
{
try
{
Q = QueryDNS("SELECT * FROM MicrosoftDNS_AType WHERE OwnerName='" + ownerName + "' AND ContainerName='" + domain + "'");
foreach (ManagementObject obj in Q) return true;
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool CreateAType(string containerName, string hostName, string ipAddress, string ttl)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_AType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,創建失敗"; return false; }
if (IsExistsAType(containerName, ownerName)) { errMessage = containerName + "中已存在" + ownerName + ",創建失敗"; return false; }
MI = DnsClass.GetMethodParameters("CreateInstanceFromPropertyData");
MI["DnsServerName"] = "localhost";
MI["ContainerName"] = containerName;
MI["OwnerName"] = ownerName;
MI["IPAddress"] = ipAddress;
MI["TTL"] = string.IsNullOrEmpty(ttl) ? "3600" : ttl;
DnsClass.InvokeMethod("CreateInstanceFromPropertyData", MI, null);
errMessage = "A記錄:" + ownerName + "創建成功.";
return true;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool ModifyAType(string containerName, string hostName, string ipAddress, string ttl)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_AType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,修改失敗"; return false; }
if (!IsExistsAType(containerName, ownerName)) { errMessage = containerName + "中不存在" + ownerName + ",修改失敗"; return false; }
Q = QueryDNS("SELECT * FROM MicrosoftDNS_AType WHERE ContainerName='" + containerName + "' AND OwnerName='" + ownerName + "'", "MicrosoftDNS_AType");
foreach (ManagementObject obj in Q)
{
if (obj["IPAddress"].ToString() == ipAddress) { errMessage = "A記錄:" + ownerName + "修改失敗,必須修改IP地址."; return false; }
MI = obj.GetMethodParameters("Modify");
MI["IPAddress"] = ipAddress;
MI["TTL"] = string.IsNullOrEmpty(ttl) ? "3600" : ttl;
obj.InvokeMethod("Modify", MI, null);
errMessage = "A記錄:" + ownerName + "修改成功.";
return true;
}
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool DelAType(string containerName, string hostName)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_AType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,刪除失敗"; return false; }
if (!IsExistsAType(containerName, ownerName)) { errMessage = containerName + "中不存在" + ownerName + ",刪除失敗"; return false; }
Q = QueryDNS("SELECT * FROM MicrosoftDNS_AType WHERE ContainerName='" + containerName + "' AND OwnerName='" + ownerName + "'", "MicrosoftDNS_AType");
foreach (ManagementObject obj in Q) { obj.Delete(); errMessage = "A記錄:" + ownerName + "刪除成功."; return true; }
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public DataTable ListExistsAType(string containerName)
{
DataTable table = new DataTable("MicrosoftDNS_AType_" + containerName);
table.Columns.Add("主機名 (A)");
table.Columns.Add("IP 位址");
table.Columns.Add("TTL");
try
{
Q = QueryDNS("SELECT * FROM MicrosoftDNS_AType WHERE ContainerName='" + containerName + "'");
foreach (ManagementObject obj in Q)
{
DataRow row = table.NewRow();
row["主機名 (A)"] = obj["OwnerName"];
row["IP 位址"] = obj["IPAddress"];
row["TTL"] = obj["TTL"];
table.Rows.Add(row);
}
}
catch (Exception e) { errMessage = e.Message; }
return table;
}
#endregion
#region MX 記錄操作
public bool IsExistsMXType(string containerName, string ownerName)
{
try
{
Q = QueryDNS("SELECT * FROM MicrosoftDNS_MXType WHERE ContainerName='" + containerName + "' AND OwnerName='" + ownerName + "'");
foreach (ManagementObject obj in Q) return true;
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool CreateMXType(string hostName, string containerName, string mailExchange, string preference, string ttl)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_MXType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,創建失敗"; return false; }
if (IsExistsMXType(containerName, ownerName)) { errMessage = containerName + "中已存在" + ownerName + ",創建失敗"; return false; }
MI = DnsClass.GetMethodParameters("CreateInstanceFromPropertyData");
MI["DnsServerName"] = "localhost";
MI["ContainerName"] = containerName;
MI["OwnerName"] = ownerName;
MI["MailExchange"] = mailExchange;
MI["Preference"] = preference;
MI["TTL"] = string.IsNullOrEmpty(ttl) ? "3600" : ttl;
DnsClass.InvokeMethod("CreateInstanceFromPropertyData", MI, null);
errMessage = "MX記錄:" + ownerName + "創建成功.";
return true;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool ModifyMXType(string hostName, string containerName, string ttl, string mailExchange, string preference)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_MXType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,修改失敗"; return false; }
if (!IsExistsMXType(containerName, ownerName)) { errMessage = containerName + "中不存在" + ownerName + ",修改失敗"; return false; }
Q = QueryDNS("SELECT * FROM MicrosoftDNS_MXType WHERE ContainerName='" + containerName + "' AND OwnerName='" + ownerName + "'");
foreach (ManagementObject obj in Q)
{
if (ClearEndDot(obj["MailExchange"].ToString()) == ClearEndDot(mailExchange) && obj["Preference"].ToString() == preference)
{ errMessage = "MX記錄:" + ownerName + "修改失敗,必須修改目標主機或郵件優先級."; return false; }
MI = obj.GetMethodParameters("Modify");
MI["TTL"] = string.IsNullOrEmpty(ttl) ? "3600" : ttl;
MI["MailExchange"] = mailExchange;
MI["Preference"] = preference;
obj.InvokeMethod("Modify", MI, null);
errMessage = "MX記錄:" + ownerName + "修改成功.";
return true;
}
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool DelMXType(string hostName, string containerName)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_MXType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,刪除失敗"; return false; }
if (!IsExistsMXType(containerName, ownerName)) { errMessage = containerName + "中不存在" + ownerName + ",刪除失敗"; return false; }
Q = QueryDNS("SELECT * FROM MicrosoftDNS_MXType WHERE ContainerName='" + containerName + "' AND OwnerName='" + ownerName + "'");
foreach (ManagementObject obj in Q) { obj.Delete(); errMessage = "MX記錄:" + ownerName + "刪除成功."; return true; }
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public DataTable ListExistsMXType(string containerName)
{
DataTable table = new DataTable("MicrosoftDNS_MXType_" + containerName);
table.Columns.Add("郵件交換記錄 (MX)");
table.Columns.Add("目標主機");
table.Columns.Add("優先級");
table.Columns.Add("TTL");
try
{
Q = QueryDNS("SELECT * FROM MicrosoftDNS_MXType WHERE ContainerName='" + containerName + "'");
foreach (ManagementObject obj in Q)
{
DataRow row = table.NewRow();
row["目標主機"] = obj["MailExchange"];
row["郵件交換記錄 (MX)"] = obj["OwnerName"];
row["優先級"] = obj["Preference"];
row["TTL"] = obj["TTL"];
table.Rows.Add(row);
}
}
catch (Exception e) { errMessage = e.Message; }
return table;
}
#endregion
#region CNAME 記錄操作
public bool IsExistsCNAMEType(string containerName, string ownerName)
{
try
{
Q = QueryDNS("SELECT * FROM MicrosoftDNS_CNAMEType WHERE ContainerName='" + containerName + "' AND OwnerName='" + ownerName + "'");
foreach (ManagementObject obj in Q) return true;
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool CreateCNAMEType(string hostName, string containerName, string primaryName, string ttl)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_CNAMEType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,創建失敗"; return false; }
if (IsExistsCNAMEType(containerName, ownerName)) { errMessage = containerName + "中已存在" + ownerName + ",創建失敗"; return false; }
MI = DnsClass.GetMethodParameters("CreateInstanceFromPropertyData");
MI["DnsServerName"] = "localhost";
MI["ContainerName"] = containerName;
MI["OwnerName"] = ownerName;
MI["PrimaryName"] = primaryName;
MI["TTL"] = string.IsNullOrEmpty(ttl) ? "3600" : ttl;
DnsClass.InvokeMethod("CreateInstanceFromPropertyData", MI, null);
errMessage = "CNAME:" + ownerName + "創建成功.";
return true;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool ModifyCNAMEType(string hostName, string containerName, string ttl, string primaryName)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_CNAMEType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,修改失敗"; return false; }
if (!IsExistsCNAMEType(containerName, ownerName)) { errMessage = containerName + "中不存在" + ownerName + ",修改失敗"; return false; }
Q = QueryDNS("SELECT * FROM MicrosoftDNS_CNAMEType WHERE ContainerName='" + containerName + "' AND OwnerName='" + ownerName + "'");
foreach (ManagementObject obj in Q)
{
if (ClearEndDot(obj["PrimaryName"].ToString()) == ClearEndDot(primaryName))
{ errMessage = "CName記錄:" + ownerName + "修改失敗,必須修改別名主機."; return false; }
MI = obj.GetMethodParameters("Modify");
MI["TTL"] = string.IsNullOrEmpty(ttl) ? "3600" : ttl;
MI["PrimaryName"] = primaryName;
obj.InvokeMethod("Modify", MI, null);
errMessage = "CNAME:" + ownerName + "修改成功.";
return true;
}
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public bool DelCNAMEType(string hostName, string containerName)
{
try
{
string ownerName = BuildOwnerName(containerName, hostName);
this.Create("MicrosoftDNS_CNAMEType");
if (!IsExistsZone(containerName)) { errMessage = "區域:" + containerName + "不存在,刪除失敗"; return false; }
if (!IsExistsCNAMEType(containerName, ownerName)) { errMessage = containerName + "中不存在" + ownerName + ",刪除失敗"; return false; }
Q = QueryDNS("SELECT * FROM MicrosoftDNS_CNAMEType WHERE ContainerName='" + containerName + "' AND OwnerName='" + ownerName + "'");
foreach (ManagementObject obj in Q) { obj.Delete(); errMessage = "CNAME:" + ownerName + "刪除成功."; return true; }
return false;
}
catch (Exception e) { errMessage = e.Message; return false; }
}
public DataTable ListExistsCNAMEType(string containerName)
{
DataTable table = new DataTable("MicrosoftDNS_CNAMEType_" + containerName);
table.Columns.Add("別名 (CNAME)");
table.Columns.Add("別名主機");
table.Columns.Add("TTL");
try
{
Q = QueryDNS("SELECT * FROM MicrosoftDNS_CNAMEType WHERE ContainerName='" + containerName + "'");
foreach (ManagementObject obj in Q)
{
DataRow row = table.NewRow();
row["別名 (CNAME)"] = obj["OwnerName"];
row["別名主機"] = obj["PrimaryName"];
row["TTL"] = obj["TTL"];
table.Rows.Add(row);
}
}
catch (Exception e) { errMessage = e.Message; }
return table;
}
#endregion
#region 工具方法
private string ClearEndDot(string str)
{
if (!string.IsNullOrEmpty(str) && str.EndsWith(".")) return str.Substring(0, str.Length - 1);
return str;
}
#endregion
}
}
在主程式中實例化並呼叫:
namespace Yaosansi
{
class Test
{
static void Main()
{
MyDnsTEST();
}
static void MyDnsTEST()
{
Yaosansi.Net.MYDNS dns = new Yaosansi.Net.MYDNS();
// 遠端連線設定 (本機可不設)
dns.ServerName = "192.168.1.10"; // DNS 伺服器 IP
dns.userName = "Administrator";
dns.passWord = "YourPassword";
// 1. 建立區域
// dns.CreateZone("example.com");
// 2. 新增 A 記錄
// dns.CreateAType("example.com", "www", "192.168.1.50", "3600");
// 3. 新增 MX 記錄
// dns.CreateMXType("mail", "example.com", "mail.example.com.", "10", "3600");
// 4. 新增 CNAME 記錄
// dns.CreateCNAMEType("web", "example.com", "www.example.com.", "3600");
// 5. 查詢並列印 A 記錄
DataTable table = dns.ListExistsAType("example.com");
// 輸出至 Console 或 GridView
foreach (DataRow row in table.Rows)
{
Console.WriteLine($"{row["主機名 (A)"]} -> {row["IP 位址"]} (TTL: {row["TTL"]})");
}
// 錯誤處理
if (!string.IsNullOrEmpty(dns.ErrMessage))
{
Console.WriteLine("--------------------------------------------------");
Console.WriteLine("返回信息: " + dns.ErrMessage);
Console.WriteLine("--------------------------------------------------");
}
Console.WriteLine("===End===");
Console.ReadLine();
}
}
}
root\MicrosoftDNS)。在 Server 2008/2012/2016/2019/2022 上通常仍相容,但建議測試特定 WMI 類別是否存在。mail.example.com.),內部 ClearEndDot 方法會處理比對邏輯。透過 System.Management 命名空間操作 MicrosoftDNS_* WMI 類別,是 C# 在無第三方庫依賴下管理 Windows DNS 服務的標準方式。本文提供的 MYDNS 類別封裝了常見的區域與記錄 (A, MX, CNAME) 生命週期管理,開發者可直接整合至自動化部署、IP 管理系統或雲端資源編排流程中。