francsi.de

francsi.de

I'm not weird! I'm a limited edition.

DFS manipulation with PowerShell

The following script deals with two DFS related problems that sometimes occur with namespaces that were created before Windows Server 2008.

Let’s say your Active Directory Domain was created years ago with Windows Server 2003, 2000 or NT. Even if you’ve done your Domain- and Namespace-Server migrations up to Server 2016 there maybe is something you’ve missed.

Problem number one

With Server 2008 Microsoft implemented Access Based Enumeration (ABE) to DFS but you have to migrate your namespace to “Windows Server 2008 mode” to use this feature. This means that you have to recreate your namespace.  Doing this via the GUI could be a real pain if your servers are hosting many or very large namespaces.

Problem number two

Maybe you’ve done your domain migration from one version of Windows Server to the next one and so on. Now you’ve decided that it’s time to get rid of this old WINS server and finally go DNS only. What happened in my case was, that connecting my DFS Shares got slower after deleting the WINS Server. Why? Because my Namespace and all of my Folder Targets were NETBIOS based. So all my connection requests were using NETBIOS first and then DNS as a fallback.  That’s not very effective but there is a solution: Get your DFS to use DNS only. To do this you have to set a registry Key on all Domain Controllers and Namespace Servers. If that’s done you can change your Namespace addresses to FQDN addresses and change your folder target addresses to FQDN addresses too.

Solution: PowerShell

REMINDER: There is no guarantee that this script will be working in your environment. It’s strictly recommended to test it before using it with productive data. I’m not responsible if you use this one without testing and your namespace goes boom.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<#
 .SYNOPSIS
 This script recreates DFS Namespaces in Server 2008 mode with DNS only
 .DESCRIPTION
 This script recreates DFS Namespaces in Server 2008 mode in a DNS only environment.
 .NOTES
 Author : Jan Francsi
 .LINK
 http://www.francsi.de/category/IT
#>


# Module

Import-Module ActiveDirectory

# Import all DFS Roots hosted by this server that are not standalone

$dfsnRoots = Get-DfsnRoot -ComputerName $env:computername |Where type -NotMatch "Standalone"

# Do for all DFS Roots on the local Server

foreach ($root in $dfsnRoots) {

  #Remember servers
  $serverList = Get-DfsnRootTarget -Path $root.path
 
  #How many servers?
  $serverCounter = $serverList.Count
 
  # Get name of namespace
  $backuptarget = "C:\temp" + ($root.path).Replace("", "-") + ".xml"
  New-Item -ItemType Directory -Force -Path C:\temp
  dfsutil.exe root export $root.path $backuptarget
 
  #Prompt to alter the Backup file (FQDN)
  $message = "Please edit the following export and change NETBIOS names to FQDN: " + $backuptarget + " Press    any key to continue..."
  Write-Host -NoNewLine $message
  $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
  $localTargetPath = ""
 
  #Remove all other amespace servers and activate FQDN
  foreach ($namespaceserver in $serverlist) {
    if (!(($namespaceserver.TargetPath).Contains($env:computername)) ) {
      Remove-DfsnRootTarget -TargetPath $namespaceserver.TargetPath -Path $root.path
      $ausgabe = "Removed " + $namespaceserver.TargetPath
      echo $ausgabe
    }
    if (($namespaceserver.TargetPath).Contains($env:computername) ) {
      $localTargetPath = $namespaceserver.TargetPath
      $ausgabe = "localTargetPath " + $localTargetPath
      echo $ausgabe
    }
 
    # Get hostname from $namespaceserver URI
    $hntemp = ($namespaceserver.TargetPath).Replace("\", "")
    $end = $hntemp.IndexOf("")
    $hn = $hntemp.SubString(0,$end)
 
    #Set DFS FQDN parameter
    Set-DfsnServerConfiguration -ComputerName $hn -UseFqdn $true
 
    # DNS only Domain Config
    if (!(($namespaceserver.TargetPath).Contains($env:computername)) ) {
      Try {
        $s = New-PSSession -ComputerName $hn -ErrorAction Stop
        Invoke-Command $s -ScriptBlock {Param($path)dfsutil server registry DfsDnsConfig set $path} -ArgumentList
        $root.path | Out-Null
        Remove-PSSession $s
      } Catch {
        Write-Host "Remote Server connection error"
      }
    } else {
      dfsutil server registry DfsDnsConfig set $root.path
    }

  }

  #Replicate changes
  repadmin /syncall
  dfsrdiag pollad
 
  #Remove root
  Remove-DfsnRoot -Path $root.path
 
  #Replicate changes
  repadmin /syncall
  dfsrdiag pollad
 
  # Restart Dfs
  Stop-Service dfs;
  Start-Service dfs
  Start-Sleep -s 5
 
  # Restore Namespace as Server 2008 version
  New-DfsnRoot -TargetPath $localTargetPath -Type DomainV2 -Path $root.path
 
  #Replicate changes
  repadmin /syncall
  dfsrdiag pollad
 
  #Add remaining targets
  foreach ($namespaceserver in $serverlist) {
    if (!(($namespaceserver.TargetPath).Contains($env:computername)) ) {
      New-DfsnRootTarget -Path $root.path -TargetPath $namespaceserver.TargetPath
      $output = "Added " + $namespaceserver.TargetPath + " to " + $root.path
      echo $output
    }
  }
 
  #Import backup
  dfsutil.exe root import set $backuptarget $root.path
}