Saturday, 30 August 2014

Using PowerShell to Set DFS Override Referral Ordering - UPDATED

Quite a nice update to the script originally posted here. Nice features of this script are that it handles timeouts. And I rather like the Columnize function. No more commentary, now for the script!

#########
# Title #
#########

"";"Set DFSN Override Referral Ordering"
   "===================================";""

#############################################
# Check for Windows Server 2012 requirement #
#############################################

$OSversion = [System.Environment]::OSVersion.Version
if ($OSversion.major -le 6){
       if ($OSversion.minor -lt 2){
              "This script needs to be run on a Windows 2012 Server or later!";"";EXIT}}

#####################################
# Check for DFSN module requirement #
#####################################

if(!(import-module -Name DFSN -PassThru -ErrorAction SilentlyContinue)){
       "Unable to Import-Module DFSN!";"";EXIT}

###################################
# Display some namespace examples #
###################################

$xDomain   = "lab.priv"
$xDFolder  = "ns001"
$xComputer = "fileserver01.lab.priv"
$xCFolder  = "data001"
      
"Domain-based namespace examples:"
"\\$xDomain\$xDFolder";""
"Stand-alone namespace examples:"
"\\$xComputer\$xCFolder";""

###################################################################################################
# This function prompts for namespace type and recursively calls itself if not answered correctly #
###################################################################################################

Function NameSpaceType{
       $readInput = Read-Host "Is this a domain-based or stand-alone namespace (enter D or S)?"
       If($readInput.ToUpper() -eq "D"){Return "D";break}
       ElseIf($readInput.ToUpper() -eq "S"){Return "S";break}
       Else{NameSpaceType}}

$nameSpaceType = NameSpaceType

##############################################
# Request input of domain name/computer name #
##############################################

If($nameSpaceType -eq "D"){
       $xNamespace = "\\$xDomain\$xDFolder"
       $domain = Read-Host "Enter the domain name (e.g. $xDomain)?"
       $ThisJob = Start-Job -Scriptblock {param ($input) Get-DfsnRoot -Domain $input -ErrorAction SilentlyContinue} -ArgumentList $domain}

If($nameSpaceType -eq "S"){
       $xNamespace = "\\$xComputer\$xCFolder"
       $computer = Read-Host "Enter the computer name (e.g. $xComputer)?"
       $ThisJob = Start-Job -Scriptblock {param ($input) Get-DfsnRoot -Computername $input -ErrorAction SilentlyContinue} -ArgumentList $computer}
""

######################################################################
# This function implements a timeout if $ThisJob is taking too long. #
# It uses $ThisJob,$seconds,$exitedJob from outside the function.    #
######################################################################

$seconds = 15
$exitedJob = $false

Function HandleTimeout{
       "This will timeout after $seconds seconds!"
       $i = 1
       $Timer = [System.Diagnostics.Stopwatch]::StartNew()
       While ($ThisJob | Get-Job | where {$_.State -imatch "Running"}){
              If ($Timer.Elapsed.Seconds -ge $seconds){
                     "Job timed out!"
                     $exitedJob = $true
                     $ThisJob | Get-Job | Remove-Job -Force
                     break}
              Start-Sleep -Seconds 1
              "$i seconds has passed..."
              $i++}
       [Void]($Timer.Stop)}

HandleTimeout

####################################################################################
# If Get-DfsnRoot has not timed-out, display the results (if any), otherwise don't #
####################################################################################

$Results = $ThisJob | where {$_.State -inotmatch "failed"} | receive-job

If (!$exitedJob){
       If (!$Results){"No results from Get-DfsnRoot.";""}
       Else {$Results | Format-Table -Autosize}}
Else {"Timed out after $seconds seconds running Get-DfsnRoot.";""}

########################
# Prompt for Namespace #
########################

$namespace  = Read-Host "Enter the DFS Namespace (e.g. $xNamespace)?"
$namespace += "\*"
""

##################################
# Get DFSN Folders in $namespace #
##################################

$ThisJob   = Start-Job -Scriptblock {param ($input) Get-DfsnFolder -path $input -ErrorAction SilentlyContinue} -ArgumentList $namespace
$seconds   = 30
$exitedJob = $false
HandleTimeout
$folders   = $ThisJob | where {$_.State -inotmatch "failed"} | receive-job

If (!$exitedJob){
       If (!$folders){"No results from Get-DfsnFolder.";"";EXIT}}
Else {"Timed out after $seconds seconds running Get-DfsnFolder.";"";EXIT}
""

########################
# Formatting Functions #
########################

Function PadR{
       Param([string]$item,[int]$padR)
       $item.PadRight($padR," ").SubString(0,$padR)}  

Function Columnize{
       $argsCount = $args.count
       $outString = ""
       $i = 0
       do {
              $outString += PadR $args[$i] $args[$i+1] + " "
              $i+=2
       } while ($i -le $argsCount)
       $outString}

######################################
# Output the Folders and TargetPaths #
######################################

$x1 = 30;$x2 = 30;$x3 = 7;$x4 = 21
Columnize "Path" $x1 "TargetPath" $x2 "State" $x3 "ReferralPriorityClass" $x4
Columnize "----" $x1 "----------" $x2 "-----" $x3 "---------------------" $x4

$start = $true            
$folders | foreach{
       $targets = Get-DfsnFolderTarget -path $_.Path
       if ($start){
              $targetsTable = $targets
              $start = $false
       }Else{
              $targetsTable += $targets}
       $targets | foreach{
              Columnize ($_.Path) $x1 ($_.TargetPath) $x2 ($_.State) $x3 ($_.ReferralPriorityClass) $x4}}
""

###########################################
# Prompt for First/Last among all targets #
###########################################

$serverFirst = Read-Host "Enter the server NETBIOS\FQDN to be set as 'First among all targets'"
$serverLast  = Read-Host "Enter the server NETBIOS\FQDN to be set as 'Last among all targets' "
""
Columnize "Path" $x1 "TargetPath" $x2 "State" $x3 "ReferralPriorityClass" $x4
Columnize "----" $x1 "----------" $x2 "-----" $x3 "---------------------" $x4

########################################
# Set GlobalHigh/GlobalLow as required #
########################################

$i=0

$targetsTable | foreach{
       If (($_.TargetPath).contains($serverFirst)){
              [Void](Set-DfsnFolderTarget -Path $_.Path -TargetPath $_.TargetPath -ReferralPriorityClass GlobalHigh)
              Columnize ($_.Path) $x1 ($_.TargetPath) $x2 ($_.State) $x3 "global-high" $x4
              $i++}}

$targetsTable | foreach{
       If (($_.TargetPath).contains($serverLast)){
              [Void](Set-DfsnFolderTarget -Path $_.Path -TargetPath $_.TargetPath -ReferralPriorityClass GlobalLow)
              Columnize ($_.Path) $x1 ($_.TargetPath) $x2 ($_.State) $x3 "global-low" $x4
              $i++}}

""
If ($i -eq 0){"Found no matches!";""}

###########
# THE END #
###########

1 comment:

  1. Hey,

    would there be a reason i get no matches each time i try set the 1st and Last servers part on this script?
    I'm trying to use it to set a 1st an last for two servers in the same site that have an equal costing.

    ReplyDelete