Always Upgrading Blog

A blog (mostly) about Enterprise IT upgrades.

Change Primary and Secondary DNS servers With Powershell and VMware PowerCLI

Incompatible Message

As I’m in the process of wiping and reloading a bunch of 2008R2 domain controllers with Server 2019, I created a handy Powershell script to change the primary and secondary DNS server settings. This is useful to ensure the primary DNS server is not set to a server that will be offline. I discovered the hard way that when reloading a server with the same hostname and IP, that DNS will not gracefully utilise the secondary DNS server if the primary IP is responding but not answering DNS queries (as is the case before DNS is reinstalled when the 2019 server is promoted).

The script takes advantage of the VMware PowerCLI to retrieve Windows server names on a per VMware Cluster basis, these are then cycled through and the DNS settings updated for each.

I’m using netsh to update DNS as some of the servers are not running more modern operating systems, so native Powershell commands wouldn’t work for all whereas netsh would.

The Get-NicName funtion exists to find the active NIC containing the DNS servers you want to change, it checks each NIC on the server for an existing DNS server and returns the NIC name. This is to ensure we only update the right NIC on servers with multiple NICs installed.

The complete script is below:

# Add the VMware Module
Import-Module VMware.PowerCLI

# Get Admin Credentials
$Credentials = Get-Credential

# Connect to vCenter
Connect-VIServer -Server <your vcenter here> -Credential $Credentials

# Existing DNS Server to check for before updating
$ExistingDNSServer = <your old DNS server here>

# New DNS Servers to set on each server
$NewPrimaryDNSServer = <your new primary DNS server here>
$NewSecondaryDNSServer = <your new secondary DNS server here>

# The VMware Cluster containing the servers on which we want to update the DNS server settings
$VMCluster = <your VMware cluster here>

# Don't edit below here...

function Get-NicName {
    param (
    Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Credential $Credentials | Where-Object {$_.DNSServerSearchOrder -contains $ExistingDNSServer} | ForEach-Object {
        $filter = "Index = $($_.Index)"
        $NicName = (Get-WmiObject Win32_NetworkAdapter -filter $filter -ComputerName $ComputerName -Credential $Credentials).NetConnectionID
        return $NicName

function Set-DnsServerIpAddresses {
    param (
    if (Test-Connection -ComputerName $ComputerName -Count 2 -Quiet) {
        Invoke-Command -ComputerName $ComputerName -Credential $Credentials -ScriptBlock { param ($ComputerName, $NicName, $PrimaryDNS, $SecondaryDNS)
            Write-Host "Clearing DNS Server settings on $NicNAme for $ComputerName"
            Invoke-Expression "netsh interface ip delete dnsservers ""$NicName"" all"
            Write-Host "Setting $PrimaryDNS as the Primary DNS server on $NicName for $ComputerName"
            Invoke-Expression "netsh interface ip add dns name=""$NicName"" addr=$PrimaryDNS"
            Write-Host "Setting $SecondaryDNS as the Secondary DNS server on $NicName for $ComputerName"
            Invoke-Expression "netsh interface ip add dns name=""$NicName"" addr=$SecondaryDNS index=2"
        } -ArgumentList $ComputerName, $NicName, $PrimaryDNS, $SecondaryDNS
    } else {
        Write-Host "Can't access $ComputerName. This computer is not online."

$vmlist = Get-Cluster $VMCluster | Get-VM | Where-Object {$_.Guest -like "*Windows*"} | Sort-Object name

$vmlist | ForEach-Object {
    $adapter = Get-NicName -ComputerName $_.Name
    #Write-Host $adapter
    Set-DnsServerIpAddresses -ComputerName $_.Name -NicName $adapter -PrimaryDNS $NewPrimaryDNSServer -SecondaryDNS $NewSecondaryDNSServer

# Clean up
Disconnect-VIServer -Force -Confirm:$false
Remove-Module VMware.PowerCLI

As the script only works for Windows VM’s, if you’d like to return a list of non-windows VMs to manually update their settings you can utilize the command below:

Get-Cluster <your cluster here> | Get-VM | Where {$_.Guest -notlike "*Windows*"} | select name,@{N="Configured OS";E={$_.ExtensionData.Config.GuestFullname}} | sort name