If you find yourself making changes to various types of DNS records on a Windows server, you may be wasting a lot of time. Why? Because it’s possible to create, modify, or remove any kind of DNS record with PowerShell!

PowerShell allows you to not only manage your DNS records from the command line but also to take those commands and put them into a script to automate all kinds of time-consuming tasks.

In this article, I will show you how to make that initial connection to your DNS servers from PowerShell and then go over a few common examples of tasks that you might find yourself needing to accomplish in the future.

Before we get too far, you need to be aware of a few prerequisites. First, I’m assuming you have permissions to read, modify, and remove DNS records from your Windows servers.

Second, I’ll be demonstrating a few concepts from DNS servers that are in an Active Directory domain with AD-integrated zones. PowerShell is still capable of managing zones and records outside of Active Directory but may not offer quite the same result as I’ll be showing you here.

Finally, you’ll need to ensure you have a version of the Remote Server Administration Tools (RSAT) installed on your client specific to your operating system.

Now that we have that out of the way, let’s start out by first ensuring the DNSServer module is available to us. To do that, I’ll use the Get-Module cmdlet.

Get-Module DNSServer –ListAvailable

Verifying that the DNSServer module is available

Verifying that the DNSServer module is available

Great! It looks like it is. Next, whenever exploring new functionality, it’s always a good idea to start with a Get PowerShell cmdlet to simply read an object. This ensures you can make the connection to the server and have permission to at least read objects.

Because we’re managing DNS records in this article, I’ll first start off by using Get-DNSServerResourceRecord. This cmdlet allows us to pull DNS records from one or many different DNS zones on a Windows DNS server.

I’m testing this in an Active Directory domain called mylab.local so, naturally, a mylab.local DNS zone has already been created on my domain controller. I’ll use the cmdlet to query that DNS zone on the domain controller called DC.

Get-DnsServerResourceRecord -ComputerName dc -ZoneName mylab.local

Reading DNS records with PowerShell

Reading DNS records with PowerShell

No red text—good! It looks like I can successfully pull all of the DNS records from a particular zone. What if I need just a particular type of record rather than all records? It’s not usual for me to fiddle with RV and NS records. I spend most of my time managing the A records. No problem: simply use the RRType parameter and specify an A. You’ll see that it only returns A records.

Get-DnsServerResourceRecord -ComputerName dc -ZoneName mylab.local -RRType A

Now that I can read various DNS records, perhaps I’d like to modify a static record. One of our server names has changed and I need to be sure its DNS record is updated to reflect that. Changing DNS records is a little convoluted but, with some tenacity, we can still make it happen.

First, we’ll need to get two identical objects representing a DNS record. In this case, I’m pulling a DNS record for my MySQL server.

$new = $old = Get-DnsServerResourceRecord -ComputerName dc -ZoneName mylab.local -Name MYSQL

After I have the two objects, I’ll then change the IPV4 address on the new object to represent the IP address it has changed to. Unfortunately, it’s not quite as easy as simply setting a string. The IPV4Address property requires a type of System.Net.IPAddress in order to successfully make the change.

$new.RecordData.IPv4Address = [System.Net.IPAddress]::parse('192.168.0.254')

After the IP address is changed on the $new object, I can then use Set-DNSServerResourceRecord to force PowerShell to update the record on the server itself.

Set-DnsServerResourceRecord -NewInputObject $new -OldInputObject $old -ZoneName mylab.local -ComputerName dc

Finally, if I’d like to remove the record, the process is much simpler. I can simply pipe the results of Get-DNSServerResourceRecord directly to Remove-DNSServerResourceRecord.

Get-DnsServerResourceRecord -ComputerName dc -ZoneName mylab.local -Name MYSQL | Remove-DNSServerResourceRecord –ZoneName mylab.local –ComputerName DC

You can do so much more with DNS records with PowerShell. To get a full list of all of the various commands in the DNSServer module, use the Get-Command cmdlet.

Get-Command -Module DNSServer -Name *record*

Also, always remember to use Get-Help if you’re curious about what a particular cmdlet might do! Get-Help is a great way to explore new cmdlets and functionality in PowerShell.

avatar
20 Comments
  1. Mattia Pasinetti 7 years ago

    Hi,

    how can i sobstitute the string

    $new.RecordData.IPv4Address = [System.Net.IPAddress]::parse(‘192.168.0.254’)

    With a variable instead of IP?

     

    Thanks

  2. Author

    Yep, you could assign the IP to a variable like this:

    $ipAddress = ‘192.168.0.254’

    $new.RecordData.IPv4Address = [System.Net.IPAddress]::parse($ipAddress)

  3. esxi 7 years ago

    nice post.

    One this is confusing tho. you said,.

     

    “One of our server names has changed and..”

    but the script does the IP change. And you said for that is “..I’ll then change the IPV4 address on the new object to represent the IP address it has changed to..”

     

    ==

    how can we change the host name dns record ? Same way , by creating 2 object, old & new ?

  4. Author

    I mentioned “server name changing” as a fictional use case. If that were the case, a company might have a CSV file with the server names and IPs those servers now need. From that, PowerShell can read the CSV and update the records accordingly.

  5. Panzerbjrn (Rank 2) 7 years ago

    This doesn’t work:

    $new = $old = Get-DnsServerResourceRecord -ComputerName dc -ZoneName mylab.local -Name MYSQL

     

    This just creates a link to the same object, so you are not able to update the old object.

    • Author

      Thanks for the feedback. Have you solved this a different way?

      • Chris 6 years ago

        I don’t know if there is a better way to do this, but the way I got around the issue Panzerbjrn mentioned was to set the $new variable in one command and the $old variable in another

        Once both variables are set separately, the rest of the instructions work fine.

        It seems like doing $new = $old = (….)  sets both variables to each other, so when you change $new it also changes $old.  When you run the Set-DnsServerResourceRecord command, it doesn’t find the $old variable because it now has the newly identified IP address.
        I found this by doing echoing both the $new and $old variables after changing one or the other.
        Great instructions, I was in need of this 🙂

      • Eugene Rosenfeld 6 years ago

        You can’t use “$new = $old” because that just copies the reference, not the underlying objects.

        Instead, use “$new = $old.Clone()”. That creates a deep copy the old record.

  6. Jdashn 6 years ago

    Likely the best way to do it would be this:

    $old = get-dns…

    $new = $old.psobject.Copy()

    Hope this helps!

     

  7. Tim 6 years ago

    what to do if Get-DnsServerResourceRecord returns a collection of records? i.e.

    $old = Get-DnsServerResourceRecord -ZoneName contoso.com -ComputerName DC -Name testrec
    
    $new = Get-DnsServerResourceRecord -ZoneName contoso.com -ComputerName DC -Name testrec
    
    $new
    
    HostName RecordType Timestamp TimeToLive RecordData
    -------- ---------- --------- ---------- ----------
    testrec A 0 00:10:00 10.1.1.10
    testrec A 0 00:10:00 10.1.1.20
    testrec A 0 00:10:00 10.1.1.30
    

    I’m able to update each record of the collection with:

    $new[0].RecordData.IPv4Address = [System.Net.IPAddress]::parse('10.2.2.10')
    $new[1].RecordData.IPv4Address = [System.Net.IPAddress]::parse('10.2.2.20')
    $new[2].RecordData.IPv4Address = [System.Net.IPAddress]::parse('10.2.2.30')

    But getting the following error when trying to Set:

    Set-DnsServerResourceRecord : Cannot process argument transformation on parameter 'NewInputObject'. Cannot convert the "System.Object[]" value of
    type "System.Object[]" to type "Microsoft.Management.Infrastructure.CimInstance".
    At line:1 char:45
    + Set-DnsServerResourceRecord -NewInputObject $new -OldInputObject $old -ComputerN ...
    + ~~~~
    + CategoryInfo : InvalidData: (:) [Set-DnsServerResourceRecord], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Set-DnsServerResourceRecord

     

    • Davis 5 years ago

      This is a little late but I was able to solve Tim’s issue. I had to update each individual item of the collection. I searched for several hours with no luck before trying this.

      Set-DnsServerResourceRecord -NewInputObject $newobj[$i] -OldInputObject $oldobj[$i] -ZoneName “domain.com” -PassThru

    • Stephen 4 years ago

      Tim,

      We have similar issues where this comes up. We use DNS to load balance some of our app servers and have to update the records and bleed the users off during our patch cycle. What i’ve found useful is doing a foreach to remove then update the list of static A records for those servers. I use the following variables but you’ll have to fill them in for your environment:

      $dnsServer = “”

      $dnsZoneName = “”

      $dnsRecordType = read-host “What type of record?” ##most common record types ‘A’ ‘PTR’ ‘MX’ ‘AAAA’ ‘CNAME’

      Then i use the get-dns record and set-dns record, or i use the get-dns record and remove-dnsresourcerecord depending on what i am needing.

      et-DnsServerResourceRecord -ComputerName $dnsServer -ZoneName $dnsZoneName -Name “recordname” -RRType “A”

      then do the foreach on the record:

      Remove-DnsServerResourceRecord -ComputerName $dnsServer -ZoneName $dnsZoneName -RRType $dnsRecordType -Name $hostName -RecordData $ipAddress

  8. Mathew 6 years ago

    Adam, There is a question I would like to ask.

    What if we want to test whether a certain Reverse Lookup Zone has been created or not? I want to create DNS A records but before, need to confirm whether there is the reverse zone. If not reverse lookup zones have to be created and then the DNS A records.

    Thank you!

  9. Rob 5 years ago

    Your post helped me get some work done quickly (not to mention being self-documented)!!!

    Thanks!!!

     

  10. Hans-Werner 5 years ago

    Hi,
    I hope somebody is still here…
    This command:

    Get-ADComputer -Filter * -Property Name,DNSHostName,Description

    What’s wrong with that name?

    Hans

  11. Keith Corkran 4 years ago

    I am trying to create the APEX record for my local AD DNS based on the IP I get back from AWS(Cloudfront)

    Where I am having trouble is the value or lack of value for the @.

    In AD DNS, the record name is simply left blank. Works great, I have not found a similar method to create a record in powershell to create this type of DNS entry.

  12. Dharani 4 years ago

    Guys, please help me understand, when it comes to this command, how and where can I check and find out the type for IPaddress as it's mentioned here as System.Net.IPAddress 

    $new.RecordData.IPv4Address = [System.Net.IPAddress]::parse('192.168.0.254')

  13. Bill 3 years ago

    I would be interested to find out if anyone is able to change the "PrimaryServer" field of an SOA record with these methods. I run commands in PowerShell that all look like they complete successfully, but the field just won't change.

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account