diff --git a/.github/Dependabot.yml b/.github/Dependabot.yml new file mode 100644 index 0000000..244a5f8 --- /dev/null +++ b/.github/Dependabot.yml @@ -0,0 +1,36 @@ +# Dependabot configuration for AsBuiltReport.Core +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + # Monitor GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "ci" + include: "scope" + open-pull-requests-limit: 5 + + # Monitor PowerShell modules (via manifest) + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + labels: + - "dependencies" + - "powershell" + commit-message: + prefix: "deps" + include: "scope" + open-pull-requests-limit: 5 + ignore: + # PScribo updates should be reviewed manually + - dependency-name: "PScribo" + update-types: ["version-update:semver-major"] \ No newline at end of file diff --git a/AsBuiltReport.NetApp.ONTAP.json b/AsBuiltReport.NetApp.ONTAP.json index 3f28e96..73f269f 100755 --- a/AsBuiltReport.NetApp.ONTAP.json +++ b/AsBuiltReport.NetApp.ONTAP.json @@ -15,6 +15,7 @@ }, "EnableDiagrams": true, "EnableDiagramDebug": false, + "DisableDiagramMainLogo": false, "DiagramTheme": "White", "DiagramWaterMark": "", "ExportDiagrams": false, @@ -87,7 +88,8 @@ "NTP": true, "DNS": true, "EMS": true, - "Backup": true + "Backup": true, + "Web": true }, "Security": { "Users": true, diff --git a/AsBuiltReport.NetApp.ONTAP.psd1 b/AsBuiltReport.NetApp.ONTAP.psd1 index b9c4d6d..55a542e 100755 --- a/AsBuiltReport.NetApp.ONTAP.psd1 +++ b/AsBuiltReport.NetApp.ONTAP.psd1 @@ -12,7 +12,7 @@ RootModule = 'AsBuiltReport.NetApp.ONTAP.psm1' # Version number of this module. - ModuleVersion = '0.6.10' + ModuleVersion = '0.6.11' # Supported PSEditions # CompatiblePSEditions = @() @@ -27,7 +27,7 @@ #CompanyName = 'Unknown' # Copyright statement for this module - Copyright = '(c) 2024 Jonathan Colon Feliciano. All rights reserved.' + Copyright = '(c) 2025 Jonathan Colon Feliciano. All rights reserved.' # Description of the functionality provided by this module Description = 'A PowerShell module to generate an as built report on the configuration of NetApp ONTAP.' diff --git a/CHANGELOG.md b/CHANGELOG.md index bdc72ee..7f3bde6 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.11] - 2025-11-07 + +### Added + +- Add Health Check best practices for general Ontap configurations +- Add sponsorship information +- Add Dependabot configuration for module dependencies + +### Changed + +- Update health check messages to use "in" instead of "on" for consistency in reporting +- Refactor Get-AbrOntapNodeAggrDiagram to handle aggregate state correctly +- Refactor Get-AbrOntapNodeAggrDiagram to handle used space calculation correctly + ## [0.6.10] - 2025-10-27 ### Added diff --git a/README.md b/README.md index 2cd2460..27f4df1 100755 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ The **Options** schema allows certain options within the report to be toggled on | DiagramTheme | string | White | Set the diagram theme (Black/White/Neon) | | DiagramWaterMark | string | empty | Set the diagram watermark | | DiagramType | true / false | true | Toggle to enable/disable the export of individual diagram diagrams | +| DisableDiagramMainLogo | true / false | false | Toggle to enable/disable the main logo in diagrams | | EnableDiagrams | true / false | false | Toggle to enable/disable infrastructure diagrams | | EnableDiagramsDebug | true / false | false | Toggle to enable/disable diagram debug option | | EnableDiagramSignature | true / false | false | Toggle to enable/disable diagram signature (bottom right corner) | diff --git a/Src/Private/Export-AbrOntapDiagram.ps1 b/Src/Private/Export-AbrOntapDiagram.ps1 index cf738f1..0bfa14e 100644 --- a/Src/Private/Export-AbrOntapDiagram.ps1 +++ b/Src/Private/Export-AbrOntapDiagram.ps1 @@ -56,6 +56,7 @@ function Export-AbrOntapDiagram { 'top-to-bottom' } } + 'DisableMainDiagramLogo' = $Options.DisableDiagramMainLogo } if ($Options.DiagramTheme -eq 'Black') { diff --git a/Src/Private/Get-AbrOntapCluster.ps1 b/Src/Private/Get-AbrOntapCluster.ps1 index 1acff73..fc22942 100755 --- a/Src/Private/Get-AbrOntapCluster.ps1 +++ b/Src/Private/Get-AbrOntapCluster.ps1 @@ -43,7 +43,7 @@ function Get-AbrOntapCluster { 'Overall System Health' = switch ([string]::IsNullOrEmpty($ClusterDiag.Status)) { $true { '--' } $false { $ClusterDiag.Status.ToUpper() } - Default { 'Unknown' } + default { 'Unknown' } } } if ($Healthcheck.Cluster.Summary) { @@ -60,6 +60,15 @@ function Get-AbrOntapCluster { $TableParams['Caption'] = "- $($TableParams.Name)" } $ClusterSummary | Table @TableParams + if ($Healthcheck.Cluster.Summary -and ($ClusterSummary | Where-Object { $_.'Overall System Health' -notlike 'OK' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "The overall system health is not OK. It is recommended to investigate the issue further to ensure the cluster is functioning properly." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapClusterASUP.ps1 b/Src/Private/Get-AbrOntapClusterASUP.ps1 index b7845a0..51951e5 100755 --- a/Src/Private/Get-AbrOntapClusterASUP.ps1 +++ b/Src/Private/Get-AbrOntapClusterASUP.ps1 @@ -24,7 +24,7 @@ function Get-AbrOntapClusterASUP { process { try { - $AutoSupport = Get-NcAutoSupportConfig -Controller $Array + $AutoSupport = Get-NcAutoSupportConfig -Controller $Array -ErrorAction Continue if ($AutoSupport) { $Outobj = @() foreach ($NodesAUTO in $AutoSupport) { @@ -51,6 +51,15 @@ function Get-AbrOntapClusterASUP { $TableParams['Caption'] = "- $($TableParams.Name)" } $Outobj | Table @TableParams + if ($Healthcheck.Cluster.AutoSupport -and ($Outobj | Where-Object { $_.'Enabled' -like 'No' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "AutoSupport is disabled on one or more nodes. It is recommended to enable AutoSupport to ensure proactive monitoring and issue resolution." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapClusterDiagram.ps1 b/Src/Private/Get-AbrOntapClusterDiagram.ps1 index 8190728..bd24e63 100644 --- a/Src/Private/Get-AbrOntapClusterDiagram.ps1 +++ b/Src/Private/Get-AbrOntapClusterDiagram.ps1 @@ -119,7 +119,7 @@ function Get-AbrOntapClusterDiagram { foreach ($Node in $NodeSum) { # $ClusterHa = $ClusterHaObj | Where-Object { $_.Name -eq $Node.Node } - $ClusterHa = Get-NcClusterHa -Node $Node.Node -Controller $Array + $ClusterHa = try { Get-NcClusterHa -Node $Node.Node -Controller $Array } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } $NodeMgmtAddress = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'node_mgmt' -and $_.HomeNode -eq $Node.Node } | Select-Object -ExpandProperty Address $NodeInterClusterAddress = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'intercluster' -and $_.HomeNode -eq $Node.Node } | Select-Object -ExpandProperty Address @@ -141,7 +141,7 @@ function Get-AbrOntapClusterDiagram { "Mgmt" = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { $true { "Unknown" } $false { $NodeMgmtAddress } - Default { "Unknown" } + default { "Unknown" } } } } diff --git a/Src/Private/Get-AbrOntapClusterHA.ps1 b/Src/Private/Get-AbrOntapClusterHA.ps1 index d25bfef..208d2b7 100755 --- a/Src/Private/Get-AbrOntapClusterHA.ps1 +++ b/Src/Private/Get-AbrOntapClusterHA.ps1 @@ -31,13 +31,13 @@ function Get-AbrOntapClusterHA { $ClusterHa = Get-NcClusterHa -Node $Nodes.Node -Controller $Array [PSCustomObject] @{ 'Name' = $Nodes.Node - 'Partner' = Switch ([string]::IsNullOrEmpty($ClusterHa.Partner)) { + 'Partner' = switch ([string]::IsNullOrEmpty($ClusterHa.Partner)) { 'True' { '-' } 'False' { $ClusterHa.Partner } default { 'Unknwon' } } 'TakeOver Possible' = ConvertTo-TextYN $ClusterHa.TakeoverPossible - 'TakeOver State' = Switch ([string]::IsNullOrEmpty($ClusterHa.TakeoverState)) { + 'TakeOver State' = switch ([string]::IsNullOrEmpty($ClusterHa.TakeoverState)) { 'True' { '-' } 'False' { $ClusterHa.TakeoverState } default { 'Unknwon' } @@ -51,7 +51,8 @@ function Get-AbrOntapClusterHA { } if ($Healthcheck.Cluster.HA) { $NodeSummary | Where-Object { $_.'TakeOver State' -like 'in_takeover' } | Set-Style -Style Warning -Property 'TakeOver State' - $NodeSummary | Where-Object { $_.'HA State' -notlike 'connected' } | Set-Style -Style Warning -Property 'HA State' + $NodeSummary | Where-Object { $_.'HA Mode' -eq 'non_ha' -and $_.'HA State' -notlike 'connected' } | Set-Style -Style Warning -Property 'HA State' + $NodeSummary | Where-Object { $_.'TakeOver Possible' -eq 'No' } | Set-Style -Style Warning -Property 'TakeOver Possible' } $TableParams = @{ @@ -63,6 +64,31 @@ function Get-AbrOntapClusterHA { $TableParams['Caption'] = "- $($TableParams.Name)" } $NodeSummary | Table @TableParams + if ($Healthcheck.Cluster.HA -and (($NodeSummary | Where-Object { $_.'TakeOver State' -like 'in_takeover' } ) -or ($NodeSummary | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' }) -or ($NodeSummary | Where-Object { $_.'TakeOver Possible' -eq 'No' }))) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + if ($NodeSummary | Where-Object { $_.'TakeOver State' -like 'in_takeover' }) { + Paragraph { + Text "Best Practice:" -Bold + Text "One or more nodes are currently in takeover state. It is recommended to investigate the cause of the takeover and ensure that the affected node is restored to normal operation as soon as possible." + } + BlankLine + } + if ($NodeSummary | Where-Object { $_.'TakeOver Possible' -eq 'No' }) { + Paragraph { + Text "Best Practice:" -Bold + Text "One or more nodes have takeover capability disabled. It is recommended to enable storage failover capability to ensure high availability in case of node failures." + } + BlankLine + } + if ($NodeSummary | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' }) { + Paragraph { + Text "Best Practice:" -Bold + Text "One or more nodes are operating in HA mode and are not connected. It is recommended to verify the HA configuration and connectivity to ensure high availability is properly set up." + } + BlankLine + } + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapClusterLicense.ps1 b/Src/Private/Get-AbrOntapClusterLicense.ps1 index c554d2c..ef3abf6 100755 --- a/Src/Private/Get-AbrOntapClusterLicense.ps1 +++ b/Src/Private/Get-AbrOntapClusterLicense.ps1 @@ -31,7 +31,7 @@ function Get-AbrOntapClusterLicense { $License = Get-NcLicense -Owner $Node -Controller $Array if ($License) { $LicenseSummary = foreach ($Licenses in $License) { - $EntitlementRisk = Try { Get-NcLicenseEntitlementRisk -Package $Licenses.Package -Controller $Array -ErrorAction SilentlyContinue } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } + $EntitlementRisk = try { Get-NcLicenseEntitlementRisk -Package $Licenses.Package -Controller $Array -ErrorAction SilentlyContinue } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } [PSCustomObject] @{ 'License' = $TextInfo.ToTitleCase($Licenses.Package) 'Type' = $TextInfo.ToTitleCase($Licenses.Type) @@ -52,6 +52,15 @@ function Get-AbrOntapClusterLicense { $TableParams['Caption'] = "- $($TableParams.Name)" } $LicenseSummary | Table @TableParams + if ($Healthcheck.License.RiskSummary -and ($LicenseSummary | Where-Object { $_.'Risk' -like 'medium' -or $_.'Risk' -like 'unknown' -or $_.'Risk' -like 'unlicensed' }) -or ($LicenseSummary | Where-Object { $_.'Risk' -like 'High' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Review the license risk summary above. It is recommended to address any licenses with medium, high, unknown, or unlicensed risk to ensure compliance and avoid potential disruptions." + } + BlankLine + } } } } catch { diff --git a/Src/Private/Get-AbrOntapDiskBroken.ps1 b/Src/Private/Get-AbrOntapDiskBroken.ps1 index 281b0f1..9639afb 100755 --- a/Src/Private/Get-AbrOntapDiskBroken.ps1 +++ b/Src/Private/Get-AbrOntapDiskBroken.ps1 @@ -47,6 +47,15 @@ function Get-AbrOntapDiskBroken { $TableParams['Caption'] = "- $($TableParams.Name)" } $DiskFailed | Table @TableParams + if ($Healthcheck.Storage.DiskStatus -and ($DiskFailed)) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Review the failed disk information above. It is recommended to replace any broken disks promptly to maintain data integrity and system performance." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapDiskShelf.ps1 b/Src/Private/Get-AbrOntapDiskShelf.ps1 index 2094d97..5e5d2ec 100755 --- a/Src/Private/Get-AbrOntapDiskShelf.ps1 +++ b/Src/Private/Get-AbrOntapDiskShelf.ps1 @@ -58,6 +58,15 @@ function Get-AbrOntapDiskShelf { $TableParams['Caption'] = "- $($TableParams.Name)" } $ShelfInventory | Table @TableParams + if ($Healthcheck.Storage.ShelfStatus -and ($ShelfInventory | Where-Object { $_.'State' -like 'offline' -or $_.'State' -like 'missing' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all disk shelves are online and operational. Investigate any shelves marked as offline or missing." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapDiskType.ps1 b/Src/Private/Get-AbrOntapDiskType.ps1 index 213b646..d76f7ef 100755 --- a/Src/Private/Get-AbrOntapDiskType.ps1 +++ b/Src/Private/Get-AbrOntapDiskType.ps1 @@ -74,6 +74,15 @@ function Get-AbrOntapDiskType { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Storage.DiskStatus -and ($OutObj | Where-Object { $_.'Aggregate Spare Low' -like 'Yes' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that aggregate spare capacity is above the recommended threshold to maintain optimal performance and reliability." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 b/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 index b6d7e08..5898951 100755 --- a/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 +++ b/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 @@ -91,9 +91,18 @@ function Get-AbrOntapEfficiencyAggr { } if ($OutObj) { Section -Style Heading4 'HealthCheck - Volume with Disabled Deduplication' { - Paragraph "The following table provides the Volume efficiency healthcheck Information on $($ClusterInfo.ClusterName)." + Paragraph "The following table provides the Volume efficiency healthcheck Information in $($ClusterInfo.ClusterName)." BlankLine $OutObj | Table @TableParams + if ($Healthcheck.Storage.Efficiency) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that deduplication is enabled on all volumes to maximize storage efficiency." + } + BlankLine + } } } } catch { diff --git a/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 b/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 index 88c207d..fb8ae4d 100755 --- a/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 +++ b/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 @@ -36,7 +36,7 @@ function Get-AbrOntapEfficiencyVolSisStatus { $Volume = $Item.Path.split('/') $inObj = [ordered] @{ 'Volume' = $Volume[2] - 'State' = Switch ($Item.State) { + 'State' = switch ($Item.State) { 'enabled' { 'Enabled' } 'disabled' { 'Disabled' } default { $Item.State } @@ -63,6 +63,15 @@ function Get-AbrOntapEfficiencyVolSisStatus { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Storage.Efficiency -and ($OutObj | Where-Object { $_.'State' -like 'Disabled' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that volume deduplication is enabled on volumes where data reduction is beneficial to optimize storage efficiency." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 b/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 index e7a3746..a02298b 100755 --- a/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 +++ b/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 @@ -64,6 +64,15 @@ function Get-AbrOntapNetworkIfgrp { $TableParams['Caption'] = "- $($TableParams.Name)" } $AggregatePorts | Table @TableParams + if ($Healthcheck.Network.Port -and ($AggregatePorts | Where-Object { $_.'Port Participation' -ne "full" })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all ports in the interface group are active and participating fully to maintain optimal network performance and redundancy." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 b/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 index 6abdf24..34eb286 100755 --- a/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 +++ b/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 @@ -37,11 +37,6 @@ function Get-AbrOntapNetworkIpSpace { } $IPSpaceObj = [pscustomobject]$inobj - if ($Healthcheck.Network.Port) { - $IPSpaceObj | Where-Object { $_.'Port' -match "Down" } | Set-Style -Style Warning -Property 'Port' - $IPSpaceObj | Where-Object { $_.'Port Participation' -ne "full" } | Set-Style -Style Warning -Property 'Port Participation' - } - $TableParams = @{ Name = "Network IPSpace - $($Item.Ipspace)" List = $true diff --git a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 index c21f426..7b118a3 100755 --- a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 +++ b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 @@ -34,7 +34,7 @@ function Get-AbrOntapNetworkMgmt { try { $inObj = [ordered] @{ 'Cluster Interface' = $Item.InterfaceName - 'Status' = Switch ($Item.OpStatus) { + 'Status' = switch ($Item.OpStatus) { "" { "Unknown" } $Null { "Unknown" } default { $Item.OpStatus.ToString().ToUpper() } @@ -61,6 +61,15 @@ function Get-AbrOntapNetworkMgmt { $TableParams['Caption'] = "- $($TableParams.Name)" } $ClusterObj | Table @TableParams + if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all cluster network interfaces are operational (UP) to maintain cluster connectivity and performance." + } + BlankLine + } } } } catch { @@ -76,7 +85,7 @@ function Get-AbrOntapNetworkMgmt { try { $inObj = [ordered] @{ 'MGMT Interface' = $Item.InterfaceName - 'Status' = Switch ($Item.OpStatus) { + 'Status' = switch ($Item.OpStatus) { "" { "Unknown" } $Null { "Unknown" } default { $Item.OpStatus.ToString().ToUpper() } @@ -103,6 +112,15 @@ function Get-AbrOntapNetworkMgmt { $TableParams['Caption'] = "- $($TableParams.Name)" } $ClusterObj | Table @TableParams + if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all management network interfaces are operational (UP) to maintain proper management access to the cluster." + } + BlankLine + } } } } catch { @@ -118,7 +136,7 @@ function Get-AbrOntapNetworkMgmt { try { $inObj = [ordered] @{ 'Intercluster Interface' = $Item.InterfaceName - 'Status' = Switch ($Item.OpStatus) { + 'Status' = switch ($Item.OpStatus) { "" { "Unknown" } $Null { "Unknown" } default { $Item.OpStatus.ToString().ToUpper() } @@ -145,6 +163,15 @@ function Get-AbrOntapNetworkMgmt { $TableParams['Caption'] = "- $($TableParams.Name)" } $ClusterObj | Table @TableParams + if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all intercluster network interfaces are operational (UP) to maintain cluster-to-cluster communication." + } + BlankLine + } } } } @@ -160,10 +187,10 @@ function Get-AbrOntapNetworkMgmt { try { if ($Item.Wwpn) { $AddressData = $Item.Wwpn - } else {$AddressData = $Item.Address} + } else { $AddressData = $Item.Address } $inObj = [ordered] @{ 'Data Interface' = $Item.InterfaceName - 'Status' = Switch ($Item.OpStatus) { + 'Status' = switch ($Item.OpStatus) { "" { "Unknown" } $Null { "Unknown" } default { $Item.OpStatus.ToString().ToUpper() } @@ -190,6 +217,15 @@ function Get-AbrOntapNetworkMgmt { $TableParams['Caption'] = "- $($TableParams.Name)" } $ClusterObj | Table @TableParams + if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all data network interfaces are operational (UP) to maintain optimal data access and performance." + } + BlankLine + } } } } catch { @@ -198,7 +234,7 @@ function Get-AbrOntapNetworkMgmt { try { if ((Get-NcNetInterface -Controller $Array | Where-Object { $_.DataProtocols -ne 'fcp' -and $_.IsHome -like "False" }) -and $Healthcheck.Network.Interface) { Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Check If Network Interface is Home' { - Paragraph "The following table provides the LIF Home Status Information on $($ClusterInfo.ClusterName)." + Paragraph "The following table provides the LIF Home Status Information in $($ClusterInfo.ClusterName)." BlankLine $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.DataProtocols -ne 'fcp' -and $_.IsHome -like "False" } $ClusterObj = @() @@ -209,7 +245,7 @@ function Get-AbrOntapNetworkMgmt { 'Network Interface' = $Item.InterfaceName 'Home Port' = $Item.HomeNode + ":" + $Item.HomePort 'Current Port' = $Item.CurrentNode + ":" + $Item.CurrentPort - 'IsHome' = Switch ($Item.IsHome) { + 'IsHome' = switch ($Item.IsHome) { "True" { 'Yes' } "False" { "No" } default { $Item.IsHome } @@ -234,6 +270,15 @@ function Get-AbrOntapNetworkMgmt { $TableParams['Caption'] = "- $($TableParams.Name)" } $ClusterObj | Table @TableParams + if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'IsHome' -ne 'Yes' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all network interfaces are on their designated home ports to maintain optimal network performance and reliability." + } + BlankLine + } } } } diff --git a/Src/Private/Get-AbrOntapNetworkPorts.ps1 b/Src/Private/Get-AbrOntapNetworkPorts.ps1 index f2aa8a7..9deb02d 100755 --- a/Src/Private/Get-AbrOntapNetworkPorts.ps1 +++ b/Src/Private/Get-AbrOntapNetworkPorts.ps1 @@ -38,7 +38,7 @@ function Get-AbrOntapNetworkPort { 'Mac Address' = $Nics.MacAddress 'MTU' = $Nics.MTU 'Link Status' = $TextInfo.ToTitleCase($Nics.LinkStatus) - 'Admin Status' = Switch ($Nics.IsAdministrativeUp) { + 'Admin Status' = switch ($Nics.IsAdministrativeUp) { "True" { 'Up' } "False" { 'Down' } default { $Nics.IsAdministrativeUp } @@ -61,6 +61,15 @@ function Get-AbrOntapNetworkPort { $TableParams['Caption'] = "- $($TableParams.Name)" } $PhysicalNic | Table @TableParams + if ($Healthcheck.Network.Port -and ($PhysicalNic | Where-Object { $_.'Link Status' -like 'down' -and $_.'Admin Status' -like 'Up' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all physical network ports with an administrative status of 'Up' also have a link status of 'Up' to maintain optimal network connectivity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapNetworkVlans.ps1 b/Src/Private/Get-AbrOntapNetworkVlans.ps1 index 2be71b9..dba8b79 100755 --- a/Src/Private/Get-AbrOntapNetworkVlans.ps1 +++ b/Src/Private/Get-AbrOntapNetworkVlans.ps1 @@ -52,7 +52,7 @@ function Get-AbrOntapNetworkVlan { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $VlanObj | Table @TableParams + $VlanObj | Sort-Object -Property 'Vlan ID' | Table @TableParams } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 b/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 index 93011e3..10f40eb 100644 --- a/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 +++ b/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 @@ -103,7 +103,7 @@ function Get-AbrOntapStorageAggrDiagram { "AggregateName" = $Aggr.Name "AdditionalInfo" = [PSCustomObject][ordered]@{ "Total Size" = $Aggr.TotalSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - "Used Space" = $Aggr.Used | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + "Used Space" = ($Aggr.TotalSize - $Aggr.Available) | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue "Assigned Disk" = $Aggr.Disks "Raid Type" = switch ([string]::IsNullOrEmpty($Aggr.RaidType)) { $true { "Unknown" } @@ -122,7 +122,11 @@ function Get-AbrOntapStorageAggrDiagram { default { "Unknown" } } "Raid Size" = $Aggr.RaidSize - "State" = $Aggr.State + "State" = switch ([string]::IsNullOrEmpty($Aggr.State)) { + $true { "Unknown" } + $false { $Aggr.State.ToUpper() } + default { "Unknown" } + } } } } diff --git a/Src/Private/Get-AbrOntapNodeStorage.ps1 b/Src/Private/Get-AbrOntapNodeStorage.ps1 index 0fcfccc..af6f9ff 100755 --- a/Src/Private/Get-AbrOntapNodeStorage.ps1 +++ b/Src/Private/Get-AbrOntapNodeStorage.ps1 @@ -56,6 +56,15 @@ function Get-AbrOntapNodeStorage { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Node.HW -and (($OutObj | Where-Object { $_.'Status' -like 'offline' }) -or ($OutObj | Where-Object { $_.'Used' -ge 90 }))) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all nodes are online and that storage usage is within acceptable limits." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapNodesHW.ps1 b/Src/Private/Get-AbrOntapNodesHW.ps1 index 05bfacc..a4f821f 100755 --- a/Src/Private/Get-AbrOntapNodesHW.ps1 +++ b/Src/Private/Get-AbrOntapNodesHW.ps1 @@ -24,7 +24,7 @@ function Get-AbrOntapNodesHW { process { try { - $NodeHW = Get-NcNodeInfo -Controller $Array + $NodeHW = Get-NcNodeInfo -Controller $Array -ErrorAction Continue if ($NodeHW) { $Outobj = @() foreach ($NodeHWs in $NodeHW) { @@ -39,7 +39,7 @@ function Get-AbrOntapNodesHW { 'AFF/FAS' = $NodeHWs.ProdType 'All Flash Optimized' = ConvertTo-TextYN $NodeInfo.IsAllFlashOptimized 'Epsilon' = ConvertTo-TextYN $NodeInfo.IsEpsilonNode - 'System Healthy' = Switch ($NodeInfo.IsNodeHealthy) { + 'System Healthy' = switch ($NodeInfo.IsNodeHealthy) { "True" { "Healthy" } "False" { "UnHealthy" } default { $NodeInfo.IsNodeHealthy } @@ -48,7 +48,7 @@ function Get-AbrOntapNodesHW { 'Failed Fan Error' = $NodeInfo.EnvFailedFanMessage 'Failed PowerSupply Count' = $NodeInfo.EnvFailedPowerSupplyCount 'Failed PowerSupply Error' = $NodeInfo.EnvFailedPowerSupplyMessage - 'Over Temperature' = Switch ($NodeInfo.EnvOverTemperature) { + 'Over Temperature' = switch ($NodeInfo.EnvOverTemperature) { "True" { "High Temperature" } "False" { "Normal Temperature" } default { $NodeInfo.EnvOverTemperature } diff --git a/Src/Private/Get-AbrOntapNodesSP.ps1 b/Src/Private/Get-AbrOntapNodesSP.ps1 index df8cab8..f3240b3 100755 --- a/Src/Private/Get-AbrOntapNodesSP.ps1 +++ b/Src/Private/Get-AbrOntapNodesSP.ps1 @@ -57,6 +57,15 @@ function Get-AbrOntapNodesSP { $TableParams['Caption'] = "- $($TableParams.Name)" } $NodeServiceProcessor | Table @TableParams + if ($Healthcheck.Node.ServiceProcessor -and ($NodeServiceProcessor | Where-Object { $_.'Status' -like 'offline' -or $_.'Status' -like 'degraded' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all service-processors are online and functioning properly to maintain system management capabilities." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapRepClusterPeer.ps1 b/Src/Private/Get-AbrOntapRepClusterPeer.ps1 index 8a075b2..f4989dc 100755 --- a/Src/Private/Get-AbrOntapRepClusterPeer.ps1 +++ b/Src/Private/Get-AbrOntapRepClusterPeer.ps1 @@ -55,6 +55,15 @@ function Get-AbrOntapRepClusterPeer { $TableParams['Caption'] = "- $($TableParams.Name)" } $ReplicaObj | Table @TableParams + if ($Healthcheck.Replication.ClusterPeer -and ($ReplicaObj | Where-Object { $_.'Status' -notlike 'Available' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all cluster peers are available to maintain replication integrity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapRepDestinations.ps1 b/Src/Private/Get-AbrOntapRepDestinations.ps1 index a1699b3..58f942b 100755 --- a/Src/Private/Get-AbrOntapRepDestinations.ps1 +++ b/Src/Private/Get-AbrOntapRepDestinations.ps1 @@ -37,7 +37,7 @@ function Get-AbrOntapRepDestination { 'Destination Location' = $Item.DestinationLocation 'Source Vserver' = $Item.SourceVserver 'Source Location' = $Item.SourceLocation - 'Relationship Type' = Switch ($Item.RelationshipType) { + 'Relationship Type' = switch ($Item.RelationshipType) { 'extended_data_protection' { 'XDP' } 'data_protection' { 'DP' } 'transition_data_protection' { 'TDP' } @@ -46,7 +46,7 @@ function Get-AbrOntapRepDestination { default { $Item.RelationshipType } } 'Policy Type' = $Item.PolicyType - 'Status' = Switch ($Item.RelationshipStatus) { + 'Status' = switch ($Item.RelationshipStatus) { $Null { 'Unknown' } default { $Item.RelationshipStatus } } @@ -66,6 +66,15 @@ function Get-AbrOntapRepDestination { $TableParams['Caption'] = "- $($TableParams.Name)" } $ReplicaObj | Table @TableParams + if ($Healthcheck.Replication.Relationship -and ($ReplicaObj | Where-Object { $_.'Status' -eq "Unknown" })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all SnapMirror relationships have a known status to maintain replication integrity." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapRepHistory.ps1 b/Src/Private/Get-AbrOntapRepHistory.ps1 index 8f04a1e..980c566 100755 --- a/Src/Private/Get-AbrOntapRepHistory.ps1 +++ b/Src/Private/Get-AbrOntapRepHistory.ps1 @@ -54,6 +54,15 @@ function Get-AbrOntapRepHistory { $TableParams['Caption'] = "- $($TableParams.Name)" } $ReplicaObj | Table @TableParams + if ($Healthcheck.Replication.History -and ($ReplicaObj | Where-Object { $_.'Result' -ne 'success' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all SnapMirror replication operations complete successfully to maintain data integrity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapRepMediator.ps1 b/Src/Private/Get-AbrOntapRepMediator.ps1 index 3e15382..d815a33 100755 --- a/Src/Private/Get-AbrOntapRepMediator.ps1 +++ b/Src/Private/Get-AbrOntapRepMediator.ps1 @@ -33,7 +33,7 @@ function Get-AbrOntapRepMediator { 'Peer cluster' = $Item.peer_cluster.name 'IP Address' = $Item.ip_address 'port' = $Item.port - 'Status' = Switch ($Item.reachable) { + 'Status' = switch ($Item.reachable) { 'True' { 'Reachable' } 'False' { 'Unreachable' } default { $Item.reachable } @@ -57,6 +57,15 @@ function Get-AbrOntapRepMediator { $TableParams['Caption'] = "- $($TableParams.Name)" } $ReplicaObj | Table @TableParams + if ($Healthcheck.Replication.Mediator -and ($ReplicaObj | Where-Object { $_.'Status' -eq "Unreachable" })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all SnapMirror Mediator relationships are reachable to facilitate proper replication management." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapRepRelations.ps1 b/Src/Private/Get-AbrOntapRepRelations.ps1 index 97745c5..b67d4fc 100755 --- a/Src/Private/Get-AbrOntapRepRelations.ps1 +++ b/Src/Private/Get-AbrOntapRepRelations.ps1 @@ -79,6 +79,15 @@ function Get-AbrOntapRepRelationship { $TableParams['Caption'] = "- $($TableParams.Name)" } $ReplicaObj | Table @TableParams + if ($Healthcheck.Replication.Relationship -and ($ReplicaObj | Where-Object { $_.'Unhealthy Reason' -ne "None" })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all SnapMirror relationships are healthy to maintain data replication integrity." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapRepVserverPeer.ps1 b/Src/Private/Get-AbrOntapRepVserverPeer.ps1 index 5142c13..9ee1ed9 100755 --- a/Src/Private/Get-AbrOntapRepVserverPeer.ps1 +++ b/Src/Private/Get-AbrOntapRepVserverPeer.ps1 @@ -54,6 +54,15 @@ function Get-AbrOntapRepVserverPeer { $TableParams['Caption'] = "- $($TableParams.Name)" } $ReplicaObj | Table @TableParams + if ($Healthcheck.Replication.VserverPeer -and ($ReplicaObj | Where-Object { $_.'Peer State' -notlike 'peered' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all Vserver Peer relationships are in 'peered' state to maintain proper data replication." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 b/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 index 9c3a3b0..a13772e 100755 --- a/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 +++ b/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 @@ -54,6 +54,15 @@ function Get-AbrOntapSecurityKMSExtStatus { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Security.KMS -and ($OutObj | Where-Object { $_.'Status' -ne 'Available' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all External Key Management Services are in 'Available' status to maintain encryption functionality." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapSecurityNAE.ps1 b/Src/Private/Get-AbrOntapSecurityNAE.ps1 index 5aa3025..8379cda 100755 --- a/Src/Private/Get-AbrOntapSecurityNAE.ps1 +++ b/Src/Private/Get-AbrOntapSecurityNAE.ps1 @@ -29,13 +29,13 @@ function Get-AbrOntapSecurityNAE { if ($Data) { foreach ($Item in $Data) { try { - $NAE = (Get-NcAggrOption -Name $Item.Name -Controller $Array | Where-Object { $_.Name -eq "encrypt_with_aggr_key" }).Value + $NAE = try { (Get-NcAggrOption -Name $Item.Name -Controller $Array | Where-Object { $_.Name -eq "encrypt_with_aggr_key" }).Value } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } $inObj = [ordered] @{ 'Aggregate' = $Item.Name - 'Aggregate Encryption' = Switch ($NAE) { + 'Aggregate Encryption' = switch ($NAE) { 'true' { 'Yes' } 'false' { 'No' } - $Null { 'Unsupported' } + $Null { 'Unknown' } default { $NAE } } 'Volume Count' = $Item.Volumes @@ -59,6 +59,15 @@ function Get-AbrOntapSecurityNAE { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Storage.Aggr -and ($OutObj | Where-Object { $_.'State' -ne 'Online' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all Aggregates are in 'Online' state to maintain optimal storage performance and client access availability." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapSecurityUsers.ps1 b/Src/Private/Get-AbrOntapSecurityUsers.ps1 index 03a618d..22e2309 100755 --- a/Src/Private/Get-AbrOntapSecurityUsers.ps1 +++ b/Src/Private/Get-AbrOntapSecurityUsers.ps1 @@ -58,6 +58,15 @@ function Get-AbrOntapSecurityUser { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Security.Users -and ($OutObj | Where-Object { $_.'Locked' -eq 'Yes' -and $_.'User Name' -ne "vsadmin" })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that local users are not locked out to maintain proper access to the system. Review locked users and unlock them if necessary." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapStorageAGGR.ps1 b/Src/Private/Get-AbrOntapStorageAGGR.ps1 index 0d64dd0..ffbd0b1 100755 --- a/Src/Private/Get-AbrOntapStorageAGGR.ps1 +++ b/Src/Private/Get-AbrOntapStorageAGGR.ps1 @@ -31,24 +31,24 @@ function Get-AbrOntapStorageAGGR { $RootAggr = Get-NcAggr $Aggr.Name -Controller $Array | ForEach-Object { $_.AggrRaidAttributes.HasLocalRoot } [PSCustomObject] @{ 'Name' = $Aggr.Name - 'Capacity' = Switch ([string]::IsNullOrEmpty($Aggr.Totalsize)) { + 'Capacity' = switch ([string]::IsNullOrEmpty($Aggr.Totalsize)) { $true { 'Unknown' } $false { $Aggr.Totalsize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { 'Unknown' } } - 'Available' = Switch ([string]::IsNullOrEmpty($Aggr.Available)) { + 'Available' = switch ([string]::IsNullOrEmpty($Aggr.Available)) { $true { 'Unknown' } $false { $Aggr.Available | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { 'Unknown' } } - 'Used' = Switch ([string]::IsNullOrEmpty($Aggr.Used)) { + 'Used' = switch ([string]::IsNullOrEmpty($Aggr.Used)) { $true { 'Unknown' } $false { $Aggr.Used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue } default { 'Unknown' } } 'Disk Count' = $Aggr.Disks 'Root' = ConvertTo-TextYN $RootAggr - 'Raid Type' = Switch ([string]::IsNullOrEmpty($Aggr.RaidType)) { + 'Raid Type' = switch ([string]::IsNullOrEmpty($Aggr.RaidType)) { $true { 'Unknown' } $false { ($Aggr.RaidType.Split(",")[0]).ToUpper() } default { 'Unknown' } @@ -73,6 +73,15 @@ function Get-AbrOntapStorageAGGR { $TableParams['Caption'] = "- $($TableParams.Name)" } $AggrSpaceSummary | Table @TableParams + if ($Healthcheck.Storage.Aggr -and (($AggrSpaceSummary | Where-Object { $_.'State' -eq 'failed' } ) -or ($AggrSpaceSummary | Where-Object { $_.'State' -eq 'unknown' -or $_.'State' -eq 'offline' }) -or ($AggrSpaceSummary | Where-Object { $_.'Used' -ge 90 -and $_.'Root' -ne 'Yes' }))) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all Aggregates are in healthy state to maintain optimal storage performance and client access availability." + } + BlankLine + } } try { $AggrSpare = Get-NcAggrSpare -Controller $Array @@ -82,17 +91,17 @@ function Get-AbrOntapStorageAGGR { try { [PSCustomObject] @{ 'Name' = $Spare.Disk - 'Capacity' = Switch ([string]::IsNullOrEmpty($Spare.TotalSize)) { + 'Capacity' = switch ([string]::IsNullOrEmpty($Spare.TotalSize)) { $true { '-' } $false { $Spare.TotalSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { '-' } } - 'Root Usable' = Switch ([string]::IsNullOrEmpty($Spare.LocalUsableRootSize)) { + 'Root Usable' = switch ([string]::IsNullOrEmpty($Spare.LocalUsableRootSize)) { $true { '-' } $false { $Spare.LocalUsableRootSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { '-' } } - 'Data Usable' = Switch ([string]::IsNullOrEmpty($Spare.LocalUsableDataSize)) { + 'Data Usable' = switch ([string]::IsNullOrEmpty($Spare.LocalUsableDataSize)) { $true { '-' } $false { $Spare.LocalUsableDataSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { '-' } diff --git a/Src/Private/Get-AbrOntapSysConfigBackup.ps1 b/Src/Private/Get-AbrOntapSysConfigBackup.ps1 index 79e9a41..e8d515a 100755 --- a/Src/Private/Get-AbrOntapSysConfigBackup.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigBackup.ps1 @@ -47,7 +47,7 @@ function Get-AbrOntapSysConfigBackup { } $TableParams = @{ - Name = "System Configuration Backups - $($Node)" + Name = "Configuration Backups - $($Node)" List = $false ColumnWidths = 40, 15, 15, 15, 15 } diff --git a/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 b/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 index dd986df..3cbd415 100755 --- a/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 @@ -30,11 +30,11 @@ function Get-AbrOntapSysConfigBackupURL { foreach ($Item in $Data) { try { $inObj = [ordered] @{ - 'Url' = Switch ($Item.Url) { + 'Url' = switch ($Item.Url) { $Null { 'Not Configured' } default { $Item.Url } } - 'Username' = Switch ($Item.Username) { + 'Username' = switch ($Item.Username) { $Null { 'Not Configured' } default { $Item.Username } } @@ -51,7 +51,7 @@ function Get-AbrOntapSysConfigBackupURL { } $TableParams = @{ - Name = "System Configuration Backup Setting - $($ClusterInfo.ClusterName)" + Name = "Configuration Backup Setting - $($ClusterInfo.ClusterName)" List = $false ColumnWidths = 60, 40 } @@ -59,6 +59,15 @@ function Get-AbrOntapSysConfigBackupURL { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.System.Backup -and ($OutObj | Where-Object { $_.'Url' -eq 'Not Configured' -or $_.'Username' -eq 'Not Configured' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to backup the system configuration to a remote location to ensure recovery in case of failures." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapSysConfigDNS.ps1 b/Src/Private/Get-AbrOntapSysConfigDNS.ps1 index a2b16a8..908be39 100755 --- a/Src/Private/Get-AbrOntapSysConfigDNS.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigDNS.ps1 @@ -44,10 +44,11 @@ function Get-AbrOntapSysConfigDNS { if ($Healthcheck.System.DNS) { $OutObj | Where-Object { $_.'Dns State' -notlike 'Enabled' } | Set-Style -Style Warning -Property 'Dns State' $OutObj | Where-Object { $_.'Timeout/s' -gt 10 } | Set-Style -Style Warning -Property 'Timeout/s' + $OutObj | Where-Object { $_.'Name Servers' -lt 2 } | Set-Style -Style Warning -Property 'Name Servers' } $TableParams = @{ - Name = "System DNS Configuration - $($ClusterInfo.ClusterName)" + Name = "DNS Configuration - $($ClusterInfo.ClusterName)" List = $false ColumnWidths = 30, 15, 20, 20, 15 } @@ -55,12 +56,28 @@ function Get-AbrOntapSysConfigDNS { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.System.DNS -and (($OutObj | Where-Object { $_.'Dns State' -notlike 'Enabled' }) -or ($OutObj | Where-Object { $_.'Name Servers' -lt 2 }))) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + if ($OutObj | Where-Object { $_.'Dns State' -notlike 'Enabled' }) { + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to enable DNS on the cluster to ensure proper name resolution for network services." + } + BlankLine + } + if ($OutObj | Where-Object { $_.'Name Servers' -lt 2 } ) { + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to configure at least two DNS name servers for redundancy and reliability." + } + BlankLine + } + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } - end {} - } \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapSysConfigEMS.ps1 b/Src/Private/Get-AbrOntapSysConfigEMS.ps1 index ad6a120..b1bf68e 100755 --- a/Src/Private/Get-AbrOntapSysConfigEMS.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigEMS.ps1 @@ -45,7 +45,7 @@ function Get-AbrOntapSysConfigEMS { } $TableParams = @{ - Name = "HealtCheck - System EMS Messages - $($Node)" + Name = "HealtCheck - EMS Messages - $($Node)" List = $false ColumnWidths = 25, 20, 55 } diff --git a/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 b/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 index f53e425..085490d 100755 --- a/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 @@ -31,23 +31,23 @@ function Get-AbrOntapSysConfigEMSSetting { try { $inObj = [ordered] @{ 'Name' = $Item.Name - 'Email Destinations' = Switch ($Item.Mail) { + 'Email Destinations' = switch ($Item.Mail) { $Null { '-' } default { $Item.Mail } } - 'Snmp Traphost' = Switch ($Item.Snmp) { + 'Snmp Traphost' = switch ($Item.Snmp) { $Null { '-' } default { $Item.Snmp } } - 'Snmp Community' = Switch ($Item.SnmpCommunity) { + 'Snmp Community' = switch ($Item.SnmpCommunity) { $Null { '-' } default { $Item.SnmpCommunity } } - 'Syslog' = Switch ($Item.Syslog) { + 'Syslog' = switch ($Item.Syslog) { $Null { '-' } default { $Item.Syslog } } - 'Syslog Facility' = Switch ($Item.SyslogFacility) { + 'Syslog Facility' = switch ($Item.SyslogFacility) { $Null { '-' } default { $Item.SyslogFacility } } @@ -59,7 +59,7 @@ function Get-AbrOntapSysConfigEMSSetting { } $TableParams = @{ - Name = "System EMS Configuration Setting - $($ClusterInfo.ClusterName)" + Name = "EMS Configuration Setting - $($ClusterInfo.ClusterName)" List = $false ColumnWidths = 17, 30, 15, 13, 15, 10 } @@ -67,6 +67,15 @@ function Get-AbrOntapSysConfigEMSSetting { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.System.EMS -and ($OutObj | Where-Object { $_.'Email Destinations' -eq '-' -and $_.'Snmp Traphost' -eq '-' -and $_.'Syslog' -eq '-' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to configure at least one EMS destination (Email, SNMP, or Syslog) to ensure proper monitoring and alerting of system events." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapSysConfigNTP.ps1 b/Src/Private/Get-AbrOntapSysConfigNTP.ps1 index 1233c8e..d4a7bd4 100755 --- a/Src/Private/Get-AbrOntapSysConfigNTP.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigNTP.ps1 @@ -42,7 +42,7 @@ function Get-AbrOntapSysConfigNTP { } $TableParams = @{ - Name = "System Network Time Protocol - $($ClusterInfo.ClusterName)" + Name = "Network Time Protocol - $($ClusterInfo.ClusterName)" List = $false ColumnWidths = 40, 20, 20, 20 } @@ -50,6 +50,37 @@ function Get-AbrOntapSysConfigNTP { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + } else { + $inObj = [ordered] @{ + 'Server Name' = 'No NTP Servers Configured' + 'NTP Version' = 'N/A' + 'Preferred' = 'N/A' + 'Authentication Enabled' = 'N/A' + } + $OutObj = [pscustomobject]$inObj + + if ($Healthcheck.System.NTP) { + $OutObj | Set-Style -Style Warning + } + + $TableParams = @{ + Name = "Network Time Protocol - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 40, 20, 20, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Configure at least one NTP server to ensure accurate time synchronization across the cluster." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 b/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 index d32b04e..4a3b5e1 100755 --- a/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 @@ -34,7 +34,7 @@ function Get-AbrOntapSysConfigNTPHost { 'Time Offset' = $Item.Offset 'Selection State' = $Item.SelectionState 'Server' = $Item.Server - 'Peer Status' = Switch ($Item.IsPeerReachable) { + 'Peer Status' = switch ($Item.IsPeerReachable) { 'True' { 'Reachable' } 'False' { 'Unreachable' } default { $Item.IsPeerReachable } @@ -50,14 +50,23 @@ function Get-AbrOntapSysConfigNTPHost { } $TableParams = @{ - Name = "System NTP Host Status - $($ClusterInfo.ClusterName)" + Name = "NTP Host Status - $($ClusterInfo.ClusterName)" List = $false - ColumnWidths = 30, 10, 20, 20, 20 + ColumnWidths = 30, 10, 25, 20, 15 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.System.NTP -and ($OutObj | Where-Object { $_.'Peer Status' -notlike 'Reachable' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all configured NTP servers are reachable to maintain accurate time synchronization across the cluster." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 b/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 index 665ff5f..eb7fe3f 100755 --- a/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 @@ -47,7 +47,7 @@ function Get-AbrOntapSysConfigSNMP { } $TableParams = @{ - Name = "System SNMP Configuration - $($ClusterInfo.ClusterName)" + Name = "SNMP Configuration - $($ClusterInfo.ClusterName)" List = $true ColumnWidths = 40, 60 } diff --git a/Src/Private/Get-AbrOntapSysConfigTZ.ps1 b/Src/Private/Get-AbrOntapSysConfigTZ.ps1 index 5d09678..b58f82a 100755 --- a/Src/Private/Get-AbrOntapSysConfigTZ.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigTZ.ps1 @@ -44,7 +44,7 @@ function Get-AbrOntapSysConfigTZ { } $TableParams = @{ - Name = "System TimeZone - $($ClusterInfo.ClusterName)" + Name = "TimeZone - $($ClusterInfo.ClusterName)" List = $false ColumnWidths = 30, 20, 20, 30 } diff --git a/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 b/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 index 23aa96e..f6e9ee8 100755 --- a/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 +++ b/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 @@ -43,13 +43,14 @@ function Get-AbrOntapSysConfigWebStatus { Write-PScriboMessage -IsWarning $_.Exception.Message } } - if ($Healthcheck.System.DNS) { + if ($Healthcheck.System.Web) { $OutObj | Where-Object { $_.'Status' -notlike 'Online' } | Set-Style -Style Warning -Property 'Status' $OutObj | Where-Object { $_.'Status Code' -ne 200 } | Set-Style -Style Warning -Property 'Status Code' + $OutObj | Where-Object { $_.'Http Enabled' -eq 'Yes' } | Set-Style -Style Warning -Property 'Http Enabled' } $TableParams = @{ - Name = "System Web Service - $($ClusterInfo.ClusterName)" + Name = "Web Service - $($ClusterInfo.ClusterName)" List = $false ColumnWidths = 25, 12, 12, 12, 12, 15, 12 } @@ -57,6 +58,15 @@ function Get-AbrOntapSysConfigWebStatus { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.System.Web -and (($OutObj | Where-Object { $_.'Http Enabled' -eq 'Yes' }))) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "It is recommended to enable HTTPS and disable HTTP on all nodes to ensure secure communication with the cluster management interface." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverCGLun.ps1 b/Src/Private/Get-AbrOntapVserverCGLun.ps1 index edbe0d8..ca307e9 100755 --- a/Src/Private/Get-AbrOntapVserverCGLun.ps1 +++ b/Src/Private/Get-AbrOntapVserverCGLun.ps1 @@ -34,12 +34,12 @@ function Get-AbrOntapVserverCGLun { try { $inObj = [ordered] @{ 'Name' = $Item.Name.Split('/')[3] - 'Capacity' = Switch ([string]::IsNullOrEmpty($Item.space.size)) { + 'Capacity' = switch ([string]::IsNullOrEmpty($Item.space.size)) { $true { '-' } $false { $Item.space.size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { '-' } } - 'Used' = Switch ([string]::IsNullOrEmpty($Item.space.used)) { + 'Used' = switch ([string]::IsNullOrEmpty($Item.space.used)) { $true { '-' } $false { $Item.space.used | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { '-' } @@ -74,6 +74,15 @@ function Get-AbrOntapVserverCGLun { $TableParams['Caption'] = "- $($TableParams.Name)" } $CGLunObj | Sort-Object -Property Name | Table @TableParams + if ($Healthcheck.Vserver.CG -and ($CGLunObj | Where-Object { $_.'State' -eq 'offline' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all LUNs within the Consistency Group are online to maintain data availability and integrity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 b/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 index f7e093a..1989c4b 100755 --- a/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 +++ b/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 @@ -34,12 +34,12 @@ function Get-AbrOntapVserverCGNamespace { try { $inObj = [ordered] @{ 'Name' = $Item.Name.Split('/')[3] - 'Capacity' = Switch ([string]::IsNullOrEmpty($Item.space.size)) { + 'Capacity' = switch ([string]::IsNullOrEmpty($Item.space.size)) { $true { '-' } $false { $Item.space.size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { '-' } } - 'Used' = Switch ([string]::IsNullOrEmpty($Item.space.used)) { + 'Used' = switch ([string]::IsNullOrEmpty($Item.space.used)) { $true { '-' } $false { $Item.space.used | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } default { '-' } @@ -74,6 +74,15 @@ function Get-AbrOntapVserverCGNamespace { $TableParams['Caption'] = "- $($TableParams.Name)" } $CGNamespaceObj | Sort-Object -Property Name | Table @TableParams + if ($Healthcheck.Vserver.CG -and ($CGNamespaceObj | Where-Object { $_.'State' -eq 'offline' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all namespaces within the Consistency Group are online to maintain data availability and integrity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 b/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 index 5efb746..038995e 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 +++ b/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 @@ -61,6 +61,15 @@ function Get-AbrOntapVserverCIFSSummary { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.CIFS -and ($VserverObj | Where-Object { $_.'Status' -like 'down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that the CIFS service is running on all nodes to maintain file sharing capabilities." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 b/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 index 6587d0b..813c0e8 100755 --- a/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 +++ b/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 @@ -34,7 +34,7 @@ function Get-AbrOntapVserverFcpAdapter { 'Adapter' = $Item.Adapter 'Protocol' = $Item.PhysicalProtocol 'Speed' = $Item.Speed - 'Status' = Switch ($Item.State) { + 'Status' = switch ($Item.State) { 'online' { 'Up' } 'offline' { 'Down' } default { $Item.State } @@ -58,6 +58,15 @@ function Get-AbrOntapVserverFcpAdapter { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.FCP -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all FCP adapters are operational to maintain optimal storage connectivity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 b/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 index 688e822..9ef7a26 100755 --- a/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 +++ b/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 @@ -35,7 +35,7 @@ function Get-AbrOntapVserverFcpSummary { try { $inObj = [ordered] @{ 'FCP WWNN' = $Item.NodeName - 'Status' = Switch ($Item.IsAvailable) { + 'Status' = switch ($Item.IsAvailable) { 'True' { 'Up' } 'False' { 'Down' } default { $Item.IsAvailable } @@ -59,6 +59,15 @@ function Get-AbrOntapVserverFcpSummary { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.FCP -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' } )) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all FCP services are operational to maintain optimal storage connectivity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 b/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 index 78a10f8..7119480 100755 --- a/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 +++ b/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 @@ -37,7 +37,7 @@ function Get-AbrOntapVserverIscsiInterface { 'Interface Name' = $Item.InterfaceName 'IP Address' = $Item.IpAddress 'Port' = $Item.IpPort - 'Status' = Switch ($Item.IsInterfaceEnabled) { + 'Status' = switch ($Item.IsInterfaceEnabled) { 'True' { 'Up' } 'False' { 'Down' } default { $Item.IsInterfaceEnabled } @@ -61,6 +61,15 @@ function Get-AbrOntapVserverIscsiInterface { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Iscsi -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all ISCSI interfaces are operational to maintain optimal storage connectivity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 b/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 index 187c657..8b6d4a2 100755 --- a/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 +++ b/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 @@ -40,7 +40,7 @@ function Get-AbrOntapVserverIscsiSummary { 'Max Cmds Per Session' = $Item.MaxCmdsPerSession 'Max Conn Per Session' = $Item.MaxConnPerSession 'Login Timeout' = $Item.LoginTimeout - 'Status' = Switch ($Item.IsAvailable) { + 'Status' = switch ($Item.IsAvailable) { 'True' { 'Up' } 'False' { 'Down' } default { $Item.IsAvailable } @@ -64,6 +64,15 @@ function Get-AbrOntapVserverIscsiSummary { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Iscsi -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all ISCSI services are operational to maintain optimal storage connectivity." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 b/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 index 41abd34..f92f660 100755 --- a/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 +++ b/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 @@ -49,11 +49,11 @@ function Get-AbrOntapVserverLunIgroup { 'Type' = $Item.Type 'Protocol' = $Item.Protocol 'Initiators' = $Item.Initiators.InitiatorName - 'Mapped Lun' = Switch (($MappedLun).count) { + 'Mapped Lun' = switch (($MappedLun).count) { 0 { "None" } default { $MappedLun } } - 'Reporting Nodes' = Switch (($reportingnodes).count) { + 'Reporting Nodes' = switch (($reportingnodes).count) { 0 { "None" } default { $reportingnodes } } @@ -72,6 +72,15 @@ function Get-AbrOntapVserverLunIgroup { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { ($_.'Reporting Nodes').count -gt 2 })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that igroups have an optimal number of reporting nodes to maintain performance and reliability." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverLunStorage.ps1 b/Src/Private/Get-AbrOntapVserverLunStorage.ps1 index 26094c8..5762b94 100755 --- a/Src/Private/Get-AbrOntapVserverLunStorage.ps1 +++ b/Src/Private/Get-AbrOntapVserverLunStorage.ps1 @@ -43,7 +43,7 @@ function Get-AbrOntapVserverLunStorage { 'Parent Volume' = $Item.Volume 'Path' = $Item.Path 'Serial Number' = $Item.SerialNumber - 'Initiator Group' = Switch (($lunmap).count) { + 'Initiator Group' = switch (($lunmap).count) { 0 { "None" } default { $lunmap } } @@ -53,18 +53,18 @@ function Get-AbrOntapVserverLunStorage { 'Used' = $used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue 'OS Type' = $Item.Protocol 'Is Thin' = ConvertTo-TextYN $Item.Thin - 'Space Allocation' = Switch ($Item.IsSpaceAllocEnabled) { + 'Space Allocation' = switch ($Item.IsSpaceAllocEnabled) { 'True' { 'Enabled' } 'False' { 'Disabled' } default { $Item.IsSpaceAllocEnabled } } - 'Space Reservation' = Switch ($Item.IsSpaceReservationEnabled) { + 'Space Reservation' = switch ($Item.IsSpaceReservationEnabled) { 'True' { 'Enabled' } 'False' { 'Disabled' } default { $Item.IsSpaceReservationEnabled } } 'Is Mapped' = ConvertTo-TextYN $Item.Mapped - 'Status' = Switch ($Item.Online) { + 'Status' = switch ($Item.Online) { 'True' { 'Up' } 'False' { 'Down' } default { $Item.Online } @@ -87,6 +87,15 @@ function Get-AbrOntapVserverLunStorage { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all LUNs are operational to maintain optimal storage connectivity." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 b/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 index 9187054..030269b 100755 --- a/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 +++ b/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 @@ -34,17 +34,17 @@ function Get-AbrOntapVserverNFSSummary { foreach ($Item in $VserverData) { try { $inObj = [ordered] @{ - 'Nfs v3' = Switch ($Item.IsNfsv3) { + 'Nfs v3' = switch ($Item.IsNfsv3) { 'True' { 'Enabled' } 'False' { 'Disabled' } default { $Item.IsNfsv3 } } - 'Nfs v4' = Switch ($Item.IsNfsv4) { + 'Nfs v4' = switch ($Item.IsNfsv4) { 'True' { 'Enabled' } 'False' { 'Disabled' } default { $Item.IsNfsv4 } } - 'Nfs v41' = Switch ($Item.IsNfsv41) { + 'Nfs v41' = switch ($Item.IsNfsv41) { 'True' { 'Enabled' } 'False' { 'Disabled' } default { $Item.IsNfsv41 } @@ -58,9 +58,7 @@ function Get-AbrOntapVserverNFSSummary { } } if ($Healthcheck.Vserver.NFS) { - $VserverObj | Where-Object { $_.'Nfs v3' -like 'Disabled' } | Set-Style -Style Warning -Property 'Nfs v3' - $VserverObj | Where-Object { $_.'Nfs v4' -like 'Disabled' } | Set-Style -Style Warning -Property 'Nfs v4' - $VserverObj | Where-Object { $_.'Nfs v41' -like 'Disabled' } | Set-Style -Style Warning -Property 'Nfs v41' + $VserverObj | Where-Object { $_.'Nfs v3' -like 'Disabled' -and $_.'Nfs v4' -like 'Disabled' -and $_.'Nfs v41' -like 'Disabled' } | Set-Style -Style Warning } $TableParams = @{ @@ -72,6 +70,15 @@ function Get-AbrOntapVserverNFSSummary { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.NFS -and ($VserverObj | Where-Object { $_.'Nfs v3' -like 'Disabled' -and $_.'Nfs v4' -like 'Disabled' -and $_.'Nfs v41' -like 'Disabled' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Evaluate enabling NFS services to support client connectivity and file sharing." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 b/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 index 3674b95..57f13d1 100755 --- a/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 +++ b/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 @@ -43,7 +43,7 @@ function Get-AbrOntapVserverNamespaceStorage { 'Parent Volume' = $Item.Volume 'Path' = $Item.Path 'Serial Number' = $Item.Uuid - 'Subsystem Map' = Switch (($namespacemap).count) { + 'Subsystem Map' = switch (($namespacemap).count) { 0 { "None" } default { $namespacemap.Subsystem } } @@ -52,13 +52,13 @@ function Get-AbrOntapVserverNamespaceStorage { 'Available' = $available | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue 'Used' = $used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue 'OS Type' = $Item.Ostype - 'Is Mapped' = Switch ([string]::IsNullOrEmpty($Item.Subsystem)) { + 'Is Mapped' = switch ([string]::IsNullOrEmpty($Item.Subsystem)) { $true { "No" } $false { "Yes" } default { $Item.Subsystem } } 'ReadOnly' = ConvertTo-TextYN $Item.IsReadOnly - 'Status' = Switch ($Item.State) { + 'Status' = switch ($Item.State) { 'online' { 'Up' } 'offline' { 'Down' } default { $Item.Online } @@ -81,6 +81,15 @@ function Get-AbrOntapVserverNamespaceStorage { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Sort-Object -Property 'Namespace Name' | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure that all namespaces are operational to maintain optimal storage connectivity." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 b/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 index fa7c4fb..fdd9129 100755 --- a/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 +++ b/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 @@ -59,6 +59,15 @@ function Get-AbrOntapVserverNonMappedLun { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($OutObj)) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Review non-mapped LUNs to determine if they are still required or can be removed to optimize storage resources." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 b/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 index 9b49d31..8090e74 100755 --- a/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 +++ b/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 @@ -28,7 +28,7 @@ function Get-AbrOntapVserverNonMappedNamespace { process { try { - $NamespaceFilter = Get-NcNvmeNamespace -VserverContext $Vserver -Controller $Array | Where-Object { -Not $_.Subsystem } + $NamespaceFilter = Get-NcNvmeNamespace -VserverContext $Vserver -Controller $Array | Where-Object { -not $_.Subsystem } $OutObj = @() if ($NamespaceFilter) { foreach ($Item in $NamespaceFilter) { @@ -59,6 +59,15 @@ function Get-AbrOntapVserverNonMappedNamespace { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($OutObj)) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Review non-mapped Namespaces to determine if they are still required or can be removed to optimize storage resources." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 b/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 index e3e9da4..cdf77e8 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 +++ b/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 @@ -28,7 +28,7 @@ function Get-AbrOntapVserverNvmeFcAdapter { process { try { - $VserverData = Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object {$_.PhysicalProtocol -eq 'fibre_channel'} | Sort-Object -Property HomeNode + $VserverData = Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'fibre_channel' } | Sort-Object -Property HomeNode $VserverObj = @() if ($VserverData) { foreach ($Item in $VserverData) { @@ -39,7 +39,7 @@ function Get-AbrOntapVserverNvmeFcAdapter { 'Protocol' = $Item.PhysicalProtocol 'WWNN' = $Item.FcWwnn 'WWPN' = $Item.FcWwpn - 'Status' = Switch ($Item.StatusAdmin) { + 'Status' = switch ($Item.StatusAdmin) { 'up' { 'Up' } 'down' { 'Down' } default { $Item.StatusAdmin } @@ -64,6 +64,15 @@ function Get-AbrOntapVserverNvmeFcAdapter { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.FCP -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all Nvme FC adapters are in 'Up' status to maintain optimal connectivity and performance." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 b/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 index 204c1c1..e510d6d 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 +++ b/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 @@ -37,7 +37,7 @@ function Get-AbrOntapVserverNvmeInterface { 'Interface Name' = $Item.Lif 'Transport Address' = $Item.TransportAddress 'Transport Protocols' = $Item.TransportProtocols - 'Status' = Switch ($Item.StatusAdmin) { + 'Status' = switch ($Item.StatusAdmin) { 'up' { 'Up' } 'down' { 'Down' } default { $Item.StatusAdmin } @@ -61,6 +61,15 @@ function Get-AbrOntapVserverNvmeInterface { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Nvme -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all NVME interfaces are in 'Up' status to maintain optimal connectivity and performance." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 b/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 index 4af45b6..ca01d90 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 +++ b/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 @@ -28,7 +28,7 @@ function Get-AbrOntapVserverNvmeTcpAdapter { process { try { - $VserverData = Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object {$_.PhysicalProtocol -eq 'ethernet'} | Sort-Object -Property HomeNode + $VserverData = Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'ethernet' } | Sort-Object -Property HomeNode $VserverObj = @() if ($VserverData) { foreach ($Item in $VserverData) { @@ -38,7 +38,7 @@ function Get-AbrOntapVserverNvmeTcpAdapter { 'Adapter' = $Item.HomePort 'Protocol' = $Item.PhysicalProtocol 'IP Address' = $Item.TransportAddress - 'Status' = Switch ($Item.StatusAdmin) { + 'Status' = switch ($Item.StatusAdmin) { 'up' { 'Up' } 'down' { 'Down' } default { $Item.StatusAdmin } @@ -63,6 +63,15 @@ function Get-AbrOntapVserverNvmeTcpAdapter { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.FCP -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all Nvme TCP adapters are in 'Up' status to maintain optimal connectivity and performance." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverSubsystem.ps1 b/Src/Private/Get-AbrOntapVserverSubsystem.ps1 index 1b90ff6..b00710d 100755 --- a/Src/Private/Get-AbrOntapVserverSubsystem.ps1 +++ b/Src/Private/Get-AbrOntapVserverSubsystem.ps1 @@ -48,7 +48,7 @@ function Get-AbrOntapVserverSubsystem { 'Type' = $Item.Ostype 'Target NQN' = $Item.TargetNqn 'Host NQN' = $Item.Hosts.Nqn - 'Mapped Namespace' = Switch (($MappedNamespace).count) { + 'Mapped Namespace' = switch (($MappedNamespace).count) { 0 { "None" } default { $MappedNamespace } } @@ -67,6 +67,15 @@ function Get-AbrOntapVserverSubsystem { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { ($_.'Mapped Namespace').count -eq 0 })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all subsystems have mapped namespaces to guarantee proper functionality and performance." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverSummary.ps1 b/Src/Private/Get-AbrOntapVserverSummary.ps1 index e2d7cb3..7d4a542 100755 --- a/Src/Private/Get-AbrOntapVserverSummary.ps1 +++ b/Src/Private/Get-AbrOntapVserverSummary.ps1 @@ -58,6 +58,15 @@ function Get-AbrOntapVserverSummary { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -like 'stopped' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all Vservers are in 'running' status to provide uninterrupted services." + } + BlankLine + } } try { Section -Style Heading4 'Root Volume' { diff --git a/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 b/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 index c074649..3a10b87 100755 --- a/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 @@ -50,7 +50,7 @@ function Get-AbrOntapVserverVolumeSnapshot { } } if ($Healthcheck.Vserver.Snapshot) { - $VserverObj | Where-Object { $_.'Snapshot Enabled' -eq 'True' -and $_.'Reserve Available' -eq 0 } | Set-Style -Style Warning -Property 'Reserve Size', 'Reserve Available', 'Used' + $VserverObj | Where-Object { $_.'Snapshot Enabled' -eq 'Yes' -and $_.'Reserve Available' -eq 0 } | Set-Style -Style Warning -Property 'Reserve Size', 'Reserve Available', 'Used' } $TableParams = @{ @@ -63,6 +63,15 @@ function Get-AbrOntapVserverVolumeSnapshot { } if ($VserverObj) { $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Snapshot -and ($VserverObj | Where-Object { $_.'Snapshot Enabled' -eq 'Yes' -and $_.'Reserve Available' -eq 0 })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Snapshots are enabled on volumes but there is no available snapshot reserve space. It is recommended to increase the snapshot reserve size to avoid snapshot failures." + } + BlankLine + } } } } catch { diff --git a/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 b/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 index 6b0dadf..c810933 100755 --- a/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 @@ -34,7 +34,7 @@ function Get-AbrOntapVserverVolumeSnapshotHealth { $SnapShotData = Get-NcSnapshot -Volume $VserverFilter -Vserver $Vserver -Controller $Array | Where-Object { $_.Name -notmatch "snapmirror.*" -and $_.Created -le $Now.AddDays(-$SnapshotDays) } if ($SnapShotData) { Section -Style Heading4 "HealthCheck - Volumes Snapshot" { - Paragraph "The following section provides the Vserver Volumes Snapshot HealthCheck on $($SVM)." + Paragraph "The following section provides the Vserver Volumes Snapshot HealthCheck in $($SVM)." BlankLine $VserverObj = @() foreach ($Item in $SnapShotData) { diff --git a/Src/Private/Get-AbrOntapVserverVolumes.ps1 b/Src/Private/Get-AbrOntapVserverVolumes.ps1 index 94357d0..04d2a04 100755 --- a/Src/Private/Get-AbrOntapVserverVolumes.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumes.ps1 @@ -60,6 +60,15 @@ function Get-AbrOntapVserverVolume { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -like 'offline' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all volumes are in 'online' status and monitor volume usage to prevent capacity issues." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 b/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 index 21131c1..7315427 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 @@ -59,6 +59,15 @@ function Get-AbrOntapVserverVolumesFlexclone { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj)) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Regularly monitor flexclone volumes to manage storage utilization effectively." + } + BlankLine + } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 b/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 index 37724da..2b18794 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 @@ -18,17 +18,17 @@ function Get-AbrOntapVserverVolumesFlexgroup { [Parameter ( Position = 0, Mandatory)] - [string] - $Vserver + [string] + $Vserver ) begin { - Write-PscriboMessage "Collecting ONTAP Vserver flexgroup volumes information." + Write-PScriboMessage "Collecting ONTAP Vserver flexgroup volumes information." } process { try { - $Data = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object {$_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.VolumeStateAttributes.IsFlexgroup -eq "True"} + $Data = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.VolumeStateAttributes.IsFlexgroup -eq "True" } $OutObj = @() if ($Data) { foreach ($Item in $Data) { @@ -39,9 +39,8 @@ function Get-AbrOntapVserverVolumesFlexgroup { 'Capacity' = $Item.Totalsize | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } $OutObj += [pscustomobject]$inobj - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Vserver.Status) { @@ -57,10 +56,18 @@ function Get-AbrOntapVserverVolumesFlexgroup { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($OutObj | Where-Object { $_.'Status' -like 'offline' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all flexgroup volumes are in 'online' status to maintain data availability." + } + BlankLine + } } - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } diff --git a/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 b/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 index 9e353e6..2bb0a03 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 @@ -58,6 +58,15 @@ function Get-AbrOntapVserverVolumesQtree { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -notlike 'normal' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Ensure all qtrees are in 'normal' status to maintain data integrity and accessibility." + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 b/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 index 6c606fd..0b75970 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 @@ -29,7 +29,7 @@ function Get-AbrOntapVserverVolumesQuota { process { try { Section -ExcludeFromTOC -Style Heading6 "$Vserver Vserver Volume Quota Status" { - Paragraph "The following section provides the $Vserver Volumes Quota Status Information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the $Vserver Volumes Quota Status Information in $($ClusterInfo.ClusterName)." BlankLine $VserverQuotaStatus = Get-NcQuotaStatus -VserverContext $Vserver -Controller $Array $VserverObj = @() @@ -62,6 +62,15 @@ function Get-AbrOntapVserverVolumesQuota { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams + if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $null -ne $_.'Quota Error' })) { + Paragraph "Health Check:" -Bold -Underline + BlankLine + Paragraph { + Text "Best Practice:" -Bold + Text "Review and resolve any quota errors to ensure proper quota enforcement and avoid potential data management issues." + } + BlankLine + } } } } catch { @@ -71,7 +80,7 @@ function Get-AbrOntapVserverVolumesQuota { if ($InfoLevel.Vserver -ge 2) { try { Section -ExcludeFromTOC -Style Heading6 "$Vserver Vserver Volume Quota Information" { - Paragraph "The following section provides the $Vserver Volumes Quota Information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the $Vserver Volumes Quota Information in $($ClusterInfo.ClusterName)." BlankLine $VserverQuota = Get-NcQuota -VserverContext $Vserver -Controller $Array $VserverObj = @() @@ -82,19 +91,19 @@ function Get-AbrOntapVserverVolumesQuota { 'Volume' = $Item.Volume 'Type' = $Item.QuotaType 'Target' = $Item.QuotaTarget - 'Disk Limit' = Switch ($Item.DiskLimit) { + 'Disk Limit' = switch ($Item.DiskLimit) { "-" { $Item.DiskLimit } default { $Item.DiskLimit | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } } - 'File Limit' = Switch ($Item.FileLimit) { + 'File Limit' = switch ($Item.FileLimit) { "-" { $Item.FileLimit } default { $Item.FileLimit | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue } } - 'Soft Disk Limit' = Switch ($Item.SoftDiskLimit) { + 'Soft Disk Limit' = switch ($Item.SoftDiskLimit) { "-" { $Item.SoftDiskLimit } default { $Item.SoftDiskLimit | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } } - 'Soft File Limit' = Switch ($Item.SoftFileLimit) { + 'Soft File Limit' = switch ($Item.SoftFileLimit) { "-" { $Item.SoftFileLimit } default { $Item.SoftFileLimit | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue } } @@ -128,7 +137,7 @@ function Get-AbrOntapVserverVolumesQuota { } try { Section -ExcludeFromTOC -Style Heading6 "$Vserver Vserver Volume Quota Report (Disk)" { - Paragraph "The following section provides the $Vserver Volumes Quota Report (Disk) Information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the $Vserver Volumes Quota Report (Disk) Information in $($ClusterInfo.ClusterName)." BlankLine $VserverQuotaReport = Get-NcQuotaReport -VserverContext $Vserver -Controller $Array $VserverObj = @() @@ -139,11 +148,11 @@ function Get-AbrOntapVserverVolumesQuota { 'Volume' = $Item.Volume 'Quota Target' = $Item.QuotaTarget 'Qtree' = $Item.Qtree - 'Disk Limit' = Switch ($Item.DiskLimit) { + 'Disk Limit' = switch ($Item.DiskLimit) { "-" { $Item.DiskLimit } default { $Item.DiskLimit | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } } - 'Soft Disk Limit' = Switch ($Item.SoftDiskLimit) { + 'Soft Disk Limit' = switch ($Item.SoftDiskLimit) { "-" { $Item.SoftDiskLimit } default { $Item.SoftDiskLimit | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } } @@ -177,7 +186,7 @@ function Get-AbrOntapVserverVolumesQuota { } try { Section -ExcludeFromTOC -Style Heading6 "$Vserver Vserver Volume Quota Report (File)" { - Paragraph "The following section provides the $Vserver Volumes Quota Report (File) Information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the $Vserver Volumes Quota Report (File) Information in $($ClusterInfo.ClusterName)." BlankLine $VserverQuotaReport = Get-NcQuotaReport -VserverContext $Vserver -Controller $Array $VserverObj = @() @@ -188,11 +197,11 @@ function Get-AbrOntapVserverVolumesQuota { 'Volume' = $Item.Volume 'Quota Target' = $Item.QuotaTarget 'Qtree' = $Item.Qtree - 'File Limit' = Switch ($Item.FileLimit) { + 'File Limit' = switch ($Item.FileLimit) { "-" { $Item.FileLimit } default { $Item.FileLimit | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue } } - 'Soft File Limit' = Switch ($Item.SoftFileLimit) { + 'Soft File Limit' = switch ($Item.SoftFileLimit) { "-" { $Item.SoftFileLimit } default { $Item.SoftFileLimit | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue } } diff --git a/Src/Private/SharedUtilsFunctions.ps1 b/Src/Private/SharedUtilsFunctions.ps1 index edfd4d9..73a097d 100644 --- a/Src/Private/SharedUtilsFunctions.ps1 +++ b/Src/Private/SharedUtilsFunctions.ps1 @@ -15,7 +15,7 @@ function ConvertTo-TextYN { #> [CmdletBinding()] [OutputType([String])] - Param + param ( [Parameter ( Position = 0, @@ -71,7 +71,7 @@ function ConvertTo-EmptyToFiller { #> [CmdletBinding()] [OutputType([String])] - Param + param ( [Parameter ( Position = 0, diff --git a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 index 7a53e54..ff05765 100755 --- a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 +++ b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 @@ -41,6 +41,8 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Write-Host "- Documentation: https://github.com/AsBuiltReport/AsBuiltReport.NetApp.ONTAP" Write-Host "- Issues or bug reporting: https://github.com/AsBuiltReport/AsBuiltReport.NetApp.ONTAP/issues" Write-Host "- This project is community maintained and has no sponsorship from NetApp, its employees or any of its affiliates." + Write-Host "- To sponsor this project, please visit: https://ko-fi.com/F1F8DEV80" + Write-Host "- Getting dependency information:" # Check the version of the dependency modules @@ -51,11 +53,11 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { $InstalledVersion = Get-Module -ListAvailable -Name $Module -ErrorAction SilentlyContinue | Sort-Object -Property Version -Descending | Select-Object -First 1 -ExpandProperty Version if ($InstalledVersion) { - Write-Host "- $Module module v$($InstalledVersion.ToString()) is currently installed." + Write-Host " - $Module module v$($InstalledVersion.ToString()) is currently installed." $LatestVersion = Find-Module -Name $Module -Repository PSGallery -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Version if ($InstalledVersion -lt $LatestVersion) { - Write-Host " - $Module module v$($LatestVersion.ToString()) is available." -ForegroundColor Red - Write-Host " - Run 'Update-Module -Name $Module -Force' to install the latest version." -ForegroundColor Red + Write-Host " - $Module module v$($LatestVersion.ToString()) is available." -ForegroundColor Red + Write-Host " - Run 'Update-Module -Name $Module -Force' to install the latest version." -ForegroundColor Red } } } catch { @@ -132,10 +134,8 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Section -Style Heading3 'Cluster HA Status' { Get-AbrOntapClusterHA } - if ($InfoLevel.Cluster -ge 2) { - Section -Style Heading3 'Cluster AutoSupport Status' { - Get-AbrOntapClusterASUP - } + Section -Style Heading3 'Cluster AutoSupport Status' { + Get-AbrOntapClusterASUP } } } @@ -147,10 +147,10 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Write-PScriboMessage "Node InfoLevel set at $($InfoLevel.Node)." if ($InfoLevel.Node -gt 0) { Section -Style Heading2 'Node Information' { - Paragraph "The following section provides a summary of the Node on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides a summary of the Node in $($ClusterInfo.ClusterName)." BlankLine Section -Style Heading3 'Node Inventory' { - Paragraph "The following section provides the node inventory on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the node inventory in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapNode Section -Style Heading4 'Node Vol0 Inventory' { @@ -176,15 +176,16 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Write-PScriboMessage "Storage InfoLevel set at $($InfoLevel.Node)." if ($InfoLevel.Storage -gt 0) { Section -Style Heading2 'Storage Information' { - Paragraph "The following section provides a summary of the storage hardware on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides a summary of the storage hardware in $($ClusterInfo.ClusterName)." BlankLine Section -Style Heading3 'Aggregate Inventory' { - Paragraph "The following section provides the Aggregates on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Aggregates in $($ClusterInfo.ClusterName)." BlankLine if (Get-NcAggr -Controller $Array) { $StorageAggrDiagram = Get-AbrOntapStorageAggrDiagram if ($StorageAggrDiagram) { Export-AbrOntapDiagram -DiagramObject $StorageAggrDiagram -MainDiagramLabel "Storage Aggregate Diagram" -FileName "AsBuiltReport.NetApp.Ontap.StorageAggr" + BlankLine } else { Write-PScriboMessage -IsWarning "Unable to generate the Storage Aggregate Diagram." } @@ -204,10 +205,10 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } Section -Style Heading3 'Disk Information' { - Paragraph "The following section provides the disk summary information on controller $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the disk summary information in controller $($ClusterInfo.ClusterName)." BlankLine Section -Style Heading4 'Per Node Disk Assignment' { - Paragraph "The following section provides the number of disks assigned to each controller on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the number of disks assigned to each controller in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapDiskAssign } @@ -243,9 +244,9 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { # License Section # #---------------------------------------------------------------------------------------------# Write-PScriboMessage "License InfoLevel set at $($InfoLevel.License)." - if ($InfoLevel.License -gt 0) { + if ($InfoLevel.License -gt 0 -and (Get-NcLicense -Controller $Array)) { Section -Style Heading2 'Licenses Information' { - Paragraph "The following section provides a summary of the license usage on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides a summary of the license usage in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapClusterLicense if ($InfoLevel.License -ge 2) { @@ -254,6 +255,8 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } } + } else { + Write-PScriboMessage -IsWarning "No license information found on $($ClusterInfo.ClusterName) or License InfoLevel is set to 0." } #---------------------------------------------------------------------------------------------# @@ -262,14 +265,14 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Write-PScriboMessage "Network InfoLevel set at $($InfoLevel.Network)." if ($InfoLevel.Network -gt 0) { Section -Style Heading2 'Network Information' { - Paragraph "The following section provides a summary of the networking features on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides a summary of the networking features in $($ClusterInfo.ClusterName)." BlankLine Section -Style Heading3 'IPSpace' { - Paragraph "The following section provides the IPSpace information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the IPSpace information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapNetworkIpSpace Section -Style Heading4 'Network Ports' { - Paragraph "The following section provides the physical network ports on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the physical network ports in $($ClusterInfo.ClusterName)." BlankLine $Nodes = Get-NcNode -Controller $Array foreach ($Node in $Nodes) { @@ -280,7 +283,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } if (Get-NcNetPortIfgrp -Controller $Array) { Section -Style Heading3 'Network Link Aggregation Group' { - Paragraph "The following section provides per Node IFGRP Aggregated Ports on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides per Node IFGRP Aggregated Ports in $($ClusterInfo.ClusterName)." BlankLine $Nodes = Get-NcNode -Controller $Array foreach ($Node in $Nodes) { @@ -292,14 +295,16 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } } - Section -Style Heading3 'Network VLANs' { - Paragraph "The following section provides Network VLAN information on $($ClusterInfo.ClusterName)." - BlankLine - $Nodes = Get-NcNode -Controller $Array - foreach ($Node in $Nodes) { - if (Get-NcNetPortVlan -Node $Node -Controller $Array) { - Section -Style Heading4 "$Node Vlans" { - Get-AbrOntapNetworkVlan -Node $Node + if (Get-NcNetPortVlan -Controller $Array) { + Section -Style Heading3 'Network VLANs' { + Paragraph "The following section provides Network VLAN information in $($ClusterInfo.ClusterName)." + BlankLine + $Nodes = Get-NcNode -Controller $Array + foreach ($Node in $Nodes) { + if (Get-NcNetPortVlan -Node $Node -Controller $Array) { + Section -Style Heading4 "$Node Vlans" { + Get-AbrOntapNetworkVlan -Node $Node + } } } } @@ -319,7 +324,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { foreach ($SVM in $Vservers) { if (Get-NcNetRoute -VserverContext $SVM -Controller $Array) { Section -Style Heading4 "$SVM Vserver Routes" { - Paragraph "The following section provides the Routes information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Routes information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapNetworkRoute -Vserver $SVM if ($InfoLevel.Network -ge 2) { @@ -331,7 +336,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } Section -Style Heading4 'Network Interfaces' { - Paragraph "The following section provides the Network Interfaces information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Network Interfaces information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapNetworkMgmt } @@ -346,7 +351,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { if ($InfoLevel.Vserver -gt 0) { if (Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq "data" }) { Section -Style Heading2 'Vserver Information' { - Paragraph "The following section provides a summary of the vserver information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides a summary of the vserver information in $($ClusterInfo.ClusterName)." BlankLine $Vservers = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq "data" -and $_.Vserver -notin $Options.Exclude.Vserver } | Select-Object -ExpandProperty Vserver foreach ($SVM in $Vservers) { @@ -357,7 +362,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { if ($InfoLevel.Vserver -ge 2) { if (Get-NcVol -Controller $Array | Select-Object -ExpandProperty VolumeQosAttributes) { Section -Style Heading4 'Volumes QoS Policy' { - Paragraph "The following section provides the Vserver QoS Configuration on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Vserver QoS Configuration in $($ClusterInfo.ClusterName)." Section -Style Heading5 'Volumes Fixed QoS Policy' { Get-AbrOntapVserverVolumesQosGPFixed } @@ -418,14 +423,14 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } Section -Style Heading4 "Protocol Information" { - Paragraph "The following section provides a summary of the Vserver protocol information on $($SVM)." + Paragraph "The following section provides a summary of the Vserver protocol information in $($SVM)." BlankLine #---------------------------------------------------------------------------------------------# # NFS Section # #---------------------------------------------------------------------------------------------# if (Get-NcNfsService -VserverContext $SVM -Controller $Array) { Section -Style Heading5 "NFS Services" { - Paragraph "The following section provides the NFS Service Information on $($SVM)." + Paragraph "The following section provides the NFS Service Information in $($SVM)." BlankLine Get-AbrOntapVserverNFSSummary -Vserver $SVM if ($InfoLevel.Vserver -ge 2) { @@ -445,7 +450,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# if (Get-NcVserver -VserverContext $SVM -Controller $Array | Where-Object { $_.VserverType -eq 'data' -and $_.AllowedProtocols -eq 'cifs' -and $_.State -eq 'running' } | Get-NcCifsServerStatus -Controller $Array -ErrorAction SilentlyContinue) { Section -Style Heading5 "CIFS Services Information" { - Paragraph "The following section provides the CIFS Service Information on $($SVM)." + Paragraph "The following section provides the CIFS Service Information in $($SVM)." BlankLine Get-AbrOntapVserverCIFSSummary -Vserver $SVM if ($InfoLevel.Vserver -ge 2) { @@ -487,7 +492,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# if ( Get-NcNvme -Controller $Array | Where-Object { $_.Vserver -eq $SVM } ) { Section -Style Heading5 'Nvme Services Information' { - Paragraph "The following section provides the Nvme Service Information on $($SVM)." + Paragraph "The following section provides the Nvme Service Information in $($SVM)." BlankLine # Get-AbrOntapVserverNvmeSummary -Vserver $SVM if (Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'fibre_channel' }) { @@ -510,7 +515,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# if ( Get-NcIscsiService -Controller $Array | Where-Object { $_.Vserver -eq $SVM } ) { Section -Style Heading5 "ISCSI Services" { - Paragraph "The following section provides the ISCSI Service Information on $($SVM)." + Paragraph "The following section provides the ISCSI Service Information in $($SVM)." BlankLine Get-AbrOntapVserverIscsiSummary -Vserver $SVM Section -ExcludeFromTOC -Style Heading6 "ISCSI Interfaces" { @@ -530,7 +535,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# if ( Get-NcFcpService -Controller $Array | Where-Object { $_.Vserver -eq $SVM } ) { Section -Style Heading5 'FCP Services Information' { - Paragraph "The following section provides the FCP Service Information on $($SVM)." + Paragraph "The following section provides the FCP Service Information in $($SVM)." BlankLine Get-AbrOntapVserverFcpSummary -Vserver $SVM Section -ExcludeFromTOC -Style Heading6 'FCP Physical Adapter' { @@ -546,20 +551,20 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# if (Get-NcLun -Controller $Array | Where-Object { $_.Vserver -eq $SVM }) { Section -Style Heading5 'Lun Storage' { - Paragraph "The following section provides the Lun Storage Information on $($SVM)." + Paragraph "The following section provides the Lun Storage Information in $($SVM)." BlankLine Get-AbrOntapVserverLunStorage -Vserver $SVM if (Get-NcIgroup -Vserver $SVM -Controller $Array) { Section -ExcludeFromTOC -Style Heading6 'Igroup Mapping' { Get-AbrOntapVserverLunIgroup -Vserver $SVM } - $NonMappedLun = Get-AbrOntapVserverNonMappedLun -Vserver $SVM - if ($Healthcheck.Vserver.Status -and $NonMappedLun) { - Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Non-Mapped Lun Information' { - Paragraph "The following section provides information of Non Mapped Lun on $($SVM)." - BlankLine - $NonMappedLun - } + } + $NonMappedLun = Get-AbrOntapVserverNonMappedLun -Vserver $SVM + if ($Healthcheck.Vserver.Status -and $NonMappedLun) { + Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Non-Mapped Lun Information' { + Paragraph "The following section provides information of Non Mapped Lun in $($SVM)." + BlankLine + $NonMappedLun } } } @@ -569,20 +574,20 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# if (Get-NcNvmeNamespace -Controller $Array | Where-Object { $_.Vserver -eq $SVM }) { Section -Style Heading5 'Namespace Storage' { - Paragraph "The following section provides the Namespace Storage Information on $($SVM)." + Paragraph "The following section provides the Namespace Storage Information in $($SVM)." BlankLine Get-AbrOntapVserverNamespaceStorage -Vserver $SVM if (Get-NcNvmeSubsystem -Vserver $SVM -Controller $Array) { Section -ExcludeFromTOC -Style Heading6 'Subsystem Mapping' { Get-AbrOntapVserverSubsystem -Vserver $SVM } - $NonMappedNamespace = Get-AbrOntapVserverNonMappedNamespace -Vserver $SVM - if ($Healthcheck.Vserver.Status -and $NonMappedNamespace) { - Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Non-Mapped Namespace Information' { - Paragraph "The following table provides information about Non Mapped Namespace on $($SVM)." - BlankLine - $NonMappedNamespace - } + } + $NonMappedNamespace = Get-AbrOntapVserverNonMappedNamespace -Vserver $SVM + if ($Healthcheck.Vserver.Status -and $NonMappedNamespace) { + Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Non-Mapped Namespace Information' { + Paragraph "The following table provides information about Non Mapped Namespace in $($SVM)." + BlankLine + $NonMappedNamespace } } } @@ -593,7 +598,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { $CGs = Get-NetAppOntapAPI -uri "/api/application/consistency-groups?svm=$SVM&fields=**&return_records=true&return_timeout=15" if ($CGs) { Section -Style Heading5 'Consistency Groups' { - Paragraph "The following section provides Consistency Group Information on $($SVM)." + Paragraph "The following section provides Consistency Group Information in $($SVM)." BlankLine Get-AbrOntapVserverCGSummary -Vserver $SVM foreach ($CG in $CGs) { @@ -616,7 +621,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { $S3Data = Get-NetAppOntapAPI -uri "/api/protocols/s3/services?svm=$SVM&fields=*&return_records=true&return_timeout=15" if ($S3Data) { Section -Style Heading5 'S3 Services Configuration Information' { - Paragraph "The following section provides the S3 Service Information on $($SVM)." + Paragraph "The following section provides the S3 Service Information in $($SVM)." BlankLine Get-AbrOntapVserverS3Summary -Vserver $SVM Section -ExcludeFromTOC -Style Heading6 'S3 Buckets' { @@ -638,7 +643,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { if ($InfoLevel.Replication -gt 0) { if (Get-NcClusterPeer -Controller $Array) { Section -Style Heading2 'Replication Information' { - Paragraph "The following section provides a summary of the replication information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides a summary of the replication information in $($ClusterInfo.ClusterName)." BlankLine $ClusterReplicationDiagram = Get-AbrOntapClusterReplicationDiagram if ($ClusterReplicationDiagram) { @@ -647,7 +652,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Write-PScriboMessage -IsWarning "Unable to generate the Cluster Replication Diagram." } Section -Style Heading3 'Cluster Peer' { - Paragraph "The following section provides the Cluster Peer information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Cluster Peer information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapRepClusterPeer } @@ -686,11 +691,11 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { $Vservers = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq "data" -and $_.Vserver -notin $Options.Exclude.Vserver } | Select-Object -ExpandProperty Vserver if (Get-NcAggrEfficiency -Controller $Array) { Section -Style Heading2 'Efficiency Information' { - Paragraph "The following section provides the Storage Efficiency Saving information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Storage Efficiency Saving information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapEfficiencyConfig Section -Style Heading3 'Aggregate Total Efficiency' { - Paragraph "The following section provides the Aggregate Efficiency Saving information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Aggregate Efficiency Saving information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapEfficiencyAggr foreach ($SVM in $Vservers) { @@ -721,12 +726,12 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { if ($InfoLevel.Security -gt 0) { $Vservers = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq "data" -or $_.VserverType -eq "admin" -and $_.Vserver -notin $Options.Exclude.Vserver } | Select-Object -ExpandProperty Vserver Section -Style Heading2 'Security Information' { - Paragraph "The following section provides the Security related information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Security related information in $($ClusterInfo.ClusterName)." BlankLine foreach ($SVM in $Vservers) { if (Get-NcUser -Vserver $SVM -Controller $Array) { Section -Style Heading3 "$SVM Vserver Local User" { - Paragraph "The following section provides the Local User information on $($SVM)." + Paragraph "The following section provides the Local User information in $($SVM)." BlankLine Get-AbrOntapSecurityUser -Vserver $SVM } @@ -745,7 +750,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } if (Get-NcSecuritySsl -Controller $Array) { Section -Style Heading3 'Vserver SSL Certificate' { - Paragraph "The following section provides the Vserver SSL Certificates information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Vserver SSL Certificates information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapSecuritySSLVserver Section -Style Heading4 'Vserver SSL Certificate Details' { @@ -755,14 +760,16 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } if (Get-NcSecurityKeyManagerKeyStore -ErrorAction SilentlyContinue -Controller $Array) { Section -Style Heading3 'Key Management Service (KMS)' { - Paragraph "The following section provides the Key Management Service type on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Key Management Service type in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapSecurityKMS if (Get-NcSecurityKeyManagerExternal -Controller $Array) { Section -Style Heading4 'External KMS' { Get-AbrOntapSecurityKMSExt - Section -Style Heading5 'External KMS Status' { - Get-AbrOntapSecurityKMSExtStatus + if (Get-NcSecurityKeyManager -Controller $Array) { + Section -Style Heading5 'External KMS Status' { + Get-AbrOntapSecurityKMSExtStatus + } } } } @@ -770,7 +777,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } if (Get-NcAggr -Controller $Array) { Section -Style Heading3 'Aggregate Encryption (NAE)' { - Paragraph "The following section provides the Aggregate Encryption (NAE) information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Aggregate Encryption (NAE) information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapSecurityNAE Section -Style Heading4 'Volume Encryption (NVE)' { @@ -779,7 +786,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } Section -Style Heading3 'Snaplock Compliance Clock' { - Paragraph "The following section provides the Snaplock Compliance Clock information on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Snaplock Compliance Clock information in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapSecuritySnapLockClock Section -Style Heading4 'Aggregate Snaplock Type' { @@ -806,7 +813,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { if ($InfoLevel.System -gt 0) { if (Get-NcTime) { Section -Style Heading2 'System Configuration Information' { - Paragraph "The following section provides the Cluster System Configuration on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the Cluster System Configuration in $($ClusterInfo.ClusterName)." BlankLine if (Get-NcSystemImage -Controller $Array) { Section -Style Heading3 'System Image Configuration' { @@ -845,7 +852,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } if (Get-NcEmsDestination -Controller $Array) { Section -Style Heading3 'EMS Configuration' { - Paragraph "The following section provides the EMS Configuration on $($ClusterInfo.ClusterName)." + Paragraph "The following section provides the EMS Configuration in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapSysConfigEMSSetting if ($InfoLevel.System -ge 2) { @@ -861,17 +868,15 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } if (Get-NcTimezone -Controller $Array) { - Section -Style Heading3 'System Timezone Configuration' { - Paragraph "The following section provides the System Timezone Configuration on $($ClusterInfo.ClusterName)." + Section -Style Heading3 'Timezone Configuration' { + Paragraph "The following section provides the Timezone Configuration in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapSysConfigTZ - if (Get-NcNtpServer -Controller $Array) { - Section -Style Heading4 'NTP Configuration' { - Get-AbrOntapSysConfigNTP - if ($InfoLevel.System -ge 2) { - Section -Style Heading5 'NTP Node Status Information' { - Get-AbrOntapSysConfigNTPHost - } + Section -Style Heading4 'NTP Configuration' { + Get-AbrOntapSysConfigNTP + if ($InfoLevel.System -ge 2 -and (Get-NcNtpServerStatus -Controller $Array)) { + Section -Style Heading5 'NTP Node Status Information' { + Get-AbrOntapSysConfigNTPHost } } }