Scripting Corner: NetApp Storage Controller Options Retriever

Once upon a time we had to make a revision of some options on about 50 NetApp Storage Controllers in our environment. The options were many and we needed to retrieve them in a reviewable fashion to mark out which comply to NetApp’s best practices.

You will require NetApp’s Data OnTap Powershell Toolkit in order for this script to run, because it uses their commandlets.

It took me four days to devise this script, mainly because I had other things to do like resolving incidents and doing actual work πŸ˜€ The hardest part was the looping and writing to CSV. This script has a few caveats:

  • If you search for just one option, the CSV will not be generated properly, so enter a random second option, input the same one or just an asterisk will do (the fields will be blank).
  • It is better if you take the CSV and invert it – better readability and searchability, however I have realized that after the script has been finished. And I’d rather not return to the cycling nightmare again πŸ™‚
  • The CSV is generated procedurally inside a variable and is output to a file at the end of the script – if you stop it while running halfway, you get no partial CSV.

The sample output can  be found below:

A sample output from options collected by the script - not transposed.

A sample output from options collected by the script – not transposed.

You will need two input files – controllers.txt with the controllers you want to query and options.txt with options you wish to retrieve – the separator is a line break. Please note that the options must be input exactly as they appear in Data OnTap, else the script can misbehave. I hope many of you will find this script useful.

Import-Module DataONTAP

Write-Host `n "--- NetApp Option Retriever ---" -ForegroundColor 'Cyan' `n
$startedtime = Get-Date

#Define path to the exported CSV.
$csvpath1 = ".\options.csv"

# Generate a new array for controller list and fill it
$sclist = @()
$sclist += Get-Content controllers.txt

# Do the same with the options array
$optIN = @()
$optIN += Get-Content options.txt

Write-Host 'Started gathering' $OptIN.count 'options on' $sclist.count 'Storage Controllers' `n

# A base for list of options we want to find
$optcmd = "Get-NaOption | Sort | Select Name, Value"

# Create an array from the options we want to find by first sorting it out...
$optIN = $optIN | Sort

# ...And then formatting it like a CSV
$datasuffix = @("Data;")

# Fill in the first column of the CSV
foreach ($item in $optIN)
{
	$datasuffix += "$item" + ";"
}

# Intialize the array with first column
$CachedCsv = @()
$CachedCsv += $datasuffix

# Initialize empty array for the ignored fields
$ignored = @()

# Initialize failed filers value
$failedcount = 0
$failednames = @()

# Procedure to write all the CSV values using procedural CSV construction
ForEach ($sc in $sclist)
{
	Try
	{
		Connect-NaController $sc -ErrorAction 'SilentlyContinue' | Out-Null
		Write-Host "Processing Controller $sc" -ForegroundColor Green
		if ($global:CurrentNaController -eq $null)
		{
			Write-Host "Could not connect to Controller $sc ! Skipping..." -ForegroundColor Red
			$failedcount++
			$failednames += $sc
			Continue
		}

	}
	Catch
	{
		Write-Host "Could not connect to Controller $sc ! Skipping..." -ForegroundColor Red
		$failedcount++
		$failednames += $sc
		Continue
	}

	#Generate another column header = storage controller name
	$CachedCsv[0] += $sc + ";"

	# run the stored command
	$getvalues = Invoke-Expression $optcmd

	# Clear the IGNORED array
	$ignored.clear()

	# For each value got...
	for ($i = 0; $i -lt $getvalues.count; $i++)
	{
		# Search this value's name in the input options array
		for ($j = 0; $j -lt $optIN.count; $j++)
		{
			# And if it matches exactly, write it there
			if ($getvalues[$i].name -contains $optIN[$j])
			{
				$presentIndex = [array]::IndexOf($optIn, $optIN[$j])
				$CachedCSV[$presentindex + 1] += $getvalues[$i].value + ";"
			}
			# If the value we are looking for does not exist, write an empty field and enter that value in the $ignored array
			# So it does not get checked over and over again.
			ElseIf (($getvalues.name -notcontains $optIN[$j]) -and ($ignored -notcontains $optIN[$j]))
			{
				$ignored += $optIN[$j]
				$missingIndex = [array]::IndexOf($optIn, $optIN[$j])
				$CachedCSV[$missingindex+1] += ";"
			}
		}
	}
}

# Write out the cached CSV
"Sep=;" | Out-File $csvpath1
$CachedCsv | Out-File $csvpath1 -Append

# Count statistics...
$endedtime = Get-Date
$timetook = ($endedtime - $startedtime).TotalSeconds

$scOK = $sclist.count - $failedcount

# Final stat listing.
Write-Host `n Processed $OptIN.count options on $scOK Storage Controllers 'in' $timetook seconds. -ForegroundColor Green
If ($failedcount -ge 1)
{
	Write-Host `n "Connection to the following $failedcount controllers failed: " $failednames `n -ForegroundColor 'Red'
}

And of course, since there is an option Retriever for NetApp, there must also be an option setter, right? Yes you are correct and that will be a subject of a future Scripting Corner πŸ™‚ See you soon!

Advertisements

Share your thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s