简体   繁体   中英

How to Change DNS with C# on Windows 10

I'm trying to change the DNS on Windows 10 through VB.NET.

I have code that works on Windows 7, however it does not work on Windows 10.

Here is my code for Windows 7 that changes the DNS:

ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
    if ((bool)mo["IPEnabled"])
    {
        ManagementBaseObject objdns = mo.GetMethodParameters("SetDNSServerSearchOrder");
        if (objdns != null)
        {
            string[] s = { "192.168.XX.X", "XXX.XX.X.XX" };
            objdns["DNSServerSearchOrder"] = s;
            mo.InvokeMethod("SetDNSServerSearchOrder", objdns, null);

My question is, how do I get this to work on Windows 10 OS?

First you need to get the NetworkInterface you want to set/unset DNS

I've tested this code on the latest version of Windows 10 and it works like a charm!

Here is the code to find the active Ethernet or Wifi network (Not 100% accurate but useful in most cases)

public static NetworkInterface GetActiveEthernetOrWifiNetworkInterface()
{
    var Nic = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(
        a => a.OperationalStatus == OperationalStatus.Up &&
        (a.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || a.NetworkInterfaceType == NetworkInterfaceType.Ethernet) &&
        a.GetIPProperties().GatewayAddresses.Any(g => g.Address.AddressFamily.ToString() == "InterNetwork"));

    return Nic;
}

SetDNS

public static void SetDNS(string DnsString)
{
    string[] Dns = { DnsString };
    var CurrentInterface = GetActiveEthernetOrWifiNetworkInterface();
    if (CurrentInterface == null) return;

    ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
    ManagementObjectCollection objMOC = objMC.GetInstances();
    foreach (ManagementObject objMO in objMOC)
    {
        if ((bool)objMO["IPEnabled"])
        {
            if (objMO["Description"].ToString().Equals(CurrentInterface.Description))
            {
                ManagementBaseObject objdns = objMO.GetMethodParameters("SetDNSServerSearchOrder");
                if (objdns != null)
                {
                    objdns["DNSServerSearchOrder"] = Dns;
                    objMO.InvokeMethod("SetDNSServerSearchOrder", objdns, null);
                }
            }
        }
    }
}

UnsetDNS

public static void UnsetDNS()
{
    var CurrentInterface = GetActiveEthernetOrWifiNetworkInterface();
        if (CurrentInterface == null) return;

    ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
    ManagementObjectCollection objMOC = objMC.GetInstances();
    foreach (ManagementObject objMO in objMOC)
    {
        if ((bool)objMO["IPEnabled"])
        {
            if (objMO["Description"].ToString().Equals(CurrentInterface.Description))
            {
                ManagementBaseObject objdns = objMO.GetMethodParameters("SetDNSServerSearchOrder");
                if (objdns != null)
                {
                    objdns["DNSServerSearchOrder"] = null;
                    objMO.InvokeMethod("SetDNSServerSearchOrder", objdns, null);
                }
            }
        }
    }
}

Usage

SetDNS("127.0.0.1");

Combining multiple solutions I found that the following code is working great for Windows 10 and 8.1 (others not tested, but should work as well):

public static void setDNS(string NIC, string DNS)
{
    ConnectionOptions options = PrepareOptions();
    ManagementScope scope = PrepareScope(Environment.MachineName, options, @"\root\CIMV2");
    ManagementPath managementPath = new ManagementPath("Win32_NetworkAdapterConfiguration");
    ObjectGetOptions objectGetOptions = new ObjectGetOptions();
    ManagementClass mc = new ManagementClass(scope, managementPath, objectGetOptions);
    ManagementObjectCollection moc = mc.GetInstances();
    foreach (ManagementObject mo in moc)
    {
        if ((bool)mo["IPEnabled"])
        {
            if (mo["Caption"].ToString().Contains(NIC))
            {
                try
                {
                    ManagementBaseObject newDNS = mo.GetMethodParameters("SetDNSServerSearchOrder");
                    newDNS["DNSServerSearchOrder"] = DNS.Split(',');
                    ManagementBaseObject setDNS = mo.InvokeMethod("SetDNSServerSearchOrder", newDNS, null);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    Console.ReadKey();
                    throw;
                }
            }
        }
    }
}

The application needs to run with elevated permissions (in my case I'm starting an elevated process running an .exe):

private void callSwapDNS(string NIC, string DNS)
{
    const int ERROR_CANCELLED = 1223; //The operation was canceled by the user.
    ProcessStartInfo info = new ProcessStartInfo(@"swap.exe");
    string wrapped = string.Format(@"""{0}"" ""{1}""", NIC, DNS);
    info.Arguments = wrapped;
    info.UseShellExecute = true;
    info.Verb = "runas";
    info.WindowStyle = ProcessWindowStyle.Hidden;
    try
    {
        Process.Start(info);
        Thread.Sleep(500);
    }
    catch (Win32Exception ex)
    {
        if (ex.NativeErrorCode == ERROR_CANCELLED)
            MessageBox.Show("Why you no select Yes?");
        else
            throw;
    }
}

Using mo["Caption"].ToString().Contains(NIC) doesn't work for Windows 10 as the WMI query returns the NIC-Name leading with [000000]

[000000] Intel(R) 82574L Gigabit Network Connection

on my Windows 10 machine.

Credit to the following answers: [WMI not working after upgrading to Windows 10

WMI not working after upgrading to Windows 10
How can you change Network settings (IP Address, DNS, WINS, Host Name) with code in C#

and the answers to this question.

With Windows 10 you may need authentication first. Pass a ConnectionOptions instance to a ManagementScope constructor, defining your Authentication and Impersonation properties.

Try this:

// Method to prepare the WMI query connection options.
public static ConnectionOptions PrepareOptions ( )
{
  ConnectionOptions options = new ConnectionOptions ( );
  options . Impersonation = ImpersonationLevel . Impersonate;
  options . Authentication = AuthenticationLevel . Default;
  options . EnablePrivileges = true;
  return options;
}

// Method to prepare WMI query management scope.
public static ManagementScope PrepareScope ( string machineName , ConnectionOptions options , string path  )
{
  ManagementScope scope = new ManagementScope ( );
  scope . Path = new ManagementPath ( @"\\" + machineName + path );
  scope . Options = options;
  scope . Connect ( );
  return scope;
}

// Set DNS.
ConnectionOptions options = PrepareOptions ( );
ManagementScope scope = PrepareScope ( Environment . MachineName , options , @"\root\CIMV2" );
ManagementClass mc = new ManagementClass(scope, "Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
    if ((bool)mo["IPEnabled"])
    {
        ManagementBaseObject objdns = mo.GetMethodParameters("SetDNSServerSearchOrder");
        if (objdns != null)
        {
            string[] s = { "192.168.XX.X", "XXX.XX.X.XX" };
            objdns["DNSServerSearchOrder"] = s;
            mo.InvokeMethod("SetDNSServerSearchOrder", objdns, null);

Based on this answer:

WMI not working after upgrading to Windows 10

This is the code I use to do this and it works:

/// <summary>
/// Set's the DNS Server of the local machine
/// </summary>
/// <param name="NIC">NIC address</param>
/// <param name="DNS">DNS server address</param>
/// <remarks>Requires a reference to the System.Management namespace</remarks>
public void setDNS(string NIC, string DNS)
{
    ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
    ManagementObjectCollection objMOC = objMC.GetInstances();

    foreach (ManagementObject objMO in objMOC)
    {
        if ((bool)objMO["IPEnabled"])
        {
            // if you are using the System.Net.NetworkInformation.NetworkInterface you'll need to change this line to if (objMO["Caption"].ToString().Contains(NIC)) and pass in the Description property instead of the name 
            if (objMO["Caption"].Equals(NIC))
            {
                try
                {
                    ManagementBaseObject newDNS =
                        objMO.GetMethodParameters("SetDNSServerSearchOrder");
                    newDNS["DNSServerSearchOrder"] = DNS.Split(',');
                    ManagementBaseObject setDNS =
                        objMO.InvokeMethod("SetDNSServerSearchOrder", newDNS, null);
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }
    }
}

Hope it helps...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM