I can’t figure out how to Add-
or Remove-
an NAPTR record using
PowerShell’s DnsServer module. Can you?
I’m not PowerShell expert, nor am I an expert on how Microsoft’s DNS
server works.
However, I can tell you that PowerShell lets you list NAPTR records,
but the “RecordData” field appears blank:
1
2
3
4
5
| > Get-DnsServerResourceRecord -rrtype naptr -zonename my.example.com -name "9.3.5.8.enum"
HostName RecordType Type Timestamp TimeToLive RecordData
-------- ---------- ---- --------- ---------- ----------
9.3.5.8.enum NAPTR 35 0 01:00:00
|
If you get that field, you get a hex-encoded version of the wire
format of the NAPTR record data:
1
2
3
4
5
6
7
8
| > $records = Get-DnsServerResourceRecord -rrtype naptr -zonename my.example.com -name "9.3.5.8.enum" ; $records[0].RecordData|SELECT *
Data : 01000A000155074532552B7369701B215E2E2A24217369703A383939394031302E3139392E392E39392100
PSComputerName :
CimClass : root/Microsoft/Windows/DNS:DnsServerResourceRecordUnknown
CimInstanceProperties : {Data}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties
|
(That record was created using the Windows GUI.)
The hex string is pretty obviously what will go in the DNS packet. You can decode it and see the ascii strings.
NOTE: That hex string was slightly redacted.
My challenge to you:
- Create an NAPTR record using
Add-DnsServerResourceRecord
(or
anything in that family), but specify the RecordData as the
individual fields, not a hex string. Remove-
or Get-
an NAPTR record using Remove-DnsServerResourceRecord
(or
equivalent), but specify all the fields such that exactly 0 or 1
records are returned.
Why am I doing this?
Why am I doing this? Because dnscontrol
needs to support NAPTR better so that SIP phone systems can be managed
better.
Why the Get/Remove requirement that it specify exactly one record?
Because I only want to remove one record and there may be multiple
matches if the DNS record is not specified completely.
Why would there be multiple matches? Because DNS permits the same
label to have many DNS records as long as they are unique.
For example, it is possible to have multiple SRV records on the same label:
1
2
3
4
5
6
7
| > Get-DnsServerResourceRecord -rrtype srv -ZoneName my.example.com -name _ldap._tcp
HostName RecordType Type Timestamp TimeToLive RecordData
-------- ---------- ---- --------- ---------- ----------
_ldap._tcp SRV 33 0 00:10:00 [0][100][389][REDACTED.example.com.]
_ldap._tcp SRV 33 0 00:10:00 [0][100][389][REDACTED.foo.com.]
_ldap._tcp SRV 33 0 00:10:00 [0][100][389][REDACTED.example2.com.]
|
Here’s how you would remove it:
1
2
| > Remove-DnsServerResourceRecord -WhatIf -RRType SRV -ZoneName "my.example.com" -Name "_ldap._tcp" -RecordData 0,100,389,"redacted.example.com."
What if: Removing DNS resource record _ldap._tcp of type SRV from zone my.example.com on TOMDEV server.
|
Notice that I specified the [0][100][389][REDACTED.example.com.]
string in the comma-separated format that PowerShell requires (no
spaces, quotes around any non-numeric data). This unambiguously
specifies the SRV record.
I can find no equivalent for NAPTR.
Can you?
Rant
Why the heck does everything telephony-related suck when it comes to
the internet? Does every SIP phone system in the world get configured
using the GUI? Does the telephony world suffer through this and not
use any kind of automated setup, infrastructure as code?
Sadly I know the answer to these questions. (Hint: Netheads vs Bellheads and AT&T Fails At Internet.)
Update: 2020-12-29
Win: I’ve successfully decoded and encoded the hex strings in Go.
Since a Go program is generating the PowerShell commands, this is
fine. See
https://github.com/StackExchange/dnscontrol/pull/1009/files
Lose: PowerShell is ignorant of NAPTR records.
I figured… what if I just recycle the hex dump?
1
2
| > Add-DnsServerResourceRecord -zonename example.com -Name foo -Type 35 -RecordData "01000A000155074532552B7369701B215E2E2A24217369703A323038304031302E3131302E322E31302100"
Add-DnsServerResourceRecord: Record type number 35 is not an unknown type, represents a NAPTR record. Known record types cannot be added using the unknown records parameter set. Windows DNS server understands the format of this record type and it must be added using the known record parameter sets.
|
It seems that the PS module just doesn’t know that NAPTR exists. I’ve
tried -Naptr
and --Rrtype NAPTR
. No good.
Others have found this problem:
Maybe I should create the object from scratch?
Update: 2020-12-30:
My conclusion is that the Remove-DnsServerResourceRecord
command
simply doesn’t have command-line flags that do the right thing. That’s
ok, if I can Get-DnsServerResourceRecord
and match the
record, then I can use Remove-DnsServerResourceRecord
and specify that object
with the -InputObject
to remove it. Right?
Wrong.
This works for A records but not NAPTR!
Here’s my repo case:
I manually added an “A” and a few “NAPTR” records using the GUI. Let’s see if we can delete them:
1
2
3
4
5
6
7
8
9
| > Get-DnsServerResourceRecord -ZoneName "example.com"
HostName RecordType Type Timestamp TimeToLive RecordData
-------- ---------- ---- --------- ---------- ----------
@ SOA 6 0 01:00:00 [26347][tomdev.][hostmaster.]
@ NAPTR 35 0 01:00:00
mya A 1 0 01:00:00 1.2.3.4
testdata NAPTR 35 0 01:00:00
testdata NAPTR 35 0 01:00:00
|
First let’s delete the “A” record:
1
2
3
4
| > $OldObj = Get-DnsServerResourceRecord -ZoneName "example.com" -Name "mya" -RRType A |
Where-Object {$_.HostName -eq "mya"
-and $_.RecordData.IPv4Address -eq "1.2.3.4"} ;
if($OldObj.Length -ne 1){ throw "Error, matched 0 or > 1 records" }
|
That found the object. Let’s remove it:
1
2
3
4
5
6
| > Remove-DnsServerResourceRecord -InputObject $OldObj -ZoneName "example.com" -Confirm -Force
Confirm
Are you sure you want to perform this action?
Removing DNS resource record mya of type A from zone example.com on TOMDEV server.
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y
|
Worked as expected! Now let’s try that with an NAPTR record:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
| > $OldObj = Get-DnsServerResourceRecord -ZoneName "example.com" -Name "testdata" -RRType naptr |
Where-Object {$_.HostName -eq "testdata"
-and $_.RecordData.Data -eq "020003000155074532552B7369701D215E282E2A2924217369703A5C5C314031302E3131302E322E3130216000"} ;
if($OldObj.Length -ne 1){ throw "Error, matched 0 or > 1 records" }
> $OldObj
HostName RecordType Type Timestamp TimeToLive RecordData
-------- ---------- ---- --------- ---------- ----------
testdata NAPTR 35 0 01:00:00
> $OldObj.RecordData.Data
020003000155074532552B7369701D215E282E2A2924217369703A5C5C314031302E3131302E322E3130216000
> Remove-DnsServerResourceRecord -InputObject $OldObj -ZoneName "example.com"
Remove-DnsServerResourceRecord: InputObject for resource record has an invalid value. Failed to remove the resource record on TOMDEV server. Please check extended error for additional details.
PS C:\Users\tlimoncelli\git\dnscontrol\integrationTest> get-error
OriginInfo :
Exception :
Type : Microsoft.Management.Infrastructure.CimException
NativeErrorCode : InvalidParameter
ErrorData : MSFT_WmiError
MessageId : WIN32 13
ErrorSource : TOMDEV
StatusCode : 4
TargetSite :
Name : ProcessNativeCallback
DeclaringType : Microsoft.Management.Infrastructure.Internal.Operations.CimAsyncObserverProxyBase`1[T]
MemberType : Method
Module : Microsoft.Management.Infrastructure.dll
StackTrace :
at Microsoft.Management.Infrastructure.Internal.Operations.CimAsyncObserverProxyBase`1.ProcessNativeCallback(OperationCallbackProcessingContext callbackProcessingContext, T currentItem, Boolean
moreResults, MiResult operationResult, String errorMessage, InstanceHandle errorDetailsHandle)
Message : InputObject for resource record has an invalid value. Failed to remove the resource record on TOMDEV server. Please check extended error for additional details.
Source : Microsoft.Management.Infrastructure
HResult : -2146233088
TargetObject : PS_DnsServerResourceRecord
CategoryInfo : InvalidData: (TOMDEV:root/Microsoft/Wind…erverResourceRecord) [Remove-DnsServerResourceRecord], CimException
FullyQualifiedErrorId : WIN32 13,Remove-DnsServerResourceRecord
InvocationInfo :
MyCommand : Remove-DnsServerResourceRecord
ScriptLineNumber : 1
OffsetInLine : 1
HistoryId : 426
Line : Remove-DnsServerResourceRecord -InputObject $OldObj -ZoneName "example.com"
PositionMessage : At line:1 char:1
+ Remove-DnsServerResourceRecord -InputObject $OldObj -ZoneName "exampl …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
InvocationName : Remove-DnsServerResourceRecord
CommandOrigin : Internal
ScriptStackTrace : at Remove-DnsServerResourceRecord<End>, <No file>: line 4550
at <ScriptBlock>, <No file>: line 1
|
Nope! Looks like this causes some kind of internal error.
Sadly I don’t know enough WMI to understand what’s going on.
Anyone have suggestions?