PowerShell How-To

Setting the DNS Server Search Order on Windows with PowerShell

PowerShell makes it very easy to set DNS server settings and then troubleshoot what might have gone wrong.

Many an IT administrator has needed to modify network interface settings in the past, usually via the graphical user interface (GUI). Besides just setting the IP address, if a system is statically addressed, one often needs to change the DNS servers that the interface uses to resolve IP addresses.

Rather than change the DNS servers via the GUI, we can save a lot of time and effort by modifying the interfaces via PowerShell. Here's how.

Find the Existing DNS Servers
Thankfully, PowerShell gives us a handy set of built-in Windows cmdlets to find everything we might want to know.

First things first -- let's get a list of our interfaces and their current DNS server settings. Next, we will run the command Get-DNSClientServerAddress without any parameters on a PowerShell prompt. As you can see from the output below, there are several interfaces returned. Every system will be different, though.

PS C:\> Get-DNSClientServerAddress

InterfaceAlias               Interface Address ServerAddresses
                             Index     Family
--------------               --------- ------- ---------------
vEthernet (DockerNAT)               49 IPv4    {}
vEthernet (DockerNAT)               49 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
Ethernet                            16 IPv4    {}
Ethernet                            16 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
Local Area Connection* 1            19 IPv4    {}
Local Area Connection* 1            19 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
Local Area Connection* 10           20 IPv4    {}
Local Area Connection* 10           20 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
Wi-Fi                               15 IPv4    {192.168.86.1}
Wi-Fi                               15 IPv6    {2601:246:8100:a111:d062:e1ff:fe3c:77e6}
Loopback Pseudo-Interface 1          1 IPv4    {}
Loopback Pseudo-Interface 1          1 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
vEthernet (Default Switch)          35 IPv4    {}
vEthernet (Default Switch)          35 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
vEthernet (WSL)                     55 IPv4    {}
vEthernet (WSL)                     55 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}

The output may show a lot of interfaces, especially if you use technologies such as the Windows Subsystem for Linux (WSL) or container services such as Docker. We need to filter the results to just what interface we are targeting to modify. In this case, we are most interested in the Ethernet interface, which has an interface index of 16.

Modify the DNS Server Settings
We know that 16 is the interface that we want to change the settings for. Instead of the default DNS server address here, we want to change this to IPv4 addresses 1.1.1.1 and 1.0.0.1, and to IPv6 addresses 2606:4700:4700::1111 and 2606:4700:4700::1001. These are the Cloudflare DNS addresses, but you can use any that you would like.

Below is an easy way to validate and set both IPv4 and IPv6 addresses for a given interface. Using the [IPAddress] type accelerator for [System.Net.IPAddress], we can both set the IP address and throw an error if an incorrect address is entered.

$DNSAddresses = @(
  ([IPAddress]'1.1.1.1').IPAddressToString
  ([IPAddress]'1.0.0.1').IPAddressToString
  ([IPAddress]'2606:4700:4700::1111').IPAddressToString
  ([IPAddress]'2606:4700:4700::1001').IPAddressToString  
)

Set-DnsClientServerAddress -ServerAddresses $DNSAddresses -InterfaceIndex 16

You may notice that both IPv4 and IPv6 addresses are included within the same array of addresses. Conveniently, the cmdlet will detect the addressing scheme and set it appropriately.

Make sure you run the Set-DnsClientServerAddress command elevated. It will not work otherwise and may output an error message similar to Set-DnsClientServerAddress: Access to a CIM resource was not available to the client.

Verify DNS Server Settings Are Changed
To make sure the settings are changed as expected, we can run Get-DnsClientServerAddress but with the parameter of InterfaceIndex to pull just the information for the interface we are modifying. As you can see below, the IP addresses were correctly set for the IPv4 and IPv6 families.

PS C:\> Get-DnsClientServerAddress -InterfaceIndex 16

InterfaceAlias               Interface Address ServerAddresses
                             Index     Family
--------------               --------- ------- ---------------
Ethernet                            16 IPv4    {1.1.1.1, 1.0.0.1}
Ethernet                            16 IPv6    {2606:4700:4700::1111, 2606:4700:4700::1001}

Set Multiple Systems DNS Server Addresses
Usually, as an IT administrator, we don't need to run this type of command on just one system but on many at once. To avoid having to individually remote to each one and modify them, we can use PowerShell to set this remotely en masse.

As you can see below, we are invoking the Set-DnsClientServerAddress on a series of servers. We are passing in the $DNSAddresses to the scriptblock by the $Using:DNSAddresses variable, which allows us to reference a variable from outside that scriptblock. Using splatting to pass in the parameters, we go ahead and set the DNS server addresses.

$DNSAddresses = @(
  ([IPAddress]'1.1.1.1').IPAddressToString
  ([IPAddress]'1.0.0.1').IPAddressToString
  ([IPAddress]'2606:4700:4700::1111').IPAddressToString
  ([IPAddress]'2606:4700:4700::1001').IPAddressToString  
)

$Servers = @(
    'Server1'
    'Server2'
    'Server3'
)

$InterfaceIndex = 16

Invoke-Command -ComputerName $Servers -ScriptBlock {
    $Params = @{
        'ServerAddresses' = $Using:DNSAddresses
        'InterfaceIndex'  = $Using:InterfaceIndex
    }
    
    Set-DnsClientServerAddress @Params
}

DNS Resolution Order
Sometimes you may find that when resolving an address, you are not getting the correct results back. In this case, you may want to look at the order Windows is resolving the address via DNS. The way that Windows 10 and Windows Server 2016 do this is by the interface metric. To see this together with the DNS servers, you can run the following to get a list.

$NetworkInterfaces  = Get-NetIPInterface | Where-Object ConnectionState -EQ 'Connected'
$DNSServerAddresses = Get-DnsClientServerAddress

$Combined = $NetworkInterfaces | ForEach-Object {
  [PSCustomObject]@{
    'InterfaceAlias'  = $_.InterfaceAlias
    'InterfaceIndex'  = $_.InterfaceIndex
    'InterfaceMetric' = $_.InterfaceMetric
    'DNSIPv4'         = ($DNSServerAddresses | Where-Object InterfaceIndex -EQ $_.InterfaceIndex | Where-Object AddressFamily -EQ 2).ServerAddresses
    'DNSIPv6'         = ($DNSServerAddresses | Where-Object InterfaceIndex -EQ $_.InterfaceIndex | Where-Object AddressFamily -EQ 23).ServerAddresses
  }
} | Sort-Object InterfaceMetric -Unique

$Combined | Format-Table -AutoSize

As you can tell from the output below, the first item may not be what you expect, but you should be able to trace the order of resolution. As a troubleshooting step, this might become useful.

InterfaceAlias              InterfaceIndex InterfaceMetric DNSIPv4            DNSIPv6
--------------              -------------- --------------- -------            -------
vEthernet (DockerNAT)                   49              15 {}                 {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
Ethernet                                16              35 {1.1.1.1, 1.0.0.1} {2606:4700:4700::1111, 2606:4700:4700::1001}
Loopback Pseudo-Interface 1              1              75 {}                 {}
vEthernet (WSL)                         55            5000 {}                 {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
vEthernet (Default Switch)              35            5000 {}                 {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}

Conclusion
PowerShell makes it very easy to set DNS server settings and then troubleshoot what might have gone wrong. If you need to see these settings on a high number of systems, PowerShell will allow you to scale up this approach effortlessly.

About the Author

Adam Bertram is a 20-year veteran of IT. He's an automation engineer, blogger, consultant, freelance writer, Pluralsight course author and content marketing advisor to multiple technology companies. Adam also founded the popular TechSnips e-learning platform. He mainly focuses on DevOps, system management and automation technologies, as well as various cloud platforms mostly in the Microsoft space. He is a Microsoft Cloud and Datacenter Management MVP who absorbs knowledge from the IT field and explains it in an easy-to-understand fashion. Catch up on Adam's articles at adamtheautomator.com, connect on LinkedIn or follow him on Twitter at @adbertram or the TechSnips Twitter account @techsnips_io.


comments powered by Disqus
Most   Popular