NetAppEfficiencyCheck.ps1

<#
 
.NOTES
 
File name: NetAppEfficiencyCheck.ps1
 
 
.COMPONENT
 
-NetApp PowerShell Toolkit: https://www.powershellgallery.com/packages/NetApp.ONTAP
  
-ImportExcel module: https://www.powershellgallery.com/packages/ImportExcel
 
 
.SYNOPSIS
  
Version:
 
1.4 One more change for aggregate efficiency for changes in ONTAP 9.9
 
1.3 Fixed an issue with previous ONTAP releases that did not support two specific properties
 
1.2 Added check for volume being online
    New column for volume TSSE effiency
    Changed "Total Storage Efficiency Ratio" to be version dependent
  
1.1 Updated to use the correct "Total Data Reduction Storage Efficiency Ratio" value
    Added another worksheet with some basic cluster information
    Changed to support only ONTAP 9.3 and newer
    Increased comments throughout
    Filter out volumes not on data SVMs
    Removed compression algorithm
  
1.0 original release
  
.DESCRIPTION
  
This script will check for the following for a NetApp ONTAP 9.3 or newer cluster. Refer to the following ONTAP release note sections:
-https://library.netapp.com/ecmdocs/ECMLP2492508/html/GUID-2DF34D39-F6E5-4C73-887A-0B10ECF5A5FB.html
-https://library.netapp.com/ecmdocs/ECMLP2492508/html/GUID-2279167C-FF02-4E89-B1AE-16BB668A0F7A.html
  
Volume Information:
-Aggregate: Must reside on an AFF model. Available in all ONTAP versions that support that AFF model.
-Thin Provisioned: Volume space guarantee set to none and the space guarantee is enabled. Available in all ONTAP versions.
-Online: Volume must be online to participate in efficiency savings. Available in all ONTAP versions.
-Encryption at Aggregate Level or Off: Either encryption is disabled or if enabled the volume is set to aggregate encryption-type. Available in ONTAP 9.6 and newer.
-Efficiency Enabled: Volume efficiency is on. Available in all ONTAP versions.
-Data Compaction Enabled: Available in all ONTAP versions.
-Compression Enabled: Available in all ONTAP versions.
-Inline Compression Enabled: Available in all ONTAP versions.
-Inline Dedupe Enabled: Available in all ONTAP versions.
-Cross Volume Background Dedupe Enabled: Available in ONTAP 9.3 and newer.
-Cross Volume Inline Dedupe Enabled: Available in ONTAP 9.3 and newer.
-Schedule Blank: The volume efficiency schedule is set to "-". Corresponds to the policy being set to auto. Available in ONTAP 9.3 and newer.
-Auto Policy: The volume efficiency policy is set to "auto". Available in ONTAP 9.3 and newer.
-Adaptive Compression Type: The volume efficiency compression-type is set to adaptive. Available in all ONTAP versions.
-Is Prioritized: The volume has not been deprioritized with the auto policy configuration. Available in ONTAP 9.3 and newer.
-Temperature Sensitive Storage Efficiency (TSSE): Available in ONTAP 9.8 and newer. Only present on new volumes created under those releases.
  
Aggregate Information:
-Name: The name of the aggregate
-Node: The node where the aggregate resides
-"Total Data Reduction Efficiency Ratio without snapshots and flexclones" or "Total Data Reduction Efficiency Ratio": Displays the storage efficiency ratio of the aggregate
-Volume Data Reduction Storage Efficiency Ratio: Displays the storage efficiency ratio of all the volumes in the aggregate
-Total Storage Efficiency Ratio: Displays the total storage efficiency ratio of the aggregate
-Used Space in TiB: Actual used space measured in TiB
-Total Space in TiB: Total space of aggregate measured in TiB
-Effective Capacity of Used Space Multiplied by Total Data Reduction SE Ratio in TiB: The "Used Space in TiB" multiplied by the first number in the "Total Storage Efficiency Ratio" field.
  
  
.PARAMETER Cluster
The cluster management LIF IP address or resolvable DNS name for the cluster to connect to.
  
.PARAMETER Username
Username to use to connect to the cluster.
  
.PARAMETER Password
Password used to connect to the cluster. This is in clear text. Unavailable if the Username parameter is not passed. If this variable is not provided you will be prompted for the password during the script and it will be obfuscated.
  
.PARAMETER VerboseOutput
See full details of the script action in addition to the Excel file output.
  
  
.EXAMPLE
  
.\NetAppEfficiencyCheck.ps1
  
Running without any parameters will prompt for all necessary values
  
.EXAMPLE
  
.\NetAppEfficiencyCheck.ps1 -Cluster NetApp1 -Username admin -Password MyPassword
  
Connects to the cluster named NetApp1 with the provided credentials.
  
  
#>



<#PSScriptInfo
 
.VERSION 1.4
 
.GUID b1d582ad-fa69-4cc0-99c1-548acfc3e577
 
.AUTHOR Tim McGue
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES NetApp.ONTAP,ImportExcel
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
  
This script will check for the following for a NetApp ONTAP 9.3 or newer cluster. Refer to the following ONTAP release note sections:
-https://library.netapp.com/ecmdocs/ECMLP2492508/html/GUID-2DF34D39-F6E5-4C73-887A-0B10ECF5A5FB.html
-https://library.netapp.com/ecmdocs/ECMLP2492508/html/GUID-2279167C-FF02-4E89-B1AE-16BB668A0F7A.html
  
Volume Information:
-Aggregate: Must reside on an AFF model. Available in all ONTAP versions that support that AFF model.
-Thin Provisioned: Volume space guarantee set to none and the space guarantee is enabled. Available in all ONTAP versions.
-Online: Volume must be online to participate in efficiency savings. Available in all ONTAP versions.
-Encryption at Aggregate Level or Off: Either encryption is disabled or if enabled the volume is set to aggregate encryption-type. Available in ONTAP 9.6 and newer.
-Online: Must be online to participate in efficiency savings. Available in all ONTAP versions.
-Efficiency Enabled: Volume efficiency is on. Available in all ONTAP versions.
-Data Compaction Enabled: Available in all ONTAP versions.
-Compression Enabled: Available in all ONTAP versions.
-Inline Compression Enabled: Available in all ONTAP versions.
-Inline Dedupe Enabled: Available in all ONTAP versions.
-Cross Volume Background Dedupe Enabled: Available in ONTAP 9.3 and newer.
-Cross Volume Inline Dedupe Enabled: Available in ONTAP 9.3 and newer.
-Schedule Blank: The volume efficiency schedule is set to "-". Corresponds to the policy being set to auto. Available in ONTAP 9.3 and newer.
-Auto Policy: The volume efficiency policy is set to "auto". Available in ONTAP 9.3 and newer.
-Adaptive Compression Type: The volume efficiency compression-type is set to adaptive. Available in all ONTAP versions.
-Is Prioritized: The volume has not been deprioritized with the auto policy configuration. Available in ONTAP 9.3 and newer.
-Temperature Sensitive Storage Efficiency (TSSE): Available in ONTAP 9.8 and newer. Only present on new volumes created under those releases.
  
Aggregate Information:
-Name: The name of the aggregate
-Node: The node where the aggregate resides
-Aggregate Data Reduction Storage Efficiency Ratio: Displays the storage efficiency ratio of the aggregate
-Volume Data Reduction Storage Efficiency Ratio: Displays the storage efficiency ratio of all the volumes in the aggregate
-"Total Data Reduction Efficiency Ratio without snapshots and flexclones" or "Total Data Reduction Efficiency Ratio": Displays the storage efficiency ratio of the aggregate
-Used Space in TiB: Actual used space measured in TiB
-Total Space in TiB: Total space of aggregate measured in TiB
-Effective Capacity of Used Space Multiplied by Total Data Reduction SE Ratio in TiB: The "Used Space in TiB" multiplied by the first number in the "Total Storage Efficiency Ratio" field.
  
#>
 

#region Parameters and Variables
[CmdletBinding(PositionalBinding=$False)]
Param(

  [Parameter(Mandatory=$False)]
   [string]$Cluster,

  [Parameter(Mandatory=$False)]
   [string]$Username,

  [Parameter(Mandatory=$False)]
   [string]$Password,

  [Parameter(Mandatory=$False)]
   [switch]$VerboseOutput

)

#Import modules
If (-Not (Get-Module NetApp.ONTAP)) {

    Import-Module NetApp.ONTAP

}

If (-Not (Get-Module ImportExcel)) {

    Import-Module ImportExcel

}

#endregion

#region Main Body
If (!$VerboseOutput) {

    $VerboseChoice = $host.ui.PromptForChoice("Do you wish to see verbose output?","Please select full or summary",[System.Management.Automation.Host.ChoiceDescription[]]("&Full","&Summary"),1)

    Switch ($VerboseChoice) {

        0 {$VerboseOutputSelection = $true}

        1 {$VerboseOutputSelection = $false}

    }

} else {

    $VerboseOutputSelection = $true

}

#Connect to the cluster
If ($Cluster.Length -eq 0) {

    $Cluster = Read-host "Enter the cluster management LIF DNS name or IP address"

}

$Cluster = $Cluster.Trim()

If ($Username.Length -eq 0) {

    $Username = ""

}

If ($Password.Length -eq 0) {

    $SecurePassword = ""

} else {

    $SecurePassword = New-Object -TypeName System.Security.SecureString

    $Password.ToCharArray() | ForEach-Object {$SecurePassword.AppendChar($_)}

}

#Preparing credential object to pass
If ($Username.Length -ne 0 -and $SecurePassword.Length -ne 0) {

    $Credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $Username, $SecurePassword

} else {

    $Credentials = $Username

}

Write-Host "Attempting connection to $Cluster"

$ClusterConnection = Connect-NcController -name $Cluster -Credential $Credentials

#Only proceeding with valid connection to cluster
If (!$ClusterConnection) {

    Write-Host "Unable to connect to NetApp cluster, please ensure all supplied information is correct and try again" -ForegroundColor Yellow

    Exit        

}

#Get basic information
$Nodes = Get-NcNode

$NumberOfNodes = $Nodes.Length

$Vservers = Get-NcVserver

$DataVservers = Get-NcVserver | Where-Object {$_.VserverType -eq "data"}

$ONTAPIFullVersion = Get-NcSystemOntapiVersion

$ClusterInformation = Get-NcCluster

$NodeInformation = Get-NcNode

$ExecutionDate = Get-Date

$DateStamp = get-date -uformat "%Y-%m-%d@%H-%M-%S"

$Global:OutputFile = $ClusterInformation.ClusterName + "_" + $DateStamp + ".xlsx"

$OntapVersonInfo = Get-NcSystemVersionInfo

$FullOTAPVersionDetails = $OntapVersonInfo.Version

$FullOTAPVersionDetails = $FullOTAPVersionDetails.ToString()

$FullONTAPVersion = $OntapVersonInfo.VersionTuple

$SegmentOntapVersion = $FullONTAPVersion -split '\.'

$FamilyRelease = $SegmentOntapVersion[0]

$MajorRelease = $SegmentOntapVersion[1]

$MinorRelease = $SegmentOntapVersion[2]

If ($VerboseOutputSelection) {

    Write-Host "Execution date and time:" $ExecutionDate

    Write-Host "Working with cluster:" $ClusterInformation.ClusterName

    Write-Host "With serial number of:" $ClusterInformation.ClusterSerialNumber

    Write-Host "Which contains the following Nodes:" $NodeInformation.Node

    Write-Host "With serial numbers of:" $NodeInformation.NodeSerialNumber

    Write-Host "ONTAP version:" $FullONTAPVersion

    Write-Host ""

}

Write-Host "Retrieving efficiency details"

$FullCollectedOutput = @()

#Worksheet #1 - Basic cluster information

#Prepare data to send to Excel
$PowerShellObject = New-Object PSCustomObject

$PowerShellObject | Add-Member -type NoteProperty -name "Cluster Name" -value $ClusterInformation.ClusterName

$PowerShellObject | Add-Member -type NoteProperty -name "Node Names" -value $NodeInformation.Node

$PowerShellObject | Add-Member -type NoteProperty -name "Node Serial Numbers" -value $NodeInformation.NodeSerialNumber.ToString()

$PowerShellObject | Add-Member -type NoteProperty -name "ONTAP Version" -value $FullONTAPVersion

$PowerShellObject | Add-Member -type NoteProperty -name "Execution date and time" -value $ExecutionDate

$FullCollectedOutput += $PowerShellObject

$WorksheetName = "Basic Cluster Info"

$WorksheetStyle = New-ExcelStyle -BorderAround Thin -BorderBottom Thin -BorderTop Thin -BorderLeft Thin -BorderRight Thin

$FullCollectedOutput | Export-Excel -Path $Global:OutputFile -WorkSheetname $WorksheetName -BoldTopRow -AutoSize -FreezeTopRow -FreezeFirstColumn -AutoFilter -Style $WorksheetStyle

#Only run on ONTAP 9.3 or greater
If ($FamilyRelease -eq 9 -and $MajorRelease -ge 3) {

    #Separate AFF and FAS models
    $CheckNodeModels = Get-NcNodeInfo

    $AFFNodesArray = @()

    $FASNodesArray = @()

    ForEach ($CheckNodeModel in $CheckNodeModels) {

        #All AFF models will include AFF as part of the model name
        If ($CheckNodeModel.SystemModel.contains("AFF")) {

            If ($VerboseOutputSelection) {

                Write-Host "Node" $CheckNodeModel.SystemName "is an AFF"

            }

            $AFFNodesArray += $CheckNodeModel.SystemName

        } else {

            If ($VerboseOutputSelection) {

                Write-Host "Node" $CheckNodeModel.SystemName "is not an AFF"

            }

            #The only potential risk here is that other systems exist such as SIM systems or SELECT; however, currently the script is only checking AFF efficiency
            $FASNodesArray += $CheckNodeModel.SystemName

        }

    }

    #Get all the data aggregates of the AFF nodes
    $AFFAggregates = Get-NcAggr | Where-Object {$_.AggrRaidAttributes.HasLocalRoot -eq $false -and $AFFNodesArray -contains $_.Nodes}

    Write-Host "Collecting volume information"

    #Find all read/write, non-SVM root volumes within the AFF aggregates that belong to data SVMs
    $AFFVolumes = Get-NcVol | Where-Object {$AFFAggregates.AggregateName -contains $_.Aggregate -and $_.VolumeStateAttributes.IsVserverRoot -eq $False -and $_.VolumeIdAttributes.Type -eq "rw"}

    #Data to export to Excel
    $FullCollectedOutput = @()

    #Worksheet #2 - Volume information
    ForEach ($AFFVolume in $AFFVolumes) {

        $Vserver = $AFFVolume.Vserver

        $VolumeName = $AFFVolume.name

        #Skip any volumes on the admin SVM or data-protection SVM
        $VserverCheck = Get-NcVserver | Where-Object {$_.VserverType -eq "data" -and $_.VserverName -eq $Vserver}        

        If ($VserverCheck.count -gt 0) {

            #Prepare data to send to Excel
            $PowerShellObject = New-Object PSCustomObject

            If ($VerboseOutputSelection) {

                Write-Host "Working with volume" $VolumeName "on SVM" $Vserver

            }

            $PowerShellObject | Add-Member -type NoteProperty -name "Volume" -value $VolumeName

            $PowerShellObject | Add-Member -type NoteProperty -name "SVM" -value $Vserver

            $PowerShellObject | Add-Member -type NoteProperty -name "Aggregate" -value $AFFVolume.Aggregate

            #Both of these values must be set as shown for it to be truly thin provisioned
            If ($AFFVolume.VolumeSpaceAttributes.SpaceGuarantee -eq "none" -and $AFFVolume.VolumeSpaceAttributes.IsSpaceGuaranteeEnabled -eq $true) {

                $PowerShellObject | Add-Member -type NoteProperty -name "Thin Provisioned" -value $true

            } else {

                $PowerShellObject | Add-Member -type NoteProperty -name "Thin Provisioned" -value $false

            }

            #Volume must be online
            If ($AFFVolume.state -eq "online") {

                $PowerShellObject | Add-Member -type NoteProperty -name "Online" -value $true

            } else {

                $PowerShellObject | Add-Member -type NoteProperty -name "Online" -value $false

            }

            #NetApp Aggregate Encryption (NAE was introduced in ONTAP 9.6)
            If ($FamilyRelease -eq 9 -and $MajorRelease -ge 6) {

                #Not available in properties so grabbing from sSH command
                $SSHCommand = "volume show -fields encryption-type -vserver $Vserver -volume $VolumeName"    

                $EncryptionType = Invoke-NcSsh $SSHCommand  

                $EncryptionType = $EncryptionType.ToString()

                $EncryptionType = $EncryptionType.Split("`n")

                #removes header rows, extra row in 9.5+ because of "last login" information
                $EncryptionType = $EncryptionType[4]

                #results are vserver, volume, value
                $EncryptionType = $EncryptionType  -split '\s+'

                $EncryptionType = $EncryptionType[2].ToString()

                If ($EncryptionType.Contains("aggregate") -or $EncryptionType.Contains("none")) {

                    $PowerShellObject | Add-Member -type NoteProperty -name "Encryption at Aggregate Level or Off" -value $true

                } else {

                    $PowerShellObject | Add-Member -type NoteProperty -name "Encryption at Aggregate Level or Off" -value $false

                }

            } else {

                $PowerShellObject | Add-Member -type NoteProperty -name "Encryption at Aggregate Level or Off" -value "FALSE - NAE not availabe in $FullONTAPVersion"

            }

            #Get efficiency information for all matching AFF volumes
            $AFFVolumeEfficiency = $AFFVolume | Get-NcSis

            If ($AFFVolumeEfficiency.State -eq "Enabled") {

                $PowerShellObject | Add-Member -type NoteProperty -name "Efficiency Enabled" -value $true

            } else {

                $PowerShellObject | Add-Member -type NoteProperty -name "Efficiency Enabled" -value $False

            }

            $PowerShellObject | Add-Member -type NoteProperty -name "Data Compaction Enabled" -value $AFFVolumeEfficiency.IsDataCompactionEnabled

            $PowerShellObject | Add-Member -type NoteProperty -name "Compression Enabled" -value $AFFVolumeEfficiency.IsCompressionEnabled

            $PowerShellObject | Add-Member -type NoteProperty -name "Inline Compression Enabled" -value $AFFVolumeEfficiency.IsInlineCompressionEnabled

            $PowerShellObject | Add-Member -type NoteProperty -name "Inline Dedupe Enabled" -value $AFFVolumeEfficiency.IsInlineDedupeEnabled

            $PowerShellObject | Add-Member -type NoteProperty -name "Cross Volume Background Dedupe Enabled" -value $AFFVolumeEfficiency.IsCrossVolumeBackgroundDedupeEnabled

            $PowerShellObject | Add-Member -type NoteProperty -name "Cross Volume Inline Dedupe Enabled" -value $AFFVolumeEfficiency.IsCrossVolumeInlineDedupeEnabled

            If ($AFFVolumeEfficiency.Schedule -eq "-") {

                $PowerShellObject | Add-Member -type NoteProperty -name "Schedule Blank" -value  $true

            } else {

                $PowerShellObject | Add-Member -type NoteProperty -name "Schedule Blank" -value  $False

            }

            If ($AFFVolumeEfficiency.Policy -eq "auto") {

                $PowerShellObject | Add-Member -type NoteProperty -name "Auto Policy" -value  $true

            } else {

                $PowerShellObject | Add-Member -type NoteProperty -name "Auto Policy" -value  $False

            }

            If ($AFFVolumeEfficiency.CompressionType -eq "adaptive") {

                $PowerShellObject | Add-Member -type NoteProperty -name "Adaptive Compression Type" -value $true

            } else {

                $PowerShellObject | Add-Member -type NoteProperty -name "Adaptive Compression Type" -value $False

            }

            #auto-state will show if a volume is deprioritized, only available in diagnostic mode so have to get it through SSH
            $SSHCommand = "set -privilege diagnostic -confirmations off;volume efficiency show -fields auto-state -vserver $Vserver -volume $VolumeName;set -privilege admin -confirmations on"    

            $DeprioritizedVolume = Invoke-NcSsh $SSHCommand  

            $DeprioritizedVolume = $DeprioritizedVolume.ToString()

            If ($DeprioritizedVolume.Contains("There are no entries matching your query.")) {

                $PowerShellObject | Add-Member -type NoteProperty -name "Is Prioritized" -value $False

            } else {

                $DeprioritizedVolume = $DeprioritizedVolume.Split("`n")

                #removes header rows, extra row in 9.5+ because of "last login" information, this requires an extra line becuase of the first diag command
                If ($FamilyRelease -eq 9 -and $MajorRelease -ge 5) {

                    $DeprioritizedVolume = $DeprioritizedVolume[5] 

                } else {

                    $DeprioritizedVolume = $DeprioritizedVolume[4] 

                }                

                #results are vserver, volume, value
                $DeprioritizedVolume = $DeprioritizedVolume -split '\s+'

                $DeprioritizedVolume = $DeprioritizedVolume[2].ToString()

                If ($DeprioritizedVolume.Contains("Deprioritized")) {

                    $PowerShellObject | Add-Member -type NoteProperty -name "Is Prioritized" -value $False

                } else {

                    $PowerShellObject | Add-Member -type NoteProperty -name "Is Prioritized" -value $true

                }

            }

            #Temperature Sensitive Storage Efficiency (TSSE was introduced in ONTAP 9.8)
            If ($FamilyRelease -eq 9 -and $MajorRelease -ge 8) {

                #Not available in properties so grabbing from sSH command
                $SSHCommand = "set -privilege diagnostic -confirmations off;volume efficiency show -fields using-auto-adaptive-compression -vserver $Vserver -volume $VolumeName;set -privilege admin -confirmations on"   

                $AutoAdaptiveCompression = Invoke-NcSsh $SSHCommand  

                $AutoAdaptiveCompression = $AutoAdaptiveCompression.ToString()

                If ($AutoAdaptiveCompression.Contains("There are no entries matching your query.")) {

                    $PowerShellObject | Add-Member -type NoteProperty -name "Temperature Sensitive Storage Efficiency" -value $False

                } else {

                    $AutoAdaptiveCompression = $AutoAdaptiveCompression.Split("`n")

                    #removes header rows, extra row in 9.5+ because of "last login" information, this requires an extra line becuase of the first diag command
                    $AutoAdaptiveCompression = $AutoAdaptiveCompression[5]

                    $AutoAdaptiveCompression = $AutoAdaptiveCompression -split '\s+'

                    #results are vserver, volume, value
                    $AutoAdaptiveCompression = $AutoAdaptiveCompression[2].ToString()

                    if ($AutoAdaptiveCompression -eq "true") {

                        $PowerShellObject | Add-Member -type NoteProperty -name "Temperature Sensitive Storage Efficiency" -value $true

                    } else {

                        $PowerShellObject | Add-Member -type NoteProperty -name "Temperature Sensitive Storage Efficiency" -value $False

                    }

                }

            } else {

                $PowerShellObject | Add-Member -type NoteProperty -name "Temperature Sensitive Storage Efficiency" -value "FALSE - TSSE not availabe in $FullONTAPVersion"

            }

            <# Removing compression algorithm. The footprint for the issue is very small (A400 model with non-recommended ONTAP releases) and the only way to change is through diagnostic mode. This is for the corresponding support bulletin which has been fixed in all recommended releases: https://kb.netapp.com/Support_Bulletins/Customer_Bulletins/SU443
            $PowerShellObject | Add-Member -type NoteProperty -name "Compression Algorithm" -value $AFFVolumeEfficiency.CompressionAlgorithm
            #>


            $FullCollectedOutput += $PowerShellObject

            If ($VerboseOutputSelection) {

                Write-Host ($PowerShellObject | Format-List | Out-String)

                Write-Host

            }

        } else {

            If ($VerboseOutputSelection) {

                Write-Host "Volume" $VolumeName "is not on a data SVM"

            }

        }

    }

    $WorksheetName = "AFF Volume Efficiency Settings"

    $WorksheetStyle = New-ExcelStyle -BorderAround Thin -BorderBottom Thin -BorderTop Thin -BorderLeft Thin -BorderRight Thin

    $RangeTrueFalse = "D:R"

    #Highlight anything that is false
    $FullCollectedOutput | Export-Excel -Path $Global:OutputFile -WorkSheetname $WorksheetName -BoldTopRow -AutoSize -FreezeTopRow -FreezeFirstColumn -AutoFilter -Numberformat "#,##0" -Style $WorksheetStyle -ConditionalText $(
            New-ConditionalText -Range $RangeTrueFalse -ConditionalType ContainsText FALSE -ConditionalTextColor black -BackgroundColor red) 

    $FullCollectedOutput = @()

    Write-Host "Collecting aggregate information"

    #Worksheet #3 - Aggregate information
    foreach ($AFFAggregate in $AFFAggregates) {

        #Prepare data to send to Excel
        $PowerShellObject = New-Object PSCustomObject

        $AggregateName = $AFFAggregate.AggregateName

        $AggregateHome = $AFFAggregate.AggrOwnershipAttributes.HomeName

        $PowerShellObject | Add-Member -type NoteProperty -name "Name" -value $AggregateName

        $PowerShellObject | Add-Member -type NoteProperty -name "Node" -value $AggregateHome

        $AFFAggregatesEfficiency =  $AFFAggregate | Get-NcAggrEfficiency

        #These next three data reduction values excludes snapshot savings
        $PowerShellObject | Add-Member -type NoteProperty -name "Aggregate Data Reduction Storage Efficiency Ratio" -value $AFFAggregatesEfficiency.AggrEfficiencyAggrInfo.AggrDataReductionStorageEfficiencyRatio

        $PowerShellObject | Add-Member -type NoteProperty -name "Volume Data Reduction Storage Efficiency Ratio" -value $AFFAggregatesEfficiency.AggrEfficiencyVolumeInfo.VolumeDataReductionStorageEfficiencyRatio

        #ONTAP 9.9 and newer uses "Total Data Reduction Efficiency Ratio without snapshots and flexclones" and previous releases use "Total Data Reduction Efficiency Ratio"
        If ($FamilyRelease -eq 9 -and $MajorRelease -ge 9) {

            #Not available in properties so grabbing from sSH command
            $SSHCommand = "storage aggregate show-efficiency -fields total-data-reduction-efficiency-ratio-wo-snapshots-flexclones -aggregate $AggregateName -node $AggregateHome"

            $TotalRatio = Invoke-NcSsh $SSHCommand  

            $TotalRatio = $TotalRatio.ToString()

            $TotalRatio = $TotalRatio.Split("`n")

            #removes header rows, extra row in 9.5+ because of "last login" information
            $TotalRatio = $TotalRatio[4]

            #results are aggregate, value
            $TotalRatio = $TotalRatio -split '\s+'

            $TotalRatio = $TotalRatio[1].ToString()

            $PowerShellObject | Add-Member -type NoteProperty -name "Total Data Reduction Efficiency Ratio without snapshots and flexclones" -value $TotalRatio

        } else {

            $TotalRatio = $AFFAggregatesEfficiency.AggrEfficiencyCumulativeInfo.TotalDataReductionEfficiencyRatio

            $PowerShellObject | Add-Member -type NoteProperty -name "Total Data Reduction Efficiency Ratio" -value $TotalRatio

        }        

        #Change the size to Tebibytes
        $PowerShellObject | Add-Member -type NoteProperty -name "Used Space in TiB" -value (($AFFAggregate.AggrSpaceAttributes.SizeUsed)/1024/1024/1024/1024)

        $PowerShellObject | Add-Member -type NoteProperty -name "Total Space in TiB" -value (($AFFAggregate.AggrSpaceAttributes.SizeTotal)/1024/1024/1024/1024)

        #This will get the first number in the total data reduction efficiency ratio. For instance 2.84:1 it will retrieve just "2.84"
        $TotalRatioMultiplier = $TotalRatio.Substring(0,$TotalRatio.IndexOf(":"))

        $TotalRatioMultiplier = [decimal]$TotalRatioMultiplier

        #This is the effective capacity after space savings. For instance if the used size is 10TiB and the total data reduction efficiency ratio is 2.84:1 this would be 28.4 TiB
        $PowerShellObject | Add-Member -type NoteProperty -name "Effective Capacity of Used Space Multiplied by Total Data Reduction SE Ratio in TiB" -value ((($AFFAggregate.AggrSpaceAttributes.SizeUsed)/1024/1024/1024/1024)*$TotalRatioMultiplier)

        $FullCollectedOutput += $PowerShellObject

        If ($VerboseOutputSelection) {

            Write-Host ($PowerShellObject | Format-List | Out-String)

            Write-Host

        }

    }

    $WorksheetName = "AFF Aggregate Efficiency Info"

    $WorksheetStyle = New-ExcelStyle -BorderAround Thin -BorderBottom Thin -BorderTop Thin -BorderLeft Thin -BorderRight Thin

    $FullCollectedOutput | Export-Excel -Path $Global:OutputFile -WorkSheetname $WorksheetName -BoldTopRow -AutoSize -FreezeTopRow -FreezeFirstColumn -AutoFilter -Numberformat "#,##0.0000" -Style $WorksheetStyle

    Write-Host

    Write-Host "See output in file:" $Global:OutputFile

} else {

       Write-Host "This script is only available for ONTAP 9.3+ clusters." -ForegroundColor Red

}