12 October, 2013

DFS link count check - DFS

There have been cases when people started screaming that their folders disappeared or they are there but are not accessible. OK... nicely defined problem, this is the sort of issue you want on a Monday morning, just to get the adrenalin flowing a bit. Let's see then, after checking a couple of these folders, it turns out that all of  them are DFS links. If I check those, they work for me... so this issue is even better that I thought 5 mins ago.
Let's check all DFS servers then. All of them seem to be healthy, but hold on... there's one which shows half of the number of pointers than it supposed to.
If you check locally, the DFS folder structure is there, but if you check it via the DFS root share, half the pointers are gone... weird, quick reboot helps, MSFT wants to reproduce the issue to get to the bottom of it... well, I don't want to reproduce it to be honest, but what I can do is run a quick check in the morning which would make sure I catch this before the users do.

If you look at the issue again, it's easy to pinpoint what to check: the count of directories on the DFS root on the DFS server's local drive is OK, however, the count of DFS links are not the same. Ok, so I need a script which counts both, compares them and if they are different, sends an alert.

Count number of folders which point to another folder (ReparsePoint):
dir $dfsdir -rec | ? {$_.Attributes -imatch 'ReparsePoint'} | measure | %{$_.count}

Count number of DFS links:
dfscmd /view $dfsroot /batch | ?{($_ -imatch "\\\\$dfsserver\\$dfsRootName") -and ($_ -inotmatch "^rem| /add")} | measure | %{$_.count}

Dfscmd lists all pointers and actions how to recreate them (map or add), we filter out all lines apart from the ones with /map and we also filter out every line which does not have the DFS root in them.

We just need to compare these numbers for each server, evaluate the result, put them in a nice output and e.g. send them via email.

Output of a GREEN checkout on two DFS roots

In my final script, I used Win32_Process to run the dir and dfscmd commands on the remote DFS servers and also used PowerShell jobs to run them in parallel therefore it's a lot quicker, however for the purpose of this article, I simplified the code to show the essence of the logic.

 $ErrorActionPreference = "SilentlyContinue"  
 #### Function for checking if a host is alive on the network  
 function PingServer ([string]$srv){  
      $ping = new-object System.Net.Networkinformation.Ping  
      Trap {Continue} $pingresult = $ping.send($srv, 3000, [byte[]][char[]]"z"*16)  
      if($pingresult.Status -ieq "Success"){$true} else {$false}  
 $objColl = @()  
 $dfsrootlist = @($Input)  
 foreach($dfsroot in $dfsrootlist){  
      $obj = "" | Select DFS_Root,Access,Dir_Count,Link_Count,Result  
      $obj.DFS_Root = $dfsroot  
      $dfsserver = $dfsroot.split("\")[2]  
      $dfsRootName = $dfsroot.split("\")[3]  
      $dfsdir = "\\" + $dfsserver + "\d$\DFSRoots\" + $dfsRootName  
      if(PingServer $dfsserver){  
           $obj.Access = "OK"  
           $obj.Dir_count = dir $dfsdir -rec | ? {$_.Attributes -imatch 'ReparsePoint'} | measure | %{$_.count}  
           $obj.Link_count = dfscmd /view $dfsroot /batch | ?{($_ -imatch "\\\\$dfsserver\\$dfsRootName") -and ($_ -inotmatch "^rem| /add")} | measure | %{$_.count}  
           # checking if link or directory count is 0  
           if(!$obj.Link_Count -or ($obj.Link_Count -eq 0)){  
                $obj.Result = "Error: Link count is 0"  
           if($obj.Link_Count -eq "N/A"){  
                $obj.Result += "Error-Could not collect dfs link count data"  
           if($obj.Dir_Count -eq "N/A"){  
                $obj.Result += "Error-Could not collect directory count data"  
           if(!$obj.Dir_Count -or ($obj.Dir_Count -eq 0)){  
                $obj.Result = "Error: Directory count is 0 <br>"  
           if($obj.Dir_Count -ne $obj.Link_Count){  
                if($obj.Result -eq "N/A"){$obj.Result = "Link/Dir count mismatch"}  
                if($obj.Result -eq "N/A"){$obj.Result = "OK"}  
           $obj.Access = "Error"  
      $objColl += $obj  
 $rfbcount = ($objColl | ?{$_.result -ine "ok"} | measure).count  
 $Subject = "DFS Link Count"  
 if($rfbcount -ge 1){  
      if($rfbcount -ge 2)     {$subject += " - RED"}  
      else                    {$subject += " - AMBER"}  
      $subject += " - GREEN"  
 $smtpServer = "smtpdroid.tatooine.com"  
 $smtpFrom = "reports@tatooine.com"  
 $smtpTo = "tompa@tatooine.com"  
 $message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpto  
 $message.Subject = $Subject  
 $message.IsBodyHTML = $true  
 $message.Body = $objColl | ConvertTo-Html  
 $smtp = New-Object Net.Mail.SmtpClient($smtpServer)  


1 comment: