{"id":54303,"date":"2009-02-26T21:18:00","date_gmt":"2009-02-26T21:18:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/02\/26\/hey-scripting-guy-how-do-i-query-and-retrieve-dns-information\/"},"modified":"2009-02-26T21:18:00","modified_gmt":"2009-02-26T21:18:00","slug":"hey-scripting-guy-how-do-i-query-and-retrieve-dns-information","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-do-i-query-and-retrieve-dns-information\/","title":{"rendered":"Hey, Scripting Guy! How Do I Query and Retrieve DNS Information?"},"content":{"rendered":"<h2><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"> <\/h2>\n<p>Hey, Scripting Guy! I know I can use the DNS WMI provider and query a DNS server. But what if I am not using a Microsoft DNS server? Or what if I do not have admin rights on the DNS server? What happens then? I really do not want to resort to parsing the output from NSLookup. Can you hook me up?<\/p>\n<p>&#8211; BP<\/p>\n<p><img decoding=\"async\" border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"><\/p>\n<p>Hi BP,<\/p>\n<p>You know, &#8220;Hook Me Up&#8221; was the second album by that Australian band, The Veronicas. It is actually pretty good. They&#8217;re not the Spice Girls, but then who is? Anyway, the problem with parsing NSLookup is that it returns string data and not an object. The problem with the DNS WMI provider, as you so adeptly put it, is that you need both rights and access, which is unlikely on the Internet.<\/p>\n<table id=\"EXC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p class=\"lastInCell\">This week we are talking about DNS. For more information about DNS, you can refer to the Windows Server 2008 Networking and Network Access Protection (NAP) book in the <a href=\"http:\/\/www.microsoft.com\/learning\/en\/us\/Books\/10345.aspx\" target=\"_blank\">Windows Server 2008 Resource Kit<\/a>. There is also a chapter on scripting network services in the <a href=\"http:\/\/www.microsoft.com\/MSPress\/books\/authors\/auth9541.aspx\" target=\"_blank\">Windows PowerShell Scripting Guide<\/a>. A number of good VBScript examples are in the <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/scripts\/network\/dns\/default.mspx\" target=\"_blank\">Script Center Script Repository<\/a>. The WMI DNS provider is documented here <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms682134(VS.85).aspx\" target=\"_blank\">on MSDN<\/a>.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>To allow us to query and to retrieve DNS information from the Internet or from our own local network for that matter, we can use the <b>System.Net.DNS<\/b> .NET Framework class. An example of using this class is seen in the <b>Get-DnsEntry.ps1<\/b> script:<\/p>\n<pre class=\"codeSample\">Function Get-DnsEntry($iphost)\n{\n If($ipHost -match \"^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$\")\n  {\n    [System.Net.Dns]::GetHostEntry($iphost).HostName\n  }\n ElseIf( $ipHost -match \"^.*\\.\\.*\")\n   {\n    [System.Net.Dns]::GetHostEntry($iphost).AddressList[0].IPAddressToString\n   }\n ELSE { Throw \"Specify either an IP V4 address or a hostname\" }\n} #end Get-DnsEntry\nGet-DnsEntry \"Vista.NwTraders.Com\"\n<\/pre>\n<p>Our script consists of a single function. To create the function, we use the <b>Function<\/b> keyword and give it a name. A good name for a script that retrieves DNS entry information is <b>Get-DnsEntry<\/b>. The function accepts a single parameter, which we call <b>$iphost<\/b>. This is seen here:<\/p>\n<pre class=\"codeSample\">Function Get-DnsEntry($iphost)\n{\n<\/pre>\n<p>Rather than creating two separate functions, we decided to create a single function that would allow you to supply an IP address and receive a corresponding host name, or supply a hostname and retrieve an IP address. We further decided to use regular expressions to decide if you had supplied an IP address or a host name.<\/p>\n<table id=\"EGE\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p class=\"lastInCell\">We have several \u201cHey, Scripting Guy!\u201d articles in which we talk about regular expressions. We also have <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/tips08\/gtip0201.mspx\" target=\"_blank\">a pretty good introduction<\/a> to using regular expressions.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>We are interested in the result of a pattern match, but only if the match was found or not. In other words, we are looking for a Boolean return value: yes\/no, true\/false, that kind of thing. We do not care where the match was found, only if it was found. This makes our logic a bit easier. Our regular expression pattern uses several special characters. These are listed in <b>Table 1<\/b>.<\/p>\n<p>That is it. All the special characters we use in our regular expression patterns in our <b>Get-DnsEntry.ps1<\/b> script are seen there in <b>Table 1<\/b>. We repeat the pattern several times. This pattern will actually match anything between 0.0.0.0 and 999.999.999.999, so it does not validate good IP addresses or eliminate bad IP addresses; however, it will detect if something is an IP address.<\/p>\n<p>When I am trying to create a new regular expression pattern, I start with a simple pattern and I work directly at the Windows PowerShell console. To match the number 1, I want to begin at the beginning of the line, and look for a digit. I will use the caret (<b>^<\/b>), followed by the <b>\\d<\/b>. This is seen here:<\/p>\n<pre class=\"codeSample\">PS C:\\&gt; 1 -match \"^\\d\"\nTrue\n<\/pre>\n<p>To match the number 1 followed by a period, I add the <b>\\.<\/b> as seen here:<\/p>\n<pre class=\"codeSample\">PS C:\\&gt; \"1.\" -match \"^\\d\\.\"\nTrue\n<\/pre>\n<p>To find three numbers in the first position, we add the <b>{1,3}<\/b> operator:<\/p>\n<pre class=\"codeSample\">PS C:\\&gt; 111 -match \"^\\d{1,3}\"\nTrue\n<\/pre>\n<p>But what happens if someone adds in four numbers: Will we get a false reading?<\/p>\n<pre class=\"codeSample\">PS C:\\&gt; 1111 -match \"^\\d{1,3}\"\nTrue\n<\/pre>\n<p>As a matter of fact, we do not because the first three positions have numbers, and we said nothing about the end. After we add in our period, we now get a false match. When we test it with three numbers followed by a period and an additional number, we once again get a match.<\/p>\n<pre class=\"codeSample\">PS C:\\&gt; \"1111\" -match \"^\\d{1,3}\\.\"\nFalse\nPS C:\\&gt; \"111.1\" -match \"^\\d{1,3}\\.\"\nTrue\n<\/pre>\n<p>We continue in this manner, until we come to the end of the pattern, which we specify as ending in 1 to 3 numbers. The <b>$<\/b> sign matches the end. Our completed regular expression pattern match is seen here: <\/p>\n<pre class=\"codeSample\">If($ipHost -match \"^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$\")\n<\/pre>\n<p>If the value of <b>$ipHost<\/b> makes it past our regular expression pattern match, we call the static <b>GetHostEntry<\/b> method, and return only the <b>HostName<\/b> property from the returned object. To use the <b>System.Net.Dns<\/b> .NET Framework class, we put the name of the class in square brackets, use two colons (because this is a static method), call the method name, and supply it the value of the <b>$iphost<\/b> variable:<\/p>\n<pre class=\"codeSample\">{\n    [System.Net.Dns]::GetHostEntry($iphost).HostName\n  }\n<\/pre>\n<p>If the value of <b>$ipHost<\/b> makes it past our regular expression pattern match, we call the static <b>GetHostEntry<\/b> method, and return only the <b>HostName<\/b> property from the returned object. To use the <b>System.Net.Dns<\/b> .NET Framework class, we put the name of the class in square brackets, use two colons (because this is a static method), call the method name, and supply it the value of the <b>$iphost<\/b> variable:<\/p>\n<pre class=\"codeSample\">{    [System.Net.Dns]::GetHostEntry($iphost).HostName  }<\/pre>\n<p>If the <b>$ipHost<\/b> value does not match the IP address regular expression pattern, we see if it matches another pattern. This pattern looks for any character <b>.*<\/b> followed by a single period and then any other number of characters. This will match domain names with dashes, numbers, and letters in them. But it must have at least one period in the name. If a host name was passed in the <b>$iphost<\/b> variable, we obtain the <b>AddressList<\/b> property, and then retrieve the <b>IPAddressToString<\/b> property. Because the <b>AddressList<\/b> property is an array, we need to index into the array to retrieve a single value prior to converting it to a string. On many systems, this approach will be fine, but on Windows Vista and later the first IP address will be IPv6 and the second one IPv4. This is seen in this image: <\/p>\n<p><img decoding=\"async\" border=\"0\" alt=\"Image of an IPv6 address\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/february\/hey0226\/hsg-02-26-9-01.jpg\" width=\"500\" height=\"248\"><\/p>\n<p>&nbsp;<\/p>\n<p>After we are done looking at the IP address that was submitted, we examine the host name to ensure it has a period in the name, has characters separated by a period, and has some more characters. This ensures that the dotted notation familiar to virtually all users of the internet is contained in the <b>$IPHost<\/b> variable. The command will kick out an attempt to resolve a simple netbios name:<\/p>\n<pre class=\"codeSample\">ElseIf( $ipHost -match \"^.*\\.\\.*\")\n   {\n    [System.Net.Dns]::GetHostEntry($iphost).AddressList[0].IPAddressToString\n   }\n<\/pre>\n<p>When the value of <b>$iphost<\/b> does not match our IP address pattern or our host name pattern, we throw an error and state that the user needs to supply the appropriate value to the function: <\/p>\n<pre class=\"codeSample\">ELSE { Throw \"Specify either an IP V4 address or a hostname\" }\n} #end Get-DnsEntry\n<\/pre>\n<p>The entry point to the script calls the <b>Get-DnsEntry<\/b> function and passes a hostname value to it. You can replace this line with one that takes command-line arguments or make whatever types of modifications to the function you wish. The entry point is seen here. <\/p>\n<pre class=\"codeSample\">Get-DnsEntry \"Vista.NwTraders.Com\"<\/pre>\n<p>Well, BP, we have come to the end of the <b>Get-DnsEntry.ps1<\/b> script. We finished a little early, so perhaps we have time to go and watch Spice World.(Okay, maybe not. I\u2019ll probably wait another decade to watch it again.) This also concludes our DNS Week articles. See you tomorrow for Quick-Hits Friday. See you tomorrow. <\/p>\n<p>&nbsp;<\/p>\n<p><b>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I know I can use the DNS WMI provider and query a DNS server. But what if I am not using a Microsoft DNS server? Or what if I do not have admin rights on the DNS server? What happens then? I really do not want to resort to parsing the output [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[188,37,3,45],"class_list":["post-54303","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-dns-server","tag-networking","tag-scripting-guy","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I know I can use the DNS WMI provider and query a DNS server. But what if I am not using a Microsoft DNS server? Or what if I do not have admin rights on the DNS server? What happens then? I really do not want to resort to parsing the output [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/54303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=54303"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/54303\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=54303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=54303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=54303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}