<# .SYNOPSIS dig-artiger DNS-Lookup fuer Windows PowerShell, basierend auf Resolve-DnsName. .DESCRIPTION Bildet die wichtigsten dig-Aufrufe nach, damit sich unter Windows die gleiche Syntax wie mit dig unter Linux verwenden laesst. Argumente koennen wie bei dig in beliebiger Reihenfolge stehen. .PARAMETER Args Freie dig-artige Argumente: name abzufragender Name (z.B. example.com) type Record-Typ (A, AAAA, MX, TXT, NS, CNAME, SOA, SRV, PTR, ...) @server zu verwendender DNS-Server; in PowerShell zwingend quoten: "@8.8.8.8" (fuehrendes @ ist sonst der Splatting-Operator) -s server @-freie Alternative fuer den DNS-Server (auch -server) -x Reverse-Lookup (PTR) fuer eine IPv4-/IPv6-Adresse +short nur die reinen Antwortwerte ausgeben .EXAMPLE .\dig.ps1 example.com .\dig.ps1 MX example.com .\dig.ps1 example.com MX -s 1.1.1.1 .\dig.ps1 example.com MX "@1.1.1.1" .\dig.ps1 -x 8.8.8.8 .\dig.ps1 AAAA example.com +short #> # Alle Argumente einsammeln (bewusst als freies Array, dig-Stil). $rest = $args $name = $null $type = $null $server = $null $short = $false $reverse = $false # Bekannte DNS-Record-Typen, die Resolve-DnsName unterstuetzt. $knownTypes = @( 'A','AAAA','A_AAAA','CNAME','MX','NS','PTR','SOA','SRV','TXT', 'CAA','DNSKEY','DS','NAPTR','NSEC','NSEC3','RRSIG','ANY','ALL' ) # Argumente parsen (Reihenfolge egal). for ($i = 0; $i -lt $rest.Count; $i++) { $arg = [string]$rest[$i] if ($arg -eq '-x') { $reverse = $true # naechstes Argument ist die IP-Adresse if ($i + 1 -lt $rest.Count) { $name = [string]$rest[$i + 1] $i++ } continue } if ($arg.StartsWith('@')) { $server = $arg.Substring(1) continue } # -s / -server als @-freie Alternative (PowerShell deutet ein fuehrendes # '@' sonst als Splatting-Operator und bricht schon beim Parsen ab). if ($arg -eq '-s' -or $arg -eq '-server') { if ($i + 1 -lt $rest.Count) { $server = [string]$rest[$i + 1] $i++ } continue } if ($arg -eq '+short') { $short = $true continue } if ($arg.StartsWith('+')) { # weitere +optionen aktuell ignorieren continue } if ($knownTypes -contains $arg.ToUpper()) { $type = $arg.ToUpper() continue } # alles andere ist der Name if (-not $name) { $name = $arg } } if (-not $name) { Write-Host "Verwendung: dig.ps1 [type] name [@server | -s server] [+short] | dig.ps1 -x [+short]" exit 1 } # Reverse-Lookup: IP in .in-addr.arpa / .ip6.arpa umwandeln. function ConvertTo-PtrName([string]$ip) { $parsed = $null if (-not [System.Net.IPAddress]::TryParse($ip, [ref]$parsed)) { return $ip # kein gueltiges IP-Literal, unveraendert zurueck } if ($parsed.AddressFamily -eq 'InterNetwork') { # IPv4: Oktette umdrehen $octets = $ip.Split('.') [array]::Reverse($octets) return ($octets -join '.') + '.in-addr.arpa' } else { # IPv6: vollstaendige Nibble-Darstellung, umgedreht $bytes = $parsed.GetAddressBytes() $nibbles = foreach ($b in $bytes) { '{0:x2}' -f $b } $hex = ($nibbles -join '') $chars = $hex.ToCharArray() [array]::Reverse($chars) return (($chars -join '.') + '.ip6.arpa') } } if ($reverse) { $name = ConvertTo-PtrName $name $type = 'PTR' } if (-not $type) { $type = 'A' } # Resolve-DnsName-Parameter zusammenbauen. $params = @{ Name = $name Type = $type ErrorAction = 'Stop' } if ($server) { $params['Server'] = $server } try { $records = Resolve-DnsName @params } catch { Write-Host ";; Fehler bei der Aufloesung von '$name' ($type): $($_.Exception.Message)" exit 1 } # Nur echte Antwort-Records (keine Query-Hinweiszeilen). $answers = $records | Where-Object { $_.Section -ne 'Question' } # Wert eines Records typgerecht als String formatieren. function Get-RecordData($r) { switch -Wildcard ($r.Type) { 'A' { return $r.IPAddress } 'AAAA' { return $r.IPAddress } 'CNAME' { return $r.NameHost } 'NS' { return $r.NameHost } 'PTR' { return $r.NameHost } 'MX' { return "$($r.Preference) $($r.NameExchange)" } 'SOA' { return "$($r.PrimaryServer) $($r.NameAdministrator) $($r.SerialNumber) $($r.TimeToZoneRefresh) $($r.TimeToZoneFailureRetry) $($r.TimeToExpiration) $($r.DefaultTTL)" } 'SRV' { return "$($r.Priority) $($r.Weight) $($r.Port) $($r.NameTarget)" } 'TXT' { return '"' + ($r.Strings -join '" "') + '"' } 'CAA' { return "$($r.Flags) $($r.Tag) `"$($r.Value)`"" } default { # Fallback: sinnvolles Feld suchen foreach ($p in 'NameHost','IPAddress','NameTarget','Strings') { if ($r.PSObject.Properties[$p] -and $r.$p) { return ($r.$p -join ' ') } } return ($r | Out-String).Trim() } } } if ($short) { # +short: nur die Werte, eine pro Zeile. foreach ($r in $answers) { Get-RecordData $r } exit 0 } # dig-artige Ausgabe. $srvText = if ($server) { $server } else { '(System-Resolver)' } Write-Host "" Write-Host "; <<>> dig.ps1 <<>> $name $type" -ForegroundColor DarkGray Write-Host ";; Server: $srvText" Write-Host "" Write-Host ";; QUESTION SECTION:" Write-Host (";{0}`t`tIN`t{1}" -f $name, $type) Write-Host "" if ($answers) { Write-Host ";; ANSWER SECTION:" foreach ($r in $answers) { $ttl = if ($r.PSObject.Properties['TTL']) { $r.TTL } else { 0 } $data = Get-RecordData $r Write-Host ("{0}`t{1}`tIN`t{2}`t{3}" -f $r.Name, $ttl, $r.Type, $data) } Write-Host "" } else { Write-Host ";; keine Antworten (ANSWER SECTION leer)" Write-Host "" }