Powershell – Get DNS A records and export to CSV

Standard

When managing and cleaning up your IP addresses/ranges it can be very useful to get some lists of the records you have in your DNS zones. Here’s a simple script which gets the IP addresses/hostnames of the given DNS zones and exports the results to CSV.
The script is split into two parts Variables and script main. I will walk through and explain both parts below.

Variables

#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$CSV = "$dir\DNS_A_records.csv"
#parameters
$DNSServer = "Some_DNS_server"
$Zone1 = "myzone.local"
$Zone2 = "me.myzone.local"

I use the $dir object in the paths of my scripts as this object always points to the directory which the script has been run from. This is practical as it allows you to move/copy the script around without having to change any paths. $CSV is the path to the CSV file which will be created at the end of the script run.
Remember to fill out the parameters section before you run the script! $DNSServer is the name of your DNS server. $Zone1, $Zone2… etc are the names of the DNS zones which you want to get A records from. If you have more than 2 zones to get A records from then just add more objects to match the number of zones you need and add the zone names.

Script Main

#SCRIPT MAIN
clear
$DNS_Zones = @()
$DNS_Zones += $Zone1
$DNS_Zones += $Zone2
$hosts = @()
$DNS_Zones | % {
	$zone = $_
	Write-Host "Getting DNS A records from $zone"	
	$DNS_A_records = @(Get-WmiObject -Class MicrosoftDNS_AType -NameSpace Root\MicrosoftDNS -ComputerName $DNSServer -Filter "ContainerName = `'$zone`'")
	$DNS_A_records | % {
		$hostA = "" | select "hostname","IPAddress"
		$hostA.hostname = $_.OwnerName
		$hostA.IPAddress = $_.IPAddress
		$hosts += $hostA
	}
}
$hosts = $hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
$hosts | Export-Csv $CSV -NoTypeInformation -Force

In the script main I first create the array $DNS_Zones which will hold the different zone names. Then the zone names ($Zone1, $Zone2… etc.) are added to the array. If you created more than two zone objects in the variables section you must add them here too.
I now create the $hosts array which will hold the records we will wish export later. The next thing that happens is that we loop through the $DNS_Zones array. For each DNS Zone we get all A records using WMI and for each of these, a custom object with the properties hostname and IPAddress is created and added to the $hosts array.
I then sort the $hosts array by IP Address using the following code:
$hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
The @{Expression} argument allows you to add the [version] type declaration on the IPAddress property on the array elements/objects which in turn enables you to easily sort the IPs.
Finally the $hosts array is exported to CSV using the great Export-CSV powershell cmdlet.
I have copied in the full script below.I hope you find it useful. Enjoy!

################################################################################################
##Script:			Get-DNS_A_Records.ps1
##
##Description:		Gets all DNS A records from a given DNS server and exports the information 
#+					to a CSV file.
##Created by:		Noam Wajnman
##Creation Date:	April 07, 2014
################################################################################################
#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$CSV = "$dir\DNS_A_records.csv"
#parameters
$DNSServer = "Some_DNS_server"
$Zone1 = "myzone.local"
$Zone2 = "me.myzone.local"
#SCRIPT MAIN
clear
$DNS_Zones = @()
$DNS_Zones += $Zone1
$DNS_Zones += $Zone2
$hosts = @()
$DNS_Zones | % {
	$zone = $_
	Write-Host "Getting DNS A records from $zone"	
	$DNS_A_records = @(Get-WmiObject -Class MicrosoftDNS_AType -NameSpace Root\MicrosoftDNS -ComputerName $DNSServer -Filter "ContainerName = `'$zone`'")
	$DNS_A_records | % {
		$hostA = "" | select "hostname","IPAddress"
		$hostA.hostname = $_.OwnerName
		$hostA.IPAddress = $_.IPAddress
		$hosts += $hostA
	}
}
$hosts = $hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
$hosts | Export-Csv $CSV -NoTypeInformation -Force

Powershell – Set static DNS on remote servers

Standard

Recently I was tasked with the job of changing the DNS search order on all the windows servers we use in my company. Since I didn’t want to change it manually by going into the TCP/IP settings of the NIC on each server I decided to write a script to help me do this.

I am working in a sensitive production environment so I needed to not only change the settings but also check that the changes were made successfully on all servers. To accomplish this I added some functionality to the script to confirm that the changes were made and write all the information to a log file. This log file could then be reviewed later for errors.

I have built the script in three different sections – variables, functions and script main. To begin with I will quickly explain the variables section.

VARIABLES

I don’t like working with too many absolute paths in my scripts because one needs to change them if they are moved to another computer or location. Therefore I use the following code so I always have an object pointing to the script directory.

$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath

When used, $dir will always point to the directory where the script was run. $log_dir specifies the path to a directory names /logs which will be used later on.

The script takes input from a file called “servers.txt” which must be placed in the script directory. $servers is an array created and populated by running Get-Content on “servers.txt”. The parameters section contains the $dns1, $dns2, $dns3 objects which will be set on the servers listed in “servers.txt” – remember to fill these out with the appropriate values before running the script.

#VARIABLES
$DebugPreference = "continue"
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$log_dir = "$dir\logs"
$servers = @(gc "$dir\servers.txt")
#parameters - Add the desired DNS servers below
[string]$dns1 = "192.168.1.2"
[string]$dns2 = "192.168.1.3"
[string]$dns3 = "192.168.1.4"

That covers the variables section – now to the functions. The script is built on four different functions which I will go over now.

FUNCTIONS

1. Function Create-Log

function Create-Log {
	$time = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
	$logFilePath = "$log_dir\SetStaticDNS_$time.log"
	New-Item -ItemType File $logFilePath -Force
}
 

This little function simply creates a logfile in $dir\logs\ which will be used by the script to record the results of attempting to change the DNS settings on each server.

2. Function Write-ToLog

function Write-ToLog {
	param (
		[string]$message
		)
	$time = Get-Date
	$logEntryStr = "$time`t" + $message
	$logEntryStr | Out-File -Append $logFilePath -Width 400
}
 

Write-ToLog takes a parameter “message” and appends it to the log file with a time stamp

3. Get-ActiveNicIP

function Get-ActiveNicIP {
 	param (
 		[Parameter(Mandatory=$true)][string]$computer
 	)
 	Write-ToLog -message "Getting IP of 'active' interface on $computer ..."
 	$conx = Test-Connection -ComputerName $computer -Count 1
 	$ActiveIP = $conx.IPV4Address.IPAddressToString
 	Write-ToLog -message "Active IP on $computer is $ActiveIP"
 	return $ActiveIP
}

Some servers can have several NICs/Teams in use and I wanted to make sure that I only change the DNS settings on the NIC which answers to the hostname of the server. Get-ActiveNicIP simply pings the server given as the parameter “computer” and returns the IP which answers.

4. Function Set-StaticDNS

function Set-StaticDNS {
	param (
		[Parameter(Mandatory=$true)][string]$computer,
		[Parameter(Mandatory=$true)][string]$ActiveIP
	)
	Write-ToLog -message "Attempting to set DNS search order on computer 	$computer on the interface with the IP $ActiveIP"
	#get dns info via WMI
	$wmi = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" -ComputerName $computer | ? { $_.IPAddress -match $ActiveIP }
	#set dns search order via WMI
	$wmi.SetDNSServerSearchOrder($DnsSearchOrder)
	#confirm that dns search order was set to desired value.
	$StrdnsSearchOrder = $dnsSearchOrder | Out-String
	$wmi2 = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" -ComputerName $computer | ? { $_.IPAddress -match $ActiveIP }
	$StrWmiDnsSearchOrder = $wmi2.DNSServerSearchOrder | Out-String
	if ($StrWmiDnsSearchOrder -eq $StrdnsSearchOrder) {
	Write-ToLog -message "Setting the DNS search order was successful. Value is now $dnsSearchOrder"
	}
	else {
		Write-ToLog -message "Error - Setting the DNS search order failed!"
	}
}

The Set-Static DNS function takes a computer and an IP as parameters and then uses WMI to change the DNS search order on the NIC.
That covers the functions – now to the script main.

SCRIPT MAIN

#SCRIPT MAIN
clear
$dnsSearchOrder = @()
$dnsSearchOrder += @($dns1)
$dnsSearchOrder += @($dns2)
$dnsSearchOrder += @($dns3)
$logFilePath = Create-Log
Write-ToLog -message "Starting script Set-StaticDNS.ps1...."
Write-ToLog -message "Setting DNS search order on all servers in 'servers.txt' to $dnsSearchOrder"
Write-ToLog -message "----------------------------------------------------------------------------------------------------------`n`n"
$servers | % {
	$ActiveIP = Get-ActiveNicIP -computer $_
	Set-StaticDNS -computer $_ -ActiveIP $ActiveIP
}
Write-ToLog -message "`n`n----------------------------------------------------------------------------------------------------------"
Write-ToLog -message "Script run ended."

The script main simply loops through the $servers array and runs the Get-ActiveNipIP and Set-StaticDNS functions on each server.
That should explain how the script works. I have copied in the full script below.
Enjoy!

################################################################################################
##Script:		Set-StaticDNS.ps1
##
##Description:		Sets the DNS search order on the servers given as input in servers.txt
#+			to the IP addresses specified in the parameters section.
##Created by:		Noam Wajnman
##Creation Date: December 9, 2013
################################################################################################
#FUNCTIONS
function Create-Log {
	$time = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
	$logFilePath = "$log_dir\SetStaticDNS_$time.log"
	New-Item -ItemType File $logFilePath -Force
}
function Write-ToLog {
	param (
		[string]$message
	)
	$time = Get-Date
	$logEntryStr = "$time`t" + $message
	$logEntryStr | Out-File -Append $logFilePath -Width 400
}
function Get-ActiveNicIP {
	param (
		[Parameter(Mandatory=$true)][string]$computer
	)
	Write-ToLog -message "Getting IP of 'active' interface on $computer ..."
	$conx = Test-Connection -ComputerName $computer -Count 1
	$ActiveIP = $conx.IPV4Address.IPAddressToString
	Write-ToLog -message "Active IP on $computer is $ActiveIP"
	return $ActiveIP
}
function Set-StaticDNS {
	param (
		[Parameter(Mandatory=$true)][string]$computer,
		[Parameter(Mandatory=$true)][string]$ActiveIP
	)
	Write-ToLog -message "Attempting to set DNS search order on computer $computer on the interface with the IP $ActiveIP"
	#get dns info via WMI
	$wmi = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" -ComputerName $computer | ? { $_.IPAddress -match $ActiveIP }
	#set dns search order via WMI
	$wmi.SetDNSServerSearchOrder($DnsSearchOrder)
	#confirm that dns search order was set to desired value.
	$StrdnsSearchOrder = $dnsSearchOrder | Out-String
	$wmi2 = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" -ComputerName $computer | ? { $_.IPAddress -match $ActiveIP }
	$StrWmiDnsSearchOrder = $wmi2.DNSServerSearchOrder | Out-String
	if ($StrWmiDnsSearchOrder -eq $StrdnsSearchOrder) {
		Write-ToLog -message "Setting the DNS search order was successful. Value is now $dnsSearchOrder"
	}
	else {
		Write-ToLog -message "Error - Setting the DNS search order failed!"
	}
}
#VARIABLES
$DebugPreference = "continue"
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$log_dir = "$dir\logs"
$servers = @(gc "$dir\servers.txt")
#parameters - Add the desired DNS servers below
[string]$dns1 = "192.168.1.2"
[string]$dns2 = "192.168.1.3"
[string]$dns3 = "192.168.1.4"
#SCRIPT MAIN
clear
$dnsSearchOrder = @()
$dnsSearchOrder += @($dns1)
$dnsSearchOrder += @($dns2)
$dnsSearchOrder += @($dns3)
$logFilePath = Create-Log
Write-ToLog -message "Starting script Set-StaticDNS.ps1...."
Write-ToLog -message "Setting DNS search order on all servers in 'servers.txt' to $dnsSearchOrder"
Write-ToLog -message "----------------------------------------------------------------------------------------------------------`n`n"
$servers | % {
	$ActiveIP = Get-ActiveNicIP -computer $_
	Set-StaticDNS -computer $_ -ActiveIP $ActiveIP
}
Write-ToLog -message "`n`n----------------------------------------------------------------------------------------------------------"
Write-ToLog -message "Script run ended."