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.0 original release .DESCRIPTION This script will check for the following for a NetApp ONTAP 9.5 or newer cluster. Volume Information: -Aggregate: Must reside on an AFF model. -Thin Provisioned: Volume space guarantee set to none and the space guarantee is enabled. -Encryption at Aggregate Level or Off: Either encryption is disabled or if enabled the volume is set to aggregate encryption-type -Efficiency Enabled: Volume efficiency is on. -Data Compaction Enabled -Compression Enabled -Inline Compression Enabled -Inline Dedupe Enabled -Cross Volume Background Dedupe Enabled -Cross Volume Inline Dedupe Enabled -Schedule Blank: The volume efficiency schedule is set to "-" -Auto Policy: The volume efficiency policy is set to "auto" -Adaptive Compression Type: The volume efficiency compression-type is set to adaptive. -Is Prioritized: The volume has not been deprioritized with the auto policy configuration. -Compression Algorithm: Current algorithm in use for the volume compression. 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 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 Ration in TiB: The "Used Space in TiB" multiplied by the first number in the "Total Data Reduction 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.0 .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.5 or newer cluster. Volume Information: -Aggregate: Must reside on an AFF model. -Thin Provisioned: Volume space guarantee set to none and the space guarantee is enabled. -Encryption at Aggregate Level or Off: Either encryption is disabled or if enabled the volume is set to aggregate encryption-type -Efficiency Enabled: Volume efficiency is on. -Data Compaction Enabled -Compression Enabled -Inline Compression Enabled -Inline Dedupe Enabled -Cross Volume Background Dedupe Enabled -Cross Volume Inline Dedupe Enabled -Schedule Blank: The volume efficiency schedule is set to "-" -Auto Policy: The volume efficiency policy is set to "auto" -Adaptive Compression Type: The volume efficiency compression-type is set to adaptive. -Is Prioritized: The volume has not been deprioritized with the auto policy configuration. -Compression Algorithm: Current algorithm in use for the volume compression. 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 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 Ration in TiB: The "Used Space in TiB" multiplied by the first number in the "Total Data Reduction 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 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 "" } $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 Write-Host "ONTAP version:" $FullONTAPVersion $SegmentOntapVersion = $FullONTAPVersion -split '\.' $FamilyRelease = $SegmentOntapVersion[0] $MajorRelease = $SegmentOntapVersion[1] $MinorRelease = $SegmentOntapVersion[2] #Only run on ONTAP 9.5 or greater If ($FamilyRelease -eq 9 -and $MajorRelease -ge 5) { #Separate AFF and FAS models $CheckNodeModels = Get-NcNodeInfo $AFFNodesArray = @() $FASNodesArray = @() ForEach ($CheckNodeModel in $CheckNodeModels) { 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 a FAS" } $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} #Find all read/write, non-SVM root volumes within the AFF aggregates $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 = @() #Volume information ForEach ($AFFVolume in $AFFVolumes) { #Prepare data to send to Excel $PowerShellObject = New-Object PSCustomObject $Vserver = $AFFVolume.vserver $VolumeName = $AFFVolume.name 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 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 } $SSHCommand = "volume show -fields encryption-type -vserver $Vserver -volume $VolumeName" $EncryptionType = Invoke-NcSsh $SSHCommand $EncryptionType = $EncryptionType.ToString() $EncryptionType = $EncryptionType.Split("`n") $EncryptionType = $EncryptionType[4].ToString() #removes header rows 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 } #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 } $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() $DeprioritizedVolume = $DeprioritizedVolume.Split("`n") $DeprioritizedVolume = $DeprioritizedVolume[4].ToString() #removes header rows 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 } #TODO - 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 } } $WorksheetName = "AFF Volume Efficiency Settings" $WorksheetStyle = New-ExcelStyle -BorderAround Thin -BorderBottom Thin -BorderTop Thin -BorderLeft Thin -BorderRight Thin $RangeTrueFalse = "D:P" #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 = @() #Aggregate information foreach ($AFFAggregate in $AFFAggregates) { #Prepare data to send to Excel $PowerShellObject = New-Object PSCustomObject $PowerShellObject | Add-Member -type NoteProperty -name "Name" -value $AFFAggregate.AggregateName $PowerShellObject | Add-Member -type NoteProperty -name "Node" -value $AFFAggregate.AggrOwnershipAttributes.HomeName $AFFAggregatesEfficiency = $AFFAggregate | Get-NcAggrEfficiency $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 $PowerShellObject | Add-Member -type NoteProperty -name "Total Data Reduction Storage Efficiency Ratio" -value $AFFAggregatesEfficiency.AggrEfficiencyCumulativeInfo.TotalStorageEfficiencyRatio $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) $TotalRatioMultiplier = $AFFAggregatesEfficiency.AggrEfficiencyCumulativeInfo.TotalStorageEfficiencyRatio.Substring(0,$AFFAggregatesEfficiency.AggrEfficiencyCumulativeInfo.TotalStorageEfficiencyRatio.IndexOf(":")) $TotalRatioMultiplier = [decimal]$TotalRatioMultiplier $PowerShellObject | Add-Member -type NoteProperty -name "Effective Capacity of Used Space Multiplied by Total Data Reduction SE Ration in TiB" -value ((($AFFAggregate.AggrSpaceAttributes.SizeTotal)/1024/1024/1024/1024)*$TotalRatioMultiplier) $FullCollectedOutput += $PowerShellObject } $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.5+ systems." -ForegroundColor Red } |