PowerShell und DNSClient

Die meisten Commandlets arbeiten auch mit dem Parameter "Computer", "DomainController" o.ä. Und akzeptieren dort natürlich auch Hostnamen. Aber was macht man, wenn man wirklich mal selbst eine DNS-Abfrage stellen will? Das NET-Framework stellt dazu eine Klasse bereit, die aber eher rudimentär ist. Gerade für Lync hingegen ist z.B. die Abfrage eines SRV-Records interessant und auch die Überprüfung, ob ein Name auf mehrere IP-Adressen auflöst. Und nicht immer ist NSLOOKUP der passende Weg.

NSLOOOKUP Fallback

Über viel Jahre habe ich wirklich meine "Tests" über den Umweg mit NSLookup gemacht. Aus PowerShell heraus wurde NSLOOKUP mit den passenden Parametern aufgerufen und die Rückgabe als Textstring geparsed. Hier z.B. ein Codeteil aus einer VBScript-Routine

Hier der gesamte Code als Download
psdns-ocsdns.1.2.vbs.txt

Das gleiche geht natürlich auch per PowerShell aber es ist nicht elegant und zudem auch abhängig von der Sprache, da hier der Rückgabetext analysiert werden muss.

DNS bis PowerShell 2

Wer auf PowerShell 2 aufbaut, der kann neben NSLOOKUP auch WMI-Anfragen oder eben das .NET Framework nutzen, z.B.

[System.Net.Dns]::GetHostAddresses("www.msxfaq.de")

Das Ergebnis ist dann eine .NET Objekt mit folgende Informationen (Stand Jul 2014)

   TypeName: System.Net.IPAddress

Name               MemberType     Definition
----               ----------     ----------
Equals             Method         bool Equals(System.Object comparand)
GetAddressBytes    Method         byte[] GetAddressBytes()
GetHashCode        Method         int GetHashCode()
GetType            Method         type GetType()
MapToIPv4          Method         ipaddress MapToIPv4()
MapToIPv6          Method         ipaddress MapToIPv6()
ToString           Method         string ToString()
Address            Property       long Address {get;set;}
AddressFamily      Property       System.Net.Sockets.AddressFamily AddressFa
IsIPv4MappedToIPv6 Property       bool IsIPv4MappedToIPv6 {get;}
IsIPv6LinkLocal    Property       bool IsIPv6LinkLocal {get;}
IsIPv6Multicast    Property       bool IsIPv6Multicast {get;}
IsIPv6SiteLocal    Property       bool IsIPv6SiteLocal {get;}
IsIPv6Teredo       Property       bool IsIPv6Teredo {get;}
ScopeId            Property       long ScopeId {get;set;}
IPAddressToString  ScriptProperty System.Object IPAddressToString {get=$this

In meinem Fall eben

c:PS C:\> [System.Net.Dns]::GetHostAddresses("www.msxfaq.de") | fl

Address            : 3947144530
AddressFamily      : InterNetwork
ScopeId            :
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 82.165.68.235

Auf dem gleichen Weg kann eine IP-Adresse rückwärts auf einen Host aufgelöst werden. Allerdings funktioniert dies nur für A, AAAA und PTR-Records. Selbst ein MX-Record kann so nicht aufgelöst werden.

DNS mit PowerShell 3+

Seit Windows 8/Windows 2012 und PowerShell 3.0 gibt es endlich ein eigenes Commandlet für die Auflösung von DNS-Namen, welches fast alle Wünsche abdeckt:

Damit lassen sich nicht nur "Hostnamen" auflösen sondern auch MX-Records, SRV-Records und einiges mehr. Die Microsoft Hilfe beschreibt aber schön die einzelnen Optionen. Voraussetzung ist natürlich die Installation von PowerShell 3 oder 4. Sie finden den Download bei der Suche nach "Windows Management Framework 4.0"

Achtung: Das .Net Framework 4.5 muss vorher installiert sein. Das WMF4 Setup weist darauf NICHT hin und stoppt auch nicht, wenn das Framework nicht installiert ist.

Windows Management Framework 4.0
http://www.microsoft.com/de-de/download/details.aspx?id=40855

Microsoft .NET Framework 4.5
http://www.microsoft.com/en-us/download/details.aspx?id=30653

Die PowerShell 4 funktioniert auch auf Windows 7 SP1 und anderen Plattformen. Prüfen Sie aber unbedingt die Systemvoraussetzungen. Bestimmte ältere Software, z.B. Exchange 2007) ist nicht damit kompatibel.

Leider ist das Commandlet per Default NICHT auf Windows 7 damit schon installiert. Das entsprechende Modul, welches in C:\Windows\System32\WindowsPowerShell\v1.0\Modules\DnsClient liegt, wird bei Windows 7 nicht mit installiert.
Tipp: Es funktioniert aber, wenn Sie das komplette Verzeichnis von einem Windows 2012 Server oder Windows 8 Client einfach kopieren. Eine entsprechende Lizenz benötigen Sie natürlich.

Erst dann steht ihnen der "Resolve-DNSName" zur Verfügung. Hier ein paar Beispiele

PS C:\> Resolve-DnsName _sipfederationtls._tcp.netatwork.de -Type SRV | fl

Name       : _sipfederationtls._tcp.netatwork.de
Type       : SRV
TTL        : 86392
NameTarget : sip.netatwork.de
Priority   : 0
Weight     : 0
Port       : 5061

Nun kann man per PowerShell sehr einfach endlich auch SRV-Records auslesen

Wenn ein Anbieter die Last auf mehrere Server verteilt, dann bekommen Sie auch mehrere Records in einem Objekt

PS C:\> Resolve-DnsName www.google.de | ft -AutoSize

Name          Type TTL Section IPAddress
----          ---- --- ------- ---------
www.google.de AAAA 178 Answer  2a00:1450:4008:800::100f
www.google.de A    139 Answer  173.194.32.223
www.google.de A    139 Answer  173.194.32.216
www.google.de A    139 Answer  173.194.32.215
www.google.de A    139 Answer  173.194.32.207

Bei Microsoft hingegen sieht es (Jun 2014) etwas anders aus.

PS C:\> Resolve-DnsName www.microsoft.com

Name                           Type   TTL   Section    NameHost
----                           ----   ---   -------    --------
www.microsoft.com              CNAME  241   Answer     toggle.www.ms.akadns.net
toggle.www.ms.akadns.net       CNAME  241   Answer     g.www.ms.akadns.net
g.www.ms.akadns.net            CNAME  241   Answer     lb1.www.ms.akadns.net

Name       : lb1.www.ms.akadns.net
QueryType  : A
TTL        : 31
Section    : Answer
IP4Address : 65.55.57.27


Name                   : akadns.net
QueryType              : SOA
TTL                    : 22
Section                : Authority
NameAdministrator      : hostmaster.akamai.com
SerialNumber           : 1403167478
TimeToZoneRefresh      : 90000
TimeToZoneFailureRetry : 90000
TimeToExpiration       : 90000
DefaultTTL             : 180

Das sind genau genommen 5 Einträge, von denen die ersten drei auf CNAME verweisen, der vierte Eintrag ein "A-Record" und der Eintrag 5 der SOA ist. Selbst wenn man den Type mit angibt, bekommt man die CNAME Einträge mit:

PS C:\> Resolve-DnsName www.microsoft.com -Type a

Name                           Type   TTL   Section    NameHost
----                           ----   ---   -------    --------
www.microsoft.com              CNAME  105   Answer     toggle.www.ms.akadns.net
toggle.www.ms.akadns.net       CNAME  105   Answer     g.www.ms.akadns.net
g.www.ms.akadns.net            CNAME  105   Answer     lb1.www.ms.akadns.net

Name       : lb1.www.ms.akadns.net
QueryType  : A
TTL        : 159
Section    : Answer
IP4Address : 65.55.57.27

Hier sollten Sie also eventuell noch etwas weiter filtern und prüfen, z.B. mit

PS C:\> Resolve-DnsName www.microsoft.com | where {$_.type -eq "a"}

Name                                           Type   TTL   Section    IPAddres
                                                                       s
----                                           ----   ---   -------    --------
lb1.www.ms.akadns.net                          A      86    Answer     65.55.57
                                                                       .27

Bild sollten Sie sich also nicht auf die Antworten verlassen, sondern zumindest damit umgehen, das die Rückgabe mehrere Records enthält. Ist ein Name nicht auflösbar, wird natürlich eine Exception geworfen.

PS C:\> Resolve-DnsName www.microsoft.egal
Resolve-DnsName : www.microsoft.egal : Der DNS-Name ist nicht vorhanden In Zeile:1 Zeichen:1
+ Resolve-DnsName www.microsoft.egal
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + CategoryInfo          : ResourceUnavailable: (www.microsoft.egal:String)[Resolve-DnsName], Win32Exception
 + FullyQualifiedErrorId : DNS_ERROR_RCODE_NAME_ERROR,Microsoft.DnsClient.Commands.ResolveDnsName

Der umgang mit Try/Catch ist hier also ratsam

Win32 API

Für die C++-Entwickler ist der Weg zu .NET und PowerShell eher ein Umweg und Sie werden vermutlich die Win32 API nutzen. Das ist gar nicht mal so verwerflich, da die Win32-API auch in Zeiten von .NET noch alle nicht abgeschrieben ist. Zugegeben würde so ein Programm vermutlich nicht auf eine "anderen Plattform" laufen, aber bislang habe ich noch keinen ernsthaften Einsatz von .NET auf fremden Plattformen gesehen. Sicher gibt es das Projekt Mono, was das .NET Framework auf Linux bereit stellt, aber dort gibt es meines Wissens noch keine PowerShell. Daher hier nur zur Vollständigkeit ein paar Links:

Weitere Links