diff --git a/.github/Dependabot.yml b/.github/Dependabot.yml index 244a5f8..ad1a88d 100644 --- a/.github/Dependabot.yml +++ b/.github/Dependabot.yml @@ -15,22 +15,4 @@ updates: 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 + open-pull-requests-limit: 5 \ No newline at end of file diff --git a/.github/workflows/PSScriptAnalyzer.yml b/.github/workflows/PSScriptAnalyzer.yml index edf12f4..700425b 100755 --- a/.github/workflows/PSScriptAnalyzer.yml +++ b/.github/workflows/PSScriptAnalyzer.yml @@ -5,7 +5,7 @@ jobs: name: Run PSScriptAnalyzer runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: lint uses: alagoutte/github-action-psscriptanalyzer@master with: diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 3d90aae..d10d2b1 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -8,7 +8,7 @@ jobs: publish-to-gallery: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Set PSRepository to Trusted for PowerShell Gallery shell: pwsh run: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f64bb63..c944b8c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -29,7 +29,7 @@ jobs: name: PSScriptAnalyzer runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Run PSScriptAnalyzer uses: microsoft/psscriptanalyzer-action@v1.1 @@ -44,6 +44,6 @@ jobs: # Upload the SARIF file generated in the previous step - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: results.sarif diff --git a/CHANGELOG.md b/CHANGELOG.md index 0591fad..083265c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bump Diagrammer.Core module requirement to v0.2.36 - Bump module version to v0.6.12 +- Update github actions to use latest version ### Fixed @@ -29,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Enhance Get-AbrOntapNodesSP function with detailed service-processor information - Fix model property assignment in Get-AbrOntapStorageAggrDiagram function - Fix Volume SnapShot Configuration section showing healthcheck for non violated item +- Fix CodeQL analysis issues 27 ### Removed diff --git a/README.md b/README.md index 5d43d84..5787f18 100755 --- a/README.md +++ b/README.md @@ -54,9 +54,9 @@ The ONTAP Storage As Built Report supports the following ONTAP versions; This report is compatible with the following PowerShell versions; -| PowerShell 5.1 | PowerShell 7 | -| :----------------: | :----------------: | -| :white_check_mark: | :white_check_mark: | +| PowerShell 5.1 | PowerShell 7 | +| :------------: | :----------------: | +| :x: | :white_check_mark: | ## :wrench: System Requirements @@ -74,7 +74,7 @@ These modules may also be manually installed. ### PowerShell -Open a PowerShell terminal window and install each of the required modules as follows; +Open a PowerShell 7 terminal window and install each of the required modules as follows; ```powershell Install-Module -Name AsBuiltReport.NetApp.ONTAP diff --git a/Src/Private/Get-AbrOntapCluster.ps1 b/Src/Private/Get-AbrOntapCluster.ps1 index 4c0be9c..20d00bc 100755 --- a/Src/Private/Get-AbrOntapCluster.ps1 +++ b/Src/Private/Get-AbrOntapCluster.ps1 @@ -26,25 +26,28 @@ function Get-AbrOntapCluster { try { $ClusterInfo = Get-NcCluster -Controller $Array if ($ClusterInfo) { - $ClusterDiag = Get-NcDiagnosisStatus -Controller $Array - $ClusterVersion = Get-NcSystemVersion -Controller $Array - $ArrayAggr = Get-NcAggr -Controller $Array - $ArrayVolumes = Get-NcVol -Controller $Array - $ClusterSummary = [PSCustomObject] @{ - 'Cluster Name' = $ClusterInfo.ClusterName - 'Cluster UUID' = $ClusterInfo.ClusterUuid - 'Cluster Serial' = $ClusterInfo.ClusterSerialNumber - 'Cluster Controller' = $ClusterInfo.NcController - 'Cluster Contact' = $ClusterInfo.ClusterContact - 'Cluster Location' = $ClusterInfo.ClusterLocation - 'Ontap Version' = $ClusterVersion.value - 'Number of Aggregates' = $ArrayAggr.count - 'Number of Volumes' = $ArrayVolumes.count - 'Overall System Health' = ${ClusterDiag}?.Status?.ToUpper() + $OutObj = @() + try { + $inObj = [ordered] @{ + 'Cluster Name' = $ClusterInfo.ClusterName + 'Cluster UUID' = $ClusterInfo.ClusterUuid + 'Cluster Serial' = $ClusterInfo.ClusterSerialNumber + 'Cluster Controller' = $ClusterInfo.NcController + 'Cluster Contact' = $ClusterInfo.ClusterContact ?? '--' + 'Cluster Location' = $ClusterInfo.ClusterLocation ?? '--' + 'Ontap Version' = (Get-NcSystemVersion -Controller $Array).value ?? 'Unknown' + 'Number of Aggregates' = (Get-NcAggr -Controller $Array).count ?? 'Unknown' + 'Number of Volumes' = (Get-NcVol -Controller $Array).count ?? 'Unknown' + 'Overall System Health' = (Get-NcDiagnosisStatus -Controller $Array).Status?.ToUpper() ?? 'Unknown' + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } + if ($Healthcheck.Cluster.Summary) { - $ClusterSummary | Where-Object { $_.'Overall System Health' -like 'OK' } | Set-Style -Style OK -Property 'Overall System Health' - $ClusterSummary | Where-Object { $_.'Overall System Health' -notlike 'OK' } | Set-Style -Style Critical -Property 'Overall System Health' + $OutObj | Where-Object { $_.'Overall System Health' -like 'OK' } | Set-Style -Style OK -Property 'Overall System Health' + $OutObj | Where-Object { $_.'Overall System Health' -notlike 'OK' } | Set-Style -Style Critical -Property 'Overall System Health' } $TableParams = @{ @@ -55,8 +58,8 @@ function Get-AbrOntapCluster { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $ClusterSummary | Table @TableParams - if ($Healthcheck.Cluster.Summary -and ($ClusterSummary | Where-Object { $_.'Overall System Health' -notlike 'OK' })) { + $OutObj | Table @TableParams + if ($Healthcheck.Cluster.Summary -and ($OutObj | Where-Object { $_.'Overall System Health' -notlike 'OK' })) { Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { diff --git a/Src/Private/Get-AbrOntapClusterHA.ps1 b/Src/Private/Get-AbrOntapClusterHA.ps1 index 1f40b8e..11ece46 100755 --- a/Src/Private/Get-AbrOntapClusterHA.ps1 +++ b/Src/Private/Get-AbrOntapClusterHA.ps1 @@ -26,10 +26,11 @@ function Get-AbrOntapClusterHA { try { $NodeSum = Get-NcNode -Controller $Array | Where-Object { $null -ne $_.NodeModel } if ($NodeSum) { - $NodeSummary = foreach ($Nodes in $NodeSum) { + $OutObj = @() + foreach ($Nodes in $NodeSum) { try { $ClusterHa = Get-NcClusterHa -Node $Nodes.Node -Controller $Array - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Name' = $Nodes.Node 'Partner' = $ClusterHa.Partner ?? '--' 'TakeOver Possible' = $ClusterHa.TakeoverPossible @@ -37,14 +38,15 @@ function Get-AbrOntapClusterHA { 'HA Mode' = $ClusterHa.CurrentMode 'HA State' = $ClusterHa.State } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Cluster.HA) { - $NodeSummary | Where-Object { $_.'TakeOver State' -like 'in_takeover' } | Set-Style -Style Warning -Property 'TakeOver State' - $NodeSummary | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' } | Set-Style -Style Warning -Property 'HA State' - $NodeSummary | Where-Object { $_.'TakeOver Possible' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' } | Set-Style -Style Warning -Property 'TakeOver Possible' + $OutObj | Where-Object { $_.'TakeOver State' -like 'in_takeover' } | Set-Style -Style Warning -Property 'TakeOver State' + $OutObj | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' } | Set-Style -Style Warning -Property 'HA State' + $OutObj | Where-Object { $_.'TakeOver Possible' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' } | Set-Style -Style Warning -Property 'TakeOver Possible' } $TableParams = @{ @@ -55,25 +57,25 @@ function Get-AbrOntapClusterHA { if ($Report.ShowTableCaptions) { $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' -and $_.'HA Mode' -ne 'non_ha' }))) { + $OutObj | Table @TableParams + if ($Healthcheck.Cluster.HA -and (($OutObj | Where-Object { $_.'TakeOver State' -like 'in_takeover' } ) -or ($OutObj | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' }) -or ($OutObj | Where-Object { $_.'TakeOver Possible' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' }))) { Paragraph 'Health Check:' -Bold -Underline BlankLine - if ($NodeSummary | Where-Object { $_.'TakeOver State' -like 'in_takeover' }) { + if ($OutObj | 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' }) { + if ($OutObj | 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' }) { + if ($OutObj | 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.' diff --git a/Src/Private/Get-AbrOntapClusterLicense.ps1 b/Src/Private/Get-AbrOntapClusterLicense.ps1 index 965c9cd..b899ed7 100755 --- a/Src/Private/Get-AbrOntapClusterLicense.ps1 +++ b/Src/Private/Get-AbrOntapClusterLicense.ps1 @@ -30,18 +30,19 @@ function Get-AbrOntapClusterLicense { $License = Get-NcLicense -Owner $Node -Controller $Array if ($License) { Section -Style Heading3 "$Node License Usage" { - $LicenseSummary = foreach ($Licenses in $License) { - $EntitlementRisk = try { Get-NcLicenseEntitlementRisk -Package $Licenses.Package -Controller $Array -ErrorAction SilentlyContinue } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } - [PSCustomObject] @{ + $OutObj = @() + foreach ($Licenses in $License) { + $inObj = [ordered] @{ 'License' = $TextInfo.ToTitleCase($Licenses.Package) 'Type' = $TextInfo.ToTitleCase($Licenses.Type) 'Description' = $Licenses.Description 'Risk' = (Get-NcLicenseEntitlementRisk -Package $Licenses.Package -Controller $Array).Risk ?? '--' } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } if ($Healthcheck.License.RiskSummary) { - $LicenseSummary | Where-Object { $_.'Risk' -like 'medium' -or $_.'Risk' -like 'unknown' -or $_.'Risk' -like 'unlicensed' } | Set-Style -Style Warning -Property 'Risk' - $LicenseSummary | Where-Object { $_.'Risk' -like 'High' } | Set-Style -Style Critical -Property 'Risk' + $OutObj | Where-Object { $_.'Risk' -like 'medium' -or $_.'Risk' -like 'unknown' -or $_.'Risk' -like 'unlicensed' } | Set-Style -Style Warning -Property 'Risk' + $OutObj | Where-Object { $_.'Risk' -like 'High' } | Set-Style -Style Critical -Property 'Risk' } $TableParams = @{ Name = "License Usage - $($Node)" @@ -51,8 +52,8 @@ function Get-AbrOntapClusterLicense { if ($Report.ShowTableCaptions) { $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' })) { + $OutObj | Table @TableParams + if ($Healthcheck.License.RiskSummary -and ($OutObj | Where-Object { $_.'Risk' -like 'medium' -or $_.'Risk' -like 'unknown' -or $_.'Risk' -like 'unlicensed' }) -or ($OutObj | Where-Object { $_.'Risk' -like 'High' })) { Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { diff --git a/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 b/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 index 8bf97f8..99f213d 100755 --- a/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 +++ b/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 @@ -26,12 +26,14 @@ function Get-AbrOntapClusterLicenseUsage { try { $LicenseFeature = Get-NcFeatureStatus -Controller $Array if ($LicenseFeature) { - $LicenseFeature = foreach ($NodeLFs in $LicenseFeature) { - [PSCustomObject] @{ + $OutObj = @() + foreach ($NodeLFs in $LicenseFeature) { + $inObj = [ordered] @{ 'Name' = $NodeLFs.FeatureName 'Status' = $NodeLFs.Status 'Notes' = $NodeLFs.Notes } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } $TableParams = @{ Name = "License Feature - $($ClusterInfo.ClusterName)" @@ -41,7 +43,7 @@ function Get-AbrOntapClusterLicenseUsage { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $LicenseFeature | Table @TableParams + $OutObj | Table @TableParams } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapDiskAssign.ps1 b/Src/Private/Get-AbrOntapDiskAssign.ps1 index 79c1d88..d459fab 100755 --- a/Src/Private/Get-AbrOntapDiskAssign.ps1 +++ b/Src/Private/Get-AbrOntapDiskAssign.ps1 @@ -26,11 +26,13 @@ function Get-AbrOntapDiskAssign { try { $NodeDiskCount = Get-NcDisk -Controller $Array | ForEach-Object { $_.DiskOwnershipInfo.HomeNodeName } | Group-Object if ($NodeDiskCount) { - $DiskSummary = foreach ($Disks in $NodeDiskCount) { - [PSCustomObject] @{ + $OutObj = @() + foreach ($Disks in $NodeDiskCount) { + $inObj = [ordered] @{ 'Node' = $Disks.Name 'Disk Count' = $Disks | Select-Object -ExpandProperty Count } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } $TableParams = @{ Name = "Assigned Disk - $($ClusterInfo.ClusterName)" @@ -40,7 +42,7 @@ function Get-AbrOntapDiskAssign { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $DiskSummary | Table @TableParams + $OutObj | Table @TableParams } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapDiskBroken.ps1 b/Src/Private/Get-AbrOntapDiskBroken.ps1 index c9496cf..05c2135 100755 --- a/Src/Private/Get-AbrOntapDiskBroken.ps1 +++ b/Src/Private/Get-AbrOntapDiskBroken.ps1 @@ -26,17 +26,19 @@ function Get-AbrOntapDiskBroken { try { $NodeDiskBroken = Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq 'broken' } if ($NodeDiskBroken) { - $DiskFailed = foreach ($DiskBroken in $NodeDiskBroken) { - [PSCustomObject] @{ + $OutObj = @() + foreach ($DiskBroken in $NodeDiskBroken) { + $inObj = [ordered] @{ 'Disk Name' = $DiskBroken.Name 'Shelf' = $DiskBroken.Shelf 'Bay' = $DiskBroken.Bay 'Pool' = $DiskBroken.Pool 'Disk Paths' = $DiskBroken.DiskPaths } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } if ($Healthcheck.Storage.DiskStatus) { - $DiskFailed | Set-Style -Style Critical -Property 'Disk Name', 'Shelf', 'Bay', 'Pool', 'Disk Paths' + $OutObj | Set-Style -Style Critical -Property 'Disk Name', 'Shelf', 'Bay', 'Pool', 'Disk Paths' } $TableParams = @{ Name = "Failed Disk - $($ClusterInfo.ClusterName)" @@ -46,8 +48,8 @@ function Get-AbrOntapDiskBroken { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $DiskFailed | Table @TableParams - if ($Healthcheck.Storage.DiskStatus -and ($DiskFailed)) { + $OutObj | Table @TableParams + if ($Healthcheck.Storage.DiskStatus -and ($OutObj)) { Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { diff --git a/Src/Private/Get-AbrOntapDiskInv.ps1 b/Src/Private/Get-AbrOntapDiskInv.ps1 index d6d810e..055a428 100755 --- a/Src/Private/Get-AbrOntapDiskInv.ps1 +++ b/Src/Private/Get-AbrOntapDiskInv.ps1 @@ -27,16 +27,17 @@ function Get-AbrOntapDiskInv { $DiskInv = Get-NcDisk -Controller $Array $NodeDiskBroken = Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq 'broken' } if ($DiskInv) { - $DiskInventory = foreach ($Disks in $DiskInv) { + $OutObj = @() + foreach ($Disks in $DiskInv) { try { - $DiskType = Get-NcDisk -Controller $Array -Name $Disks.Name | ForEach-Object { $_.DiskInventoryInfo } + $DiskType = Get-NcDisk -Controller $Array -Name $Disks.Name | ForEach-Object { $_.OutObjInfo } $DiskFailed = $NodeDiskBroken | Where-Object { $_.'Name' -eq $Disks.Name } if ($DiskFailed.Name -eq $Disks.Name ) { $Disk = " $($DiskFailed.Name)(*)" } else { $Disk = $Disks.Name } - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Disk Name' = $Disk 'Shelf' = $Disks.Shelf 'Bay' = $Disks.Bay @@ -45,12 +46,13 @@ function Get-AbrOntapDiskInv { 'Serial Number' = $DiskType.SerialNumber 'Type' = $DiskType.DiskType } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Storage.DiskStatus) { - $DiskInventory | Where-Object { $_.'Disk Name' -like '*(*)' } | Set-Style -Style Critical -Property 'Disk Name' + $OutObj | Where-Object { $_.'Disk Name' -like '*(*)' } | Set-Style -Style Critical -Property 'Disk Name' } $TableParams = @{ Name = "Disk Inventory - $($ClusterInfo.ClusterName)" @@ -60,7 +62,7 @@ function Get-AbrOntapDiskInv { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $DiskInventory | Table @TableParams + $OutObj | Table @TableParams } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapDiskOwner.ps1 b/Src/Private/Get-AbrOntapDiskOwner.ps1 index a31c104..4067f35 100755 --- a/Src/Private/Get-AbrOntapDiskOwner.ps1 +++ b/Src/Private/Get-AbrOntapDiskOwner.ps1 @@ -30,16 +30,18 @@ function Get-AbrOntapDiskOwner { process { try { if ($Node) { - $DiskSummary = foreach ($Owner in $Node) { + $OutObj = @() + foreach ($Owner in $Node) { try { foreach ($Disk in (Get-NcDiskOwner -Node $Owner -Controller $Array)) { - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Disk' = $Disk.Name 'Owner Id' = $Disk.OwnerId 'Home' = $Disk.Home 'Home Id' = $Disk.HomeId 'Type' = $Disk.Type } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message @@ -53,7 +55,7 @@ function Get-AbrOntapDiskOwner { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $DiskSummary | Table @TableParams + $OutObj | Table @TableParams } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapDiskShelf.ps1 b/Src/Private/Get-AbrOntapDiskShelf.ps1 index 5a5021f..3981912 100755 --- a/Src/Private/Get-AbrOntapDiskShelf.ps1 +++ b/Src/Private/Get-AbrOntapDiskShelf.ps1 @@ -26,11 +26,12 @@ function Get-AbrOntapDiskShelf { try { $NodeSum = Get-NcNode -Controller $Array if ($NodeSum) { - $ShelfInventory = foreach ($Nodes in $NodeSum) { + $OutObj = @() + foreach ($Nodes in $NodeSum) { try { $Nodeshelf = Get-NcShelf -NodeName $Nodes.Node -Controller $Array if ($Nodeshelf) { - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Node Name' = $Nodeshelf.NodeName 'Channel' = $Nodeshelf.ChannelName 'Shelf Name' = $Nodeshelf.ShelfName @@ -40,14 +41,15 @@ function Get-AbrOntapDiskShelf { 'Firmware' = $Nodeshelf.FirmwareRevA + $Nodeshelf.FirmwareRevB 'Bay Count' = $Nodeshelf.ShelfBayCount } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Storage.ShelfStatus) { - $ShelfInventory | Where-Object { $_.'State' -like 'offline' -or $_.'State' -like 'missing' } | Set-Style -Style Critical -Property 'State' - $ShelfInventory | Where-Object { $_.'State' -like 'unknown' -or $_.'State' -like 'no-status' } | Set-Style -Style Warning -Property 'State' + $OutObj | Where-Object { $_.'State' -like 'offline' -or $_.'State' -like 'missing' } | Set-Style -Style Critical -Property 'State' + $OutObj | Where-Object { $_.'State' -like 'unknown' -or $_.'State' -like 'no-status' } | Set-Style -Style Warning -Property 'State' } $TableParams = @{ Name = "Shelf Inventory - $($ClusterInfo.ClusterName)" @@ -57,8 +59,8 @@ function Get-AbrOntapDiskShelf { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $ShelfInventory | Table @TableParams - if ($Healthcheck.Storage.ShelfStatus -and ($ShelfInventory | Where-Object { $_.'State' -like 'offline' -or $_.'State' -like 'missing' })) { + $OutObj | Table @TableParams + if ($Healthcheck.Storage.ShelfStatus -and ($OutObj | Where-Object { $_.'State' -like 'offline' -or $_.'State' -like 'missing' })) { Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { diff --git a/Src/Private/Get-AbrOntapDiskType.ps1 b/Src/Private/Get-AbrOntapDiskType.ps1 index fa3429f..1dc38d0 100755 --- a/Src/Private/Get-AbrOntapDiskType.ps1 +++ b/Src/Private/Get-AbrOntapDiskType.ps1 @@ -25,18 +25,20 @@ function Get-AbrOntapDiskType { process { try { if ($NodeDiskContainerType) { - $DiskType = foreach ($DiskContainers in (Get-NcDisk -Controller $Array | ForEach-Object { $_.DiskRaidInfo.ContainerType } | Group-Object)) { + $OutObj = @() + foreach ($DiskContainers in (Get-NcDisk -Controller $Array | ForEach-Object { $_.DiskRaidInfo.ContainerType } | Group-Object)) { try { - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Container' = $DiskContainers.Name 'Disk Count' = $DiskContainers | Select-Object -ExpandProperty Count } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Storage.DiskStatus) { - $DiskType | Where-Object { $_.'Container' -like 'broken' } | Set-Style -Style Critical -Property 'Disk Count' + $OutObj | Where-Object { $_.'Container' -like 'broken' } | Set-Style -Style Critical -Property 'Disk Count' } $TableParams = @{ Name = "Disk Container Type - $($ClusterInfo.ClusterName)" @@ -46,16 +48,18 @@ function Get-AbrOntapDiskType { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $DiskType | Table @TableParams + $OutObj | Table @TableParams } $Node = Get-NcNode | Where-Object { $_.IsNodeHealthy -eq 'True' } if ($Node -and (Confirm-NcAggrSpareLow | Where-Object { $_.Value -eq 'True' })) { - $OutObj = foreach ($Item in $Node) { + $OutObj = @() + foreach ($Item in $Node) { try { - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Node' = $Item.Node 'Aggregate Spare Low' = (Confirm-NcAggrSpareLow -Node $Item.Node).Value.ToString().Replace('True', 'Yes').Replace('False', 'No') } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 b/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 index fe1986a..00dd6b7 100755 --- a/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 +++ b/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 @@ -30,14 +30,13 @@ function Get-AbrOntapEfficiencyConfig { foreach ($Item in $Data) { try { $Saving = Get-NcAggr -Aggregate $Item.Name -Controller $Array | Select-Object -ExpandProperty AggrSpaceAttributes - $TotalStorageEfficiencyRatio = Get-NcAggrEfficiency -Aggregate $Item.Name -Controller $Array | Select-Object -ExpandProperty AggrEfficiencyCumulativeInfo $inObj = [ordered] @{ 'Aggregate' = $Item.Name 'Used %' = ($Saving.PercentUsedCapacity | ConvertTo-FormattedNumber -Type Percent) ?? '--' 'Capacity Tier Used' = ($Saving.CapacityTierUsed | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' 'Compaction Saved %' = ($Saving.DataCompactionSpaceSavedPercent | ConvertTo-FormattedNumber -Type Percent) ?? '--' 'Deduplication Saved %' = ($Saving.SisSpaceSavedPercent | ConvertTo-FormattedNumber -Type Percent) ?? '--' - 'Total Data Reduction' = $TotalStorageEfficiencyRatio.TotalStorageEfficiencyRatio + 'Total Data Reduction' = (Get-NcAggrEfficiency -Aggregate $Item.Name -Controller $Array | Select-Object -ExpandProperty ).TotalStorageEfficiencyRatio ?? '--' } $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) diff --git a/Src/Private/Get-AbrOntapNetworkBdomain.ps1 b/Src/Private/Get-AbrOntapNetworkBroadCastDomain.ps1 similarity index 98% rename from Src/Private/Get-AbrOntapNetworkBdomain.ps1 rename to Src/Private/Get-AbrOntapNetworkBroadCastDomain.ps1 index 7b64d3f..97ee163 100755 --- a/Src/Private/Get-AbrOntapNetworkBdomain.ps1 +++ b/Src/Private/Get-AbrOntapNetworkBroadCastDomain.ps1 @@ -1,4 +1,4 @@ -function Get-AbrOntapNetworkBdomain { +function Get-AbrOntapNetworkBroadCastDomain { <# .SYNOPSIS Used by As Built Report to retrieve NetApp ONTAP Network Broadcast Domain information from the Cluster Management Network diff --git a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 index 541e68c..6159871 100755 --- a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 +++ b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 @@ -24,59 +24,58 @@ function Get-AbrOntapNetworkMgmt { process { try { - if (Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'cluster' }) { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'cluster' } + if ($ClusterData) { try { Section -ExcludeFromTOC -Style Heading6 'Cluster Network Interfaces' { - $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'cluster' } $ClusterObj = @() - if ($ClusterData) { - foreach ($Item in $ClusterData) { - try { - $inObj = [ordered] @{ - 'Cluster Interface' = $Item.InterfaceName - 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() - 'Data Protocols' = $Item.DataProtocols - 'Address' = $Item.Address - 'Vserver' = $Item.Vserver - } - $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message + foreach ($Item in $ClusterData) { + try { + $inObj = [ordered] @{ + 'Cluster Interface' = $Item.InterfaceName + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() + 'Data Protocols' = $Item.DataProtocols + 'Address' = $Item.Address + 'Vserver' = $Item.Vserver } + $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } - if ($Healthcheck.Network.Interface) { - $ClusterObj | Where-Object { $_.'Status' -notlike 'UP' } | Set-Style -Style Warning -Property 'Status' - } + } + if ($Healthcheck.Network.Interface) { + $ClusterObj | Where-Object { $_.'Status' -notlike 'UP' } | Set-Style -Style Warning -Property 'Status' + } - $TableParams = @{ - Name = "Cluster Network - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 35, 8, 21, 18, 18 - } - if ($Report.ShowTableCaptions) { - $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 + $TableParams = @{ + Name = "Cluster Network - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 35, 8, 21, 18, 18 + } + if ($Report.ShowTableCaptions) { + $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 { Write-PScriboMessage -IsWarning $_.Exception.Message } } try { - Section -ExcludeFromTOC -Style Heading6 'Management Network Interfaces' { - $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'cluster_mgmt' -or $_.Role -eq 'node_mgmt' } - $ClusterObj = @() - if ($ClusterData) { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'cluster_mgmt' -or $_.Role -eq 'node_mgmt' } + if ($ClusterData) { + Section -ExcludeFromTOC -Style Heading6 'Management Network Interfaces' { + $ClusterObj = @() foreach ($Item in $ClusterData) { try { $inObj = [ordered] @{ @@ -119,58 +118,57 @@ function Get-AbrOntapNetworkMgmt { Write-PScriboMessage -IsWarning $_.Exception.Message } try { - if (Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'intercluster' }) { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'intercluster' } + if ($ClusterData) { Section -ExcludeFromTOC -Style Heading6 'Intercluster Network Interfaces' { - $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'intercluster' } $ClusterObj = @() - if ($ClusterData) { - foreach ($Item in $ClusterData) { - try { - $inObj = [ordered] @{ - 'Intercluster Interface' = $Item.InterfaceName - 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() - 'Data Protocols' = $Item.DataProtocols - 'Address' = $Item.Address - 'Vserver' = $Item.Vserver - } - $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message + foreach ($Item in $ClusterData) { + try { + $inObj = [ordered] @{ + 'Intercluster Interface' = $Item.InterfaceName + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() + 'Data Protocols' = $Item.DataProtocols + 'Address' = $Item.Address + 'Vserver' = $Item.Vserver } + $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } - if ($Healthcheck.Network.Interface) { - $ClusterObj | Where-Object { $_.'Status' -notlike 'UP' } | Set-Style -Style Warning -Property 'Status' - } + } + if ($Healthcheck.Network.Interface) { + $ClusterObj | Where-Object { $_.'Status' -notlike 'UP' } | Set-Style -Style Warning -Property 'Status' + } - $TableParams = @{ - Name = "Intercluster Network - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 35, 8, 21, 18, 18 - } - if ($Report.ShowTableCaptions) { - $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 + $TableParams = @{ + Name = "Intercluster Network - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 35, 8, 21, 18, 18 + } + if ($Report.ShowTableCaptions) { + $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 } + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } try { - Section -ExcludeFromTOC -Style Heading6 'Data Network Interfaces' { - $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'data' -and $_.Vserver -notin $options.Exclude.Vserver } - $ClusterObj = @() - if ($ClusterData) { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'data' -and $_.Vserver -notin $options.Exclude.Vserver } + if ($ClusterData) { + Section -ExcludeFromTOC -Style Heading6 'Data Network Interfaces' { + $ClusterObj = @() foreach ($Item in $ClusterData) { try { if ($Item.Wwpn) { @@ -216,50 +214,49 @@ function Get-AbrOntapNetworkMgmt { Write-PScriboMessage -IsWarning $_.Exception.Message } 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' { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.DataProtocols -ne 'fcp' -and $_.IsHome -like 'False' } + if ($ClusterData) { + Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Network Interface Home Status' { 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 = @() - if ($ClusterData) { - foreach ($Item in $ClusterData) { - try { - $inObj = [ordered] @{ - 'Network Interface' = $Item.InterfaceName - 'Home Port' = $Item.HomeNode + ':' + $Item.HomePort - 'Current Port' = $Item.CurrentNode + ':' + $Item.CurrentPort - 'IsHome' = ($Item.IsHome -eq $True) ? 'Yes': 'No' - 'Vserver' = $Item.Vserver - } - $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message + foreach ($Item in $ClusterData) { + try { + $inObj = [ordered] @{ + 'Network Interface' = $Item.InterfaceName + 'Home Port' = $Item.HomeNode + ':' + $Item.HomePort + 'Current Port' = $Item.CurrentNode + ':' + $Item.CurrentPort + 'IsHome' = ($Item.IsHome -eq $True) ? 'Yes': 'No' + 'Vserver' = $Item.Vserver } + $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } - if ($Healthcheck.Network.Interface) { - $ClusterObj | Where-Object { $_.'IsHome' -ne 'Yes' } | Set-Style -Style Warning -Property 'Network Interface', 'IsHome', 'Home Port', 'Current Port', 'Vserver' - } + } + if ($Healthcheck.Network.Interface) { + $ClusterObj | Where-Object { $_.'IsHome' -ne 'Yes' } | Set-Style -Style Warning -Property 'Network Interface', 'IsHome', 'Home Port', 'Current Port', 'Vserver' + } - $TableParams = @{ - Name = "Network Interface Home Status - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 20, 25, 25, 10, 20 - } - if ($Report.ShowTableCaptions) { - $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 + $TableParams = @{ + Name = "Network Interface Home Status - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 20, 25, 25, 10, 20 + } + if ($Report.ShowTableCaptions) { + $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 } + } } } catch { diff --git a/Src/Private/Get-AbrOntapNetworkPorts.ps1 b/Src/Private/Get-AbrOntapNetworkPorts.ps1 index 447bb55..7078a76 100755 --- a/Src/Private/Get-AbrOntapNetworkPorts.ps1 +++ b/Src/Private/Get-AbrOntapNetworkPorts.ps1 @@ -30,9 +30,10 @@ function Get-AbrOntapNetworkPort { try { $PhysicalPorts = Get-NcNetPort -Node $Node -Controller $Array | Where-Object { $_.PortType -like 'physical' } if ($PhysicalPorts) { - $PhysicalNic = foreach ($Nics in $PhysicalPorts) { + $OutObj = @() + foreach ($Nics in $PhysicalPorts) { try { - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Port Name' = $Nics.Port 'Role' = $TextInfo.ToTitleCase($Nics.Role) 'Mac Address' = $Nics.MacAddress @@ -40,12 +41,13 @@ function Get-AbrOntapNetworkPort { 'Link Status' = $TextInfo.ToTitleCase($Nics.LinkStatus) 'Admin Status' = $Nics.IsAdministrativeUp -eq $True ? 'Up': 'Down' } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Network.Port) { - $PhysicalNic | Where-Object { $_.'Link Status' -like 'down' -and $_.'Admin Status' -like 'Up' } | Set-Style -Style Warning -Property 'Link Status' + $OutObj | Where-Object { $_.'Link Status' -like 'down' -and $_.'Admin Status' -like 'Up' } | Set-Style -Style Warning -Property 'Link Status' } $TableParams = @{ @@ -56,8 +58,8 @@ function Get-AbrOntapNetworkPort { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $PhysicalNic | Table @TableParams - if ($Healthcheck.Network.Port -and ($PhysicalNic | Where-Object { $_.'Link Status' -like 'down' -and $_.'Admin Status' -like 'Up' })) { + $OutObj | Table @TableParams + if ($Healthcheck.Network.Port -and ($OutObj | Where-Object { $_.'Link Status' -like 'down' -and $_.'Admin Status' -like 'Up' })) { Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { diff --git a/Src/Private/Get-AbrOntapNodeStorage.ps1 b/Src/Private/Get-AbrOntapNodeStorage.ps1 index 36e81c9..5299e82 100755 --- a/Src/Private/Get-AbrOntapNodeStorage.ps1 +++ b/Src/Private/Get-AbrOntapNodeStorage.ps1 @@ -32,7 +32,6 @@ function Get-AbrOntapNodeStorage { $inObj = [ordered] @{ 'Node' = $Item.Vserver 'Aggregate' = $Item.Aggregate - 'Volume' = $Item.Name 'Capacity' = ($Item.Totalsize | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type DataSize) ?? '--' 'Available' = ($Item.Available | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type DataSize) ?? '--' 'Used' = ($Item.Used | ConvertTo-FormattedNumber -Type Percent) ?? '--' @@ -50,7 +49,7 @@ function Get-AbrOntapNodeStorage { $TableParams = @{ Name = "Node Storage - $($ClusterInfo.ClusterName)" List = $false - ColumnWidths = 30, 30, 10, 10, 10, 10 + ColumnWidths = 30, 30, 15, 15, 10 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" diff --git a/Src/Private/Get-AbrOntapNodes.ps1 b/Src/Private/Get-AbrOntapNodes.ps1 index 2128044..22496db 100755 --- a/Src/Private/Get-AbrOntapNodes.ps1 +++ b/Src/Private/Get-AbrOntapNodes.ps1 @@ -26,15 +26,17 @@ function Get-AbrOntapNode { try { $NodeSum = Get-NcNode -Controller $Array if ($NodeSum) { - $NodeSummary = foreach ($Nodes in $NodeSum) { + $OutObj = @() + foreach ($Nodes in $NodeSum) { try { - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Name' = $Nodes.Node 'Model' = $Nodes.NodeModel 'Id' = $Nodes.NodeSystemId 'Serial' = $Nodes.NodeSerialNumber 'Uptime' = $Nodes.NodeUptimeTS } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -47,7 +49,7 @@ function Get-AbrOntapNode { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $NodeSummary | Table @TableParams + $OutObj | Table @TableParams } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapStorageAGGR.ps1 b/Src/Private/Get-AbrOntapStorageAGGR.ps1 index 8d0fa22..28d6d3d 100755 --- a/Src/Private/Get-AbrOntapStorageAGGR.ps1 +++ b/Src/Private/Get-AbrOntapStorageAGGR.ps1 @@ -112,9 +112,10 @@ function Get-AbrOntapStorageAGGR { $AggrSpare = Get-NcAggrSpare -Controller $Array if ($AggrSpare) { Section -Style Heading4 'Aggregate Spares' { - $AggrSpareSummary = foreach ($Spare in $AggrSpare) { + $OutObj = @() + foreach ($Spare in $AggrSpare) { try { - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Name' = $Spare.Disk 'Capacity' = ($Spare.TotalSize | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' 'Root Usable' = ($Spare.LocalUsableRootSize | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' @@ -123,12 +124,13 @@ function Get-AbrOntapStorageAGGR { 'Disk Zeroed' = $Spare.IsDiskZeroed 'Owner' = $Spare.OriginalOwner } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Storage.Aggr) { - $AggrSpareSummary | Where-Object { $_.'Disk Zeroed' -eq 'No' } | Set-Style -Style Warning -Property 'Disk Zeroed' + $OutObj | Where-Object { $_.'Disk Zeroed' -eq 'No' } | Set-Style -Style Warning -Property 'Disk Zeroed' } $TableParams = @{ Name = "Aggregates Spares - $($ClusterInfo.ClusterName)" @@ -138,7 +140,7 @@ function Get-AbrOntapStorageAGGR { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $AggrSpareSummary | Table @TableParams + $OutObj | Table @TableParams } } } catch { diff --git a/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 b/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 index d14dd01..f6ff407 100644 --- a/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 +++ b/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 @@ -48,6 +48,7 @@ function Get-AbrOntapVserverNetworkInterface { } if ($Healthcheck.Network.Interface) { $ClusterObj | Where-Object { $_.'Status' -notlike 'UP' } | Set-Style -Style Warning -Property 'Status' + $ClusterObj | Where-Object { $_.'Is Home' -eq 'No' } | Set-Style -Style Warning -Property 'Is Home' } $TableParams = @{ @@ -59,14 +60,23 @@ function Get-AbrOntapVserverNetworkInterface { $TableParams['Caption'] = "- $($TableParams.Name)" } $ClusterObj | Table @TableParams - if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { + if ($Healthcheck.Network.Interface -and (($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' }) -or (($ClusterObj | Where-Object { $_.'IsHome' -ne 'Yes' })))) { 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.' + if ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' }) { + Paragraph { + Text 'Best Practice:' -Bold + Text 'Ensure that all data network interfaces are operational (UP) to maintain optimal data access and performance.' + } + BlankLine + } + if ($ClusterObj | Where-Object { $_.'IsHome' -ne 'Yes' }) { + 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 } - BlankLine } } } catch { diff --git a/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 b/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 index a020fdc..9cbfd50 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 { $_.'Used'.split()[0] -gt $_.'Reserve Size'.split()[0] } | Set-Style -Style Warning -Property 'Reserve Size', 'Reserve Available', 'Used' + $VserverObj | Where-Object { $_.'Used' -gt $_.'Reserve Size' } | Set-Style -Style Warning -Property 'Reserve Size', 'Reserve Available', 'Used' } $TableParams = @{ diff --git a/Src/Private/Get-AbrOntapVserverVolumes.ps1 b/Src/Private/Get-AbrOntapVserverVolumes.ps1 index d1b58bf..c0ba2e9 100755 --- a/Src/Private/Get-AbrOntapVserverVolumes.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumes.ps1 @@ -48,7 +48,7 @@ function Get-AbrOntapVserverVolume { } if ($Healthcheck.Vserver.Status) { $VserverObj | Where-Object { $_.'Status' -like 'offline' } | Set-Style -Style Warning -Property 'Status' - $VserverObj | Where-Object { $_.'Used' -ge 75 } | Set-Style -Style Warning -Property 'Used' + $VserverObj | Where-Object { $_.'Used'.Split('%')[0] -ge 75 } | Set-Style -Style Warning -Property 'Used' } $TableParams = @{ @@ -60,14 +60,23 @@ function Get-AbrOntapVserverVolume { $TableParams['Caption'] = "- $($TableParams.Name)" } $VserverObj | Table @TableParams - if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -like 'offline' })) { + if ($Healthcheck.Vserver.Status -and (($VserverObj | Where-Object { $_.'Status' -like 'offline' }) -or ($VserverObj | Where-Object { $_.'Used'.Split('%')[0] -ge 75 }))) { 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." + if ($VserverObj | Where-Object { $_.'Status' -like 'offline' }) { + Paragraph { + Text 'Best Practice:' -Bold + Text "Ensure all volumes are in 'online' status and monitor volume usage to prevent capacity issues." + } + BlankLine + } + if ($VserverObj | Where-Object { $_.'Used'.Split('%')[0] -ge 75 }) { + Paragraph { + Text 'Best Practice:' -Bold + Text 'Ensure all volumes are below 95% usage to prevent capacity issues.' + } + BlankLine } - BlankLine } } } catch { diff --git a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 index 7b3b3f5..c99a946 100755 --- a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 +++ b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 @@ -343,7 +343,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } Section -Style Heading4 'Broadcast Domain' { - Get-AbrOntapNetworkBdomain + Get-AbrOntapNetworkBroadcastDomain } Section -Style Heading4 'Failover Groups' { Get-AbrOntapNetworkFailoverGroup diff --git a/Todo.md b/Todo.md index 9b32492..ea5ca07 100644 --- a/Todo.md +++ b/Todo.md @@ -1,4 +1,4 @@ -- [] Migrate [PSCustomObject] @{ to $inObj +- [x] Migrate [PSCustomObject] @{ to $inObj - [] Network Port Diagram - [] Cluster Network Ports: - [] Document all ports and lifs used by the cluster nodes for cluster communication. @@ -17,6 +17,8 @@ - [] Data Network Ports: - [] Document all ports used for data access to the vservers running on the cluster +- [] Add Health check for Nodes without intercluster interface (Replication Information) + - [x] Add Per Volumes Export Policies - [] Implement InfoLevel 1/2 on every section - Example @@ -28,7 +30,7 @@ - [x] Add Vserver Lifs - [] IP - [] Add healthcheck for no route in vserver - - [] Configure at least one route to ensure accurate client can assess the vserver services. + - [] Configure at least one route to ensure client can assess the vserver services. ```powershell