Saturday, 30 November 2013

Understanding NetApp Snapshots

Here’s my attempt at explaining how NetApp snapshots work. It’s not a discussion on the benefits of the redirect-on-write (as opposed to copy-on-write) method that NetApp uses, simply an example illustrating what happens when you add and delete stuff.

We have a 1GB (1024MB) volume with 5% snapshot reserve (51MB) which gives 972MB filesystem visible space.

na81::> df -m cdotshare
Filesystem               total   used   avail capacity
/vol/cdotshare/          972MB    0MB   972MB       0%
/vol/cdotshare/.snapshot  51MB    0MB    51MB       0%

We add roughly 10MB’s worth.

Filesystem               total   used   avail capacity
/vol/cdotshare/          972MB   10MB   962MB       1%
/vol/cdotshare/.snapshot  51MB    0MB    51MB       0%

We take a snapshot.

na81::> snap create -vserver vs1 -volume cdotshare -snapshot snap01

Filesystem               total   used   avail capacity
/vol/cdotshare/          972MB   10MB   962MB       1%
/vol/cdotshare/.snapshot  51MB    0MB    51MB       0%

We add 10MB more to make it 20MB.

Filesystem               total   used   avail capacity
/vol/cdotshare/          972MB   20MB   952MB       2%
/vol/cdotshare/.snapshot  51MB    0MB    51MB       0%

We take a second snapshot.

na81::> snap create -vserver vs1 -volume cdotshare -snapshot snap02

Filesystem               total   used   avail capacity
/vol/cdotshare/          972MB   20MB   952MB       2%
/vol/cdotshare/.snapshot  51MB    0MB    51MB       0%

We add 10MB more to make it 30MB.

Filesystem               total   used   avail capacity
/vol/cdotshare/          972MB   30MB   941MB       3%
/vol/cdotshare/.snapshot  51MB    0MB    51MB       0%

Now we’re starting to see how it works. We can keep adding new stuff to this volume (without deleting anything) and no snapshot space will ever be consumed.

Okay, we delete the 10MB we added just after the last snapshot.

Filesystem               total   used   avail capacity
/vol/cdotshare/          972MB   20MB   951MB       2%
/vol/cdotshare/.snapshot  51MB    0MB    51MB       0%

Of course, the latest 10MB is not referenced in any snapshot so no snapshot space is consumed.

We delete all 20MB we’ve added.

Filesystem               total   used   avail capacity
/vol/cdotshare/          972MB    0MB   972MB       0%
/vol/cdotshare/.snapshot  51MB   20MB    30MB      40%

And there we see it; the volume is back to 0MB filesystem data, but with 20MB referenced in snapshots.



Setting Volume Attributes on SnapMirror Destinations

This post was inspired by OnCommand Unified Manager and an alert that came in about snapshot-reserve being over capacity on a SnapMirror destination volume. In my noobishness at NetApp storage administration, there I was scratching my head and thinking “do we have to break the SnapMirror and apply the attribute to the DR volume, then resync?” Completely wrong! (In fact, after breaking, attributes set on the DR volume would have been overwritten once we did the resync…)

As an example, I have a cluster called na81 with two Vservers - vs1 and vs2. There’s a volume called testshare on vs1 that’s being replicated to testDR on vs2.

na81::> snapmirror show
Source              Destination  Mirror        Relationship
Path          Type  Path         State         Status        Healthy
------------- ---- ------------ ------------- -------------- -------
na81://vs1/testshare DP na81://vs2/testDR Snapmirrored Idle  true

If I try to modify the % snapshot space (snapshot reserve) on the DR volume I get this error:

na81::> vol modify -vserver vs2 -volume testDR -percent-snapshot-space 20
Error: command failed: Unable to set volume attributes for volume "testDR" on Vserver "vs2". Reason: Unable to set attribute snapshot-reserve-percentage for volume. Reason: Operation not permitted on read-only volume 'testDR'

So, what we do to change the % snapshot space on the DR volume, is change it on the source and do a SnapMirror update. This is demonstrated below:

na81::> vol show -fields percent-snapshot-space
vserver volume percent-snapshot-space
------- ------ ----------------------
vs1     testshare 5%
vs2     testDR 5%

na81::> vol modify -vserver vs1 -volume testshare -percent-snapshot-space 20

na81::> vol show -fields percent-snapshot-space
vserver volume percent-snapshot-space
------- ------ ----------------------
vs1     testshare 20%
vs2     testDR 5%

na81::> snapmirror update -destination-path na81://vs2/testDR

na81::> vol show -fields percent-snapshot-space
vserver volume percent-snapshot-space
------- ------ ----------------------
vs1     testshare 20%
vs2     testDR 20%

Simples!

And it gives me an excuse to post an image of a cute meerkat!

Image: Cute meerkat...


How to Setup Intercluster SnapMirror in CDOT 8.1.X

The following post runs through all the steps involved in setting up a volume SnapMirror relationship in NetApp Clustered Data ONTAP.
Note: The commands were verified on a lab environment of two one-node SIM 8.1.2 clusters, which had actually been upgraded to 8.1.3P1.

Walkthrough

On the source (cluster nac1 and node nac1-01):

In the following 5 lines (3 lines ignoring shows), we: add the SnapMirror license; create a volume on a pre-existing Vserver; and create an intercluster LIF (every node in the cluster needs an intercluster LIF but here we have just one node).

license show
license add -license-code BEOYIXMWZWYQSD

vol create DC1_VOL1 -vserver vs1 -aggregate aggr1 -size 5g -space-guarantee none

net int show
net int create -vserver nac1-01 -lif n1_icl -role intercluster -home-node nac1-01 -home-port e0d -address 192.168.168.45 -netmask 255.255.255.0

On the destination (cluster nac2 and node nac2-01):

In the following 15 lines (8 lines ignoring shows/ping test), we: add the SnapMirror license; create a Vserver to replicate to (in the circumstance there is not pre-existing one); create a volume of type DP; create an intercluster LIF; create a cluster peer relationship to the remote clusters intercluster LIF; initialize the snapmirror; perform a snapmirror update; and finally set a snapmirror schedule.

license show
license add -license-code BEOYIXMWZWYQSD

vserver create -vserver vs1 -rootvolume vs1_root -aggregate aggr1 -ns-switch file -nm-switch file -rootvolume-security-style unix -language C.UTF-8

vol create DC1_VOL1_REPL -vserver vs1 -aggregate aggr1 -size 5g -space-guarantee none -type DP

net int show
net int create -vserver nac2-01 -lif n1_icl -role intercluster -home-node nac2-01 -home-port e0d -address 192.168.168.65 -netmask 255.255.255.0

network ping -node nac2-01 -destination 192.168.168.45
cluster peer create -peer-addrs 192.168.168.45 -username admin
cluster peer show

snapmirror initialize -source-path nac1://vs1/DC1_VOL1 -destination-path nac2://vs1/DC1_VOL1_REPL -type DP

snapmirror show
snapmirror update -destination-path nac2://vs1/DC1_VOL1_REPL
job sched cron show
snapmirror show -fields schedule
snapmirror modify -destination-path nac2://vs1/DC1_VOL1_REPL -schedule daily

Deconstruction

Since in a testing environment it’s equally useful to know how to construct and then deconstruct something, the following commands completely deconstruct the test volume SnapMirror setup created above.
Note: Above we created a Vserver on cluster nac2. Here we leave the Vserver in place.

On the destination (cluster nac2 and node nac2-01):

snapmirror delete -destination-path NAC2://vs1/DC1_VOL1_REPL
vol destroy -volume DC1_VOL1_REPL -vserver vs1
cluster peer delete -cluster nac1
net int delete -vserver nac2-01 -lif n1_icl
license delete SnapMirror_DP

On the source (cluster nac1 and node nac1-01):

vol destroy -volume DC1_VOL1 -vserver vs1
net int delete -vserver nac1-01 -lif n1_icl
license delete SnapMirror_DP

Image: In Clustered ONTAP, each node requires an Intercluster LIF where Intercluster SnapMirror is used.

 

Friday, 29 November 2013

UPDATE: CDOT Snapshot Deletor PowerShell (non-interactive for specific volumes)

For an UPDATE of the UPDATE see: PowerShell Script to Delete Aged Snapshots for NetApp Clustered ONTAP

The following post is an update of the PowerShell script from the below post after some development:

Essentially the script is the same except it now:

- Has a customer friendly amount of comment
- Details how to create a minimal permission role and user account to run SnapDeletor
- Outputs to console much more detail (such as the individual Snapshots being deleted, date they were created)
- Outputs to a date-stamped log file at a user specified path
- Has intelligence to know if the volume has no aged Snapshots
- Has intelligence to alert/report if a Snapshot could not be deleted
- Sends a simple text email to an administrator(s)

An example of its use:

The script was designed to work in an environment with Exchange 2010 DAGs across two sites. The remote DAGs required 90 day retention using NetApp SnapManager for Exchange (SME). The Snapshots of the transaction logs beyond 7 days were not required (I mean, who’s going to roll database beyond much more than 7 days of logs and definitely not 90!) And the SME version in use (6.0.4) did not have the ability to have different Snapshot retention on transaction log volumes compared to database volumes. Hence, the script was designed to run as a scheduled task on a management server, to keep the Snapshot retention on the transaction log volumes to a more reasonable level (like 9 days.)

The Script

Save the following script into Notepad++ as say ‘cdotsnapdeletor.ps1’ and run in PowerShell (after first setting credentials with set-cred.ps1):

### START COPYING HERE ###

#############
### TITLE ###
###################################################################
## CDOT Snapshot Deletor of Snapshots older than X days          ##
##  (Non-interactive using Cluster login, and for a specified    ##
##   list of volumes only)                                       ##
###################################################################
## AUTHOR: vCosonok @ www.cosonok.com                            ##
## CREDITS: The awesome PowerShell community on the internet!    ##
###################################################################

######################
## COMMENTS SECTION ##
###################################################################
# For the cluster, cluster user account, Vserver, list of volumes #
#  and number of days specified in SECTION 1: this script will    #
#  delete snapshots older than the specified number of days       #
#  of days. Also specify $logFilePath.                            #
# If you want to email the text report, unhash SECTION 3 and      #
#  specify: email from, email to, and SMTP server                 #
# If you want to run it in "REPORT-MODE" then simply hash out the #
#  one line that starts with Remove-NcSnapshot                    #
# This script does not force delete snapshots, the Powershell     #
#  option "-IgnoreOwners" flag has not been added to the          #
#  Remove-NcSnapshot line                                         #
# SECTION 2: Removes snapshots/does reporting                     #
# SECTION 3: Creates and sends the report as an email             #
# Save this script in notepad/notepad++ as say                    #
#  cdotSnapshotDeletor.ps1 and run in Powershell!                 #
# NOTE: This script designed specifically to trim down snapshots  #
#  on certain volumes to a certain number of days (example:       #
#  remote Exchange DAG transaction log snapshots where a database #
#  retention of 90 days is required but logs only for 7 days, and #
#  SME cannot currently do this (27/11/2013)                      #
###################################################################
# Pre-requisities:                                                #
#  1) The file c:\scripts\encrypted_password.txt must have been   #
#      created first using set-cred.ps1                           #
#      (commented below for reference)                            #
#  2) Additionally the Data ONTAP PowerShell Toolkit must be      #
#      installed, and PowerShell execution policy set accordingly #
#      (RemoteSigned will work.)                                  #
###################################################################
# # set-cred.ps1 file contents
# # Creates a text file with encrypted password string
# # Note: A blank file c:\scripts\encrypted_password.txt must be created first!
# $credential = Get-Credential
# $credential.Password | ConvertFrom-SecureString | Set-Content c:\scripts\encrypted_password.txt
###################################################################
# Using a specific cluster logon account for SnapDeletor:         #
# If you don't want to use your cluster admin account to run this #
# (which you shouldn't really be using for security reasons),     #
# then the following Clustershell commands can be used to         #
# create a SnapDeletor role and SnapDeletor account that will     #
# work with this script                                           #
###################################################################
# ::> sec login role create -role SnapDeletor -cmddirname DEFAULT -access readonly
# ::> sec login role create -role SnapDeletor -cmddirname snapshot -access all
# ::> sec login role create -role SnapDeletor -cmddirname volume -access all
# ::> sec login create -username SnapDeletor -application ontapi -authmethod password -role SnapDeletor
###################################################################
## END OF COMMENTS SECTION ##
#############################

#################################
## SECTION 1: Set Up Variables ##
#################################

# Enter the following variables/lists: $cluster,$username,$vserver,$volumes,$daysWorth,$logFilePath
$cluster = "192.168.168.40"
$username = "SnapDeletor"
$vserver = "vs1"
$volumes = "REMOTEDAG_TL01", "REMOTEDAG_TL02", "REMOTEDAG_TL03"
$daysWorth = 9
$logFilePath = "C:\scripts\logs\"

# These two lines get the encrypted password string from the text file
$encrypted = Get-Content c:\scripts\encrypted_password.txt | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($username, $encrypted)

# The following section creates the filename for the output report file
$fileTag = "CLUSTER_SnapshotDeletorOutput_"
$dateStamp = (get-date).tostring("yyyyMMddHHmm")
$extension = ".log"
$filename = $filetag + $dateStamp + $extension
$fullPathToFile = $logFilePath + $filename

###################################
## SECTION 2: Removing Snapshots ##
###################################

# NOTE: If you want to test (run in "report-mode"), hash the Remove-NcSnapshot line

# Connect to Cluster
Import-Module DataOnTap
echo "Connecting ... this can take a few minutes!"
Connect-NcController $cluster -Credential $credential -Vserver $vserver
echo "Connected to cluster $cluster and vserver $vserver" ""
echo "Connected to cluster $cluster and vserver $vserver" "" >> $fullPathToFile

# POWERSHELL NOTE 1: If this was Powershell 3.0, we could use:
# > "text","" | tee-object -FilePath $fullPathToFile -Append
# but -Append is not available Powershell pre-3.0.
# POWERSHELL NOTE 2: write-host has more functionality than echo but echo works here for our purposes

echo "The following snapshots are older than $daysWorth days and are being deleted!" ""
echo "The following snapshots are older than $daysWorth days and are being deleted!" "" >> $fullPathToFile

# This line cycles through each volume in the $volumes list
foreach ($volume in $volumes){

echo "" "Volume=$volume" ""
echo "" "Volume=$volume" "" >> $fullPathToFile
$snapshots = Get-NcSnapshot -Volume $volume | where-object {$_.Created -lt (Get-Date).AddDays(-$daysWorth)}

# This if statement operates if $snapshots is not null/empty
if ($snapshots){

# This line cycles through each snapshot in the $snapshots list
foreach ($snapshot in $snapshots){

$snapshotName = $snapshot.name
$snapshotDate = $snapshot.created

# NOTE: If you hash the next line this script just does reporting!
# Remove-NcSnapshot -Volume $volume -Snapshot $snapshotName -confirm:$false

$snapStillThere = Get-NcSnapshot -Volume $volume -Snapshot $snapshotName

# This if statement operates if $snapStillThere is null/empty
if (!$snapStillThere) {
echo "Deleted $snapshotName from $snapshotDate. "
echo "Deleted $snapshotName from $snapshotDate. " >> $fullPathToFile
} # END of if (!$snapStillThere)

# This if statement operates if $snapStillThere is not null/empty
if ($snapStillThere) {
echo "$snapshotName from $snapshotDate @@@@@ WAS NOT DELETED!"
echo "$snapshotName from $snapshotDate @@@@@ WAS NOT DELETED!" >> $fullPathToFile
} # END of if ($snapStillThere)

} # END of "foreach ($snapshot in $snapshots)"

} # END of "if ($snapshots)"

# This if statement operates if $snapshots is null/empty
if (!$snapshots){
echo "Volume $volume has no snapshots older than $daysWorth days!"
echo "Volume $volume has no snapshots older than $daysWorth days!" >> $fullPathToFile
} # END of "if (!$snapshots)

} # END of "foreach ($volume in $volumes)"

echo "" "Snapshot deletion complete." "Report saved as $filename."
echo "" "Snapshot deletion complete." "Report saved as $filename." >> $fullPathToFile

################################################
## SECTION 3: Sending the report as an email! ##
################################################

# Define these 3 email variables
$emailFrom = "noreply@domain.com"
$emailTo = "email1@domain.com,email2@domain.com"
$smtpserver = "smtprelay.domain.com"

# Subject will be the output filename
$subject = $filename

# Email message contents taken from the output file
[string]$message = ""
$messageRaw = get-content -path $fullPathToFile
foreach ($line in $messageRaw) {$message = $message + $line + "`r`n"}

# Send the email
$smtp=new-object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($emailFrom, $emailTo, $subject, $message)

### STOP COPYING HERE ###

Illustration

Image: Example of SnapDeletor running on a LAB VSIM and deleting snapshots older than 2 days!

Sunday, 17 November 2013

Check for Over-Aged Clustered ONTAP Snapshots with Powershell

The following script was created to find over-aged snapshots in a multi-cluster Clustered ONTAP environment. The script runs interactively, asks for connection IP and credentials, asks what age we’re looking for as over-aged, and then runs through the cluster checking for over-aged snapshots. When finished checking one cluster, it prompts whether you want to check another. The culmination of the script is an excel spreadsheet report with each cluster on a different tab, and listing all the aged snapshots.

Copy the below and save as getOverAgedSnapshots.ps1 (or whatever name you like) and run!

PS Apologies for the formatting of this script on this blog … and at the end is an image of the script in action and example of the output.

## START COPYING HERE ##

# The following interactive script
#  connects to a NetApp Clustered ONTAP Cluster (or more)
#  prompts for an age beyond which you want to find snapshots
#  then outputs an Excel report of all the aged snapshots
#  + additional information

## Section 1: Import DOT PS, create Excel Workbook, setup templates

Import-module DataOnTap
$xl=New-Object -ComObject "Excel.Application"
$wb=$xl.Workbooks.Add()
$xl.Worksheets.Item("Sheet2").Delete()
$xl.Worksheets.Item("Sheet3").Delete()
$ws=$wb.ActiveSheet
$worksheets=1
$confirm_do_loop1 = "y"

# do loop to cycle through clusters
do {

## Section 2: User prompts and connect

echo ""
$controller = Read-host "Enter IP of cluster-mgmt LIF"
$user = Read-host "Enter username"
echo "" "connecting ..."
Connect-NcController $controller -credential $user
echo ""
$daysWorth = Read-host "Enter age of aged snapshots to look for (days)"
if ($worksheets -eq "1"){$filename = Read-host "Enter file name for output file"}
if ($worksheets -eq "1"){$filename = $filename + ".xlsx"}
$units = Read-host "Units for output [g=gigabyte,m=megabyte,k=kilobyte]"
$conversion = 1; $unit = "B"
if ($units -eq "k"){ $conversion = 1024; $unit = "KB" }
if ($units -eq "m"){ $conversion = 1048576; $unit = "MB" }
if ($units -eq "g"){ $conversion = 1073741824; $unit = "GB" }
echo ""

## Section 3: Excel Worksheet Setup

$cells=$ws.Cells
$cells.item(1,1)="Aged Snapshots Report for "+$controller
$cells.item(1,1).font.bold=$True
$cells.item(1,1).font.size=18
$row=2
$col=1
$grandSnapTotal=0

## Section 4: For every Vserver and Volume, find those aged snapshots  

# We're only interested in data Vservers
$template1 = Get-NcVserver -Template
$template1.VserverType = "data"
$vservers = Get-NcVserver -Query $template1

# loop through Vservers
foreach ($vserver in $vservers){

$vserverName = $vserver.Vserver
echo "checking Vserver $vserverName ..."
$row++
$cells.item($row,1)="Vserver $vserverName"
$cells.item($row,1).font.bold=$True
$cells.item($row,1).font.size=16
$row++
$global:CurrentNcController.Vserver = $vserverName

# We only want to pull volume names when run Get-NcVol
$template2 = Get-NcVol -Template
$template2.Name = ""
$volumes = Get-NcVol -Attributes $template2

# loop through Volumes  
foreach ($volume in $volumes){
  
$volumeName=$volume.name
echo "checking volume $volumeName ..."

$snapCount = (Get-NcSnapshot $volumeName | where-object {$_.Created -lt (Get-Date).AddDays(-$daysWorth)} | measure).count
echo " volume $volumeName has $snapCount snapshots older than $daysWorth days"

# ignore volumes with no aged snapshots        
if ($snapcount -ne "0" ){

$row++
$cells.item($row,1)=$volumeName+" has "+$snapcount+" snapshots older than "+$daysWorth+" days."
$cells.item($row,1).font.bold=$True
$cells.item($row,1).font.size=14
$row++

# output column headers             
"Name","Volume","Vserver","Created","Total ($unit)","Cumulative ($unit)","Dependency" | foreach {
$cells.item($row,$col)=$_
$cells.item($row,$col).font.bold=$True
$col++
}

$row++
$col=1
$snapshots = Get-NcSnapshot $volumeName | where-object {$_.Created -lt (Get-Date).AddDays(-$daysWorth)}
$snapSizeTotal = 0

# loop through snapshots outputting info            
foreach ($snapshot in $snapshots){

$cells.item($row,1)=$snapshot.Name
$cells.item($row,2)=$snapshot.Volume
$cells.item($row,3)=$snapshot.Vserver
$cells.item($row,4)=$snapshot.Created
$total=[int]($snapshot.Total/$conversion)
$cells.item($row,5)=$total
$snapSizeTotal = $snapSizeTotal + $total
$cumulative=[int]($snapshot.Cumulative/$conversion)
$cells.item($row,6)=$cumulative
$cells.item($row,7)=$snapshot.Dependency    
$row++
     
} # foreach ($snapshot in $snapshots)

# display the total of the SnapShots
$cells.item($row,4)="TOTAL ($unit)"
$cells.item($row,4).font.bold=$True
$cells.item($row,5)=$snapSizeTotal
$cells.item($row,5).font.bold=$True
$row++
$grandSnapTotal = $grandSnapTotal + $snapSizeTotal
 
} # if ($snapcount -ne "0")

} # foreach ($volume in $volumes)

echo ""

} # foreach ($vserver in $vservers)

# display the GRAND total of the SnapShots
$row++
$cells.item($row,4)="GRAND TOTAL ($unit)"
$cells.item($row,4).font.bold=$True
$cells.item($row,5)=$grandSnapTotal
$cells.item($row,5).font.bold=$True
$row++

# autofit excel columns and name
$range = $ws.UsedRange
$range.EntireColumn.Autofit() | out-null

# name the current worksheet and move it to the end
$ws.name = "$controller"
$lastSheet = $wb.WorkSheets.Item($wb.WorkSheets.Count)
$ws.Move([System.Reflection.Missing]::Value,$lastSheet)
  
# check more clusters?
$confirm_do_loop1 = Read-host "Do you want to check more Clusters (y/n)"
if ($confirm_do_loop1 -eq "y"){$ws=$wb.Worksheets.Add();$worksheets++}

} until ($confirm_do_loop1 -ne "y") # do

## Section 6: Display the Excel Workbook and Save

$xl.Visible=$True
$path = [Environment]::GetFolderPath('MyDocuments')
$path = $path + "\" + $filename
Remove-Item $path -Force -ErrorAction SilentlyContinue
$wb.SaveAs($filename)

# Note: Excel defaults to your documents path and
#  the above deletes any pre-existing file with the same name!

## STOP COPYING HERE ##

Image 1: The Over-Aged Snapshot Check script in action!
Image 2: Example Output (each Cluster will appear on a separate tab)

Wednesday, 13 November 2013

Clustered ONTAP Snapshot Deletor Non-Interactive

Update: See http://www.cosonok.com/2013/11/update-cdot-snapshot-deletor-powershell.html for a slightly more advanced script (with logging, email reporting, ...)

Here we present a PowerShell script which allows you to delete snapshots for volumes on your NetApp Clustered ONTAP clusters that are aged over a certain number of days. This is the non-interactive version that might be run as a scheduled task/add-on script to an existing process. The previous post contained the interactive version.

The first PowerShell script is required to make an encrypted password string.
The remaining two powershell scripts present connecting via a Cluster admin credential or a Cluster admin credential (there’s very little difference to the scripts.)

Set Credentials Script
Copy the following into Notepad (or - even better - Notepad++) and save as say set-cred.ps1 and then run using PowerShell:

## START COPYING HERE ##

## Set Credentials Script
#########################
## Creates a text file with encrypted password string
## Note: A blank file c:\scripts\encrypted_password.txt must be created first

$credential = Get-Credential
$credential.Password | ConvertFrom-SecureString | Set-Content c:\scripts\encrypted_password.txt

## STOP COPYING HERE ##

CDOT Snapshot Non-Interactive Deletion Script using Cluster login
Copy the following into Notepad (or - even better - Notepad++) and save as say cdotsnapdel.ps1 and then run using PowerShell:

## START COPYING HERE ##

## CDOT Snapshot Deletor (Non-interactive using Cluster login)
##############################################################
## For the Cluster, Vserver and Volumes specified, it will delete snapshots older than the specified days
## Pre-requisites:
## The file c:\scripts\encrypted_password.txt must have be created first using set-cred.ps1
## Additionally the Data ONTAP PowerShell Toolkit must be installed,
##  and PowerShell execution policy set accordingly (RemoteSigned will work.)

## Section 1: Set Up Variables
## Enter the following variables/lists: $cluster,$username,$vserver,$volumes,$daysWorth

$cluster = "192.168.168.40"
$username = "admin"
$vserver = "vs1"
$volumes = "testshare", "testvol2"
$daysWorth = 7

$encrypted = Get-Content c:\scripts\encrypted_password.txt | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($username, $encrypted)

## Section 2: Removing Snapshots
## Note: If you want to test, hash the Remove-NcSnapshot

Import-Module DataOnTap
Connect-NcController $cluster -Credential $credential -Vserver $vserver

echo "The following snapshots are older than $daysWorth days and are being deleted!" ""

foreach ($volume in $volumes){

echo "" "Volume=$volume" ""
$list = Get-NcVol -Name $volume | Get-NcSnapshot | where-object {$_.Created -lt (Get-Date).AddDays(-$daysWorth)}

foreach ($line in $list){

 $snapName = $line
 Remove-NcSnapshot -Volume $volume -Snapshot $snapName -confirm:$false
 echo "$snapName"

 }

}

## STOP COPYING HERE ##

CDOT Snapshot Non-Interactive Deletion Script using Vserver login
Copy the following into Notepad (or - even better - Notepad++) and save as say cdotsnapdel.ps1 and then run using PowerShell:

## START COPYING HERE ##

## CDOT Snapshot Deletor (Non-interactive using Vserver login)
##############################################################
## For the Cluster, Vserver and Volumes specified, it will delete snapshots older than the specified days
## Pre-requisites:
## The file c:\scripts\encrypted_password.txt must have be created first using set-cred.ps1
## Additionally the Data ONTAP PowerShell Toolkit must be installed,
##  and PowerShell execution policy set accordingly (RemoteSigned will work.)

## Section 1: Set Up Variables
## Enter the following variables/lists: $cluster,$username,$vserver,$volumes,$daysWorth

$vserver = "192.168.168.20"
$username = "vsadmin"
$volumes = "testshare", "testvol2"
$daysWorth = 7

$encrypted = Get-Content c:\scripts\encrypted_password.txt | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($username, $encrypted)

## Section 2: Removing Snapshots
## Note: If you want to test, hash the Remove-NcSnapshot

Import-Module DataOnTap
Connect-NcController $vserver -Credential $credential

echo "The following snapshots are older than $daysWorth days and will be deleted!" ""

foreach ($volume in $volumes){

echo "" "Volume=$volume" ""
$list = Get-NcVol -Name $volume | Get-NcSnapshot | where-object {$_.Created -lt (Get-Date).AddDays(-$daysWorth)}

foreach ($line in $list){

 $snapName = $line
 Remove-NcSnapshot -Volume $volume -Snapshot $snapName -confirm:$false
 echo "$snapName"

 }

}

## STOP COPYING HERE ##

Image: An Example of the CDOT Snap Deletor Script in Action