DNS SRV lookup from Powershell

[After posting this blog, I have realized that Powershell 3.0 already provides a built-in cmdlet called Resolve-DnsName which could help you make any kind of DNS queries. But I still wanted to leave this blog post active for those who might want to see how it could be done with Win32 API. Also Powershell 3.0 is available only on Windows 8/Windows server 2012 and forward which means you still need another way of doing your own SRV queries for earlier OS versions]

 

Hi there,

 

While working on another tool that I mentioned in the previous blog post, I needed to lookup SRV records from powershell script. Under normal circumstances, we should be able to call any .Net API through powershell and considering that there’s a Dns class already implemented in the System.net namespace, this shouldn’t be a tough thing. But when you check the Dns class, you’ll see that it doesn’t allow you to make SRV queries:

 

https://msdn.microsoft.com/en-us/library/system.net.dns_methods.aspx Dns Methods

 

After some research I have concluded that it might be easier and faster to implement it with Win32 code. The below code just returns the host part of DNS SRV response as I only needed that part but it’s just a matter of uncommenting the printf() statements in the below code. Here is the full code that could be complied from Visual studio:

 

 // dnssrvclient.cpp : Defines the entry point for the console application.
//
 
 #include "stdio.h"
 #include "winsock2.h"
 #include "windows.h"
 #include "windns.h"
 
 
 int wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )
 
 {
 
 
 PWSTR resultname;
 
 PDNS_RECORD ppQueryResultsSet = NULL;
 
 // ppQueryResultsSet = (PDNS_RECORD) malloc(sizeof(DNS_RECORD));
 // memset(ppQueryResultsSet,'\0',sizeof(DNS_RECORD));
 
 int retvalue;
 
 // printf("Sending SRV query for the name '%S'. Please wait...\n",argv[1]);
 
 retvalue = DnsQuery(
 argv[1],
 DNS_TYPE_SRV,
 DNS_QUERY_BYPASS_CACHE,
 NULL,
 &ppQueryResultsSet,
 NULL
 
 );
 if(!retvalue)
 
 {
 resultname = ppQueryResultsSet->Data.SRV.pNameTarget;
 printf("%S",resultname);
 // printf("SRV query succeeded.\n");
 // printf("SRV record name:\t %S \n", resultname);
 // printf("SRV record port:\t %d \n", ppQueryResultsSet->Data.SRV.wPort);
 // printf("SRV record priority:\t %d \n", ppQueryResultsSet->Data.SRV.wPriority);
 
 return retvalue;
 }
 
 else 
 {
 
 // printf("The SRV record couldn't be resolved, error code: %d",retvalue);
 
 return retvalue;
 }
 
 }
 

Note: If you decide to compile the above code, please make sure that Windows Kit (SDK) is already installed on the Visual Studio client and make sure that you add the dnsapi.lib as an additonal options from linker properties.

 

 

Basically the application calls the DnsQuery() API with parameters stating that it would be an SRV query and the local DNS client cache will be bypassed when resolving the name. Once the result is returned, the application simply returns the Data.SRV.pNameTarget which holds the name part of SRV query response. You can see below an example run of the application code:

 

C:\> dnssrvclient.exe _sip._tls.contoso.com

sip.contoso.com

 

Note: _sip._tls.contoso.com is the SRV record being queried and sip.contoso.com is the result of this SRV lookup. If the query fails, the application returns a non-zero value

 

If you need to use the application from a powershell script, you can use a code similar below:

Note: The powershell code snipet below assumes that dnssrvclient.exe exists within the same folder.

 

 $result = .\dnssrvclient.exe _sip._tls.contoso.com
 if($LASTEXITCODE)
 
 {
 
 Write-Host "DNS SRV query failed, error code: $LASTEXITCODE" -ForegroundColor Red
 
 }
 
 else
 
 {
 
 write-host "DNS SRV query succeeded: $result" -ForegroundColor Green
 
 }
 

  

A successful run will be like below:

 

DNS SRV query succeeded: sip.contoso.com

 

When SRV lookup fails, you should a response similar to below:

 

DNS SRV query failed, error code: 9003

 

Hope this helps

 

Thanks,

Murat