Managing Multiple cDOT Clusters with PowerShell

The following is a PowerShell Module I wrote to help manage multiple cDOT Clusters.
Save the script as Multi-NcCmdlets.psm1 into:

C:\Users\{USERNAME}\Documents\WindowsPowerShell\Modules\Multi-NcCmdlets

Then in PowerShell run:

Import-Module Multi-NcCmdlets -DisableNameChecking

Note: DisableNameChecking is only there because PowerShell likes verbs at the start of cmdlet names, and complains if you don’t use this convention.

You’ll need a text file with all the Cluster IPs/DNS entries in, then run these cmdlets -

Multi-NcClusters-Load
Multi-NcCredentials-Add
Multi-NcControllers-Connect

- and then we can manage multiple clusters with PowerShell with single commands!

There is a help output:

Multi-Help

And an example of something we can do -

Multi-Set-NcUserPassword-AdminSVM

- which allows changing a password for a user in the Admin SVM, across all connected clusters.

Time permitting, I’ll expand the list.

Note: The DataONTAP PowerShell Toolkit is a requirement.

The Script

###########################
## PART 1: Multi-Nc Core ##
###########################

Function Multi-Help{ [Void](Multi-NcCmdlets) }
Function Multi-NcCmdlets{
  Wr; Wr "+++++ Multi-NcCmdlets +++++" MAGENTA; Wr
  Wr; Wr "A selection of cmdlets to manage multiple clusters in one go!" CYAN; Wr
  Wr; Wr "1 " CYAN; Wr "Multi-NcClusters-Load" YELLOW; Wr ' ==> creates the $Global variable $NcClusterNames' GREEN
  Wr; Wr "2 " CYAN; Wr "Multi-NcCredentials-Add" YELLOW
  Wr; Wr "- " CYAN; Wr "Multi-NcCredentials-Remove" YELLOW
  Wr; Wr "3 " CYAN; Wr "Multi-NcControllers-Connect" YELLOW; Wr ' ==> creates the $Global variable $NcConnectedControllers' GREEN
  Wr; Wr "- " CYAN; Wr "Multi-NcControllers-Release" YELLOW; Wr
  Wr; Wr "Run 1 -> 2 -> 3, then we're ready to use Multi-* comdlets!" CYAN; Wr
  Wr; Wr "X " CYAN; Wr "Multi-Set-NcUserPassword-AdminSVM" YELLOW; Wr; Wr
}

Function Multi-NcClusters-Load {
  Param([String]$File)
  If(!(Get-Module DataONTAP)){
    [Void](Import-Module DataONTAP -ErrorAction SilentlyContinue)
    If( !(Get-Module DataONTAP) ){ Wr; Wr "Unable to load PSTK!" RED; Wr; Wr; RETURN }         
  }
  Wr; Wr "PSTK loaded ..." GREEN; Wr
  Wr; Wr "Loading file containing cluster management IPs/Name ..." CYAN; Wr; Wr
  [String]$File = PromptValidator -Prompt "Enter Filename/Filepath" -PreAnswer $File
  If(Test-Path $File){ [System.Array]$FileContent = Get-Content $File }
  Else{ Wr; Wr "Failed to load $File!" RED; Wr; Wr; RETURN }
  If($FileContent.count -eq 0){ Wr; Wr "No content in $File!" RED; Wr; Wr; RETURN }
  [System.Array]$Global:NcClusterNames = @()
  Foreach ($Line in $FileContent){
    $Line = $Line.Trim("`t"," ")
    If( !$Line.StartsWith("#") -and ($Line -ne "") ){
      $Global:NcClusterNames += $Line.Split("#")[0].Trim("`t"," ")
    }
  }
  If($Global:NcClusterNames.count -eq 0){ Wr; Wr "No valid content in $File!" RED; Wr; Wr; RETURN }
  Wr; Wr "Loaded $File ..." GREEN; Wr
  Wr; Wr 'PS> $NcClusterNames' CYAN; Wr; Wr
  $Global:NcClusterNames; Wr
}

Function Multi-NcCredentials-Remove{ [Void](Multi-NcCredentials-Add -Remove) }
Function Multi-NcCredentials-Add{
  Param([Switch]$Remove)
  If(!$Global:NcClusterNames){ Wr; Wr 'No $NcClusterNames - run Multi-NcClusters-Load!' RED; Wr; Wr; RETURN }
  If(!$Remove){ Wr; Wr 'Note: If there are existing stored NcCredentials for $NcClusterNames, they will be overwritten (can use Get-NcCredential to check)!' YELLOW; Wr; Wr }
  If(!$Remove){ [String]$UserName = PromptValidator -Prompt "Enter Username" }
  If(!$Remove){ Wr "Enter Password:" CYAN; $Password = Read-Host -AsSecureString }
  If(!$Remove){ $Credentials = New-Object System.Management.Automation.PsCredential($Username,$Password) }
  If(!$Remove){ $Global:NcClusterNames | Foreach{ [Void](Add-NcCredential -Controller $_ -Credential $Credentials) } }
  else{ $Global:NcClusterNames | Foreach{ [Void](Remove-NcCredential -Name $_ -ErrorAction SilentlyContinue) } }
  Wr; Wr "PS> (Get-NcCredential).Name" CYAN; Wr; Wr
  (Get-NcCredential).Name; Wr
}

Function Multi-NcControllers-Connect{
  If(!$Global:NcClusterNames){ Wr; Wr 'No $NcClusterNames - run Multi-NcClusters-Load!' RED; Wr; Wr; RETURN }
  [System.Array]$Global:NcConnectedControllers = @(); Wr
  Foreach($Controller in $Global:NcClusterNames){
    If( !(Get-NcCredential -Name $Controller) ){ Wr "No credentials for $Controller - run Multi-NcCredentials-Add!" RED; Wr }
    Else{
      $ConnectNcController = Connect-NcController -Name $Controller -Timeout 15000 -ErrorAction SilentlyContinue
      If($ConnectNcController){ $Global:NcConnectedControllers += $Controller }
      If($ConnectNcController){ Wr "Connected to $Controller!" GREEN; Wr }       
      Else{ Wr "Unable to connect to $Controller!" RED; Wr }
    }
  }
  $Global:CurrentNcController = $null
  Foreach($Controller in $Global:NcConnectedControllers){
    [Void](Connect-NcController -Name $Controller -Add -Timeout 15000 -ErrorAction SilentlyContinue)
  }
  Wr; Wr 'Connected to all $NcConnectedControllers below:' GREEN; Wr
  Wr 'PS> $CurrentNcController' CYAN; Wr
  $Global:CurrentNcController
}

Function Multi-NcControllers-Release{
  [System.Array]$Global:NcConnectedControllers = @()
  $Global:CurrentNcController = $null
}

Function Verify-NcConnectedControllers{
  If(!$Global:NcConnectedControllers){ Wr; Wr 'No $NcConnectedControllers - run Multi-NcControllers-Connect!' RED; Wr; Wr; RETURN $FALSE }
  [System.Array]$GlobalCurrentNccontrollerNames = ($Global:CurrentNcController).Name
  Foreach($Controller in $Global:NcConnectedControllers){
    If( !($GlobalCurrentNccontrollerNames -Contains $Controller) ){
      Wr; Wr 'Mismatch of $CurrentNcController v $NcConnectedControllers - re-run Multi-NcControllers-Connect!' RED; Wr; Wr; RETURN $FALSE
    }
  }
  RETURN $TRUE
}

Function Wr{
  Param([String]$Echo,[String]$Ink = "WHITE")
  If($Echo){ Write-Host $Echo -ForegroundColor $Ink -NoNewLine }
  Else { Write-Host }
}

Function PromptValidator{
  Param([String]$Prompt,[System.Array]$Answers,[String]$PreAnswer,[Switch]$CaseSensitive,[Switch]$AllowCR)
  While ($true){
    Wr ($Prompt + ":") CYAN
    If($PreAnswer){ Wr $PreAnswer; Wr; RETURN $PreAnswer }
    else{ $ReadIn = Read-Host }
    If($Answers -and  $CaseSensitive){ Foreach ($a in $Answers){ If($ReadIn -ceq $a){ RETURN $ReadIn } } }
    If($Answers -and !$CaseSensitive){ Foreach ($a in $Answers){ If($ReadIn -eq  $a){ RETURN $ReadIn } } }
    If(!$Answers -and ($ReadIn.length -gt 0) ){ RETURN $ReadIn }
    If($AllowCR  -and ($ReadIn.length -eq 0) ){ RETURN "" }
  }
}

##############################
## PART 2: Multi-Nc Add Ons ##
##############################

Function Multi-Set-NcUserPassword-AdminSVM{
  If( !(Verify-NcConnectedControllers) ){ RETURN }; Wr
  [String]$UserName = PromptValidator -Prompt "Enter user whose password is to be reset"
  Wr "Enter new password:" CYAN; $Password = Read-Host -AsSecureString
  $NewCred = New-Object System.Management.Automation.PsCredential($UserName,$Password)
  $VsAttrs = Get-NcVserver -Template
  $VsQuery = Get-NcVserver -Template
  $VsQuery.VserverType = "admin"; Wr    
  $Global:CurrentNcController | Foreach {
    $_.Vserver = (Get-NcVserver -Query $VsQuery -Attributes $VsAttrs -Controller $_)
    [System.Array]$GetUser = Get-NcUser -Name $Username -Controller $_ -ErrorAction SilentlyContinue
    If(!$GetUser){ Wr ("User $UserName does not exist on " + $_.Name + ":" + $_.Vserver + "!") RED; Wr }
    elseif($GetUser[0].AuthMethod -ne "password"){ Wr ("User $UserName is not password authenticated on " + $_.Name + ":" + $_.Vserver + "!") RED; Wr }
    else{
      [Void](Set-NcUserPassword -Credential $NewCred -Controller $_)
      Wr ("Ran Set-NcUserPassword for user $UserName on " + $_.Name + ":" + $_.Vserver + "!") GREEN; Wr
    }
  }; Wr
}


Comments