Wednesday, June 21, 2017

Setting DFS Links in Powershell or Wfa (W2008)

DFS or Distributed File System, is often used in enterprise environments to virtualize your CIFS tree structure.  If you are automating storage, and if so, CIFS, you might also take it a little further and update your DFS.  This powershell code allows you to add/create, remove & offline/online your dfs links and target shares and get the targets of dfs link.   The code is using dfsutil, so it will still work on older 2008 servers.  Obviously you need to install the DFS role.   NOTE : There is another post on how to do this with remote powershell (Windows 2012+ only)
http://www.wfaguy.com/2017/08/manage-dfs-from-wfa-w2012.html 


First I'm just adding a Get-WfaLogger function.  As the code uses the WFA logger function.

function Get-WFALogger{
    param(
        [switch] $Info,
        [switch] $Error,
        [switch] $Warn,
        [string] $Message
    )

    if($Info){
        Write-Host $Message -foregroundColor green
    }
    if($Warn){
        Write-Host $Message -ForegroundColor yellow
    }
    if($Error){
        Write-Host $Message -ForegroundColor red
    }

}


A function to test a dfs link and/or dfs link target ($null = dfsutil.exe fails)

function testDfsLink{

    param(
      [parameter(Mandatory=$true, HelpMessage="DFS link")]
      [string]$dfsLink,

      [parameter(Mandatory=$false, HelpMessage="Target share")]
      [string]$dfsTarget=''   
    )

    try{
        $proc = Start-Process dfsutil.exe -Wait -PassThru -ErrorAction SilentlyContinue
        if ($proc.ExitCode -eq 87){

            # exists ?
            Get-WFALogger -Info -message ("Checking existance of link " + $dfsLink)
            $DFSCommand = "link `"" + $dfsLink + "`""
            $proc = start-process dfsutil.exe -ArgumentList $DFSCommand -wait -PassThru
            If($proc.ExitCode -eq 0) {

                if($dfsTarget){
                 $DFSCommand = "target " + "`"" + $dfsLink + "`""  + " " + $dfsTarget
                 Get-WFALogger -Info -message ("Checking target " + $dfsTarget + " to link " + $dfsLink)
                 $proc =  start-process dfsutil.exe -ArgumentList $DFSCommand -wait -PassThru

                 if($proc.ExitCode -eq 0) {
                        return $true
                    }else{
                        return $false
                    }

                }else{
                    return $true
                }


            }else{
                return $false
            }
        }else{
            return $null
        }

        
    }catch{
        return $null
    }

}

A function to create a dfs link or add a target to an existing

function addDfsLink{
    param (

      [parameter(Mandatory=$true, HelpMessage="DFS link")]
      [string]$dfsLink,

      [parameter(Mandatory=$true, HelpMessage="Target share")]
      [string]$dfsTarget,
  
      [parameter(Mandatory=$false, HelpMessage="Priority")]
      [ValidateSet("GlobalHigh","GlobalLow")]
      [string]$priority

    )
    
    $dfs = (testDfsLink -dfsLink $dfsLink)


    if($dfs -ne $null){

        If($dfs)
        {

            Get-WFALogger -Warn -message ("Link already exists: " + $dfsLink)

            $dfs = (testDfsLink -dfsLink $dfsLink -dfsTarget $dfsTarget)

         if(-not $dfs)
         {

             $DFSCommand = "target add " + "`"" + $dfsLink + "`""  + " " + $dfsTarget
             Get-WFALogger -Info -message ("Adding target " + $dfsTarget + " to link " + $dfsLink)
             $proc =  start-process dfsutil.exe -ArgumentList $DFSCommand -wait -PassThru

             if($proc.ExitCode -ne 0)
             {
 
              Get-WFALogger -Error -message ("There has been a problem adding target " + $dfsTarget + " to link " + $dfsLink)
              Throw "There has been a problem adding a target to the DFS link"
 
             }
 
 
         }else{

                Get-WFALogger -Warn -message ("target " + $dfsTarget + " on link " + $dfsLink + " already exists")

            }


        }else{

         Get-WFALogger -Warn -message ("Link does not exist, creating it first : " + $dfsLink)
         $DFSCommand = "link add " + "`"" + $dfsLink + "`""  + " " + $dfsTarget

         Get-WFALogger -Info -message ("Adding link " + $dfsLink + " with target " + $dfsTarget)
         $proc = start-process dfsutil.exe -ArgumentList $DFSCommand -wait -PassThru
 
         if($proc.ExitCode -ne 0)
         {
 
          Get-WFALogger -Error -message ("There has been a problem adding link " + $dfsLink + " with target " + $dfsTarget)
                Throw "There has been a problem adding the DFS link"
 
         }
        }



        if([boolean]$priority)
        {
         $DFSCommand = " property PriorityClass set " + "`"" + $dfsLink + "`"" + " " + $dfsTarget + " " + $priority
         Get-WFALogger -Info -message ("Setting Priority class in " + $dfsTarget + " for link " + $dfsLink + " to " + $priority)
         $proc =  start-process dfsutil.exe -ArgumentList $DFSCommand -wait -PassThru

         if($proc.ExitCode -ne 0) {
             Get-WFALogger -Error -message ("There has been a problem setting the priority in " + $dfsTarget + " for link " + $dfsLink + " to " + $priority)
          Throw "There has been a problem setting the priority in the DFS link"
         }

        }
    }else{
        Get-WFALogger -Error -message ("DfsUtil is not installed or failed to validate...")
    }
}

A function to remove a target from a dfs link, the last one, will remove the link as well.  Or if you omit the target, the link gets removed

function removeDfsLink{

    param (

      [parameter(Mandatory=$true, HelpMessage="DFS link name")]
      [string]$dfsLink,

      [parameter(Mandatory=$false, HelpMessage="Target share")]
      [string]$dfsTarget=""

    )


    # exists ?
    $dfs = (testDfsLink -dfsLink $dfsLink)

    if($dfs -ne $null){

        If($dfs) {

            if($dfsTarget){

                $dfs = (testDfsLink -dfsLink $dfsLink -dfsTarget $dfsTarget)

             if($dfs)
             {
                 $DFSCommand = "target remove " + "`"" + $dfsLink + "`""  + " " + $dfsTarget
                 Get-WFALogger -Info -message ("Removing target " + $dfsTarget + " from link " + $dfsLink)
                 $proc =  start-process dfsutil.exe -ArgumentList $DFSCommand -wait -PassThru

                 if($proc.ExitCode -ne 0)
                 {
 
                  Get-WFALogger -Error -message ("There has been a problem removing target " + $dfsTarget + " from link " + $dfsLink)
                  Throw "There has been a problem removing a target from the DFS link"
 
                 }
             }else{

                    Get-WFALogger -Warn -message ("target " + $dfsTarget + " on link " + $dfsLink + " doesn't exist")

                }
            }else{

                $DFSCommand = "link remove " + "`"" + $dfsLink + "`""
                Get-WFALogger -Info -message ("Deleting " + $DFSCommand)
                $proc = start-process dfsutil.exe -ArgumentList $DFSCommand -wait -PassThru
             if($proc.ExitCode -ne 0) {
 
              Get-WFALogger -Error -message ("There has been a problem removing dfs link " + $dfsLink)
              Throw "There has been a problem removing the DFS link"
 
             }
            }
        }else{

         Get-WFALogger -Warn -message "Link does not exist"

        }

    }else{

        Get-WFALogger -Error -message ("DfsUtil is not installed or failed to validate...")

    }

}

A function to set a target online or offline.

function setDfsLink{

    param (

      [parameter(Mandatory=$true, HelpMessage="DFS link name")]
      [string]$dfsLink,

      [parameter(Mandatory=$true, HelpMessage="Target share")]
      [string]$dfsTarget,

      [parameter(Mandatory=$true, HelpMessage="DFS status")]
      [ValidateSet("offline","online")]
      [string]$status

    )


    # exists ?
    $dfs = (testDfsLink -dfsLink $dfsLink -dfsTarget $dfsTarget)

    if($dfs -ne $null){

        If($dfs) {

         $DFSCommand = "property state $status " + "`"" + $dfsLink + "`""  + " " + $dfsTarget
         Get-WFALogger -Info -message ("Setting target " + $dfsTarget + " to $status on link " + $dfsLink)
         $proc =  start-process dfsutil.exe -ArgumentList $DFSCommand -wait -PassThru

         if($proc.ExitCode -ne 0) {
 
          Get-WFALogger -Error -message ("There has been a problem setting target " + $dfsTarget + " $status on link " + $dfsLink)
          Throw "There has been a problem set target $status on the DFS link"
 
         }

        }else{

         Get-WFALogger -Warn -message ("target " + $dfsTarget + " on link " + $dfsLink + " doesn't exist")

        }

    }else{

        Get-WFALogger -Error -message ("DfsUtil is not installed or failed to validate...")

    }

}

A function to get the targets from a dfs link

function getDfsTargets{

    param (

      [parameter(Mandatory=$true, HelpMessage="DFS link name")]
      [string]$dfsLink,

      [parameter(Mandatory=$false, HelpMessage="DFS status")]
      [ValidateSet("OFFLINE","ONLINE","")]
      [string]$status=""

    )

    $dfs = testDfsLink -dfsLink $dfsLink

    if($dfs){
        $psi = New-object System.Diagnostics.ProcessStartInfo 
        $psi.CreateNoWindow = $true 
        $psi.UseShellExecute = $false 
        $psi.RedirectStandardOutput = $true 
        $psi.RedirectStandardError = $true 
        $psi.FileName = 'dfsutil' 
        $psi.Arguments = @("link `"$dfslink`"") 
        $process = New-Object System.Diagnostics.Process 
        $process.StartInfo = $psi 
        [void]$process.Start()
        $output = $process.StandardOutput.ReadToEnd() 
        $process.WaitForExit() 
        $dfslinks = @()

        $regex = if($status -eq ""){
            "Target=`"([^`"]*)`" State=`"([^`"]*)`".*"
        }else{
            "Target=`"([^`"]*)`" State=`"$status`".*"
        }

        foreach($o in ($output -split "`n")){
            if($o -match $regex){
                $dfslinks += $Matches[1]
            }
        }
        return $dfslinks
    }else{
        return @()
    }
}


PS : Special credits to José German Fernandez Diaz

No comments :

Post a Comment