14 May, 2016

Find target of DFS links - OS

There are many times when people need to know the target folder of a DFS link. However, when you have multiple levels of DFS namespaces, for example, you have a Domain Based root called \\tatooine.com\root and under it there are DFS folders and links, but one link points to a standalone DFS root, e.g.: \\tatooine\root\cities\moseisley and this pointer points to another DFS root: \\c3podc1\root and then there are folders and pointers under this namespace as well.

It takes many clicks on DFS Management console to open each DFS namespace and root and walk trough them. Alternatively, you can use the DFSN module on Windows Server 2012 but the command Get-DFSNFolderTarget doesn't understand the multi level structure, it can only wok in one given DFSN root.

Let's take an example, we want to know which file server and which folder the following path points to : \\tatooine.com\root\cities\moseisley\cantina\stock
In the DFS management console, you have to
  1. add \\tatooine.com\root namespace for display
  2. drill down to the MosEisley folder to find that it actually points to \\c3podc1\moseisley
  3. so then you add \\c3podc1\moseisley DFS root to the console
  4. drill down to the Stock folder under Cantina and find that it points to \\fileserver\share1\documents folder

multi-level dfs roots
Find a target in a multi-level DFS structure on DFS Management Console



















It's not very rewarding after you get the 5th of these requests from users...

Here is a quick script which can walk through the folder structure, just specify the full path of a folder and it will tell you for each level where it points to, the script requires the DFSN PS module installed on the box - included in the DFS Management Tools Feature.
If the given folder level is just a DFS folder without target, obviously it will show and empty target, e.g.:

DFS lookup with powershell


On the above picture:

  • \\tatooine.com\root\cities is just a folder because it doesn't point anywhere
  • \\tatooine.com\root\cities\moseisley points to another DFS root
  • \\c3podc1\moseisley\Cantina is again just a folder without DFS target
  • \\c3podc1\moseisley\Cantina\stock is the pointer we wanted to look for and it points to \\fileserver\share1\documents


Here is the code:
 param([string]$folderpath = "")  
   
 $erroractionpreference = "silentlycontinue"  
 Import-module DFSN
 $arr = $folderpath.split("\\")  
 $basepath = ("\\" + $arr[2] + "\" + $arr[3])  
 $testpath = $basepath  
   
 # go from the 4th element of the path and try to get the target of each
 for($i = 4; $i -lt $arr.count; $i++){  
    $testpath = $testpath + "\" + $arr[$i]  
    $result = get-dfsnfoldertarget $testpath  
    $testpath + "->" + $result.targetpath  
   
    if($result.targetpath){  
       $testpath = $result.targetpath  
    }  
 }  



17 January, 2016

Search host name based on IP from Forward Lookup zone - DNS

There are times when the need calls for very ugly but practical workarounds. This time, we want to know the DNS name of a host, we only know the IP address and we don't have reverse lookup zones.

In this case, we can list all the A records from the forward lookup zone and search for the IP address we know.


Use WMI

If you have admin rights on the DNS server, you can use WMI:
gwmi -Namespace root/microsoftDNS -q "select * from MicrosoftDNS_AType where recorddata='10.1.1.123'" | select Ownername,recordData


Use dnscmd

However, if you don't have any sort of permissions, you can try to use dnscmd to enumerate all records from the given zone and then use powershell to search for the IP, then do some text parsing to get a proper output:



A bit of explanation:
  • $zoneContent = dnscmd $dnsserver /enumrecords $dnsDomain . /continue
    Get the full list of records from the given zone
  • if($item -match "$ip"){...
    Go through each line in the output and if the given line contains the IP you are looking for, start processing the data
  • if($item -match "^  "){
    If the line starts with spaces, that means it will have an IP which belongs to a host with multiple IPs, so we will need to list the previous line as well
  • $aging = $($tmp=$zoneContent[$k-1] -match "aging:(?<number>[^\]]+)"; $matches.number)
    $timestamp = (Get-Date ("1601/01/01 00:00")).addhours($aging)
    Calculate the time stamp of the record from the Aging number (which is the number of hours from 1st Jan 1601
  • New-Object -TypeName psobject -Property @{"IP"=$ip; Host=($zoneContent[$k-1].split(" ")[0]); timestamp=$timestamp}
    Put the data into an object and throw it to the std out
The sample script in full:








 $ip = "10.1.1.122"  
 $dnsServer = "c3podc1"  
 $dnsDomain = "tatooine.com"  
   
 $zoneContent = dnscmd $dnsserver /enumrecords $dnsDomain . /continue  
 $k = 0  
   
 Foreach($item in $zoneContent){  
    if($item -match "$ip"){  
       # if the host has 2 IPs and we searched for the 2nd one, we will need the previous line from the output  
       if($item -match "^ "){  
          $aging = $($tmp=$zoneContent[$k-1] -match "aging:(?<number>[^\]]+)"; $matches.number)  
          $timestamp = (Get-Date ("1601/01/01 00:00")).addhours($aging)  
          New-Object -TypeName psobject -Property @{"IP"=$ip; Host=($zoneContent[$k-1].split(" ")[0]); timestamp=$timestamp}  
            
          $aging = $($tmp=$item -match "aging:(?<number>[^\]]+)"; $matches.number)  
          $timestamp = (Get-Date ("1601/01/01 00:00")).addhours($aging)  
          New-Object -TypeName psobject -Property @{"IP"=$ip; Host=($zoneContent[$k-1].split(" ")[0]); timestamp=$timestamp}  
       }  
       else{  
          $aging = $($tmp=$item -match "aging:(?<number>[^\]]+)"; $matches.number)  
          $timestamp = (Get-Date ("1601/01/01 00:00")).addhours($aging)  
          New-Object -TypeName psobject -Property @{"IP"=$ip; Host=($item.split(" ")[0]); timestamp=$timestamp}  
       }  
    }  
    $k++  
 }