Getting Started with DFSN and PowerShell

DFS is a really cool feature. There are two parts to DFS: Namespace and Replication. They do different jobs, and can be thought of as different roles. DFS Namespace is designed to create a unified UNC path, where subfolders can be links to different serves and shares. The servers linked-to can be assigned costs and placed into sites.

Example

Here’s an example:

Let’s say I have 5 file servers and shares:

  • OH-FS1
    • \\oh-fs1\hr
    • \\oh-fs1\finances
  • OH-FS2
    • \\oh-fs2\software
  • OH-FS3
    • \\oh-fs3\public
  • CA-FS1
    • \\ca-fs1\hr
    • \\ca-fs1\finances

It can be confusing for a user to remember what file server they need to go to. DFS Namespaces can help us unify the structure into this:

  • \\mycorp.com\
    • files\
      • software
      • public
      • finances
      • hr

Then, we can configure DFS Namespaces so that if you’re at the CA site, accessing \\mycorp.com\hr will redirect you to \\ca-fs1\hr. Conversely, we can configure this namespace so that accessing \\mycorp.com\hr from the OH site will redirect the user to the share \\oh-fs1\hr. This is incredibly cool.

You might be wondering, what good is it to redirect people to servers in different sites if they won’t see the same data? For example, what if the HR folk at the OH and CA site want to collaborate via the ‘hr’ share? This is what DFS Replication is for. It will be covered in a different post.

Getting Started

Let’s walk through the creation of a DFS Namespace.

Our final namespace will look like this:

  • \\contoso.com\files\
    • hr
    • software
    • finances
    • public

The following shares will be on a server named fs1: hr, finances, software. The share ‘public’ will be on a server named fs2.

  1. Install two file servers: fs1 ans fs2.
  2. Configure the file servers normally and join them to the domain.
  3. Run the following PowerShell code on both file servers to install the DFS Namespace feature:
    Install-WindowsFeature FS-DFS-Namespace -IncludeManagementTools
  4. Run the following PowerShell code on fs1 to create a 1-server namespace.
    #Create the SMB share folders:
    $folders = @("C:\DFSRoots\Files","C:\shares\hr","C:\shares\finances","C:\shares\software")
    $folders | mkdir
    
    #Create the shares
    $folders | %{sharename = (GC $_).name; New-SMBShare -Name $shareName -Path $_ -FullAccess "contoso\administrator"}
    
    #Create the DFS Root
    New-DfsnRoot -Path \\contoso.com\files -TargetPath \\fs1\files -Type DomainV2
    
    #Create the DFS Folders for fs1
    $folders | ?{$_ -like "*shares*"} | % {$name = (gc $_).name; $DfsPath = ("\\contoso.com\files\" + $name); $targetPath = ("\\fs1\" + $name);New-DfsnRootFolder -Path $dfsPath -TargetPath $targetPath}
    
  5. At this point, fs1 is configured. In order to add shares from fs2 into the DFS Namespace, we first need to configure fs2 to host the ‘files’ namespace. Run the following PowerShell code on fs2.
  6. $folders = @("C:\DFSRoots\Files","C:\shares\public")
    $folders | mkdir
    
    #Create the shares
    $folders | %{sharename = (GC $_).name; New-SMBShare -Name $shareName -Path $_ -FullAccess "contoso\administrator"}
    
    #Host the DFS Root
    New-DfsnRootTarget -Path \\contoso.com\files -TargetPath \\fs2\files
    
    #Create the DFS Folders for fs2
    $folders | ?{$_ -like "*shares*"} | % {$name = (gc $_).name; $DfsPath = ("\\contoso.com\files\" + $name); $targetPath = ("\\fs1\" + $name);New-DfsnRootFolder -Path $dfsPath -TargetPath $targetPath}
    

Note that we don’t need to run New-DfsnRootTarget on fs2, but the SMB Shares ‘files’ and ‘public’ must be configured on fs2 before we can add the fs2 shares as targets on the \\contoso.com\files namespace.

And that’s it! You can now browse the tree from a client or the servers, and you’d never know that the folders are on different servers.

Server 2008 Enterprise Subordinate CA Install Scripts – Part 3 – DFSR

It’s important that the inetpub directories of both Subordinate CA’s are synchronized. We can use DFSR to do this!

Overview

  • Part 1 – Installing ADCS
  • Part 2 – Installing IIS 7
  • Part 3 – Installing DFSR
  • Part 4 – Installing Certificate Web Enrollment Pages
  • Part 5 – Installing CES\CEP
  • Part 6 – Installing an OCSP Responder Array

Scripts!

File 1 – Install-DFSR.cmd

REM Install and Configure DFSR for IIS Content Repl
Powershell -executionpolicy bypass -command "Import-Module ServerManager; Add-WindowsFeature File-Services,FS-DFS,FS-DFS-Replication"
dfsradmin RG New /rgname:"CDP Replication Group"
dfsrAdmin RG Set Schedule full /RGName:"CDP Replication Group"
dfsradmin member new /rgname:"CDP Replication Group" /memname:%computername%
dfsradmin RF New /rgName:"CDP Replication Group" /RfName:CertData
dfsradmin Membership Set /RgName:"CDP Replication Group" /RfName:CertData /MemName:%computername% /LocalPath:F:\inetpub\wwwroot\CertData /MembershipEnabled:true /IsPrimary:true

REM Set staging directory
IF NOT EXIST "G:\DFSR" MKDIR "G:\DFSR"
IF NOT EXIST "G:\DFSR\Staging" MKDIR "G:\DFSR\Staging"
IF NOT EXIST "G:\DFSR\Staging\CertData" MKDIR "G:\DFSR\Staging\CertData"
Powershell -ExecutionPolicy bypass -file ".\Change-DFSRStaging.ps1"
IF EXIST "F:\inetpub\wwwroot\certdata\dfsrPrivate\staging" RMDIR /s /q "F:\inetpub\wwwroot\certdata\dfsrPrivate\staging"

File 2 – Change-DFSRStaging.ps1

Here’s a previous blog post of mine with very similar information: Changing the DSFR Staging Path with PowerShell.

#I want to change the stagingPath parameter of the respective instance of the DfsrReplicatedFolderConfig class
#The staging path is actually stored in AD
$computer = gc env:computername
$targetStagingPath = "G:\dfsr\staging\certdata"

#find the repl folder GUID
$ReplFolderConfigs = $null
$i = 0
While($ReplFolderConfigs -eq $null)
	{
		If($i -gt 0)
			{Sleep -seconds 2}
		ElseIf($i -gt 15)
			{
				$foundFolderConfigs = $false
				Break
			}
		$ReplFolderConfigs = gwmi -namespace "root\MicrosoftDFS" -class DfsrReplicatedFolderConfig
		$i++
	}

If(($ReplFolderConfigs.GetType().BaseType.Name) -eq "Array")
	{
		$ReplFolderConfigs | % {
			write-host -f cyan $_.RootPath
			If($_.RootPath -like "*inetPub*CertData*" -and $_.StagingPath -like "*inetPub*CertData*")
				{$replFolder = $_}
		}
	}
Else
	{$replFolder = $ReplFolderConfigs}
$folderGUID = $ReplFolder.ReplicatedFolderGuid

write-host -f cyan "folderGuid: $folderGUID"

#grab the objet from AD
$strFilter = "(&(objectClass=msDFSR-Subscription)(CN=" + $folderGUID + "))"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = $strFilter
$colResults = $objSearcher.FindAll()

If(($colResults.PSBase.GetType().Name) -eq "SearchResult")
	{$sDFSRConfigLDAPPath = $colResults.Path}
Else
	{
		$colResults | % {
			$result = $_
			$ldapResult = $result.Path
#			write-host -f green $ldapResult
			If($ldapResult -like ("*" + $computer + "*"))
				{$sDFSRConfigLDAPPath = $ldapResult}
		}
	}

#write-host -f yellow "sDFSRConfigLDAPPath: $sDFSRConfigLDAPPath"
$objDFSRConfig = [adsi]$sDFSRConfigLDAPPath

#modify the property
$stagepath = $objDFSRConfig.Get("msDFSR-StagingPath")
#write-host -f yellow "Current staging path: $stagepath"
$objDFSRConfig.Put("msDFSR-StagingPath",$targetStagingPath)
$objDFSRConfig.SetInfo()

#restart the dfsr service
Restart-Service DFSR
Sleep -seconds 10

Running the install-dfsr.cmd script on both Sub CA’s should start them sync’ing their inetpub folders! Stay tuned for Part 4.

Changing the DSFR Staging Path with PowerShell

It took a while to figure out, but it’s totally possible to change the DFSR Staging Path programatically for any replicated folder. Here’s the scoop!

Required Reading

The Script

You’ll need to change the variables at the top.

#I want to change the stagingPath parameter of the respective instance of the DfsrReplicatedFolderConfig class
#The staging path is actually stored in AD
$computer = gc env:computername
$targetStagingPath = "G:\dfsr\staging\certdata"
$rootPathToLookFor = "*inetPub*CertData*"

#find the repl folder GUID
$ReplFolderConfigs = $null
$i = 0
While($ReplFolderConfigs -eq $null)
	{
		If($i -gt 0)
			{Sleep -seconds 2}
		ElseIf($i -gt 15)
			{
				$foundFolderConfigs = $false
				Break
			}
		$ReplFolderConfigs = gwmi -namespace "root\MicrosoftDFS" -class DfsrReplicatedFolderConfig
		$i++
	}

If(($ReplFolderConfigs.GetType().BaseType.Name) -eq "Array")
	{
		$ReplFolderConfigs | % {
			write-host -f cyan $_.RootPath
			If($_.RootPath -like $rootPathToLookFor -and $_.StagingPath -like $rootPathToLookFor)
				{$replFolder = $_}
		}
	}
Else
	{$replFolder = $ReplFolderConfigs}
$folderGUID = $ReplFolder.ReplicatedFolderGuid

write-host -f cyan "folderGuid: $folderGUID"

#grab the objet from AD
$strFilter = "(&(objectClass=msDFSR-Subscription)(CN=" + $folderGUID + "))"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = $strFilter
$colResults = $objSearcher.FindAll()

If(($colResults.PSBase.GetType().Name) -eq "SearchResult")
	{$sDFSRConfigLDAPPath = $colResults.Path}
Else
	{
		$colResults | % {
			$result = $_
			$ldapResult = $result.Path
#			write-host -f green $ldapResult
			If($ldapResult -like ("*" + $computer + "*"))
				{$sDFSRConfigLDAPPath = $ldapResult}
		}
	}

#write-host -f yellow "sDFSRConfigLDAPPath: $sDFSRConfigLDAPPath"
$objDFSRConfig = [adsi]$sDFSRConfigLDAPPath

#modify the property
$stagepath = $objDFSRConfig.Get("msDFSR-StagingPath")
#write-host -f yellow "Current staging path: $stagepath"
$objDFSRConfig.Put("msDFSR-StagingPath",$targetStagingPath)
$objDFSRConfig.SetInfo()

#restart the dfsr service
Restart-Service DFSR
Sleep -seconds 10

Thanks for reading!