2 questions about cmdlet

Mar 7, 2011 at 6:07 PM

hello,

i must create/ckeck/update about 400 domains on our external company dns server and luckily found this cmdlet! this makes creating zones very easy - no messing around with complicated wmi parameters. :)

2 things i am not happy at the moment:

remove-dnsobject wants me to confirm the delete. in a script i don´t want to confirm it for every record. there must be a way to set -confirm:$false which is not working at the moment

how can i set the primary server in the SOA record? when i create a new zone this is always the local machine name and not the external published name of the ns.

brgds Deas

Coordinator
Mar 8, 2011 at 9:07 AM

The first is simple:

 

... | Remove-DnsObject -Force

I could add -Confirm as well, but I never liked that convention :)

Changing the SOA record needs us to use Set-DnsRecord:

 

Get-DnsRecord -RecordType SOA -Zone "somezone.example" | Set-DnsRecord -TargetName "newserver.somezone.example" -MinimumTTL 28800

There's a bug with Set-DnsRecord which prevents you from just setting TargetName, something to add to my list, you can work-around it by setting any of the other values on the record (it's a problem with parameter set selection).

This is the syntax for that particular parameter set (13 of 17 for the Set-DnsRecord CmdLet):

 

Set-DnsRecord -Identity  [-Server ] [-TTL ] [-TargetName ] [-SerialNumber ]
  [-RefreshInterval ] [-RetryDelay ] [-ExpireLimit ] [-MinimumTTL ] [-PassThru]
  [-Credential ] [-WhatIf] [-Confirm]

Of those, SerialNumber, RefreshInterval, RetryDelay, ExpireLimit and MinimumTTL are unique to the SOA record and setting any (even if it's to the same value as before) will get through the parameter set selection issue until I fix it properly.

HTH

Chris

 

Mar 8, 2011 at 10:36 AM

hello,

cool - i never tried -Force (and it is also not documented i think... ;) )

the modification of the soa record also works perfect. i have no problem setting anything else, because i must do it anyway. the default values do not meet my requirements. only one thing to say to your "MinimumTTL" example - if you only set the minimumttl and it is greater than the ttl of the object the ttl is removed. so you must set minimumttl and ttl together.

brgds Andreas

Coordinator
Mar 8, 2011 at 7:34 PM

Unless my help file is woefully out of date:

 

Get-Help Remove-DnsObject -Parameter Force

:)

Thanks for noting the behaviour of MinimumTTL / TTL, I certainly appreciate that, another to add to the list of checks to perform before allowing an update.

Cheers,

Chris

Mar 9, 2011 at 8:37 AM

oh - you are right. i didn´t saw it! sorry...

something else i noticed:

when i do a Get-DnsZone -ZoneType Primary i also get the reverse lookup zones and the "TrustedAnchors" entry. would it be possible to remove these or specify what zone type i´d like to see?

brgds Andreas

Coordinator
Mar 9, 2011 at 8:49 AM

TrustedAnchors, never seen that, any idea what generates it?

Filtering out Reverse can be done like this:

Get-DnsZone -Filter "Reverse=$False"

Although I'll certainly concede that's not exactly intuitive. Get-DnsZone and its documentation needs work.

Chris

Mar 9, 2011 at 8:59 AM
Edited Mar 9, 2011 at 9:12 AM

i run it on a w2k8 r2 dns server and when i open the properties on that server i have a Trust Anchors tab in the properties. but there is no zone shown in the gui.

http://technet.microsoft.com/en-us/library/ee649280(WS.10).aspx

looks like this tab is also located in a zone file.

edit: do you support piping of your commands? i mean e.g. Get-DnsZone | Get-dnsRecord -RecordType SOA or is this a bad idea from me? because this lists me 400 times (in my case with 400 zones) the soa records of all 400 zones...

brgds Andreas

Coordinator
Mar 9, 2011 at 9:10 AM

Ahh, DNSSEC. Okay, that makes sense. I'll have to build a new test environment to figure that out, my current environment is kaput which is messing up my, admittedly slow, progress :)

Chris

Coordinator
Mar 9, 2011 at 10:18 AM

Sorry, missed the edit.

Do I support piping? Yes, although it would be fair to say there are a few unintended "features" there, mostly that the wrong value is passed in the pipeline to Get-DnsRecord. So the command you've posted should work, but doesn't at present as you've discovered.

There's been a bit of an issue finding time to address all of these things recently, that said, I very much appreciate your feedback :)

Chris

Mar 9, 2011 at 10:32 AM

well, this is nothing i need immediately, but when i must do something i mostly do it with a powershell script. and i don´t want to look after 400 zones by hand. but as long as i have a workaround it is no problem for me. i just want to know the limitations before i start developing my script.

brgds Andreas

Coordinator
Mar 9, 2011 at 10:44 AM

The pipeline for Get-DnsZone -> Get-DnsRecord will be fixed in the next version. I'll try and address some of the other issues you've raised then get a release out.

Cheers,

Chris

Mar 9, 2011 at 10:56 AM

cool, thank´s a lot!

but no stress - if you don´t do it i can also live with it. there is always a way for doing things.

brgds Andreas

Coordinator
Mar 9, 2011 at 11:57 AM

There we go, a few fixes at least. These three work (I hope!):

 

Get-DnsZone
Get-DnsZone -Forward
Get-DnsZone -Reverse

And pipeline from Get-DnsZone to Get-DnsRecord works.

I still need to update the documentation so don't expect that to reflect changes.

Chris

Mar 9, 2011 at 12:17 PM
Edited Mar 9, 2011 at 12:19 PM

PERFECT - works like a charm! :)

brgds Andreas

Mar 9, 2011 at 12:28 PM

have you ever thought about this:

2 new commands: Export-DnsZone and Import-DnsZone

exports a complete dns zone with all records in a file and so this zone can be easily imported. would be great for "online" server backup. yes, dnscmd can do this, but that´s not powershell... :)

brgds Andreas

Coordinator
Mar 9, 2011 at 1:32 PM
Edited Mar 9, 2011 at 1:32 PM

I thought about Export a while ago and decided it's far better consigned to a script. Here's one I made earlier, mostly fluff for making things appear in shorthand:

 

Function Export-DnsZone {
  Param(
    [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
    [String]$ZoneName,
    [String]$Server,
    [Management.Automation.PsCredential]$Credential
  )

  Process {

    $Params = @{}
    If ($Server) { $Params.Add("Server", $Server) }
    If ($Credential) { $Params.Add("Credential", $Credential) }

    $SOA = Get-DnsRecord -ZoneName $ZoneName -RecordType SOA @Params
    $NS = Get-DnsRecord -ZoneName $ZoneName -RecordType NS @Params

    $Other = [Enum]::GetNames([DnsShell.RecordType]) | Where-Object { $_ -NotMatch 'NS|SOA' } | ForEach-Object {
      Try { Get-DnsRecord -ZoneName $ZoneName -RecordType $_ @Params } Catch { }
    }

    @($SOA) + @($NS) + $Other | ForEach-Object {
      If ($_.TTL -eq $SOA.MinimumTTL) {
        $TTL = ""
      } Else {
        $TTL = $_.TTL
      }
      $Name = ($_.Name -Replace "\.$ZoneName") -Replace "$ZoneName", '@'
      If ($_.RecordType -ne "TXT") {
        $RecordData = ($_.RecordData -Replace "\.$ZoneName\.") -Replace "$ZoneName\.", '@'
      }
      "$Name`t$TTL`t$($_.RecordType)`t$RecordData"
    }
  }
}

 

Try and Catch because it flagged another thing I needed to fix with Get-DnsRecord, but it'll do like this for now.

Import-Zone is a harder proposition, it works well for making a zone from scratch, but merging changes is not quite so fun as New-DnsRecord needs parameters not strings. I wrap around the WMI method CreateInstanceFromPropertyData because I found it easier to enforce correct input than CreateInstanceFromTextRepresentation (Win32_ResourceRecord class).

Chris

Mar 9, 2011 at 2:49 PM

ok, that´s a little bit more experienced script technique than i am able to write.

another question: this line does not work - do i want too much? :)

Get-DnsZone aaa.internal -Forward | Where-Object {$_.ZoneName -ne "TrustAnchors"} | Get-DnsRecord -RecordType SOA | Set-DnsRecord -TargetName dns1.domain.com -RefreshInterval 21600 -RetryDelay 3600 -ExpireLimit 604800 -MinimumTTL 10800 -TTL 10800

this is the error:

Set-DnsRecord : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:130
+ Get-DnsZone aaa.internal -Forward | Where-Object {$_.ZoneName -ne "TrustAnchors"} | Get-DnsRecord -RecordType SOA | S
et-DnsRecord <<<<  $_ -TargetName dns1.domain.com -RefreshInterval 21600 -RetryDelay 3600 -ExpireLimit 604800 -MinimumTTL
10800 -TTL 10800
    + CategoryInfo          : InvalidArgument: (:) [Set-DnsRecord], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,DnsShell.PowerShell.CmdLet.SetDnsRecord

brgds Andreas

Coordinator
Mar 9, 2011 at 2:54 PM

I changed the SOA record parameter name:

Get-DnsZone aaa.internal -Forward | 
Where-Object {$_.ZoneName -ne "TrustAnchors"} |
Get-DnsRecord -RecordType SOA |
Set-DnsRecord -SOAServer dns1.domain.com -RefreshInterval 21600 -RetryDelay 3600 -ExpireLimit 604800 -MinimumTTL 10800 -TTL 10800

Just to be annoying ;) But mainly because it lets the CmdLet select a unique parameter set even if you only want to set the name.

Chris

Mar 9, 2011 at 3:38 PM

ahh.... :) i just copied the command i used yesterday to play around. ;) didn´t checked if there are other/new parameters.

what should i say - i changed with that one-liner the soa default settings of all my external domains at once in about 5 seconds. GREAT!!!!!

i did the same for all my CNAME records - worked the same way. just replaced SOA with CNAME and reduced Set-DnsRecord to -TTL 10800

but with the A records i have a problem. i get the following error:

Get-DnsZone aaa.internal -Forward | Where-Object {$_.ZoneName -ne "TrustAnchors"} | Get-DnsRecord -RecordType A | Set-DnsRecord -TTL 10800

Set-DnsRecord : Object reference not set to an instance of an object.
At line:1 char:128
+ Get-DnsZone aaa.internal -Forward | Where-Object {$_.ZoneName -ne "TrustAnchors"} | Get-DnsRecord -RecordType A | Set
-DnsRecord <<<<  -TTL 10800
    + CategoryInfo          : NotSpecified: (:) [Set-DnsRecord], NullReferenceException
    + FullyQualifiedErrorId : System.NullReferenceException,DnsShell.PowerShell.CmdLet.SetDnsRecord

anyway a VERY BIG thank´s for your help and this amazing cmdlet! :)

brgds Andreas

Mar 25, 2011 at 9:59 AM

any idea so far about the a records set-dnsrecord issue i have? i got the csv file now from the domains i must check - now i have 531 domains to modify...

brgds Andreas

Coordinator
Mar 25, 2011 at 10:09 AM
Edited Mar 25, 2011 at 10:10 AM

Ah yeah, it's failing to pass the IP in the pipeline properly. Half way though chasing it down, it's only that work things continually get in the way.

We can work-around it:

Get-DnsZone aaa.internal -Forward | Where-Object {$_.ZoneName -ne "TrustAnchors"} | Get-DnsRecord -RecordType A | ForEach-Object { Set-DnsRecord -Address $_.IPAddress -TTL 10800 }

If I get a chance to fix it completely today I'll republish and we can go back to the version you have above.

Chris

Mar 25, 2011 at 10:23 AM

yes, those work things... get rid of them! ;)

btw.: your work-around needs a little modification to work:

Get-DnsZone aaa.internal -Forward | Where-Object {$_.ZoneName -ne "TrustAnchors"} | Get-DnsRecord -RecordType A | ForEach-Object {Set-DnsRecord -Identity $_.Identity -Address $_.IPAddress -TTL 10800}

and if i remove the -Address parameter it is also not working.

thank´s a lot for your help!

brgds Andreas

Mar 25, 2011 at 11:37 AM

another thing about changing the ttl.

the ttl of a NS record is only shown with your powershell cmdlet. so i did not find a way to change it via the gui.

might be a stupid question, but when i want to align my ttl for these records also - that doesn´t make any problems... right? because i noticed with your cmdlet that i have a few old domains that have a ttl on the NS record of 0.

another question that comes up now: what´s the easiest way to add a zone on my primary server and also add this zone to my secondary server? do i need to execute the New-DnsZone twice or can this be done in one command? i tried it now with this command, but failed.

New-DnsZone -ZoneName aaa.internal -ZoneType Secondary -Server dns2.server.com -MasterServer dns1.server.com

New-DnsZone : Invalid parameter
At line:1 char:12
+ New-DnsZone <<<<  -Server dns2.server.com -ZoneName aaa.internal -ZoneType Secondary -MasterServer dns1.server.com
    + CategoryInfo          : NotSpecified: (:) [New-DnsZone], ManagementException
    + FullyQualifiedErrorId : System.Management.ManagementException,DnsShell.PowerShell.CmdLet.NewDnsZone

and i had to export my server to a csv file for verification now. i noticed that the ipaddress field is the first and the zone name is last. i´d suggest a little rearangement if possible. i did the export with this command:

Get-DnsZone -Forward | Where-Object {$_.ZoneName -ne "TrustAnchors"} | Get-DnsRecord | Export-Csv c:\dns.csv -NoTypeInformation

brgds Andreas

Coordinator
Mar 25, 2011 at 12:03 PM

> might be a stupid question, but when i want to align my ttl for these records also - that doesn´t make any problems... right?

The TTL shouldn't be a problem, you should be able to set whatever you please regardless of what the GUI tells you :) You may find some reset if the DNS server is allowed to automatically create NS records (on by default).

> do i need to execute the New-DnsZone twice or can this be done in one command?

Yep, twice.

MasterServer must be an IP address, that's why it doesn't like your parameter. I need to write better handling for that one, it's getting much too far along. I'll add it to the list so it validates on input rather than throwing an error halfway through. Doesn't help that my documentation doesn't state that either :)

> i noticed that the ipaddress field is the first and the zone name is last.

I can't dictate the order for that output, it's combining too many different fields (different record types). If you need a specific order you'll have to call Select-Object I'm afraid.

Chris

Mar 25, 2011 at 12:21 PM

ok, with the right syntax it is working as expected! :)

i am now able to create a complete zone with all entries and also add the secondary server. GREAT!!!!

now a little bit csv reading and validating and i´m done! :)

about the export-csv: no problem! i thought that this is something that you can control.

brgds Andreas

Mar 28, 2011 at 3:38 PM

just found another "problem" i must deal with which is not directly related to your cmdlet: we also have a few wildcard dns records on some domains

my question now: how can i deal with the * character? means where-object { $_.Name -like ...}???

i found that there are 2 escape characters like \ and `, but i didn´t got them to work.

any help would be highly appreciated...

brgds Andreas

Mar 28, 2011 at 4:56 PM

60 lines of powershell and another question... :)

when i have 2 a records, one for www.aaa.internal and one for aaa.internal - why do i get both of them when i do:

Get-DnsRecord -ZoneName aaa.internal -Name aaa.internal -RecordType A

IPAddress     : 1.2.3.4
Name          : aaa.internal
TTL           : 10800
RecordClass   : IN
RecordType    : A
RecordData    : 1.2.3.4
TimeStamp     : Static
ZoneName      : aaa.internal

IPAddress     : 1.2.3.4
Name          : www.aaa.internal
TTL           : 10800
RecordClass   : IN
RecordType    : A
RecordData    : 1.2.3.4
TimeStamp     : Static
ZoneName      : aaa.internal

???

i have no wildcard in my query and the name aaa.internal is unique for me because the other one is named www.aaa.internal.

brgds Andreas

Mar 28, 2011 at 6:03 PM

final one for today - something i don´t unterstand:

i have a loop to check specific records - works as it should be.

$ARecords = Get-DnsRecord -ZoneName $Domain -RecordType A
   
   $ARecords | Foreach-Object {
    If (($_.Name -like "www.*") -or ($_.Name -eq $Domain)) {
     Remove-DnsObject -Identity $_.Identity -Force
     Write-Host "A-Record for $_.Name Deleted!"
    }
   }

output on the shell is:

A-Record for aaa.internal 10800 IN A 2.3.4.5.Name Deleted!
A-Record for www.aaa.internal 10800 IN A 1.2.3.4.Name Deleted!

ok, that´s more than i expected (marked bold) - ttl, etc. shouldn´t be there.

when i change the write-host line to

Write-Host "A-Record for" $_.Name "Deleted!"

the output is correct!

A-Record for aaa.internal Deleted!
A-Record for www.aaa.internal Deleted!

any idea why?

brgds Andreas

Coordinator
Mar 28, 2011 at 7:06 PM

Hey Andreas :)

> my question now: how can i deal with the * character? means where-object { $_.Name -like ...}???

So either -eq '*', or -Match:

$_.Name -Match '\*'

\ should escape the regex meaning of *.

I may have to test that, I'm unsure whether or not my test zones had wildcard records.

> Get-DnsRecord -ZoneName aaa.internal -Name aaa.internal -RecordType A

Wildcard match by default, I may have to check that. You can have more flexibility if you pick on the Filter parameter (WQL filter, passed straight through). The downside is that you have to know about underlying names (in the WMI class I abstract).

Get-DnsRecord -RecordType A -Filter "OwnerName='aaa.internal' AND ContainerName='aaa.internal'"

I hope!

The last one :)

>      Write-Host "A-Record for $_.Name Deleted!"

Fortunately is not my fault ;)

When you include a variable in a string it'll expand using the ToString method on the object. $_, which is DnsShell.Management.ResourceRecord in this context, has a ToString method that produces the long output you have above (TTL, et al).

The reason you get that and not the Name Property is because .Name is part of the string, not a way of accessing the property (in this context). If you want the property you need to enclose your object variable and its property in a Sub-Expression; That will expand out the property on the object before including it in the rest of the string. For example:

 

Write-Host "A-Record for $($_.Name) Deleted!"

Chris

Mar 28, 2011 at 7:44 PM

ad * character:

Get-DnsRecord -RecordType CNAME | Where-Object { $_.Name -Match "\*"} works perfect! :)

ad wildcard by default:

not sure if this is a good idea. would it be very complicated for you to change that? if i query for aaa.internal only aaa.internal is returned if available. and if i query for *.aaa.internal every a record that matches is returned. for me that would make more sense. because in my worst case i get with that query about 30 a-records and not just the one that might exist for "same as parent folder".

ad write-host output:

didn´t said that it is your fault!!! but i had no clue why it happened. and the only person i could think off that could explain it to me is you at the moment... ;)

i´m a self-learned powershell´er and might miss some of those things others might know. ;)

brgds Andreas

Coordinator
Mar 28, 2011 at 8:13 PM
Edited Mar 28, 2011 at 8:14 PM

Yep, it's actually quite a simple change. I'll re-do the wildcard support and see if I can't make a better generator for the filter.

I am, of course, happy to help. But you might consider the virtual powershell user group if you need a pointer or two with anything:

I may hang around there quite a lot anyway ;)

Chris