# encoding: ascii
# api: powershell
# title: CDOT-Check.ps1
# description: See www.cosonok.com and CDOT-Check.ps1
# version: 8.2
# type: script
# author: vCosonok
# license: CC0
# function: Pad-R
# x-poshcode-id: 5498
# x-archived: 2016-11-14T08:37:31
# x-published: 2016-10-09T10:01:00
#
#
##########################################################################
## CDOT-Check - V1 OCT '14 (For CDOT 8.2.X) ##
## ==================================================================== ##
## CAVEAT UTILITOR! This program comes with no warranty and no support! ##
################################################################################
## CONTENTS - This script can be broken down into the following sections: ##
## 1) (Generic) PowerShell Functions ##
## 2) (Generic) Data ONTAP PowerShell Toolkit Functions ##
## 3) CLUSTER CONNECT Set of Functions ##
## 4) HEALTH CHECK Set of Functions (ADD ADDITIONAL CHECKS HERE!) ##
## 5) GET/SAVE CONFIGURATION Set of Functions ##
## 6) DISPLAY-ALL Set of Functions (Used by GET-CONFIGURATION) ##
## 7) LOAD CLUSTERCFG Set of Functions ##
## 8) COMPARE-DATA Set of Functions ##
## 0) MAIN MENU ##
################################################################################
$title = "CDOT-Check - V1 OCT '14 (For CDOT 8.2.X)"
$TKmajor = 3; $TKminor = 1 # Recommended minimum DOT PSTK major.minor version
[String]$P = $null # Used to put text into some Wr-* Functions
$aggrUsedThreshold = 90 # % used threshold for health check (default)
$clusterCfg = New-Object 'object[,]' 2,3 # Define an array of 2 x 3 for 2 cluster configuration with filename, node count, data SVM count! (might make this global!)
$global:CfgContent = New-Object 'object[]' 2 # Use to store the Get-Content of the clustercfg files
$global:saveConfig = $null # Re-initialized in Get-Configuration as an array
$whoAmI = $env:username # The user running this script
$workingPath = $env:USERPROFILE # The users profile (used to save credentials) Note: Originally used (pwd).path
$defaultClusterCfgFolder = $workingPath + "\CLUSTERCFG" # Default folder for CLUSTERCFG files
$global:CompareA = @{}; $global:CompareB = @{} # Define hashtables for A&B compare options (CLUSTER=,CLUSTERFILE=,NODE=,NODEFILE=,SVM=,SVMFILE=)
# NEW CLUSTER/NODE/SVM CONFIGURATION CHECKS CAN BE ADDED HERE!
# These are the Get-Nc*'s we use to get configuration information from CLUSTERs/NODEs/SVMs
# Note 1: "$global:currentnccontroller.Vserver =" does not work with nodes - for this reason GetNcNODEs is a bit different
# Note 2: These variables are all used in "FN:GET-CONFIGURATION" and "FN:COMPARE-DATA" (supplied via parameter)
$GetNcCLUSTER = ("Get-NcCluster","Get-NcSnmp","Get-NcOption","Get-NcTimezone","Get-NcNetDns","Get-NcNetDnsHost","Get-NcConfigBackupURL","Get-NcConfigBackupCount","Get-NcLicense",
"Get-NcEmsConfig","Get-NcEmsDestination","Get-NcJobCronSchedule","Get-NcJobIntervalSchedule","Get-NcKerberosRealm",
"Get-NcNetOption","Get-NcNetRoutingGroupRoute","Get-NcNetInterface",
"Get-NcSnapmirrorPolicy","Get-NcSecurityCertificate","Get-NcSecuritySSL","Get-NcSnapshotPolicy")
$GetNcCLUSTERLR = ("Get-NcUser","Get-NcRoleConfig","Get-NcRole")
$GetNcNODE = ("Get-NcNode -Name","Get-NcSystemImage -Node","Get-NcServiceProcessor -Node","Get-NcOption -Vserver","Get-NcAutoSupportConfig -Node","Get-NcClusterHA","Get-NcVol -Vserver",
"Get-NcNetRoutingGroupRoute","Get-NcNetInterface -Vserver",
"Get-NcNetPort -Node","Get-NcNetPortIfgrp -Node","Get-NcNetPortVlan -Node",
"Get-NcAggrNodeInfo -Name","Get-NcSecurityCertificate -Vserver","Get-NcSecuritySSL -Vserver")
$GetNcAGGR = ("Get-NcAggr","Get-NcAggrOption")
$GetNcSVM = ("Get-NcVserver","Get-NcOption","Get-NcNetDns","Get-NcNetDnsHost","Get-NcFileServiceAudit","Get-NcFlexcachePolicy",
"Get-NcFpolicyStatus","Get-NcFpolicyPolicy","Get-NcFpolicyEvent",
"Get-NcKerberosConfig","Get-NcLdapConfig","Get-NcLdapClient",
"Get-NcNetRoutingGroupRoute","Get-NcNetInterface",
"Get-NcSnapmirrorPolicy","Get-NcSecurityCertificate","Get-NcSecuritySSL","Get-NcSisPolicy","Get-NcSnapshotPolicy")
$GetNcSVMLR = ("Get-NcUser","Get-NcRoleConfig","Get-NcRole")
$GetNcSVMCIFS = ("Get-NcCifsServer","Get-NcCifsPreferredDomainController","Get-NcGpo","Get-NcCifsOption","Get-NcCifsSecurity","Get-NcCifsHomeDirectorySearchPath",
"Get-NcCifsLocalUser","Get-NcCifsLocalGroup","Get-NcCifsLocalGroupMember","Get-NcCifsShareAcl","Get-NcCifsShare")
$GetNcSVMNFS = ("Get-NcNfsService","Get-NcNis",
"Get-NcNameMapping","Get-NcNameMappingUnixGroup","Get-NcNameMappingUnixUser",
"Get-NcExportPolicy","Get-NcExportRule","Get-NcNfsExport")
$GetNcSVMVOLUMES = ("Get-NcQtree","Get-NcQuota","Get-NcQuotaStatus",
"Get-NcSis","Get-NcSnapshotAutodelete","Get-NcSnapshotReserve",
"Get-NcVol","Get-NcVolAutosize","Get-NcVolLanguage","Get-NcVolOption")
$clusterConfigurations = $GetNcCLUSTER + $GetNcCLUSTERLR
$nodeConfigurations = $GetNcNODE + $GetNcAGGR
$SVMConfigurations = $GetNcSVM + $GetNcSVMLR + $GetNcSVMCIFS + $GetNcSVMNFS
################################################################################
## 1) (Generic) PowerShell Functions ##
################################################################################
Function Pad-R{ Param([string]$string, [int]$int=30)
$string.PadRight($int," ").SubString(0,$int) }
Function Pad-L{ Param([string]$in, [int]$padL=3, [string]$pad=" ")
$in.PadLeft($padL,$pad) }
Function Columnize-W{
$i = 0
while($i -lt $args.count){
Write-Host ((Pad-R $args[$i] $args[$i+1]) + " ") -F White -NoNewline
$i += 2 }; Write-Host}
Function Columnize-C{
$i = 0
while($i -lt $args.count){
Write-Host ((Pad-R $args[$i] $args[$i+1]) + " ") -F $args[$i+2] -NoNewline
$i += 3 }; Write-Host}
Function Wr-E{Write-Host}
Function Wr-C{If($args[0]){$P=$args[0]};Write-Host $P -F Cyan}
Function Wr-D{If($args[0]){$P=$args[0]};Write-Host $P -F DarkGray}
Function Wr-G{If($args[0]){$P=$args[0]};Write-Host $P -F Green}
Function Wr-M{If($args[0]){$P=$args[0]};Write-Host $P -F Magenta}
Function Wr-R{If($args[0]){$P=$args[0]};Write-Host $P -F Red}
Function Wr-W{If($args[0]){$P=$args[0]};Write-Host $P -F White}
Function Wr-Y{If($args[0]){$P=$args[0]};Write-Host $P -F Yellow}
Function Wn-C{If($args[0]){$P=$args[0]};Write-Host $P -F Cyan -NoNewline}
Function Wn-D{If($args[0]){$P=$args[0]};Write-Host $P -F DarkGray -NoNewline}
Function Wn-G{If($args[0]){$P=$args[0]};Write-Host $P -F Green -NoNewline}
Function Wn-R{If($args[0]){$P=$args[0]};Write-Host $P -F Red -NoNewline}
Function Wn-W{If($args[0]){$P=$args[0]};Write-Host $P -F White -NoNewline}
Function Wn-Y{If($args[0]){$P=$args[0]};Write-Host $P -F Yellow -NoNewline}
Function Rd-W{If($args){Write-Host ($args[0]) -F White -NoNewline}; return (Read-Host "?")}
Function Prompt-Keys{
Param([switch]$anykey)
If(!$anykey -and !$args[0]){ return $null }
If($args[0]){
If($args[0].count -ne 1){ $answers = $args[0] }
else { $answers = $args[0..(($args.count)-1)] } }
while($true){
$keyPress = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
$keyPress = $keyPress.character.ToString().ToUpper()
If($anyKey){return $keypress}
foreach($answer in $answers){
if($keyPress -eq $answer.ToUpper()){ return $keyPress } }
Write-Host " " -NoNewLine; Write-Host "`b" -NoNewLine } }
Function Prompt-Menu{
$question = $args[0]
If(($args[1].count) -ne 1){$answers = $args[1]}
else{$answers = $args[1..(($args.count)-1)]}
while($true){
$readIn = Read-Host "$question"
$readIn = $readIn.ToUpper()
foreach($answer in $answers){
if($readIn -eq $answer.ToUpper()){return $readIn} } } }
Function Set-Window{
Param([string]$textcolor,[string]$background,[string]$title,[int]$percentMax)
$window = (get-host).UI.RawUI
If($textcolor) {$window.ForegroundColor = $textcolor}
If($background -and ($window.BackgroundColor -ne $background)){
$window.BackgroundColor = $background;cls}
If($title) {$window.WindowTitle = $title}
$buffer = $window.BufferSize
$buffer.Height = 9999
$window.BufferSize = $buffer
If($perCentMax){
$maxX = [int](($window.MaxPhysicalWindowSize.Width)*$percentMax/100)
$maxY = [int](($window.MaxPhysicalWindowSize.Height)*$percentMax/100)
$buffer.Width = $maxX
$window.BufferSize = $buffer
$size = $window.WindowSize
$size.Width = $maxX
$size.Height = $maxY
$window.WindowSize = $size } }
Function Format-Units{
Param([int64]$raw,[string]$unit)
$unit = $unit.ToUpper()
If($unit -eq "GB"){return (([int64]($raw/(1024*1024*1024))).ToString() + " $unit")} }
Function Create-Folder {
If(!$args[0]){ return $null }
If(Test-Path $args[0] -ErrorAction SilentlyContinue){ return ($args[0]) }
Else {[Void](New-item $args[0] -type directory -ErrorAction SilentlyContinue)}
If(Test-Path $args[0] -ErrorAction SilentlyContinue){ return ($args[0]) }
Else { return $null } }
################################################################################
## 2) (Generic) Data ONTAP PowerShell Toolkit Functions ##
################################################################################
Function Check-PSTK{
if(!(Get-Module DataONTAP)){Import-Module DataONTAP -ErrorAction SilentlyContinue}
if(!(Get-Module DataONTAP)){return $null}
$true}
Function Check-PSTKversion{
Param($major,$minor)
$ver = Get-NaToolKitVersion
if($ver.major -lt $major){return $null}elseif($ver.major -gt $major){return $true}
if($ver.minor -lt $minor){return $null}
$true}
Function Current-Cluster {
If($global:currentnccontroller.name){ $ClusterName = (Get-NcCluster).ClusterName } else { return $null}
If($ClusterName){ return $ClusterName } else { Current-ClusterNull; return $null } }
Function Current-ClusterIP {$global:currentnccontroller.Address.IPAddressToString}
Function Current-ClusterNull{$global:currentnccontroller = $null}
Function Current-UserName {$global:currentnccontroller.Credentials.Username}
Function Current-Vserver {$global:currentnccontroller.Vserver}
Function Current-VserverSet {$global:currentnccontroller.Vserver = $args[0]}
Function Current-VserverNull{$global:currentnccontroller.Vserver = $null}
################################################################################
## 3) CLUSTER CONNECT Set of Functions ##
################################################################################
Function Cluster-Connect{
Wr-W ">>>>>>> Connect to Cluster"; Wr-E
while ($true) {
Wr-W "Enter Netbios/FQDN/IP of Cluster to connect to (or enter to return to MAIN MENU)?";Wr-E
$cluster = Read-Host; Wr-E
If(!$cluster){return}
$getCreds = Get-Creds; Wr-E
If($getCreds){return} } }
Function Get-Creds{
$filePath = $workingPath + "\" + $cluster + "-" + $whoAmI + ".cred"
Wn-W "Checking for credentials at ";Wr-C $filepath
$check = Test-Path $filePath
If (!$check){
Wr-Y "No saved credentials for $cluster detected!"; Wr-E
$PromptForCreds = Prompt-ForCreds
If($PromptForCreds){return $true} else {return $null}
} else {
$readFile = Get-Content $filePath
$rdUsername = $readFile[0] # Variable used in UseSavedCreds
$rdPassword = $readFile[1] # Variable used in UseSavedCreds
Wr-G "Saved credentials for $cluster detected with user $rdUsername!"; Wr-E
Wn-G "<<<<< Re-use credentials <Y/N>: "
$key = Prompt-Keys "Y" "N"; Wr-Y $key; Wr-E
If($key -eq "Y"){
$UseSavedCreds = Use-SavedCreds
If($UseSavedCreds) {return $true} else {return $null}}
If($key -eq "N"){
$PromptForCreds = Prompt-ForCreds
If($PromptForCreds){return $true} else {return $null}} } }
Function Prompt-ForCreds{
Wr-W "Enter username to connect to $cluster (or enter to return)?"; Wr-E
$username = Read-Host; Wr-E
If(!$username){return $null}
Wr-W "Enter the password (or enter to return)?"; Wr-E
$securePassword = Read-Host -AsSecureString; Wr-E
If($securePassword.length -eq 0){return $null}
$password = $securePassword | ConvertFrom-SecureString
$credential = New-Object System.Management.Automation.PsCredential($username,$securePassword)
$connect = Connect-NcController $cluster -Credential $credential -ErrorAction SilentlyContinue
If($connect){
Wn-G "Connected!"; Wn-W " Saved credentials to "; Wr-C $filePath
[Void](New-Item $filePath -Type file -Force)
$username,$password | Set-Content $filePath
return $true
} else {
Wr-R "Failed to connect!"
return $null } }
Function Use-SavedCreds{
$securePassword = $rdPassword | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($rdUsername,$securePassword)
$connect = Connect-NcController $cluster -Credential $credential -ErrorAction SilentlyContinue
If($connect){Wr-G "Connected!";return $true} else {Wr-R "Failed to connect!";return $false}}
################################################################################
## 4) HEALTH CHECK Set of Functions (ADD MORE HEALTH CHECKS HERE) ##
################################################################################
Function Check-Health{
$nodes = Get-NcNode # Used with node checks ($node is available to functions)
$SVMquery = Get-NcVserver -Template
$SVMquery.VserverType = "data"
$dataSVMs = Get-NcVserver -Query $SVMquery # Data SVMs
$cifsServers = 0 # Count later
$nfsServers = 0 # Count later
Wr-W ">>>>> Get-NcDiagnosisSubsystem Checks"; Wr-E
Display-HC (get-ncdiagnosissubsystem cifs_ndo) $cCluster "health" "ok"
Display-HC (get-ncdiagnosissubsystem sas_connect) $cCluster "health" "ok"
Display-HC (get-ncdiagnosissubsystem switch_health) $cCluster "health" "ok"; Wr-E
Wr-W ">>>>> Get-NcNode Checks"; Wr-E
$nodes | foreach {Check-Nodes $_ 24} # Uptime > 24 hours
Wr-W ">>>>> Get-NcAutoSupportConfig Checks"; Wr-E
$nodes | foreach {Check-ASUP ($_.node)}; Wr-E
Wr-W ">>>>> Get-NcAutoSupportHistory Checks"; Wr-E
$nodes | foreach {Check-AsupSent ($_.node)}; Wr-E
Wr-W ">>>>> Get-NcNetPort Checks"; Wr-E
$nodes | foreach {Check-Ports ($_.node)}
Wr-W ">>>>> Get-NcAggr Checks"; Wr-E
$nodes | foreach {Check-Aggrs $_}
Wr-W ">>>>> Get-NcEmsMessage Checks"; Wr-E
$nodes | foreach {Check-EventLog ($_.node) 24} # Check events in last 24 hours!
Wr-W ">>>>> Get-NcVserver Checks"; Wr-E
$dataSVMs | foreach {Check-DataSVMs $_}; Wr-E
Wr-W ">>>>> Get-NcCifs Checks"; Wr-E
$dataSVMs | foreach {If(($_.AllowedProtocols).Contains("cifs")){$cifsServers++;Check-CIFS ($_.Vserver)}}
If($countCifsServers -eq 0){Wr-C "No CIFS enabled SVMs!"}; Wr-E
Wr-W ">>>>> Get-NcNfsService Checks"; Wr-E
$dataSVMs | foreach {If(($_.AllowedProtocols).Contains("nfs")){$nfsServers++;Check-NFS ($_.Vserver)}}
If($nfsServers -eq 0){Wr-C "No NFS enabled SVMs!"}; Wr-E
}
Function Display-HC { # Display-HC is used to display Health Checks with different conditions! #
Param(
$thingToDot,$toDisplay,$member,$greenResult,$memberOverride,$resultOverride,
[switch]$lt,[switch]$gt,[switch]$ni,[switch]$ct,[switch]$pass,[switch]$failY)
$result = $thingToDot.$member
If($resultOverride){$outResult = " = " + $resultOverride} else {$outResult = " = " + $result}
If($memberOverride){$outString = (Pad-R ($toDisplay + "." + $memberOverride) 40) + $outResult}
else {$outString = (Pad-R ($toDisplay + "." + $member) 40) + $outResult}
$P = $outString # The complete output ($P feeds into Wr-* functions)
If($lt) {If($result -lt $greenResult) {Wr-G} else {Wr-R}; return} # Green is result Less Than greenResult
If($gt) {If($result -gt $greenResult) {Wr-G} else {Wr-R}; return} # Green is result Greater Than greenResult
If($ni) {If(!$result) {Wr-G} else {Wr-R}; return} # Green is the null result
If($ct) {If($result.contains($greenResult)){Wr-G} else {Wr-R}; return} # Green if it contains the greenResult
If($pass) {Wr-G ; return} # No checking, returns in green
If($failY) {Wr-Y ; return} # No checking, returns in yellow
If(!$greenResult) {Wr-C ; return} # If no $greenresult parameter out with WrC
If($result -eq $greenResult) {Wr-G} else {Wr-R} # Standard check
}
Function Check-Nodes {
Param($node,[int]$hoursUp = 24)
$nodeName = $node.Node
$secondsUptime = $hoursUp*60*60
Display-HC $node $nodeName "IsNodeHealthy" "true"
Display-HC $node $nodeName "NodeUptime" $secondsUptime -gt
Display-HC $node $nodeName "EnvFailedFanCount" "0"
Display-HC $node $nodeName "EnvFailedPowerSupplyCount" "0"
Display-HC $node $nodeName "EnvOverTemperature" -ni
Display-HC $node $nodeName "NvramBatteryStatus" "battery_ok"
Display-HC $node $nodeName "IsEpsilonNode"
Display-HC $node $nodeName "IsNodeClusterEligible" "true"
Wr-E}
function Check-ASUP {
Param([string]$nodeName)
$attributes = Get-NcAutoSupportConfig -Template
$attributes.IsEnabled = ""
$attributes.IsSupportEnabled = ""
$getAsupConf = Get-NcAutoSupportConfig -Node $nodeName -Attributes $attributes
Display-HC $getAsupConf $nodeName "IsEnabled" "true"
Display-HC $getAsupConf $nodeName "IsSupportEnabled" "true"}
function Check-AsupSent {
Param([string]$nodeName)
$outString = (Pad-R ($nodeName + ".ASUP Sent Successfully") 40) + " =" # Define display out string
$attributes = Get-NcAutoSupportConfig -Template # Get-NcAutoSupportConfig: Template
$attributes.Transport = "" # Get-NcAutoSupportConfig: Transport = "" (Attribute)
$getAsupConf = Get-NcAutoSupportConfig -Node $nodeName -Attributes $attributes # Get-NcAutoSupportConfig <<<
$transport = $getAsupConf.transport # Get ASUP Transport
If ($transport -eq "https"){ $transport = "http"} # Get-NcAutoSupportHistory 'Destination' is smtp/http/noteto only!
$attributes = Get-NcAutoSupportHistory -Template # Get-NcAutoSupportHistory: Template for Attributes
$attributes.Status = "" # Get-NcAutoSupportHistory: Status = "" (Attribute)
$query = Get-NcAutoSupportHistory -Template # Get-NcAutoSupportHistory: Template for Queries
$query.Destination = $transport # Get-NcAutoSupportHistory: Destination = $transport (Query)
$query.NodeName = $nodeName # Get-NcAutoSupportHistory: Node = $nodeName (Query)
$getAsupHistory = Get-NcAutoSupportHistory -Attributes $attributes -Query $query # Get-NcAutoSupportHistory <<<
$asupHistoryCount = $getAsupHistory.count # Count the rows of ASUP History
if ($asupHistoryCount -eq 0){ Wr-R "$outString No ASUP History!"; return} # If no ASUP History, report this, and return!
$i = 0
while ($i -lt $asupHistoryCount) { ## Cycle through ASUP History ##
if ($getAsupHistory[$i].status -eq "transmission_failed"){Wr-R "$outString Failed!"; return}
if ($getAsupHistory[$i].status -eq "sent-successful"){ Wr-R "$outString Sent Successful!"; return}
$i++}
Wr-R "$outString Failed!"
}
Function Check-Ports{
Param([string]$nodeName)
$ncNetPort = Get-NcNetPort -Node $nodeName
$ncNetPort | foreach {
$port = $_.Port
$adminUp = $_.IsAdministrativeUp
$link = $_.LinkStatus
$nodePort = "$nodeName" + ":" + "$port"
$P = "$nodePort.LinkStatus = $link (and IsAdminUp = $adminUp)";If($adminUp -and ($link -eq "up")){Wr-G}else{Wr-R}
Display-HC $_ $port "OperationalDuplex" "full"
Display-HC $_ $port "AdministrativeDuplex" "full"
Display-HC $_ $port "OperationalFlowcontrol" "none"
Display-HC $_ $port "AdministrativeFlowcontrol" "none"
Display-HC $_ $port "OperationalSpeed"
Display-HC $_ $port "AdministrativeSpeed" "auto"
Display-HC $_ $port "IsOperationalAutoNegotiate" "True"
Display-HC $_ $port "IsAdministrativeAutoNegotiate" "True"
Display-HC $_ $port "Mtu"
Wr-E}}
Function Check-Aggrs{
Param($node)
$volCount = 0
$nodename = $node.Node
$maxAggrSize = $node.MaximumAggregateSize
$maxAggrSizeDisplay = Format-Units $maxAggrSize GB
$maxAggrSizeThreshold = $maxAggrSize*0.95
$NcAggrQuery = Get-NcAggr -Template
$NcAggrQuery.Nodes = $nodename
$aggrs = Get-NcAggr -Query $NcAggrQuery
$aggrs | foreach {
$root = $false
$aggrname = $_.name
Display-HC $_ $aggrname "state" "online"
Display-HC $_ $aggrname "RaidType" "normal" -ct
Display-HC ($_.AggrOwnershipAttributes) $aggrname "HomeName" ($_.AggrOwnershipAttributes.OwnerName)
If($_.AggrRaidAttributes.HasLocalRoot){Display-HC ($_.AggrRaidAttributes) $aggrname "HasLocalRoot";$root = $true}
$modulo = ($_.Disks) % ($_.RaidSize)
If(!$root -and ($modulo -eq 0)){
Display-HC $_ $aggrname "Disks" -Pass
Display-HC $_ $aggrname "RaidSize" -Pass
} elseif (!$root -and ($modulo -ne 0)) {
Display-HC $_ $aggrname "Disks" -FailY
Display-HC $_ $aggrname "RaidSize" -FailY
}
Display-HC $_ $aggrname "used" $aggrUsedThreshold "UsedPercent" -lt
Display-HC $_ $aggrname "TotalSize" $maxAggrSizeThreshold "TotalSize (max = $maxAggrSizeDisplay)" -r (Format-Units $_.TotalSize GB) -lt
Display-HC ($_.AggrSnapshotAttributes) $aggrname "SizeUsed" "0" "SnapshotSpaceUsed"
Display-HC ($_.AggrSnapshotAttributes) $aggrname "SnapshotReservePercent" "0"
Display-HC ($_.AggrPerformanceAttributes) $aggrname "FreeSpaceRealloc"
Wr-E
$volCount += $_.volumes
} # END $aggrs
$maxVols = $_.MaximumNumberOfVolumes
$maxVolTH = $maxVols*0.95
$P = "$nodename has $volCount volumes from a maximum of $maxVols!";If ($volCount -lt $maxVolTH){Wr-G} else {Wr-R}
Wr-E
}
Function Check-EventLog{
Param([string]$nodeName,[int]$hours = 24)
$attributes = Get-NcEmsMessage -Template
$attributes.Event = ""
$attributes.Node = ""
$attributes.Time = ""
$severityList = "EMERGENCY","R","ALERT","R","CRITICAL","R","ERROR","Y","WARNING","Y"
$sevListCount = $severityList.count
$i = 0
$uniqueMessages = New-Object 'object[]' 5 # 5 severities
while ($i -lt $sevListCount) {
$severity = $severityList[$i]
$colour = $severityList[$i+1]
$ems = Get-NcEmsMessage -Severity $severity -StartTime (Get-Date).AddHours(-$hours) -Attributes $attributes -Node $nodeName
$emsCount = $ems.count
$P = "$nodeName has $emsCount events for type $severity in the last $hours hours!"; If($emsCount -eq 0){Wr-G} elseif($colour -eq "R"){Wr-R} else{Wr-Y}
$uniqueMessages[$i/2] = Check-EventLogUniqueMessages
$i+=2
}
Wr-E
$i = 0
while ($i -lt $sevListCount) {
$uniqueMessageTable = $uniqueMessages[$i/2]
$uniqueMessageCount = $uniqueMessageTable.count
If ($uniqueMessageCount -ne 0){
$colour = $severityList[$i+1]
Wr-W ("$nodeName occurrences of unique " + $severityList[$i] + " events in the last $hours hours >")
Columnize-W "Count" 5 "Last Occurrence" 20 "Event" 80
$y = 0
while ($y -lt $uniqueMessageCount) {
Columnize-C $uniqueMessageTable[3,$y] 5 $colour $uniqueMessageTable[0,$y] 20 $colour $uniqueMessageTable[2,$y] 80 $colour
$y++
If(!$uniqueMessageTable[0,$y]){$y = $uniqueMessageCount}
}
Wr-E
}
$i+=2
}
}
Function Check-EventLogUniqueMessages {
$outputArray = New-Object 'object[,]' 4,$emsCount
$arrayYsize = 0
foreach ($message in $ems){
$match = Check-EventLogMessageMatch
if (!$match){
$outputArray[0,$arrayYsize]=$message.TimeDT
$outputArray[1,$arrayYsize]=$message.Node
$outputArray[2,$arrayYsize]=$message.Event
$outputArray[3,$arrayYsize]=1
$arrayYsize++
}
} # END of foreach ($message in $messages)
, $outputArray
}
Function Check-EventLogMessageMatch{
$j=0
while ($j -lt $arrayYsize){ # NOTE SURE why the -1
if ($message.Event -eq $outputArray[2,$j]){
$outputArray[3,$j]++ # Accumulate the counter
return $true # Have found a match - stop checking!
}
$j++
}
return $false
}
Function Check-DataSVMs {
Param($dataSVM)
Display-HC $dataSVM ($dataSVM.Vserver) "State" "running"}
Function Check-CIFS {
Param([string]$currentVserver)
Current-VserverSet $currentVserver
$getCifsServer = Get-NcCifsServer
If (!$getCifsServer){Wr-R "$currentVserver has CIFS allowed but no CIFS server created!"; Current-VserverNull; return}
$cifsServer = $getCifsServer.CifsServer
Display-HC $getCifsServer $cifsServer "AdministrativeStatus" "up"
Current-VserverNull}
Function Check-NFS{
Param([string]$currentVserver)
Current-VserverSet $currentVserver
$getNfsService = Get-NcNfsService
If (!$getNfsService){Wr-R "$currentVserver has NFS allowed but no NFS server created!"; Current-VserverNull; return}
Display-HC $getNfsService $currentVserver "GeneralAccess" "True"
Current-VserverNull}
################################################################################
## 5) GET/SAVE CONFIGURATION Set of Functions ##
###################################################################################
# For saving configurations, the txt file has headers and footers like the below: #
# #START#WHAT-TYPE-OF-CONFIGURATION(CLUSTER/NODE/SVM)#ENTITY-NAME#GET-? #
# #FINIR#WHAT-TYPE-OF-CONFIGURATION(CLUSTER/NODE/SVM)#ENTITY-NAME#GET-? #
###################################################################################
Function Get-Configuration {
$nodes = (Get-NcNode).Node # NODE: Get list of Node Names
$query = Get-NcVserver -Template # SVM: Template for Get-NcVserver
$query.VserverType = "data" # SVM: Query for "data" Vservers
$dataSVMs = (Get-NcVserver -Query $query).Vserver # SVM: Get list of Data SVMs Names
# Initialize the content for the clustercfg file
$saveConfig = @() # The configuration is saved into this array
$saveConfig += "$cCluster" # First row [0] of $saveConfig = Cluster Name
[string]$listOfNodes = "";$nodes | foreach {$listOfNodes += $_ + ","}
$saveConfig += $listOfNodes # Second row [1] of $saveConfig = List of Nodes (separated by ,)
$saveConfig += ($nodes.count) # Third row [2] of $saveConfig = nodes count
[string]$listOfSVMs = "";$dataSVMs | foreach {$listOfSVMs += $_ + ","}
$saveConfig += $listOfSVMs # Fourth row [3] of $saveConfig = List of SVMs (separated by ,)
$saveConfig += ($dataSVMs.count) # Fifth row [4] of $saveConfig = Data SVMs count
## >> CLUSTER Configurations << ##
foreach ($getNc in $clusterConfigurations){
Get-CFGwDisplayAll CLUSTER $cCluster $getNc }
## >> NODE Configurations << ##
foreach ($getNc in $GetNcNODE){
foreach ($node in $nodes){
Get-CFGwDisplayAll NODE $node $getNc } }
## >> AGGREGATE Configurations (still NODE entity type) << ##
$attributes = Get-NcAggr -template
$query = Get-NcAggr -template
Initialize-NcObjectProperty -object $query -name AggrOwnershipAttributes
foreach ($getNc in $GetNcAGGR){
foreach ($node in $nodes){
Wn-W ">>>>> NODE: "; Wr-C $node
Wn-W ">>>>> Configuration: "; Wr-C $getNc; Wr-E
$saveConfig += "#START#NODE#$node#$getNc"
$query.AggrOwnershipAttributes.OwnerName = $node
$aggrs = (Get-NcAggr -Attributes $attributes -Query $query).Name | sort
$lastAggr = $aggrs[$aggrs.count-1]
foreach ($aggr in $aggrs){
$aggrHeader = "AGGREGATE".PadRight(30," ") + " = " + $aggr
Display-CI $aggrHeader
$cmdToDisplayAll = $getNc + " -Name " + $aggr
$output = Display-All $cmdToDisplayAll -All
$output | foreach {Display-CI $_}
If($aggr -ne $lastAggr) { Display-CI " " }
}
$saveConfig += "#FINIR#NODE#$node#$getNc"
Wr-E
}
}
## >> SVM Configurations << ##
foreach ($getNc in $SVMConfigurations){
foreach ($dataSVM in $dataSVMs){
Get-CFGwDisplayAll SVM $dataSVM $getNc } }
## >> VOLUMES Configurations (still SVM entity type) << ##
$attributes = Get-NcVol -template
foreach ($getNc in $GetNcSVMVOLUMES){
foreach ($dataSVM in $dataSVMs){
Current-VserverSet $dataSVM
Wn-W ">>>>> SVM: "; Wr-C $dataSVM
Wn-W ">>>>> Configuration: "; Wr-C $getNc; Wr-E
$saveConfig += "#START#SVM#$dataSVM#$getNc"
$volumes = (Get-NcVol -Attributes $attributes).Name | sort
$lastVol = $volumes[$volumes.count-1]
If (($getNc -eq "Get-NcVolOption") -or ($getNc -eq "Get-NcVolLanguage") -or ($getNc -eq "Get-NcVolAutoSize"))
{ $switchParam = " -Name " } else { $switchParam = " -Volume " }
foreach ($volume in $volumes) {
$volHeader = "VOLUME".PadRight(30," ") + " = " + $volume
Display-CI $volHeader
$cmdToDisplayAll = $getNc + $switchParam + $volume
$output = Display-All $cmdToDisplayAll -All
$output | foreach {Display-CI $_}
If($volume -ne $lastVol) { Display-CI " " }
}
$saveConfig += "#FINIR#SVM#$dataSVM#$getNc"
Wr-E
}
}; Current-VserverNull
}
Function Display-CI { Param($member); $saveConfig += $member; Wr-C $member }
Function Get-CFGwDisplayAll { # NOTE: Only used with CLUSTER/NODE/SVM above (and not AGGRS in NODEs, and VOLS in SVMs)!
Param($EntityType,$SVMname,$GetNcCommand)
If ($EntityType -ne "NODE") { # IF "!NODE"
Current-VserverSet $SVMname # . Current-VserverSet (does not work with anything "NODE")
$cmdToDisplayAll = $GetNcCommand # . STANDARD $cmdToDisplayAll
} elseif ( $GetNcCommand -eq "Get-NcClusterHA" ){ # OVERRIDE for "Get-NcClusterHA"
$cmdToDisplayAll = "(Get-NcClusterHa -Node $SVMName).SfOptions" # . CUSTOM SHOW just .SfOptions
} else { $cmdToDisplayAll = $GetNcCommand + " " + $SVMName} # If "NODE" add NODENAME to $GetNcCommand
$output = Display-All $cmdToDisplayAll -All
$EntityDisplay = ($EntityType + ":").PadRight(14)
Wn-W ">>>>> $EntityDisplay ";Wr-C $SVMname
Wn-W ">>>>> Configuration: ";Wr-C $cmdToDisplayAll; Wr-E
$saveConfig += "#START#$EntityType#$SVMname#$GetNcCommand"
$output | foreach {Display-CI $_}
$saveConfig += "#FINIR#$EntityType#$SVMname#$GetNcCommand"
Current-VserverNull; Wr-E }
Function Save-Configuration{
Wr-W ">>>>>>> Save Configuration";Wr-E
$dateString = Get-Date -uformat "%Y%m%d"
Wn-W "Current folder for clustercfg files = "; Wr-C $clusterCfgFolder
Wn-W "Default filename = "; Wr-C "$cCluster.$dateString.clustercfg"; Wr-E
Wn-G "<<<<< Use default filename <Y/N>: "
$key = Prompt-Keys "Y" "N"; Wr-Y $key; Wr-E
If ($key -eq "Y"){$saveFile = "$clusterCfgFolder\$cCluster.$dateString.clustercfg"}
If ($key -eq "N"){
$filename = Read-Host "Enter filename (.clustercfg is added)?";Wr-E
If(!$filename){return}
$saveFile = "$clusterCfgFolder\$filename.clustercfg"
}
[Void](New-Item $saveFile -Type file -Force)
Get-Configuration
$saveConfig | Out-File $saveFile
}
################################################################################
## 6) DISPLAY-ALL Set of Functions (Used by GET-CONFIGURATION) ##
################################################################################
Function Display-All {
Param($getCmd,[int]$padR = 30,[switch]$all = $null)
If(!$getCmd) { return }
If($getCmd.gettype().name -eq "String"){$parsedCmd = Invoke-Expression $getCmd}
else {$parsedCmd = $getCmd}
If(!$parsedCmd){ return }
$parsedCmdCount = $parsedCmd.count
If( ($parsedCmd.Name.count -ge 1) -and # Override for Name - Value pairs
($parsedCmd.Name.count -eq $parsedCmd.Value.count) ) # As an example, this is required for:
{ Display-AllNameValuePairs } # Get-NcOption
elseif ($parsedCmdCount -eq 1) { Display-AllMembers $parsedCmd} # If $parsedCmdCount = 1, it is not an array
else { # ... otherwise it is an array
$count = 0 # To count where in the array
$parsedCmd | foreach { # Cycle through the array $parsedCmd
Display-AllMembers $_ # Invoke Display-AllMembers
$count++ # Accumulate count of where in the array
If ($count -ne $parsedCmdCount){" "} } } } # Adds a space between array items (but not after the last)
Function Display-AllNameValuePairs{
$parsedCmd | foreach { ($_.Name).PadRight($padR," ").SubString(0,$padR) + " = " + ($_.Value) } }
Function Display-AllMembers{
Param($element,[int]$padL=1)
($element|gm) | foreach{Member-Data $element $_} }
Function Member-Data {
Param($element,$member)
If($member.MemberType -eq "Method"){return}
$name = $member.Name
$checks = "Specified","NcController","Vserver","VserverName","VserverType","PublicCertificate"
foreach($check in $checks){If($name.Contains($check)){return}}
$data = $element.$name
$padding = $name.length + $padL
$output = $name.PadLeft($padding,".").PadRight($padR," ").SubString(0,$padR) + " = " + $data
If (!$data){If($all){return $output}else{return}}
$checks = "bool","string[]","NcController","System.Object"
foreach($check in $checks){If($member.Definition.Contains($check)){return $output}}
$checks = "String","Boolean","TimeSpan","DateTime","Int32","Int64"
foreach($check in $checks){If($data.gettype().name -eq $check){return $output}}
If (($data|gm).count -eq 0){return $output}
$name.PadLeft($padding,".");$padL++
$output = Display-AllMembers $data $padL
return $output}
################################################################################
## 7) LOAD CLUSTERCFG Set of Functions ##
################################################################################
Function Set-ClusterCFGFolder{
Wr-W "Enter folder/folderpath for clustercfg files?"; Wr-E
$readIn = Read-Host; Wr-E
$testCreate = Create-Folder $readIn
If (!$testCreate){Wr-R "Failed to create folder!"; Wr-E; return $clusterCfgFolder} # If fails to create, we return the original $clusterCfgFolder
else {return $readIn} # Otherwise we return the new clustercfg folder
}
Function Load-ClusterCfg {
Param([int]$fileNumber)
Wr-W ">>>>>>> Load ClusterCfg File"; Wr-E
Wn-W "Folder/folderpath for clustercfg files = "; Wr-C $clusterCfgFolder
$items = Get-ChildItem -Path $clusterCfgFolder
$searchString = "*.clustercfg"
# Note: -like will only return true and not the list of matches if the array is only 1 in size
If ( $items.count -eq 0) { Wr-R "No *.clustercfg files in this folder!"; Wr-E; return $null}
elseif (($items.count -eq 1) -and ($items.name -like $searchString)) { $matches = @(); $matches += $items.name } # Makes $matches to be an array with 1 item
else { $matches = $items -like $searchString }
If (!$matches) { Wr-R "No *.clustercfg files in this folder!"; Wr-E; return $null}
Wr-E; Wr-W "Clustercfg Files in this Directory:"; Wr-E
$i = 1
$promptOptions = @()
$promptOptions += "0"
Wr-W " 0) Unload clustercfg file and/or Return to Main Menu"
$matches | foreach{
$promptOptions += ($i.toString())
$display = Pad-L ($i.toString())
Wr-C "$display) $_"
$i++
}; Wr-E
$answer = Prompt-Menu "Choose clustercfg file to load (or 0)?" $promptOptions
Unload-ClusterCfg # We unload the clustercfg for this filenumber prior to reloading it below
If($answer -eq "0"){ Wr-E; return} # If 0 is chosen return (clustercfgfile unloaded)
$chosenFilename = $matches[([Int]$answer) -1] # We allow chosing the same clustercfg file twice! (for checking script functionality)
$content = Get-Content ($clusterCfgFolder + "\" + $chosenFilename) -ErrorAction SilentlyContinue
If(!$content){ Wr-E; Wr-R "Unable to load file!"; Wr-E; return}
$clusterCfg[$fileNumber,0] = $chosenFilename
$clusterCfg[$fileNumber,1] = $content[2] # Count of nodes is on line 3 of the clustercfg file
$clusterCfg[$fileNumber,2] = $content[4] # Count of SVMs is on line 5 of the clustercfg file
$CfgContent[$fileNumber] = $content
If($fileNumber -eq 0){ $CompareA.CLUSTER = $content[0]; $CompareA.CLUSTERFILE = 0} # Automatically sets Compare A and B for clusters
If($fileNumber -eq 1){ $CompareB.CLUSTER = $content[0]; $CompareB.CLUSTERFILE = 1} # since only one cluster per config file with name at row 1 (0 for array)
Wr-E
}
Function Unload-ClusterCfg {
$clusterCfg[$fileNumber,0] = $clusterCfg[$fileNumber,1] = $clusterCfg[$fileNumber,2] = $null
If($CompareA.CLUSTERFILE -eq $fileNumber){$CompareA.CLUSTER = $null}
If($CompareB.CLUSTERFILE -eq $fileNumber){$CompareB.CLUSTER = $null}
# Reset $CompareA/B.NODE/SVM if they were taken from the config file number which we've now reloaded
# . or if there was previously only 1 config file loaded, and CompareA/B NODE/SVM pairs got autoselected!
If(($CompareA.NODEFILE -eq $fileNumber) -or ($cfgFiles -eq 1)){$CompareA.NODE = $null}
If(($CompareB.NODEFILE -eq $fileNumber) -or ($cfgFiles -eq 1)){$CompareB.NODE = $null}
If(($CompareA.SVMFILE -eq $fileNumber ) -or ($cfgFiles -eq 1)){$CompareA.SVM = $null}
If(($CompareB.SVMFILE -eq $fileNumber ) -or ($cfgFiles -eq 1)){$CompareB.SVM = $null}
}
################################################################################
## 8) COMPARE-DATA Set of Functions ##
################################################################################
Function Select-PairToCompare{
Param([string]$EntityType)
# $itemsMenu is an array with X x 3, the 3 are the columns - ENTITY, cluster, clustercfg file number
If ($EntityType -eq "NODE"){ $itemsMenu = New-Object 'object[,]' $cfgNodeCount,3 ; $rowInCfgFile = 1} # Menu of NODEs / row (-1) in cfg file with list of NODEs
If ($EntityType -eq "SVM") { $itemsMenu = New-Object 'object[,]' $cfgSVMCount,3 ; $rowInCfgFile = 3} # Menu of SVMs / row (-1) in cfg file with list of SVMs
$x = 0 # The ITEM number in the complete list of ITEMs
0,1 | foreach { # -------------------------------------------- # There's only 2 config files - 0 & 1
If($global:CfgContent[$_]){ # .Checking there is some content!
$items = $CfgContent[$_][$rowInCfgFile].split(",") # .. we get clustercfg row with the NODE/SVMS in and split it
$itemCount = $items.count -1 # .. count is one less than the split (because of trailing ",")
$j = 0 # .. The ITEM in the list of ITEMs for that config file
while ($j -lt $itemCount){ # .. LOOP items in the clustercfg file
$itemsMenu[$x,0] = $items[$j] # ... item $j (NODE/SVM) from the clustercfg file (COLUMN 2 in table below) ENTITY
$itemsMenu[$x,1] = $CfgContent[$_][0] # ... get CLUSTER from line 0 of clustercfg file (COLUMN 3 in table below) CLUSTER
$itemsMenu[$x,2] = $_ # ... clustercfg file number (COLUMN 4 in table below) CLUSTERCFGFILE
$x++ ; $j++ } } } # ------------------------------ # ... accumulate total number of ITEMs / accumulate item in the current clustercfg
Columnize-W "Menu Option" 20 "$EntityType Name" 20 "Cluster Name" 20 "Config File Number" 20
Columnize-C "0" 20 Yellow "<Return to Main Menu>" 25 Cyan
$r = 0 # r for rows (must use $r because Columnize uses $i)
$menuOptions = @() # Define Menu Options Array
$menuOptions += "0" # Add option 0
while ($r -lt $x){ # ---------------- # START: WHILE: r < x (total number of ITEMs in the loaded config files from above)
$option = ($r+1).ToString() # Put option in string form (COLUMN 1 in table below)
$menuOptions += $option # Accumulate Menu Options Array
Columnize-C $option 20 Yellow ($itemsMenu[$r,0]) 20 Green ($itemsMenu[$r,1]) 20 Cyan ($itemsMenu[$r,2].ToString()) 20 Cyan
$r++ # Accumulate r (ITEM in ITEMs Menu)
}; Wr-E # --------------------------- # FINIT: WHILE
$answer0 = Prompt-Menu "Enter 1st item (to be compared with) ?" $menuOptions; If($answer0 -eq "0"){ Wr-E; return}; $option0 = ([int]$answer0) -1
$answer1 = Prompt-Menu "Enter 2nd item (to compare with the 1st)?" $menuOptions; If($answer1 -eq "0"){ Wr-E; return}; $option1 = ([int]$answer1) -1; Wr-E
$CompareA.$EntityType = $itemsMenu[$option0,0]; $CompareB.$EntityType = $itemsMenu[$option1,0] # Sets comparison A/B object for Entity (NODE/SVM)
$CompareA.($EntityType + "FILE") = $itemsMenu[$option0,2]; $CompareB.($EntityType + "FILE") = $itemsMenu[$option1,2] # Sets comparison A/B filenumber (0/1) for Entity (NODE/SVM)
}
Function Compare-Data{
Param($EntityType,$check) # $EntityType = CLUSTER\NODE\SVM, and $configChecks the list of $GetNc?(s)
Wn-W ">>>>>>> Compare $EntityType"; Wr-W "s"; Wr-E # Heading
## >> Search through the cluster cfg files << ##
# Initialize arrays (for comparing two objects) with source cfgfile number, row count in CfgContent, size of cfgfile, and output
$cfgFile = New-Object 'object[]' 2; $rowCount = New-Object 'object[]' 2; $rowsInFile = New-Object 'object[]' 2; $output = New-Object 'object[]' 2
$cfgFile[0] = $CompareA.($EntityType + "FILE") # CFG file number 0 comes from svmsMenu and the chosen option1
$cfgFile[1] = $CompareB.($EntityType + "FILE") # CFG file number 1 comes from svmsMenu and the chosen option2
$rowCount[0] = $rowCount[1] = 5 # Start on 6th row (5 in array) of CfgContent
$rowsInFile[0] = ($global:CfgContent[ $cfgFile[0] ]).count # Records size of file
$rowsInFile[1] = ($global:CfgContent[ $cfgFile[1] ]).count # Records size of file
$entityName1 = $CompareA.$EntityType
$entityName2 = $CompareB.$EntityType
$searchString = New-Object 'object[,]' 2,2
$searchString[0,0] = "#START#$EntityType#" + $entityName1 + "#" + $check
$searchString[0,1] = "#FINIR#$EntityType#" + $entityName1 + "#" + $check
$searchString[1,0] = "#START#$EntityType#" + $entityName2 + "#" + $check
$searchString[1,1] = "#FINIR#$EntityType#" + $entityName2 + "#" + $check
"0","1" | foreach { # ---- # START: Cycle through the two config files, 0 and 1 (may be the same clustercfg file)
$checking = $true # Initialize $checking TRUE
$recording = $null # Initialize $recording NULL
$output[$_] = @() # Initialize $output as a blank array
while ($checking) { # START: Checking for $searchString ------------------------------------------------------------ #
If( $CfgContent[ $cfgFile[$_] ][ $rowCount[$_] ] -eq $searchString[$_,0]){ $recording = $true; $rowCount[$_]++ } # If it finds the start searchString, start recording from the next row
If( $CfgContent[ $cfgFile[$_] ][ $rowCount[$_] ] -eq $searchString[$_,1]){ $recording = $null; $checking = $null } # If finds the end searchString, stop recording and stop checking
If( $recording ) { $output[$_] += $CfgContent[ $cfgFile[$_] ][ $rowCount[$_] ] } # If recording then add the row to output
$rowCount[$_]++ # Accumulate row count by 1
If ($rowCount[$_] -ge $rowsInFile[$_]){ $checking = $null; $rowCount[$_] = 5 } # Don't let rowCount go beyond the file size, and reset counter back to the start
} # FINIR: while ($checking) -------------------------------- #
} # ---------------------- # FINIR: foreach
## >> Output the comparison << ##
Wn-W ">>>>> $EntityType Configuration Compare: "; Wr-C $check; Wr-E
$x1 = 30; $x2 = 25; $x3 = 25; $x4 = 30 # Define column widths for output
Columnize-W "PROPERTY" $x1 "$entityName1" $x2 "$entityName2" $x3 "PROPERTY" $x4
$count0 = $output[0].count; $count1 = $output[1].count # Get the size of the outputs
$maxCount = $count0; If ($count1 -gt $count0){ $maxCount = $count1 } # Max Count = $count0, unless $count1 is greater!
$r = 0 # Initialize $r for (R)ow count as 0
$haveContent = $true # The loop below runs whilst we have content to display
while ($haveContent){
# This section generates for display $property0 and $entity0item ------------- #
If ($r -ge $count0) { $property0 = ""; $entity0item = "" } # If $r (row) >= count of rows in $output[0]
elseif ($output[0][$r].trim() -eq ""){ $property0 = " "; $entity0item = " " } # Handles config file having blank output (separator) (Generated with Display-All)
else { # ------------------------ #
$splitString0 = $output[0][$r].split("=") # Split output row on "="
$property0 = $splitString0[0] # $property0 is the bit before the first/only "="
If ($splitString0.count -eq 1){ $entity0item = " "} # Handles if theres no = in the output
elseif ($splitString0.count -eq 3){ $entity0item = $splitString0[1].trim() + "=" + $splitString0[2] } # Handles if there's a 2nd = in the output, concatentate [1]=[2]
else { $entity0item = $splitString0[1].trim() } } # $entity0item is the bit after the first/only "="
# This section generates for display $property1 and $entity1item ------------- #
If ($r -ge $count1) { $property1 = ""; $entity1item = "" } # If $r (row) >= count of rows in $output[1]
elseif ($output[1][$r].trim() -eq ""){ $property1 = " "; $entity1item = " " } # Handles config file having blank output (separator) (Generated with Display-All)
else { # ------------------------ #
$splitString1 = $output[1][$r].split("=") # Split output row on "="
$property1 = $splitString1[0] # $property0 is the bit before the first/only "="
If ($splitString1.count -eq 1){ $entity1item = " "} # Handles if theres no = in the output
elseif ($splitString1.count -eq 3){ $entity1item = $splitString1[1].trim() + "=" + $splitString1[2] } # Handles if there's a 2nd = in the output, concatentate [1]=[2]
else { $entity1item = $splitString1[1].trim() } } # $entity0item is the bit after the first/only "="
# If the properties are the same, we check for attribute matching, and display green (matched), yellow (unmatched)
# ... otherwise we cannot, so display attributes as yellow (unmatched)
If (($property0 -eq " ") -and ($property1 -eq " ")) { Columnize-W "PROPERTY" $x1 $entityName1 $x2 $entityName2 $x3 "PROPERTY" $x4 } # No properties
elseif ($property0 -eq " ") { Columnize-C "PROPERTY" $x1 White $entityName1 $x2 White $entity1item $x3 Yellow $property1 $x4 Cyan } # No "left" property
elseif ($property1 -eq " ") { Columnize-C $property0 $x1 Cyan $entity0item $x2 Yellow $entityName2 $x3 White "PROPERTY" $x4 White } # No "right" property
elseif ($property0 -eq $property1) { # Properties match
If ($entity0item -eq $entity1item) { Columnize-C $property0 $x1 Cyan $entity0item $x2 Green $entity1item $x3 Green $property1 $x4 Cyan } # Entities match
else { Columnize-C $property0 $x1 Cyan $entity0item $x2 Yellow $entity1item $x3 Yellow $property1 $x4 Cyan } # Entities don't match
} else { Columnize-C $property0 $x1 Cyan $entity0item $x2 Yellow $entity1item $x3 Yellow $property1 $x4 Cyan } # Properties don't match
$r ++ # accumulate the row count
If (($count0 -le $r) -and ($count1 -le $r)){$haveContent = $null} # If $r (rows) has gone beyond the rows in $output[0] and [1], have content = NULL
}; Wr-E # FINIR: while ($haveContent)
} # FINIR: Function Compare-Data
Function Compare-DataChooseGetNc{
Param($entity,$list)
Wr-W "Type a COMPLETE command from the following list, or type:"; Wr-E
Wr-W " ALL to cycle through the complete list"
Wr-W " EXIT to return"; Wr-E
$list = $list | sort ; $listCount = $list.count
$menuChoices = @() ; $menuChoices += "ALL","EXIT"; $l = 0
while ($l -lt $listCount){
# Note 1: substring(6) gets rid of the "Get-Nc". Note 2: split(" ") is for NODE Get-NC*'s which have a " -SWITCHNAME"
If( ($l+0) -lt $listCount){ $col0 = ($list[$l].substring(6).split(" "))[0]; $menuChoices += $col0 } else { $col0 = " " }
If( ($l+1) -lt $listCount){ $col1 = ($list[$l+1].substring(6).split(" "))[0]; $menuChoices += $col1 } else { $col1 = " " }
If( ($l+2) -lt $listCount){ $col2 = ($list[$l+2].substring(6).split(" "))[0]; $menuChoices += $col2 } else { $col2 = " " }
Columnize-C $col0 35 Cyan $col1 35 Cyan $col2 35 Cyan
$l+=3 }; Wr-E
$answer = Prompt-Menu "Type a Get-Nc* command" $menuChoices; Wr-E
If($answer -eq "EXIT") { return }
If($answer -eq "ALL"){
Foreach ($GetNcCompare in $list){
Compare-Data $entity $GetNcCompare
Wr-G ">>>> Press ANY key to continue or X to E(X)IT"; Wr-E
$key = Prompt-Keys -AnyKey; If($key -eq "X"){ return } }
return }
$GetNcCompare = "Get-Nc" + $answer
If($entity -eq "NODE"){
# NODE Get-NC*'s need their " -SWITCHNAME" re-added
$i = 0
while ($i -lt $listCount){
If ($list[$i] -match $GetNcCompare){ $GetNcCompare = $list[$i]; $i = $listCount }
$i++ } }
Compare-Data $entity $GetNcCompare
}
################################################################################
## 0) MAIN PROGRAM ##
################################################################################
If($PSIse){Wr-E; Wr-R "This program cannot run in PowerShell ISE. ISE does not support ReadKey!"; Wr-E; EXIT} # Check not running in PowerShell ISE
$toolkit = Check-PSTK; If($toolkit){$versionChk = Check-PSTKversion $TKmajor $TKminor} else {$versionChk = $null} # Check for DOT PSTK and Version
[Void](Create-Folder $defaultClusterCfgFolder); $clusterCfgFolder = $defaultClusterCfgFolder # Check for default CLUSTERCFG folder
Set-Window White Black $title 80 # Set White text, Black background, Window Title, @ 80% max window size
Wr-E;Wr-M "<<<<<<<<< $title >>>>>>>>>";Wr-E # Display TITLE
If($toolkit -and !$versionChk){Wr-Y "Recommend DataONTAP PowerShell Toolkit version $TKmajor.$TKminor or better - older version detected!"};Wr-E
$lastPressed = $null # We record the last pressed key (since sometimes the output's big and I forget what I last pressed, and don't want to scroll back)
while ($true) { ## >> MENU SYSTEM << ##
Wr-M "<<<<<<<<< MAIN MENU >>>>>>>>>"; Wr-E
# Checking currently-connected-to-cluster
$cCluster = Current-Cluster; $cClusterIP = Current-ClusterIP; $cUsername = Current-Username
If($cCluster) { Current-VserverNull } # Make sure no Vserver is selected!
# Checking loaded clustercfg files & CompareA/B HashTables
If ($clusterCfg[0,0] -and $clusterCfg[1,0]){$cfgFiles = 2} elseif ($clusterCfg[0,0] -or $clusterCfg[1,0]){$cfgFiles = 1} else {$cfgFiles = 0}
$cfgNodeCount = [int]$clusterCfg[0,1] + [int]$clusterCfg[1,1]; If(!$cfgNodeCount){$cfgNodeCount = 0} # Count Nodes
$cfgSVMCount = [int]$clusterCfg[0,2] + [int]$clusterCfg[1,2]; If(!$cfgSVMCount) {$cfgSVMCount = 0} # Count SVMs
If($cfgNodeCount -eq 2){ # We have a pair of nodes, so to override needing to select two from two
If ($cfgFiles -eq 2){ # Two files so take one node from each file
$CompareA.NODE = ( ($CfgContent[0][1]).Split(",") )[0]; $CompareA.NODEFILE = 0
$CompareB.NODE = ( ($CfgContent[1][1]).Split(",") )[0]; $CompareB.NODEFILE = 1
} else { # We must have 1 $cfgFile, but which?
If ($clusterCfg[0,0]){
$CompareA.NODE = ( ($CfgContent[0][1]).Split(",") )[0]; $CompareA.NODEFILE = 0
$CompareB.NODE = ( ($CfgContent[0][1]).Split(",") )[1]; $CompareB.NODEFILE = 0 }
If ($clusterCfg[1,0]){
$CompareA.NODE = ( ($CfgContent[1][1]).Split(",") )[0]; $CompareA.NODEFILE = 1
$CompareB.NODE = ( ($CfgContent[1][1]).Split(",") )[1]; $CompareB.NODEFILE = 1 } } }
If($cfgSVMCount -eq 2){ # We have a pair of SVMs, so to override needing to select two from two
If ($cfgFiles -eq 2){ # Two files so take one SVM from each file
$CompareA.SVM = ( ($CfgContent[0][3]).Split(",") )[0]; $CompareA.SVMFILE = 0
$CompareB.SVM = ( ($CfgContent[1][3]).Split(",") )[0]; $CompareB.SVMFILE = 1
} else { # We must have 1 $cfgFile, but which?
If ($clusterCfg[0,0]){
$CompareA.SVM = ( ($CfgContent[0][3]).Split(",") )[0]; $CompareA.SVMFILE = 0
$CompareB.SVM = ( ($CfgContent[0][3]).Split(",") )[1]; $CompareB.SVMFILE = 0 }
If ($clusterCfg[1,0]){
$CompareA.SVM = ( ($CfgContent[1][3]).Split(",") )[0]; $CompareA.SVMFILE = 1
$CompareB.SVM = ( ($CfgContent[1][3]).Split(",") )[1]; $CompareB.SVMFILE = 1 } } }
$clusterA = $CompareA.CLUSTER; $clusterB = $CompareB.CLUSTER; If($clusterA -and $clusterB){$clusterPair = $true} else {$clusterPair = $null}
$nodeA = $CompareA.NODE; $nodeB = $CompareB.NODE; If($nodeA -and $nodeB) {$nodePair = $true} else {$nodePair = $null}
$svmA = $CompareA.SVM; $svmB = $CompareB.SVM; If($svmA -and $svmB) {$svmPair = $true} else {$svmPair = $null}
# Display menu options
$PROMPTKEYS = "X","3","A","B" # Always available options
$P = " < 1 > Connect to Cluster - PS toolkit not loaded!"; If(!$toolkit){Wr-D}
$P = " < 1 > Connect to Cluster - "; If($toolkit -and !$cCluster){Wn-W;Wr-Y "no current connection!";$PROMPTKEYS += "1"}
$P = " < 1 > Connect to Cluster -"; If($toolkit -and $cCluster){Wn-W "$P current = ";Wn-C $cCluster;Wn-W " (IP ";Wn-C $cClusterIP;Wn-W ", user ";Wn-C $cUsername;Wr-W ")";$PROMPTKEYS += "1"}
$P = " < 2 > Health Check Cluster"; If($cCluster) {Wr-W;$PROMPTKEYS += "2"} else {Wr-D}; Wr-E
Wn-W " < 3 > Change Folder for saved clustercfg files - current = "; Wr-C $clusterCfgFolder
$P = " < 4 > Save Current Cluster's Configuration"; If($cCluster) {Wr-W;$PROMPTKEYS += "4"} else {Wr-D}
$P = " < A > Load clustercfg File A -"; If($clusterCfg[0,0]) {Wn-W "$P loaded = "; Wr-C $clusterCfg[0,0]} else {Wr-W "$P nothing loaded!"}
$P = " < B > Load clustercfg File B -"; If($clusterCfg[1,0]) {Wn-W "$P loaded = "; Wr-C $clusterCfg[1,0]} else {Wr-W "$P nothing loaded!"}
$P = " Loaded clustercfg files contain: "; If($cfgFiles -ne 0) {Wr-E; Wn-W; Wr-C "$cfgFiles CLUSTER(s), $cfgNodeCount NODE(s), and $cfgSVMCount Data SVM(s)"}; Wr-E
$P = " < C > Compare CLUSTER Configurations"; If($clusterPair) {Wn-W "$P for ";Wn-C $clusterA;Wn-W " and ";Wr-C $clusterB;$PROMPTKEYS += "C"} else {Wr-D}
$P = " < M > Select NODEs to Compare"; If($cfgNodeCount -gt 2){Wr-W; $PROMPTKEYS += "M"}
$P = " < N > Compare NODE Configurations"; If($nodePair) {Wn-W "$P for ";Wn-C $nodeA;Wn-W " and ";Wr-C $nodeB;$PROMPTKEYS += "N"} else {Wr-D}
$P = " < R > Select SVMs to Compare"; If($cfgSVMCount -gt 2) {Wr-W; $PROMPTKEYS += "R"}
$P = " < S > Compare SVM Configurations"; If($svmPair) {Wn-W "$P for ";Wn-C $svmA; Wn-W " and ";Wr-C $svmB; $PROMPTKEYS += "S"} else {Wr-D}; Wr-E
Wr-W " < X > Exit"; Wr-E
$P = " <<<<< Last pressed key: $lastPressed"; If($lastPressed) {Wr-W}
Wn-G " >>>>> Press a Key: "
# Handle the Keys
$key = Prompt-Keys $PROMPTKEYS;Wr-Y $key; Wr-E
If($key -eq "1"){ Cluster-Connect }
If($key -eq "2"){ Check-Health }
If($key -eq "3"){ $clusterCfgFolder = Set-ClusterCFGFolder }
If($key -eq "4"){ Save-Configuration }
If($key -eq "A"){ Load-ClusterCfg 0 }
If($key -eq "B"){ Load-ClusterCfg 1 }
If($key -eq "C"){ Compare-DataChooseGetNc CLUSTER $clusterConfigurations }
If($key -eq "M"){ Select-PairToCompare NODE }
If($key -eq "N"){ Compare-DataChooseGetNc NODE $nodeConfigurations }
If($key -eq "R"){ Select-PairToCompare SVM }
If($key -eq "S"){ Compare-DataChooseGetNc SVM ($SVMConfigurations + $GetNcSVMVOLUMEs) }
If($key -eq "X"){ EXIT }
$lastPressed = $key
} ## END of MENU SYSTEM ##