Manage DNS in a Windows Environment by Using PowerShell

Manage DNS in a Windows Environment by Using PowerShell

  • Comments 6
  • Likes

Summary: Manage DNS in a Windows environment by using Windows PowerShell. Guest Blogger Richard Siddaway shows how to do it in a simple and effective manner.

 

Hey, Scripting Guy! Question Hey, Scripting Guy! What can I do with Windows PowerShell to manage my DNS infrastructure?

-- RS

 

Hey, Scripting Guy! Answer

Hello RS,

Microsoft Scripting Guy Ed Wilson here. I am happy to announce that this is Guest Blogger Week. I love to host these guest bloggers because they give our readers a glimpse into other professionals’ minds and knowledge. Today, we have Richard Siddaway. Richard is a technical architect for Serco in the United Kingdom. He works on transformation projects in the local government and commercial arena. With more than 20 years of experience in various aspects of information technology, Richard specializes in the Microsoft environment at an architectural level, especially around Active Directory, Exchange, SQL Server, and infrastructure optimization.

Richard is always looking for the opportunity to automate a process, preferably with Windows PowerShell. Richard founded and currently leads the UK Windows PowerShell User Group. Microsoft has recognized his technical expertise and community activities by presenting him with a Microsoft Most Valued Professional award. Richard has presented to the Directory Experts Conference, at various events at Microsoft in the UK and Europe, and for other UK User Groups. He has a number of articles and technical publications to his credit, and his first print book has recently been released. The subject? Windows PowerShell, of course.

Blog: http://msmvps.com/blogs/RichardSiddaway/Default.aspx

Book details: http://www.manning.com/siddaway

Take it away, Richard…

_______

RS, the short answer to the question about using Windows PowerShell to manage DNS is that you can do anything you want. The longer answer is that you have to work at it a bit. Some areas of working with DNS have already been blogged about by Ed Wilson of the Microsoft Scripting Guys. Here are links to his articles:

Windows PowerShell doesn’t have any way of directly working with DNS. However, there is a great set of WMI classes. They are installed automatically when DNS is installed. At this point, you might be groaning “I don’t like WMI; it’s too hard”. It used to be. Windows PowerShell has brilliant WMI support that makes using it easy and well worth spending a bit of time learning, as you will see.

A new namespace is created for the DNS WMI classes: root\MicrosoftDNS. Because we are using WMI, we can access the DNS server remotely (which makes administration easier). The classes available to work with DNS can be found by using Windows PowerShell:

Get-WmiObject -Namespace root\MicrosoftDNS -List 

The DNS classes from a remote DNS server running on a Windows Server 2008 domain controller are shown in the following image.

Image of DNS classes from remote DNS server running on Windows Server 2008 domain controller

In a modern Windows environment, most machines will register their own addresses with DNS (we may need to set reverse lookup—PTR—records through DHCP). There is still a need to create DNS records from time to time, such as if you need to create an alias record. You have a number of WMI classes for working with different DNS record types, which you can see here:

Get-WmiObject -Namespace root\MicrosoftDNS -List *type | Format-Wide -Column 3
MicrosoftDNS_MGType MicrosoftDNS_X25Type MicrosoftDNS_AFSDBType
MicrosoftDNS_PTRType MicrosoftDNS_KEYType MicrosoftDNS_SRVType
MicrosoftDNS_MDType MicrosoftDNS_MBType MicrosoftDNS_AAAAType
MicrosoftDNS_ISDNType MicrosoftDNS_MINFOType MicrosoftDNS_RPType
MicrosoftDNS_SIGType MicrosoftDNS_MFType MicrosoftDNS_AType
MicrosoftDNS_WKSType MicrosoftDNS_WINSRType MicrosoftDNS_SOAType
MicrosoftDNS_MXType MicrosoftDNS_WINSType MicrosoftDNS_ATMAType
MicrosoftDNS_NSType MicrosoftDNS_NXTType MicrosoftDNS_RTType
MicrosoftDNS_CNAMEType MicrosoftDNS_TXTType MicrosoftDNS_HINFOType
MicrosoftDNS_MRType

I’ve written various scripts in the past to work with individual record types, and I’ve found that each class has slightly different syntax and requirements. This makes life awkward when you want to start automating this process, because you have to have a different script or function for each record type. I decided I wanted a universal script for creating records so that I could create multiple records at the same time from minimal information. The following script shows the function that I came up with to create A, PTR, MX, and CNAME records—these being the most common ones I have to deal with. We will be using the MicrosoftDNS_ResourceRecord class with varying inputs.

function new-dnsrecord {
param(
   
[string]$server,
   
[string]$fzone,
   
[string]$rzone,
   
[string]$computer,
   
[string]$address,
   
[string]$alias,
   
[string]$maildomain,
   
[int]$priority,
   
[switch]$arec,
   
[switch]$ptr,
   
[switch]$cname,
   
[switch]$mx
)
## check DNS server contactable
   
if (-not (Test-Connection -ComputerName $server)){Throw "DNS server not found"}
## split the server fqdn and address
   
$srvr = $server -split "\."
   
$addr = $address -split "\."

   
$rec = [WmiClass]"\\$($srvr[0])\root\MicrosoftDNS:MicrosoftDNS_ResourceRecord" 
##
## create records
## 
## A
   
if ($arec){
       
$text = "$computer IN A $address" 
       
$rec.CreateInstanceFromTextRepresentation($server, $fzone, $text) 
   
}
## CNAME
   
if ($cname){
       
$text = "$alias IN CNAME $computer" 
       
$rec.CreateInstanceFromTextRepresentation($server, $fzone, $text) 
   
}
## PTR
   
if ($ptr){
       
$text = "$($addr[3]).$rzone IN PTR $computer" 
       
$rec.CreateInstanceFromTextRepresentation($server, $rzone, $text) 
   
}
## MX
   
if ($mx){
       
$text = "$maildomain IN MX $priority $computer" 
       
$rec.CreateInstanceFromTextRepresentation($server, $fzone, $text) 
   
}
}

The script was written using Windows PowerShell 2.0, but it is usable in Windows PowerShell1.0 with suitable modifications as detailed in the text. The first change is in the section where we test the connectivity to the DNS server (the Test-Connection cmdlet was introduced in version 2.0 of Windows PowerShell). We can overcome this problem by replacing that line with this one:

if ((Get-WmiObject -Query "Select * from Win32_PingStatus WHERE Address = '$server'").StatusCode -ne 0){Throw "DNS server not found"}

More information about using Win32_PingStatus can be found on MSDN at http://msdn.microsoft.com/en-us/library/aa394350(VS.85).aspx#1

OK, let’s pick this function apart. I start out by defining a bunch of parameters. I haven’t used any of the advanced function capabilities here so as to ensure maximum usability of the script. A deliberate decision was made to avoid using parameter sets because this would cause additional complexity when I wanted to create multiple records. The parameters are as follows:

Parameter

Type

Meaning

$server

String

DNS Server FQDN

$fzone

String

Forward lookup zone

$rzone

String

Reverse lookup zone

$computer

String

Computer FQDN for which we are creating DNS entry

$address

String

Address of the computer

$alias

String

Alias of the computer

$maildomain

String

Mail domain

$priority

Int

Mail priority

$arec

Switch

Create A record

$ptr

Switch

Create PTR record

$cname

Switch

Create Alias record

$mx

Switch

Create MX (mail server) record

I haven’t defined any defaults for the parameters. After the parameter definitions, you can check whether the DNS server is contactable as mentioned earlier. It is possible to test if the DNS service was actually running by using one or the other of these Get commands:

Get-Service (Windows PowerShell 2.0 has a computername parameter) 

Get-Service -Name DNS

WMI (computername parameter in Windows PowerShell versions 2.0 and 1.0)

Get-WmiObject -Class Win32_Service -Filter "Name = 'DNS'"

The next task is to split the server and address into their separate parts. They both have a period (“.”) as the separator. Using the –split operator, you need to escape the dot using the back slash (“\”) character. An alternative, which will work in PowerShell 1.0 as well, is to use the Split() method of the string class:

$server = "server02.manticore.org"
$address = "10.10.54.27"
$srvr = $server.Split(".")
$addr = $address.Split(".")

In this case, you don’t need the escape character.

The final preparatory step is to create an instance of the MicrosoftDNS_ResourceRecord class using the [wmiclass] type accelerator. A type accelerator is used as a shortcut to a .NET Framework class. In this case, we create an instance of the System.Management.ManagementClass. In other words, you are creating a WMI class. When you use Get-WmiObject, you are getting an instance of an existing class, and Windows PowerShell returns an object from the System.Management.ManagementObject class:

$rec = [WmiClass]\\server02\root\MicrosoftDNS:MicrosoftDNS_ResourceRecord

$rec | gm

Using gm (an alias for Get-Member), we can view the class of object we have created:

TypeName: System.Management.ManagementClass#ROOT\MicrosoftDNS\MicrosoftDNS_ResourceRecord

You can also determine the methods that are available to this class:

CreateInstanceFromTextRepresentation

GetObjectByTextRepresentation

You can use CreateInstanceFromTextRepresentation, which must be one of the longest method names I’ve come across. It’s not something I want to type on a regular basis, and at moments like this, I’m extremely grateful to the inventors of cut and paste.

The last step in the script is to create the DNS records:

    if ($arec){

       
$text = "$computer IN A $address" 

       
$rec.CreateInstanceFromTextRepresentation($server, $fzone, $text) 

   
}

Now test to see if the switch for that record type is set (remember that switch parameters default to false so you can just ignore them if you don’t need to create a record of a particular type). If it is set, you create the appropriate text for the record and call the CreateInstanceFromTextRepresentation method, which takes three parameters:

  • DNS server
  • DNS zone
  • Text representation of DNS record.

Let’s create some records. There are a number of common parameters:

  • Server name
  • Computer name (host which new record points to) and its address
  • A zone, usually the forward lookup zone.

 

A record

The only additional parameter is the switch to tell the script to create an A record:

new-dnsrecord -server server02 -fzone 'manticore.org' `

-computer 'test27.manticore.org' -address 10.10.54.241 -arec

PTR Record

The reverse lookup zone needs to be supplied as well as the –prt switch:

new-dnsrecord -server server02 -rzone '54.10.10.in-addr.arpa' `

-computer 'test27.manticore.org' -address 10.10.54.241 -ptr

Alias Record

This adds the -alias parameter and uses the –cname switch rather than the –arec switch that we saw with the A record:

new-dnsrecord -server server02 -fzone 'manticore.org' -computer 'test27.manticore.org' `

-alias 'mydnstest.manticore.org' -cname

MX record

This one is a bit different in that you add the mail domain along with a priority. The priority dictates which mail server is used; the lowest priority value wins. The example is completed by using an –mx switch:

new-dnsrecord -server server02 -fzone 'manticore.org' -computer 'test27.manticore.org' `

-maildomain 'manticore.org' -priority 10 -mx

Multiple records

You can put several of the previous examples together to use this function to create a number of records at the same time:

new-dnsrecord -server server02 -fzone 'manticore.org' -rzone '54.10.10.in-addr.arpa' `

-computer 'test27.manticore.org' -address 10.10.54.241 -alias 'mydnstest.manticore.org' `

-arec -cname -ptr

This example creates an A record, a PTR record, and an alias, all in one pass. You have to supply the reverse lookup zone, although that could be calculated from the address parameter if required, as well as the alias.

The function can be easily extended if other record types are required. If your environment has a single forward zone and a single reverse zone, it would be possible to set those values as defaults for the relevant parameters. This would save some typing and make the script easier to use.

It is also possible to use this script for the bulk creation of DNS records. Put the data in a CSV file and pipe the contents into foreach with the function call within the foreach.

As well as showing how to use the DNS WMI classes, this script has a number of useful techniques that can be used in other places.

Further information about using Windows PowerShell to administer DNS can be found in chapter 9 of PowerShell in Practice and in a recording of a PowerShell User Group meeting.

 

RS, that is all there is to using Windows PowerShell to work with DNS. And thank you, Richard, for writing such an informative post. Guest Blogger Week will continue tomorrow when we will talk about SharePoint with Josh Gavant as our guest.

We would love for you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • How does this line work?

    $rec.CreateInstanceFromTextRepresentation($server, $fzone, $text)

    Isn't a fourth argument required? (msdn.microsoft.com/.../ms682714(v=VS.85).aspx)

  • Hi Laurence

    Thanks for the question.  The function in the post essentially does this.

    $server = "server02"

    $fzone = 'manticore.org'

    $text = "test27.manticore.org IN A 10.10.54.241"

    $rec = [WmiClass]"\\$server\root\MicrosoftDNS:MicrosoftDNS_ResourceRecord"

    $rec.CreateInstanceFromTextRepresentation($server, $fzone, $text)

    You are correct in that the documentation does show four arguments. The fourth is the output from the completion of the method. It isn't needed for the method to work. In fact if you try

    $rec.CreateInstanceFromTextRepresentation($server, $fzone, $text, $rout)

    You will get an error that states

    Cannot find an overload for "CreateInstanceFromTextRepresentation" and the argument count: "4".

    We can see how to use the output in this script

    $server = "server02"

    $fzone = 'manticore.org'

    $text = "test27.manticore.org IN A 10.10.54.241"

    $rec = [WmiClass]"\\$server\root\MicrosoftDNS:MicrosoftDNS_ResourceRecord"

    $rr = $rec.CreateInstanceFromTextRepresentation($server, $fzone, $text)

    $rr.RR -split ","

    We put the output into a variable and then take the RR property (a list divided by commas) and split it to make it readable.  We get soemthing like this back

    MicrosoftDNS_AType.RecordData="10.10.54.241"

    RecordClass=1

    DnsServerName="SERVER02.Manticore.org"

    ContainerName="manticore.org"

    DomainName="manticore.org"

    OwnerName="test27.manticore.org"

    In summary the fourth parameter in the documentation is the return information and we can ignore it if required.

  • I get the following error when trying to run the function:

    Exception calling "CreateInstanceFromTextRepresentation" : "Generic failure "

    At D:\Admin\ps\mwiest\DNS_RecordAdd.ps1:29 char:50

    +         $rec.CreateInstanceFromTextRepresentation <<<< ($server, $fzone, $text)  

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : WMIMethodException

    Any ideas why?

    Thanks.

  • I get "Access Denied" when using WMI with DNS on powershell. The DNS server is on a DC and since we don't want to run the script as a Domain Admin, WMI access is not allowed. How do you make this work so that only the required access to WMI is granted for the user to run the script against a DNS/DC?

  • Microsoft has an unreleased software utility called "DNS_Exporter_Application_V1.2" that does a great job of exporting and importing DNS entries, with user-supplied parameters like days to allow for "stale" calculations. Unfortunately, the tool is old and doesn't provide any command-line parameters so it can't be automated.

    It supplies the following (info or examples in brackets)

    Record Type (ie. "MicrosoftDNS_AType")

    ContainerName (domain.name)

    DnsServerName (server name)

    DomainName (domain.name)

    OwnerName (what registered it)

    RecordData (IP address)

    TextRepresentation (record data)

    TimeStamp (epoch time)

    TimeStamp (Friendly) (human readable time)

    Static (T/F)

    Stale (T/F)

    TTL (time to live in seconds)

    I have yet to find a way to emulate this with a Powershell query. Any suggestions? I've tried the user-supplied "DNSShell" module, but it doesn't have this functionality either. Thanks!

  • Request to provide some inputs to monitor changes in dns records through wmi event filters for dns