Translating CIFS Shares from 7-Mode to cDOT Tool - CS7C.ps1 - Part 2 of 2: The Script


Copy and paste the below into a text editor and save as say CS7C.ps1.


###############################
## CIFS_Shares_7_to_C (CS7C) ##
###############################

# The program can run run simply as .\CS7C.ps1.
# The following parameters are not necessary to run CS7C.
# You need to construct the VolsToMigrate file first.
Param(
 # (NO PROMPT) Version:
 [String]$Version = "1.0",
 # Clustername / Cluster Mgmt IP:
 [String]$Cluster,
 # SVM Name:
 [String]$SVM,
 # Specifies whether volume names are changing going to CDOT:
 [Switch]$VolNameChange,
 [Switch]$NoVolNameChange,
 # (NO PROMPT) File path to file containing 7 to C volume name mappings:
 [String]$VolMappingFilePath = "CS7C.VolNameMap.TXT",
 # (NO PROMPT) File path to file containing 7-Mode volumes to migrate:
 [String]$VolsToMigrateFilePath = "CS7C.VolsToMigrate.TXT",
 # The workstation is either ON / OFF the domain used by source 7-Mode CIFS server:
 [Switch]$OnDomain,
 [Switch]$OffDomain,
 # (NO PROMPT) If running from a machine off domain you need to provide this:
 [String]$SIDtoNameMapFilePath = "CS7C.SIDtoNameMap.TXT",
 # (NO PROMPT) This file contains the list of CDOT Shares on the SVM:
 [String]$CDOTSVMsharesFilePath = "CS7C.CdotVserverShares.TXT",
 # Do CDOT volume junctions paths have /vol or just /?:
 [Switch]$SlashVol,
 [Switch]$NoSlashVol,
 # (NO PROMPT) CIFS Share Property Standards:
 [String]$OfflineFiles = "manual",
 [String]$ShareProperties = "browsable,oplocks,changenotify",
 [String]$SymlinkProperties = "symlinks",
 [String]$VscanFileopProfile = "standard",
 # (NO PROMPT) CLI only switch to add _FILER to the CIFS share name:
 [Switch]$AppendFilerNameToShare,
 # Output Filename Prefix:
 [String]$OutputFilePrefix,
 # You can specify $INIfile if you want run from an INI file:
 [String]$INIfile,
 # INTERNAL SWITCH!:
 [Switch]$InvokedByINIfile
)

## BASIC DISPLAY FUNCTIONS / GENERIC FUNCTIONS ##
## =========================================== ##

FUNCTION Uline{$args[0];("## " + "".PadRight($args[0].length -6,"=") + " ##");""}
FUNCTION Wr {
 Param([String]$ToDisplay,[String]$Color = "WHITE")
 If($ToDisplay){
  Write-Host $ToDisplay -ForegroundColor $Color -NoNewLine
 }else{
  Write-Host
 }
}
FUNCTION Columnize {
 For($i = 0; $i -lt $args.count; $i += 3){
  If($i -lt ($args.count - 3)){
   Wr ($args[$i].PadRight($args[$i+1]," ").SubString(0,$args[$i+1])) ($args[$i+2])
  }else{
   Wr ($args[$i]) -Color ($args[$i+2]);Wr
  }
 }
}
FUNCTION Press-Enter{Wr "Press Enter to continue... " CYAN;$P = Read-Host}
FUNCTION EXITING{Wr " - exiting!" RED;Wr;Wr;Press-Enter;EXIT}
FUNCTION PromptValidator{
 Param([Switch]$YesOrNo)
 while ($TRUE){
  $ReadIn = Read-Host
  If ($YesOrNo){
   If(($ReadIn -eq "YES") -or ($ReadIn -eq "Y")){
    RETURN $True
   }
   If(($ReadIn -eq "NO")  -or ($ReadIn -eq "N")){
    RETURN $False
   }
  }ELSEIF($args[0]){
   Foreach($argument in $args){
    If($ReadIn -eq  $argument){
     RETURN $ReadIn
    }
   }
  }ELSE{
   If($ReadIn.length -ge 1){RETURN $ReadIn}
  }
 }
}
FUNCTION PromptSetting {
 Param([String]$Prompt,[String]$Setting,[Switch]$AllowEnter)
 Wr $Prompt CYAN
 If($Setting){
  Wr $Setting;Wr;RETURN $Setting
 }
 If($AllowEnter){
  $NewSetting = Read-Host;RETURN $NewSetting
 }
 Return (PromptValidator)
}
FUNCTION ProcessYesNoSwitch {
 Param([String]$Question,[Boolean]$EnableSwitch,[Boolean]$DisableSwitch)
 Wr $Question CYAN
 If($EnableSwitch){
  Wr "YES";Wr;RETURN $true
 }elseif($DisableSwitch){
  Wr "NO";Wr;RETURN $false
 }else{
  PromptValidator -YesOrNo
 }
}
FUNCTION ProcessArray {
 Param([System.Array]$ArrayToProcess,[Switch]$AllowHash)
 [System.Array]$ProcessedArray = @()
 Foreach($ArrayLine in $ArrayToProcess){
  If($ArrayLine -ne ""){
   If($ArrayLine.substring(0,1) -ne "#"){
    If($AllowHash){
     $ProcessedArray += $ArrayLine
    }else{
     $ProcessedArray += $ArrayLine.Split("#")[0].Trim()
    }
   }
  }
 }
 , $ProcessedArray
}
FUNCTION Process7MMTinputFile {
 Param([String]$InputFile,[String]$Description,[Switch]$AllowHash)
 If(!(Test-Path $InputFile)){
  Wr "$Description specified but path test to $InputFile failed" RED;EXITING
 }
 [System.Array]$GetFile = Get-Content $InputFile
 If(!$GetFile){
  Wr "$Description specified but file $InputFile is empty!" RED;Wr;Wr
 }
 Wr "Loaded $Description from $InputFile successfully!" GREEN;Wr
 If($AllowHash){
  $GetFile = ProcessArray $GetFile -AllowHash
 }else{
  $GetFile = ProcessArray $GetFile
 }
 , $GetFile
}

## IF HAVE INI FILE ##
## ================ ##

If($INIfile -and !$InvokedByINIfile){
 If (!(Test-Path $INIfile)){
  Wr;Wr "INI file $INIfile specified but not detected!" RED;Wr;Wr;EXIT
 }
 $INIcontent = Get-Content $INIfile
 $INIcontent = ProcessArray $INIcontent
 [String]$CommandExpression = ""
 $INIcontent | foreach{
  If($_.split("=").count -ge 2){
   $CommandExpression += ((($_.split("="))[0]).trim() + " " + (($_.split("="))[1]).trim() + " ")
  }else{
   $CommandExpression += $_.trim() + " "
  }
 }
 Cls;Wr;Wr "Detected $INIfile and running:" MAGENTA;Wr
 Wr;Wr $commandExpression;Wr;Wr      
 Invoke-Expression ($CommandExpression + " -InvokedByINIfile")
 EXIT
}elseif(!$InvokedByINIfile){
 Wr;Wr "-INIfile not specified: not running from an INI File" CYAN;Wr
}

## CONNECT TO 7-MODE/CDOT CLUSTER FUNCTION ##
## ======================================= ##

FUNCTION Get-PsCredential{
 Param([String]$Username,[String]$PasswordPrompt)
 Wr $PasswordPrompt CYAN;$Password = Read-Host -AsSecureString;Wr
 RETURN (New-Object System.Management.Automation.PsCredential($Username,$Password))
}
FUNCTION Load-DataOntapPSTK {
 If(Get-Module DataONTAP){RETURN}
 [Void](Import-Module DataONTAP -ErrorAction SilentlyContinue)
 If(!(Get-Module DataONTAP)){
  Wr "Unable to load the DataONTAP PowerShell Toolkit" RED;EXITING
 }
 Wr "Loaded the Data ONTAP PowerShell Toolkit!" GREEN;Wr;Wr
}
FUNCTION Connect-ToNetApp {
 Param([String]$System,[System.Object]$Creds,[Switch]$SevenMode) # Note: The default is cDOT
 [Void](Load-DataOntapPSTK)
 Wr "Checking connection to $System ..." CYAN; Wr
 If($SevenMode){
  $Connected = Connect-NaController -Name $System -Credential $Creds -Timeout 20000 -ErrorAction SilentlyContinue
 }else{
  $Connected = Connect-NcController -Name $System -Credential $Creds -Timeout 20000 -ErrorAction SilentlyContinue
 }
 If($Connected){
  Wr "Successfully connected to $System" GREEN;Wr;Wr
 }else{
  Wr "Unable to connect to $System with provided credentials" RED;EXITING
 }
}

#############################
## PART 1: DATA COLLECTION ##
#############################

Wr;Wr "<<<<<<<<<< CS7C: $Version >>>>>>>>>>" MAGENTA;Wr;Wr
$OutputFilePrefix = PromptSetting "Output File Prefix? " $OutputFilePrefix
$OutputFileName = $OutputFilePrefix + "_CIFS_SHARES.txt"
Wr;Wr ">>>>>>> PART 1: DATA COLLECTION <<<<<<<" MAGENTA;Wr;Wr

## MAPPING 7-MODE VOLUMES TO CDOT VOLUMES ##
## ====================================== ##

[System.Array]$Systems7G     = @()
[System.Object]$7ModeVol     = @{}
[System.Object]$CutoverVols  = @{}
[System.Object]$MapVols      = @{}
[System.Array]$CdotVolsArray = @()
[String]$CdotVolsList        = ""
[System.Object]$vFilerList   = @{}

$VolNameChange = ProcessYesNoSwitch "Are volume names changing going to CDOT (yes/no)? " $VolNameChange $NoVolNameChange;Wr
If($VolNameChange){
 [System.Array]$VolMap = Process7MMTinputFile $VolMappingFilePath "7CGT 7-C Volume Name Mapping File"
}
[System.Array]$VolsToMigrate = Process7MMTinputFile $VolsToMigrateFilePath "Volumes to Migrate from 7-Mode File"

## PROCESS THE VOLUMES TO MIGRATE FILE ##
Foreach ($line in $VolsToMigrate){
 $lineSplit = $line.split(",")
 If(($lineSplit.count -eq 3) -or ($lineSplit.count -eq 4)){
  $pFiler = $lineSplit[0]
  If(!($Systems7G -contains $pFiler)){
   $Systems7G += $pFiler
   [System.Object]$7ModeVol.$pFiler = @{}
   [System.Object]$CutoverVols.$pFiler = @{}
   [System.Array]$CutoverVols.$pFiler.VOLs7 = @()   
  }
  $Volume7G = $lineSplit[2]
  $7ModeVol.$pFiler.$Volume7G = $lineSplit[1]
  $CutoverVols.$pFiler.VOLs7 += $Volume7G
  If(!$Volume7G){
   Wr;Wr "Error processing Vols to Migrate File and this line - " RED;Wr;Wr $line YELLOW;EXITING
  }
 }
}      
If(!$Systems7G){
 Wr;Wr "Error processing the Vols To Migrate file $VolsToMigrateFilePath" RED;EXITING
}

## PROCESS 7-MODE TO CDOT VOLUME NAME CHANGES ##
$Systems7G | Foreach {
 [System.Array]$CutoverVols.$_.VOLsC = @()
 If($VolNameChange){
  Foreach($vol7G in $CutoverVols.$_.VOLs7){
   $FoundMatch = $null
   Foreach($line in $VolMap){
    $lineSplit = $line.split(",")
    If($lineSplit[0] -eq $_){
     If($lineSplit[1] -eq $vol7G){
      $FoundMatch = $true
      If($lineSplit.count -gt 2){
       $CutoverVols.$_.VOLsC += $lineSplit[2]
      }else{
       $CutoverVols.$_.VOLsC += $lineSplit[1]
      }
     }                                       
    }
   }
   If(!$FoundMatch){Wr "Unable to find a match for volume $vol7G in $VolMappingFilePath" RED;EXITING}
  }
 }else{
  $CutoverVols.$_.VOLsC = $CutoverVols.$_.VOLs7
 }
}

## OUTPUT TO 7-MODE VOLS TO CDOT VOLS TABLE ##
Wr;Wr ">>> MAPPING 7-MODE VOLUMES TO CDOT VOLUMES <<<" GREEN;Wr;Wr
Columnize "7-MODE SYSTEM" 25 Green "OWNING VFILER" 25 Green "VOLUME (7G)" 25 Green "VOLUME (CDOT)" 30 Green
$j = 0
$Systems7G | Foreach {
 $j++;$i = 0
 [System.Object]$MapVols.$_ = @{}
 [System.Object]$vFilerList.$_ = @{}
 [System.Array]$vFilerList.$_.vFilers = @()
 $CdotVolsArray += $CutoverVols.$_.VOLsC
 Foreach($vol7G in ($CutoverVols.$_.VOLs7)){
  $volCM = ($CutoverVols.$_.VOLsC)[$i]
  $MapVols.$_.$vol7G = $volCM
  $OwningVfiler = $7ModeVol.$_.$vol7G
  Columnize $_ 25 Cyan $OwningVfiler 25 Cyan $vol7G 25 Yellow $volCM 30 Yellow
  ## THIS SECTION CONSTRUCTS VFILERLIST ##
  If($OwningVfiler){
   If($vFilerList.$_.$OwningVfiler -eq $null){
    [System.Array]$vFilerList.$_.vFilers += $OwningVfiler
    [System.Array]$vFilerList.$_.$OwningVfiler  = @()
    $vFilerList.$_.$OwningVfiler += $vol7G
   }else{
    $vFilerList.$_.$OwningVfiler += $vol7G
   }
  };$i++
  ## THIS LINE CONSTRUCTS A COMMA SEPARATED STRING OF CDOT VOLS ##
  If(($i -eq $CutoverVols.$_.VOLs7.count) -and ($j -eq $Systems7G.count)){
   $CdotVolsList += $volCM
  }else{
   $CdotVolsList += $volCM + ","
  }
 }
}

FUNCTION Get-7MConfigFile{
 Param([String]$ETCPATH,[String]$7MConfigFile,[String]$ConfigDirectory)
 Wr "Reading the file: " GREEN; Wr $7MConfigFile; Wr
 [String]$ConfigFilePath = $ETCPATH + "/$7MConfigFile"             
 [String]$StringOutput = Read-NaFile $ConfigFilePath
 [System.Array]$ArrayOutput = $StringOutput.Split("`n")
 $ArrayOutput | Set-Content ($ConfigDirectory + "/" + $7MConfigFile)
}

## 7-Mode: ONLINE MODE ##
## =================== ##

Wr;[Boolean]$OnlineFor7Mode = ProcessYesNoSwitch "Online acquisition of 7-Mode Config Files (yes/no)? ";Wr
If($OnlineFor7Mode){
 $UserName7Mode = PromptSetting "7-Mode Username: "
 $Credential7M  = Get-PsCredential $UserName7Mode "7-Mode Password: "
 $Systems7G | Foreach{
  [Void](Connect-ToNetApp $_ $Credential7M -SevenMode)                    
  Foreach($vFiler in $vFilerList.$_.vFilers){
   [String]$GetRootVol = ""
   [String]$ETCPATH = ""
   [String]$ConfigDirectory = ($_ + "." + $vFiler)
   [Void](New-Item -Path $ConfigDirectory -ItemType Directory -Force)
   If($vFiler -eq "vFiler0"){
    $global:CurrentNaController.vfiler = ""
   }else{
    $global:CurrentNaController.vfiler = $vFiler
   }
   $GetRootVol = (Get-NaVolRoot -ErrorAction SilentlyContinue).Name
   If($GetRootVol){
    $ETCPATH = "/vol/" + $GetRootVol + "/etc"
   }else{
    $ETCPATH = (Get-NaCifsShare -Share ETC$).MountPoint
   }
   If(!$ETCPATH){
    Wr;Wr "$UserName7Mode has permission issues getting $_ $vFiler 's /etc path, recommend use root" RED;EXITING
   }
   Wr "ETC path for 7GSystem = $_ & vFiler = $vFiler is " GREEN;Wr $ETCPATH YELLOW;Wr
   [Void](Get-7MConfigFile $ETCPATH "cifsconfig_share.cfg" $ConfigDirectory)
  }
 }
}

## PRIMARY CDOT CLUSTER & SVM ##
## ========================== ##

Wr;Wr ">>> PRIMARY cDOT CLUSTER & SVM <<<" GREEN;Wr;Wr
$Cluster = PromptSetting "Enter the Cluster: " $Cluster
$SVM     = PromptSetting "Enter the SVM    : " $SVM; Wr
[Boolean]$OnlineForCDOT = ProcessYesNoSwitch "Online cDOT data acquisition (yes/no)? "; Wr
If($OnlineForCDOT){
 $UserNameCdot = PromptSetting "Cluster Username: "
 $Credential  = Get-PsCredential $UserNameCdot "Cluster Password: "
 [Void](Connect-ToNetApp $Cluster $Credential)
}

## CIFS SHARE SETTINGS ##
## =================== ##

Wr; Wr ">>> COMMON (STANDARD) CIFS SHARE SETTINGS <<<" GREEN;Wr;Wr
$SlashVol = ProcessYesNoSwitch "Are volumes mounted with /vol in the CDOT Junction Path (yes/no)? " $SlashVol $NoSlashVol;Wr

Wr; Wr ">>> CIFS SHARE SETTING STANDARDS <<<" GREEN;Wr;Wr
Wr "These share settings are applied to all shares:" GREEN;Wr;Wr
Wr "CIFS Share Property: OfflineFiles       = " CYAN;Wr $OfflineFiles;Wr
Wr "CIFS Share Property: ShareProperties    = " CYAN;Wr $ShareProperties;Wr
Wr "CIFS Share Property: SymlinkProperties  = " CYAN;Wr $SymlinkProperties;Wr
Wr "CIFS Share Property: VscanFileopProfile = " CYAN;Wr $VscanFileopProfile;Wr;Wr
Wr "The following settings adopt default values:" GREEN; Wr
Wr "-file-umask / -dir-umask / -attribute-cache-ttl" CYAN; Wr

## TRANSLATING SIDS TO USERS/GROUPS ##
## ================================ ##

Wr;Wr ">>> TRANSLATING SIDS TO USERS/GROUPS <<<" GREEN;Wr;Wr
Wr "To translate SIDs used in the 7-Mode cifsconfig_share.cfg files to Domain User/Group Names used in CDOT, we need either a SID to Name Mapping File, or - if the machine we're running 7CGT on is on the same domain as the systems being transitioned - we can obtain SIDs using Powershell." GREEN;Wr;Wr
$OnDomain = ProcessYesNoSwitch "Is this workstation on the same Domain as the systems being transitioned (yes/no)? " $OnDomain $OffDomain
If(!$OnDomain){
 [System.Array]$SIDtoNameMap = Process7MMTinputFile $SIDtoNameMapFilePath  "SID to Name Map File"
}
[System.Array]$Global:SIDMapFileContent = @()
$Global:SIDMapFileContent += "## SIDMAPFILE"
$Global:SIDMapFileContent += "## Setup file with on each row: SID,USERorGROUP"

## CIFS: GET LIST OF SHARES ON THE CDOT SVM (NEED TO PREVENT CONFLICTS) ##
## ==================================================================== ##

[System.Array]$CifsSharesSVM = @()
Wr; Wr ">>> CIFS SHARES ON $SVM <<<" GREEN; Wr; Wr
If($OnlineForCDOT){
 $attrs = Get-NcCifsShare -Template
 $GetNcCifsShares = Get-NcCifsShare -VserverContext $SVM -Attributes $attrs
 $GetNcCifsShares | Foreach {
  $CifsSharesSVM += $_.ShareName
 }
 [System.Array]$CreateCDOTSharesFile = @()
 Foreach($Share in $CifsSharesSVM){
  $CreateCDOTSharesFile += ($SVM + ',' + $Share + ',')
 }
 $CreateCDOTSharesFile | Set-Content $CDOTSVMsharesFilePath
}else{
 Wr "Create the CDOT Shares File by running -" GREEN;Wr
 Wr ("$Cluster" + "::> ") GREEN; Wr ("set -showseparator " + '"' + "," + '"'+ "; rows 0; cifs share show -fields share-name -vserver $SVM") YELLOW;Wr
 Wr "- and then copy and paste this information into a text file." GREEN;Wr;Wr
 [System.Array]$CDOTSharesFile = Process7MMTinputFile $CDOTSVMsharesFilePath "CDOT SVM Shares File" -AllowHash;Wr
 $CDOTSharesFile | Foreach {
  $CifsSharesSVM += $_.Split(",")[1]
 }
}
$CifsSharesSVM | Foreach {
 Wr $_ YELLOW;Wr
}

## FUNCTION: COLLECT REQUIRED 7G CONFIG FILES (works on a per vFiler basis) ##
## ======================================================================== ##

FUNCTION GetConfigFile {
 Param([String]$7GcfgFile,[String]$7GSystem,[String]$vFilerName)
 Wr ("Looking for $7GcfgFile for $7Gsystem & $vFilerName") GREEN;Wr
 Wr (" in this folder ") GREEN;Wr ($7Gsystem + "." + $vFilerName) YELLOW;If($vFilerName -eq "vFiler0"){Wr " or " GREEN;Wr $7Gsystem YELLOW};Wr
 If(Test-Path ($7Gsystem + "." + $vFilerName + "\" + $7GcfgFile)){
  $ArrayOutput = Get-Content ($7Gsystem + "." + $vFilerName + "\" + $7GcfgFile)
 }elseif(($vFilerName -eq "vFiler0") -and ( Test-Path ($7Gsystem + "\" + $7GcfgFile))){
  $ArrayOutput = Get-Content ($7Gsystem + "\" + $7GcfgFile)
 }else{
  Wr "Unable to find file" RED;EXITING
 }
 If(!$ArrayOutput){
  Wr "$7GcfgFile file at $cfgFilePath is a blank file!" YELLOW;Wr;Wr
 }
 , $ArrayOutput
}

## FUNCTIONS FOR PROCESSING CIFS SHARES ##
## ==================================== ##

[System.Object]$CifsCfg = @{} # CifsCfg hashtable structure:
# OBJECT $CifsCfg.$System7G.$vFiler
# ARRAY  $CifsCfg.$System7G.$vFiler.Volumes
# OBJECT $CifsCfg.$System7G.$vFiler.ShareToVolume
# STRING $CifsCfg.$System7G.$vFiler.ShareToVolume.$Share
# OBJECT $CifsCfg.$System7G.$vFiler.$Volume
# ARRAY  $CifsCfg.$System7G.$vFiler.$Volume.Shares
# OBJECT $CifsCfg.$System7G.$vFiler.$Volume.$Sharename
# STRING $CifsCfg.$System7G.$vFiler.$Volume.$Sharename.ShareName
# STRING $CifsCfg.$System7G.$vFiler.$Volume.$Sharename.SharePath
# STRING $CifsCfg.$System7G.$vFiler.$Volume.$Sharename.PathAfterVolume
# STRING $CifsCfg.$System7G.$vFiler.$Volume.$Sharename.Comment
# INT    $CifsCfg.$System7G.$vFiler.$Volume.$Sharename.AccessRules
# STRING $CifsCfg.$System7G.$vFiler.$Volume.$Sharename.X.UserOrGroup
# STRING $CifsCfg.$System7G.$vFiler.$Volume.$Sharename.X.Permission

FUNCTION Process-CifsShareAddLine {
 ## MANIPULATION: Manipulation of $line ##
 $splitLineQuotes = $line.split('"')
 If(($splitLineQuotes.count) -ne 7){
  Wr ("This line >>> $line <<< does not have the expected number of quotes (6)!") RED;Wr;RETURN
 }
 [String]$Share     = $splitLineQuotes[1]
 [String]$SharePath = $splitLineQuotes[3]
 [String]$comment   = $splitLineQuotes[5]

 ## MANIPULATION: Mainpulate $SharePath to get $Vol7G,$PathAfterVolName ##
 $SplitSharePath = $SharePath.Split("/")
 If ($SharePath -eq "/"){
  $Vol7G = "/"
  $PathAfterVolName = ""
 }elseif($SharePath -eq "/etc"){
  $Vol7G = "/"
  $PathAfterVolName = "etc"  
 }else{
  $Vol7G = $SplitSharePath[2]
  $VolChars = $Vol7G.Length
  $PathAfterVolName = $SharePath.Substring((5 + $VolChars),($SharePath.Length - 5 - $VolChars))
 }
       
 ## CONSTRUCTION: Construct $CifsCfg.$System7G.$vFiler ##
 If(!($CifsCfg.$System7G.$vFiler.Volumes -Contains $Vol7G)){
  $CifsCfg.$System7G.$vFiler.Volumes += $Vol7G
  [System.Object]$CifsCfg.$System7G.$vFiler.$Vol7G = @{}
  [System.Array]$CifsCfg.$System7G.$vFiler.$Vol7G.Shares = @()     
  [Int]$CifsCfg.$System7G.$vFiler.$Vol7G.SharesCount = 0
 }     
 [String]$CifsCfg.$System7G.$vFiler.ShareToVolume.$Share = $Vol7G
 $CifsCfg.$System7G.$vFiler.$Vol7G.Shares += $share
 [System.Object]$CifsCfg.$System7G.$vFiler.$Vol7G.$Share = @{}
 [String]$CifsCfg.$System7G.$vFiler.$Vol7G.$Share.ShareName = $Share
 [String]$CifsCfg.$System7G.$vFiler.$Vol7G.$Share.SharePath = $SharePath
 [String]$CifsCfg.$System7G.$vFiler.$Vol7G.$Share.PathAfterVolume = $PathAfterVolName
 [String]$CifsCfg.$System7G.$vFiler.$Vol7G.$Share.Comment = $Comment
 [Int]$CifsCfg.$System7G.$vFiler.$Vol7G.$Share.AccessRules = 0
 Columnize "ADD" 8 Cyan ($Share) 25 Yellow (" " + $Vol7G) 25 Yellow (" " + $PathAfterVolName) 40 Yellow
}

FUNCTION Process-CifsShareAccessLine {
 ## MANIPULATION: Manipulation of $line ##
 $Share = ($line.split('"'))[1]
 $ToEndOfShare = 11 + 2 + ($share.length) + 2
 $line = $line.Substring($ToEndOfShare,($line.length - $ToEndOfShare))
 $userGroupSID = ($line.Split(" "))[0]
 $permission = $line.Substring(($userGroupSID.length + 1),($line.length - $userGroupSID.length - 1))

 ## CONSTRUCTION: Construction of $CifsCfg.$System7G.$vFiler        ##
 $Vol7G = $CifsCfg.$System7G.$vFiler.ShareToVolume.$Share
 $CifsCfg.$System7G.$vFiler.$Vol7G.$Share.AccessRules ++
 $AccessRule = $CifsCfg.$System7G.$vFiler.$Vol7G.$Share.AccessRules
 [System.Object]$CifsCfg.$System7G.$vFiler.$Vol7G.$Share.$AccessRule = @{}
 $CifsCfg.$System7G.$vFiler.$Vol7G.$Share.$AccessRule.UserOrGroup = $userGroupSID
 $CifsCfg.$System7G.$vFiler.$Vol7G.$Share.$AccessRule.Permission = $permission
 Columnize "ACCESS" 8 Cyan $Share 25 Yellow (" " + $userGroupSID) 25 Yellow (" " + $permission) 40 Yellow
}

## CIFS: COLLECT AND PROCESS cifsconfig_share.cfg FILES ##
## ==================================================== ##

Wr;Wr ">>> COLLECT AND PROCESS cifsconfig_share.cfg FILES <<<" GREEN;Wr;Wr
Foreach($System7G in $Systems7G){
 [System.Object]$CifsCfg.$System7G = @{}
 Foreach($vFiler in ($vFilerList.$System7G.vFilers)){
  Wr "Collecting the cifsconfig_share.cfg file from vFiler $vFiler on $System7G :" GREEN;Wr
  [System.Array]$CifsConfigFile = @()
  $CifsConfigFile  = GetConfigFile "cifsconfig_share.cfg" $System7G $vFiler;Wr
  Columnize "ADD"    8 Green "SHARE NAME" 25 Green " VOLUME (7-MODE)" 25 Green " PATH"       40 Green
  Columnize "ACCESS" 8 Green "SHARE NAME" 25 Green " SID"             25 Green " PERMISSION" 40 Green
  [System.Object]$CifsCfg.$System7G.$vFiler = @{}
  [System.Array]$CifsCfg.$System7G.$vFiler.Volumes = @()
  [System.Object]$CifsCfg.$System7G.$vFiler.ShareToVolume = @{}
  Foreach($line in (ProcessArray $CifsConfigFile -AllowHash)){
   If($line.substring(0,16) -eq "cifs shares -add"){
    [Void](Process-CifsShareAddLine)
   }elseif($line.substring(0,11) -eq "cifs access"){
    [Void](Process-CifsShareAccessLine)
   }
  };Wr
 }
}

########################################
## PART 2: GENERATING COMMANDS OUTPUT ##
########################################

Wr;Wr ">>>>>>> PART 2: GENERATING COMMANDS OUTPUT <<<<<<<" MAGENTA;Wr
Wr;Wr "Clustershell Commands Output Filename = " CYAN; Wr $OutputFileName;Wr
Wr;Wr ".................. PLEASE WAIT ..................." GREEN;Wr;Wr
FUNCTION Cshell{ ("# " + $ClusterName + "::>"),("")}
[Int]$Spacing = 15

## CIFS: SHARE CREATE COMMANDS FOR NEW VOLUME$ SHARES ##
## ================================================== ##

[System.Object]$CdotShareCount = @{}
$CdotVolsArray | Foreach{$CdotShareCount.$_ = 0}
$CdotVolsArray | Foreach{$CdotShareCount.$_ ++}

FUNCTION OUTPUT-CifsShareCreateVolumes {
 Param([String]$ClusterName,[String]$SVMname)       
 Uline ("## CIFS: SHARE CREATE COMMANDS FOR NEW VOLUME$ SHARES ##")
 ("# (1) Create VOLUME$ shares with default properties")
 ("# (2) Removes the default Everyone access")
 ("# (3) Adds BUILTIN\Administrators with Full_Control")
 ("# (4) Adds NT AUTHORITY\Authenticated Users with Change");("")
 Cshell;$CdotVolsArray | Foreach{
 [String]$VolPath = "/"
  If($SlashVol){
   $VolPath += "vol/"
  }
  $VolPath += $_
  ("vserver cifs share create -vserver $SVMname -share-name $_$ -path $VolPath -share-properties $ShareProperties -symlink-properties $SymlinkProperties -offline-files $OfflineFiles -vscan-fileop-profile $VscanFileopProfile")
 };("")
 Cshell;$CdotVolsArray | Foreach{
  ("vserver cifs share access-control create -vserver $SVMname -share $_$ -user-or-group BUILTIN\Administrators -permission Full_Control")
 };("")
 Cshell;$CdotVolsArray | Foreach{
  ("vserver cifs share access-control create -vserver $SVMname -share $_$ -user-or-group " + '"' + "NT AUTHORITY\Authenticated Users" + '"' + " -permission Change")
 };("")
 Cshell;$CdotVolsArray | Foreach{
  ("vserver cifs share access-control delete -vserver $SVMname -share $_$ -user-or-group Everyone")
 };("")
}

## CIFS: SHARE CREATE AND ACCESS COMMANDS ##
## ====================================== ##

[Int]$ACLsCount = 0
[System.Object]$ShareConflictsText = @{}
[System.Object]$ShareCreatesText = @{}
[System.Object]$ShareAccessText = @{}

$Systems7G | Foreach {
 [System.Object]$ShareConflictsText.$_ = @{}
 [System.Object]$ShareCreatesText.$_ = @{}
 [System.Object]$ShareAccessText.$_ = @{}
 [System.Array]$SpecialShares = "ETC$","HOME","C$"
 Foreach($Vol7G in ($CutoverVols.$_.VOLs7)){
  $SpecialShares += ($Vol7G + "$")
 }

 Foreach($vFiler in ($vFilerList.$_.vFilers)){
  [System.Array]$ShareConflictsText.$_.$vFiler = @()
  [System.Array]$ShareCreatesText.$_.$vFiler = @()
  [System.Array]$ShareAccessText.$_.$vFiler = @()
  $SpaceCreates = $SpaceAccess = 0
  Foreach($Vol in ($CifsCfg.$_.$vFiler.Volumes)){
   If($CutoverVols.$_.VOLs7 -contains $Vol){
    Foreach($Share in ($CifsCfg.$_.$vFiler.$Vol.Shares)){
     [String]$CifsCfg.$_.$vFiler.$Vol.$Share.CdotShareName = $Share
     If(!($SpecialShares -Contains $share)){
      [String]$newShare = $share
      [Boolean]$dollarShare = $false
      If($AppendFilerNameToShare){
       If($newShare.substring(($newShare.length -1),1) -eq "$"){
        $dollarShare = $true
        $newShare = $newShare.Substring(0,($newShare.length -1))
       }                                                           
       If($vFiler -eq "vFiler0"){
        $newShare = $newShare + "_" + $_
       }else{
        $newShare = $newShare + "_" + $vFiler
       }
       If($dollarShare){
        $newShare = $newShare + "$"
       }
       [String]$CifsCfg.$_.$vFiler.$Vol.$Share.CdotShareName = $newShare
      }
      If($CifsSharesSVM -Contains $newShare){
       [Boolean]$valid = $false
       [Boolean]$dollarShare = $false
       [Int]$append = 2                                                           
       while (!$valid){
        If($newShare.substring(($newShare.length -1),1) -eq "$"){
         $dollarShare = $TRUE
        }
        [String]$tempShare = $newShare
        If($dollarShare){
         $tempShare = $newShare.substring(0,($newShare.length-1))
        }
        $tempShare = $tempShare + "_" + [String]$append
        If($dollarShare){
         $tempShare += "$"
        }
        If(!($CifsSharesSVM -Contains $tempShare)){
         $valid = $true; $newShare = $tempShare
        }
        else{
         $append++
        }
       }                                                                  
       $ShareConflictsText.$_.$vFiler += ("# ++ WARNING ++ Share $share (from $_ vfiler $vFiler) already exists, we will rename to: $newShare ")
       $CifsSharesSVM += $newShare
       $CifsCfg.$_.$vFiler.$Vol.$Share.CdotShareName = $newShare   
      }else{
       $CifsSharesSVM += $share
      }
     
      ## SECTION: CIFS SHARE CREATES ##                                   
      $ShareName = $CifsCfg.$_.$vFiler.$Vol.$Share.CdotShareName
      [String]$newPath = "/"
      If($SlashVol){
       $newPath += "vol/"
      }                                     
      $newPath += ($MapVols.$_.$Vol + $CifsCfg.$_.$vFiler.$Vol.$Share.PathAfterVolume)
      $Comment = $CifsCfg.$_.$vFiler.$Vol.$Share.Comment
      If($Comment -ne ""){
       $comment = " -comment " + '"' + $comment + '"'
      }
      $ShareCreatesText.$_.$vFiler += ("vserver cifs share create -vserver_PLACEHOLDER -share-name " + '"' + $ShareName + '"' + " -path " + '"' + $newPath + '"' + $comment + " -share-properties $ShareProperties -symlink-properties $SymlinkProperties -offline-files $OfflineFiles -vscan-fileop-profile $VscanFileopProfile")
     
      $CdotShareCount.($MapVols.$_.$Vol) ++
      $SpaceCreates ++
      If($SpaceCreates -eq ($Spacing -1)){
       $SpaceCreates = 0
       $ShareCreatesText.$_.$vFiler += ""
      }
     
      ## SECTION: ACCESS RULES ##                                  
      [Boolean]$EveryoneFull = $false
      $ARULES = $CifsCfg.$_.$vFiler.$Vol.$Share.AccessRules                               
      [Int]$ARULE = 1
     
      while($ARULE -le $ARULES){                    
       $UserGroupSID = $CifsCfg.$_.$vFiler.$Vol.$Share.$ARULE.UserOrGroup
       $Permission   = $CifsCfg.$_.$vFiler.$Vol.$Share.$ARULE.Permission
      
       # Convert $UserGroupSID from SID (if it is), to User/Group
       If($UserGroupSID -eq "everyone"){
        $userGroupSID = "everyone"
       }elseif($userGroupSID -eq "S-NONE"){
        $userGroupSID = "everyone"
       }elseif(!$OnDomain){
        Foreach ($linePair in $SIDtoNameMap){
         $linePairSplit = $linePair.split(",")
         If($linePairSplit.count -eq 2){
          If($userGroupSID -eq $linePairSplit[0]){
           $userGroupSID = $linePairSplit[1]
          }
         }
        }                                                                                                               
       }else{
        $objSID = New-Object System.Security.Principal.SecurityIdentifier($userGroupSID)
        $objUser = $objSID.Translate([System.Security.Principal.NTAccount])
        If($objUser){
         $Global:SIDMapFileContent += $userGroupSID + "," + $objUser.Value
        }else{
         $Global:SIDMapFileContent += $userGroupSID + ",UNABLE_TO_TRANSLATE_SID"
        }
        # NB1: It doesn't matter if there are duplicates in the list.
        # NB2: $Global:SIDMapFileContent must come before the below lines.
        If($objUser){
         $userGroupSID = $objUser.Value
        }else{
         Wr ("# ++ WARNING ++ UNABLE TO TRANSLATE SID: $userGroupSID") RED;Wr
        }
       }
      
       # Convert 7MODE Permission to CDOT Permission
       If($permission -eq "No Access"){
        $permission = "No_access"
       }elseif($permission -eq '"emptydacl"'){
        $permission = "No_access"
       }elseif($permission -eq "Full Control"){
        $permission = "Full_control"
       }elseif($permission -eq '"nosd"'){
        $permission = "Full_control"
       }
       If(($UserGroupSID -eq "everyone") -and ($Permission -eq "Full_control")){
        $EveryoneFull = $True
       }
      
       If(!$EveryoneFull){
        If($UserGroupSID -ne "everyone"){
         $ShareAccessText.$_.$vFiler += ("vserver cifs share access-control create -vserver_PLACEHOLDER -share " + '"' + $ShareName + '"' + " -user-or-group " + '"' + $userGroupSID + '"' + " -permission $permission")
        }else{
         $ShareAccessText.$_.$vFiler += ("vserver cifs share access-control modify -vserver_PLACEHOLDER -share " + '"' + $ShareName + '"' + " -user-or-group " + '"' + $userGroupSID + '"' + " -permission $permission")
         $EveryoneFull = $True
        }
        $SpaceAccess ++
        If($SpaceAccess -eq ($Spacing -1)){
         $SpaceAccess = 0
         $ShareAccessText.$_.$vFiler += ""
        }
        $ACLsCount ++
       }
       $ARULE++
      }
      If(!$EveryoneFull){
       $ShareAccessText.$_.$vFiler += ("vserver cifs share access-control delete -vserver_PLACEHOLDER -share " + '"' + $ShareName + '"' + " -user-or-group Everyone")
       $SpaceAccess ++
       If($SpaceAccess -eq ($Spacing -1)){
        $SpaceAccess = 0
        $ShareAccessText.$_.$vFiler += ""
       }
      }else{
       $ACLsCount++
      }
     }
    }
   }
  }
 }     
}

FUNCTION OUTPUT-CifsShareCreate{
 Param([String]$ClusterName,[String]$SVMname)
 Uline ("## CIFS: SHARE CREATE AND ACCESS COMMANDS ##")
 ("# NB1: We ignore the 7-Mode default shares ETC$,HOME,C$ and OLDVOLUMENAME$ shares")
 ("# NB2: A CIFS share create automatically gives Everyone Full_control, we do not recreate this!")
 ("# Before starting please run the below:");("")
 Cshell; ("rows 0")
 ("cifs share access-control show -fields share -vserver $SVMname")
 ("# RECORD THE NUMBER OF ACLS ABOVE FOR LATER USE!");("")
 Foreach($7Gsystem in $Systems7G){
  Foreach($vFiler in $vFilerList.$7Gsystem.vFilers){
    ("## FOR $7Gsystem AND VFILER $vFiler ##");("")
    ($ShareConflictsText.$7Gsystem.$vFiler);("")
    Cshell
    Foreach($line in $ShareCreatesText.$7Gsystem.$vFiler){
     $line.replace("-vserver_PLACEHOLDER","-vserver $SVMname")
    };("")
    Cshell
    Foreach($line in $ShareAccessText.$7Gsystem.$vFiler){
     $line.replace("-vserver_PLACEHOLDER","-vserver $SVMname")
    };("")
  }
 }
 ("# TO VERIFY THE CORRECT NUMBER OF SHARES HAVE BEEN CREATED:");("")
 Cshell
 Foreach ($Vol in $CdotVolsArray){
  $ShareCount = $CdotShareCount.$Vol
  ("cifs share show -path *$Vol* -fields share-name -vserver $SVMname")
  ("# EXPECTED SHARES = $ShareCount");("")
 };("")
 ("# TO VERIFY THE CORRECT NUMBER OF ACLS EXIST:");("")
 Cshell
 ("cifs share access-control show -fields share -vserver $SVMname")
 ("# EXPECTED ADDITIONAL ACLS = $ACLsCount ");("")
}

####################
## PART 3: OUTPUT ##
####################

[System.Array]$Output = @()
$Output += Uline ("## CS7C: COMMANDS GENERATED " + (Get-Date -uformat %d%h%G) + " ##")
$Output += ("# CAVEAT UTILITOR! This tool comes with no support and no warranty, please REVIEW and SANITY CHECK!")
$Output += ("# '++ WARNING ++' indicates detected conflicts - search the output for these and review.")
$Output += ("# NB: Transition commands should be generated from the LATEST 7-Mode and CDOT information!"),("")
$Output += Uline ("## >>>>> COMMANDS TO APPLY CIFS SHARES <<<<< ##")
$Output += OUTPUT-CifsShareCreateVolumes $Cluster $SVM
$Output += OUTPUT-CifsShareCreate $Cluster $SVM
$Output | Set-Content $OutputFileName
Notepad $OutputFileName
If($OnDomain){
 $Global:SIDMapFileContent | Set-Content $SIDtoNameMapFilePath
}
Press-Enter



Comments