Examples/New-PfaStatusReport.ps1

function New-PfaStatusReport {
    param ( 
        [Parameter(Mandatory = $true, ParameterSetName = 'NewConnection', Position = 0)]
        [String]$Array,
        [Parameter(Mandatory = $true, ParameterSetName = 'NewConnection', Position = 1)]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential,

        [Parameter(Mandatory = $true, ParameterSetName = 'ExistingConnection', Position = 0)]
        [ValidateNotNullOrEmpty()]
        [PureStorageRestApi]$Connection,

        [Parameter()][ValidateSet("All", "Capacity", "Overview", "Health", "Latency", "IOPS", "Bandwidth", "Replication")]
        [String[]]$IncludeCharts = "None",
        [Switch]$SkipVolumesReport,
        [String]$DataFolder = $env:APPDATA + "\PureStorage",
        [Switch]$SendEmail = $false,
        [Switch]$SaveAsHTML = $false,
        [Switch]$SaveCharts = $false,
        [String]$FromAddress = "First.Last@domain.com",
        [String]$RecipientAddress = "recipient@domain.com",
        [String]$SMTPServer = "",
        [Int32]$SMTPPort = 25
        )

    begin {
        $StartTime = Get-Date
        $MyCSS = '
        body {
            color: #333333;
            font-family: Calibri,Tahoma,Arial,Verdana;
            font-size: 11pt;
        }
        h3 {
            margin-top: 0px;
            margin-bottom: 5px;
            text-align: left;
        }
        h4 {
            margin-top: 10px !important;
            margin-bottom: 10px !important;
        }
        table {
            border-collapse: collapse;
        }
        table#volumes {
            width: 100%;
        }
        table#volumes tfoot tr th {
            border: none !important;
            background-color: transparent;
            color: #333333;
        }
        th {
            text-align: center;
            font-weight: bold;
            color: #ffffff;
            background-color: #444444;
            padding: 5px;
            white-space: nowrap;
            border-top: 1px solid black;
            border-bottom: 1px solid black;
        }
        th.col-0 {
            text-align: left;
            border-left: 1px solid black;
        }
        th.single-col {
            border-left: 1px solid black;
            border-right: 1px solid black;
            text-align: left;
        }
        th.instant-data {
            text-align: right;
            border-right: 1px solid black;
        }
        table#info th.col-4 {
            border-right: 1px solid black;
        }
        table#volumes th {
            border: none;
        }
        table#volumes th.col-0 {
            border-left: 1px solid black;
        }
        table#volumes th.col-15 {
            border-right: 1px solid black;
        }
        td {
            padding: 5px;
            border: 1px solid black;
            text-align: center;
            white-space: nowrap;
        }
        td.col-0 {
            text-align: left;
        }
        ul {
            margin-top: 5px;
        }
        .odd {
            background-color:#ffffff;
        }
        .even {
            background-color:#e6e6e6;
        }'

        # Define parameters array for the "Growth" columns
        $paramsPercentChanged = @{ 
            # Test criteria: Is value a positive percent?
            ScriptBlock = {([string]$args[0] -ne "n/a" -and [string]$args[0] -ne "0.00 %") -and -not ([string]$args[0]).StartsWith("-")}
            # CSS attribute to add if ScriptBlock is true
            CSSAttribute = "style"
        }
        # Define parameters array for the "Growth" columns
        $paramsPercentChangedNegative = @{ 
            # Test criteria: Is value a positive percent?
            ScriptBlock = {([string]$args[0]).StartsWith('-')}  
            # CSS attribute to add if ScriptBlock is true
            CSSAttribute = "style"
        }
        # Define parameters array for the "Utilization" column
        $paramsUtilization = @{ 
            # Column name
            Column = "Utilization"
            # Test criteria: Is value greater than or equal to Argument?
            ScriptBlock = {[double]$args[0] -ge [double]$args[1]}  
            # CSS attribute to add if ScriptBlock is true
            CSSAttribute = "style"
            # Format column with 2 decimal places and add a percent symbol
            StringFormat = "{0:N2} %"
        }
        function Get-PercentChanged {
            [CmdletBinding()]
            param (
                [Parameter(Mandatory = $true, Position = 0)]
                [double]$Reference,
                [Parameter(Mandatory = $true, Position = 1)]
                [double]$Difference
            )
            if (($null -ne $Reference -and $Reference -ne 0) -and ($null -ne $Difference -and $Difference -ne 0)) {
                $Result = [math]::Round((($Difference - $Reference) / $Reference * 100), 2, [MidPointRounding]::AwayFromZero)
                if ($Result -ne -0) {
                    "{0:N2} %" -f $Result
                } else {
                    "0.00 %"
                }
            } else {
                "n/a"
            }
        }

        try {
            if ($StartTime.DayOfWeek -ne [Globalization.CultureInfo]::CurrentCulture.DateTimeFormat.FirstDayOfWeek) {
                $Today = $StartTime.Date
                $FirstDayOfWeek = $Today.AddDays(-($Today).DayOfWeek.Value__)
                $StartOfWeekData = Get-Content "$DataFolder\$Array-$($FirstDayOfWeek.ToString("yyyyMMdd")).json" -ErrorAction SilentlyContinue | ConvertFrom-Json
            } else {
                $StartOfWeekData = Get-Content "$DataFolder\$Array-$($StartTime.AddDays(-1).ToString("yyyyMMdd")).json" -ErrorAction SilentlyContinue | ConvertFrom-Json
            }
            if ($StartTime.Day -eq 1) {
                $StartOfMonthData = Get-Content "$DataFolder\$Array-$($StartTime.AddDays(-1).ToString("yyyyMMdd")).json" -ErrorAction SilentlyContinue | ConvertFrom-Json
            } else {
                $StartOfMonthData = Get-Content "$DataFolder\$Array-$($StartTime.ToString("yyyyMM01")).json" -ErrorAction SilentlyContinue | ConvertFrom-Json
            }
            if ($StartTime.Month -eq 1 -and $StartTime.Day -eq 1) {
                $StartOfYearData = Get-Content "$DataFolder\$Array-$($StartTime.AddDays(-1).ToString("yyyyMMdd")).json" -ErrorAction SilentlyContinue | ConvertFrom-Json
            } else {
                $StartOfYearData = Get-Content "$DataFolder\$Array-$($StartTime.ToString("yyyy0101")).json" -ErrorAction SilentlyContinue | ConvertFrom-Json
            }

            if (-not (Test-Path -PathType Container $DataFolder)) {
                New-Item -ItemType Directory -Path $DataFolder -Force -ErrorAction Stop | Out-Null
            }

            if ($PSCmdlet.ParameterSetName -eq 'NewConnection') {
                try {
                    $Connection = Connect-PfaApi -ArrayName $Array -Credential $Credential -SkipCertificateCheck -ErrorAction Stop
                } catch {
                    Write-Error $_.Exception.Message
                }
            }

            $ArrayAttributes = Invoke-PfaApiRequest -Array $Connection -Request RestMethod -Method GET -Path "/array" -ApiVersion 1 -SkipCertificateCheck -ErrorAction Stop | Select-Object array_name, version, revision, id
            if (-not (($Connection.ApiVersion[2].Minor | Select-Object -Last 1) -gt 1)) {
                $ArrayAttributes | Add-Member -MemberType NoteProperty -Name model -Value (Invoke-PfaApiRequest -Array $Connection -Request RestMethod -Method GET -Path "/array?controllers=true" -ApiVersion 1.18 -SkipCertificateCheck -ErrorAction Stop | Select-Object -Unique -Property model).model
            } else {
                $ArrayAttributes | Add-Member -MemberType NoteProperty -Name model -Value (Invoke-PfaApiRequest -Array $Connection -Request RestMethod -Method GET -Path "/controllers" -SkipCertificateCheck -ErrorAction Stop | Select-Object -Unique -Property model).model
            }

            $PfaVolumes = Invoke-PfaApiRequest -Array $Connection -Request RestMethod -Method GET -Path "/volumes" -SkipCertificateCheck -ErrorAction Stop | Where-Object {$_.Name -ne 'pure-protocol-endpoint'} | ForEach-Object {
                $Volume = $_
                $VolumeMetrics = Invoke-PfaApiRequest -Array $Connection -Request RestMethod -Method GET -Path "/volumes/space?names=$($_.Name)" -SkipCertificateCheck -ErrorAction Stop
                $HostConnections = Invoke-PfaApiRequest -Array $Connection -Request RestMethod -Method GET -Path "/connections?volume_names=$($_.Name)" -SkipCertificateCheck -ErrorAction Stop
                [PSCustomObject]@{
                    Name                =   $_.Name
                    Size                =   $_.Provisioned
                    Volumes             =   $VolumeMetrics.Space.Total_Physical
                    Snapshots           =   $VolumeMetrics.Space.Snapshots
                    Reduction           =   $VolumeMetrics.Space.Data_Reduction
                    Shared              =   if ($null -ne $VolumeMetrics.Space.Shared) {
                                                $VolumeMetrics.Space.Shared
                                            } else {
                                                "-"
                                            }
                    System              =   if ($null -ne $VolumeMetrics.Space.System) {
                                                $VolumeMetrics.Space.System
                                            } else {
                                                "-"
                                            }
                    ThinProvisioning    =   $VolumeMetrics.Space.Thin_Provisioning
                    Written             =   ((1 - $VolumeMetrics.Space.Thin_Provisioning) * $VolumeMetrics.Space.Total_Physical)
                    Total               =   $VolumeMetrics.Space.Total_Physical
                    Protected           =   if (-not (Invoke-PfaApiRequest -Array $Connection -Request RestMethod -Method GET -Path "/volume-snapshots?names=$($_.Name)" -SkipCertificateCheck -ErrorAction Stop)) {
                                                "No"
                                            } else {
                                                "Yes"
                                            }
                    Connection          =   if (-not $HostConnections.Host -and -not ($HostConnections.Host_Group)) {
                                                "Not Connected"
                                            } else {
                                                if (($HostConnections.Host_Group.Name | Sort-Object -Unique).Count -gt 0) {
                                                    ($HostConnections.Host_Group | Sort-Object -Unique Name | Select-Object -ExpandProperty Name) -join ", "
                                                } else {
                                                    if (($HostConnections.Host.Name | Sort-Object -Unique).Count -gt 1) {
                                                        ($HostConnections.Host | Sort-Object -Unique Name | Select-Object -ExpandProperty Name) -join ", "
                                                    } else {
                                                        $HostConnections.Host.Name
                                                    }
                                                }
                                            }
                    ChangedThisWeek     =   if ($null -ne $StartOfWeekData.Volumes) {
                                                $PreviousData = $StartOfWeekData.Volumes | Where-Object {$_.Name -eq $Volume.Name}
                                                Get-PercentChanged $PreviousData.Written $((1 - $VolumeMetrics.Space.Thin_Provisioning) * $VolumeMetrics.Space.Total_Physical)
                                            } else {
                                                "n/a"
                                            }
                    ChangedThisMonth    =   if ($null -ne $StartOfMonthData.Volumes) {
                                                $PreviousData = $StartOfMonthData.Volumes | Where-Object {$_.Name -eq $Volume.Name}
                                                Get-PercentChanged $PreviousData.Written $((1 - $VolumeMetrics.space.Thin_Provisioning) * $VolumeMetrics.Space.Total_Physical)
                                            } else {
                                                "n/a"
                                            }
                    ChangedThisYear     =   if ($null -ne $StartOfYearData.Volumes) {
                                                $PreviousData = $StartOfYearData.Volumes | Where-Object {$_.Name -eq $Volume.Name}
                                                Get-PercentChanged $PreviousData.Written $((1 - $VolumeMetrics.Space.Thin_Provisioning) * $VolumeMetrics.Space.Total_Physical)
                                            } else {
                                                "n/a"
                                            }
                }
            }
            if ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Overview") {
                $OverviewMetrics = Get-PfaChartData -Array $Connection -Type Dashboard -ChartName Overview
            }
            if ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Health") {
                $HealthMetrics = Get-PfaChartData -Array $Connection -Type Dashboard -ChartName Health
            }
            if ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Capacity") {
                $SpaceMetrics = Get-PfaChartData -Array $Connection -Type Dashboard -ChartName Capacity
            }
            if ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Latency") {
                try {
                    $IOLatencyMetrics = Get-PfaChartData -Array $Connection -Type Performance -Group Array
                } finally {
                }
            }
            if ($IncludeCharts -contains "All" -or $IncludeCharts -contains "IOPS" -or $IncludeCharts -contains "Bandwidth") {
                try {
                    $IOMetrics = Get-PfaChartData -Array $Connection -Type Performance -Group Array
                } finally {
                }
            }
            if ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Replication") {
                try {
                    $IOReplicationBandwidthMetrics = Get-PfaChartData -Array $Connection -Type Replication -Group Array -Historical '24h'
                } finally {
                }
            }
        } catch {
            throw $_
        } finally {
            if ($PSCmdlet.ParameterSetName -eq 'NewConnection' -and $null -ne $Connection) {
                Disconnect-PfaApi -Array $Connection -SkipCertificateCheck | Out-Null
            }
        }
    }
    process {
        $ResultsObj = [PSCustomObject]@{
            Attributes  =   $ArrayAttributes
            Volumes     =   $PfaVolumes
            Metrics     =   [PSCustomObject]@{
                                Space       =   $SpaceMetrics
                                IOLatency   =   $IOLatencyMetrics
                                IO          =   $IOMetrics
                                Replication =   $IOReplicationBandwidthMetrics
                            }
            Overview    =   if ($null -ne $OverviewMetrics -and ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Overview")) {
                                New-PfaChart -Type Dashboard -ChartName Overview -ChartData $OverviewMetrics -AsBase64
                            } else {
                                $null
                            }
            Health      =   if ($null -ne $HealthMetrics -and ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Health")) {
                                New-PfaChart -Type Dashboard -ChartName Health -ChartData $HealthMetrics -AsBase64
                            } else {
                                $null
                            }
            Capacity    =   if ($null -ne $SpaceMetrics -and ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Capacity")) {
                                New-PfaChart -Type Dashboard -ChartName Capacity -ChartData $SpaceMetrics -AsBase64
                            } else {
                                $null
                            }
            Latency     =   if ($null -ne $IOLatencyMetrics -and ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Latency")) {
                                New-PfaChart -Type Performance -Group Array -ChartName Latency -ChartData $IOLatencyMetrics -Property "Read","Write" -AsBase64
                            } else {
                                $null
                            }
            IOPS        =   if ($null -ne $IOMetrics-and ($IncludeCharts -contains "All" -or $IncludeCharts -contains "IOPS")) {
                                New-PfaChart -Type Performance -Group Array -ChartName IOPS -ChartData $IOMetrics -AsBase64
                            } else {
                                $null
                            }
            Bandwidth   =   if ($null -ne $IOMetrics -and ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Bandwidth")) {
                                New-PfaChart -Type Performance -Group Array -ChartName Bandwidth -ChartData $IOMetrics -AsBase64
                            } else {
                                $null
                            }
            Replication =   if ($null -ne $IOReplicationBandwidthMetrics -and ($IncludeCharts -contains "All" -or $IncludeCharts -contains "Replication")) {
                                New-PfaChart -Type Performance -Group Array -ChartName Latency -ChartData $IOReplicationBandwidthMetrics -Property "Read","Write" -AsBase64
                            } else {
                                $null
                            }
        }
        if (-not $SaveCharts) {
            $ExcludedProperties = @("Overview", "Health", "Capacity", "Latency", "IOPS", "Bandwidth", "Replication")
        }
        $ResultsObj | Select-Object * -ExcludeProperty $ExcludedProperties | ConvertTo-Json -Depth 5 -Compress | Out-File "$DataFolder\$Array-$(($StartTime).ToString("yyyyMMdd")).json" -Encoding utf8 -ErrorAction SilentlyContinue

        if (-not $SkipVolumesReport) {
            $Volumes = $PfaVolumes |
                Sort-Object Name | ForEach-Object {
                    $VolumeObj = [PSCustomObject]@{
                        Name                =   $_.Name
                        Size                =   Format-Byte $_.Size
                        Volumes             =   Format-Byte $_.Volumes
                        Utilization         =   (($_.Volumes / $_.Size) * 100)
                        Snapshots           =   Format-Byte $_.Snapshots
                        Reduction           =   "{0:N2} to 1" -f $_.Reduction
                        Shared              =   Invoke-Command -Command {
                                                    if ($_.Shared -ne "-") {
                                                        Format-Byte $_.Shared
                                                    } else {
                                                        "-"
                                                    }
                                                }
                        System              =   Invoke-Command -Command {
                                                    if ($_.System -ne "-") {
                                                        Format-Byte $_.System
                                                    } else {
                                                        "-"
                                                    }
                                                }
                        Total               =   Format-Byte $_.Total
                        "Thin Provisioning" =   "{0:N3}" -f $_.ThinProvisioning
                        Written             =   Format-Byte $_.Written
                        Protected           =   $_.Protected
                        "Connection(s)"     =   $_.Connection
                    }
                    if ($null -ne $StartOfWeekData.Volumes) {
                        $VolumeObj | Add-Member -MemberType NoteProperty -Name "This Week" -Value $_.ChangedThisWeek
                    }
                    if ($null -ne $StartOfMonthData.Volumes) {
                        $VolumeObj | Add-Member -MemberType NoteProperty -Name "This Month" -Value $_.ChangedThisMonth
                    }
                    if ($null -ne $StartOfYearData.Volumes) {
                        $VolumeObj | Add-Member -MemberType NoteProperty -Name "This Year" -Value $_.ChangedThisYear
                    }
                    $VolumeObj
            }
        }
        if ($SendEmail -or $SaveAsHTML) {
            $HTMLCharts = ""
            
            if (-not $SkipVolumesReport) {
                if ($null -ne $StartOfWeekData.Volumes) {
                    if ($null -eq $StartOfMonthData.Volumes -and $null -eq $StartOfYearData.Volumes) {
                        $MyCSS += '
                            table#volumes th.col-13 {
                                border-right: 1px solid black;
                                border-left: 1px solid #dddddd;
                            }
                        '

                    }
                } else {
                    $MyCSS += '
                        table#volumes th.col-12 {
                            border-right: 1px solid black;
                        }
                        table#volumes th {
                            border-top: 1px solid black;
                        }
                    '

                }
                if ($null -ne $StartOfMonthData.Volumes) {
                    if ($null -eq $StartOfYearData.Volumes) {
                        $MyCSS += '
                            table#volumes th.col-13 {
                                border-left: 1px solid #dddddd;
                            }
                            table#volumes th.col-14 {
                                border-right: 1px solid black;
                            }
                    '

                    } else {
                        $MyCSS += '
                            table#volumes th.col-13 {
                                border-left: 1px solid #dddddd;
                            }
                        '

                    }
                }
            }
            if ($null -ne $ResultsObj.Overview) {
                $HTMLCharts += "<table><tr><th class=""single-col"">Overview</th></tr><tr><td><img src=""data:image/png;charset=utf-8;base64,$($ResultsObj.Overview)""></img></td></tr></table><br/>"
            }
            if ($null -ne $ResultsObj.Capacity) {
                $HTMLCharts += "<table><tr><th class=""single-col"">Capacity</th></tr><tr><td><img src=""data:image/png;charset=utf-8;base64,$($ResultsObj.Capacity)""></img></td></tr></table><br/>"
            }
            if ($null -ne $ResultsObj.Health) {
                $HTMLCharts += "<table><tr><th class=""single-col"">Health</th></tr><tr><td><img src=""data:image/png;charset=utf-8;base64,$($ResultsObj.Health)""></img></td></tr></table><br/>"
            }
            if ($null -ne $ResultsObj.Latency) {
                $HTMLCharts += "<table><tr><th class=""col-0"">Latency</th><th class=""instant-data""><span style=""color: #0d98e3;"">R</span> $("{0:N2}" -f ($ResultsObj.Metrics.IOLatency[$ResultsObj.Metrics.IOLatency.Count - 1].Usec_Per_Read_Op / 1000)) ms | <span style=""color: #f37430;"">W</span> $("{0:N2}" -f ($ResultsObj.Metrics.IOLatency[$ResultsObj.Metrics.IOLatency.Count - 1].Usec_Per_Write_Op / 1000)) ms | <span style=""color: #50ae54;"">Q</span> $("{0:N2}" -f ($ResultsObj.Metrics.IOLatency[$ResultsObj.Metrics.IOLatency.Count - 1].Queue_Usec_Per_Write_Op / 1000)) ms</th></tr><tr><td colspan=""2""><img src=""data:image/png;charset=utf-8;base64,$($ResultsObj.Latency)""></img></td></tr></table><br/>"
            }
            if ($null -ne $ResultsObj.IOPS) {
                $HTMLCharts += "<table><tr><th class=""col-0"">IOPS</th><th class=""instant-data""><span style=""color: #0d98e3;"">R</span> $("{0:N2}" -f ($ResultsObj.Metrics.IO[$ResultsObj.Metrics.IO.Count - 1].Reads_Per_Sec / 1000)) K | <span style=""color: #f37430;"">W</span> $("{0:N2}" -f ($ResultsObj.Metrics.IO[$ResultsObj.Metrics.IO.Count - 1].Writes_Per_Sec / 1000)) K</th></tr><tr><td colspan=""2""><img src=""data:image/png;charset=utf-8;base64,$($ResultsObj.IOPS)""></img></td></tr></table><br/>"
            }
            if ($null -ne $ResultsObj.Bandwidth) {
                $HTMLCharts += "<table><tr><th class=""col-0"">Bandwidth</th><th class=""instant-data""><span style=""color: #0d98e3;"">R</span> $(Format-Byte -Bytes $ResultsObj.Metrics.IO[$ResultsObj.Metrics.IO.Count - 1].Output_Per_Sec -Suffix "/s") | <span style=""color: #f37430;"">W</span> $(Format-Byte -Bytes $ResultsObj.Metrics.IO[$ResultsObj.Metrics.IO.Count - 1].Input_Per_Sec -Suffix "/s")</th></tr><tr><td colspan=""2""><img src=""data:image/png;charset=utf-8;base64,$($ResultsObj.Bandwidth)""></img></td></tr></table><br/>"
            }
            if ($null -ne $ResultsObj.Replication) {
                $HTMLCharts += "<table><tr><th class=""col-0"">Replication</th><th class=""instant-data""><span style=""color: #0d98e3;"">T</span> $(Format-Byte -Bytes ($ResultsObj.Metrics.Replication | Group-Object Time | Select-Object -Last 1 -ExpandProperty Group | Measure-Object -Sum Bytes_Per_Sec).Sum -Suffix "/s")</th></tr><tr><td colspan=""2""><img src=""data:image/png;charset=utf-8;base64,$($ResultsObj.Replication)""></img></td></tr></table><br/>"
            }
            
            if (Get-Module -Name "PS2HTMLTable") {
                $HTML = New-HTMLHead -Style $MyCSS -Title "$Array - Status Report"
                $HTML += "<h3>Array Information</h3>"
                $HTML += '<table id="container" cellpadding="0" cellspacing="0"><tr><td style="border: none; text-align: left;">'
                $HTMLTable = $ArrayAttributes | Select-Object @{Name = "Name";Expression = {$_.Array_Name}},
                                                              @{Name = "Purity//FA";Expression = {$_.Version}},
                                                              @{Name = "Revision";Expression = {$_.Revision}},
                                                              @{Name = "ID";Expression = {$_.Id}},
                                                              @{Name = "Model";Expression = {$_.Model}} |
                                                              New-HTMLTable -HTMLDecode -ColumnClassPrefix "col" -TableAttributes @{width = "1186";id = "info"}
                $HTML += $HTMLTable + "<br />"
                $HTML += $HTMLCharts
                if (-not $SkipVolumesReport) {
                    $HTML += "<h3>Volumes ($($Volumes.Count))</h3>"
                    $HTML += '<table id="volumes" cellpadding="0" cellspacing="0" border="0">'
                    if ($null -ne $Volumes[0]."This Week") {
                        $Header = "<tr><th colspan=""13"" style=""border-right: 1px solid #dddddd;border-left: 1px solid black;border-top: 1px solid black;""></th><th colspan=""3"" style=""border-left: 1px solid #dddddd;border-right: 1px solid black;border-top: 1px solid black;"">Growth</th></tr>"
                    }
                    $HTMLTable = $Volumes | New-HTMLTable -HTMLDecode -SetAlternating -ColumnClassPrefix "col" -PrependHeader $Header -NestedTable -AddTableTags
                    $HTMLTable += "<tfoot><tr><th></th><th>$(Format-Byte ($PfaVolumes.Size | Measure-Object -Sum).Sum)</th><th>$(Format-Byte ($PfaVolumes.Volumes | Measure-Object -Sum).Sum)</th><th>$("{0:N2} %" -f (($Volumes.Utilization | Measure-Object -Maximum).Maximum))</th><th>$(Format-Byte ($PfaVolumes.Snapshots | Measure-Object -Sum).Sum)</th><th>$("{0:N2} to 1" -f ($PfaVolumes.Reduction | Measure-Object -Average).Average)</th><th></th><th></th><th>$(Format-Byte ($PfaVolumes.Total | Measure-Object -Sum).Sum)</th><th></th><th>$(Format-Byte ($PfaVolumes.Written | Measure-Object -Sum).Sum)</th><th></th><th></th>$(if ($null -ne $Volumes[0].'This Week') {"<th>{0:N2} %</th>" -f (($Volumes.'This Week' | Where-Object {$_ -ne "n/a"}).Replace(' %','') | Measure-Object -Average).Average})$(if ($null -ne $Volumes[0].'This Month') {"<th>{0:N2} %</th>" -f (($Volumes.'This Month' | Where-Object {$_ -ne "n/a"}).Replace(' %','') | Measure-Object -Average).Average})$(if ($null -ne $Volumes[0].'This Year' -and $null -ne ($Volumes.'This Year' | Where-Object {$_ -ne "n/a"})) {"<th>{0:N2} %</th>" -f (($Volumes.'This Year' | Where-Object {$_ -ne "n/a"}).Replace(' %','') | Measure-Object -Average).Average})</tr></tfoot>"
                    # Color "Utilization" cell yellow if value is greater than or equal to 60%
                    $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -Argument 60 -CSSAttributeValue "background-color:#fac13a;" @paramsUtilization
                    # Color "Utilization" cell orange if value is greater than or equal to 75%
                    $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -Argument 75 -CSSAttributeValue "background-color:#fa8a1c;" @paramsUtilization
                    # Color "Utilization" cell red if value is greater than or equal to 90%
                    $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -Argument 90 -CSSAttributeValue "background-color:#e44f12;" @paramsUtilization -ApplyFormat
                    if ($null -ne $Volumes[0]."This Week") {
                        $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -CSSAttributeValue "color:#fe5000;" -Column "This Week" @paramsPercentChanged
                        $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -CSSAttributeValue "color:#0d98e3;" -Column "This Week" @paramsPercentChangedNegative
                    }
                    if ($null -ne $Volumes[0]."This Month") {
                        $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -CSSAttributeValue "color:#fe5000;" -Column "This Month" @paramsPercentChanged
                        $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -CSSAttributeValue "color:#0d98e3;" -Column "This Month" @paramsPercentChangedNegative
                    }
                    if ($null -ne $Volumes[0]."This Year") {
                        $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -CSSAttributeValue "color:#fe5000;" -Column "This Year" @paramsPercentChanged
                        $HTMLTable = Add-HTMLTableColor -HTML $HTMLTable -CSSAttributeValue "color:#0d98e3;" -Column "This Year" @paramsPercentChangedNegative
                    }
                    $HTML += $HTMLTable
                    $HTML += "</table>"
                }
                $HTML += "</td></tr></table>"
                $HTML = $HTML | Close-HTML -Validate
            } else {
                $HTML = @"
                <!DOCTYPE html>
                    <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
                        <head>
                            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
                            <title>$Array - Status Report</title>
                            <style>
                            $MyCSS
                            </Style>
                        </head>
                        <body>
"@

                $HTML += "<h3>Array Information</h3>"
                $HTML += '<table id="container" cellpadding="0" cellspacing="0"><tr><td style="border: none; text-align: left;">'
                $HTML += ($ArrayAttributes | Select-Object @{Name = "Name";Expression = {$_.Array_Name}},
                                                           @{Name = "Purity//FA";Expression = {$_.Version}},
                                                           @{Name = "Revision";Expression = {$_.Revision}},
                                                           @{Name = "ID";Expression = {$_.Id}},
                                                           @{Name = "Model";Expression = {$_.Model}} |
                                                           ConvertTo-HTML -Fragment).Replace("<table>",'<table width="1186">').Replace("<tr><th>",'<tr><th style="text-align: left;border-left: 1px solid black;">').Replace("<th>Model</th>",'<th style="border-right: 1px solid black;">Model</th>').Replace("<tr><td>",'<tr><td class="col-0">')
                $HTML += "<br />"

                $HTML += $HTMLCharts
                if (-not $SkipVolumesReport) {
                    $HTML += "<h3>Volumes ($($Volumes.Count))</h3>"

                    $HTMLTable = $Volumes | Select-Object Name,
                                                    Size,
                                                    Volumes,
                                                    @{Name = "Utilization";Expression = {"{0:N2} %" -f $_.Utilization}},
                                                    Snapshots,
                                                    Reduction,
                                                    Shared,
                                                    System,
                                                    Total,
                                                    'Thin Provisioning',
                                                    Written,
                                                    Protected,
                                                    'Connection(s)',
                                                    'This Week',
                                                    'This Month',
                                                    'This Year' |
                                                    ConvertTo-HTML -Fragment -Property $Volumes[0].PSObject.Properties.Name | Out-String
                    $HTMLTable = $HTMLTable.Replace("<th>Name</th>",'<th class="col-0">Name</th>').Replace("<th>Growth This Year</th>",'<th style="border-right: 1px solid black;">Growth This Year</th>').Replace("<tr><td>",'<tr><td class="col-0">').Replace("<table>", '<table id="volumes">').Replace("</table>", "<tfoot><tr><th></th><th>$(Format-Byte ($PfaVolumes.Size | Measure-Object -Sum).Sum)</th><th>$(Format-Byte ($PfaVolumes.Volumes | Measure-Object -Sum).Sum)</th><th>$("{0:N2} %" -f (($Volumes.Utilization | Measure-Object -Maximum).Maximum))</th><th>$(Format-Byte ($PfaVolumes.Snapshots | Measure-Object -Sum).Sum)</th><th>$("{0:N2} to 1" -f ($PfaVolumes.Reduction | Measure-Object -Average).Average)</th><th></th><th></th><th>$(Format-Byte ($PfaVolumes.Total | Measure-Object -Sum).Sum)</th><th></th><th>$(Format-Byte ($PfaVolumes.Written | Measure-Object -Sum).Sum)</th><th></th><th></th>$(if ($null -ne $Volumes[0].'This Week') {"<th>{0:N2} %</th>" -f (($Volumes.'This Week' | Where-Object {$_ -ne "n/a"}).Replace(' %','') | Measure-Object -Average).Average})$(if ($null -ne $Volumes[0].'This Month') {"<th>{0:N2} %</th>" -f (($Volumes.'This Month' | Where-Object {$_ -ne "n/a"}).Replace(' %','') | Measure-Object -Average).Average})$(if ($null -ne $Volumes[0].'This Year') {"<th>{0:N2} %</th>" -f (($Volumes.'This Year' | Where-Object {$_ -ne "n/a"}).Replace(' %','') | Measure-Object -Average).Average})</tr></tfoot></table>")
                    $HTML += $HTMLTable
                }
                $HTML += "</td></tr></table>"
                $HTML += "</body></html>"
            }
            if ($SaveAsHTML) {
                try {
                    $HTML | Out-File "$DataFolder\$Array.html" -Encoding utf8
                } finally {
                }
            }
            if ($SendEmail) {
                try {
                    $Message = New-Object Net.Mail.MailMessage $FromAddress, $RecipientAddress
                    $ResultsObj.PSObject.Properties | Where-Object {$_.Name -eq "Overview" -or $_.Name -eq "Health" -or $_.Name -eq "Capacity" -or $_.Name -eq "Latency" -or $_.Name -eq "IOPS" -or $_.Name -eq "Bandwidth" -or $_.Name -eq "Replication"} | ForEach-Object {
                        if ($null -ne $_.Value) {
                            $HTML = $HTML.Replace("data:image/png;charset=utf-8;base64,$($_.Value)", "cid:$($_.Name).png")
                            $ImageBytes = [Convert]::FromBase64String($_.Value)
                            $MemoryStream = New-Object IO.MemoryStream($ImageBytes, 0, $ImageBytes.Length)
                            $MemoryStream.Write($ImageBytes, 0, $ImageBytes.Length)
                            $MemoryStream.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null
                            $AttachmentObj = New-Object Net.Mail.Attachment($MemoryStream, (New-Object Net.Mime.ContentType));
                            $AttachmentObj.ContentType.MediaType = "image/png"
                            $AttachmentObj.ContentId = "$($_.Name).png"
                            $AttachmentObj.ContentDisposition.Inline = $true
                            $AttachmentObj.ContentDisposition.DispositionType = "Inline"
                            $Message.Attachments.Add($AttachmentObj)
                        }
                    }
                    $Message.IsBodyHtml = $true
                    $Message.Subject = "$Array - Status Report"
                    $Message.Body = $HTML
                    try {
                        $HTML | Out-File "$DataFolder\$Array.eml" -Encoding utf8
                    } finally {
                    }
                    $SMTPClient = New-Object Net.Mail.SmtpClient($SMTPServer)
                    $SMTPClient.EnableSsl = $false
                    $SMTPClient.Send($Message)
                } catch {
                    throw $_
                }
            }
        }
    }
}