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/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 59ad50b..80659e4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -10,8 +10,7 @@ body: Thanks for taking the time to fill out this bug report :) - Kindly **DO NOT** ask for instructions. - Use [Discussions](https://github.com/orgs/AsBuiltReport/discussions) section if you have a query or doubts or any other relevant question. - - You may join [Slack community](https://the-code-community.slack.com#asbuiltreport) to interact with fellow contributors and users - - Read project's [Web Site](https://www.asbuiltreport.com/user-guide/installation/) for detailed documentation. + - Read project's [Web Site](https://www.asbuiltreport.com/user-guide/quickstart/) for detailed documentation. - Read project's [FAQs](https://www.asbuiltreport.com/support/faq/) section for Frequently asked questions. - Search for previous [Issues](https://github.com/AsBuiltReport/AsBuiltReport.NetApp.ONTAP/issues)/[Pull Requests](https://github.com/AsBuiltReport/AsBuiltReport.NetApp.ONTAP/pulls) if this issue is already reported or fix has been created. - type: textarea @@ -99,3 +98,10 @@ body: - label: >- I have read and followed the [bug reporting guidelines](https://www.asbuiltreport.com/about/contributing/#reporting-issues-and-bugs). required: true + - label: >- + I have read [the documentation](https://www.asbuiltreport.com/user-guide/new-asbuiltreport), + and referred to the [known issues](https://www.asbuiltreport.com/support/known-issues/) before submitting this bug report. + required: true + - label: >- + I have checked for previously opened & closed [issues](https://github.com/AsBuiltReport/AsBuiltReport.NetApp.ONTAP/issues) before submitting this bug report. + required: true diff --git a/.github/ISSUE_TEMPLATE/change_request.yml b/.github/ISSUE_TEMPLATE/change_request.yml index 4f6c670..b6b14bc 100644 --- a/.github/ISSUE_TEMPLATE/change_request.yml +++ b/.github/ISSUE_TEMPLATE/change_request.yml @@ -26,9 +26,9 @@ body: If you are unsure of what a specific requirement means, please follow the links to learn about it and understand why it is necessary before submitting. options: - label: >- - I have read [the documentation](https://www.asbuiltreport.com/user-guide/new-asbuiltconfig), - and referred to the [known issues](https://www.asbuiltreport.com/user-guide/known-issues/) before submitting this change request. + I have read [the documentation](https://www.asbuiltreport.com/user-guide/quickstart/), + and referred to the [known issues](https://www.asbuiltreport.com/support/known-issues/) before submitting this change request. required: true - label: >- I have checked for previously opened & closed [issues](https://github.com/AsBuiltReport/AsBuiltReport.NetApp.ONTAP/issues) before submitting this change request. - required: true + required: true \ No newline at end of file diff --git a/.github/workflows/PSScriptAnalyzer.yml b/.github/workflows/PSScriptAnalyzer.yml index a73694f..700425b 100755 --- a/.github/workflows/PSScriptAnalyzer.yml +++ b/.github/workflows/PSScriptAnalyzer.yml @@ -1,17 +1,17 @@ name: PSScriptAnalyzer on: [push, pull_request] jobs: - lint: - name: Run PSScriptAnalyzer - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - name: lint - uses: devblackops/github-action-psscriptanalyzer@master - with: - sendComment: true - failOnErrors: true - failOnWarnings: false - failOnInfos: false - repoToken: ${{ secrets.GITHUB_TOKEN }} - settingsPath: .github/workflows/PSScriptAnalyzerSettings.psd1 \ No newline at end of file + lint: + name: Run PSScriptAnalyzer + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: lint + uses: alagoutte/github-action-psscriptanalyzer@master + with: + sendComment: true + failOnErrors: true + failOnWarnings: false + failOnInfos: false + repoToken: ${{ secrets.GITHUB_TOKEN }} + settingsPath: .github/workflows/PSScriptAnalyzerSettings.psd1 diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 67069b2..4ff1129 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: | @@ -21,18 +21,18 @@ jobs: shell: pwsh run: | Install-Module -Name NetApp.ONTAP -Repository PSGallery -Force - - name: Install Diagrammer.Core module + - name: Install AsBuiltReport.Diagram module shell: pwsh run: | - Install-Module -Name Diagrammer.Core -Repository PSGallery -Force + Install-Module -Name AsBuiltReport.Diagram -Repository PSGallery -Force - name: Test Module Manifest shell: pwsh run: | - Test-ModuleManifest .\AsBuiltReport.NetApp.ONTAP.psd1 + Test-ModuleManifest .\AsBuiltReport.NetApp.ONTAP\AsBuiltReport.NetApp.ONTAP.psd1 - name: Publish module to PowerShell Gallery shell: pwsh run: | - Publish-Module -Path ./ -NuGetApiKey ${{ secrets.PSGALLERY_API_KEY }} -Verbose + Publish-Module -Path ./AsBuiltReport.NetApp.ONTAP -NuGetApiKey ${{ secrets.PSGALLERY_API_KEY }} -Verbose tweet: needs: publish-to-gallery runs-on: ubuntu-latest @@ -58,4 +58,4 @@ jobs: post: "[New Release] ${{ github.event.repository.name }} ${{ github.event.release.tag_name }}! Check out what's new! ${{ github.event.release.html_url }} #Netapp #AsBuiltReport #PowerShell #Ontap #NetAppATeam" env: BSKY_IDENTIFIER: ${{ secrets.BSKY_IDENTIFIER }} - BSKY_PASSWORD: ${{ secrets.BSKY_PASSWORD }} \ No newline at end of file + BSKY_PASSWORD: ${{ secrets.BSKY_PASSWORD }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a2aeb0f..c944b8c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -10,40 +10,40 @@ name: CodeQL on: - push: - branches: [ "dev" ] - pull_request: - branches: [ "dev" ] - schedule: - - cron: '20 14 * * 1' + push: + branches: ["dev"] + pull_request: + branches: ["dev"] + schedule: + - cron: "20 14 * * 1" permissions: - contents: read + contents: read jobs: - build: - permissions: - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/upload-sarif to upload SARIF results - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - name: PSScriptAnalyzer - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 + build: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + name: PSScriptAnalyzer + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 - - name: Run PSScriptAnalyzer - uses: microsoft/psscriptanalyzer-action@v1.1 - with: - # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. - # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. - path: .\ - recurse: true - # Include your own basic security rules. Removing this option will run all the rules - excludeRule: '"PSAvoidUsingPlainTextForPassword", "PSAvoidUsingUsernameAndPasswordParams", "PSAvoidUsingConvertToSecureStringWithPlainText"' - output: results.sarif + - name: Run PSScriptAnalyzer + uses: microsoft/psscriptanalyzer-action@v1.1 + with: + # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. + # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. + path: .\ + recurse: true + # Include your own basic security rules. Removing this option will run all the rules + excludeRule: '"PSAvoidUsingPlainTextForPassword", "PSAvoidUsingUsernameAndPasswordParams", "PSAvoidUsingConvertToSecureStringWithPlainText"' + output: results.sarif - # Upload the SARIF file generated in the previous step - - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: results.sarif + # Upload the SARIF file generated in the previous step + - name: Upload SARIF results file + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: results.sarif diff --git a/AsBuiltReport.NetApp.ONTAP.Style.ps1 b/AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.Style.ps1 similarity index 99% rename from AsBuiltReport.NetApp.ONTAP.Style.ps1 rename to AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.Style.ps1 index 91ce353..888d644 100755 --- a/AsBuiltReport.NetApp.ONTAP.Style.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.Style.ps1 @@ -74,10 +74,10 @@ if ($Orientation -eq 'Portrait') { # Cover Page Image if ($ReportConfig.Report.ShowCoverPageImage) { - Try { - Image -Text 'AsBuiltReport Logo' -Align 'Center' -Percent 45 -Base64 "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" + try { + Image -Text 'AsBuiltReport Logo' -Align 'Center' -Percent 45 -Base64 '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' BlankLine -Count 1 - } Catch { + } catch { Write-PScriboMessage -IsWarning "Unable to display cover page image. Please set 'ShowCoverPageImage' to 'false' in the report JSON configuration file to avoid this error." Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/AsBuiltReport.NetApp.ONTAP.json b/AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.json similarity index 95% rename from AsBuiltReport.NetApp.ONTAP.json rename to AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.json index 73f269f..962878e 100755 --- a/AsBuiltReport.NetApp.ONTAP.json +++ b/AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.json @@ -18,14 +18,15 @@ "DisableDiagramMainLogo": false, "DiagramTheme": "White", "DiagramWaterMark": "", - "ExportDiagrams": false, + "ExportDiagrams": true, "ExportDiagramsFormat": [ - "png" + "pdf" ], "EnableDiagramSignature": false, "DiagramColumnSize": 4, "SignatureAuthorName": "", - "SignatureCompanyName": "" + "SignatureCompanyName": "", + "UpdateCheck": true }, "InfoLevel": { "_comment_": "0 = Disabled, 1 = Enabled, 2 = Adv Summary", diff --git a/AsBuiltReport.NetApp.ONTAP.psd1 b/AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.psd1 similarity index 91% rename from AsBuiltReport.NetApp.ONTAP.psd1 rename to AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.psd1 index 55a542e..aeca4d0 100755 --- a/AsBuiltReport.NetApp.ONTAP.psd1 +++ b/AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.psd1 @@ -12,7 +12,7 @@ RootModule = 'AsBuiltReport.NetApp.ONTAP.psm1' # Version number of this module. - ModuleVersion = '0.6.11' + ModuleVersion = '0.6.12' # Supported PSEditions # CompatiblePSEditions = @() @@ -27,7 +27,7 @@ #CompanyName = 'Unknown' # Copyright statement for this module - Copyright = '(c) 2025 Jonathan Colon Feliciano. All rights reserved.' + Copyright = '(c) 2026 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.' @@ -54,15 +54,19 @@ RequiredModules = @( @{ ModuleName = 'AsBuiltReport.Core'; - ModuleVersion = '1.5.0' + ModuleVersion = '1.6.2' + }, + @{ + ModuleName = 'AsBuiltReport.Chart'; + ModuleVersion = '0.3.0' }, @{ ModuleName = 'NetApp.ONTAP'; - ModuleVersion = '9.17.1.2509' + ModuleVersion = '9.18.1.2601' }, @{ - ModuleName = 'Diagrammer.Core'; - ModuleVersion = '0.2.33' + ModuleName = 'AsBuiltReport.Diagram'; + ModuleVersion = '1.0.3' } ) @@ -129,7 +133,7 @@ # HelpInfo URI of this module # HelpInfoURI = '' - # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + # Default prefix for commands exported from this module. Override the default prefix using Import-Mod-Prefix. # DefaultCommandPrefix = '' } diff --git a/AsBuiltReport.NetApp.ONTAP.psm1 b/AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.psm1 similarity index 100% rename from AsBuiltReport.NetApp.ONTAP.psm1 rename to AsBuiltReport.NetApp.ONTAP/AsBuiltReport.NetApp.ONTAP.psm1 diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/ConvertTo-HashToYN.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/ConvertTo-HashToYN.ps1 new file mode 100644 index 0000000..02be54f --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/ConvertTo-HashToYN.ps1 @@ -0,0 +1,35 @@ +function ConvertTo-HashToYN { + <# + .SYNOPSIS + Used by As Built Report to convert array content true or false automatically to Yes or No. + .DESCRIPTION + + .NOTES + Version: 0.2.0 + Author: Jonathan Colon + + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + [OutputType([System.Collections.Specialized.OrderedDictionary])] + param ( + [Parameter (Position = 0, Mandatory)] + [AllowEmptyString()] + [System.Collections.Specialized.OrderedDictionary] $TEXT + ) + + $result = [ordered] @{} + foreach ($i in $TEXT.GetEnumerator()) { + try { + $result.add($i.Key, (ConvertTo-TextYN $i.Value)) + } catch { + $result.add($i.Key, ($i.Value)) + } + } + if ($result) { + return $result + } else { return $TEXT } +} \ No newline at end of file diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/ConvertTo-TextYN.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/ConvertTo-TextYN.ps1 new file mode 100644 index 0000000..07cd0bf --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/ConvertTo-TextYN.ps1 @@ -0,0 +1,39 @@ +function ConvertTo-TextYN { + <# + .SYNOPSIS + Used by As Built Report to convert true or false automatically to Yes or No. + .DESCRIPTION + + .NOTES + Version: 0.2.0 + Author: LEE DAILEY + + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + [OutputType([String])] + param + ( + [Parameter ( + Position = 0, + Mandatory)] + [AllowEmptyString()] + [string] + $TEXT + ) + + switch ([string]::IsNullOrEmpty($TEXT)) { + $true { '--' } + $false { + switch ($TEXT) { + 'True' { 'Yes'; break } + 'False' { 'No'; break } + default { $TEXT } + } + } + default { '--' } + } +} # end \ No newline at end of file diff --git a/Src/Private/Export-AbrOntapDiagram.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Export-AbrOntapDiagram.ps1 similarity index 82% rename from Src/Private/Export-AbrOntapDiagram.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Export-AbrOntapDiagram.ps1 index 0bfa14e..a6508ea 100644 --- a/Src/Private/Export-AbrOntapDiagram.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Export-AbrOntapDiagram.ps1 @@ -5,7 +5,7 @@ function Export-AbrOntapDiagram { .DESCRIPTION Documents the configuration of NetApp Ontap in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -15,7 +15,7 @@ function Export-AbrOntapDiagram { https://github.com/AsBuiltReport/AsBuiltReport.NetApp.Ontap #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingCmdletAliases", "", Scope = "Function")] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '', Scope = 'Function')] [CmdletBinding()] param ( @@ -31,7 +31,7 @@ function Export-AbrOntapDiagram { process { if ($Options.EnableDiagrams) { - Write-PScriboMessage -Message "Collecting NetApp Ontap Infrastructure diagram" + Write-PScriboMessage -Message 'Collecting NetApp Ontap Infrastructure diagram' $RootPath = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent [System.IO.FileInfo]$IconPath = Join-Path $RootPath 'icons' @@ -83,7 +83,7 @@ function Export-AbrOntapDiagram { } $DiagramParams.Add('Format', $DiagramFormat) } else { - $DiagramParams.Add('Format', "base64") + $DiagramParams.Add('Format', 'base64') } if ($Options.EnableDiagramDebug) { @@ -100,11 +100,11 @@ function Export-AbrOntapDiagram { if ($Options.ExportDiagrams) { try { - Write-PScriboMessage -Message "Generating NetApp Ontap diagram" + Write-PScriboMessage -Message 'Generating NetApp Ontap diagram' $Graph = $DiagramObject if ($Graph) { - Write-PScriboMessage -Message "Saving NetApp Ontap diagram" - $Diagram = New-Diagrammer @DiagramParams -InputObject $Graph + Write-PScriboMessage -Message 'Saving NetApp Ontap diagram' + $Diagram = New-AbrDiagram @DiagramParams -InputObject $Graph if ($Diagram) { foreach ($OutputFormat in $DiagramFormat) { Write-Information -MessageData "Saved '$($FileName).$($OutputFormat)' diagram to '$($OutputFolderPath)'." -InformationAction Continue @@ -117,15 +117,14 @@ function Export-AbrOntapDiagram { } try { $DiagramParams.Remove('Format') - $DiagramParams.Add('Format', "base64") + $DiagramParams.Add('Format', 'base64') $Graph = $DiagramObject - $Diagram = New-Diagrammer @DiagramParams -InputObject $Graph + $Diagram = New-AbrDiagram @DiagramParams -InputObject $Graph if ($Diagram) { - if ((Get-DiaImagePercent -GraphObj $Diagram).Width -gt 600) { $ImagePrty = 40 } else { $ImagePrty = 30 } + $BestAspectRatio = Get-BestImageAspectRatio -GraphObj $Diagram -MaxWidth 600 Section -Style Heading2 $MainDiagramLabel { - Image -Base64 $Diagram -Text "NetApp Ontap Diagram" -Percent $ImagePrty -Align Center - Paragraph "Image preview: Opens the image in a new tab to view it at full resolution." -Tabs 2 + Image -Base64 $Diagram -Text 'NetApp Ontap Diagram' -Width $BestAspectRatio.Width -Height $BestAspectRatio.Height -Align Center } } } catch { diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapCluster.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapCluster.ps1 new file mode 100755 index 0000000..20d00bc --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapCluster.ps1 @@ -0,0 +1,79 @@ +function Get-AbrOntapCluster { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP cluster information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP cluster information.' + } + + process { + try { + $ClusterInfo = Get-NcCluster -Controller $Array + if ($ClusterInfo) { + $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) { + $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 = @{ + Name = "Cluster Information - $($ClusterInfo.ClusterName)" + List = $true + ColumnWidths = 25, 75 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + if ($Healthcheck.Cluster.Summary -and ($OutObj | 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 + } + } + + end {} + +} \ No newline at end of file diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterASUP.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterASUP.ps1 new file mode 100755 index 0000000..91d79cd --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterASUP.ps1 @@ -0,0 +1,106 @@ +function Get-AbrOntapClusterASUP { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP cluster autoSupport status from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP AutoSupport information.' + } + + process { + try { + $AutoSupport = Get-NcAutoSupportConfig -Controller $Array -ErrorAction Continue + if ($AutoSupport) { + $Outobj = @() + foreach ($NodesAUTO in $AutoSupport) { + try { + $Inobj = [ordered] @{ + 'Node Name' = $NodesAUTO.NodeName + 'Protocol' = $NodesAUTO.Transport + 'Enabled' = $NodesAUTO.IsEnabled + 'Last Time Stamp' = $NodesAUTO.LastTimestampDT + 'Last Subject' = $NodesAUTO.LastSubject + 'Ondemand Server URL' = $NodesAUTO.OndemandServerUrl + 'Validate Digital Certificate' = $NodesAUTO.ValidateDigitalCertificate + 'Ondemand Remote Diagnostic Enabled' = $NodesAUTO.IsOndemandRemoteDiagEnabled + 'Performance Data Enabled' = $NodesAUTO.IsPerfDataEnabled + 'Private Data Removed' = $NodesAUTO.IsPrivateDataRemoved + 'Support Enabled' = $NodesAUTO.IsSupportEnabled + } + $Outobj += [pscustomobject](ConvertTo-HashToYN $inObj) + + if ($Healthcheck.Cluster.AutoSupport) { + $Outobj | Where-Object { $_.'Enabled' -like 'No' } | Set-Style -Style Warning -Property 'Enabled' + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + if ($InfoLevel.Storage -ge 2) { + foreach ($NodesAUTO in $Outobj) { + Section -Style NOTOCHeading4 -ExcludeFromTOC "$($NodesAUTO.'Node Name')" { + $TableParams = @{ + Name = "Cluster AutoSupport Status - $($NodesAUTO.'Node Name')" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $NodesAUTO | Table @TableParams + if ($Healthcheck.Cluster.AutoSupport -and ($NodesAUTO | 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 + } + } + } + } else { + $TableParams = @{ + Name = "Cluster AutoSupport Status - $($ClusterInfo.ClusterName)" + List = $false + Columns = 'Node Name', 'Protocol', 'Enabled' + ColumnWidths = 40, 30, 30 + } + if ($Report.ShowTableCaptions) { + $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 + } + } + + end {} + +} \ No newline at end of file diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterDiagram.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterDiagram.ps1 new file mode 100644 index 0000000..ed5ca52 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterDiagram.ps1 @@ -0,0 +1,218 @@ +function Get-AbrOntapClusterDiagram { + <# + .SYNOPSIS + Used by As Built Report to built NetApp ONTAP cluster diagram + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Generating Cluster Diagram for NetApp ONTAP.' + # Used for DiagramDebug + if ($Options.EnableDiagramDebug) { + $EdgeDebug = @{style = 'filled'; color = 'red' } + $SubGraphDebug = @{style = 'dashed'; color = 'red' } + $NodeDebug = @{color = 'black'; style = 'red'; shape = 'plain' } + $NodeDebugEdge = @{color = 'black'; style = 'red'; shape = 'plain' } + $IconDebug = $true + } else { + $EdgeDebug = @{style = 'invis'; color = 'red' } + $SubGraphDebug = @{style = 'invis'; color = 'gray' } + $NodeDebug = @{color = 'transparent'; style = 'transparent'; shape = 'point' } + $NodeDebugEdge = @{color = 'transparent'; style = 'transparent'; shape = 'none' } + $IconDebug = $false + } + + if ($Options.DiagramTheme -eq 'Black') { + $Edgecolor = 'White' + $Fontcolor = 'White' + } elseif ($Options.DiagramTheme -eq 'Neon') { + $Edgecolor = 'gold2' + $Fontcolor = 'gold2' + } else { + $Edgecolor = '#71797E' + $Fontcolor = '#565656' + } + } + + process { + try { + $ClusterInfo = Get-NcCluster -Controller $Array + $NodeSum = Get-NcNode -Controller $Array + + SubGraph Cluster -Attributes @{Label = $ClusterInfo.ClusterName; fontsize = 22; penwidth = 1.5; labelloc = 't'; style = 'dashed,rounded'; color = 'gray' } { + SubGraph ClusterInfo -Attributes @{Label = "Management: $($ClusterInfo.NcController)"; fontsize = 16; penwidth = 1.5; labelloc = 'b'; labeljust = 'r'; style = 'dashed,rounded'; color = 'transparent' } { + try { + + if ($NodeSum.Count -eq 1) { + $NodeSumColumnSize = 1 + } elseif ($ColumnSize) { + $NodeSumColumnSize = $ColumnSize + } else { + $NodeSumColumnSize = $NodeSum.Count + } + + $HAObject = @() + + $NodeAdditionalInfo = @() + + foreach ($Node in $NodeSum) { + $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 + + if ($ClusterHa.Name -notin $HAObject.Partner) { + $HAObject += [PSCustomObject][ordered]@{ + 'Name' = $ClusterHa.Name + 'Partner' = $ClusterHa.Partner + 'HAState' = $ClusterHa.State + } + } + + $NodeAdditionalInfo += [PSCustomObject][ordered]@{ + 'NodeName' = $Node.Node + 'AdditionalInfo' = [PSCustomObject][ordered]@{ + 'System Id' = $Node.NodeSystemId + 'Serial' = $Node.NodeSerialNumber + 'Model' = $Node.NodeModel + 'Mgmt' = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { + $true { 'Unknown' } + $false { @($NodeMgmtAddress) -join ', ' } + default { 'Unknown' } + } + 'Intercluster' = switch ([string]::IsNullOrEmpty($NodeInterClusterAddress)) { + $true { 'Unknown' } + $false { $NodeInterClusterAddress } + default { 'Unknown' } + } + } + } + } + + # Build a flat list of all graphviz node names for edge creation + $AllNodeNames = @() + foreach ($HA in $HAObject) { + $AllNodeNames += Remove-SpecialCharacter -String $HA.Name -SpecialChars '\-_' + if ($HA.Partner) { + $AllNodeNames += Remove-SpecialCharacter -String $HA.Partner -SpecialChars '\-_' + } + } + + # Cluster Network switch + $ClusterNetworkImage = Add-NodeImage -Name 'ClusterSwitch1' -ImagesObj $Images -IconType 'Ontap_Cluster_Network' -IconDebug $IconDebug -TableBackgroundColor '#a1e3fd' + Add-HtmlSubGraph -Name 'ClusterNetwork' -TableArray $ClusterNetworkImage -Label 'Cluster Network' -LabelPos top -ImagesObj $Images -IconDebug $IconDebug -NodeObject -TableBorder 1 -FontSize 16 -TableBorderColor '#71797E' -TableStyle 'rounded,dashed' -FontColor 'darkblue' -FontBold -FontName 'Segoe Ui Bold' -TableBackgroundColor '#a1e3fd' + + if ($HAObject.Name -and $HAObject.Partner) { + foreach ($HA in $HAObject) { + $HAClusterName = Remove-SpecialCharacter -String "HA$($HA.Name)$($HA.Partner)" -SpecialChars '\-_' + SubGraph $HAClusterName -Attributes @{Label = 'HA Pair'; fontsize = 16; penwidth = 1.5; labelloc = 't'; style = 'dashed,rounded'; color = 'gray'; labeljust = 'c' } { + + $HAName = Remove-SpecialCharacter -String $HA.Name -SpecialChars '\-_' + $HAPartner = Remove-SpecialCharacter -String $HA.Partner -SpecialChars '\-_' + + Node $HAName @{Label = Add-NodeIcon -Name $HA.Name -AditionalInfo ($NodeAdditionalInfo | Where-Object { $_.NodeName -eq $HA.Name }).AdditionalInfo -ImagesObj $Images -IconType 'Ontap_Node' -Align 'Center' -IconDebug $IconDebug -FontSize 18; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } + + Node $HAPartner @{Label = Add-NodeIcon -Name $HA.Partner -AditionalInfo ($NodeAdditionalInfo | Where-Object { $_.NodeName -eq $HA.Partner }).AdditionalInfo -ImagesObj $Images -IconType 'Ontap_Node' -Align 'Center' -IconDebug $IconDebug -FontSize 18; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } + + Rank $HAName, $HAPartner + + Add-NodeEdge -From $HAName -To $HAPartner -EdgeColor $Edgecolor -EdgeStyle 'solid' -EdgeThickness 2 -Arrowhead 'box' -Arrowtail 'box' -EdgeLabel "HA: $($HA.HAState)" -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 16 -EdgeLength 2 + } + } + } else { + foreach ($HA in $HAObject) { + $HAClusterName = Remove-SpecialCharacter -String "HA$($HA.Name)" -SpecialChars '\-_' + SubGraph $HAClusterName -Attributes @{Label = 'Single Node Cluster'; fontsize = 16; penwidth = 1.5; labelloc = 't'; style = 'dashed,rounded'; color = 'gray'; labeljust = 'c' } { + $HAName = Remove-SpecialCharacter -String $HA.Name -SpecialChars '\-_' + Node $HAName @{Label = Add-NodeIcon -Name $HA.Name -AditionalInfo ($NodeAdditionalInfo | Where-Object { $_.NodeName -eq $HA.Name }).AdditionalInfo -ImagesObj $Images -IconType 'Ontap_Node' -Align 'Center' -IconDebug $IconDebug -FontSize 18; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } + } + } + } + + # Management Network switch + $MgmtNetworkImage = Add-NodeImage -Name 'MgmtSwitch1' -ImagesObj $Images -IconType 'Ontap_Cluster_Network' -IconDebug $IconDebug -TableBackgroundColor '#d5e8d4' + Add-HtmlSubGraph -Name 'ManagementNetwork' -TableArray $MgmtNetworkImage -Label 'Management Network' -LabelPos top -ImagesObj $Images -IconDebug $IconDebug -NodeObject -TableBorder 1 -FontSize 16 -TableBorderColor '#71797E' -TableStyle 'rounded,dashed' -FontColor 'darkgreen' -FontBold -FontName 'Segoe Ui Bold' -TableBackgroundColor '#d5e8d4' + + # Data Network switch + $DataNetworkImage = Add-NodeImage -Name 'DataSwitch1' -ImagesObj $Images -IconType 'Ontap_Cluster_Network' -IconDebug $IconDebug -TableBackgroundColor '#dae8fc' + Add-HtmlSubGraph -Name 'DataNetwork' -TableArray $DataNetworkImage -Label 'Data Network' -LabelPos top -ImagesObj $Images -IconDebug $IconDebug -NodeObject -TableBorder 1 -FontSize 16 -TableBorderColor '#71797E' -TableStyle 'rounded,dashed' -FontColor 'darkblue' -FontBold -FontName 'Segoe Ui Bold' -TableBackgroundColor '#dae8fc' + + # Connect all nodes to the network infrastructure elements + foreach ($NodeName in $AllNodeNames) { + Add-NodeEdge -From 'ClusterNetwork' -To $NodeName -EdgeColor '#5B9BD5' -EdgeStyle 'dashed' -Arrowhead 'none' -Arrowtail 'none' -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 10 -EdgeLength 2 -EdgeThickness 3 + Add-NodeEdge -From 'ManagementNetwork' -To $NodeName -EdgeColor $Edgecolor -EdgeStyle 'dashed' -Arrowhead 'none' -Arrowtail 'none' -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 10 -EdgeLength 2 -EdgeThickness 3 + Add-NodeEdge -From $NodeName -To 'DataNetwork' -EdgeColor '#70AD47' -EdgeStyle 'dashed' -Arrowhead 'none' -Arrowtail 'none' -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 10 -EdgeLength 2 -EdgeThickness 3 + } + + # Data Network - Per Broadcast Domain Information + try { + $DataBroadcastDomains = Get-NcNetPortBroadcastDomain -Controller $Array | Where-Object { $_.BroadcastDomain -ne 'Cluster' } + + if ($DataBroadcastDomains) { + foreach ($BDomain in $DataBroadcastDomains) { + $BDomainSafeName = Remove-SpecialCharacter -String $BDomain.BroadcastDomain -SpecialChars '\-_:' + + $PortTextItems = @() + if ($BDomain.Ports) { + foreach ($PortMember in $BDomain.Ports) { + $PortSafeName = Remove-SpecialCharacter -String $PortMember -SpecialChars '\-_:' + + $PortTextItems += Add-NodeText -Name "BD${BDomainSafeName}${PortSafeName}" -Text $PortMember -IconDebug $IconDebug -FontSize 12 + } + } else { + $PortTextItems += Add-NodeText -Name "BD${BDomainSafeName}NoPorts" -Text 'No Ports Assigned' -IconDebug $IconDebug -FontSize 12 + } + + Add-HtmlSubGraph -Name "${BDomainSafeName}BroadcastDomain" ` + -TableArray $PortTextItems ` + -ImagesObj $Images ` + -IconDebug $IconDebug ` + -TableBorder 1 ` + -Label "$($BDomain.BroadcastDomain) | MTU: $($BDomain.Mtu)" ` + -LabelPos 'top' ` + -TableStyle 'rounded,dashed' ` + -TableBorderColor '#70AD47' ` + -FontName 'Segoe Ui Bold' ` + -NodeObject ` + -ColumnSize 3 ` + -FontSize 14 + + Add-NodeEdge -From 'DataNetwork' -To "${BDomainSafeName}BroadcastDomain" ` + -EdgeColor '#70AD47' ` + -EdgeStyle 'dashed' ` + -Arrowhead 'none' ` + -Arrowtail 'none' ` + -EdgeLength 2 ` + -EdgeThickness 3 + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + } + + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterHA.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterHA.ps1 new file mode 100755 index 0000000..212d6f6 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterHA.ps1 @@ -0,0 +1,163 @@ +function Get-AbrOntapClusterHA { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP cluster HA information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP cluster high availability information.' + } + + process { + try { + $NodeSum = Get-NcNode -Controller $Array | Where-Object { $null -ne $_.NodeModel } + if ($NodeSum) { + $OutObj = @() + foreach ($Nodes in $NodeSum) { + try { + $ClusterHa = Get-NcClusterHa -Node $Nodes.Node -Controller $Array + $inObj = [ordered] @{ + 'Name' = $Nodes.Node + 'NVRAM ID' = $Nodes.NodeNvramId + 'Local Mailbox Disks' = ($ClusterHa.LocalMailboxDisks | ForEach-Object { $_.Name }) -join ', ' + 'Partner' = $ClusterHa.Partner ?? '--' + 'Partner NVRAM ID' = $ClusterHa.PartnerNvramId + 'Partner Mailbox Disks' = ($ClusterHa.PartnerMailboxDisks | ForEach-Object { $_.Name }) -join ', ' + 'TakeOver Possible' = $ClusterHa.TakeoverPossible + 'TakeOver By Partner Possible' = $ClusterHa.TakeoverByPartnerPossible + 'TakeOver State' = $ClusterHa.TakeoverState ?? '--' + 'HA Mode' = $ClusterHa.CurrentMode + 'HA Type' = $ClusterHa.HaType + 'HA State' = $ClusterHa.State + 'Interconnect Type' = $ClusterHa.InterconnectType + 'Interconnect Links' = $ClusterHa.InterconnectLinks + 'Is Enabled' = $ClusterHa.IsEnabled + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + if ($Healthcheck.Cluster.HA) { + $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' + $OutObj | Where-Object { $_.'TakeOver By Partner Possible' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' } | Set-Style -Style Warning -Property 'TakeOver By Partner Possible' + $OutObj | Where-Object { $_.'Is Enabled' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' } | Set-Style -Style Warning -Property 'Is Enabled' + + } + + if ($InfoLevel.Cluster -ge 2) { + foreach ($NodeHa in $OutObj) { + Section -Style NOTOCHeading4 -ExcludeFromTOC "$($NodeHa.Name)" { + $TableParams = @{ + Name = "Cluster HA Status - $($NodeHa.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $NodeHa | Table @TableParams + if ($Healthcheck.Cluster.HA -and (($NodeHa | Where-Object { $_.'TakeOver State' -like 'in_takeover' } ) -or ($NodeHa | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' }) -or ($NodeHa | Where-Object { $_.'TakeOver Possible' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' }))) { + Paragraph 'Health Check:' -Bold -Underline + BlankLine + if ($NodeHa | 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 ($NodeHa | 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 ($NodeHa | 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 + } + if ($NodeHa | Where-Object { $_.'Is Enabled' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' }) { + Paragraph { + Text 'Best Practice:' -Bold + Text 'One or more nodes have HA disabled while operating in HA mode. It is recommended to enable HA to ensure redundancy and high availability.' + } + BlankLine + } + } + } + } + } else { + $TableParams = @{ + Name = "Cluster AutoSupport Status - $($ClusterInfo.ClusterName)" + List = $false + Columns = 'Name', 'Partner', 'TakeOver Possible', 'TakeOver State', 'HA Mode', 'HA State' + ColumnWidths = 20, 20, 11, 19, 10, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $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 ($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 ($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 ($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.' + } + BlankLine + } + if ($Outobj | Where-Object { $_.'Is Enabled' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' }) { + Paragraph { + Text 'Best Practice:' -Bold + Text 'One or more nodes have HA disabled while operating in HA mode. It is recommended to enable HA to ensure redundancy and high availability.' + } + BlankLine + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapClusterLicense.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterLicense.ps1 similarity index 56% rename from Src/Private/Get-AbrOntapClusterLicense.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterLicense.ps1 index ef3abf6..b899ed7 100755 --- a/Src/Private/Get-AbrOntapClusterLicense.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterLicense.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapClusterLicense { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapClusterLicense { ) begin { - Write-PScriboMessage "Collecting ONTAP cluster license information." + Write-PScriboMessage 'Collecting ONTAP cluster license information.' } process { @@ -27,21 +27,22 @@ function Get-AbrOntapClusterLicense { $Nodes = Get-NcNode -Controller $Array foreach ($Node in $Nodes) { try { - Section -Style Heading3 "$Node License Usage" { - $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 } - [PSCustomObject] @{ + $License = Get-NcLicense -Owner $Node -Controller $Array + if ($License) { + Section -Style Heading3 "$Node License Usage" { + $OutObj = @() + foreach ($Licenses in $License) { + $inObj = [ordered] @{ 'License' = $TextInfo.ToTitleCase($Licenses.Package) 'Type' = $TextInfo.ToTitleCase($Licenses.Type) 'Description' = $Licenses.Description - 'Risk' = ConvertTo-EmptyToFiller $EntitlementRisk.Risk + '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,13 +52,13 @@ 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' })) { - Paragraph "Health Check:" -Bold -Underline + $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 { - 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." + 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 } diff --git a/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 similarity index 71% rename from Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 index 4c14837..99f213d 100755 --- a/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapClusterLicenseUsage { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,22 +19,21 @@ function Get-AbrOntapClusterLicenseUsage { ) begin { - Write-PScriboMessage "Collecting ONTAP cluster license usage information." + Write-PScriboMessage 'Collecting ONTAP cluster license usage information.' } process { 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' = Switch ($NodeLFs.Notes) { - "-" { 'None' } - default { $NodeLFs.Notes } - } + 'Notes' = $NodeLFs.Notes } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } $TableParams = @{ Name = "License Feature - $($ClusterInfo.ClusterName)" @@ -44,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-AbrOntapClusterReplicationDiagram.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterReplicationDiagram.ps1 similarity index 57% rename from Src/Private/Get-AbrOntapClusterReplicationDiagram.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterReplicationDiagram.ps1 index af2d044..4b10045 100644 --- a/Src/Private/Get-AbrOntapClusterReplicationDiagram.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapClusterReplicationDiagram.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapClusterReplicationDiagram { .DESCRIPTION .NOTES - Version: 0.6.9 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapClusterReplicationDiagram { ) begin { - Write-PScriboMessage "Generating Cluster Replication Diagram for NetApp ONTAP." + Write-PScriboMessage 'Generating Cluster Replication Diagram for NetApp ONTAP.' # Used for DiagramDebug if ($Options.EnableDiagramDebug) { $EdgeDebug = @{style = 'filled'; color = 'red' } @@ -72,35 +72,41 @@ function Get-AbrOntapClusterReplicationDiagram { if ($ClusterHa.Name -notin $HAObject.Partner) { $HAObject += [PSCustomObject][ordered]@{ - "HAState" = $ClusterHa.State + 'HAState' = $ClusterHa.State } } $NodeAdditionalInfo += [PSCustomObject][ordered]@{ - "Management" = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { - $true { "Unknown" } - $false { $NodeMgmtAddress } - Default { "Unknown" } + 'Management' = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { + $true { 'Unknown' } + $false { + if ($NodeMgmtAddress -is [System.Array]) { + $NodeMgmtAddress -join ', ' + } else { + $NodeMgmtAddress + } + } + default { 'Unknown' } } - "Intercluster" = switch ([string]::IsNullOrEmpty($NodeInterClusterAddress)) { - $true { "Unknown" } + 'Intercluster' = switch ([string]::IsNullOrEmpty($NodeInterClusterAddress)) { + $true { 'Unknown' } $false { $NodeInterClusterAddress } - Default { "Unknown" } + default { 'Unknown' } } } } if ($ClusterInfo) { - $ClusterNodeObj = Add-DiaHTMLNodeTable -ImagesObj $Images -inputObject $NodeSum.Node -Align "Center" -iconType "Ontap_Node" -columnSize $NodeSumColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo $NodeAdditionalInfo -Subgraph -SubgraphIconType "Ontap_Node_Icon" -SubgraphLabel $ClusterInfo.ClusterName -SubgraphLabelPos "top" -SubgraphTableStyle "dashed,rounded" -TableBorderColor "#71797E" -TableBorder "0" -SubgraphLabelFontsize 22 -fontSize 18 + $ClusterNodeObj = Add-HtmlNodeTable -Name 'ClusterNodeObj' -ImagesObj $Images -inputObject $NodeSum.Node -Align 'Center' -iconType 'Ontap_Node' -ColumnSize $NodeSumColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo $NodeAdditionalInfo -Subgraph -SubgraphIconType 'Ontap_Node_Icon' -SubgraphLabel $ClusterInfo.ClusterName -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder '0' -SubgraphLabelFontSize 22 -FontSize 18 } if ($ClusterNodeObj) { - $ClusterMgmtObj = Add-DiaHTMLSubGraph -ImagesObj $Images -TableArray $ClusterNodeObj -Align 'Right' -IconDebug $IconDebug -Label "Management: $($ClusterInfo.NcController)" -LabelPos 'down' -TableStyle "dashed,rounded" -TableBorderColor $Edgecolor -TableBorder "1" -columnSize 1 -fontSize 12 + $ClusterMgmtObj = Add-HtmlSubGraph -Name 'ClusterMgmtObj' -ImagesObj $Images -TableArray $ClusterNodeObj -Align 'Right' -IconDebug $IconDebug -Label "Management: $($ClusterInfo.NcController)" -LabelPos 'down' -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -ColumnSize 1 -FontSize 12 if ($ClusterMgmtObj) { Node SourceCluster @{Label = $ClusterMgmtObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } } else { - Write-PScriboMessage -IsWarning "Unable to create Cluster Node. No Cluster Management Object found." + Write-PScriboMessage -IsWarning 'Unable to create Cluster Node. No Cluster Management Object found.' } } } catch { @@ -114,20 +120,20 @@ function Get-AbrOntapClusterReplicationDiagram { $Index = $VserverPeersColors.Count - 1 foreach ($VserverPeer in $VserverPeers) { $VserversPeerInfo += [PSCustomObject][ordered]@{ - "SourceCluster" = $ClusterInfo.ClusterName - "SourceVserver" = $VserverPeer.Vserver - "RemoteCluster" = $VserverPeer.PeerCluster - "RemoteVserver" = $VserverPeer.PeerVserver - "Color" = Get-RandomPastelColorHex - "SourceAdditionalInfo" = [PSCustomObject][ordered]@{ - "Peer Vserver" = $VserverPeer.PeerVserver - "Peer Cluster" = $VserverPeer.PeerCluster - "Applications" = $VserverPeer.Applications -join ", " + 'SourceCluster' = $ClusterInfo.ClusterName + 'SourceVserver' = $VserverPeer.Vserver + 'RemoteCluster' = $VserverPeer.PeerCluster + 'RemoteVserver' = $VserverPeer.PeerVserver + 'Color' = Get-RandomPastelColorHex + 'SourceAdditionalInfo' = [PSCustomObject][ordered]@{ + 'Peer Vserver' = $VserverPeer.PeerVserver + 'Peer Cluster' = $VserverPeer.PeerCluster + 'Applications' = $VserverPeer.Applications -join ', ' } - "DestinationAdditionalInfo" = [PSCustomObject][ordered]@{ - "Peer Vserver" = $VserverPeer.Vserver - "Peer Cluster" = $ClusterInfo.ClusterName - "Applications" = $VserverPeer.Applications -join ", " + 'DestinationAdditionalInfo' = [PSCustomObject][ordered]@{ + 'Peer Vserver' = $VserverPeer.Vserver + 'Peer Cluster' = $ClusterInfo.ClusterName + 'Applications' = $VserverPeer.Applications -join ', ' } } } @@ -136,7 +142,7 @@ function Get-AbrOntapClusterReplicationDiagram { $VserverPeerObj = @() $VserverPeerObj = foreach ($VserverPeer in $VserversPeerInfo) { - Add-DiaHTMLNodeTable -ImagesObj $Images -inputObject $VserverPeer.SourceVserver -Align "Center" -iconType "Ontap_SVM" -columnSize 1 -IconDebug $IconDebug -MultiIcon -AditionalInfo $VserverPeer.SourceAdditionalInfo -SubgraphTableStyle "dashed,rounded" -TableBorderColor "#71797E" -TableBorder 1 -fontSize 18 -CellBackgroundColor $VserverPeer.Color + Add-HtmlNodeTable -Name 'VserverPeerObj' -ImagesObj $Images -inputObject $VserverPeer.SourceVserver -Align 'Center' -iconType 'Ontap_SVM' -ColumnSize 1 -IconDebug $IconDebug -MultiIcon -AditionalInfo $VserverPeer.SourceAdditionalInfo -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder 1 -FontSize 18 -CellBackgroundColor $VserverPeer.Color } if ($VserverPeerObj.Count -eq 1) { @@ -147,11 +153,11 @@ function Get-AbrOntapClusterReplicationDiagram { $VserverPeerObjColumnSize = $VserverPeerObj.Count } - $VserverPeerSubGraphObj = Add-DiaHTMLSubGraph -ImagesObj $Images -TableArray $VserverPeerObj -Align 'Center' -IconDebug $IconDebug -Label "Source Storage VMs" -LabelPos 'top' -TableStyle "dashed,rounded" -TableBorderColor $Edgecolor -TableBorder "1" -columnSize $VserverPeerObjColumnSize -fontSize 18 -IconType "Ontap_SVM_Icon" + $VserverPeerSubGraphObj = Add-HtmlSubGraph -Name 'VserverPeerSubGraphObj' -ImagesObj $Images -TableArray $VserverPeerObj -Align 'Center' -IconDebug $IconDebug -Label 'Source Storage VMs' -LabelPos 'top' -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -ColumnSize $VserverPeerObjColumnSize -FontSize 18 -IconType 'Ontap_SVM_Icon' if ($VserverPeerSubGraphObj) { Node SourceVservers @{Label = $VserverPeerSubGraphObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } - Edge -From SourceVservers -To SourceCluster @{minlen = 2; color = '#71797E'; style = 'filled'; arrowhead = 'box'; arrowtail = 'box' } + Add-NodeEdge -From 'SourceVservers' -To 'SourceCluster' -EdgeColor '#71797E' -Arrowhead 'box' -Arrowtail 'box' -EdgeLength 2 -GraphvizAttributes @{style = 'filled' } Rank SourceVservers, SourceCluster } } catch { @@ -182,8 +188,8 @@ function Get-AbrOntapClusterReplicationDiagram { $NodeMgmtAddress = $ClusterReplicaInfo.NcController $NodeAdditionalInfo += [PSCustomObject][ordered]@{ - "Intercluster" = switch ([string]::IsNullOrEmpty($ClusterReplicaInfo.ActiveAddresses)) { - $true { "Unknown" } + 'Intercluster' = switch ([string]::IsNullOrEmpty($ClusterReplicaInfo.ActiveAddresses)) { + $true { 'Unknown' } $false { & { if ($ClusterReplicaInfo.ActiveAddresses.Count -gt 1) { @@ -193,7 +199,7 @@ function Get-AbrOntapClusterReplicationDiagram { } } } - Default { "Unknown" } + default { 'Unknown' } } } $Num++ @@ -201,33 +207,33 @@ function Get-AbrOntapClusterReplicationDiagram { if ($ClusterReplicaInfo -and $NodeReplicaSum) { try { - $ClusterReplicaNodeObj = Add-DiaHTMLNodeTable -ImagesObj $Images -inputObject $NodeReplicaSum -Align "Center" -iconType "Ontap_Node" -columnSize $NodeSumColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo $NodeAdditionalInfo -Subgraph -SubgraphIconType "Ontap_Node_Icon" -SubgraphLabel $ClusterReplicaInfo.ClusterName -SubgraphLabelPos "top" -SubgraphTableStyle "dashed,rounded" -TableBorderColor "#71797E" -TableBorder "1" -SubgraphLabelFontsize 22 -fontSize 18 + $ClusterReplicaNodeObj = Add-HtmlNodeTable -Name 'ClusterReplicaNodeObj' -ImagesObj $Images -inputObject $NodeReplicaSum -Align 'Center' -iconType 'Ontap_Node' -ColumnSize $NodeSumColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo $NodeAdditionalInfo -Subgraph -SubgraphIconType 'Ontap_Node_Icon' -SubgraphLabel $ClusterReplicaInfo.ClusterName -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder '1' -SubgraphLabelFontSize 22 -FontSize 18 } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } else { - Write-PScriboMessage -IsWarning "Unable to create Cluster Replication Node. No Cluster Management Object found." + Write-PScriboMessage -IsWarning 'Unable to create Cluster Replication Node. No Cluster Management Object found.' } if ($ClusterReplicaNodeObj) { if ($ClusterReplicaNodeObj) { - $RemoteClusterName = Remove-SpecialChar -String $ClusterReplicaInfo.ClusterName -SpecialChars '\-_' + $RemoteClusterName = Remove-SpecialCharacter -String $ClusterReplicaInfo.ClusterName -SpecialChars '\-_' Node $RemoteClusterName @{Label = $ClusterReplicaNodeObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } $Ranks += $RemoteClusterName } else { - Write-PScriboMessage -IsWarning "Unable to create Cluster Replication Node. No Cluster Management Object found." + Write-PScriboMessage -IsWarning 'Unable to create Cluster Replication Node. No Cluster Management Object found.' } } if ($ClusterReplicaNodeObj) { - Edge -From SourceCluster:e -To $RemoteClusterName @{minlen = 3; color = '#71797E'; style = 'filled'; arrowhead = 'box'; arrowtail = 'box' } + Add-NodeEdge -From 'SourceCluster:e' -To $RemoteClusterName -EdgeColor '#71797E' -Arrowhead 'box' -Arrowtail 'box' -EdgeLength 3 -GraphvizAttributes @{style = 'filled' } } try { $PeerVserverPeerObj = @() $PeerVserverPeerObj = foreach ($VserversPeer in ($VserversPeerInfo | Where-Object { $_.RemoteCluster -eq $ClusterReplicaInfo.ClusterName })) { - Add-DiaHTMLNodeTable -ImagesObj $Images -inputObject $VserversPeer.RemoteVserver -Align "Center" -iconType "Ontap_SVM" -columnSize 1 -IconDebug $IconDebug -MultiIcon -AditionalInfo $VserversPeer.DestinationAdditionalInfo -SubgraphTableStyle "dashed,rounded" -TableBorderColor "#71797E" -TableBorder "1" -SubgraphLabelFontsize 22 -fontSize 18 -CellBackgroundColor $VserversPeer.Color + Add-HtmlNodeTable -Name 'PeerVserverPeerObj' -ImagesObj $Images -inputObject $VserversPeer.RemoteVserver -Align 'Center' -iconType 'Ontap_SVM' -ColumnSize 1 -IconDebug $IconDebug -MultiIcon -AditionalInfo $VserversPeer.DestinationAdditionalInfo -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder '1' -SubgraphLabelFontSize 22 -FontSize 18 -CellBackgroundColor $VserversPeer.Color } if ($PeerVserverPeerObj.Count -eq 1) { @@ -238,13 +244,13 @@ function Get-AbrOntapClusterReplicationDiagram { $PeerVserverPeerObjColumnSize = $PeerVserverPeerObj.Count } - $PeerVserverPeerSubGraphObj = Add-DiaHTMLSubGraph -ImagesObj $Images -TableArray $PeerVserverPeerObj -Align 'Center' -IconDebug $IconDebug -Label "Peer Storage VMs" -LabelPos 'top' -TableStyle "dashed,rounded" -TableBorderColor $Edgecolor -TableBorder "1" -columnSize $PeerVserverPeerObjColumnSize -fontSize 18 -IconType "Ontap_SVM_Icon" + $PeerVserverPeerSubGraphObj = Add-HtmlSubGraph -Name 'PeerVserverPeerSubGraphObj' -ImagesObj $Images -TableArray $PeerVserverPeerObj -Align 'Center' -IconDebug $IconDebug -Label 'Peer Storage VMs' -LabelPos 'top' -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -ColumnSize $PeerVserverPeerObjColumnSize -FontSize 18 -IconType 'Ontap_SVM_Icon' if ($PeerVserverPeerSubGraphObj -and $RemoteClusterName) { Node "$($RemoteClusterName)PeerVservers" @{Label = $PeerVserverPeerSubGraphObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } - Edge -From $RemoteClusterName -To "$($RemoteClusterName)PeerVservers" @{minlen = 2; color = '#71797E'; style = 'filled'; arrowhead = 'box'; arrowtail = 'box' } + Add-NodeEdge -From $RemoteClusterName -To "$($RemoteClusterName)PeerVservers" -EdgeColor '#71797E' -Arrowhead 'box' -Arrowtail 'box' -EdgeLength 2 -GraphvizAttributes @{style = 'filled' } } else { - Write-PScriboMessage -IsWarning "Unable to create Peer Vserver Node. No Peer Vserver Object found." + Write-PScriboMessage -IsWarning 'Unable to create Peer Vserver Node. No Peer Vserver Object found.' } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskAssign.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskAssign.ps1 new file mode 100755 index 0000000..a4654a2 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskAssign.ps1 @@ -0,0 +1,68 @@ +function Get-AbrOntapDiskAssign { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP disk assign summary information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP disk assignment per node information.' + } + + process { + try { + $NodeDiskCount = Get-NcDisk -Controller $Array | ForEach-Object { $_.DiskOwnershipInfo.HomeNodeName } | Group-Object + if ($NodeDiskCount) { + $ChartData = @() + $OwnerName = @() + $OutObj = @() + foreach ($Disks in $NodeDiskCount) { + $OwnerName += $Disks.Name + $ChartData += $Disks.Count + $inObj = [ordered] @{ + 'Node' = $Disks.Name + 'Disk Count' = $Disks | Select-Object -ExpandProperty Count + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } + $TableParams = @{ + Name = "Assigned Disk - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 50, 50 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + try { + $Chart = New-BarChart -Values $ChartData -Labels $OwnerName -Title 'Disk Assignment' -EnableLegend -LegendOrientation Horizontal -LegendAlignment UpperCenter -Width 600 -Height 600 -Format base64 -LabelYAxis 'Disk Count' -LabelXAxis 'Nodes' -TitleFontSize 20 -TitleFontBold -AreaOrientation Vertical -EnableCustomColorPalette -CustomColorPalette @('#395879', '#59779a', '#7b98bc', '#9dbae0', '#c0ddff') -AxesMarginsTop 0.5 + if ($Chart) { + Section -Style NOTOCHeading5 -ExcludeFromTOC 'Per Node Disk Assignment - Chart' { + Image -Text 'Per Node Disk Assignment - Chart' -Align 'Center' -Percent 100 -Base64 $Chart + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapDiskBroken.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskBroken.ps1 similarity index 65% rename from Src/Private/Get-AbrOntapDiskBroken.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskBroken.ps1 index 9639afb..05c2135 100755 --- a/Src/Private/Get-AbrOntapDiskBroken.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskBroken.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapDiskBroken { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,24 +19,26 @@ function Get-AbrOntapDiskBroken { ) begin { - Write-PScriboMessage "Collecting ONTAP failed disk per node information." + Write-PScriboMessage 'Collecting ONTAP failed disk per node information.' } process { try { - $NodeDiskBroken = Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq "broken" } + $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,13 +48,13 @@ function Get-AbrOntapDiskBroken { if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $DiskFailed | Table @TableParams - if ($Healthcheck.Storage.DiskStatus -and ($DiskFailed)) { - Paragraph "Health Check:" -Bold -Underline + $OutObj | Table @TableParams + if ($Healthcheck.Storage.DiskStatus -and ($OutObj)) { + 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." + 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 } diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskInv.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskInv.ps1 new file mode 100755 index 0000000..d7a2955 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskInv.ps1 @@ -0,0 +1,98 @@ +function Get-AbrOntapDiskInv { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP disk inventort information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP disk inventory per node.' + } + + process { + try { + $DiskInv = Get-NcDisk -Controller $Array + $NodeDiskBroken = Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq 'broken' } + if ($DiskInv) { + $OutObj = @() + foreach ($Disks in $DiskInv) { + try { + $DiskType = Get-NcDisk -Controller $Array -Name $Disks.Name | ForEach-Object { $_.DiskInventoryInfo } + $inObj = [ordered] @{ + 'Disk Name' = $Disks.Name + 'Shelf' = $Disks.Shelf + 'Bay' = $Disks.Bay + 'Capacity' = ($Disks.Capacity | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Disksize) ?? '--' + 'Model' = $Disks.Model + 'Serial Number' = $DiskType.SerialNumber + 'Firmware' = $Disks.FW + 'Type' = $DiskType.DiskType + 'Aggregate' = $Disks.Aggregate + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + if ($Healthcheck.Storage.DiskStatus) { + $OutObj | Where-Object { $_.'Disk Name' -like '*(*)' } | Set-Style -Style Critical -Property 'Disk Name' + } + + if ($InfoLevel.Storage -ge 2) { + foreach ($Disks in $Outobj) { + Section -Style NOTOCHeading4 -ExcludeFromTOC "$($Disks.'Disk Name')" { + $TableParams = @{ + Name = "Disk Inventory - $($Disks.'Disk Name')" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $Disks | Select-Object -ExcludeProperty 'Disk Name' | Table @TableParams + if ($Healthcheck.Cluster.AutoSupport -and ($Disks | 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 + } + } + } + } else { + $TableParams = @{ + Name = "Disk Inventory - $($ClusterInfo.ClusterName)" + List = $false + Columns = 'Disk Name', 'Shelf', 'Bay', 'Capacity', 'Model', 'Type', 'Firmware' + ColumnWidths = 18, 13, 10, 10, 25, 12, 12 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapDiskOwner.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskOwner.ps1 similarity index 76% rename from Src/Private/Get-AbrOntapDiskOwner.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskOwner.ps1 index 2ca44a3..4067f35 100755 --- a/Src/Private/Get-AbrOntapDiskOwner.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskOwner.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapDiskOwner { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -24,23 +24,24 @@ function Get-AbrOntapDiskOwner { ) begin { - Write-PScriboMessage "Collecting ONTAP disk owned per node information." + Write-PScriboMessage 'Collecting ONTAP disk owned per node information.' } process { try { if ($Node) { - $DiskSummary = foreach ($Owner in $Node) { + $OutObj = @() + foreach ($Owner in $Node) { try { - $DiskOwner = Get-NcDiskOwner -Node $Owner -Controller $Array - foreach ($Disk in $DiskOwner) { - [PSCustomObject] @{ + foreach ($Disk in (Get-NcDiskOwner -Node $Owner -Controller $Array)) { + $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 @@ -54,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/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskShelf.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskShelf.ps1 new file mode 100755 index 0000000..96c4c69 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskShelf.ps1 @@ -0,0 +1,84 @@ +function Get-AbrOntapDiskShelf { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP disk shelf information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP disk shelf information.' + } + + process { + try { + $NodeSum = Get-NcNode -Controller $Array + if ($NodeSum) { + foreach ($Nodes in $NodeSum) { + try { + $Nodeshelf = Get-NcShelf -NodeName $Nodes.Node -Controller $Array -ErrorAction SilentlyContinue + if ($Nodeshelf) { + Section -ExcludeFromTOC -Style NOTOCHeading4 $($Nodes.Node) { + $OutObj = @() + foreach ($Shelf in $Nodeshelf) { + $inObj = [ordered] @{ + 'Channel' = $Shelf.ChannelName + 'Shelf Name' = $Shelf.ShelfName + 'Shelf ID' = $Shelf.ShelfId + 'Module' = $Shelf.Module + 'Module State' = $Shelf.ModuleState + 'State' = $Shelf.ShelfState + 'Type' = $Shelf.ShelfType + 'Firmware' = ($Shelf.FirmwareRevA + $Shelf.FirmwareRevB) ?? '--' + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } + if ($Healthcheck.Storage.ShelfStatus) { + $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 = "Storage Shelf - $($Nodes.Node)" + List = $false + ColumnWidths = 13, 13, 13, 13, 12, 12, 12, 12 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $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 { + 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 + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskShelfStorage.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskShelfStorage.ps1 new file mode 100755 index 0000000..8111bbd --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskShelfStorage.ps1 @@ -0,0 +1,71 @@ +function Get-AbrOntapDiskShelfStorage { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP disk shelf storage information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP disk shelf storage information.' + } + + process { + try { + $NodeshelfObj = Get-NcStorageShelf -Controller $Array -ErrorAction SilentlyContinue + if ($NodeshelfObj) { + $OutObj = @() + foreach ($Shelf in $NodeshelfObj) { + $inObj = [ordered] @{ + 'Model' = $Shelf.ShelfModel + 'Connection Type' = $Shelf.ConnectionType + 'Module Type' = $Shelf.ModuleType + 'Disk Count' = $Shelf.DiskCount + 'Serial Number' = $Shelf.SerialNumber + 'Operational Status' = $Shelf.OpStatus + 'Shelf Id' = $Shelf.Shelf + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } + if ($Healthcheck.Storage.ShelfStatus) { + $OutObj | Where-Object { $_.'Operational Status' -ne 'normal' } | Set-Style -Style Warning -Property 'Operational Status' + } + $TableParams = @{ + Name = "Disk Shelf - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 18, 13, 12, 11, 22, 14, 10 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + if ($Healthcheck.Storage.ShelfStatus -and ($OutObj | Where-Object { $_.'Operational Status' -ne 'normal' })) { + Paragraph 'Health Check:' -Bold -Underline + BlankLine + Paragraph { + Text 'Best Practice:' -Bold + Text ' All disk shelves should have an working operational status.' + } + BlankLine + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskType.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskType.ps1 new file mode 100755 index 0000000..7431870 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapDiskType.ps1 @@ -0,0 +1,96 @@ +function Get-AbrOntapDiskType { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP disk type information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP disk type per node information.' + } + + process { + try { + $OutObj = @() + foreach ($DiskContainers in (Get-NcDisk -Controller $Array | ForEach-Object { $_.DiskRaidInfo.ContainerType } | Group-Object)) { + try { + $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) { + $OutObj | Where-Object { $_.'Container' -like 'broken' } | Set-Style -Style Critical -Property 'Disk Count' + } + $TableParams = @{ + Name = "Disk Container Type - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 50, 50 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + $Node = Get-NcNode | Where-Object { $_.IsNodeHealthy -eq 'True' } + if ($Node -and (Confirm-NcAggrSpareLow | Where-Object { $_.Value -eq 'True' })) { + Section -ExcludeFromTOC -Style NOTOCHeading5 'Aggregate Spare Low Warning Per Node' { + $OutObj = @() + foreach ($Item in $Node) { + try { + $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 + } + } + if ($Healthcheck.Storage.DiskStatus) { + $OutObj | Where-Object { $_.'Aggregate Spare Low' -like 'Yes' } | Set-Style -Style Critical -Property 'Node', 'Aggregate Spare Low' + } + $TableParams = @{ + Name = "Aggregate Disk Spare Low - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 50, 50 + } + if ($Report.ShowTableCaptions) { + $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 + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 similarity index 77% rename from Src/Private/Get-AbrOntapEfficiencyAggr.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 index 5898951..a1d7a0e 100755 --- a/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapEfficiencyAggr { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapEfficiencyAggr { ) begin { - Write-PScriboMessage "Collecting ONTAP Aggregate Efficiency Savings information." + Write-PScriboMessage 'Collecting ONTAP Aggregate Efficiency Savings information.' } process { @@ -32,13 +32,13 @@ function Get-AbrOntapEfficiencyAggr { $Saving = Get-NcAggrEfficiency -Aggregate $Item.Name -Controller $Array | Select-Object -ExpandProperty AggrEfficiencyAggrInfo $inObj = [ordered] @{ 'Aggregate' = $Item.Name - 'Logical Used' = $Saving.AggrLogicalUsed | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Physical Used' = $Saving.AggrPhysicalUsed | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Compaction Saved' = $Saving.AggrCompactionSaved | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Data Reduction' = $Saving.AggrDataReductionStorageEfficiencyRatio + 'Logical Used' = ($Saving.AggrLogicalUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Physical Used' = ($Saving.AggrPhysicalUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Compaction Saved' = ($Saving.AggrCompactionSaved | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Data Reduction' = ${Saving}?.AggrDataReductionStorageEfficiencyRatio } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -55,21 +55,21 @@ function Get-AbrOntapEfficiencyAggr { $OutObj | Table @TableParams } try { + $OutObj = @() $Data = Get-NcAggr -Controller $Array | Where-Object { $_.AggrRaidAttributes.HasLocalRoot -ne 'True' } $Savingfilter = (Get-NcAggrEfficiency -Controller $Array | Select-Object -ExpandProperty AggrEfficiencyAdditionalDetailsInfo).NumberOfSisDisabledVolumes | Measure-Object -Sum if ($Data -and $Savingfilter.Sum -gt 0 -and $Healthcheck.Storage.Efficiency) { - $OutObj = @() foreach ($Item in $Data) { try { $Saving = (Get-NcAggrEfficiency -Aggregate $Item.Name -Controller $Array | Select-Object -ExpandProperty AggrEfficiencyAdditionalDetailsInfo).NumberOfSisDisabledVolumes $VolInAggr = Get-NcVol -Aggregate $Item.Name -Controller $Array | Where-Object { $_.VolumeStateAttributes.IsVserverRoot -ne 'True' } - $VolFilter = $VolInAggr | Where-Object { $_.VolumeSisAttributes.IsSisStateEnabled -ne "True" } + $VolFilter = $VolInAggr | Where-Object { $_.VolumeSisAttributes.IsSisStateEnabled -ne 'True' } if ($Saving -ne 0 -and $VolFilter) { $inObj = [ordered] @{ 'Aggregate' = $Item.Name - 'Volumes without Deduplication' = $VolFilter.Name -join ", " + 'Volumes without Deduplication' = $VolFilter.Name -join ', ' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message @@ -95,11 +95,11 @@ function Get-AbrOntapEfficiencyAggr { BlankLine $OutObj | Table @TableParams if ($Healthcheck.Storage.Efficiency) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that deduplication is enabled on all volumes to maximize storage efficiency." + Text 'Best Practice:' -Bold + Text 'Ensure that deduplication is enabled on all volumes to maximize storage efficiency.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 similarity index 59% rename from Src/Private/Get-AbrOntapEfficiencyConfig.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 index f20c2c5..5d5a625 100755 --- a/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapEfficiencyConfig { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapEfficiencyConfig { ) begin { - Write-PScriboMessage "Collecting ONTAP Storage Efficiency Savings information." + Write-PScriboMessage 'Collecting ONTAP Storage Efficiency Savings information.' } process { @@ -30,17 +30,16 @@ 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 -ErrorAction SilentlyContinue - 'Capacity Tier Used' = $Saving.CapacityTierUsed | ConvertTo-FormattedNumber -Type Datasize -NumberFormatString "0.0" -ErrorAction SilentlyContinue - 'Compaction Saved %' = $Saving.DataCompactionSpaceSavedPercent | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue - 'Deduplication Saved %' = $Saving.SisSpaceSavedPercent | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue - 'Total Data Reduction' = $TotalStorageEfficiencyRatio.TotalStorageEfficiencyRatio + 'Used %' = ($Saving.PercentUsedCapacity | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' + 'Capacity Tier Used' = ($Saving.CapacityTierUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Compaction Saved %' = ($Saving.DataCompactionSpaceSavedPercent | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' + 'Deduplication Saved %' = ($Saving.SisSpaceSavedPercent | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' + 'Total Data Reduction' = (Get-NcAggrEfficiency -Aggregate $Item.Name -Controller $Array | Select-Object -ExpandProperty AggrEfficiencyCumulativeInfo).TotalStorageEfficiencyRatio ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapEfficiencyVol.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVol.ps1 similarity index 57% rename from Src/Private/Get-AbrOntapEfficiencyVol.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVol.ps1 index f2e2e1f..e38c518 100755 --- a/Src/Private/Get-AbrOntapEfficiencyVol.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVol.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapEfficiencyVol { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,12 +23,12 @@ function Get-AbrOntapEfficiencyVol { ) begin { - Write-PScriboMessage "Collecting ONTAP Volume Efficiency Savings information." + Write-PScriboMessage 'Collecting ONTAP Volume Efficiency Savings information.' } process { try { - $Data = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.State -eq "online" } + $Data = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.State -eq 'online' } $OutObj = @() if ($Data) { foreach ($Item in $Data) { @@ -36,14 +36,14 @@ function Get-AbrOntapEfficiencyVol { $Saving = Get-NcEfficiency -Volume $Item.Name -Vserver $Vserver -Controller $Array $inObj = [ordered] @{ 'Volume' = $Item.Name - 'Capacity' = $Saving.Capacity | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Used' = $Saving.Used | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Snapshot Used' = $Saving.SnapshotUsed | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Total Savings' = $Saving.Returns.Total | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Effective Used' = $Saving.EffectiveUsed | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Efficiency Percent' = $Saving.EfficiencyPercent | ConvertTo-FormattedNumber -Type Percent -NumberFormatString "0.0" -ErrorAction SilentlyContinue + 'Capacity' = ($Saving.Capacity | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Saving.Used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Snapshot Used' = ($Saving.SnapshotUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Total Savings' = ($Saving.Returns.Total | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Effective Used' = ($Saving.EffectiveUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Efficiency Percent' = ($Saving.EfficiencyPercent | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent -NumberFormatString 0.0) ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapEfficiencyVolDetailed.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVolDetailed.ps1 similarity index 51% rename from Src/Private/Get-AbrOntapEfficiencyVolDetailed.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVolDetailed.ps1 index c745d29..207dc92 100755 --- a/Src/Private/Get-AbrOntapEfficiencyVolDetailed.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVolDetailed.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapEfficiencyVolDetailed { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,12 +23,12 @@ function Get-AbrOntapEfficiencyVolDetailed { ) begin { - Write-PScriboMessage "Collecting ONTAP Volume Efficiency Savings information." + Write-PScriboMessage 'Collecting ONTAP Volume Efficiency Savings information.' } process { try { - $Data = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.State -eq "online" } + $Data = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.State -eq 'online' } $OutObj = @() if ($Data) { foreach ($Item in $Data) { @@ -36,15 +36,15 @@ function Get-AbrOntapEfficiencyVolDetailed { $Saving = Get-NcEfficiency -Volume $Item.Name -Vserver $Vserver -Controller $Array $inObj = [ordered] @{ 'Volume' = $Item.Name - 'Capacity' = $Saving.Capacity | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Dedupe Savings' = $Saving.Returns.Dedupe | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Compression Savings' = $Saving.Returns.Compression | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Snapshot Savings' = $Saving.Returns.Snapshot | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Cloning Savings' = $Saving.Returns.Cloning | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Efficiency %' = $Saving.EfficiencyPercent | ConvertTo-FormattedNumber -Type Percent -NumberFormatString "0.0" -ErrorAction SilentlyContinue - 'Efficiency % w/o Snapshots' = [Math]::Round((($Saving.Returns.Dedupe + $Saving.Returns.Compression) / ($Saving.Used + $Saving.Returns.Dedupe + $Saving.Returns.Compression)) * 100) | ConvertTo-FormattedNumber -Type Percent -NumberFormatString "0.0" -ErrorAction SilentlyContinue + 'Capacity' = ($Saving.Capacity | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Dedupe Savings' = ($Saving.Returns.Dedupe | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Compression Savings' = ($Saving.Returns.Compression | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Snapshot Savings' = ($Saving.Returns.Snapshot | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Cloning Savings' = ($Saving.Returns.Cloning | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Efficiency %' = ($Saving.EfficiencyPercent | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Percent ) ?? '--' + 'Efficiency % w/o Snapshots' = ([Math]::Round((($Saving.Returns.Dedupe + $Saving.Returns.Compression) / ($Saving.Used + $Saving.Returns.Dedupe + $Saving.Returns.Compression)) * 100) | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Percent) ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 similarity index 69% rename from Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 index fb8ae4d..919e961 100755 --- a/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapEfficiencyVolSisStatus { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapEfficiencyVolSisStatus { ) begin { - Write-PScriboMessage "Collecting ONTAP Volume Deduplication information." + Write-PScriboMessage 'Collecting ONTAP Volume Deduplication information.' } process { @@ -33,19 +33,14 @@ function Get-AbrOntapEfficiencyVolSisStatus { if ($Data) { foreach ($Item in $Data) { try { - $Volume = $Item.Path.split('/') $inObj = [ordered] @{ - 'Volume' = $Volume[2] - 'State' = switch ($Item.State) { - 'enabled' { 'Enabled' } - 'disabled' { 'Disabled' } - default { $Item.State } - } + 'Volume' = ($Item.Path.split('/'))[2] ?? '--' + 'State' = ($Item.State -eq 'enabled') ? 'Enabled': 'Disabled' 'Status' = $Item.Status - 'Schedule Or Policy' = ConvertTo-EmptyToFiller $Item.ScheduleOrPolicy - 'Progress' = ConvertTo-EmptyToFiller $Item.Progress + 'Schedule Or Policy' = $Item.ScheduleOrPolicy + 'Progress' = $Item.Progress } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -64,11 +59,11 @@ function Get-AbrOntapEfficiencyVolSisStatus { } $OutObj | Table @TableParams if ($Healthcheck.Storage.Efficiency -and ($OutObj | Where-Object { $_.'State' -like 'Disabled' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that volume deduplication is enabled on volumes where data reduction is beneficial to optimize storage efficiency.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapNetworkBdomain.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkBroadCastDomain.ps1 similarity index 58% rename from Src/Private/Get-AbrOntapNetworkBdomain.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkBroadCastDomain.ps1 index 26a6201..97ee163 100755 --- a/Src/Private/Get-AbrOntapNetworkBdomain.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkBroadCastDomain.ps1 @@ -1,11 +1,11 @@ -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 .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapNetworkBdomain { ) begin { - Write-PScriboMessage "Collecting ONTAP Broadcast information." + Write-PScriboMessage 'Collecting ONTAP Broadcast information.' } process { @@ -35,7 +35,11 @@ function Get-AbrOntapNetworkBdomain { 'MTU' = $Item.Mtu 'Ports' = $Item.Ports } - $BDomainObj += [pscustomobject]$inobj + $BDomainObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } + + if ($Healthcheck.Network.Port) { + $BDomainObj | Where-Object { $null -eq $_.'Failover Groups' -and $null -eq $_.'Ports' } | Set-Style -Style Warning } $TableParams = @{ @@ -47,6 +51,15 @@ function Get-AbrOntapNetworkBdomain { $TableParams['Caption'] = "- $($TableParams.Name)" } $BDomainObj | Table @TableParams + if ($Healthcheck.Network.Port -and ($BDomainObj | Where-Object { $null -eq $_.'Failover Groups' -and $null -eq $_.'Ports' })) { + Paragraph 'Health Check:' -Bold -Underline + BlankLine + Paragraph { + Text 'Best Practice:' -Bold + Text ' Broadcast Domains should have associated Failover Groups and Ports assigned to them, review the highlighted Broadcast Domains above and take corrective action as necessary.' + } + BlankLine + } } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapNetworkFailoverGroup.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkFailoverGroup.ps1 similarity index 89% rename from Src/Private/Get-AbrOntapNetworkFailoverGroup.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkFailoverGroup.ps1 index d855ead..831570f 100755 --- a/Src/Private/Get-AbrOntapNetworkFailoverGroup.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkFailoverGroup.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkFailoverGroup { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapNetworkFailoverGroup { ) begin { - Write-PScriboMessage "Collecting ONTAP Failover Group information." + Write-PScriboMessage 'Collecting ONTAP Failover Group information.' } process { @@ -34,7 +34,7 @@ function Get-AbrOntapNetworkFailoverGroup { 'Vserver' = $Item.Vserver 'Target' = $Item.Target } - $FGObj += [pscustomobject]$inobj + $FGObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 similarity index 73% rename from Src/Private/Get-AbrOntapNetworkIfgrp.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 index a02298b..50e79bb 100755 --- a/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkIfgrp { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapNetworkIfgrp { ) begin { - Write-PScriboMessage "Collecting ONTAP physical aggregata interface information." + Write-PScriboMessage 'Collecting ONTAP physical aggregata interface information.' } process { @@ -33,25 +33,22 @@ function Get-AbrOntapNetworkIfgrp { if ($IFGRPPorts) { foreach ($Nics in $IFGRPPorts) { try { - if ($Nics.DownPorts) { - $UPPort = "$($Nics.UpPorts) $($Nics.DownPorts)(Down)" - } else { $UPPort = [String]$Nics.UpPorts } $inObj = [ordered] @{ 'Port Name' = $Nics.IfgrpName 'Distribution Function' = $Nics.DistributionFunction 'Mode' = $Nics.Mode - 'Port' = $UPPort + 'Port' = ($Null -eq $Nics.DownPorts) ? [String]$Nics.UpPorts: "$($Nics.UpPorts) - {$($Nics.DownPorts)}(Down)" 'Mac Address' = $Nics.MacAddress 'Port Participation' = $Nics.PortParticipation } - $AggregatePorts += [pscustomobject]$inobj + $AggregatePorts += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Network.Port) { - $AggregatePorts | Where-Object { $_.'Port' -match "Down" } | Set-Style -Style Warning -Property 'Port' - $AggregatePorts | Where-Object { $_.'Port Participation' -ne "full" } | Set-Style -Style Warning -Property 'Port Participation' + $AggregatePorts | Where-Object { $_.'Port' -match 'Down' } | Set-Style -Style Warning -Property 'Port' + $AggregatePorts | Where-Object { $_.'Port Participation' -ne 'full' } | Set-Style -Style Warning -Property 'Port Participation' } @@ -64,12 +61,12 @@ 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 + 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." + 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 } diff --git a/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 similarity index 90% rename from Src/Private/Get-AbrOntapNetworkIpSpace.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 index 34eb286..8c0ff0a 100755 --- a/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkIpSpace { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapNetworkIpSpace { ) begin { - Write-PScriboMessage "Collecting ONTAP IPSpace information." + Write-PScriboMessage 'Collecting ONTAP IPSpace information.' } process { @@ -35,7 +35,7 @@ function Get-AbrOntapNetworkIpSpace { 'Ports' = $Item.Ports -join '; ' 'Broadcast Domains' = $Item.BroadcastDomains -join '; ' } - $IPSpaceObj = [pscustomobject]$inobj + $IPSpaceObj = [pscustomobject](ConvertTo-HashToYN $inObj) $TableParams = @{ Name = "Network IPSpace - $($Item.Ipspace)" diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkMGMT.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkMGMT.ps1 new file mode 100755 index 0000000..946ea39 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkMGMT.ps1 @@ -0,0 +1,276 @@ +function Get-AbrOntapNetworkMgmt { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP network management interfaces information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP network management interface information.' + } + + process { + try { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'cluster' } + if ($ClusterData) { + try { + Section -ExcludeFromTOC -Style Heading6 'Cluster Network Interfaces' { + $ClusterObj = @() + foreach ($Item in $ClusterData) { + try { + $inObj = [ordered] @{ + 'Cluster Interface' = $Item.InterfaceName + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() + 'Data Protocols' = $Item.DataProtocols + 'Address' = $Item.Address + 'Home Node' = $Item.HomeNode + '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' + } + + $TableParams = @{ + Name = "Cluster Network - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 27, 8, 12, 18, 17, 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 { + $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] @{ + 'MGMT Interface' = $Item.InterfaceName + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() + 'Data Protocols' = $Item.DataProtocols + 'Address' = $Item.Address + 'Home Node' = $Item.HomeNode + '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' + } + + $TableParams = @{ + Name = "Management Network - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 27, 8, 17, 15, 15, 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 management network interfaces are operational (UP) to maintain proper management access to the cluster.' + } + BlankLine + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + try { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'intercluster' } + if ($ClusterData) { + Section -ExcludeFromTOC -Style Heading6 'Intercluster Network Interfaces' { + $ClusterObj = @() + foreach ($Item in $ClusterData) { + try { + $inObj = [ordered] @{ + 'Intercluster Interface' = $Item.InterfaceName + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() + 'Data Protocols' = $Item.DataProtocols + 'Address' = $Item.Address + 'Home Node' = $Item.HomeNode + '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' + } + + $TableParams = @{ + Name = "Intercluster Network - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 27, 8, 17, 15, 15, 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 { + $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) { + $AddressData = $Item.Wwpn + } else { $AddressData = $Item.Address } + $inObj = [ordered] @{ + 'Data Interface' = $Item.InterfaceName + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() + 'Data Protocols' = [string]$Item.DataProtocols + 'Address' = $AddressData + 'Home Node' = $Item.HomeNode + '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' + } + + $TableParams = @{ + Name = "Data Network - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 25, 10, 17, 15, 15, 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 data network interfaces are operational (UP) to maintain optimal data access and performance.' + } + BlankLine + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + try { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.DataProtocols -ne 'fcp' -and $_.IsHome -like 'False' } + if ($ClusterData) { + Section -ExcludeFromTOC -Style Heading6 'Network Interfaces Home Status' { + Paragraph "The following table provides the LIF Home Status Information from $($ClusterInfo.ClusterName)." + BlankLine + $ClusterObj = @() + 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' + } + + $TableParams = @{ + Name = "Network Interfaces 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 { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapNetworkPorts.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkPorts.ps1 similarity index 67% rename from Src/Private/Get-AbrOntapNetworkPorts.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkPorts.ps1 index 9deb02d..7078a76 100755 --- a/Src/Private/Get-AbrOntapNetworkPorts.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkPorts.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkPort { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,33 +23,31 @@ function Get-AbrOntapNetworkPort { ) begin { - Write-PScriboMessage "Collecting ONTAP physical interface information." + Write-PScriboMessage 'Collecting ONTAP physical interface information.' } process { 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 'MTU' = $Nics.MTU 'Link Status' = $TextInfo.ToTitleCase($Nics.LinkStatus) - 'Admin Status' = switch ($Nics.IsAdministrativeUp) { - "True" { 'Up' } - "False" { 'Down' } - default { $Nics.IsAdministrativeUp } - } + '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 = @{ @@ -60,12 +58,12 @@ 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' })) { - Paragraph "Health Check:" -Bold -Underline + $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 { - Text "Best Practice:" -Bold + 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 diff --git a/Src/Private/Get-AbrOntapNetworkRoute.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkRoute.ps1 similarity index 85% rename from Src/Private/Get-AbrOntapNetworkRoute.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkRoute.ps1 index e682990..316d6fc 100755 --- a/Src/Private/Get-AbrOntapNetworkRoute.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkRoute.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkRoute { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapNetworkRoute { ) begin { - Write-PScriboMessage "Collecting ONTAP network route information." + Write-PScriboMessage 'Collecting ONTAP network route information.' } process { @@ -37,9 +37,9 @@ function Get-AbrOntapNetworkRoute { 'Destination' = $Item.Destination 'Gateway' = $Item.Gateway 'Metric' = $Item.Metric - 'Address Family' = $Item.AddressFamily.ToString() + 'Address Family' = ${Item}?.AddressFamily?.ToString() } - $RoutesObj += [pscustomobject]$inobj + $RoutesObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapNetworkRouteLifs.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkRouteLifs.ps1 similarity index 85% rename from Src/Private/Get-AbrOntapNetworkRouteLifs.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkRouteLifs.ps1 index cfdf15f..42399f7 100755 --- a/Src/Private/Get-AbrOntapNetworkRouteLifs.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkRouteLifs.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkRouteLif { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapNetworkRouteLif { ) begin { - Write-PScriboMessage "Collecting ONTAP network route per lif information." + Write-PScriboMessage 'Collecting ONTAP network route per lif information.' } process { @@ -37,9 +37,9 @@ function Get-AbrOntapNetworkRouteLif { 'Destination' = $Item.Destination 'Gateway' = $Item.Gateway 'Lif Names' = $Item.LifNames - 'Address Family' = $Item.AddressFamily.ToString() + 'Address Family' = ${Item}?.AddressFamily?.ToString() } - $RoutesObj += [pscustomobject]$inobj + $RoutesObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapNetworkSubnet.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkSubnet.ps1 similarity index 90% rename from Src/Private/Get-AbrOntapNetworkSubnet.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkSubnet.ps1 index b046cd1..cee259c 100755 --- a/Src/Private/Get-AbrOntapNetworkSubnet.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkSubnet.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkSubnet { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapNetworkSubnet { ) begin { - Write-PScriboMessage "Collecting ONTAP Subnets information." + Write-PScriboMessage 'Collecting ONTAP Subnets information.' } process { @@ -37,7 +37,7 @@ function Get-AbrOntapNetworkSubnet { 'Used IP' = $Item.Used 'Ip Ranges' = $Item.IpRanges } - $SubnetObj += [pscustomobject]$inobj + $SubnetObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapNetworkVlans.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkVlans.ps1 similarity index 90% rename from Src/Private/Get-AbrOntapNetworkVlans.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkVlans.ps1 index dba8b79..cb19877 100755 --- a/Src/Private/Get-AbrOntapNetworkVlans.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNetworkVlans.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkVlan { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapNetworkVlan { ) begin { - Write-PScriboMessage "Collecting ONTAP VLAN information." + Write-PScriboMessage 'Collecting ONTAP VLAN information.' } process { @@ -38,7 +38,7 @@ function Get-AbrOntapNetworkVlan { 'Parent Interface' = $Item.ParentInterface 'Vlan ID' = $Item.VlanID } - $VlanObj += [pscustomobject]$inobj + $VlanObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 similarity index 59% rename from Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 index 10f40eb..a9273c6 100644 --- a/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapStorageAggrDiagram { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapStorageAggrDiagram { ) begin { - Write-PScriboMessage "Generating Storage Aggregates Diagram for NetApp ONTAP." + Write-PScriboMessage 'Generating Storage Aggregates Diagram for NetApp ONTAP.' # Used for DiagramDebug if ($Options.EnableDiagramDebug) { $EdgeDebug = @{style = 'filled'; color = 'red' } @@ -52,7 +52,7 @@ function Get-AbrOntapStorageAggrDiagram { $ClusterInfo = Get-NcCluster -Controller $Array $NodeSum = Get-NcNode -Controller $Array - SubGraph Cluster -Attributes @{Label = $ClusterInfo.ClusterName; fontsize = 22; penwidth = 1.5; labelloc = 't'; style = "dashed,rounded"; color = "gray" } { + SubGraph Cluster -Attributes @{Label = $ClusterInfo.ClusterName; fontsize = 22; penwidth = 1.5; labelloc = 't'; style = 'dashed,rounded'; color = 'gray' } { try { if ($NodeSum.Count -eq 1) { @@ -76,22 +76,22 @@ function Get-AbrOntapStorageAggrDiagram { if ($ClusterHa.Name -notin $HAObject.Partner) { $HAObject += [PSCustomObject][ordered]@{ - "Name" = $ClusterHa.Name - "Partner" = $ClusterHa.Partner - "HAState" = $ClusterHa.State + 'Name' = $ClusterHa.Name + 'Partner' = $ClusterHa.Partner + 'HAState' = $ClusterHa.State } } $NodeAdditionalInfo += [PSCustomObject][ordered]@{ 'NodeName' = $Node.Node 'AdditionalInfo' = [PSCustomObject][ordered]@{ - "System Id" = $Node.NodeSystemId - "Serial" = $Node.NodeSerialNumber - "Model" = $Node.NodeSerialNumber - "Mgmt" = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { - $true { "Unknown" } - $false { $NodeMgmtAddress } - default { "Unknown" } + 'System Id' = $Node.NodeSystemId + 'Serial' = $Node.NodeSerialNumber + 'Model' = $Node.NodeModel + 'Mgmt' = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { + $true { 'Unknown' } + $false { $NodeMgmtAddress -join ', ' } + default { 'Unknown' } } } } @@ -99,33 +99,33 @@ function Get-AbrOntapStorageAggrDiagram { $NodeAggr = Get-NcAggr | Where-Object { $_.Nodes -eq $Node.Node } foreach ($Aggr in $NodeAggr) { $AggrInfo += [PSCustomObject][ordered]@{ - "NodeName" = $Node.Node - "AggregateName" = $Aggr.Name - "AdditionalInfo" = [PSCustomObject][ordered]@{ - "Total Size" = $Aggr.TotalSize | 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" } + 'NodeName' = $Node.Node + 'AggregateName' = $Aggr.Name + 'AdditionalInfo' = [PSCustomObject][ordered]@{ + 'Total Size' = $Aggr.TotalSize | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize -ErrorAction SilentlyContinue + 'Used Space' = ($Aggr.TotalSize - $Aggr.Available) | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize -ErrorAction SilentlyContinue + 'Assigned Disk' = $Aggr.Disks + 'Raid Type' = switch ([string]::IsNullOrEmpty($Aggr.RaidType)) { + $true { 'Unknown' } $false { & { - switch ($Aggr.RaidType.Split(", ")[0]) { - "raid4" { "RAID 4" } - "raid_dp" { "RAID DP" } - "raid0" { "RAID 0" } - "raid1" { "RAID 1" } - "raid10" { "RAID 10" } - default { "Unknown" } + switch ($Aggr.RaidType.Split(', ')[0]) { + 'raid4' { 'RAID 4' } + 'raid_dp' { 'RAID DP' } + 'raid0' { 'RAID 0' } + 'raid1' { 'RAID 1' } + 'raid10' { 'RAID 10' } + default { 'Unknown' } } } } - default { "Unknown" } + default { 'Unknown' } } - "Raid Size" = $Aggr.RaidSize - "State" = switch ([string]::IsNullOrEmpty($Aggr.State)) { - $true { "Unknown" } + 'Raid Size' = $Aggr.RaidSize + 'State' = switch ([string]::IsNullOrEmpty($Aggr.State)) { + $true { 'Unknown' } $false { $Aggr.State.ToUpper() } - default { "Unknown" } + default { 'Unknown' } } } } @@ -136,7 +136,7 @@ function Get-AbrOntapStorageAggrDiagram { foreach ($Node in $NodeAdditionalInfo) { $ClusterNodeObj = @() - $ClusterNodeObj += Add-DiaHtmlNodeTable -ImagesObj $Images -inputObject $Node.NodeName -Align "Center" -iconType "Ontap_Node" -ColumnSize 1 -IconDebug $IconDebug -MultiIcon -AditionalInfo $Node.AdditionalInfo -Subgraph -SubgraphLabel $Node.NodeName -SubgraphLabelPos "top" -SubgraphTableStyle "dashed,rounded" -TableBorderColor "#71797E" -TableBorder 0 -SubgraphLabelFontSize 22 -FontSize 18 + $ClusterNodeObj += Add-HtmlNodeTable -Name 'ClusterNodeObj' -ImagesObj $Images -inputObject $Node.NodeName -Align 'Center' -iconType 'Ontap_Node' -ColumnSize 1 -IconDebug $IconDebug -MultiIcon -AditionalInfo $Node.AdditionalInfo -Subgraph -SubgraphLabel $Node.NodeName -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder 0 -SubgraphLabelFontSize 22 -FontSize 18 if ($ClusterNodeObj) { if ($AggrInfo.Count -eq 1) { @@ -146,11 +146,11 @@ function Get-AbrOntapStorageAggrDiagram { } else { $AggrInfoColumnSize = $AggrInfo.Count } - $ClusterNodeObj += Add-DiaHtmlNodeTable -ImagesObj $Images -inputObject ($AggrInfo | Where-Object { $_.NodeName -eq $Node.Nodename }).AggregateName -Align "Center" -iconType "Ontap_Aggregate" -ColumnSize $AggrInfoColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo ($AggrInfo | Where-Object { $_.NodeName -eq $Node.Nodename }).AdditionalInfo -Subgraph -SubgraphLabel "Aggregates" -SubgraphLabelPos "top" -SubgraphTableStyle "dashed,rounded" -TableBorderColor "#71797E" -TableBorder 1 -SubgraphLabelFontSize 22 -FontSize 18 + $ClusterNodeObj += Add-HtmlNodeTable -Name 'ClusterNodeObj' -ImagesObj $Images -inputObject ($AggrInfo | Where-Object { $_.NodeName -eq $Node.Nodename }).AggregateName -Align 'Center' -iconType 'Ontap_Aggregate' -ColumnSize $AggrInfoColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo ($AggrInfo | Where-Object { $_.NodeName -eq $Node.Nodename }).AdditionalInfo -Subgraph -SubgraphLabel 'Aggregates' -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder 1 -SubgraphLabelFontSize 22 -FontSize 18 } if ($ClusterNodeObj) { - $ClusterNodeSubgraphObj = Add-DiaHtmlSubGraph -ImagesObj $Images -TableArray $ClusterNodeObj -Align 'Center' -IconDebug $IconDebug -Label " " -LabelPos 'top' -TableStyle "dashed,rounded" -TableBorderColor $Edgecolor -TableBorder 1 -ColumnSize 1 -FontSize 12 + $ClusterNodeSubgraphObj = Add-HtmlSubGraph -Name 'ClusterNodeSubgraphObj' -ImagesObj $Images -TableArray $ClusterNodeObj -Align 'Center' -IconDebug $IconDebug -Label ' ' -LabelPos 'top' -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder 1 -ColumnSize 1 -FontSize 12 } $ClusterNodesObj += $ClusterNodeSubgraphObj @@ -164,13 +164,13 @@ function Get-AbrOntapStorageAggrDiagram { } else { $ClusterNodesObjColumnSize = $ClusterNodesObj.Count } - $ClusterMgmtObj = Add-DiaHtmlSubGraph -ImagesObj $Images -TableArray $ClusterNodesObj -Align 'Right' -IconDebug $IconDebug -Label "Management: $($ClusterInfo.NcController.Name)" -LabelPos 'down' -TableStyle "dashed,rounded" -TableBorderColor $Edgecolor -TableBorder 0 -ColumnSize $ClusterNodesObjColumnSize -FontSize 18 + $ClusterMgmtObj = Add-HtmlSubGraph -Name 'ClusterMgmtObj' -ImagesObj $Images -TableArray $ClusterNodesObj -Align 'Right' -IconDebug $IconDebug -Label "Management: $($ClusterInfo.NcController.Name)" -LabelPos 'down' -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder 0 -ColumnSize $ClusterNodesObjColumnSize -FontSize 18 if ($ClusterMgmtObj) { Node ClusterAggrs @{Label = $ClusterMgmtObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } } else { - Write-PScriboMessage -IsWarning "Unable to create ClusterNodesObj. No Cluster Management Object found." + Write-PScriboMessage -IsWarning 'Unable to create ClusterNodesObj. No Cluster Management Object found.' } } } catch { diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeNetworkDiagram.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeNetworkDiagram.ps1 new file mode 100644 index 0000000..718c1f0 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeNetworkDiagram.ps1 @@ -0,0 +1,343 @@ +function Get-AbrOntapNodeNetworkDiagram { + <# + .SYNOPSIS + Used by As Built Report to built NetApp ONTAP node network diagram + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Generating Node Network Diagram for NetApp ONTAP.' + # Set the root path for icons + $RootPath = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + [System.IO.FileInfo]$IconPath = Join-Path $RootPath 'icons' + + # Used for DiagramDebug + if ($Options.EnableDiagramDebug) { + $EdgeDebug = @{style = 'filled'; color = 'red' } + $SubGraphDebug = @{style = 'dashed'; color = 'red' } + $NodeDebug = @{color = 'black'; style = 'red'; shape = 'plain' } + $NodeDebugEdge = @{color = 'black'; style = 'red'; shape = 'plain' } + $IconDebug = $true + } else { + $EdgeDebug = @{style = 'invis'; color = 'red' } + $SubGraphDebug = @{style = 'invis'; color = 'gray' } + $NodeDebug = @{color = 'transparent'; style = 'transparent'; shape = 'point' } + $NodeDebugEdge = @{color = 'transparent'; style = 'transparent'; shape = 'none' } + $IconDebug = $false + } + + if ($Options.DiagramTheme -eq 'Black') { + $Edgecolor = 'White' + $Fontcolor = 'White' + } elseif ($Options.DiagramTheme -eq 'Neon') { + $Edgecolor = 'gold2' + $Fontcolor = 'gold2' + } else { + $Edgecolor = '#71797E' + $Fontcolor = '#565656' + } + } + + process { + try { + $ClusterInfo = Get-NcCluster -Controller $Array + $NodeSum = Get-NcNode -Controller $Array + + try { + + $HAObject = @() + + $NodeAdditionalInfo = @() + $NetPortInfo = @() + $NetLifsInfo = @() + $NetVlanInfo = @() + + foreach ($Node in $NodeSum) { + $ClusterHa = Get-NcClusterHa -Node $Node.Node -Controller $Array + + $NodeMgmtAddress = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'node_mgmt' -and $_.HomeNode -eq $Node.Node } | Select-Object -ExpandProperty Address + + if ($ClusterHa.Name -notin $HAObject.Partner) { + $HAObject += [PSCustomObject][ordered]@{ + 'Name' = $ClusterHa.Name + 'Partner' = $ClusterHa.Partner + 'HAState' = $ClusterHa.State + } + } + + $NodeAdditionalInfo += [PSCustomObject][ordered]@{ + 'NodeName' = $Node.Node + 'AdditionalInfo' = [PSCustomObject][ordered]@{ + 'System Id' = $Node.NodeSystemId + 'Serial' = $Node.NodeSerialNumber + 'Model' = $Node.NodeModel + 'Mgmt' = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { + $true { 'Unknown' } + $false { $NodeMgmtAddress -join ', ' } + default { 'Unknown' } + } + } + } + + $NodePorts = Get-NcNetPort -Controller $Array | Where-Object { $_.Node -eq $Node.Node } + foreach ($NodePort in $NodePorts) { + $NetPortInfo += [PSCustomObject][ordered]@{ + 'NodeName' = $NodePort.Node + 'PortName' = $NodePort.Name + 'PortType' = $NodePort.PortType + 'IsParentVlan' = & { if (Get-NcNetPortVlan -Controller $Array -ParentInterface $NodePort.Name -Node $Node.Node) { $true } else { $false } } + 'AdditionalInfo' = [PSCustomObject][ordered]@{ + 'Health' = $NodePort.HealthStatus + 'Broadcast Domain' = switch ([string]::IsNullOrEmpty($NodePort.BroadcastDomain)) { + $true { 'Unknown' } + $false { $NodePort.BroadcastDomain } + default { 'Unknown' } + } + 'Ifgrp Port' = switch ([string]::IsNullOrEmpty($NodePort.IfgrpPort)) { + $true { 'None' } + $false { $NodePort.IfgrpPort } + default { 'Unknown' } + } + 'Ipspace' = $NodePort.IpSpace + 'Link Status' = switch ($NodePort.LinkStatus) { + 'up' { 'Up' } + 'down' { 'Down' } + default { 'Unknown' } + } + 'Mac' = $NodePort.MacAddress + 'Mtu' = $NodePort.Mtu + } + } + } + + $NodeLifs = Get-NcNetInterface -Controller $Array | Where-Object { $_.HomeNode -eq $Node.Node -and $_.DataProtocols -ne 'fcp' } + foreach ($NodeLif in $NodeLifs) { + $NetLifsInfo += [PSCustomObject][ordered]@{ + 'NodeName' = $NodeLif.HomeNode + 'InterfaceName' = $NodeLif.InterfaceName + 'HomeNode' = $NodeLif.HomeNode + 'HomePort' = $NodeLif.HomePort + 'CurrentNode' = $NodeLif.CurrentNode + 'CurrentPort' = $NodeLif.CurrentPort + 'AdditionalInfo' = [PSCustomObject][ordered]@{ + 'IP' = $NodeLif.Address + 'Netmask' = $NodeLif.Netmask + 'Is Home?' = switch ($NodeLif.IsHome) { + $true { 'Yes' } + $false { 'No' } + default { 'Unknown' } + } + 'Status' = switch ($NodeLif.AdministrativeStatus) { + 'up' { 'Up' } + 'down' { 'Down' } + default { 'Unknown' } + } + 'Role' = switch ([string]::IsNullOrEmpty($NodeLif.Role)) { + $true { 'Unknown' } + $false { $TextInfo.ToTitleCase($NodeLif.Role) } + default { 'Unknown' } + } + } + } + } + + $NodeVlans = Get-NcNetPortVlan -Node $Node.Node -Controller $Array + foreach ($NodeVlan in $NodeVlans) { + $NetVlanInfo += [PSCustomObject][ordered]@{ + 'NodeName' = $NodeVlan.Node + 'InterfaceName' = $NodeVlan.InterfaceName + 'ParentInterface' = $NodeVlan.ParentInterface + 'VlanID' = $NodeVlan.VlanID + } + } + } + + # Cluster Network Diagram + $ClusterNetwork = Add-NodeImage -Name 'ClusterSwitch1' -ImagesObj $Images -IconType 'Ontap_Cluster_Network' -IconDebug $IconDebug -TableBackgroundColor '#a1e3fd' + + Add-HtmlSubGraph -Name 'ClusterNetwork' -TableArray $ClusterNetwork -Label 'Cluster Network' -LabelPos top -ImagesObj $Images -IconDebug $IconDebug -NodeObject -TableBorder 1 -FontSize 20 -TableBorderColor '#71797E' -TableStyle 'rounded,dashed' -FontColor 'darkblue' -FontBold -FontName 'Segoe Ui Bold' -TableBackgroundColor '#a1e3fd' + + foreach ($Node in $NodeAdditionalInfo) { + + # Ontap System Node + Add-NodeIcon -Name $Node.NodeName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Node' -IconDebug $IconDebug -AditionalInfo $Node.AdditionalInfo -TableBorder 1 -FontSize 18 -NodeObject -TableBorderColor '#71797E' -TableStyle 'rounded,dashed' + + + if ($NetPortInfo) { + # Cluster Network Ports + $ClusterPortObj = @() + foreach ($Port in ($NetPortInfo | Where-Object { $_.Nodename -eq $Node.Nodename -and $_.AdditionalInfo.'Broadcast Domain' -eq 'Cluster' })) { + + $PerPortLifs = @() + foreach ($Lif in ($NetLifsInfo | Where-Object { $_.NodeName -eq $Node.Nodename -and $_.CurrentPort -eq $Port.PortName })) { + $PerPortLifs += if ($Lif.AdditionalInfo.'Is Home?' -eq 'Yes') { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 + } else { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 -TableBackgroundColor '#ffcccc' -CellBackgroundColor '#ffcccc' + } + } + + if (-not $PerPortLifs) { + $PerPortLifs = Add-NodeIcon -Name "$($Port.NodeName)_$($Port.PortName)_NoLifs" -LabelName 'No LIFs Assigned' -ImagesObj $Images -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -FontSize 12 -ImageSizePercent 50 -AditionalInfo @() -IconPath $IconPath + } + + if ($PerPortLifs.Count -eq 1) { $PerPortLifsColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $PerPortLifsColumnSize = $Options.DiagramColumnSize } else { $PerPortLifsColumnSize = $PerPortLifs.Count } + + $ClusterPortObj += Add-HtmlSubGraph -Name "$($Port.NodeName)$($Port.PortName)_Lifs" -TableArray $PerPortLifs -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -Label $Port.PortName -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -ColumnSize $PerPortLifsColumnSize + } + + if ($ClusterPortObj.Count -eq 1) { $ClusterPortObjColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $ClusterPortObjColumnSize = $Options.DiagramColumnSize } else { $ClusterPortObjColumnSize = $ClusterPortObj.Count } + + Add-HtmlSubGraph -Name "$($Port.NodeName)ClusterPorts" -TableArray $ClusterPortObj -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -IconType 'Ontap_Network_Port' -Label 'Cluster Network Ports' -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -ColumnSize $ClusterPortObjColumnSize -NodeObject + + Add-NodeEdge -From 'ClusterNetwork' -To "$($Port.NodeName)ClusterPorts" -EdgeColor $Edgecolor -EdgeStyle 'dashed' -EdgeThickness 1 -Arrowhead 'box' -Arrowtail 'box' -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 12 + + Add-NodeEdge -From "$($Port.NodeName)ClusterPorts" -To $Node.NodeName -EdgeColor $Edgecolor -EdgeStyle 'dashed' -EdgeThickness 1 -Arrowhead 'box' -Arrowtail 'box' -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 12 -EdgeLength 1 + + # Non-IFGRP Ports without Vlan Interfces + foreach ($Port in ($NetPortInfo | Where-Object { $_.Nodename -eq $Node.Nodename -and $_.AdditionalInfo.'Broadcast Domain' -ne 'Cluster' -and $_.AdditionalInfo.'Ifgrp Port' -in @('None', 'Unknown') -and $_.PortName -notmatch 'a0' -and $_.PortType -ne 'vlan' -and $_.IsParentVlan -eq $false })) { + $PerPortLifs = @() + foreach ($Lif in ($NetLifsInfo | Where-Object { $_.CurrentNode -eq $Node.Nodename -and $_.CurrentPort -eq $Port.PortName })) { + $PerPortLifs += if ($Lif.AdditionalInfo.'Is Home?' -eq 'Yes') { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 + } else { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 -TableBackgroundColor '#ffcccc' -CellBackgroundColor '#ffcccc' + } + } + + if (-not $PerPortLifs) { + $PerPortLifs = Add-NodeIcon -Name "$($Port.NodeName)_$($Port.PortName)_NoLifs" -LabelName 'No LIFs Assigned' -ImagesObj $Images -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -FontSize 12 -ImageSizePercent 50 -AditionalInfo @() -IconPath $IconPath + } + + if ($PerPortLifs.Count -eq 1) { $PerPortLifsColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $PerPortLifsColumnSize = $Options.DiagramColumnSize } else { $PerPortLifsColumnSize = $PerPortLifs.Count } + + Add-HtmlSubGraph -Name "$($Port.NodeName)$($Port.PortName)_Lifs" -TableArray $PerPortLifs -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -IconType 'Ontap_Network_Port' -Label $Port.PortName -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -NodeObject -ColumnSize $PerPortLifsColumnSize + + Add-NodeEdge -From $Node.NodeName -To "$($Port.NodeName)$($Port.PortName)_Lifs" -EdgeColor $Edgecolor -EdgeStyle 'dashed' -EdgeThickness 1 -Arrowhead 'box' -Arrowtail 'box' -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 12 -EdgeLength 1 + } + + # IFGRP Ports (Link Aggregation Groups) with member ports and LIFs + foreach ($IfgrpPort in ($NetPortInfo | Where-Object { $_.Nodename -eq $Node.Nodename -and $_.PortType -eq 'ifgrp' })) { + $IfgrpPortLifs = @() + foreach ($Lif in ($NetLifsInfo | Where-Object { $_.CurrentNode -eq $Node.Nodename -and $_.CurrentPort -eq $IfgrpPort.PortName })) { + $IfgrpPortLifs += if ($Lif.AdditionalInfo.'Is Home?' -eq 'Yes') { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 + } else { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 -TableBackgroundColor '#ffcccc' -CellBackgroundColor '#ffcccc' + } + } + + if (-not $IfgrpPortLifs) { + $IfgrpPortLifs = Add-NodeIcon -Name "$($IfgrpPort.NodeName)_$($IfgrpPort.PortName)_NoLifs" -LabelName 'No LIFs Assigned' -ImagesObj $Images -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -FontSize 12 -ImageSizePercent 50 -AditionalInfo @() -IconPath $IconPath + } + + if ($IfgrpPortLifs.Count -eq 1) { $IfgrpPortLifsColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $IfgrpPortLifsColumnSize = $Options.DiagramColumnSize } else { $IfgrpPortLifsColumnSize = $IfgrpPortLifs.Count } + + # Member physical ports of this IFGRP + $MemberPortItems = @() + foreach ($MemberPort in ($NetPortInfo | Where-Object { $_.Nodename -eq $Node.Nodename -and $_.AdditionalInfo.'Ifgrp Port' -eq $IfgrpPort.PortName })) { + $MemberPortItems += Add-NodeText -Name "$($MemberPort.NodeName)_$($MemberPort.PortName)_MemberPort" -Text $MemberPort.PortName -IconDebug $IconDebug -FontSize 12 + } + + $IfgrpPortObj = @() + if ($MemberPortItems) { + if ($MemberPortItems.Count -eq 1) { $MemberPortColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $MemberPortColumnSize = $Options.DiagramColumnSize } else { $MemberPortColumnSize = $MemberPortItems.Count } + $IfgrpPortObj += Add-HtmlSubGraph -Name "$($IfgrpPort.NodeName)$($IfgrpPort.PortName)_Members" -TableArray $MemberPortItems -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -Label 'Member Ports' -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -ColumnSize $MemberPortColumnSize + } + + $IfgrpPortObj += Add-HtmlSubGraph -Name "$($IfgrpPort.NodeName)$($IfgrpPort.PortName)_IfgrpLifs" -TableArray $IfgrpPortLifs -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -Label $IfgrpPort.PortName -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -ColumnSize $IfgrpPortLifsColumnSize + + # Child VLAN interfaces grouped under this IFGRP port + if ($NetVlanInfo) { + foreach ($VlanPort in ($NetVlanInfo | Where-Object { $_.NodeName -eq $Node.Nodename -and $_.ParentInterface -eq $IfgrpPort.PortName })) { + $IfgrpVlanLifs = @() + foreach ($Lif in ($NetLifsInfo | Where-Object { $_.CurrentNode -eq $Node.Nodename -and $_.CurrentPort -eq $VlanPort.InterfaceName })) { + $IfgrpVlanLifs += if ($Lif.AdditionalInfo.'Is Home?' -eq 'Yes') { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 + } else { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 -TableBackgroundColor '#ffcccc' -CellBackgroundColor '#ffcccc' + } + } + + if (-not $IfgrpVlanLifs) { + $IfgrpVlanLifs = Add-NodeIcon -Name "$($VlanPort.NodeName)_$($VlanPort.InterfaceName)_NoLifs" -LabelName 'No LIFs Assigned' -ImagesObj $Images -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -FontSize 12 -ImageSizePercent 50 -AditionalInfo @() -IconPath $IconPath + } + + if ($IfgrpVlanLifs.Count -eq 1) { $IfgrpVlanLifsColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $IfgrpVlanLifsColumnSize = $Options.DiagramColumnSize } else { $IfgrpVlanLifsColumnSize = $IfgrpVlanLifs.Count } + + $IfgrpPortObj += Add-HtmlSubGraph -Name "$($VlanPort.NodeName)$($VlanPort.InterfaceName)_VlanLifs" -TableArray $IfgrpVlanLifs -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -Label "$($VlanPort.InterfaceName) (VLAN $($VlanPort.VlanID))" -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -ColumnSize $IfgrpVlanLifsColumnSize + } + } + + if ($IfgrpPortObj.Count -eq 1) { $IfgrpPortObjColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $IfgrpPortObjColumnSize = $Options.DiagramColumnSize } else { $IfgrpPortObjColumnSize = $IfgrpPortObj.Count } + + Add-HtmlSubGraph -Name "$($IfgrpPort.NodeName)$($IfgrpPort.PortName)_Ifgrp" -TableArray $IfgrpPortObj -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -IconType 'Ontap_Network_Port' -Label "$($IfgrpPort.PortName) (IFGRP)" -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -NodeObject -ColumnSize $IfgrpPortObjColumnSize + + Add-NodeEdge -From $Node.NodeName -To "$($IfgrpPort.NodeName)$($IfgrpPort.PortName)_Ifgrp" -EdgeColor $Edgecolor -EdgeStyle 'dashed' -EdgeThickness 1 -Arrowhead 'box' -Arrowtail 'box' -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 12 -EdgeLength 1 + } + + # Physical Parent Ports with grouped Child VLAN Interfaces + if ($NetVlanInfo) { + foreach ($ParentPort in ($NetPortInfo | Where-Object { $_.Nodename -eq $Node.Nodename -and $_.IsParentVlan -eq $true -and $_.PortType -ne 'ifgrp' -and $_.AdditionalInfo.'Broadcast Domain' -ne 'Cluster' -and $_.AdditionalInfo.'Ifgrp Port' -in @('None', 'Unknown') })) { + $ChildVlanObjs = @() + foreach ($VlanPort in ($NetVlanInfo | Where-Object { $_.NodeName -eq $Node.Nodename -and $_.ParentInterface -eq $ParentPort.PortName })) { + $VlanPortLifs = @() + foreach ($Lif in ($NetLifsInfo | Where-Object { $_.CurrentNode -eq $Node.Nodename -and $_.CurrentPort -eq $VlanPort.InterfaceName })) { + $VlanPortLifs += if ($Lif.AdditionalInfo.'Is Home?' -eq 'Yes') { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 + } else { + Add-NodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 -TableBackgroundColor '#ffcccc' -CellBackgroundColor '#ffcccc' + } + } + + if (-not $VlanPortLifs) { + $VlanPortLifs = Add-NodeIcon -Name "$($VlanPort.NodeName)_$($VlanPort.InterfaceName)_NoLifs" -LabelName 'No LIFs Assigned' -ImagesObj $Images -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -FontSize 12 -ImageSizePercent 50 -AditionalInfo @() -IconPath $IconPath + } + + if ($VlanPortLifs.Count -eq 1) { $VlanPortLifsColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $VlanPortLifsColumnSize = $Options.DiagramColumnSize } else { $VlanPortLifsColumnSize = $VlanPortLifs.Count } + + $ChildVlanObjs += Add-HtmlSubGraph -Name "$($VlanPort.NodeName)$($VlanPort.InterfaceName)_VlanLifs" -TableArray $VlanPortLifs -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -Label "$($VlanPort.InterfaceName) (VLAN $($VlanPort.VlanID))" -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -ColumnSize $VlanPortLifsColumnSize + } + + if ($ChildVlanObjs) { + if ($ChildVlanObjs.Count -eq 1) { $ChildVlanColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $ChildVlanColumnSize = $Options.DiagramColumnSize } else { $ChildVlanColumnSize = $ChildVlanObjs.Count } + + Add-HtmlSubGraph -Name "$($ParentPort.NodeName)$($ParentPort.PortName)_ParentVlanPort" -TableArray $ChildVlanObjs -ImagesObj $Images -IconDebug $IconDebug -TableBorder 1 -IconType 'Ontap_Network_Port' -Label $ParentPort.PortName -LabelPos top -TableStyle 'rounded,dashed' -TableBorderColor '#71797E' -FontName 'Segoe Ui Bold' -NodeObject -ColumnSize $ChildVlanColumnSize + + Add-NodeEdge -From $Node.NodeName -To "$($ParentPort.NodeName)$($ParentPort.PortName)_ParentVlanPort" -EdgeColor $Edgecolor -EdgeStyle 'dashed' -EdgeThickness 1 -Arrowhead 'box' -Arrowtail 'box' -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 12 -EdgeLength 1 + } + } + } + } + } + + foreach ($HA in $HAObject) { + if ($HA.Partner) { + Add-NodeEdge -From $HA.Name -To $HA.Partner -EdgeColor $Edgecolor -EdgeStyle 'solid' -EdgeThickness 2 -Arrowhead 'box' -Arrowtail 'box' -EdgeLabel "HA: $($HA.HAState)" -EdgeLabelFontColor $Fontcolor -EdgeLabelFontSize 16 -EdgeLength 3 -TailPort $HA.Name -HeadPort $HA.Partner + Rank $HA.Name, $HA.Partner + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapNodeStorage.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeStorage.ps1 similarity index 65% rename from Src/Private/Get-AbrOntapNodeStorage.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeStorage.ps1 index af6f9ff..3f34217 100755 --- a/Src/Private/Get-AbrOntapNodeStorage.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodeStorage.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNodeStorage { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapNodeStorage { ) begin { - Write-PScriboMessage "Collecting ONTAP Node Storage information." + Write-PScriboMessage 'Collecting ONTAP Node Storage information.' } process { @@ -32,36 +32,34 @@ function Get-AbrOntapNodeStorage { $inObj = [ordered] @{ 'Node' = $Item.Vserver 'Aggregate' = $Item.Aggregate - 'Volume' = $Item.Name - 'Capacity' = $Item.Totalsize | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue - 'Available' = $Item.Available | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue - 'Used' = $Item.Used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue + 'Capacity' = ($Item.Totalsize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Available' = ($Item.Available | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Used' = ($Item.Used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Node.HW) { - $OutObj | Where-Object { $_.'Status' -like 'offline' } | Set-Style -Style Warning -Property 'Status' $OutObj | Where-Object { $_.'Used' -ge 90 } | Set-Style -Style Critical -Property 'Used' } $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)" } $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 + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all nodes are online and that storage usage is within acceptable limits.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapNodes.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodes.ps1 similarity index 80% rename from Src/Private/Get-AbrOntapNodes.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodes.ps1 index a4f5eeb..22496db 100755 --- a/Src/Private/Get-AbrOntapNodes.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodes.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNode { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,22 +19,24 @@ function Get-AbrOntapNode { ) begin { - Write-PScriboMessage "Collecting ONTAP node information." + Write-PScriboMessage 'Collecting ONTAP node information.' } process { 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/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodesHW.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodesHW.ps1 new file mode 100755 index 0000000..43e20bd --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodesHW.ps1 @@ -0,0 +1,83 @@ +function Get-AbrOntapNodesHW { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP system nodes hardware information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP Node Hardware information.' + } + + process { + try { + $NodeHW = Get-NcNodeInfo -Controller $Array -ErrorAction Continue + if ($NodeHW) { + $Outobj = @() + foreach ($NodeHWs in $NodeHW) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($NodeHWs.SystemName) { + try { + $NodeInfo = Get-NcNode -Node $NodeHWs.SystemName -Controller $Array + $Inobj = [ordered] @{ + 'System Type' = $NodeHWs.SystemMachineType + 'CPU Count' = $NodeHWs.NumberOfProcessors + 'Total Memory' = ("$($NodeHWs.MemorySize / 1024)GB") ?? '--' + 'Vendor' = $NodeHWs.VendorId + 'AFF/FAS' = $NodeHWs.ProdType + 'All Flash Optimized' = $NodeInfo.IsAllFlashOptimized + 'Cloud Optimized' = $NodeInfo.IsCloudOptimized + 'Epsilon' = $NodeInfo.IsEpsilonNode + 'System Healthy' = ($NodeInfo.IsNodeHealthy -eq $True) ? 'Healthy': 'UnHealthy' + 'Failed Fan Count' = $NodeInfo.EnvFailedFanCount + 'Failed Fan Error' = $NodeInfo.EnvFailedFanMessage + 'Failed PowerSupply Count' = $NodeInfo.EnvFailedPowerSupplyCount + 'Failed PowerSupply Error' = $NodeInfo.EnvFailedPowerSupplyMessage + 'Over Temperature' = ($NodeInfo.EnvOverTemperature -eq $True) ? 'High Temperature': 'Normal Temperature' + 'NVRAM Battery Healthy' = $NodeInfo.NvramBatteryStatus + } + $Outobj = [pscustomobject](ConvertTo-HashToYN $inObj) + + if ($Healthcheck.Node.HW) { + $Outobj | Where-Object { $_.'System Healthy' -like 'UnHealthy' } | Set-Style -Style Critical -Property 'System Healthy' + $Outobj | Where-Object { $_.'Failed Fan Count' -gt 0 } | Set-Style -Style Critical -Property 'Failed Fan Count' + $Outobj | Where-Object { $_.'Failed PowerSupply Count' -gt 0 } | Set-Style -Style Critical -Property 'Failed PowerSupply Count' + $Outobj | Where-Object { $_.'Over Temperature' -like 'High Temperature' } | Set-Style -Style Critical -Property 'Over Temperature' + $Outobj | Where-Object { $_.'NVRAM Battery Healthy' -notlike 'battery_ok' } | Set-Style -Style Critical -Property 'NVRAM Battery Healthy' + } + + $TableParams = @{ + Name = "Node Hardware - $($NodeHWs.SystemName)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $Outobj | Table @TableParams + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodesSP.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodesSP.ps1 new file mode 100755 index 0000000..ec2e360 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapNodesSP.ps1 @@ -0,0 +1,119 @@ +function Get-AbrOntapNodesSP { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP system nodes service-processor information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP Node Service-Processor information.' + } + + process { + try { + $ServiceProcessor = Get-NcServiceProcessor -Controller $Array + + # $ServiceProcessor = @( + # @{ + # 'Node' = 'cluster-01' + # 'Type' = 'BMC' + # 'IpAddress' = '192.168.0.1' + # 'MacAddress' = '00:02:23:24:43:AA' + # 'IsIpConfigured' = 'True' + # 'FirmwareVersion' = '8.1' + # 'Status' = 'Online' + # }, + # @{ + # 'Node' = 'cluster-02' + # 'Type' = 'BMC' + # 'IpAddress' = '192.168.0.2' + # 'MacAddress' = '00:02:23:24:43:AB' + # 'IsIpConfigured' = 'True' + # 'FirmwareVersion' = '8.1' + # 'Status' = 'Online' + # }, + # @{ + # 'Node' = 'cluster-03' + # 'Type' = 'BMC' + # 'IpAddress' = '192.168.0.2' + # 'MacAddress' = '00:02:23:24:43:AB' + # 'IsIpConfigured' = 'True' + # 'FirmwareVersion' = '8.1' + # 'Status' = 'Unknown' + # }, + # @{ + # 'Node' = 'cluster-04' + # 'Type' = 'BMC' + # 'IpAddress' = '' + # 'MacAddress' = '00:02:23:24:43:AB' + # 'IsIpConfigured' = 'False' + # 'FirmwareVersion' = '8.1' + # 'Status' = 'Offline' + # } + # ) + if ($ServiceProcessor) { + $SPObj = @() + foreach ($NodeSPs in $ServiceProcessor) { + try { + $inObj = [ordered] @{ + 'Name' = $NodeSPs.Node + 'Type' = $NodeSPs.Type + 'IP Address' = $NodeSPs.IpAddress + 'MAC Address' = $NodeSPs.MacAddress + 'Network Configured' = $NodeSPs.IsIpConfigured + 'Firmware' = $NodeSPs.FirmwareVersion + 'Status' = $NodeSPs.Status + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + + $SPObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } + if ($Healthcheck.Node.ServiceProcessor) { + $SPObj | Where-Object { $_.'Status' -like 'offline' -or $_.'Status' -like 'degraded' } | Set-Style -Style Critical -Property 'Status' + $SPObj | Where-Object { $_.'Status' -like 'unknown' -or $_.'Status' -like 'sp-daemon-offline' } | Set-Style -Style Warning -Property 'Status' + $SPObj | Where-Object { $_.'Network Configured' -eq 'No' } | Set-Style -Style Critical -Property 'Network Configured' + } + + $TableParams = @{ + Name = "Node Service-Processor - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 16, 11, 16, 20, 13, 12, 12 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $SPObj | Table @TableParams + if ($Healthcheck.Node.ServiceProcessor -and ($SPObj | Where-Object { $_.'Status' -in @('unknown', 'offline', 'degraded') -or $_.'Network Configured' -eq 'No' })) { + Paragraph 'Health Check:' -Bold -Underline + BlankLine + Paragraph { + Text 'Best Practice:' -Bold + Text 'Ensure that all service-processors are online, configured and functioning properly to maintain system management capabilities.' + } + BlankLine + } + } + + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapRepClusterPeer.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepClusterPeer.ps1 similarity index 84% rename from Src/Private/Get-AbrOntapRepClusterPeer.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepClusterPeer.ps1 index f4989dc..0aadaf9 100755 --- a/Src/Private/Get-AbrOntapRepClusterPeer.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepClusterPeer.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapRepClusterPeer { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapRepClusterPeer { ) begin { - Write-PScriboMessage "Collecting ONTAP Replication information." + Write-PScriboMessage 'Collecting ONTAP Replication information.' } process { @@ -37,7 +37,7 @@ function Get-AbrOntapRepClusterPeer { 'IP Space' = $Item.IpspaceName 'Status' = ($Item.Availability) } - $ReplicaObj += [pscustomobject]$inobj + $ReplicaObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -56,11 +56,11 @@ function Get-AbrOntapRepClusterPeer { } $ReplicaObj | Table @TableParams if ($Healthcheck.Replication.ClusterPeer -and ($ReplicaObj | Where-Object { $_.'Status' -notlike 'Available' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that all cluster peers are available to maintain replication integrity." + Text 'Best Practice:' -Bold + Text 'Ensure that all cluster peers are available to maintain replication integrity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapRepDestinations.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepDestinations.ps1 similarity index 80% rename from Src/Private/Get-AbrOntapRepDestinations.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepDestinations.ps1 index 58f942b..fc3d05c 100755 --- a/Src/Private/Get-AbrOntapRepDestinations.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepDestinations.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapRepDestination { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapRepDestination { ) begin { - Write-PScriboMessage "Collecting ONTAP SnapMirror Destination relationship information." + Write-PScriboMessage 'Collecting ONTAP SnapMirror Destination relationship information.' } process { @@ -46,15 +46,12 @@ function Get-AbrOntapRepDestination { default { $Item.RelationshipType } } 'Policy Type' = $Item.PolicyType - 'Status' = switch ($Item.RelationshipStatus) { - $Null { 'Unknown' } - default { $Item.RelationshipStatus } - } + 'Status' = ($Null -eq $Item.RelationshipStatus) ? 'Unknown': $Item.RelationshipStatus } - $ReplicaObj = [pscustomobject]$inobj + $ReplicaObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Replication.Relationship) { - $ReplicaObj | Where-Object { $_.'Status' -eq "Unknown" } | Set-Style -Style Warning -Property 'Status' + $ReplicaObj | Where-Object { $_.'Status' -eq 'Unknown' } | Set-Style -Style Warning -Property 'Status' } $TableParams = @{ @@ -66,12 +63,12 @@ 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 + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all SnapMirror relationships have a known status to maintain replication integrity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapRepHistory.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepHistory.ps1 similarity index 85% rename from Src/Private/Get-AbrOntapRepHistory.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepHistory.ps1 index 980c566..d8def2d 100755 --- a/Src/Private/Get-AbrOntapRepHistory.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepHistory.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapRepHistory { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapRepHistory { ) begin { - Write-PScriboMessage "Collecting ONTAP SnapMirror replication history information." + Write-PScriboMessage 'Collecting ONTAP SnapMirror replication history information.' } process { @@ -36,7 +36,7 @@ function Get-AbrOntapRepHistory { 'Result' = $Item.Result 'Start' = $Item.Start } - $ReplicaObj += [pscustomobject]$inobj + $ReplicaObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -55,11 +55,11 @@ function Get-AbrOntapRepHistory { } $ReplicaObj | Table @TableParams if ($Healthcheck.Replication.History -and ($ReplicaObj | Where-Object { $_.'Result' -ne 'success' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that all SnapMirror replication operations complete successfully to maintain data integrity." + Text 'Best Practice:' -Bold + Text 'Ensure that all SnapMirror replication operations complete successfully to maintain data integrity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapRepMediator.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepMediator.ps1 similarity index 68% rename from Src/Private/Get-AbrOntapRepMediator.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepMediator.ps1 index d815a33..5a92cad 100755 --- a/Src/Private/Get-AbrOntapRepMediator.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepMediator.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapRepMediator { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,12 +19,12 @@ function Get-AbrOntapRepMediator { ) begin { - Write-PScriboMessage "Collecting ONTAP SnapMirror Mediator relationship information." + Write-PScriboMessage 'Collecting ONTAP SnapMirror Mediator relationship information.' } process { try { - $ReplicaData = Get-NetAppOntapAPI -uri "/api/cluster/mediators?fields=*&return_records=true&return_timeout=15" + $ReplicaData = Get-NetAppOntapAPI -uri '/api/cluster/mediators?fields=*&return_records=true&return_timeout=15' $ReplicaObj = @() if ($ReplicaData) { foreach ($Item in $ReplicaData) { @@ -33,19 +33,15 @@ function Get-AbrOntapRepMediator { 'Peer cluster' = $Item.peer_cluster.name 'IP Address' = $Item.ip_address 'port' = $Item.port - 'Status' = switch ($Item.reachable) { - 'True' { 'Reachable' } - 'False' { 'Unreachable' } - default { $Item.reachable } - } + 'Status' = ($Item.reachable -eq $True) ? 'Reachable': 'Unreachable' } - $ReplicaObj += [pscustomobject]$inobj + $ReplicaObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Replication.Mediator) { - $ReplicaObj | Where-Object { $_.'Status' -eq "Unreachable" } | Set-Style -Style Critical -Property 'Status' + $ReplicaObj | Where-Object { $_.'Status' -eq 'Unreachable' } | Set-Style -Style Critical -Property 'Status' } $TableParams = @{ @@ -57,12 +53,12 @@ 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 + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all SnapMirror Mediator relationships are reachable to facilitate proper replication management.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapRepRelations.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepRelations.ps1 similarity index 66% rename from Src/Private/Get-AbrOntapRepRelations.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepRelations.ps1 index b67d4fc..f880bb3 100755 --- a/Src/Private/Get-AbrOntapRepRelations.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepRelations.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapRepRelationship { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapRepRelationship { ) begin { - Write-PScriboMessage "Collecting ONTAP SnapMirror relationship information." + Write-PScriboMessage 'Collecting ONTAP SnapMirror relationship information.' } process { @@ -30,19 +30,15 @@ function Get-AbrOntapRepRelationship { foreach ($Item in $ReplicaData) { try { $lag = [timespan]::fromseconds($Item.LagTime).tostring() - $time = $lag.Split(".").Split(":") - $lagtime = $time[0] + " days, " + $time[1] + " hrs, " + $time[2] + " mins, " + $time[0] + " secs" + $time = $lag.Split('.').Split(':') + $lagtime = $time[0] + ' days, ' + $time[1] + ' hrs, ' + $time[2] + ' mins, ' + $time[0] + ' secs' $inObj = [ordered] @{ 'Source Vserver' = $Item.SourceVserver 'Source Location' = $Item.SourceLocation 'Destination Vserver' = $Item.DestinationVserver 'Destination Location' = $Item.DestinationLocation 'Mirror State' = $Item.MirrorState - 'Schedule' = switch ([string]::IsNullOrEmpty($Item.Schedule)) { - $true { "None" } - $false { ($Item.Schedule).toUpper() } - default { "Unknown" } - } + 'Schedule' = ${Item}?.Schedule?.toUpper() 'Relationship Type' = switch ($Item.RelationshipType) { 'extended_data_protection' { 'XDP' } 'data_protection' { 'DP' } @@ -53,21 +49,14 @@ function Get-AbrOntapRepRelationship { } 'Policy' = $Item.Policy 'Policy Type' = $Item.PolicyType - 'Unhealthy Reason' = switch ($Item.UnhealthyReason) { - $NULL { "None" } - default { $Item.UnhealthyReason } - } + 'Unhealthy Reason' = ($Null -eq $Item.UnhealthyReason) ? 'None': $Item.UnhealthyReason 'Lag Time' = $lagtime - 'Status' = switch ([string]::IsNullOrEmpty($Item.Status)) { - $true { '--' } - $false { ($Item.Status).toUpper() } - default { 'Unknown' } - } + 'Status' = ${Item}?.Status?.toUpper() } - $ReplicaObj = [pscustomobject]$inobj + $ReplicaObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Replication.Relationship) { - $ReplicaObj | Where-Object { $_.'Unhealthy Reason' -ne "None" } | Set-Style -Style Warning -Property 'Unhealthy Reason' + $ReplicaObj | Where-Object { $_.'Unhealthy Reason' -ne 'None' } | Set-Style -Style Warning -Property 'Unhealthy Reason' } $TableParams = @{ @@ -79,12 +68,12 @@ 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 + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all SnapMirror relationships are healthy to maintain data replication integrity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapRepVserverPeer.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepVserverPeer.ps1 similarity index 88% rename from Src/Private/Get-AbrOntapRepVserverPeer.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepVserverPeer.ps1 index 9ee1ed9..76f7d37 100755 --- a/Src/Private/Get-AbrOntapRepVserverPeer.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapRepVserverPeer.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapRepVserverPeer { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapRepVserverPeer { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver Peer information." + Write-PScriboMessage 'Collecting ONTAP Vserver Peer information.' } process { @@ -36,7 +36,7 @@ function Get-AbrOntapRepVserverPeer { 'Applications' = $Item.Applications 'Peer State' = $Item.PeerState } - $ReplicaObj += [pscustomobject]$inobj + $ReplicaObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -55,10 +55,10 @@ function Get-AbrOntapRepVserverPeer { } $ReplicaObj | Table @TableParams if ($Healthcheck.Replication.VserverPeer -and ($ReplicaObj | Where-Object { $_.'Peer State' -notlike 'peered' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure that all Vserver Peer relationships are in 'peered' state to maintain proper data replication." } BlankLine diff --git a/Src/Private/Get-AbrOntapSecurityKMS.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMS.ps1 similarity index 88% rename from Src/Private/Get-AbrOntapSecurityKMS.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMS.ps1 index 4980d0e..1453007 100755 --- a/Src/Private/Get-AbrOntapSecurityKMS.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMS.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecurityKMS { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSecurityKMS { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Key Management Service information." + Write-PScriboMessage 'Collecting ONTAP Security Key Management Service information.' } process { @@ -34,7 +34,7 @@ function Get-AbrOntapSecurityKMS { 'Key Store' = $TextInfo.ToTitleCase($Item.KeyStore) 'Vserver' = $Item.Vserver } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecurityKMSExt.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMSExt.ps1 similarity index 89% rename from Src/Private/Get-AbrOntapSecurityKMSExt.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMSExt.ps1 index c772041..699473a 100755 --- a/Src/Private/Get-AbrOntapSecurityKMSExt.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMSExt.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecurityKMSExt { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSecurityKMSExt { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Key Management Service External information." + Write-PScriboMessage 'Collecting ONTAP Security Key Management Service External information.' } process { @@ -36,7 +36,7 @@ function Get-AbrOntapSecurityKMSExt { 'Timeout' = $Item.Timeout 'Vserver' = $Item.Vserver } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 similarity index 87% rename from Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 index a13772e..25582c9 100755 --- a/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecurityKMSExtStatus { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSecurityKMSExtStatus { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Key Management Service External Status information." + Write-PScriboMessage 'Collecting ONTAP Security Key Management Service External Status information.' } process { @@ -35,7 +35,7 @@ function Get-AbrOntapSecurityKMSExtStatus { 'Key Manager Port' = $Item.KeyManagerTcpPort 'Status' = $TextInfo.ToTitleCase($Item.KeyManagerServerStatus) } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -55,10 +55,10 @@ function Get-AbrOntapSecurityKMSExtStatus { } $OutObj | Table @TableParams if ($Healthcheck.Security.KMS -and ($OutObj | Where-Object { $_.'Status' -ne 'Available' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure that all External Key Management Services are in 'Available' status to maintain encryption functionality." } BlankLine diff --git a/Src/Private/Get-AbrOntapSecurityMAP.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityMAP.ps1 similarity index 63% rename from Src/Private/Get-AbrOntapSecurityMAP.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityMAP.ps1 index c4fd05c..999dd86 100755 --- a/Src/Private/Get-AbrOntapSecurityMAP.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityMAP.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecurityMAP { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,30 +19,22 @@ function Get-AbrOntapSecurityMAP { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Vserver Multi-Admin Approval information." + Write-PScriboMessage 'Collecting ONTAP Security Vserver Multi-Admin Approval information.' } process { try { - $Data = Get-NetAppOntapAPI -uri "/api/security/multi-admin-verify/approval-groups?fields=**&return_records=true&return_timeout=15" + $Data = Get-NetAppOntapAPI -uri '/api/security/multi-admin-verify/approval-groups?fields=**&return_records=true&return_timeout=15' $OutObj = @() if ($Data) { foreach ($Item in $Data) { try { $inObj = [ordered] @{ 'Name' = $Item.Name - 'Approvers' = Switch ([string]::IsNullOrEmpty($Item.Approvers)) { - $true { '-' } - $false { $Item.Approvers -join ', ' } - default { '-' } - } - 'Email' = Switch ([string]::IsNullOrEmpty($Item.Email)) { - $true { '-' } - $false { $Item.Email -join ', ' } - default { '-' } - } + 'Approvers' = $Item.Approvers -join ', ' + 'Email' = $Item.Email -join ', ' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecurityMAPRule.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityMAPRule.ps1 similarity index 64% rename from Src/Private/Get-AbrOntapSecurityMAPRule.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityMAPRule.ps1 index ce0329c..b380cc5 100755 --- a/Src/Private/Get-AbrOntapSecurityMAPRule.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityMAPRule.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecurityMAPRule { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,29 +19,25 @@ function Get-AbrOntapSecurityMAPRule { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Vserver Multi-Admin Approval rules information." + Write-PScriboMessage 'Collecting ONTAP Security Vserver Multi-Admin Approval rules information.' } process { try { - $Data = Get-NetAppOntapAPI -uri "/api/security/multi-admin-verify/rules?fields=**&return_records=true&return_timeout=15" + $Data = Get-NetAppOntapAPI -uri '/api/security/multi-admin-verify/rules?fields=**&return_records=true&return_timeout=15' $OutObj = @() if ($Data) { foreach ($Item in $Data) { try { $inObj = [ordered] @{ 'operation' = $Item.operation - 'query' = ConvertTo-EmptyToFiller $Item.query - 'Approval Groups' = Switch ([string]::IsNullOrEmpty($Item.approval_groups.name)) { - $true { '-' } - $false { $Item.approval_groups.name } - default { '-' } - } - 'Required Approvers' = ConvertTo-EmptyToFiller $Item.required_approvers - 'System Defined' = ConvertTo-TextYN $Item.system_defined + 'query' = $Item.query + 'Approval Groups' = $Item.approval_groups.name + 'Required Approvers' = $Item.required_approvers + 'System Defined' = $Item.system_defined } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecurityNAE.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityNAE.ps1 similarity index 75% rename from Src/Private/Get-AbrOntapSecurityNAE.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityNAE.ps1 index 8379cda..3fa21f8 100755 --- a/Src/Private/Get-AbrOntapSecurityNAE.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityNAE.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecurityNAE { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSecurityNAE { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Aggregate NAE information." + Write-PScriboMessage 'Collecting ONTAP Security Aggregate NAE information.' } process { @@ -29,19 +29,14 @@ function Get-AbrOntapSecurityNAE { if ($Data) { foreach ($Item in $Data) { try { - $NAE = try { (Get-NcAggrOption -Name $Item.Name -Controller $Array | Where-Object { $_.Name -eq "encrypt_with_aggr_key" }).Value } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } + $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) { - 'true' { 'Yes' } - 'false' { 'No' } - $Null { 'Unknown' } - default { $NAE } - } + 'Aggregate Encryption' = $NAE 'Volume Count' = $Item.Volumes 'State' = $TextInfo.ToTitleCase($Item.State) } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -60,10 +55,10 @@ function Get-AbrOntapSecurityNAE { } $OutObj | Table @TableParams if ($Healthcheck.Storage.Aggr -and ($OutObj | Where-Object { $_.'State' -ne 'Online' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure that all Aggregates are in 'Online' state to maintain optimal storage performance and client access availability." } BlankLine diff --git a/Src/Private/Get-AbrOntapSecurityNVE.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityNVE.ps1 similarity index 75% rename from Src/Private/Get-AbrOntapSecurityNVE.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityNVE.ps1 index 3615aec..a31c33d 100755 --- a/Src/Private/Get-AbrOntapSecurityNVE.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityNVE.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecurityNVE { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,12 +19,12 @@ function Get-AbrOntapSecurityNVE { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Volume NVE information." + Write-PScriboMessage 'Collecting ONTAP Security Volume NVE information.' } process { try { - $Data = Get-NcVol -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.VolumeStateAttributes.IsConstituent -ne "True" } | Select-Object -Property vserver, name, aggregate, state, @{Label = "Node"; expression = { $_.VolumeIdAttributes.Nodes } }, encrypt, @{Label = "encryptionstate"; expression = { (Get-NcVolumeEncryptionConversion -Vserver $_.vserver -Volume $_.name -Controller $Array).status } } + $Data = Get-NcVol -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.VolumeStateAttributes.IsConstituent -ne 'True' } | Select-Object -Property vserver, name, aggregate, state, @{Label = 'Node'; expression = { $_.VolumeIdAttributes.Nodes } }, encrypt, @{Label = 'encryptionstate'; expression = { (Get-NcVolumeEncryptionConversion -Vserver $_.vserver -Volume $_.name -Controller $Array).status } } $OutObj = @() if ($Data) { foreach ($Item in $Data) { @@ -32,10 +32,10 @@ function Get-AbrOntapSecurityNVE { $inObj = [ordered] @{ 'Name' = $Item.Name 'Aggregate' = $Item.Aggregate - 'Encrypted' = ConvertTo-TextYN $Item.Encrypt + 'Encrypted' = $Item.Encrypt 'State' = $TextInfo.ToTitleCase($Item.State) } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecuritySSLDetailed.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySSLDetailed.ps1 similarity index 75% rename from Src/Private/Get-AbrOntapSecuritySSLDetailed.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySSLDetailed.ps1 index f34bec7..b2af76a 100755 --- a/Src/Private/Get-AbrOntapSecuritySSLDetailed.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySSLDetailed.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecuritySSLDetailed { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,12 +19,12 @@ function Get-AbrOntapSecuritySSLDetailed { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Vserver SSL Detailed information." + Write-PScriboMessage 'Collecting ONTAP Security Vserver SSL Detailed information.' } process { try { - $Data = Get-NcSecurityCertificate -Controller $Array | Where-Object { $_.Type -eq "server" -and $_.Vserver -notin $Options.Exclude.Vserver } + $Data = Get-NcSecurityCertificate -Controller $Array | Where-Object { $_.Type -eq 'server' -and $_.Vserver -notin $Options.Exclude.Vserver } $OutObj = @() if ($Data) { foreach ($Item in $Data) { @@ -34,14 +34,10 @@ function Get-AbrOntapSecuritySSLDetailed { 'Protocol' = $Item.Protocol 'Hash Function' = $Item.HashFunction 'Serial Number' = $Item.SerialNumber - 'Expiration' = Switch ([string]::IsNullOrEmpty($Item.ExpirationDateDT)) { - $true { '-' } - $false { ($Item.ExpirationDateDT).ToString().Split(" ")[0] } - default { 'Unknown' } - } + 'Expiration' = ${Item}?.ExpirationDateDT?.ToString()?.Split(' ')[0] 'Vserver' = $Item.Vserver } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecuritySSLVserver.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySSLVserver.ps1 similarity index 83% rename from Src/Private/Get-AbrOntapSecuritySSLVserver.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySSLVserver.ps1 index 58b2a9d..e4d6c68 100755 --- a/Src/Private/Get-AbrOntapSecuritySSLVserver.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySSLVserver.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecuritySSLVserver { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSecuritySSLVserver { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Vserver SSL information." + Write-PScriboMessage 'Collecting ONTAP Security Vserver SSL information.' } process { @@ -32,12 +32,12 @@ function Get-AbrOntapSecuritySSLVserver { $inObj = [ordered] @{ 'Common Name' = $Item.CommonName 'Certificate Authority' = $Item.CertificateAuthority - 'Client Auth' = ConvertTo-TextYN $Item.ClientAuth - 'Server Auth' = ConvertTo-TextYN $Item.ServerAuth + 'Client Auth' = $Item.ClientAuth + 'Server Auth' = $Item.ServerAuth 'Serial Number' = $Item.CertificateSerialNumber 'Vserver' = $Item.Vserver } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecuritySnapLockAggr.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockAggr.ps1 similarity index 81% rename from Src/Private/Get-AbrOntapSecuritySnapLockAggr.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockAggr.ps1 index 3c52902..aa1a234 100755 --- a/Src/Private/Get-AbrOntapSecuritySnapLockAggr.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockAggr.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecuritySnapLockAggr { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSecuritySnapLockAggr { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Aggregate Snaplock Type information." + Write-PScriboMessage 'Collecting ONTAP Security Aggregate Snaplock Type information.' } process { @@ -29,12 +29,11 @@ function Get-AbrOntapSecuritySnapLockAggr { if ($Data) { foreach ($Item in $Data) { try { - $SnapLockType = Get-NcAggr $Item.Name -Controller $Array | Select-Object -ExpandProperty AggrSnaplockAttributes $inObj = [ordered] @{ 'Aggregate Name' = $Item.Name - 'Snaplock Type' = $TextInfo.ToTitleCase($SnapLockType.SnaplockType) + 'Snaplock Type' = $TextInfo.ToTitleCase((Get-NcAggr $Item.Name -Controller $Array | Select-Object -ExpandProperty AggrSnaplockAttributes).SnaplockType) } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecuritySnapLockClock.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockClock.ps1 similarity index 84% rename from Src/Private/Get-AbrOntapSecuritySnapLockClock.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockClock.ps1 index 2e5e159..847f8c5 100755 --- a/Src/Private/Get-AbrOntapSecuritySnapLockClock.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockClock.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecuritySnapLockClock { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSecuritySnapLockClock { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Snaplock compliance clock information." + Write-PScriboMessage 'Collecting ONTAP Security Snaplock compliance clock information.' } process { @@ -32,12 +32,12 @@ function Get-AbrOntapSecuritySnapLockClock { $SnapLockClock = Get-NcSnaplockComplianceClock $Item.Node -Controller $Array $inObj = [ordered] @{ 'Node Name' = $Item.Node - 'Compliance Clock' = Switch ($SnapLockClock.FormattedSnaplockComplianceClock) { + 'Compliance Clock' = switch (($SnapLockClock).FormattedSnaplockComplianceClock) { $Null { 'Uninitialized' } default { $SnapLockClock.FormattedSnaplockComplianceClock } } } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecuritySnapLockVol.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockVol.ps1 similarity index 82% rename from Src/Private/Get-AbrOntapSecuritySnapLockVol.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockVol.ps1 index 21459b8..c34cba4 100755 --- a/Src/Private/Get-AbrOntapSecuritySnapLockVol.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockVol.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecuritySnapLockVol { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSecuritySnapLockVol { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Volume Snaplock Type information." + Write-PScriboMessage 'Collecting ONTAP Security Volume Snaplock Type information.' } process { @@ -29,13 +29,12 @@ function Get-AbrOntapSecuritySnapLockVol { if ($Data) { foreach ($Item in $Data) { try { - $SnapLockType = Get-NcVol $Item.Name -Controller $Array | Select-Object -ExpandProperty VolumeSnaplockAttributes $inObj = [ordered] @{ 'Volume' = $Item.Name 'Aggregate' = $Item.Aggregate - 'Snaplock Type' = $TextInfo.ToTitleCase($SnapLockType.SnaplockType) + 'Snaplock Type' = $TextInfo.ToTitleCase((Get-NcVol $Item.Name -Controller $Array | Select-Object -ExpandProperty VolumeSnaplockAttributes).SnaplockType) } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSecuritySnapLockVollAttr.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockVollAttr.ps1 similarity index 81% rename from Src/Private/Get-AbrOntapSecuritySnapLockVollAttr.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockVollAttr.ps1 index dda9191..a55de44 100755 --- a/Src/Private/Get-AbrOntapSecuritySnapLockVollAttr.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecuritySnapLockVollAttr.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecuritySnapLockVollAttr { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,18 +19,18 @@ function Get-AbrOntapSecuritySnapLockVollAttr { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Snaplock volume attributes information." + Write-PScriboMessage 'Collecting ONTAP Security Snaplock volume attributes information.' } process { try { - $Data = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq "data" } - $VolumeFilter = Get-NcVol -Controller $Array | Where-Object { $_.VolumeSnaplockAttributes.SnaplockType -in "enterprise", "compliance" } + $Data = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq 'data' } + $VolumeFilter = Get-NcVol -Controller $Array | Where-Object { $_.VolumeSnaplockAttributes.SnaplockType -in 'enterprise', 'compliance' } $OutObj = @() if ($Data -and $VolumeFilter) { foreach ($Item in $Data) { try { - $VolumeFilter = Get-NcVol -VserverContext $Item.Vserver -Controller $Array | Where-Object { $_.VolumeSnaplockAttributes.SnaplockType -in "enterprise", "compliance" } + $VolumeFilter = Get-NcVol -VserverContext $Item.Vserver -Controller $Array | Where-Object { $_.VolumeSnaplockAttributes.SnaplockType -in 'enterprise', 'compliance' } foreach ($vol in $VolumeFilter) { $SnapLockVolAttr = Get-NcSnaplockVolAttr -Volume $vol.Name -VserverContext $Item.VserverName -Controller $Array $inObj = [ordered] @{ @@ -39,17 +39,14 @@ function Get-AbrOntapSecuritySnapLockVollAttr { 'Snaplock Type' = $TextInfo.ToTitleCase($SnapLockVolAttr.Type) 'Maximum Retention Period' = $SnapLockVolAttr.MaximumRetentionPeriod 'Minimum Retention Period' = $SnapLockVolAttr.MinimumRetentionPeriod - 'Privileged Delete State' = Switch ($SnapLockVolAttr.PrivilegedDeleteState) { - $Null { '-' } - default { $SnapLockVolAttr.PrivilegedDeleteState } - } + 'Privileged Delete State' = $SnapLockVolAttr.PrivilegedDeleteState 'Volume Expiry Time' = $SnapLockVolAttr.VolumeExpiryTime 'Volume Expiry Time Secs' = $SnapLockVolAttr.VolumeExpiryTimeSecs 'Auto Commit Period' = $SnapLockVolAttr.AutocommitPeriod 'Default Retention Period' = $SnapLockVolAttr.DefaultRetentionPeriod 'Litigation Count' = $SnapLockVolAttr.LitigationCount } - $OutObj = [pscustomobject]$inobj + $OutObj = [pscustomobject](ConvertTo-HashToYN $inObj) $TableParams = @{ Name = "Snaplock Volume Attributes - $($vol.Name)" diff --git a/Src/Private/Get-AbrOntapSecurityUsers.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityUsers.ps1 similarity index 77% rename from Src/Private/Get-AbrOntapSecurityUsers.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityUsers.ps1 index 22e2309..be2a554 100755 --- a/Src/Private/Get-AbrOntapSecurityUsers.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSecurityUsers.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSecurityUser { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapSecurityUser { ) begin { - Write-PScriboMessage "Collecting ONTAP Security Local Users information." + Write-PScriboMessage 'Collecting ONTAP Security Local Users information.' } process { @@ -38,15 +38,15 @@ function Get-AbrOntapSecurityUser { 'Application' = $TextInfo.ToTitleCase($Item.Application) 'Auth Method' = $Item.AuthMethod 'Role Name' = $Item.RoleName - 'Locked' = ConvertTo-TextYN $Item.IsLocked + 'Locked' = $Item.IsLocked } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Security.Users) { - $OutObj | Where-Object { $_.'Locked' -eq 'Yes' -and $_.'User Name' -ne "vsadmin" } | Set-Style -Style Warning -Property 'Locked' + $OutObj | Where-Object { $_.'Locked' -eq 'Yes' -and $_.'User Name' -ne 'vsadmin' } | Set-Style -Style Warning -Property 'Locked' } $TableParams = @{ @@ -58,12 +58,12 @@ 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 + 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." + 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 } diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageAGGR.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageAGGR.ps1 new file mode 100755 index 0000000..0da894f --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageAGGR.ps1 @@ -0,0 +1,230 @@ +function Get-AbrOntapStorageAGGR { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP storage summary information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP storage aggregate information.' + } + + process { + try { + try { + $ObjectData = Get-NcAggr -Controller $Array + if ($ObjectData) { + $ChartData = @() + $AggrName = @() + $ObjectDataInfo = @() + foreach ($Data in $ObjectData) { + try { + if (-not (Get-NcAggr -Name $Data.Name -Controller $Array).AggrRaidAttributes.IsRootAggregate) { + $AggrName += $Data.Name + $ChartData += , @([math]::Round((($Data.Totalsize - $Data.Available) / $Data.TotalSize * 100), 0), [math]::Round(($Data.Available / $Data.TotalSize) * 100, 0)) + } + $AggrOwner = (Get-NcAggr -Name $Data.Name ).AggrOwnershipAttributes + $inObj = [Ordered]@{ + 'Name' = $Data.Name + 'Home Nodes' = ${AggrOwner}?.HomeName ?? '--' + 'Owner Nodes' = ${AggrOwner}?.OwnerName ?? '--' + 'Capacity' = ($Data.Totalsize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = ($Data.Available | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = (($Data.Totalsize - $Data.Available ) | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Disk Count' = $Data.Disks + 'Root' = ((Get-NcAggr -Name $Data.Name -Controller $Array).AggrRaidAttributes.IsRootAggregate) ? 'Yes': 'No' + 'Raid Type' = (($Data.RaidType.Split(',')[0]).ToUpper()) ?? '--' + 'Raid Size' = $Data.RaidSize + 'Volumes in Aggregate' = $Data.Volumes + 'State' = $Data.State + } + $ObjectDataInfo += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + if ($Healthcheck.Storage.Aggr) { + $ObjectDataInfo | Where-Object { $_.'State' -eq 'failed' } | Set-Style -Style Critical -Property 'State' + $ObjectDataInfo | Where-Object { $_.'State' -eq 'unknown' -or $_.'State' -eq 'offline' } | Set-Style -Style Warning -Property 'State' + $ObjectDataInfo | Where-Object { $_.'Used' -ge 90 } | Set-Style -Style Critical -Property 'Used' + } + + if ($InfoLevel.Storage -ge 2) { + Paragraph "The following sections detail the storage aggregate configuration and health status in $($ClusterInfo.ClusterName)." + foreach ($Data in $ObjectDataInfo) { + Section -Style NOTOCHeading4 -ExcludeFromTOC "$($Data.Name)" { + $TableParams = @{ + Name = "Aggregates - $($Data.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $Data | Table @TableParams + if ($Healthcheck.Storage.Aggr -and (($Data | Where-Object { $_.'State' -eq 'failed' } ) -or ($Data | Where-Object { $_.'State' -eq 'unknown' -or $_.'State' -eq 'offline' }) -or ($Data | 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 + } + } + } + } else { + Paragraph "The following table summarises the aggregates in $($ClusterInfo.ClusterName)." + BlankLine + $TableParams = @{ + Name = "Aggregates - $($ClusterInfo.ClusterName)" + List = $false + Columns = 'Name', 'Capacity', 'Available', 'Used', 'Disk Count', 'Root', 'Raid Type', 'State' + ColumnWidths = 27, 10, 10, 10, 10, 8, 15, 10 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $ObjectDataInfo | Table @TableParams + if ($Healthcheck.Storage.Aggr -and (($ObjectDataInfo | Where-Object { $_.'State' -eq 'failed' } ) -or ($ObjectDataInfo | Where-Object { $_.'State' -eq 'unknown' -or $_.'State' -eq 'offline' }) -or ($ObjectDataInfo | 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 + } + } + $Chart = New-StackedBarChart -Values $ChartData -Labels $AggrName -LegendCategories @('Used', 'Free') -Title 'Aggregates Usage' -EnableLegend -LegendOrientation Horizontal -LegendAlignment UpperCenter -Width 600 -Height 600 -Format base64 -LabelYAxis '%' -LabelXAxis 'Aggregates' -TitleFontSize 20 -TitleFontBold -AreaOrientation Horizontal -EnableCustomColorPalette -CustomColorPalette @('#7b98bc', '#c0ddff') + if ($Chart) { + Section -Style NOTOCHeading4 -ExcludeFromTOC 'Aggragate Usage - Chart' { + Image -Text 'Aggragate Usage - Chart' -Align 'Center' -Percent 100 -Base64 $Chart + } + } + } + } catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) + } + try { + $AggrSpare = Get-NcAggrSpare -Controller $Array + if ($AggrSpare) { + Section -Style Heading4 'Disk Spares' { + $OutObj = @() + foreach ($Spare in $AggrSpare) { + try { + $inObj = [ordered] @{ + 'Name' = $Spare.Disk + 'Capacity' = ($Spare.TotalSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Root Usable' = ($Spare.LocalUsableRootSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Data Usable' = ($Spare.LocalUsableDataSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Shared Disk' = $Spare.IsDiskShared + 'Disk Zeroed' = $Spare.IsDiskZeroed + 'Owner' = $Spare.OriginalOwner + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + if ($Healthcheck.Storage.Aggr) { + $OutObj | Where-Object { $_.'Disk Zeroed' -eq 'No' } | Set-Style -Style Warning -Property 'Disk Zeroed' + } + $TableParams = @{ + Name = "Disk Spares - $($ClusterInfo.ClusterName)" + List = $false + ColumnWidths = 20, 12, 12, 12, 12, 12, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + try { + if ($InfoLevel.Storage -ge 2) { + Section -Style Heading4 'Per Aggregate Options' { + $Aggregates = Get-NcAggr -Controller $Array | Where-Object { !$_.AggrRaidAttributes.HasLocalRoot } + foreach ($Aggregate in $Aggregates) { + try { + Section -ExcludeFromTOC -Style NOTOCHeading5 "$($Aggregate.Name)" { + $OutObj = @() + $Options = Get-NcAggrOption -Controller $Array -Name $Aggregate.Name + $Option = @{} + $Options | ForEach-Object { $Option.add($_.Name, $_.Value) } + $inObj = [ordered] @{ + 'azcs_read_optimization' = $TextInfo.ToTitleCase($Option.azcs_read_optimization) + 'dir_holes' = $Option.dir_holes + 'dlog_hole_reserve' = $TextInfo.ToTitleCase($Option.dlog_hole_reserve) + 'enable_cold_data_reporting' = $Option.enable_cold_data_reporting + 'encrypt_with_aggr_key' = $Option.encrypt_with_aggr_key + 'free_space_realloc' = $TextInfo.ToTitleCase($Option.free_space_realloc) + 'fs_size_fixed' = $TextInfo.ToTitleCase($Option.fs_size_fixed) + 'ha_policy' = $TextInfo.ToTitleCase($Option.ha_policy) + 'hybrid_enabled' = $Option.hybrid_enabled + 'ignore_inconsistent' = $TextInfo.ToTitleCase($Option.ignore_inconsistent) + 'logical_space_enforcement' = $Option.logical_space_enforcement + 'logical_space_reporting' = $Option.logical_space_reporting + 'max_write_alloc_blocks' = $TextInfo.ToTitleCase($Option.max_write_alloc_blocks) + 'nearly_full_threshold' = $TextInfo.ToTitleCase($Option.nearly_full_threshold) + 'no_delete_log' = $TextInfo.ToTitleCase($Option.no_delete_log) + 'no_i2p' = $TextInfo.ToTitleCase($Option.no_i2p) + 'nosnap' = $TextInfo.ToTitleCase($Option.nosnap) + 'percent_snapshot_space' = $TextInfo.ToTitleCase($Option.percent_snapshot_space) + 'raid_cv' = $TextInfo.ToTitleCase($Option.raid_cv) + 'raid_lost_write' = $TextInfo.ToTitleCase($Option.raid_lost_write) + 'raidsize' = $TextInfo.ToTitleCase($Option.raidsize) + 'raidtype' = $TextInfo.ToTitleCase($Option.raidtype) + 'resyncsnaptime' = $TextInfo.ToTitleCase($Option.resyncsnaptime) + 'single_instance_data_logging' = $TextInfo.ToTitleCase($Option.single_instance_data_logging) + 'snapmirrored' = $TextInfo.ToTitleCase($Option.snapmirrored) + 'snapshot_autodelete' = $TextInfo.ToTitleCase($Option.snapshot_autodelete) + 'striping' = $TextInfo.ToTitleCase($Option.striping) + 'thorough_scrub' = $TextInfo.ToTitleCase($Option.thorough_scrub) + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + + $TableParams = @{ + Name = "Options - $($Aggregate.Name)" + List = $true + ColumnWidths = 50, 50 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapStorageFabricPool.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageFabricPool.ps1 similarity index 82% rename from Src/Private/Get-AbrOntapStorageFabricPool.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageFabricPool.ps1 index b05d8bf..60c087d 100755 --- a/Src/Private/Get-AbrOntapStorageFabricPool.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageFabricPool.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapStorageFabricPool { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapStorageFabricPool { ) begin { - Write-PScriboMessage "Collecting ONTAP Aggregate FabriPool information." + Write-PScriboMessage 'Collecting ONTAP Aggregate FabriPool information.' } process { @@ -34,10 +34,10 @@ function Get-AbrOntapStorageFabricPool { 'Aggregate' = $Item.Aggregate 'Fabric Pool Name' = $Item.ObjectStoreName 'Type' = $Item.ProviderType - 'Used Space' = $Item.UsedSpace | ConvertTo-FormattedNumber -Type Datasize -NumberFormatString "0.0" -ErrorAction SilentlyContinue + 'Used Space' = ($Item.UsedSpace | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize -NumberFormatString 0.0) ?? '--' 'Status' = $Item.ObjectStoreAvailability } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapStorageFabricPoolConfig.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageFabricPoolConfig.ps1 similarity index 79% rename from Src/Private/Get-AbrOntapStorageFabricPoolConfig.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageFabricPoolConfig.ps1 index efcec6f..50091e9 100755 --- a/Src/Private/Get-AbrOntapStorageFabricPoolConfig.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapStorageFabricPoolConfig.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapEfficiencyAggrConfig { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapEfficiencyAggrConfig { ) begin { - Write-PScriboMessage "Collecting ONTAP Aggregate FabriPool Object Store information." + Write-PScriboMessage 'Collecting ONTAP Aggregate FabriPool Object Store information.' } process { @@ -34,11 +34,11 @@ function Get-AbrOntapEfficiencyAggrConfig { 'S3 Name' = $Item.S3Name 'Server FQDN' = $Item.Server 'Port' = $Item.Port - 'SSL Enabled' = ConvertTo-TextYN $Item.SslEnabled + 'SSL Enabled' = $Item.SslEnabled 'Provider Type' = $Item.ProviderType - 'Used Space' = $Item.UsedSpace | ConvertTo-FormattedNumber -Type Datasize -NumberFormatString "0.0" -ErrorAction SilentlyContinue + 'Used Space' = ($Item.UsedSpace | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize -NumberFormatString 0.0) ?? '--' } - $OutObj = [pscustomobject]$inobj + $OutObj = [pscustomobject](ConvertTo-HashToYN $inObj) $TableParams = @{ Name = "Aggregate FabriPool Object Store Configuration - $($Item.ObjectStoreName)" diff --git a/Src/Private/Get-AbrOntapSysConfigBackup.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigBackup.ps1 similarity index 79% rename from Src/Private/Get-AbrOntapSysConfigBackup.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigBackup.ps1 index e8d515a..1c4af77 100755 --- a/Src/Private/Get-AbrOntapSysConfigBackup.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigBackup.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigBackup { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapSysConfigBackup { ) begin { - Write-PScriboMessage "Collecting ONTAP System Configuration Backups information." + Write-PScriboMessage 'Collecting ONTAP System Configuration Backups information.' } process { @@ -36,11 +36,11 @@ function Get-AbrOntapSysConfigBackup { $inObj = [ordered] @{ 'Backup Name' = $Item.BackupName 'Created' = $Item.Created - 'Size' = $Item.BackupSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Size' = ($Item.BackupSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' 'Schedule' = $Item.Schedule - 'Is Auto' = ConvertTo-TextYN $Item.IsAuto + 'Is Auto' = $Item.IsAuto } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 similarity index 72% rename from Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 index 3cbd415..fd004d7 100755 --- a/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigBackupURL { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigBackupURL { ) begin { - Write-PScriboMessage "Collecting ONTAP System Configuration Backup Setting information." + Write-PScriboMessage 'Collecting ONTAP System Configuration Backup Setting information.' } process { @@ -30,16 +30,10 @@ function Get-AbrOntapSysConfigBackupURL { foreach ($Item in $Data) { try { $inObj = [ordered] @{ - 'Url' = switch ($Item.Url) { - $Null { 'Not Configured' } - default { $Item.Url } - } - 'Username' = switch ($Item.Username) { - $Null { 'Not Configured' } - default { $Item.Username } - } + 'Url' = ($Null -eq $Item.Url) ? 'Not Configured': $Item.Url + 'Username' = ($Null -eq $Item.Username) ? 'Not Configured': $Item.Username } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -60,11 +54,11 @@ function Get-AbrOntapSysConfigBackupURL { } $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 + 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." + 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 } diff --git a/Src/Private/Get-AbrOntapSysConfigDNS.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigDNS.ps1 similarity index 83% rename from Src/Private/Get-AbrOntapSysConfigDNS.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigDNS.ps1 index 908be39..90c718e 100755 --- a/Src/Private/Get-AbrOntapSysConfigDNS.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigDNS.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigDNS { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigDNS { ) begin { - Write-PScriboMessage "Collecting ONTAP System DNS Configuration information." + Write-PScriboMessage 'Collecting ONTAP System DNS Configuration information.' } process { @@ -36,7 +36,7 @@ function Get-AbrOntapSysConfigDNS { 'Name Servers' = $Item.NameServers 'Timeout/s' = $Item.Timeout } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -57,19 +57,19 @@ function Get-AbrOntapSysConfigDNS { } $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 + 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." + 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." + Text 'Best Practice:' -Bold + Text 'It is recommended to configure at least two DNS name servers for redundancy and reliability.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapSysConfigEMS.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigEMS.ps1 similarity index 82% rename from Src/Private/Get-AbrOntapSysConfigEMS.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigEMS.ps1 index b1bf68e..98de35b 100755 --- a/Src/Private/Get-AbrOntapSysConfigEMS.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigEMS.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigEMS { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,12 +23,12 @@ function Get-AbrOntapSysConfigEMS { ) begin { - Write-PScriboMessage "Collecting ONTAP System EMS Messages information." + Write-PScriboMessage 'Collecting ONTAP System EMS Messages information.' } process { try { - $Data = Get-NcEmsMessage -Node $Node -Severity "emergency", "alert" -Controller $Array | Select-Object -First 30 + $Data = Get-NcEmsMessage -Node $Node -Severity 'emergency', 'alert' -Controller $Array | Select-Object -First 30 $OutObj = @() if ($Data) { foreach ($Item in $Data) { @@ -38,7 +38,7 @@ function Get-AbrOntapSysConfigEMS { 'Severity' = $Item.Severity 'Event' = $Item.Event } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 similarity index 68% rename from Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 index 085490d..6d0ad43 100755 --- a/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigEMSSetting { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigEMSSetting { ) begin { - Write-PScriboMessage "Collecting ONTAP System EMS Settings information." + Write-PScriboMessage 'Collecting ONTAP System EMS Settings information.' } process { @@ -31,33 +31,22 @@ function Get-AbrOntapSysConfigEMSSetting { try { $inObj = [ordered] @{ 'Name' = $Item.Name - 'Email Destinations' = switch ($Item.Mail) { - $Null { '-' } - default { $Item.Mail } - } - 'Snmp Traphost' = switch ($Item.Snmp) { - $Null { '-' } - default { $Item.Snmp } - } - 'Snmp Community' = switch ($Item.SnmpCommunity) { - $Null { '-' } - default { $Item.SnmpCommunity } - } - 'Syslog' = switch ($Item.Syslog) { - $Null { '-' } - default { $Item.Syslog } - } - 'Syslog Facility' = switch ($Item.SyslogFacility) { - $Null { '-' } - default { $Item.SyslogFacility } - } + 'Email Destinations' = $Item.Mail + 'Snmp Traphost' = $Item.Snmp + 'Snmp Community' = $Item.SnmpCommunity + 'Syslog' = $Item.Syslog + 'Syslog Facility' = $Item.SyslogFacility } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } + if ($Healthcheck.System.EMS) { + $OutObj | Where-Object { $_.'Email Destinations' -eq '--' -or $_.'Snmp Traphost' -eq '--' -or $_.'Syslog' -eq '--' } | Set-Style -Style Warning + } + $TableParams = @{ Name = "EMS Configuration Setting - $($ClusterInfo.ClusterName)" List = $false @@ -67,12 +56,12 @@ 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 + 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." + 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 } @@ -83,18 +72,18 @@ function Get-AbrOntapSysConfigEMSSetting { try { $Data = Get-NcAudit -Controller $Array if ($Data) { - Section -Style Heading4 "Audit Settings" { + Section -Style Heading4 'Audit Settings' { Paragraph "The following section provides information about Audit Setting from $($ClusterInfo.ClusterName)." BlankLine $OutObj = @() foreach ($Item in $Data) { try { $inObj = [ordered] @{ - 'Enable HTTP Get request' = ConvertTo-TextYN $Item.HttpGet - 'Enable ONTAPI Get request' = ConvertTo-TextYN $Item.OntapiGet - 'Enable CLI Get request' = ConvertTo-TextYN $Item.CliGet + 'Enable HTTP Get request' = $Item.HttpGet + 'Enable ONTAPI Get request' = $Item.OntapiGet + 'Enable CLI Get request' = $Item.CliGet } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -112,7 +101,7 @@ function Get-AbrOntapSysConfigEMSSetting { try { $Data = Get-NcClusterLogForward -Controller $Array if ($Data) { - Section -Style Heading4 "Audit Log Destinations" { + Section -Style Heading4 'Audit Log Destinations' { $OutObj = @() foreach ($Item in $Data) { try { @@ -121,9 +110,9 @@ function Get-AbrOntapSysConfigEMSSetting { 'Facility' = $Item.Facility 'Port' = $Item.Port 'Protocol' = $Item.Protocol - 'Server Verification' = ConvertTo-TextYN $Item.VerifyServerSpecified + 'Server Verification' = $Item.VerifyServerSpecified } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSysConfigImage.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigImage.ps1 similarity index 83% rename from Src/Private/Get-AbrOntapSysConfigImage.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigImage.ps1 index 25e2347..8fd901c 100755 --- a/Src/Private/Get-AbrOntapSysConfigImage.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigImage.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigImage { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigImage { ) begin { - Write-PScriboMessage "Collecting ONTAP System Image information." + Write-PScriboMessage 'Collecting ONTAP System Image information.' } process { @@ -32,12 +32,12 @@ function Get-AbrOntapSysConfigImage { $inObj = [ordered] @{ 'Node' = $Item.Node 'Location' = $Item.Image - 'Is Current' = ConvertTo-TextYN $Item.IsCurrent - 'Is Default' = ConvertTo-TextYN $Item.IsDefault + 'Is Current' = $Item.IsCurrent + 'Is Default' = $Item.IsDefault 'Install Time' = $Item.InstallTimeDT 'Version' = $Item.Version } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSysConfigNTP.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigNTP.ps1 similarity index 66% rename from Src/Private/Get-AbrOntapSysConfigNTP.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigNTP.ps1 index d4a7bd4..dea13fa 100755 --- a/Src/Private/Get-AbrOntapSysConfigNTP.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigNTP.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigNTP { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigNTP { ) begin { - Write-PScriboMessage "Collecting ONTAP System NTP information." + Write-PScriboMessage 'Collecting ONTAP System NTP information.' } process { @@ -32,15 +32,19 @@ function Get-AbrOntapSysConfigNTP { $inObj = [ordered] @{ 'Server Name' = $Item.ServerName 'NTP Version' = $TextInfo.ToTitleCase($Item.Version) - 'Preferred' = ConvertTo-TextYN $Item.IsPreferred - 'Authentication Enabled' = ConvertTo-TextYN $Item.IsAuthenticationEnabled + 'Preferred' = $Item.IsPreferred + 'Authentication Enabled' = $Item.IsAuthenticationEnabled } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } + if ($Healthcheck.System.NTP -and $OutObj.Count -eq 1) { + $OutObj | Set-Style -Style Warning + } + $TableParams = @{ Name = "Network Time Protocol - $($ClusterInfo.ClusterName)" List = $false @@ -50,6 +54,15 @@ function Get-AbrOntapSysConfigNTP { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Table @TableParams + if ($Healthcheck.System.NTP -and ($OutObj.Count -eq 1)) { + Paragraph 'Health Check:' -Bold -Underline + BlankLine + Paragraph { + Text 'Best Practice:' -Bold + Text 'It is recommended to configure multiple NTP servers for redundancy and reliability.' + } + BlankLine + } } else { $inObj = [ordered] @{ 'Server Name' = 'No NTP Servers Configured' @@ -57,7 +70,7 @@ function Get-AbrOntapSysConfigNTP { 'Preferred' = 'N/A' 'Authentication Enabled' = 'N/A' } - $OutObj = [pscustomobject]$inObj + $OutObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.System.NTP) { $OutObj | Set-Style -Style Warning @@ -73,11 +86,11 @@ function Get-AbrOntapSysConfigNTP { } $OutObj | Table @TableParams - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Configure at least one NTP server to ensure accurate time synchronization across the cluster.' } BlankLine diff --git a/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 similarity index 76% rename from Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 index 4a3b5e1..8695606 100755 --- a/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigNTPHost { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigNTPHost { ) begin { - Write-PScriboMessage "Collecting ONTAP System NTP Host Status information." + Write-PScriboMessage 'Collecting ONTAP System NTP Host Status information.' } process { @@ -34,13 +34,9 @@ function Get-AbrOntapSysConfigNTPHost { 'Time Offset' = $Item.Offset 'Selection State' = $Item.SelectionState 'Server' = $Item.Server - 'Peer Status' = switch ($Item.IsPeerReachable) { - 'True' { 'Reachable' } - 'False' { 'Unreachable' } - default { $Item.IsPeerReachable } - } + 'Peer Status' = ($Item.IsPeerReachable -eq $True) ? 'Reachable': 'Unreachable' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -59,11 +55,11 @@ function Get-AbrOntapSysConfigNTPHost { } $OutObj | Table @TableParams if ($Healthcheck.System.NTP -and ($OutObj | Where-Object { $_.'Peer Status' -notlike 'Reachable' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all configured NTP servers are reachable to maintain accurate time synchronization across the cluster.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 similarity index 77% rename from Src/Private/Get-AbrOntapSysConfigSNMP.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 index eb7fe3f..df9ff94 100755 --- a/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigSNMP { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigSNMP { ) begin { - Write-PScriboMessage "Collecting ONTAP System SNMP Configuration information." + Write-PScriboMessage 'Collecting ONTAP System SNMP Configuration information.' } process { @@ -34,13 +34,9 @@ function Get-AbrOntapSysConfigSNMP { 'Location' = $Item.Location 'Communities' = $Item.Communities 'Traphosts' = $Item.Traphosts - 'Status' = Switch ($Item.IsTrapEnabled) { - 'True' { 'Enabled' } - 'False' { 'Disabled' } - default { $Item.IsTrapEnabled } - } + 'Status' = $Item.IsTrapEnabled -eq $True ? 'Enabled': 'Disabled' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSysConfigTZ.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigTZ.ps1 similarity index 80% rename from Src/Private/Get-AbrOntapSysConfigTZ.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigTZ.ps1 index b58f82a..42d8759 100755 --- a/Src/Private/Get-AbrOntapSysConfigTZ.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigTZ.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigTZ { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigTZ { ) begin { - Write-PScriboMessage "Collecting ONTAP System TimeZone information." + Write-PScriboMessage 'Collecting ONTAP System TimeZone information.' } process { @@ -29,15 +29,13 @@ function Get-AbrOntapSysConfigTZ { if ($Data) { foreach ($Item in $Data) { try { - $Time = (Get-NcTime -Controller $Array).UtcTime[0] - $CurrentTime = Get-UnixDate($Time) $inObj = [ordered] @{ 'Timezone' = $Item.Timezone 'Timezone UTC' = $Item.TimezoneUtc 'Timezone Version' = $Item.TimezoneVersion - 'Current Time' = $CurrentTime + 'Current Time' = ([timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds((Get-NcTime -Controller $Array).UtcTime[0]))) ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 similarity index 81% rename from Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 index f6e9ee8..52f3227 100755 --- a/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapSysConfigWebStatus { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapSysConfigWebStatus { ) begin { - Write-PScriboMessage "Collecting ONTAP System Web Service information." + Write-PScriboMessage 'Collecting ONTAP System Web Service information.' } process { @@ -31,14 +31,14 @@ function Get-AbrOntapSysConfigWebStatus { try { $inObj = [ordered] @{ 'Node' = $Item.Node - 'Http Enabled' = ConvertTo-TextYN $Item.HttpEnabled + 'Http Enabled' = $Item.HttpEnabled 'Http Port' = $Item.HttpPort 'Https Port' = $Item.HttpsPort - 'External' = ConvertTo-TextYN $Item.External + 'External' = $Item.External 'Status' = $TextInfo.ToTitleCase($Item.Status) 'Status Code' = $Item.StatusCode } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -59,11 +59,11 @@ function Get-AbrOntapSysConfigWebStatus { } $OutObj | Table @TableParams if ($Healthcheck.System.Web -and (($OutObj | Where-Object { $_.'Http Enabled' -eq 'Yes' }))) { - Paragraph "Health Check:" -Bold -Underline + 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." + 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 } diff --git a/Src/Private/Get-AbrOntapVserverCGLun.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGLun.ps1 similarity index 65% rename from Src/Private/Get-AbrOntapVserverCGLun.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGLun.ps1 index ca307e9..2472c35 100755 --- a/Src/Private/Get-AbrOntapVserverCGLun.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGLun.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCGLun { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -22,7 +22,7 @@ function Get-AbrOntapVserverCGLun { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver Consistency Groups lun information." + Write-PScriboMessage 'Collecting ONTAP Vserver Consistency Groups lun information.' } process { @@ -34,25 +34,17 @@ function Get-AbrOntapVserverCGLun { try { $inObj = [ordered] @{ 'Name' = $Item.Name.Split('/')[3] - '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)) { - $true { '-' } - $false { $Item.space.used | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } - default { '-' } - } - 'OS Type' = ConvertTo-EmptyToFiller $Item.os_type + 'Capacity' = ($Item.space.size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.space.used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'OS Type' = $Item.os_type 'Volume State' = $Item.status.container_state - 'Mapped' = ConvertTo-TextYN $Item.status.mapped - 'Read Only' = ConvertTo-TextYN $Item.status.read_only + 'Mapped' = $Item.status.mapped + 'Read Only' = $Item.status.read_only 'State' = $Item.status.state } - $CGLunObj += [pscustomobject]$inobj + $CGLunObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -75,11 +67,11 @@ function Get-AbrOntapVserverCGLun { } $CGLunObj | Sort-Object -Property Name | Table @TableParams if ($Healthcheck.Vserver.CG -and ($CGLunObj | Where-Object { $_.'State' -eq 'offline' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all LUNs within the Consistency Group are online to maintain data availability and integrity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 similarity index 66% rename from Src/Private/Get-AbrOntapVserverCGNamespace.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 index 1989c4b..c19e611 100755 --- a/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCGNamespace { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -22,7 +22,7 @@ function Get-AbrOntapVserverCGNamespace { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver Consistency Groups namespace information." + Write-PScriboMessage 'Collecting ONTAP Vserver Consistency Groups namespace information.' } process { @@ -34,25 +34,17 @@ function Get-AbrOntapVserverCGNamespace { try { $inObj = [ordered] @{ 'Name' = $Item.Name.Split('/')[3] - '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)) { - $true { '-' } - $false { $Item.space.used | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } - default { '-' } - } - 'OS Type' = ConvertTo-EmptyToFiller $Item.os_type + 'Capacity' = ($Item.space.size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.space.used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'OS Type' = $Item.os_type 'Volume State' = $Item.status.container_state - 'Mapped' = ConvertTo-TextYN $Item.status.mapped - 'Read Only' = ConvertTo-TextYN $Item.status.read_only + 'Mapped' = $Item.status.mapped + 'Read Only' = $Item.status.read_only 'State' = $Item.status.state } - $CGNamespaceObj += [pscustomobject]$inobj + $CGNamespaceObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -75,11 +67,11 @@ function Get-AbrOntapVserverCGNamespace { } $CGNamespaceObj | Sort-Object -Property Name | Table @TableParams if ($Healthcheck.Vserver.CG -and ($CGNamespaceObj | Where-Object { $_.'State' -eq 'offline' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all namespaces within the Consistency Group are online to maintain data availability and integrity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverCGSummary.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGSummary.ps1 similarity index 50% rename from Src/Private/Get-AbrOntapVserverCGSummary.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGSummary.ps1 index 597232d..9ec9b78 100755 --- a/Src/Private/Get-AbrOntapVserverCGSummary.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCGSummary.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCGSummary { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCGSummary { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver Consistency Groups information." + Write-PScriboMessage 'Collecting ONTAP Vserver Consistency Groups information.' } process { @@ -35,29 +35,13 @@ function Get-AbrOntapVserverCGSummary { try { $inObj = [ordered] @{ 'Name' = $Item.Name - 'Capacity' = Switch ([string]::IsNullOrEmpty($Item.space.size)) { - $true { '-' } - $false { $Item.space.size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } - default { '-' } - } - 'Available' = Switch ([string]::IsNullOrEmpty($Item.space.available)) { - $true { '-' } - $false { $Item.space.available | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } - default { '-' } - } - 'Used' = Switch ([string]::IsNullOrEmpty($Item.space.used)) { - $true { '-' } - $false { $Item.space.used | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } - default { '-' } - } - 'Replicated' = ConvertTo-TextYN $Item.replicated - 'Lun Count' = Switch ([string]::IsNullOrEmpty($Item.luns.name)) { - $true { '-' } - $false { ($Item.luns.name).count } - default { '-' } - } + 'Capacity' = ($Item.space.size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = ($Item.space.available | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.space.used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Replicated' = $Item.replicated + 'Lun Count' = ($Item.luns.name).count } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverCIFSDC.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSDC.ps1 similarity index 89% rename from Src/Private/Get-AbrOntapVserverCIFSDC.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSDC.ps1 index 2136918..b8166d4 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSDC.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSDC.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSDC { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSDC { ) begin { - Write-PScriboMessage "Collecting ONTAP CIFS Domain Controller Properties information." + Write-PScriboMessage 'Collecting ONTAP CIFS Domain Controller Properties information.' } process { @@ -41,7 +41,7 @@ function Get-AbrOntapVserverCIFSDC { 'Prefer Type' = $Item.PreferType 'Status' = $Item.Status } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverCIFSLGMembers.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSLGMembers.ps1 similarity index 89% rename from Src/Private/Get-AbrOntapVserverCIFSLGMembers.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSLGMembers.ps1 index 73e02db..82c8daf 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSLGMembers.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSLGMembers.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSLGMember { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSLGMember { ) begin { - Write-PScriboMessage "Collecting ONTAP CIFS Local Group Members information." + Write-PScriboMessage 'Collecting ONTAP CIFS Local Group Members information.' } process { @@ -37,7 +37,7 @@ function Get-AbrOntapVserverCIFSLGMember { 'Group Name' = $Item.GroupName 'Description' = $Item.Member } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverCIFSLocalGroup.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSLocalGroup.ps1 similarity index 89% rename from Src/Private/Get-AbrOntapVserverCIFSLocalGroup.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSLocalGroup.ps1 index 70350fd..df6a837 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSLocalGroup.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSLocalGroup.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSLocalGroup { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSLocalGroup { ) begin { - Write-PScriboMessage "Collecting ONTAP CIFS Local Group information." + Write-PScriboMessage 'Collecting ONTAP CIFS Local Group information.' } process { @@ -37,7 +37,7 @@ function Get-AbrOntapVserverCIFSLocalGroup { 'Group Name' = $Item.GroupName 'Description' = $Item.Description } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverCIFSOptions.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSOptions.ps1 similarity index 64% rename from Src/Private/Get-AbrOntapVserverCIFSOptions.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSOptions.ps1 index 5a1d499..51517f5 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSOptions.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSOptions.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSOption { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSOption { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver CIFS Option information." + Write-PScriboMessage 'Collecting ONTAP Vserver CIFS Option information.' } process { @@ -33,29 +33,29 @@ function Get-AbrOntapVserverCIFSOption { if ($VserverData) { foreach ($SVM in $VserverData) { try { - $CIFSSVM = Get-NcCifsOption -VserverContext $SVM.Vserver -Controller $Array + $CIFSSVM = Get-NcCifsOption -VserverContext $SVM -Controller $Array foreach ($Item in $CIFSSVM) { try { $inObj = [ordered] @{ 'Client Session Timeout' = $Item.ClientSessionTimeout 'Default Unix User' = $Item.DefaultUnixUser - 'Client Version Reporting Enabled' = ConvertTo-TextYN $Item.IsClientVersionReportingEnabled - 'Copy Offload Direct Copy Enabled' = ConvertTo-TextYN $Item.IsCopyOffloadDirectCopyEnabled - 'Copy Offload Enabled' = ConvertTo-TextYN $Item.IsCopyOffloadEnabled - 'Dac Enabled' = ConvertTo-TextYN $Item.IsDacEnabled - 'Export Policy Enabled' = ConvertTo-TextYN $Item.IsExportpolicyEnabled - 'Large MTU Enabled' = ConvertTo-TextYN $Item.IsLargeMtuEnabled - 'Local Auth Enabled' = ConvertTo-TextYN $Item.IsLocalAuthEnabled - 'Local Users And Groups Enabled' = ConvertTo-TextYN $Item.IsLocalUsersAndGroupsEnabled - 'Multi Channel Enabled' = ConvertTo-TextYN $Item.IsMultichannelEnabled - 'Nbns Enabled' = ConvertTo-TextYN $Item.IsNbnsEnabled - 'Netbios Over Tcp Enabled' = ConvertTo-TextYN $Item.IsNetbiosOverTcpEnabled - 'Referral Enabled' = ConvertTo-TextYN $Item.IsReferralEnabled - 'Shadow Copy Enabled' = ConvertTo-TextYN $Item.IsShadowcopyEnabled - 'Smb1 Enabled' = ConvertTo-TextYN $Item.IsSmb1Enabled - 'Smb2 Enabled' = ConvertTo-TextYN $Item.IsSmb2Enabled - 'Smb31 Enabled' = ConvertTo-TextYN $Item.IsSmb31Enabled - 'Smb3 Enabled' = ConvertTo-TextYN $Item.IsSmb3Enabled + 'Client Version Reporting Enabled' = $Item.IsClientVersionReportingEnabled + 'Copy Offload Direct Copy Enabled' = $Item.IsCopyOffloadDirectCopyEnabled + 'Copy Offload Enabled' = $Item.IsCopyOffloadEnabled + 'Dac Enabled' = $Item.IsDacEnabled + 'Export Policy Enabled' = $Item.IsExportpolicyEnabled + 'Large MTU Enabled' = $Item.IsLargeMtuEnabled + 'Local Auth Enabled' = $Item.IsLocalAuthEnabled + 'Local Users And Groups Enabled' = $Item.IsLocalUsersAndGroupsEnabled + 'Multi Channel Enabled' = $Item.IsMultichannelEnabled + 'Nbns Enabled' = $Item.IsNbnsEnabled + 'Netbios Over Tcp Enabled' = $Item.IsNetbiosOverTcpEnabled + 'Referral Enabled' = $Item.IsReferralEnabled + 'Shadow Copy Enabled' = $Item.IsShadowcopyEnabled + 'Smb1 Enabled' = $Item.IsSmb1Enabled + 'Smb2 Enabled' = $Item.IsSmb2Enabled + 'Smb31 Enabled' = $Item.IsSmb31Enabled + 'Smb3 Enabled' = $Item.IsSmb3Enabled 'Max Connections Per Session' = $Item.MaxConnectionsPerSession 'Max Credits' = $Item.MaxCredits 'Max File Write Zero Length' = $Item.MaxFileWriteZeroLength @@ -66,7 +66,7 @@ function Get-AbrOntapVserverCIFSOption { 'Shadow Copy Dir Depth' = $Item.ShadowcopyDirDepth 'Smb1 Max Buffer Size' = $Item.Smb1MaxBufferSize } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverCIFSSecurity.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSecurity.ps1 similarity index 84% rename from Src/Private/Get-AbrOntapVserverCIFSSecurity.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSecurity.ps1 index 9220a3e..d1b47ca 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSSecurity.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSecurity.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSSecurity { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSSecurity { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver CIFS Security information." + Write-PScriboMessage 'Collecting ONTAP Vserver CIFS Security information.' } process { @@ -40,12 +40,12 @@ function Get-AbrOntapVserverCIFSSecurity { 'Kerberos Clock Skew' = $SVM.KerberosClockSkew 'Kerberos Renew Age' = $SVM.KerberosRenewAge 'Kerberos Ticket Age' = $SVM.KerberosTicketAge - 'Aes Encryption Enabled' = ConvertTo-TextYN $SVM.IsAesEncryptionEnabled - 'Signing Required' = ConvertTo-TextYN $SVM.IsSigningRequired - 'Smb Encryption Required' = ConvertTo-TextYN $SVM.IsSmbEncryptionRequired + 'Aes Encryption Enabled' = $SVM.IsAesEncryptionEnabled + 'Signing Required' = $SVM.IsSigningRequired + 'Smb Encryption Required' = $SVM.IsSmbEncryptionRequired 'Lm Compatibility Level' = $SVM.LmCompatibilityLevel } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } else { continue } } } catch { diff --git a/Src/Private/Get-AbrOntapVserverCIFSSession.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSession.ps1 similarity index 90% rename from Src/Private/Get-AbrOntapVserverCIFSSession.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSession.ps1 index 3c434d1..4b1c5b9 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSSession.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSession.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSSession { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSSession { ) begin { - Write-PScriboMessage "Collecting ONTAP CIFS Session information." + Write-PScriboMessage 'Collecting ONTAP CIFS Session information.' } process { @@ -40,7 +40,7 @@ function Get-AbrOntapVserverCIFSSession { 'Address' = $Item.Address 'User' = $Item.WindowsUser } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverCIFSShare.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSShare.ps1 similarity index 89% rename from Src/Private/Get-AbrOntapVserverCIFSShare.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSShare.ps1 index e617292..51c9b29 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSShare.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSShare.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSShare { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSShare { ) begin { - Write-PScriboMessage "Collecting ONTAP CIFS Share information." + Write-PScriboMessage 'Collecting ONTAP CIFS Share information.' } process { @@ -38,7 +38,7 @@ function Get-AbrOntapVserverCIFSShare { 'Volume' = $Item.Volume 'Path' = $Item.Path } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverCIFSShareProp.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSShareProp.ps1 similarity index 85% rename from Src/Private/Get-AbrOntapVserverCIFSShareProp.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSShareProp.ps1 index 85c0406..1b9c8ca 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSShareProp.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSShareProp.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSShareProp { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSShareProp { ) begin { - Write-PScriboMessage "Collecting ONTAP CIFS Share Properties information." + Write-PScriboMessage 'Collecting ONTAP CIFS Share Properties information.' } process { @@ -36,9 +36,9 @@ function Get-AbrOntapVserverCIFSShareProp { $inObj = [ordered] @{ 'Share Name' = $Item.ShareName 'Share ACL' = $Item.Acl - 'Share Properties' = ($Item).ShareProperties -join ', ' + 'Share Properties' = $Item.ShareProperties -join ', ' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 similarity index 87% rename from Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 index 038995e..4c33532 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverCIFSSummary { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverCIFSSummary { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver CIFS information." + Write-PScriboMessage 'Collecting ONTAP Vserver CIFS information.' } process { @@ -43,9 +43,9 @@ function Get-AbrOntapVserverCIFSSummary { 'AD Server Site' = $SVM.CifsServerSite 'Cifs Server Status' = $SVM.CifsServerStatus 'Status Details' = $SVM.StatusDetails - 'Status' = $SVM.Status.ToString() + 'Status' = ${SVM}?.Status?.ToString() } - $VserverObj = [pscustomobject]$inobj + $VserverObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Vserver.CIFS) { $VserverObj | Where-Object { $_.'Cifs Server Status' -notlike 'Running' } | Set-Style -Style Warning -Property 'Cifs Server Status' @@ -62,11 +62,11 @@ function Get-AbrOntapVserverCIFSSummary { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.CIFS -and ($VserverObj | Where-Object { $_.'Status' -like 'down' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that the CIFS service is running on all nodes to maintain file sharing capabilities.' } BlankLine } diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverDiagram.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverDiagram.ps1 new file mode 100644 index 0000000..c45d2cb --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverDiagram.ps1 @@ -0,0 +1,279 @@ +function Get-AbrOntapVserverDiagram { + <# + .SYNOPSIS + Used by As Built Report to build NetApp ONTAP Vserver resources diagram + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage "Generating Vserver Diagram for $Vserver." + # Used for DiagramDebug + if ($Options.EnableDiagramDebug) { + $EdgeDebug = @{style = 'filled'; color = 'red' } + $SubGraphDebug = @{style = 'dashed'; color = 'red' } + $NodeDebug = @{color = 'black'; style = 'red'; shape = 'plain' } + $NodeDebugEdge = @{color = 'black'; style = 'red'; shape = 'plain' } + $IconDebug = $true + } else { + $EdgeDebug = @{style = 'invis'; color = 'red' } + $SubGraphDebug = @{style = 'invis'; color = 'gray' } + $NodeDebug = @{color = 'transparent'; style = 'transparent'; shape = 'point' } + $NodeDebugEdge = @{color = 'transparent'; style = 'transparent'; shape = 'none' } + $IconDebug = $false + } + + if ($Options.DiagramTheme -eq 'Black') { + $Edgecolor = 'White' + $Fontcolor = 'White' + } elseif ($Options.DiagramTheme -eq 'Neon') { + $Edgecolor = 'gold2' + $Fontcolor = 'gold2' + } else { + $Edgecolor = '#71797E' + $Fontcolor = '#565656' + } + } + + process { + try { + $ClusterInfo = Get-NcCluster -Controller $Array + $VserverData = Get-NcVserver -VserverContext $Vserver | Where-Object { $_.VserverType -eq 'data' } + $VserverAggrs = (Get-NcVol -VserverContext $Vserver -Controller $Array).Aggregate | ForEach-Object { Get-NcAggr -Name $_ } | Select-Object -Unique + $VserverLifs = Get-NcNetInterface -Controller $Array | Where-Object { $_.Vserver -eq $Vserver -and $_.Role -eq 'data' } + + $VserverNodeName = Remove-SpecialChar -String $Vserver -SpecialChars '\-_' + + # SVM Additional Info + $SVMAdditionalInfo = [PSCustomObject][ordered]@{ + 'State' = switch ([string]::IsNullOrEmpty($VserverData.State)) { + $true { 'Unknown' } + $false { $TextInfo.ToTitleCase($VserverData.State) } + default { 'Unknown' } + } + 'Protocols' = switch ([string]::IsNullOrEmpty($VserverData.AllowedProtocols)) { + $true { 'None' } + $false { ($VserverData.AllowedProtocols | Sort-Object) -join ', ' } + default { 'None' } + } + 'IPSpace' = switch ([string]::IsNullOrEmpty($VserverData.Ipspace)) { + $true { 'Unknown' } + $false { $VserverData.Ipspace } + default { 'Unknown' } + } + 'Root Vol' = switch ([string]::IsNullOrEmpty($VserverData.RootVolume)) { + $true { 'Unknown' } + $false { $VserverData.RootVolume } + default { 'Unknown' } + } + } + + # SVM node + $SVMNodeObj = Add-HtmlNodeTable -Name 'SVMNodeObj' -ImagesObj $Images -inputObject $Vserver -Align 'Center' -iconType 'Ontap_SVM' -ColumnSize 1 -IconDebug $IconDebug -MultiIcon -AditionalInfo $SVMAdditionalInfo -TableBorderColor '#71797E' -TableBorder '0' -FontSize 18 + + if ($SVMNodeObj) { + $SVMMgmtObj = Add-HtmlSubGraph -Name 'SVMMgmtObj' -ImagesObj $Images -TableArray $SVMNodeObj -Align 'Right' -IconDebug $IconDebug -Label "Management: $($ClusterInfo.NcController)" -LabelPos 'down' -TableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder 1 -ColumnSize 1 -FontSize 12 + + if ($SVMMgmtObj) { + Node $VserverNodeName @{Label = $SVMMgmtObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } + } else { + Write-PScriboMessage -IsWarning "Unable to create SVM Node for $Vserver." + } + } + + # Aggregates + if ($VserverAggrs) { + try { + $AggrInfo = @() + foreach ($Aggr in $VserverAggrs) { + $AggrData = Get-NcAggr -Name $Aggr.AggregateName -Controller $Array + $AggrInfo += [PSCustomObject][ordered]@{ + 'Name' = $Aggr.AggregateName + 'AdditionalInfo' = [PSCustomObject][ordered]@{ + 'Raid Type' = switch ([string]::IsNullOrEmpty($Aggr.RaidType)) { + $true { 'Unknown' } + $false { $Aggr.RaidType } + default { 'Unknown' } + } + 'Available' = switch ([string]::IsNullOrEmpty($AggrData.Available)) { + $true { 'Unknown' } + $false { ($AggrData.Available | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize -ErrorAction SilentlyContinue) } + default { 'Unknown' } + } + 'SnapLock' = switch ([string]::IsNullOrEmpty($Aggr.SnaplockType)) { + $true { 'None' } + $false { $Aggr.SnaplockType } + default { 'None' } + } + } + } + } + + if ($AggrInfo.Count -eq 1) { + $AggrColumnSize = 1 + } elseif ($ColumnSize) { + $AggrColumnSize = $ColumnSize + } else { + $AggrColumnSize = $AggrInfo.Count + } + + $AggrNodeObj = Add-HtmlNodeTable -Name 'AggrNodeObj' -ImagesObj $Images -inputObject $AggrInfo.Name -Align 'Center' -iconType 'Ontap_Aggregate' -ColumnSize $AggrColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo $AggrInfo.AdditionalInfo -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder 1 -FontSize 18 + + if ($AggrNodeObj) { + $AggrSubGraphObj = Add-HtmlSubGraph -Name 'AggrSubGraphObj' -ImagesObj $Images -TableArray $AggrNodeObj -Align 'Center' -IconDebug $IconDebug -Label 'Aggregates' -LabelPos 'top' -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -ColumnSize 1 -FontSize 18 + + if ($AggrSubGraphObj) { + Node "$($VserverNodeName)Aggrs" @{Label = $AggrSubGraphObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } + Edge -To "$($VserverNodeName)Aggrs" -From $VserverNodeName @{minlen = 2; color = $Edgecolor; style = 'filled'; arrowhead = 'box'; arrowtail = 'box' } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + # Volumes + $VserverVolumes = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } + if ($VserverVolumes) { + try { + $VolInfo = @() + foreach ($Vol in $VserverVolumes) { + $VolInfo += [PSCustomObject][ordered]@{ + 'Name' = $Vol.Name + 'AdditionalInfo' = [PSCustomObject][ordered]@{ + 'State' = switch ([string]::IsNullOrEmpty($Vol.State)) { + $true { 'Unknown' } + $false { $TextInfo.ToTitleCase($Vol.State) } + default { 'Unknown' } + } + 'Size' = switch ([string]::IsNullOrEmpty($Vol.Totalsize)) { + $true { 'Unknown' } + $false { ($Vol.Totalsize | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type DataSize -ErrorAction SilentlyContinue) } + default { 'Unknown' } + } + 'Used' = switch ([string]::IsNullOrEmpty($Vol.Used)) { + $true { 'Unknown' } + $false { ($Vol.Used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) } + default { 'Unknown' } + } + 'Aggr' = switch ([string]::IsNullOrEmpty($Vol.Aggregate)) { + $true { 'Unknown' } + $false { $Vol.Aggregate } + default { 'Unknown' } + } + } + } + } + + if ($VolInfo.Count -eq 1) { + $VolColumnSize = 1 + } elseif ($ColumnSize) { + $VolColumnSize = $ColumnSize + } else { + $VolColumnSize = $VolInfo.Count + } + + $VolNodeObj = Add-HtmlNodeTable -Name 'VolNodeObj' -ImagesObj $Images -inputObject $VolInfo.Name -Align 'Center' -iconType 'Ontap_Volume' -ColumnSize $VolColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo $VolInfo.AdditionalInfo -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder 1 -FontSize 18 + + if ($VolNodeObj) { + $VolSubGraphObj = Add-HtmlSubGraph -Name 'VolSubGraphObj' -ImagesObj $Images -TableArray $VolNodeObj -Align 'Center' -IconDebug $IconDebug -Label 'Volumes' -LabelPos 'top' -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -ColumnSize 1 -FontSize 18 + + if ($VolSubGraphObj) { + Node "$($VserverNodeName)Vols" @{Label = $VolSubGraphObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } + Add-NodeEdge -From $VserverNodeName -To "$($VserverNodeName)Vols" -EdgeColor $Edgecolor -Arrowhead 'box' -Arrowtail 'box' -EdgeLength 2 -GraphvizAttributes @{style = 'filled'} + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + # LIFs + if ($VserverLifs) { + try { + $LifInfo = @() + foreach ($Lif in $VserverLifs) { + $LifInfo += [PSCustomObject][ordered]@{ + 'Name' = $Lif.InterfaceName + 'AdditionalInfo' = [PSCustomObject][ordered]@{ + 'IP' = switch ($Null -eq $Lif.Wwpn) { + $true { + switch ([string]::IsNullOrEmpty($Lif.Address)) { + $true { 'Unknown' } + $false { $Lif.Address } + default { 'Unknown' } + } + } + $false { $Lif.Wwpn } + } + 'Protocol' = switch ([string]::IsNullOrEmpty($Lif.DataProtocols)) { + $true { 'Unknown' } + $false { ($Lif.DataProtocols | Sort-Object) -join ', ' } + default { 'Unknown' } + } + 'Status' = switch ($Lif.AdministrativeStatus) { + 'up' { 'Up' } + 'down' { 'Down' } + default { 'Unknown' } + } + 'Is Home?' = switch ($Lif.IsHome) { + $true { 'Yes' } + $false { 'No' } + default { 'Unknown' } + } + 'Home Node' = switch ([string]::IsNullOrEmpty($Lif.HomeNode)) { + $true { 'Unknown' } + $false { $Lif.HomeNode } + default { 'Unknown' } + } + } + } + } + + if ($LifInfo.Count -eq 1) { + $LifColumnSize = 1 + } elseif ($ColumnSize) { + $LifColumnSize = $ColumnSize + } else { + $LifColumnSize = $LifInfo.Count + } + + $LifNodeObj = Add-HtmlNodeTable -Name 'LifNodeObj' -ImagesObj $Images -inputObject $LifInfo.Name -Align 'Center' -iconType 'Ontap_Network_Nic' -ColumnSize $LifColumnSize -IconDebug $IconDebug -MultiIcon -AditionalInfo $LifInfo.AdditionalInfo -SubgraphTableStyle 'dashed,rounded' -TableBorderColor '#71797E' -TableBorder 1 -FontSize 18 + + if ($LifNodeObj) { + $LifSubGraphObj = Add-HtmlSubGraph -Name 'LifSubGraphObj' -ImagesObj $Images -TableArray $LifNodeObj -Align 'Center' -IconDebug $IconDebug -Label 'Network Interfaces (LIFs)' -LabelPos 'top' -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -ColumnSize 1 -FontSize 18 + + if ($LifSubGraphObj) { + Node "$($VserverNodeName)Lifs" @{Label = $LifSubGraphObj; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } + Add-NodeEdge -From $VserverNodeName -To "$($VserverNodeName)Lifs" -EdgeColor $Edgecolor -Arrowhead 'box' -Arrowtail 'box' -EdgeLength 2 -GraphvizAttributes @{style = 'filled'} + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} diff --git a/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverExportPolicy.ps1 similarity index 78% rename from Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverExportPolicy.ps1 index d0a2554..42c905b 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverExportPolicy.ps1 @@ -1,11 +1,11 @@ -function Get-AbrOntapVserverVolumesExportPolicy { +function Get-AbrOntapVserverExportPolicy { <# .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP vserver volumes export policy information from the Cluster Management Network + Used by As Built Report to retrieve NetApp ONTAP vserver export policy information from the Cluster Management Network .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverVolumesExportPolicy { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes export policy information." + Write-PScriboMessage 'Collecting ONTAP Vserver export policy information.' } process { @@ -37,18 +37,18 @@ function Get-AbrOntapVserverVolumesExportPolicy { 'Policy Name' = $Item.PolicyName 'Rule Index' = $Item.RuleIndex 'Client Match' = $Item.ClientMatch - 'Protocol' = $Item.Protocol -join ", " + 'Protocol' = $Item.Protocol -join ', ' 'Ro Rule' = $Item.RoRule 'Rw Rule' = $Item.RwRule } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } $TableParams = @{ - Name = "Volume Export Policy - $($Vserver)" + Name = "Export Policies - $($Vserver)" List = $false ColumnWidths = 20, 15, 20, 15, 15, 15 } diff --git a/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 similarity index 76% rename from Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 index 813c0e8..45ce34c 100755 --- a/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverFcpAdapter { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapVserverFcpAdapter { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver FCP adapter information." + Write-PScriboMessage 'Collecting ONTAP Vserver FCP adapter information.' } process { @@ -34,13 +34,9 @@ function Get-AbrOntapVserverFcpAdapter { 'Adapter' = $Item.Adapter 'Protocol' = $Item.PhysicalProtocol 'Speed' = $Item.Speed - 'Status' = switch ($Item.State) { - 'online' { 'Up' } - 'offline' { 'Down' } - default { $Item.State } - } + 'Status' = ($Item.State -eq 'online') ? 'Up': 'Down' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -59,11 +55,11 @@ function Get-AbrOntapVserverFcpAdapter { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.FCP -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that all FCP adapters are operational to maintain optimal storage connectivity." + Text 'Best Practice:' -Bold + Text 'Ensure that all FCP adapters are operational to maintain optimal storage connectivity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverFcpInterface.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpInterface.ps1 similarity index 81% rename from Src/Private/Get-AbrOntapVserverFcpInterface.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpInterface.ps1 index e200fd3..99b789e 100755 --- a/Src/Private/Get-AbrOntapVserverFcpInterface.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpInterface.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverFcpInterface { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,12 +23,12 @@ function Get-AbrOntapVserverFcpInterface { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver FCP interface information." + Write-PScriboMessage 'Collecting ONTAP Vserver FCP interface information.' } process { try { - $VserverData = Get-NcFcpInterface -VserverContext $Vserver -Controller $Array + $VserverData = Get-NcFcpInterface -VserverContext $Vserver -Controller $Array | Sort-Object -Property CurrentNode $VserverObj = @() if ($VserverData) { foreach ($Item in $VserverData) { @@ -36,9 +36,10 @@ function Get-AbrOntapVserverFcpInterface { $inObj = [ordered] @{ 'Interface Name' = $Item.InterfaceName 'FCP WWPN' = $Item.PortName + 'Node Name' = $Item.CurrentNode 'Home Port' = $Item.CurrentPort } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -47,7 +48,7 @@ function Get-AbrOntapVserverFcpInterface { $TableParams = @{ Name = "FCP Interface - $($Vserver)" List = $false - ColumnWidths = 35, 35, 30 + ColumnWidths = 30, 30, 20, 20 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" diff --git a/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 similarity index 74% rename from Src/Private/Get-AbrOntapVserverFcpSummary.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 index 9ef7a26..7c5d4c8 100755 --- a/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverFcpSummary { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverFcpSummary { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver FCP information." + Write-PScriboMessage 'Collecting ONTAP Vserver FCP information.' } process { @@ -35,13 +35,9 @@ function Get-AbrOntapVserverFcpSummary { try { $inObj = [ordered] @{ 'FCP WWNN' = $Item.NodeName - 'Status' = switch ($Item.IsAvailable) { - 'True' { 'Up' } - 'False' { 'Down' } - default { $Item.IsAvailable } - } + 'Status' = $Item.IsAvailable -eq $true ? 'Up': 'Down' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -60,11 +56,11 @@ function Get-AbrOntapVserverFcpSummary { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.FCP -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' } )) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that all FCP services are operational to maintain optimal storage connectivity." + Text 'Best Practice:' -Bold + Text 'Ensure that all FCP services are operational to maintain optimal storage connectivity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverIscsiInitiator.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiInitiator.ps1 similarity index 88% rename from Src/Private/Get-AbrOntapVserverIscsiInitiator.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiInitiator.ps1 index 793bab6..a53cd7e 100755 --- a/Src/Private/Get-AbrOntapVserverIscsiInitiator.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiInitiator.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverIscsiInitiator { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverIscsiInitiator { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver ISCSI Client Initiators information." + Write-PScriboMessage 'Collecting ONTAP Vserver ISCSI Client Initiators information.' } process { @@ -37,7 +37,7 @@ function Get-AbrOntapVserverIscsiInitiator { 'Initiator Name' = $Item.InitiatorNodeName 'Target Port Group' = $Item.TpGroupName } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 similarity index 75% rename from Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 index 7119480..7564713 100755 --- a/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverIscsiInterface { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverIscsiInterface { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver ISCSI interface information." + Write-PScriboMessage 'Collecting ONTAP Vserver ISCSI interface information.' } process { @@ -37,13 +37,9 @@ function Get-AbrOntapVserverIscsiInterface { 'Interface Name' = $Item.InterfaceName 'IP Address' = $Item.IpAddress 'Port' = $Item.IpPort - 'Status' = switch ($Item.IsInterfaceEnabled) { - 'True' { 'Up' } - 'False' { 'Down' } - default { $Item.IsInterfaceEnabled } - } + 'Status' = ($Item.IsInterfaceEnabled -eq $true) ? 'Up': 'Down' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -62,11 +58,11 @@ function Get-AbrOntapVserverIscsiInterface { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Iscsi -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that all ISCSI interfaces are operational to maintain optimal storage connectivity." + Text 'Best Practice:' -Bold + Text 'Ensure that all ISCSI interfaces are operational to maintain optimal storage connectivity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 similarity index 77% rename from Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 index 8b6d4a2..3e7007d 100755 --- a/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverIscsiSummary { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverIscsiSummary { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver ISCSI information." + Write-PScriboMessage 'Collecting ONTAP Vserver ISCSI information.' } process { @@ -40,13 +40,9 @@ function Get-AbrOntapVserverIscsiSummary { 'Max Cmds Per Session' = $Item.MaxCmdsPerSession 'Max Conn Per Session' = $Item.MaxConnPerSession 'Login Timeout' = $Item.LoginTimeout - 'Status' = switch ($Item.IsAvailable) { - 'True' { 'Up' } - 'False' { 'Down' } - default { $Item.IsAvailable } - } + 'Status' = ($Item.IsAvailable -eq $true) ? 'Up': 'Down' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -65,11 +61,11 @@ function Get-AbrOntapVserverIscsiSummary { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Iscsi -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that all ISCSI services are operational to maintain optimal storage connectivity." + Text 'Best Practice:' -Bold + Text 'Ensure that all ISCSI services are operational to maintain optimal storage connectivity.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 similarity index 79% rename from Src/Private/Get-AbrOntapVserverLunIgroup.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 index f92f660..85e00f8 100755 --- a/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverLunIgroup { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverLunIgroup { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver Igroup information." + Write-PScriboMessage 'Collecting ONTAP Vserver Igroup information.' } process { @@ -49,16 +49,10 @@ function Get-AbrOntapVserverLunIgroup { 'Type' = $Item.Type 'Protocol' = $Item.Protocol 'Initiators' = $Item.Initiators.InitiatorName - 'Mapped Lun' = switch (($MappedLun).count) { - 0 { "None" } - default { $MappedLun } - } - 'Reporting Nodes' = switch (($reportingnodes).count) { - 0 { "None" } - default { $reportingnodes } - } + 'Mapped Lun' = (($MappedLun).count -eq 0) ? 'None': $MappedLun + 'Reporting Nodes' = (($reportingnodes).count) ? 'None': $reportingnodes } - $VserverObj = [pscustomobject]$inobj + $VserverObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Vserver.Status) { $VserverObj | Where-Object { ($_.'Reporting Nodes').count -gt 2 } | Set-Style -Style Warning -Property 'Reporting Nodes' } @@ -73,11 +67,11 @@ function Get-AbrOntapVserverLunIgroup { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { ($_.'Reporting Nodes').count -gt 2 })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that igroups have an optimal number of reporting nodes to maintain performance and reliability.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverLunStorage.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverLunStorage.ps1 similarity index 55% rename from Src/Private/Get-AbrOntapVserverLunStorage.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverLunStorage.ps1 index 5762b94..16e33a1 100755 --- a/Src/Private/Get-AbrOntapVserverLunStorage.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverLunStorage.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverLunStorage { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverLunStorage { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver lun information." + Write-PScriboMessage 'Collecting ONTAP Vserver lun information.' } process { @@ -34,43 +34,25 @@ function Get-AbrOntapVserverLunStorage { foreach ($Item in $VserverLun) { try { $lunmap = Get-NcLunMap -Path $Item.Path -Controller $Array | Select-Object -ExpandProperty InitiatorGroup - $lunpath = $Item.Path.split('/') - $lun = $lunpath[3] - $available = $Item.Size - $Item.SizeUsed - $used = ($Item.SizeUsed / $Item.Size) * 100 + $lun = $Item.Path.split('/')[3] $inObj = [ordered] @{ 'Lun Name' = $lun 'Parent Volume' = $Item.Volume 'Path' = $Item.Path 'Serial Number' = $Item.SerialNumber - 'Initiator Group' = switch (($lunmap).count) { - 0 { "None" } - default { $lunmap } - } + 'Initiator Group' = ($lunmap.count -eq 0) ? 'None': $lunmap 'Home Node ' = $Item.Node - 'Capacity' = $Item.Size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Available' = $available | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Used' = $used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue + 'Capacity' = ($Item.Size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = (($Item.Size - $Item.SizeUsed) | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ((($Item.SizeUsed / $Item.Size) * 100) | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' 'OS Type' = $Item.Protocol - 'Is Thin' = ConvertTo-TextYN $Item.Thin - 'Space Allocation' = switch ($Item.IsSpaceAllocEnabled) { - 'True' { 'Enabled' } - 'False' { 'Disabled' } - default { $Item.IsSpaceAllocEnabled } - } - 'Space Reservation' = switch ($Item.IsSpaceReservationEnabled) { - 'True' { 'Enabled' } - 'False' { 'Disabled' } - default { $Item.IsSpaceReservationEnabled } - } - 'Is Mapped' = ConvertTo-TextYN $Item.Mapped - 'Status' = switch ($Item.Online) { - 'True' { 'Up' } - 'False' { 'Down' } - default { $Item.Online } - } + 'Is Thin' = $Item.Thin + 'Space Allocation' = $Item.IsSpaceAllocEnabled -eq $True ? 'Enabled': 'Disabled' + 'Space Reservation' = $Item.IsSpaceReservationEnabled -eq $True ? 'Enabled': 'Disabled' + 'Is Mapped' = $Item.Mapped + 'Status' = $Item.Online -eq $True ? 'Up': 'Down' } - $VserverObj = [pscustomobject]$inobj + $VserverObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Vserver.Status) { $VserverObj | Where-Object { $_.'Status' -like 'Down' } | Set-Style -Style Warning -Property 'Status' @@ -88,11 +70,11 @@ function Get-AbrOntapVserverLunStorage { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that all LUNs are operational to maintain optimal storage connectivity." + Text 'Best Practice:' -Bold + Text 'Ensure that all LUNs are operational to maintain optimal storage connectivity.' } BlankLine } diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSExport.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSExport.ps1 new file mode 100755 index 0000000..e1daa28 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSExport.ps1 @@ -0,0 +1,64 @@ +function Get-AbrOntapVserverNFSExport { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP Vserver NFS Export information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP Vserver NFS Export information.' + } + + process { + try { + $VserverObj = @() + $NFSVserver = Get-NcNfsExport -VS $Vserver -Controller $Array + if ($NFSVserver ) { + foreach ($Item in $NFSVserver) { + try { + $inObj = [ordered] @{ + 'Path Name' = $Item.Pathname + 'Export Policy' = (((Get-NcVol -VS $Vserver -Controller $Array | Where-Object { $_.JunctionPath -eq $Item.Pathname }).VolumeExportAttributes).Policy) ?? 'None' + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } + } + + $TableParams = @{ + Name = "NFS Service Volume Export - $($Vserver)" + List = $false + ColumnWidths = 50, 50 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + if ($VserverObj) { + $VserverObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapVserverNFSOptions.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSOptions.ps1 similarity index 56% rename from Src/Private/Get-AbrOntapVserverNFSOptions.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSOptions.ps1 index 154a408..cc1078e 100755 --- a/Src/Private/Get-AbrOntapVserverNFSOptions.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSOptions.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNFSOption { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverNFSOption { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver NFS Option information." + Write-PScriboMessage 'Collecting ONTAP Vserver NFS Option information.' } process { @@ -34,21 +34,21 @@ function Get-AbrOntapVserverNFSOption { foreach ($Item in $VserverData) { try { $inObj = [ordered] @{ - 'Allow Idle Connection' = ConvertTo-TextYN $Item.AllowIdleConnection + 'Allow Idle Connection' = $Item.AllowIdleConnection 'Idle Connection Timeout' = $Item.IdleConnectionTimeout - 'Ignore NtAcl For Root' = ConvertTo-TextYN $Item.IgnoreNtAclForRoot - 'Enable Ejukebox' = ConvertTo-TextYN $Item.EnableEjukebox - 'Nfs Access Enabled' = ConvertTo-TextYN $Item.IsNfsAccessEnabled - 'Nfs Rootonly Enabled' = ConvertTo-TextYN $Item.IsNfsRootonlyEnabled - 'Nfsv2 Enabled' = ConvertTo-TextYN $Item.IsNfsv2Enabled - 'Nfsv3 Enabled' = ConvertTo-TextYN $Item.IsNfsv3Enabled - 'Nfsv3 64bit Identifiers Enabled' = ConvertTo-TextYN $Item.IsNfsv364bitIdentifiersEnabled - 'Nfsv3 Connection Drop Enabled' = ConvertTo-TextYN $Item.IsNfsv3ConnectionDropEnabled - 'Nfsv3 Fsid Change Enabled' = ConvertTo-TextYN $Item.IsNfsv3FsidChangeEnabled - 'Nfsv40 Acl Enabled' = ConvertTo-TextYN $Item.IsNfsv40AclEnabled - 'Nfsv40 Enabled' = ConvertTo-TextYN $Item.IsNfsv40Enabled + 'Ignore NtAcl For Root' = $Item.IgnoreNtAclForRoot + 'Enable Ejukebox' = $Item.EnableEjukebox + 'Nfs Access Enabled' = $Item.IsNfsAccessEnabled + 'Nfs Rootonly Enabled' = $Item.IsNfsRootonlyEnabled + 'Nfsv2 Enabled' = $Item.IsNfsv2Enabled + 'Nfsv3 Enabled' = $Item.IsNfsv3Enabled + 'Nfsv3 64bit Identifiers Enabled' = $Item.IsNfsv364bitIdentifiersEnabled + 'Nfsv3 Connection Drop Enabled' = $Item.IsNfsv3ConnectionDropEnabled + 'Nfsv3 Fsid Change Enabled' = $Item.IsNfsv3FsidChangeEnabled + 'Nfsv40 Acl Enabled' = $Item.IsNfsv40AclEnabled + 'Nfsv40 Enabled' = $Item.IsNfsv40Enabled } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 similarity index 61% rename from Src/Private/Get-AbrOntapVserverNFSSummary.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 index 030269b..cbaf343 100755 --- a/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNFSSummary { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverNFSSummary { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver NFS information." + Write-PScriboMessage 'Collecting ONTAP Vserver NFS information.' } process { @@ -34,25 +34,13 @@ function Get-AbrOntapVserverNFSSummary { foreach ($Item in $VserverData) { try { $inObj = [ordered] @{ - 'Nfs v3' = switch ($Item.IsNfsv3) { - 'True' { 'Enabled' } - 'False' { 'Disabled' } - default { $Item.IsNfsv3 } - } - 'Nfs v4' = switch ($Item.IsNfsv4) { - 'True' { 'Enabled' } - 'False' { 'Disabled' } - default { $Item.IsNfsv4 } - } - 'Nfs v41' = switch ($Item.IsNfsv41) { - 'True' { 'Enabled' } - 'False' { 'Disabled' } - default { $Item.IsNfsv41 } - } - 'General Access' = ConvertTo-TextYN $Item.GeneralAccess + 'Nfs v3' = $Item.IsNfsv3 -eq $true ? 'Enabled': 'Disabled' + 'Nfs v4' = $Item.IsNfsv4 -eq $true ? 'Enabled': 'Disabled' + 'Nfs v41' = $Item.IsNfsv41 -eq $true ? 'Enabled': 'Disabled' + 'General Access' = $Item.GeneralAccess } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -71,11 +59,11 @@ function Get-AbrOntapVserverNFSSummary { } $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 + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Evaluate enabling NFS services to support client connectivity and file sharing." + Text 'Best Practice:' -Bold + Text 'Evaluate enabling NFS services to support client connectivity and file sharing.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 similarity index 69% rename from Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 index 57f13d1..c9435a1 100755 --- a/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNamespaceStorage { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverNamespaceStorage { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver namespace information." + Write-PScriboMessage 'Collecting ONTAP Vserver namespace information.' } process { @@ -34,37 +34,31 @@ function Get-AbrOntapVserverNamespaceStorage { foreach ($Item in $VserverNamespace) { try { $namespacemap = Get-NcNvmeSubsystemMap -Vserver $Vserver -Controller $Array | Where-Object { $_.Path -eq $Item.Path } - $namespacepath = $Item.Path.split('/') - $namespace = $namespacepath[3] - $available = $Item.Size - $Item.SizeUsed - $used = ($Item.SizeUsed / $Item.Size) * 100 + $namespace = $Item.Path.split('/')[3] $inObj = [ordered] @{ 'Namespace Name' = $namespace 'Parent Volume' = $Item.Volume 'Path' = $Item.Path 'Serial Number' = $Item.Uuid - 'Subsystem Map' = switch (($namespacemap).count) { - 0 { "None" } - default { $namespacemap.Subsystem } - } + 'Subsystem Map' = ($namespacemap).count -eq 0 ? 'None': $namespacemap.Subsystem 'Home Node ' = $Item.Node - 'Capacity' = $Item.Size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Available' = $available | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Used' = $used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue + 'Capacity' = ($Item.Size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = (($Item.Size - $Item.SizeUsed) | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ((($Item.SizeUsed / $Item.Size) * 100) | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' 'OS Type' = $Item.Ostype 'Is Mapped' = switch ([string]::IsNullOrEmpty($Item.Subsystem)) { - $true { "No" } - $false { "Yes" } + $true { 'No' } + $false { 'Yes' } default { $Item.Subsystem } } - 'ReadOnly' = ConvertTo-TextYN $Item.IsReadOnly + 'ReadOnly' = $Item.IsReadOnly 'Status' = switch ($Item.State) { 'online' { 'Up' } 'offline' { 'Down' } default { $Item.Online } } } - $VserverObj = [pscustomobject]$inobj + $VserverObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Vserver.Status) { $VserverObj | Where-Object { $_.'Status' -like 'Down' } | Set-Style -Style Warning -Property 'Status' @@ -82,11 +76,11 @@ function Get-AbrOntapVserverNamespaceStorage { } $VserverObj | Sort-Object -Property 'Namespace Name' | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure that all namespaces are operational to maintain optimal storage connectivity." + Text 'Best Practice:' -Bold + Text 'Ensure that all namespaces are operational to maintain optimal storage connectivity.' } BlankLine } diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 new file mode 100644 index 0000000..6352416 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 @@ -0,0 +1,90 @@ +function Get-AbrOntapVserverNetworkInterface { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver interfaces information + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP vserver network interface information.' + } + + process { + try { + $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'data' -and $_.Vserver -notin $options.Exclude.Vserver -and $_.Vserver -eq $Vserver } + $ClusterObj = @() + if ($ClusterData) { + foreach ($Item in $ClusterData) { + try { + $inObj = [ordered] @{ + 'Data Interface' = $Item.InterfaceName + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() + 'Data Protocols' = [string]$Item.DataProtocols + 'Address' = ($Null -eq $Item.Wwpn) ? $Item.Address: $Item.Wwpn + 'Home Node' = $Item.HomeNode + 'Is Home' = $Item.IsHome + } + $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' + $ClusterObj | Where-Object { $_.'Is Home' -eq 'No' } | Set-Style -Style Warning -Property 'Is Home' + } + + $TableParams = @{ + Name = "Data Network - $($Vserver)" + List = $false + ColumnWidths = 25, 9, 19, 17, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $ClusterObj | Table @TableParams + if ($Healthcheck.Network.Interface -and (($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' }) -or (($ClusterObj | Where-Object { $_.'Is Home' -ne 'Yes' })))) { + Paragraph 'Health Check:' -Bold -Underline + BlankLine + 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 { $_.'Is Home' -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 + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 similarity index 74% rename from Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 index fdd9129..d6eb756 100755 --- a/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNonMappedLun { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,25 +23,24 @@ function Get-AbrOntapVserverNonMappedLun { ) begin { - Write-PScriboMessage "Collecting ONTAP ISCSI/FCP Non Mapped Lun information." + Write-PScriboMessage 'Collecting ONTAP ISCSI/FCP Non Mapped Lun information.' } process { try { - $LunFilter = Get-NcLun -VserverContext $Vserver -Controller $Array | Where-Object { $_.Mapped -ne "True" } + $LunFilter = Get-NcLun -VserverContext $Vserver -Controller $Array | Where-Object { $_.Mapped -ne 'True' } $OutObj = @() if ($LunFilter) { foreach ($Item in $LunFilter) { try { - $lunname = (($Item.Path).split('/'))[3] $inObj = [ordered] @{ 'Volume Name' = $Item.Volume - 'Lun Name' = $lunname - 'Online' = ConvertTo-TextYN $Item.Online - 'Mapped' = ConvertTo-TextYN $Item.Mapped + 'Lun Name' = ($Item.Path).split('/')[3] + 'Online' = $Item.Online + 'Mapped' = $Item.Mapped 'Lun Format' = $Item.Protocol } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -60,11 +59,11 @@ function Get-AbrOntapVserverNonMappedLun { } $OutObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($OutObj)) { - Paragraph "Health Check:" -Bold -Underline + 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." + 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 } diff --git a/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 similarity index 79% rename from Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 index 8090e74..29fac33 100755 --- a/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNonMappedNamespace { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverNonMappedNamespace { ) begin { - Write-PScriboMessage "Collecting ONTAP NVME Non Mapped Namespace information." + Write-PScriboMessage 'Collecting ONTAP NVME Non Mapped Namespace information.' } process { @@ -33,15 +33,14 @@ function Get-AbrOntapVserverNonMappedNamespace { if ($NamespaceFilter) { foreach ($Item in $NamespaceFilter) { try { - $namespacename = (($Item.Path).split('/'))[3] $inObj = [ordered] @{ 'Volume Name' = $Item.Volume - 'Lun Name' = $namespacename + 'Namespace Name' = ($Item.Path).split('/')[3] 'Type' = $Item.Ostype - 'Mapped' = "No" + 'Mapped' = 'No' 'State' = $Item.State } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -60,11 +59,11 @@ function Get-AbrOntapVserverNonMappedNamespace { } $OutObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($OutObj)) { - Paragraph "Health Check:" -Bold -Underline + 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." + 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 } diff --git a/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 similarity index 81% rename from Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 index cdf77e8..ecfa5d1 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNvmeFcAdapter { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverNvmeFcAdapter { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver Nvme FC adapter information." + Write-PScriboMessage 'Collecting ONTAP Vserver Nvme FC adapter information.' } process { @@ -39,13 +39,9 @@ function Get-AbrOntapVserverNvmeFcAdapter { 'Protocol' = $Item.PhysicalProtocol 'WWNN' = $Item.FcWwnn 'WWPN' = $Item.FcWwpn - 'Status' = switch ($Item.StatusAdmin) { - 'up' { 'Up' } - 'down' { 'Down' } - default { $Item.StatusAdmin } - } + 'Status' = ($Item.StatusAdmin -eq 'up') ? 'Up': 'Down' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -65,10 +61,10 @@ function Get-AbrOntapVserverNvmeFcAdapter { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.FCP -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure all Nvme FC adapters are in 'Up' status to maintain optimal connectivity and performance." } BlankLine diff --git a/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 similarity index 80% rename from Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 index e510d6d..5b5f4fb 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNvmeInterface { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverNvmeInterface { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver NVME interface information." + Write-PScriboMessage 'Collecting ONTAP Vserver NVME interface information.' } process { @@ -37,13 +37,9 @@ function Get-AbrOntapVserverNvmeInterface { 'Interface Name' = $Item.Lif 'Transport Address' = $Item.TransportAddress 'Transport Protocols' = $Item.TransportProtocols - 'Status' = switch ($Item.StatusAdmin) { - 'up' { 'Up' } - 'down' { 'Down' } - default { $Item.StatusAdmin } - } + 'Status' = $Item.StatusAdmin -eq 'up' ? 'Up': 'Down' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -62,10 +58,10 @@ function Get-AbrOntapVserverNvmeInterface { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Nvme -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure all NVME interfaces are in 'Up' status to maintain optimal connectivity and performance." } BlankLine diff --git a/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 similarity index 81% rename from Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 index ca01d90..863e86c 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNvmeTcpAdapter { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverNvmeTcpAdapter { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver Nvme TCP adapter information." + Write-PScriboMessage 'Collecting ONTAP Vserver Nvme TCP adapter information.' } process { @@ -38,13 +38,9 @@ function Get-AbrOntapVserverNvmeTcpAdapter { 'Adapter' = $Item.HomePort 'Protocol' = $Item.PhysicalProtocol 'IP Address' = $Item.TransportAddress - 'Status' = switch ($Item.StatusAdmin) { - 'up' { 'Up' } - 'down' { 'Down' } - default { $Item.StatusAdmin } - } + 'Status' = $Item.StatusAdmin -eq 'up' ? 'Up': 'Down' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -64,10 +60,10 @@ function Get-AbrOntapVserverNvmeTcpAdapter { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.FCP -and ($VserverObj | Where-Object { $_.'Status' -like 'Down' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure all Nvme TCP adapters are in 'Up' status to maintain optimal connectivity and performance." } BlankLine diff --git a/Src/Private/Get-AbrOntapVserverS3Bucket.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverS3Bucket.ps1 similarity index 75% rename from Src/Private/Get-AbrOntapVserverS3Bucket.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverS3Bucket.ps1 index 799cc1d..6353c22 100755 --- a/Src/Private/Get-AbrOntapVserverS3Bucket.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverS3Bucket.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverS3Bucket { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverS3Bucket { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver S3 bucket information." + Write-PScriboMessage 'Collecting ONTAP Vserver S3 bucket information.' } process { @@ -36,10 +36,10 @@ function Get-AbrOntapVserverS3Bucket { $inObj = [ordered] @{ 'Bucket' = $Item.Name 'Volume' = $Item.volume.name - 'Total' = $Item.size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Used' = $Item.logical_used_size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Total' = ($Item.size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.logical_used_size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverS3Summary.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverS3Summary.ps1 similarity index 74% rename from Src/Private/Get-AbrOntapVserverS3Summary.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverS3Summary.ps1 index 25b1c07..69fd8d6 100755 --- a/Src/Private/Get-AbrOntapVserverS3Summary.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverS3Summary.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverS3Summary { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverS3Summary { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver S3 information." + Write-PScriboMessage 'Collecting ONTAP Vserver S3 information.' } process { @@ -34,17 +34,13 @@ function Get-AbrOntapVserverS3Summary { foreach ($Item in $VserverData) { try { $inObj = [ordered] @{ - 'HTTP' = ConvertTo-TextYN $Item.is_http_enabled + 'HTTP' = $Item.is_http_enabled 'HTTP Port' = $Item.port - 'HTTPS' = ConvertTo-TextYN $Item.is_https_enabled + 'HTTPS' = $Item.is_https_enabled 'HTTPS Port' = $Item.secure_port - 'Status' = Switch ($Item.enabled) { - 'True' { 'UP' } - 'False' { 'Down' } - default { $Item.enabled } - } + 'Status' = $Item.enabled -eq $true ? 'Up': 'Down' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverSubsystem.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverSubsystem.ps1 similarity index 83% rename from Src/Private/Get-AbrOntapVserverSubsystem.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverSubsystem.ps1 index b00710d..38ddb93 100755 --- a/Src/Private/Get-AbrOntapVserverSubsystem.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverSubsystem.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverSubsystem { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverSubsystem { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver Subsystem information." + Write-PScriboMessage 'Collecting ONTAP Vserver Subsystem information.' } process { @@ -48,12 +48,9 @@ function Get-AbrOntapVserverSubsystem { 'Type' = $Item.Ostype 'Target NQN' = $Item.TargetNqn 'Host NQN' = $Item.Hosts.Nqn - 'Mapped Namespace' = switch (($MappedNamespace).count) { - 0 { "None" } - default { $MappedNamespace } - } + 'Mapped Namespace' = (($MappedNamespace).count -eq 0) ? 'None': $MappedNamespaces } - $VserverObj = [pscustomobject]$inobj + $VserverObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Vserver.Status) { $VserverObj | Where-Object { ($_.'Mapped Namespace').count -eq 0 } | Set-Style -Style Warning -Property 'Mapped Namespace' } @@ -68,11 +65,11 @@ function Get-AbrOntapVserverSubsystem { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { ($_.'Mapped Namespace').count -eq 0 })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Ensure all subsystems have mapped namespaces to guarantee proper functionality and performance." + Text 'Best Practice:' -Bold + Text 'Ensure all subsystems have mapped namespaces to guarantee proper functionality and performance.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverSummary.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverSummary.ps1 similarity index 82% rename from Src/Private/Get-AbrOntapVserverSummary.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverSummary.ps1 index 7d4a542..f8e4100 100755 --- a/Src/Private/Get-AbrOntapVserverSummary.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverSummary.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverSummary { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,12 +23,12 @@ function Get-AbrOntapVserverSummary { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver information." + Write-PScriboMessage 'Collecting ONTAP Vserver information.' } process { try { - $VserverData = Get-NcVserver -VserverContext $Vserver | Where-Object { $_.VserverType -eq "data" } + $VserverData = Get-NcVserver -VserverContext $Vserver | Where-Object { $_.VserverType -eq 'data' } $VserverObj = @() if ($VserverData) { foreach ($Item in $VserverData) { @@ -40,7 +40,7 @@ function Get-AbrOntapVserverSummary { 'IPSpace' = $Item.Ipspace 'Status' = $Item.State } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -59,10 +59,10 @@ function Get-AbrOntapVserverSummary { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -like 'stopped' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure all Vservers are in 'running' status to provide uninterrupted services." } BlankLine @@ -78,13 +78,13 @@ function Get-AbrOntapVserverSummary { $inObj = [ordered] @{ 'Root Volume' = $Item.Name 'Status' = $Item.State - 'Total Size' = $Item.Totalsize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Used' = $Item.Used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue - 'Available' = $Item.Available | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Dedup' = ConvertTo-TextYN $Item.Dedupe + 'Total Size' = ($Item.Totalsize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.Used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' + 'Available' = ($Item.Available | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Dedup' = $Item.Dedupe 'Aggregate' = $Item.Aggregate } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -109,7 +109,7 @@ function Get-AbrOntapVserverSummary { Write-PScriboMessage -IsWarning $_.Exception.Message } try { - if (Get-NcVserverAggr) { + if (Get-NcVserverAggr -VserverContext $Vserver) { Section -Style Heading4 'Aggregate Resource Allocation' { $VserverAGGR = Get-NcVserverAggr -VserverContext $Vserver -Controller $Array $VserverObj = @() @@ -120,9 +120,9 @@ function Get-AbrOntapVserverSummary { 'Aggregate' = $Item.AggregateName 'Type' = $Item.AggregateType 'SnapLock Type' = $Item.SnaplockType - 'Available' = $Item.AvailableSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Available' = ($Item.AvailableSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 similarity index 65% rename from Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 index 3a10b87..0f41d19 100755 --- a/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumeSnapshot { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverVolumeSnapshot { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes snapshot information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes snapshot information.' } process { @@ -37,20 +37,20 @@ function Get-AbrOntapVserverVolumeSnapshot { $SnapPolicy = Get-NcVol $Item.Name -VserverContext $Vserver -Controller $Array | Select-Object -ExpandProperty VolumeSnapshotAttributes $inObj = [ordered] @{ 'Volume' = $Item.Name - 'Snapshot Enabled' = ConvertTo-TextYN $SnapPolicy.AutoSnapshotsEnabled - 'Reserve Size' = $SnapReserve.SnapshotReserveSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Reserve Available' = $SnapReserve.SnapshotReserveAvailable | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue - 'Used' = $SnapReserve.SizeUsedBySnapshots | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Snapshot Enabled' = $SnapPolicy.AutoSnapshotsEnabled + 'Reserve Size' = ($SnapReserve.SnapshotReserveSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Reserve Available' = ($SnapReserve.SnapshotReserveAvailable | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($SnapReserve.SizeUsedBySnapshots | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' 'Policy' = $SnapPolicy.SnapshotPolicy } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } if ($Healthcheck.Vserver.Snapshot) { - $VserverObj | Where-Object { $_.'Snapshot Enabled' -eq 'Yes' -and $_.'Reserve Available' -eq 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 = @{ @@ -63,12 +63,12 @@ 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 + if ($Healthcheck.Vserver.Snapshot -and ($VserverObj | Where-Object { $_.'Snapshot Enabled' -eq 'Yes' -and ($_.'Used'.split()[0] -gt $_.'Reserve Size'.split()[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." + 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 } diff --git a/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 similarity index 78% rename from Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 index c810933..efd6fd7 100755 --- a/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumeSnapshotHealth { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,17 +23,17 @@ function Get-AbrOntapVserverVolumeSnapshotHealth { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes snapshot healthcheck information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes snapshot healthcheck information.' } process { try { - $SnapshotDays = 7 + $SnapshotDays = 30 $Now = Get-Date $VserverFilter = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } - $SnapShotData = Get-NcSnapshot -Volume $VserverFilter -Vserver $Vserver -Controller $Array | Where-Object { $_.Name -notmatch "snapmirror.*" -and $_.Created -le $Now.AddDays(-$SnapshotDays) } + $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" { + Section -Style Heading4 'HealthCheck - Volumes Snapshot' { Paragraph "The following section provides the Vserver Volumes Snapshot HealthCheck in $($SVM)." BlankLine $VserverObj = @() @@ -43,16 +43,16 @@ function Get-AbrOntapVserverVolumeSnapshotHealth { 'Volume Name' = $Item.Volume 'Snapshot Name' = $Item.Name 'Created Time' = $Item.Created - 'Used' = $Item.Total | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Used' = ($Item.Total | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } $TableParams = @{ - Name = "HealthCheck - Volume Snapshot over 7 days - $($Vserver)" + Name = "HealthCheck - Volume Snapshot over $($SnapshotDays) days - $($Vserver)" List = $false ColumnWidths = 25, 35, 25, 15 } diff --git a/Src/Private/Get-AbrOntapVserverVolumes.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumes.ps1 similarity index 52% rename from Src/Private/Get-AbrOntapVserverVolumes.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumes.ps1 index 04d2a04..98a5dc8 100755 --- a/Src/Private/Get-AbrOntapVserverVolumes.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumes.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolume { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverVolume { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes information.' } process { @@ -36,19 +36,19 @@ function Get-AbrOntapVserverVolume { $inObj = [ordered] @{ 'Volume' = $Item.Name 'Status' = $Item.State - 'Capacity' = $Item.Totalsize | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue - 'Available' = $Item.Available | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue - 'Used' = $Item.Used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue + 'Capacity' = ($Item.Totalsize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Available' = ($Item.Available | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Used' = ($Item.Used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' 'Aggregate' = $Item.Aggregate } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } 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 { [int]$_.'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' })) { - Paragraph "Health Check:" -Bold -Underline + 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 { [int]$_.'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/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesAutosize.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesAutosize.ps1 new file mode 100644 index 0000000..8258929 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesAutosize.ps1 @@ -0,0 +1,69 @@ +function Get-AbrOntapVserverVolumesAutosize { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver per volumes autosize attributes information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP Vserver per volumes autosize attributes information.' + } + + process { + try { + $VolumeFilter = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } + $OutObj = @() + if ($VolumeFilter) { + foreach ($Item in $VolumeFilter) { + try { + $AutosizeAttr = $Item.VolumeAutosizeAttributes + $inObj = [ordered] @{ + 'Volume' = $Item.Name + 'Autosize Enabled' = $AutosizeAttr.IsEnabled + 'Mode' = $AutosizeAttr.Mode ?? '--' + 'Minimum Size' = ($AutosizeAttr.MinimumSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Maximum Size' = ($AutosizeAttr.MaximumSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Grow Threshold %' = ($AutosizeAttr.GrowThresholdPercent | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' + 'Shrink Threshold %' = ($AutosizeAttr.ShrinkThresholdPercent | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + $TableParams = @{ + Name = "Per Volume Autosize Attributes - $($Vserver)" + List = $false + ColumnWidths = 20, 14, 10, 14, 14, 14, 14 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 new file mode 100755 index 0000000..604b3f3 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 @@ -0,0 +1,63 @@ +function Get-AbrOntapVserverVolumesExportPolicy { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver per volumes export policy information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP Vserver per volumes export policy information.' + } + + process { + try { + $VolumeData = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } + $VolumeObj = @() + if ($VolumeData) { + foreach ($Volume in $VolumeData) { + try { + $inObj = [ordered] @{ + 'Volume Name' = $Volume.Name + 'Export Policy' = (((Get-NcVol -VS $Vserver -Controller $Array | Where-Object { $_.Name -eq $Volume.Name }).VolumeExportAttributes).Policy) ?? 'None' + } + $VolumeObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + $TableParams = @{ + Name = "Per Volume Export Policy - $($Vserver)" + List = $false + ColumnWidths = 50, 50 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $VolumeObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 similarity index 84% rename from Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 index 3ff0c21..c72c62c 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumesFlexcache { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverVolumesFlexcache { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver flexcache volumes information." + Write-PScriboMessage 'Collecting ONTAP Vserver flexcache volumes information.' } process { @@ -41,9 +41,9 @@ function Get-AbrOntapVserverVolumesFlexcache { 'Cache Volume' = $Item.CacheVolume 'Origin Vserver' = $Item.OriginVserver 'Origin Volume' = $Item.OriginVolume - 'Capacity' = $VolumeUsage.TotalSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Capacity' = ($VolumeUsage.TotalSize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -72,9 +72,9 @@ function Get-AbrOntapVserverVolumesFlexcache { 'Origin Volume' = $Item.OriginVolume 'Cache Vserver' = $Item.Vserver 'Cache Volume' = $Item.Volume - 'Capacity' = $Item.Size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Capacity' = ($Item.Size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 similarity index 68% rename from Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 index 7315427..45e0bdc 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumesFlexclone { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverVolumesFlexclone { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes flexclone information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes flexclone information.' } process { @@ -35,16 +35,16 @@ function Get-AbrOntapVserverVolumesFlexclone { $inObj = [ordered] @{ 'Volume' = $Item.Name 'Parent Volume' = $Item.ParentVolume - 'Volume Type' = $Item.VolumeType.ToUpper() + 'Volume Type' = ${Item}?.VolumeType?.ToUpper() 'Parent Snapshot' = $Item.ParentSnapshot 'Space Reserve' = $Item.SpaceReserve - 'Space Guarantee' = ConvertTo-TextYN $Item.SpaceGuaranteeEnabled - 'Capacity' = $Item.Size | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue - 'Available' = $Item.Size - $Item.Used | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue - 'Used' = $Item.Used | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue + 'Space Guarantee' = $Item.SpaceGuaranteeEnabled + 'Capacity' = ($Item.Size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Available' = ($Item.Size - $Item.Used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Used' = ($Item.Used | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' 'Aggregate' = $Item.Aggregate } - $VserverObj = [pscustomobject]$inobj + $VserverObj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Vserver.Status) { $VserverObj | Where-Object { $_.'Status' -like 'offline' } | Set-Style -Style Warning -Property 'Status' @@ -60,11 +60,11 @@ function Get-AbrOntapVserverVolumesFlexclone { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj)) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold - Text "Regularly monitor flexclone volumes to manage storage utilization effectively." + Text 'Best Practice:' -Bold + Text 'Regularly monitor flexclone volumes to manage storage utilization effectively.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 similarity index 80% rename from Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 index 2b18794..d58f158 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumesFlexgroup { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,12 +23,12 @@ function Get-AbrOntapVserverVolumesFlexgroup { ) 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) { @@ -36,9 +36,9 @@ function Get-AbrOntapVserverVolumesFlexgroup { $inObj = [ordered] @{ 'Volume' = $Item.Name 'Status' = $Item.State - 'Capacity' = $Item.Totalsize | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue + 'Capacity' = ($Item.Totalsize | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -57,10 +57,10 @@ function Get-AbrOntapVserverVolumesFlexgroup { } $OutObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($OutObj | Where-Object { $_.'Status' -like 'offline' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure all flexgroup volumes are in 'online' status to maintain data availability." } BlankLine diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesInodeAttr.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesInodeAttr.ps1 new file mode 100644 index 0000000..6edd3e9 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesInodeAttr.ps1 @@ -0,0 +1,68 @@ +function Get-AbrOntapVserverVolumesInodeAttr { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver per volumes inode attributes information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP Vserver per volumes inode attributes information.' + } + + process { + try { + $VolumeFilter = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } + $OutObj = @() + if ($VolumeFilter) { + foreach ($Item in $VolumeFilter) { + try { + $InodeAttr = $Item.VolumeInodeAttributes + $inObj = [ordered] @{ + 'Volume' = $Item.Name + 'Files Total' = $InodeAttr.FilesTotal ?? '--' + 'Files Used' = $InodeAttr.FilesUsed ?? '--' + 'Files Private Used' = $InodeAttr.FilesPrivateUsed ?? '--' + 'Inode File Private Capacity' = $InodeAttr.InodefilePrivateCapacity ?? '--' + 'Inode File Public Capacity' = $InodeAttr.InodefilePublicCapacity ?? '--' + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + $TableParams = @{ + Name = "Per Volume Inode Attributes - $($Vserver)" + List = $false + ColumnWidths = 22, 14, 14, 16, 17, 17 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesLanguage.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesLanguage.ps1 new file mode 100644 index 0000000..06ab363 --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesLanguage.ps1 @@ -0,0 +1,67 @@ +function Get-AbrOntapVserverVolumesLanguage { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver per volumes language attributes information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP Vserver per volumes language attributes information.' + } + + process { + try { + $VolumeFilter = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } + $OutObj = @() + if ($VolumeFilter) { + foreach ($Item in $VolumeFilter) { + try { + $LangAttr = $Item.VolumeLanguageAttributes + $inObj = [ordered] @{ + 'Volume' = $Item.Name + 'Language' = $LangAttr.Language ?? '--' + 'Language Code' = $LangAttr.LanguageCode ?? '--' + 'Convert Ucode Enabled' = $LangAttr.IsConvertUcodeEnabled + 'Create Ucode Enabled' = $LangAttr.IsCreateUcodeEnabled + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + $TableParams = @{ + Name = "Per Volume Language Attributes - $($Vserver)" + List = $false + ColumnWidths = 22, 30, 20, 14, 14 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} diff --git a/Src/Private/Get-AbrOntapVserverVolumesQos.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQos.ps1 similarity index 72% rename from Src/Private/Get-AbrOntapVserverVolumesQos.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQos.ps1 index fb4d293..c839444 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQos.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQos.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumesQosSetting { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,12 +23,12 @@ function Get-AbrOntapVserverVolumesQosSetting { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes qos information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes qos information.' } process { try { - $VolumeFilter = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.VolumeStateAttributes.IsConstituent -ne "True" } + $VolumeFilter = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.VolumeStateAttributes.IsConstituent -ne 'True' } $OutObj = @() if ($VolumeFilter) { foreach ($Item in $VolumeFilter) { @@ -36,16 +36,10 @@ function Get-AbrOntapVserverVolumesQosSetting { $VolQoS = Get-NcVol $Item.Name -Controller $Array | Select-Object -ExpandProperty VolumeQosAttributes $inObj = [ordered] @{ 'Volume' = $Item.Name - 'Fixed Policy Name' = Switch ($VolQoS.PolicyGroupName) { - $Null { 'None' } - default { $VolQoS.PolicyGroupName } - } - 'Adaptive Policy Name' = Switch ($VolQoS.AdaptivePolicyGroupName) { - $Null { 'None' } - default { $VolQoS.AdaptivePolicyGroupName } - } + 'Fixed Policy Name' = ($Null -eq $VolQoS.PolicyGroupName) ? 'None': $VolQoS.PolicyGroupName + 'Adaptive Policy Name' = ($Null -eq $VolQoS.PolicyGroupName) ? 'None': $VolQoS.AdaptivePolicyGroupName } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverVolumesQosGPAdaptive.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQosGPAdaptive.ps1 similarity index 89% rename from Src/Private/Get-AbrOntapVserverVolumesQosGPAdaptive.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQosGPAdaptive.ps1 index e0143db..1f68801 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQosGPAdaptive.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQosGPAdaptive.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumesQosGPAdaptive { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapVserverVolumesQosGPAdaptive { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes qos group adaptive information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes qos group adaptive information.' } process { @@ -36,7 +36,7 @@ function Get-AbrOntapVserverVolumesQosGPAdaptive { 'Min Iops' = $Item.AbsoluteMinIops 'Vserver' = $Item.Vserver } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverVolumesQosGPFixed.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQosGPFixed.ps1 similarity index 83% rename from Src/Private/Get-AbrOntapVserverVolumesQosGPFixed.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQosGPFixed.ps1 index 9e631cb..f05976b 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQosGPFixed.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQosGPFixed.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumesQosGPFixed { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,12 +19,12 @@ function Get-AbrOntapVserverVolumesQosGPFixed { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes qos group fixed information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes qos group fixed information.' } process { try { - $QoSFilter = Get-NcQosPolicyGroup -Controller $Array | Where-Object { $_.PolicyGroupClass -eq "user_defined" } + $QoSFilter = Get-NcQosPolicyGroup -Controller $Array | Where-Object { $_.PolicyGroupClass -eq 'user_defined' } $OutObj = @() if ($QoSFilter) { foreach ($Item in $QoSFilter) { @@ -33,10 +33,10 @@ function Get-AbrOntapVserverVolumesQosGPFixed { 'Policy Name' = $Item.PolicyGroup 'Max Throughput' = $Item.MaxThroughput 'Min Throughput' = $Item.MinThroughput - 'Is Shared' = ConvertTo-TextYN $Item.IsShared + 'Is Shared' = $Item.IsShared 'Vserver' = $Item.Vserver } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 similarity index 88% rename from Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 index 2bb0a03..093e998 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumesQtree { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverVolumesQtree { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes qtree information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes qtree information.' } process { @@ -40,7 +40,7 @@ function Get-AbrOntapVserverVolumesQtree { 'Security Style' = $Item.SecurityStyle 'Export Policy' = $Item.ExportPolicy } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -59,10 +59,10 @@ function Get-AbrOntapVserverVolumesQtree { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $_.'Status' -notlike 'normal' })) { - Paragraph "Health Check:" -Bold -Underline + Paragraph 'Health Check:' -Bold -Underline BlankLine Paragraph { - Text "Best Practice:" -Bold + Text 'Best Practice:' -Bold Text "Ensure all qtrees are in 'normal' status to maintain data integrity and accessibility." } BlankLine diff --git a/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 similarity index 72% rename from Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 index 0b75970..50d1a1d 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverVolumesQuota { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,7 +23,7 @@ function Get-AbrOntapVserverVolumesQuota { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes quota information." + Write-PScriboMessage 'Collecting ONTAP Vserver volumes quota information.' } process { @@ -41,7 +41,7 @@ function Get-AbrOntapVserverVolumesQuota { 'Status' = $Item.Status 'Substatus' = $Item.Substatus } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) if ($null -ne $Item.QuotaErrorMsgs) { $VserverObj.Add('Quota Error', $Item.QuotaErrorMsgs) } @@ -63,11 +63,11 @@ function Get-AbrOntapVserverVolumesQuota { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj | Where-Object { $null -ne $_.'Quota Error' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Review and resolve any quota errors to ensure proper quota enforcement and avoid potential data management issues.' } BlankLine } @@ -91,24 +91,12 @@ function Get-AbrOntapVserverVolumesQuota { 'Volume' = $Item.Volume 'Type' = $Item.QuotaType 'Target' = $Item.QuotaTarget - 'Disk Limit' = switch ($Item.DiskLimit) { - "-" { $Item.DiskLimit } - default { $Item.DiskLimit | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } - } - 'File Limit' = switch ($Item.FileLimit) { - "-" { $Item.FileLimit } - default { $Item.FileLimit | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue } - } - 'Soft Disk Limit' = switch ($Item.SoftDiskLimit) { - "-" { $Item.SoftDiskLimit } - default { $Item.SoftDiskLimit | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } - } - 'Soft File Limit' = switch ($Item.SoftFileLimit) { - "-" { $Item.SoftFileLimit } - default { $Item.SoftFileLimit | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue } - } + 'Disk Limit' = ($Item.DiskLimit | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'File Limit' = ($Item.FileLimit | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Count) ?? '--' + 'Soft Disk Limit' = ($Item.SoftDiskLimit | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Soft File Limit' = ($Item.SoftFileLimit | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Count) ?? '--' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) if ($null -ne $Item.QuotaError) { $VserverObj.Add('Quota Error', $Item.QuotaError) } @@ -148,17 +136,11 @@ function Get-AbrOntapVserverVolumesQuota { 'Volume' = $Item.Volume 'Quota Target' = $Item.QuotaTarget 'Qtree' = $Item.Qtree - 'Disk Limit' = switch ($Item.DiskLimit) { - "-" { $Item.DiskLimit } - default { $Item.DiskLimit | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } - } - 'Soft Disk Limit' = switch ($Item.SoftDiskLimit) { - "-" { $Item.SoftDiskLimit } - default { $Item.SoftDiskLimit | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue } - } - 'Disk Used' = $Item.DiskUsed | ConvertTo-FormattedNumber -Type DataSize -ErrorAction SilentlyContinue + 'Disk Limit' = ($Item.DiskLimit | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Soft Disk Limit' = ($Item.SoftDiskLimit | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Disk Used' = ($Item.DiskUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type DataSize) ?? '--' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -197,17 +179,11 @@ function Get-AbrOntapVserverVolumesQuota { 'Volume' = $Item.Volume 'Quota Target' = $Item.QuotaTarget 'Qtree' = $Item.Qtree - 'File Limit' = switch ($Item.FileLimit) { - "-" { $Item.FileLimit } - default { $Item.FileLimit | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue } - } - 'Soft File Limit' = switch ($Item.SoftFileLimit) { - "-" { $Item.SoftFileLimit } - default { $Item.SoftFileLimit | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue } - } - 'Files Used' = $Item.FilesUsed | ConvertTo-FormattedNumber -Type Count -ErrorAction SilentlyContinue + 'File Limit' = ($Item.FileLimit | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Count) ?? '--' + 'Soft File Limit' = ($Item.SoftFileLimit | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Count) ?? '--' + 'Files Used' = ($Item.FilesUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Count) ?? '--' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesSpaceAttr.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesSpaceAttr.ps1 new file mode 100644 index 0000000..5cc32eb --- /dev/null +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-AbrOntapVserverVolumesSpaceAttr.ps1 @@ -0,0 +1,69 @@ +function Get-AbrOntapVserverVolumesSpaceAttr { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver per volumes space attributes information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.12 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage 'Collecting ONTAP Vserver per volumes space attributes information.' + } + + process { + try { + $VolumeFilter = Get-NcVol -VserverContext $Vserver -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } + $OutObj = @() + if ($VolumeFilter) { + foreach ($Item in $VolumeFilter) { + try { + $SpaceAttr = $Item.VolumeSpaceAttributes + $inObj = [ordered] @{ + 'Volume' = $Item.Name + 'Total Size' = ($SpaceAttr.Size | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = ($SpaceAttr.SizeAvailable | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($SpaceAttr.SizeUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -NumberFormatString 0.0 -Type Datasize) ?? '--' + '% Used' = ($SpaceAttr.PercentageSizeUsed | ConvertTo-FormattedNumber -ErrorAction SilentlyContinue -Type Percent) ?? '--' + 'Space Guarantee' = $SpaceAttr.SpaceGuarantee ?? '--' + 'Guarantee Enabled' = $SpaceAttr.IsSpaceGuaranteeEnabled + } + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + $TableParams = @{ + Name = "Per Volume Space Attributes - $($Vserver)" + List = $false + ColumnWidths = 20, 12, 12, 12, 10, 18, 16 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} diff --git a/Src/Private/Get-NetAppOntapAPI.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-NetAppOntapAPI.ps1 similarity index 92% rename from Src/Private/Get-NetAppOntapAPI.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Private/Get-NetAppOntapAPI.ps1 index efc0e2e..8d6e12c 100644 --- a/Src/Private/Get-NetAppOntapAPI.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Private/Get-NetAppOntapAPI.ps1 @@ -5,7 +5,7 @@ function Get-NetAppOntapAPI { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Tim Carman Editor: Jonathan Colon Twitter: @jcolonfzenpr @@ -26,7 +26,7 @@ function Get-NetAppOntapAPI { ) begin { - $certCallback = @" + $certCallback = @' using System; using System.Net; using System.Net.Security; @@ -51,23 +51,23 @@ function Get-NetAppOntapAPI { } } } -"@ +'@ if ($PSVersionTable.PSEdition -ne 'Core') { #region Workaround for SelfSigned Cert an force TLS 1.2 if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type) { Add-Type $certCallback } [ServerCertificateValidationCallback]::Ignore() - [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" + [Net.ServicePointManager]::SecurityProtocol = 'tls12, tls11, tls' #endregion Workaround for SelfSigned Cert an force TLS 1.2 } $username = $Credential.UserName $password = $Credential.GetNetworkCredential().Password - $auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($username + ":" + $password )) + $auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($username + ':' + $password )) $ClusterIP = $ClusterInfo.NcController.Address.IPAddressToString #$fields = 'fields=*&return_records=true&return_timeout=15' - $api = "https://" + $($ClusterIP) + $api = 'https://' + $($ClusterIP) $headers = @{ 'Accept' = 'application/json' 'Authorization' = "Basic $auth" diff --git a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 b/AsBuiltReport.NetApp.ONTAP/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 similarity index 51% rename from Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 rename to AsBuiltReport.NetApp.ONTAP/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 index ff05765..822c9f0 100755 --- a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 +++ b/AsBuiltReport.NetApp.ONTAP/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 @@ -5,7 +5,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { .DESCRIPTION Documents the configuration of NetApp ONTAP in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Feliciano Twitter: @jcolonfzenpr Github: rebelinux @@ -15,13 +15,15 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { https://github.com/AsBuiltReport/AsBuiltReport.NetApp.ONTAP #> - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Scope = "Function")] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "", Scope = "Function")] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "", Scope = "Function")] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "", Scope = "Function")] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "", Scope = "Function")] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Scope = 'Function')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUserNameAndPassWordParams', '', Scope = 'Function')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '', Scope = 'Function')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Scope = 'Function')] #Requires -RunAsAdministrator + #Requires -Version 7.5 + #Requires -PSEdition Core # Do not remove or add to these parameters param ( @@ -29,50 +31,52 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { [PSCredential] $Credential ) - #Requires -RunAsAdministrator - if ($psISE) { - Write-Error -Message "You cannot run this script inside the PowerShell ISE. Please execute it from the PowerShell Command Window." + Write-Error -Message 'You cannot run this script inside the PowerShell ISE. Please execute it from the PowerShell Command Window.' break } - Write-Host "- Please refer to the AsBuiltReport.NetApp.ONTAP github website for more detailed information about this project." - Write-Host "- Do not forget to update your report configuration file after each new version release." - 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:" - + # Import Report Configuration + $script:Report = $ReportConfig.Report + $script:InfoLevel = $ReportConfig.InfoLevel + $script:Options = $ReportConfig.Options # Check the version of the dependency modules - $ModuleArray = @('AsBuiltReport.Netapp.ONTAP', 'Diagrammer.Core') + if ($Options.UpdateCheck) { + Write-ReportModuleInfo -ModuleName 'Netapp.ONTAP' + } + Write-Host ' - To sponsor this project, please visit: ' -NoNewline + Write-Host 'https://ko-fi.com/F1F8DEV80' -ForegroundColor Cyan - foreach ($Module in $ModuleArray) { - try { - $InstalledVersion = Get-Module -ListAvailable -Name $Module -ErrorAction SilentlyContinue | Sort-Object -Property Version -Descending | Select-Object -First 1 -ExpandProperty Version + if ($Options.UpdateCheck) { + Write-Host ' - Getting dependency information:' + # Check the version of the dependency modules + $ModuleArray = @('AsBuiltReport.Core', 'AsBuiltReport.Diagram', 'NetApp.ONTAP') - if ($InstalledVersion) { - 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 + foreach ($Module in $ModuleArray) { + try { + $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." + $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 + } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message } } - # Import Report Configuration - $script:Report = $ReportConfig.Report - $script:InfoLevel = $ReportConfig.InfoLevel - $script:Options = $ReportConfig.Options - # General information $script:TextInfo = (Get-Culture).TextInfo + $script:RootPath = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent + $FontPath = Join-Path -Path $RootPath -ChildPath 'Tools/Fonts/ARIAL.TTF' + #Connect to Ontap Storage Array using supplied credentials foreach ($OntapArray in $Target) { try { @@ -101,15 +105,21 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { # Variable translating Icon to Image Path ($IconPath) $script:Images = @{ - "Ontap_LOGO" = "netapp-logo.png" - "AsBuiltReport_LOGO" = "AsBuiltReport_Logo.png" - "AsBuiltReport_Signature" = "AsBuiltReport_Signature.png" - "Ontap_Node" = "ontap_node_new.png" - "Abr_LOGO_Footer" = "AsBuiltReport.png" - "Ontap_Node_Icon" = "netapp_node_icon.png" - "Ontap_Aggregate" = "netapp_aggregate.png" - "Ontap_SVM" = "ontap_svm.png" - "Ontap_SVM_Icon" = "ontap_svm_icon.png" + 'Ontap_LOGO' = 'netapp-logo.png' + 'AsBuiltReport_LOGO' = 'AsBuiltReport_Logo.png' + 'AsBuiltReport_Signature' = 'AsBuiltReport_Signature.png' + 'Ontap_Node' = 'ontap_node_new.png' + 'Abr_LOGO_Footer' = 'AsBuiltReport.png' + 'Ontap_Node_Icon' = 'netapp_node_icon.png' + 'Ontap_Aggregate' = 'netapp_aggregate.png' + 'Ontap_SVM' = 'ontap_svm.png' + 'Ontap_SVM_Icon' = 'ontap_svm_icon.png' + 'Ontap_Network_Port' = 'network_port.png' + 'Ontap_Management_Network' = 'network-switch.png' + 'Ontap_Cluster_Network' = 'ontap_stack_switch.png' + 'Ontap_Single_Network' = 'ontap_single_switch.png' + 'Ontap_Network_Nic' = 'nic_port.png' + 'Ontap_Volume' = 'FlexVol.png' } $script:ColumnSize = $Options.DiagramColumnSize @@ -122,9 +132,9 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #region Cluster Section $ClusterDiagram = Get-AbrOntapClusterDiagram if ($ClusterDiagram) { - Export-AbrOntapDiagram -DiagramObject $ClusterDiagram -MainDiagramLabel "$($ClusterInfo.ClusterName) Cluster Diagram" -FileName "AsBuiltReport.NetApp.Ontap.Cluster" + Export-AbrOntapDiagram -DiagramObject $ClusterDiagram -MainDiagramLabel "$($ClusterInfo.ClusterName) Cluster Diagram" -FileName 'AsBuiltReport.NetApp.Ontap.Cluster' } else { - Write-PScriboMessage -IsWarning "Unable to generate the Cluster Diagram." + Write-PScriboMessage -IsWarning 'Unable to generate the Cluster Diagram.' } Write-PScriboMessage "Cluster InfoLevel set at $($InfoLevel.Cluster)." if ($InfoLevel.Cluster -gt 0) { @@ -146,23 +156,21 @@ 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 in $($ClusterInfo.ClusterName)." + Section -Style Heading2 'Nodes' { + Paragraph "The following section provides detailed information of nodes in cluster $($ClusterInfo.ClusterName)." BlankLine - Section -Style Heading3 'Node Inventory' { - Paragraph "The following section provides the node inventory in $($ClusterInfo.ClusterName)." - BlankLine + Section -Style Heading3 'Inventory' { Get-AbrOntapNode - Section -Style Heading4 'Node Vol0 Inventory' { + Section -Style Heading4 'Root Volume Vol0' { Get-AbrOntapNodeStorage } if ($InfoLevel.Node -ge 2) { - Section -Style Heading4 'Node Hardware Inventory' { + Section -Style Heading4 'Hardware Details' { Get-AbrOntapNodesHW } } - if (Get-NcServiceProcessor -Controller $Array | Where-Object { $NULL -ne $_.IpAddress -and $NULL -ne $_.MacAddress }) { - Section -Style Heading4 'Node Service-Processor Inventory' { + if (Get-NcServiceProcessor -Controller $Array) { + Section -Style Heading4 'Service-Processor' { Get-AbrOntapNodesSP } } @@ -176,20 +184,18 @@ 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 in $($ClusterInfo.ClusterName)." + Paragraph "The following section provides detailed information about the storage configuration for cluster $($ClusterInfo.ClusterName)." BlankLine - Section -Style Heading3 'Aggregate Inventory' { - Paragraph "The following section provides the Aggregates in $($ClusterInfo.ClusterName)." - BlankLine + Section -Style Heading3 'Aggregates (Local Tiers)' { if (Get-NcAggr -Controller $Array) { + Get-AbrOntapStorageAGGR $StorageAggrDiagram = Get-AbrOntapStorageAggrDiagram if ($StorageAggrDiagram) { - Export-AbrOntapDiagram -DiagramObject $StorageAggrDiagram -MainDiagramLabel "Storage Aggregate Diagram" -FileName "AsBuiltReport.NetApp.Ontap.StorageAggr" + Export-AbrOntapDiagram -DiagramObject $StorageAggrDiagram -MainDiagramLabel 'Aggregate Diagram' -FileName 'AsBuiltReport.NetApp.Ontap.Aggregate' BlankLine } else { - Write-PScriboMessage -IsWarning "Unable to generate the Storage Aggregate Diagram." + Write-PScriboMessage -IsWarning 'Unable to generate the Aggregate Diagram.' } - Get-AbrOntapStorageAGGR } if (Get-NcAggrObjectStore -Controller $Array -Aggregate (Get-NcAggr -Controller $Array).Name) { Section -Style Heading4 'FabricPool' { @@ -204,36 +210,45 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } } - Section -Style Heading3 'Disk Information' { - 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 in $($ClusterInfo.ClusterName)." + if ($InfoLevel.Storage -gt 0) { + Section -Style Heading3 'Disks' { + Paragraph "The following section provides a comprehensive summary of disk inventory and configuration across all controllers in the $($ClusterInfo.ClusterName) cluster." BlankLine - Get-AbrOntapDiskAssign - } - $Nodes = Get-NcNode -Controller $Array - foreach ($Node in $Nodes) { - Section -Style Heading4 "Disk Owned by Node $Node" { - Get-AbrOntapDiskOwner -Node $Node + Section -Style Heading4 'Per Node Disk Assignment' { + Get-AbrOntapDiskAssign + $Nodes = Get-NcNode -Controller $Array + foreach ($Node in $Nodes) { + try { + Section -ExcludeFromTOC -Style NOTOCHeading5 $Node { + Get-AbrOntapDiskOwner -Node $Node + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } } - } - Section -Style Heading4 'Disk Container Type' { - Get-AbrOntapDiskType - } - if (Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq "broken" }) { - Section -Style Heading4 'Failed Disk' { - Get-AbrOntapDiskBroken + Section -Style Heading4 'Disk Container Type' { + Get-AbrOntapDiskType } - } - if (Get-NcNode -Controller $Array | Select-Object Node | Get-NcShelf -Controller $Array -ErrorAction SilentlyContinue) { - Section -Style Heading3 'Shelf Inventory' { - Get-AbrOntapDiskShelf + if (Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq 'broken' }) { + Section -Style Heading4 'Failed Disk' { + Get-AbrOntapDiskBroken + } } - } - if ($InfoLevel.Storage -ge 2) { - Section -Style Heading4 'Disk Inventory' { - Get-AbrOntapDiskInv + if (Get-NcNode -Controller $Array | Select-Object Node | Get-NcShelf -Controller $Array -ErrorAction SilentlyContinue) { + Section -Style Heading3 'Storage Shelf' { + Get-AbrOntapDiskShelf + } + } + if (Get-NcStorageShelf -Controller $Array -ErrorAction SilentlyContinue) { + Section -Style Heading3 ' Disk Shelf' { + Get-AbrOntapDiskShelfStorage + } + } + if (Get-NcDisk -Controller $Array) { + Section -Style Heading4 'Disk Inventory' { + Get-AbrOntapDiskInv + } } } } @@ -264,6 +279,13 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# Write-PScriboMessage "Network InfoLevel set at $($InfoLevel.Network)." if ($InfoLevel.Network -gt 0) { + $NetworkDiagram = Get-AbrOntapNodeNetworkDiagram + if ($NetworkDiagram) { + Export-AbrOntapDiagram -DiagramObject $NetworkDiagram -MainDiagramLabel 'Networking Diagram' -FileName 'AsBuiltReport.NetApp.Ontap.Networking' + BlankLine + } else { + Write-PScriboMessage -IsWarning 'Unable to generate the Networking Diagram.' + } Section -Style Heading2 'Network Information' { Paragraph "The following section provides a summary of the networking features in $($ClusterInfo.ClusterName)." BlankLine @@ -276,8 +298,12 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { BlankLine $Nodes = Get-NcNode -Controller $Array foreach ($Node in $Nodes) { - Section -Style Heading5 "$Node Ports" { - Get-AbrOntapNetworkPort -Node $Node + try { + Section -Style Heading5 "$Node Ports" { + Get-AbrOntapNetworkPort -Node $Node + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } } @@ -287,10 +313,14 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { BlankLine $Nodes = Get-NcNode -Controller $Array foreach ($Node in $Nodes) { - if (Get-NcNetPortIfgrp -Node $Node -Controller $Array) { - Section -Style Heading4 "$Node IFGRP" { - Get-AbrOntapNetworkIfgrp -Node $Node + try { + if (Get-NcNetPortIfgrp -Node $Node -Controller $Array) { + Section -Style Heading4 "$Node IFGRP" { + Get-AbrOntapNetworkIfgrp -Node $Node + } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } } @@ -301,16 +331,20 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { 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 + try { + if (Get-NcNetPortVlan -Node $Node -Controller $Array) { + Section -Style Heading4 "$Node Vlans" { + Get-AbrOntapNetworkVlan -Node $Node + } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } } } - Section -Style Heading4 'Broadcast Domain' { - Get-AbrOntapNetworkBdomain + Section -Style Heading4 'Broadcast Domains' { + Get-AbrOntapNetworkBroadcastDomain } Section -Style Heading4 'Failover Groups' { Get-AbrOntapNetworkFailoverGroup @@ -320,19 +354,23 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Get-AbrOntapNetworkSubnet } } - $Vservers = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -ne "node" -and $_.VserverType -ne "system" -and $_.Vserver -notin $Options.Exclude.Vserver } | Select-Object -ExpandProperty Vserver + $Vservers = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -ne 'node' -and $_.VserverType -ne 'system' -and $_.Vserver -notin $Options.Exclude.Vserver } | Select-Object -ExpandProperty Vserver 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 in $($ClusterInfo.ClusterName)." - BlankLine - Get-AbrOntapNetworkRoute -Vserver $SVM - if ($InfoLevel.Network -ge 2) { - Section -Style Heading5 "Network Interface Routes" { - Get-AbrOntapNetworkRouteLif -Vserver $SVM + try { + if (Get-NcNetRoute -VserverContext $SVM -Controller $Array) { + Section -Style Heading4 "$SVM Vserver Routes" { + Paragraph "The following section provides the Routes information in $($ClusterInfo.ClusterName)." + BlankLine + Get-AbrOntapNetworkRoute -Vserver $SVM + if ($InfoLevel.Network -ge 2) { + Section -Style Heading5 'Network Interface Routes' { + Get-AbrOntapNetworkRouteLif -Vserver $SVM + } } } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } Section -Style Heading4 'Network Interfaces' { @@ -349,287 +387,327 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# Write-PScriboMessage "Vserver InfoLevel set at $($InfoLevel.Vserver)." if ($InfoLevel.Vserver -gt 0) { - if (Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq "data" }) { + 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 in $($ClusterInfo.ClusterName)." BlankLine - $Vservers = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq "data" -and $_.Vserver -notin $Options.Exclude.Vserver } | Select-Object -ExpandProperty Vserver + $Vservers = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq 'data' -and $_.Vserver -notin $Options.Exclude.Vserver } | Select-Object -ExpandProperty Vserver foreach ($SVM in $Vservers) { - Section -Style Heading3 "$SVM Vserver Configuration" { - Paragraph "The following section provides the configuration of the vserver $($SVM)." - BlankLine - Get-AbrOntapVserverSummary -Vserver $SVM - 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 in $($ClusterInfo.ClusterName)." - Section -Style Heading5 'Volumes Fixed QoS Policy' { - Get-AbrOntapVserverVolumesQosGPFixed - } - Section -Style Heading5 'Volumes Adaptive QoS Policy' { - Get-AbrOntapVserverVolumesQosGPAdaptive - } - } + try { + Section -Style Heading3 "$SVM Vserver Configuration" { + Paragraph "The following section provides the configuration of the vserver $($SVM)." + BlankLine + $VserverDiagram = Get-AbrOntapVserverDiagram -Vserver $SVM + if ($VserverDiagram) { + Export-AbrOntapDiagram -DiagramObject $VserverDiagram -MainDiagramLabel "$SVM Vserver Diagram" -FileName "AsBuiltReport.NetApp.Ontap.Vserver.$SVM" + } else { + Write-PScriboMessage -IsWarning "Unable to generate the $SVM Vserver Diagram." } - } - if (Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' }) { - Section -Style Heading4 "Storage Volumes" { - Get-AbrOntapVserverVolume -Vserver $SVM - if ($InfoLevel.Vserver -ge 2) { - if (Get-NcVol -VserverContext $SVM -Controller $Array | Select-Object -ExpandProperty VolumeQosAttributes) { - Section -Style Heading5 "Per Volumes QoS Policy" { - Get-AbrOntapVserverVolumesQosSetting -Vserver $SVM - } - } - } - if (Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.VolumeStateAttributes.IsFlexgroup -eq "True" }) { - Section -Style Heading4 "FlexGroup Volumes" { - Get-AbrOntapVserverVolumesFlexgroup -Vserver $SVM - } - } - if (Get-NcVolClone -VserverContext $SVM -Controller $Array) { - Section -Style Heading4 "Flexclone Volumes" { - Get-AbrOntapVserverVolumesFlexclone -Vserver $SVM - } - } - if ((Get-NcFlexcacheConnectedCache -VserverContext $SVM -Controller $Array) -or ((Get-NcFlexcache -Controller $Array).CacheVolume).count -gt 0) { - Section -Style Heading4 "Flexcache Volumes" { - Get-AbrOntapVserverVolumesFlexcache -Vserver $SVM - } + Get-AbrOntapVserverSummary -Vserver $SVM + + if (Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'data' -and $_.Vserver -notin $options.Exclude.Vserver -and $_.Vserver -eq $SVM }) { + Section -Style Heading4 'Interfaces (Lifs)' { + Get-AbrOntapVserverNetworkInterface -Vserver $SVM } } - if (Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } | Get-NcSnapshot -Controller $Array) { - Section -Style Heading4 "Volumes Snapshot Configuration" { - Get-AbrOntapVserverVolumeSnapshot -Vserver $SVM - if ($HealthCheck.Vserver.Snapshot) { - Get-AbrOntapVserverVolumeSnapshotHealth -Vserver $SVM + + 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 in $($ClusterInfo.ClusterName)." + Section -Style Heading5 'Volumes Fixed QoS Policy' { + Get-AbrOntapVserverVolumesQosGPFixed + } + Section -Style Heading5 'Volumes Adaptive QoS Policy' { + Get-AbrOntapVserverVolumesQosGPAdaptive + } } } } if (Get-NcExportRule -VserverContext $SVM -Controller $Array) { - Section -Style Heading4 "Export Policy" { - Get-AbrOntapVserverVolumesExportPolicy -Vserver $SVM - } - } - if (Get-NcQtree -VserverContext $SVM -Controller $Array | Where-Object { $NULL -ne $_.Qtree }) { - Section -Style Heading4 "Qtrees" { - Get-AbrOntapVserverVolumesQtree -Vserver $SVM + Section -Style Heading4 'Export Policies' { + Get-AbrOntapVserverExportPolicy -Vserver $SVM } } - if (Get-NcQuota -VserverContext $SVM -Controller $Array) { - Section -Style Heading4 "Volume Quota" { - Get-AbrOntapVserverVolumesQuota -Vserver $SVM - } - } - } - Section -Style Heading4 "Protocol Information" { - 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 in $($SVM)." - BlankLine - Get-AbrOntapVserverNFSSummary -Vserver $SVM - if ($InfoLevel.Vserver -ge 2) { - Section -ExcludeFromTOC -Style Heading6 "NFS Options" { - Get-AbrOntapVserverNFSOption -Vserver $SVM - } - } - if (Get-NcVserver -VserverContext $SVM -Controller $Array | Where-Object { $_.VserverType -eq 'data' -and $_.AllowedProtocols -eq 'nfs' -and $_.State -eq 'running' } | Get-NcNfsExport) { - Section -ExcludeFromTOC -Style Heading6 "NFS Volume Export" { - Get-AbrOntapVserverNFSExport -Vserver $SVM + if (Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' }) { + Section -Style Heading4 'Storage Volumes' { + Get-AbrOntapVserverVolume -Vserver $SVM + if ((Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } | Select-Object -ExpandProperty VolumeExportAttributes) ) { + Section -Style Heading5 'Per Volumes Export Policies' { + Get-AbrOntapVserverVolumesExportPolicy -Vserver $SVM } } - } - } - #---------------------------------------------------------------------------------------------# - # CIFS Section # - #---------------------------------------------------------------------------------------------# - 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 in $($SVM)." - BlankLine - Get-AbrOntapVserverCIFSSummary -Vserver $SVM if ($InfoLevel.Vserver -ge 2) { - Section -ExcludeFromTOC -Style Heading6 'CIFS Service Configuration' { - Get-AbrOntapVserverCIFSSecurity -Vserver $SVM + if (Get-NcVol -VserverContext $SVM -Controller $Array | Select-Object -ExpandProperty VolumeQosAttributes) { + Section -Style Heading5 'Per Volumes QoS Policies' { + Get-AbrOntapVserverVolumesQosSetting -Vserver $SVM + } + } + Section -Style Heading5 'Per Volumes Space Attributes' { + Get-AbrOntapVserverVolumesSpaceAttr -Vserver $SVM + } + Section -Style Heading5 'Per Volumes Autosize Attributes' { + Get-AbrOntapVserverVolumesAutosize -Vserver $SVM + } + Section -Style Heading5 'Per Volumes Inode Attributes' { + Get-AbrOntapVserverVolumesInodeAttr -Vserver $SVM } - Section -ExcludeFromTOC -Style Heading6 'CIFS Domain Controller' { - Get-AbrOntapVserverCIFSDC -Vserver $SVM + Section -Style Heading5 'Per Volumes Language Attributes' { + Get-AbrOntapVserverVolumesLanguage -Vserver $SVM } } - Section -ExcludeFromTOC -Style Heading6 'CIFS Local Group' { - Get-AbrOntapVserverCIFSLocalGroup -Vserver $SVM + if (Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' -and $_.VolumeStateAttributes.IsFlexgroup -eq 'True' }) { + Section -Style Heading4 'FlexGroup Volumes' { + Get-AbrOntapVserverVolumesFlexgroup -Vserver $SVM + } } - Section -ExcludeFromTOC -Style Heading6 'CIFS Local Group Members' { - Get-AbrOntapVserverCIFSLGMember -Vserver $SVM + if (Get-NcVolClone -VserverContext $SVM -Controller $Array) { + Section -Style Heading4 'Flexclone Volumes' { + Get-AbrOntapVserverVolumesFlexclone -Vserver $SVM + } } - if ($InfoLevel.Vserver -ge 2) { - Section -ExcludeFromTOC -Style Heading6 'CIFS Options' { - Get-AbrOntapVserverCIFSOption -Vserver $SVM + if ((Get-NcFlexcacheConnectedCache -VserverContext $SVM -Controller $Array) -or ((Get-NcFlexcache -Controller $Array).CacheVolume).count -gt 0) { + Section -Style Heading4 'Flexcache Volumes' { + Get-AbrOntapVserverVolumesFlexcache -Vserver $SVM } } - Section -ExcludeFromTOC -Style Heading6 'CIFS Share' { - Get-AbrOntapVserverCIFSShare -Vserver $SVM + } + if (Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' } | Get-NcSnapshot -Controller $Array) { + Section -Style Heading4 'Volumes Snapshot Configuration' { + Get-AbrOntapVserverVolumeSnapshot -Vserver $SVM + if ($HealthCheck.Vserver.Snapshot) { + Get-AbrOntapVserverVolumeSnapshotHealth -Vserver $SVM + } } - Section -ExcludeFromTOC -Style Heading6 'CIFS Share Configuration' { - Get-AbrOntapVserverCIFSShareProp -Vserver $SVM + } + if (Get-NcQtree -VserverContext $SVM -Controller $Array | Where-Object { $NULL -ne $_.Qtree }) { + Section -Style Heading4 'Qtrees' { + Get-AbrOntapVserverVolumesQtree -Vserver $SVM } - if ($InfoLevel.Vserver -ge 2) { - if (Get-NcCifsSession -VserverContext $SVM -Controller $Array) { - Section -ExcludeFromTOC -Style Heading6 'CIFS Sessions' { - Get-AbrOntapVserverCIFSSession -Vserver $SVM - } - } + } + if (Get-NcQuota -VserverContext $SVM -Controller $Array) { + Section -Style Heading4 'Volume Quota' { + Get-AbrOntapVserverVolumesQuota -Vserver $SVM } } } - #---------------------------------------------------------------------------------------------# - # NVME Section # - #---------------------------------------------------------------------------------------------# - 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 in $($SVM)." - BlankLine - # Get-AbrOntapVserverNvmeSummary -Vserver $SVM - if (Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'fibre_channel' }) { - Section -ExcludeFromTOC -Style Heading6 'Nvme FC Physical Adapter' { - Get-AbrOntapVserverNvmeFcAdapter -Vserver $SVM + Section -Style Heading4 'Protocol Information' { + 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 in $($SVM)." + BlankLine + Get-AbrOntapVserverNFSSummary -Vserver $SVM + if ($InfoLevel.Vserver -ge 2) { + Section -ExcludeFromTOC -Style Heading6 'NFS Options' { + Get-AbrOntapVserverNFSOption -Vserver $SVM + } } - } - if (Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'ethernet' }) { - Section -ExcludeFromTOC -Style Heading6 'Nvme TCP Physical Adapter' { - Get-AbrOntapVserverNvmeTcpAdapter -Vserver $SVM + if (Get-NcVserver -VserverContext $SVM -Controller $Array | Where-Object { $_.VserverType -eq 'data' -and $_.AllowedProtocols -eq 'nfs' -and $_.State -eq 'running' } | Get-NcNfsExport) { + Section -ExcludeFromTOC -Style Heading6 'NFS Volume Export' { + Get-AbrOntapVserverNFSExport -Vserver $SVM + } } } - Section -ExcludeFromTOC -Style Heading6 'NVME Interfaces' { - Get-AbrOntapVserverNvmeInterface -Vserver $SVM + } + #---------------------------------------------------------------------------------------------# + # CIFS Section # + #---------------------------------------------------------------------------------------------# + 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 in $($SVM)." + BlankLine + Get-AbrOntapVserverCIFSSummary -Vserver $SVM + if ($InfoLevel.Vserver -ge 2) { + Section -ExcludeFromTOC -Style Heading6 'CIFS Service Configuration' { + Get-AbrOntapVserverCIFSSecurity -Vserver $SVM + } + Section -ExcludeFromTOC -Style Heading6 'CIFS Domain Controller' { + Get-AbrOntapVserverCIFSDC -Vserver $SVM + } + } + if (Get-NcCifsLocalGroup -VserverContext $SVM -Controller $Array) { + Section -ExcludeFromTOC -Style Heading6 'CIFS Local Group' { + Get-AbrOntapVserverCIFSLocalGroup -Vserver $SVM + } + } + if (Get-NcCifsLocalGroupMember -VserverContext $SVM -Controller $Array) { + Section -ExcludeFromTOC -Style Heading6 'CIFS Local Group Members' { + Get-AbrOntapVserverCIFSLGMember -Vserver $SVM + } + } + if ($InfoLevel.Vserver -ge 2) { + Section -ExcludeFromTOC -Style Heading6 'CIFS Options' { + Get-AbrOntapVserverCIFSOption -Vserver $SVM + } + } + if (Get-NcCifsShare -VserverContext $SVM -Controller $Array) { + Section -ExcludeFromTOC -Style Heading6 'CIFS Share' { + Get-AbrOntapVserverCIFSShare -Vserver $SVM + } + Section -ExcludeFromTOC -Style Heading6 'CIFS Share Configuration' { + Get-AbrOntapVserverCIFSShareProp -Vserver $SVM + } + } + if ($InfoLevel.Vserver -ge 2) { + if (Get-NcCifsSession -VserverContext $SVM -Controller $Array) { + Section -ExcludeFromTOC -Style Heading6 'CIFS Sessions' { + Get-AbrOntapVserverCIFSSession -Vserver $SVM + } + } + } } } - } - #---------------------------------------------------------------------------------------------# - # ISCSI Section # - #---------------------------------------------------------------------------------------------# - if ( Get-NcIscsiService -Controller $Array | Where-Object { $_.Vserver -eq $SVM } ) { - Section -Style Heading5 "ISCSI Services" { - Paragraph "The following section provides the ISCSI Service Information in $($SVM)." - BlankLine - Get-AbrOntapVserverIscsiSummary -Vserver $SVM - Section -ExcludeFromTOC -Style Heading6 "ISCSI Interfaces" { - Get-AbrOntapVserverIscsiInterface -Vserver $SVM + #---------------------------------------------------------------------------------------------# + # NVME Section # + #---------------------------------------------------------------------------------------------# + 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 in $($SVM)." + BlankLine + # Get-AbrOntapVserverNvmeSummary -Vserver $SVM + if (Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'fibre_channel' }) { + Section -ExcludeFromTOC -Style Heading6 'Nvme FC Physical Adapter' { + Get-AbrOntapVserverNvmeFcAdapter -Vserver $SVM + } + } + if (Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'ethernet' }) { + Section -ExcludeFromTOC -Style Heading6 'Nvme TCP Physical Adapter' { + Get-AbrOntapVserverNvmeTcpAdapter -Vserver $SVM + } + } + Section -ExcludeFromTOC -Style Heading6 'NVME Interfaces' { + Get-AbrOntapVserverNvmeInterface -Vserver $SVM + } } + } + #---------------------------------------------------------------------------------------------# + # ISCSI Section # + #---------------------------------------------------------------------------------------------# + if ( Get-NcIscsiService -Controller $Array | Where-Object { $_.Vserver -eq $SVM } ) { + Section -Style Heading5 'ISCSI Services' { + Paragraph "The following section provides the ISCSI Service Information in $($SVM)." + BlankLine + Get-AbrOntapVserverIscsiSummary -Vserver $SVM + Section -ExcludeFromTOC -Style Heading6 'ISCSI Interfaces' { + Get-AbrOntapVserverIscsiInterface -Vserver $SVM + } - $ISCSIClientInitiators = Get-AbrOntapVserverIscsiInitiator -Vserver $SVM - if ($ISCSIClientInitiators) { - Section -ExcludeFromTOC -Style Heading6 "ISCSI Client Initiators" { - $ISCSIClientInitiators + $ISCSIClientInitiators = Get-AbrOntapVserverIscsiInitiator -Vserver $SVM + if ($ISCSIClientInitiators) { + Section -ExcludeFromTOC -Style Heading6 'ISCSI Client Initiators' { + $ISCSIClientInitiators + } } } } - } - #---------------------------------------------------------------------------------------------# - # FCP Section # - #---------------------------------------------------------------------------------------------# - 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 in $($SVM)." - BlankLine - Get-AbrOntapVserverFcpSummary -Vserver $SVM - Section -ExcludeFromTOC -Style Heading6 'FCP Physical Adapter' { - Get-AbrOntapVserverFcpAdapter - } - Section -ExcludeFromTOC -Style Heading6 'FCP Interfaces' { - Get-AbrOntapVserverFcpInterface -Vserver $SVM + #---------------------------------------------------------------------------------------------# + # FCP Section # + #---------------------------------------------------------------------------------------------# + 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 in $($SVM)." + BlankLine + Get-AbrOntapVserverFcpSummary -Vserver $SVM + Section -ExcludeFromTOC -Style Heading6 'FCP Physical Adapter' { + Get-AbrOntapVserverFcpAdapter + } + Section -ExcludeFromTOC -Style Heading6 'FCP Interfaces' { + Get-AbrOntapVserverFcpInterface -Vserver $SVM + } } } - } - #---------------------------------------------------------------------------------------------# - # Lun Storage Section # - #---------------------------------------------------------------------------------------------# - if (Get-NcLun -Controller $Array | Where-Object { $_.Vserver -eq $SVM }) { - Section -Style Heading5 'Lun Storage' { - 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 + #---------------------------------------------------------------------------------------------# + # Lun Storage Section # + #---------------------------------------------------------------------------------------------# + if (Get-NcLun -Controller $Array | Where-Object { $_.Vserver -eq $SVM }) { + Section -Style Heading5 'Lun Storage' { + 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 in $($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 + } } } } - } - #---------------------------------------------------------------------------------------------# - # NameSpace & Subsystem Storage Section # - #---------------------------------------------------------------------------------------------# - if (Get-NcNvmeNamespace -Controller $Array | Where-Object { $_.Vserver -eq $SVM }) { - Section -Style Heading5 'Namespace Storage' { - 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 + #---------------------------------------------------------------------------------------------# + # NameSpace & Subsystem Storage Section # + #---------------------------------------------------------------------------------------------# + if (Get-NcNvmeNamespace -Controller $Array | Where-Object { $_.Vserver -eq $SVM }) { + Section -Style Heading5 'Namespace Storage' { + 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 in $($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 + } } } } - } - #---------------------------------------------------------------------------------------------# - # Consistency Groups Section # - #---------------------------------------------------------------------------------------------# - $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 in $($SVM)." - BlankLine - Get-AbrOntapVserverCGSummary -Vserver $SVM - foreach ($CG in $CGs) { - if ($CG.luns) { - Section -ExcludeFromTOC -Style Heading6 "$($CG.name) Luns" { - Get-AbrOntapVserverCGLun -CGObj $CG + #---------------------------------------------------------------------------------------------# + # Consistency Groups Section # + #---------------------------------------------------------------------------------------------# + $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 in $($SVM)." + BlankLine + Get-AbrOntapVserverCGSummary -Vserver $SVM + foreach ($CG in $CGs) { + if ($CG.luns) { + Section -ExcludeFromTOC -Style Heading6 "$($CG.name) Luns" { + Get-AbrOntapVserverCGLun -CGObj $CG + } } - } - if ($CG.namespaces) { - Section -ExcludeFromTOC -Style Heading6 "$($CG.name) Namespaces" { - Get-AbrOntapVserverCGNamespace -CGObj $CG + if ($CG.namespaces) { + Section -ExcludeFromTOC -Style Heading6 "$($CG.name) Namespaces" { + Get-AbrOntapVserverCGNamespace -CGObj $CG + } } } } } - } - #---------------------------------------------------------------------------------------------# - # S3 Section # - #---------------------------------------------------------------------------------------------# - $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 in $($SVM)." - BlankLine - Get-AbrOntapVserverS3Summary -Vserver $SVM - Section -ExcludeFromTOC -Style Heading6 'S3 Buckets' { - Get-AbrOntapVserverS3Bucket -Vserver $SVM + #---------------------------------------------------------------------------------------------# + # S3 Section # + #---------------------------------------------------------------------------------------------# + $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 in $($SVM)." + BlankLine + Get-AbrOntapVserverS3Summary -Vserver $SVM + Section -ExcludeFromTOC -Style Heading6 'S3 Buckets' { + Get-AbrOntapVserverS3Bucket -Vserver $SVM + } } } } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } } @@ -647,9 +725,9 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { BlankLine $ClusterReplicationDiagram = Get-AbrOntapClusterReplicationDiagram if ($ClusterReplicationDiagram) { - Export-AbrOntapDiagram -DiagramObject $ClusterReplicationDiagram -MainDiagramLabel "Cluster Replication Diagram" -FileName "AsBuiltReport.NetApp.Ontap.Replication" + Export-AbrOntapDiagram -DiagramObject $ClusterReplicationDiagram -MainDiagramLabel 'Cluster Replication Diagram' -FileName 'AsBuiltReport.NetApp.Ontap.Replication' } else { - Write-PScriboMessage -IsWarning "Unable to generate the Cluster Replication Diagram." + Write-PScriboMessage -IsWarning 'Unable to generate the Cluster Replication Diagram.' } Section -Style Heading3 'Cluster Peer' { Paragraph "The following section provides the Cluster Peer information in $($ClusterInfo.ClusterName)." @@ -674,7 +752,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Get-AbrOntapRepDestination } } - if (Get-NetAppOntapAPI -uri "/api/cluster/mediators?") { + if (Get-NetAppOntapAPI -uri '/api/cluster/mediators?') { Section -Style Heading5 'Ontap Mediator' { Get-AbrOntapRepMediator } @@ -688,7 +766,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------y Write-PScriboMessage "Efficiency InfoLevel set at $($InfoLevel.Efficiency)." if ($InfoLevel.Efficiency -gt 0) { - $Vservers = Get-NcVserver -Controller $Array | Where-Object { $_.VserverType -eq "data" -and $_.Vserver -notin $Options.Exclude.Vserver } | Select-Object -ExpandProperty Vserver + $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 in $($ClusterInfo.ClusterName)." @@ -699,19 +777,23 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { BlankLine Get-AbrOntapEfficiencyAggr foreach ($SVM in $Vservers) { - $VolFilter = Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { ($_.State -eq "online") -and ($_.Name -ne "vol0") } - if (Get-NcEfficiency -Volume $VolFilter.Name[0] -Vserver $SVM -Controller $Array) { - Section -Style Heading4 "$SVM Vserver Volume Deduplication" { - Get-AbrOntapEfficiencyVolSisStatus -Vserver $SVM - Section -Style Heading5 "Volume Efficiency" { - Get-AbrOntapEfficiencyVol -Vserver $SVM - } - if ($InfoLevel.Efficiency -ge 2) { - Section -Style Heading5 "Detailed Volume Efficiency" { - Get-AbrOntapEfficiencyVolDetailed -Vserver $SVM + try { + $VolFilter = Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { ($_.State -eq 'online') -and ($_.Name -ne 'vol0') } + if ($VolFilter -and (Get-NcEfficiency -Volume $VolFilter.Name[0] -Vserver $SVM -Controller $Array)) { + Section -Style Heading4 "$SVM Vserver Volume Deduplication" { + Get-AbrOntapEfficiencyVolSisStatus -Vserver $SVM + Section -Style Heading5 'Volume Efficiency' { + Get-AbrOntapEfficiencyVol -Vserver $SVM + } + if ($InfoLevel.Efficiency -ge 2) { + Section -Style Heading5 'Detailed Volume Efficiency' { + Get-AbrOntapEfficiencyVolDetailed -Vserver $SVM + } } } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } } @@ -724,20 +806,24 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# Write-PScriboMessage "Security InfoLevel set at $($InfoLevel.Security)." 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 + $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 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 in $($SVM)." - BlankLine - Get-AbrOntapSecurityUser -Vserver $SVM + try { + if (Get-NcUser -Vserver $SVM -Controller $Array) { + Section -Style Heading3 "$SVM Vserver Local User" { + Paragraph "The following section provides the Local User information in $($SVM)." + BlankLine + Get-AbrOntapSecurityUser -Vserver $SVM + } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } - $MAPData = Get-NetAppOntapAPI -uri "/api/security/multi-admin-verify/approval-groups?fields=**&return_records=true&return_timeout=15" + $MAPData = Get-NetAppOntapAPI -uri '/api/security/multi-admin-verify/approval-groups?fields=**&return_records=true&return_timeout=15' if ($MAPData) { Section -Style Heading3 'Multi-Admin Approval Configuration' { Paragraph "The following section provides information about Multi-Admin Approval from $($ClusterInfo.ClusterName)." @@ -794,7 +880,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Section -Style Heading5 'Volume Snaplock Type' { Get-AbrOntapSecuritySnapLockVol if ($InfoLevel.Security -ge 2) { - if (Get-NcVol -Controller $Array | Where-Object { $_.VolumeSnaplockAttributes.SnaplockType -in "enterprise", "compliance" }) { + if (Get-NcVol -Controller $Array | Where-Object { $_.VolumeSnaplockAttributes.SnaplockType -in 'enterprise', 'compliance' }) { Section -ExcludeFromTOC -Style Heading6 'Snaplock Volume Attributes' { Get-AbrOntapSecuritySnapLockVollAttr } @@ -841,10 +927,14 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { if ($InfoLevel.System -ge 2) { $Nodes = Get-NcNode -Controller $Array foreach ($Node in $Nodes) { - if (Get-NcConfigBackup -Node $Node -Controller $Array) { - Section -Style Heading4 "$Node Configuration" { - Get-AbrOntapSysConfigBackup -Node $Node + try { + if (Get-NcConfigBackup -Node $Node -Controller $Array) { + Section -Style Heading4 "$Node Configuration" { + Get-AbrOntapSysConfigBackup -Node $Node + } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } } @@ -858,10 +948,14 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { if ($InfoLevel.System -ge 2) { $Nodes = Get-NcNode -Controller $Array foreach ($Node in $Nodes) { - if ($HealthCheck.System.EMS -and (Get-NcEmsMessage -Node $Node -Severity "emergency", "alert" -Controller $Array | Select-Object -First 30)) { - Section -Style Heading4 "$Node Emergency and Alert Messages" { - Get-AbrOntapSysConfigEMS -Node $Node + try { + if ($HealthCheck.System.EMS -and (Get-NcEmsMessage -Node $Node -Severity 'emergency', 'alert' -Controller $Array | Select-Object -First 30)) { + Section -Style Heading4 "$Node Emergency and Alert Messages" { + Get-AbrOntapSysConfigEMS -Node $Node + } } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message } } } diff --git a/icons/AsBuiltReport_Logo.png b/AsBuiltReport.NetApp.ONTAP/icons/AsBuiltReport_Logo.png similarity index 100% rename from icons/AsBuiltReport_Logo.png rename to AsBuiltReport.NetApp.ONTAP/icons/AsBuiltReport_Logo.png diff --git a/icons/AsBuiltReport_Signature.png b/AsBuiltReport.NetApp.ONTAP/icons/AsBuiltReport_Signature.png similarity index 100% rename from icons/AsBuiltReport_Signature.png rename to AsBuiltReport.NetApp.ONTAP/icons/AsBuiltReport_Signature.png diff --git a/AsBuiltReport.NetApp.ONTAP/icons/Disk.png b/AsBuiltReport.NetApp.ONTAP/icons/Disk.png new file mode 100644 index 0000000..4cb66ea Binary files /dev/null and b/AsBuiltReport.NetApp.ONTAP/icons/Disk.png differ diff --git a/AsBuiltReport.NetApp.ONTAP/icons/FlexVol.png b/AsBuiltReport.NetApp.ONTAP/icons/FlexVol.png new file mode 100644 index 0000000..3fd51a5 Binary files /dev/null and b/AsBuiltReport.NetApp.ONTAP/icons/FlexVol.png differ diff --git a/AsBuiltReport.NetApp.ONTAP/icons/RaidGroup.png b/AsBuiltReport.NetApp.ONTAP/icons/RaidGroup.png new file mode 100644 index 0000000..027a3b1 Binary files /dev/null and b/AsBuiltReport.NetApp.ONTAP/icons/RaidGroup.png differ diff --git a/icons/netapp-logo.png b/AsBuiltReport.NetApp.ONTAP/icons/netapp-logo.png similarity index 100% rename from icons/netapp-logo.png rename to AsBuiltReport.NetApp.ONTAP/icons/netapp-logo.png diff --git a/icons/netapp_aggregate.png b/AsBuiltReport.NetApp.ONTAP/icons/netapp_aggregate.png similarity index 100% rename from icons/netapp_aggregate.png rename to AsBuiltReport.NetApp.ONTAP/icons/netapp_aggregate.png diff --git a/icons/netapp_node.png b/AsBuiltReport.NetApp.ONTAP/icons/netapp_node.png similarity index 100% rename from icons/netapp_node.png rename to AsBuiltReport.NetApp.ONTAP/icons/netapp_node.png diff --git a/icons/netapp_node_icon.png b/AsBuiltReport.NetApp.ONTAP/icons/netapp_node_icon.png similarity index 100% rename from icons/netapp_node_icon.png rename to AsBuiltReport.NetApp.ONTAP/icons/netapp_node_icon.png diff --git a/AsBuiltReport.NetApp.ONTAP/icons/network-switch.png b/AsBuiltReport.NetApp.ONTAP/icons/network-switch.png new file mode 100644 index 0000000..a51e7e1 Binary files /dev/null and b/AsBuiltReport.NetApp.ONTAP/icons/network-switch.png differ diff --git a/AsBuiltReport.NetApp.ONTAP/icons/network_port.png b/AsBuiltReport.NetApp.ONTAP/icons/network_port.png new file mode 100644 index 0000000..fa6b0d6 Binary files /dev/null and b/AsBuiltReport.NetApp.ONTAP/icons/network_port.png differ diff --git a/AsBuiltReport.NetApp.ONTAP/icons/nic_port.png b/AsBuiltReport.NetApp.ONTAP/icons/nic_port.png new file mode 100644 index 0000000..dd984ba Binary files /dev/null and b/AsBuiltReport.NetApp.ONTAP/icons/nic_port.png differ diff --git a/icons/no_icon.png b/AsBuiltReport.NetApp.ONTAP/icons/no_icon.png similarity index 100% rename from icons/no_icon.png rename to AsBuiltReport.NetApp.ONTAP/icons/no_icon.png diff --git a/icons/ontap_node_new.png b/AsBuiltReport.NetApp.ONTAP/icons/ontap_node_new.png similarity index 100% rename from icons/ontap_node_new.png rename to AsBuiltReport.NetApp.ONTAP/icons/ontap_node_new.png diff --git a/AsBuiltReport.NetApp.ONTAP/icons/ontap_single_switch.png b/AsBuiltReport.NetApp.ONTAP/icons/ontap_single_switch.png new file mode 100644 index 0000000..f6f8add Binary files /dev/null and b/AsBuiltReport.NetApp.ONTAP/icons/ontap_single_switch.png differ diff --git a/AsBuiltReport.NetApp.ONTAP/icons/ontap_stack_switch.png b/AsBuiltReport.NetApp.ONTAP/icons/ontap_stack_switch.png new file mode 100644 index 0000000..ace130f Binary files /dev/null and b/AsBuiltReport.NetApp.ONTAP/icons/ontap_stack_switch.png differ diff --git a/icons/ontap_svm.png b/AsBuiltReport.NetApp.ONTAP/icons/ontap_svm.png similarity index 100% rename from icons/ontap_svm.png rename to AsBuiltReport.NetApp.ONTAP/icons/ontap_svm.png diff --git a/icons/ontap_svm_icon.png b/AsBuiltReport.NetApp.ONTAP/icons/ontap_svm_icon.png similarity index 100% rename from icons/ontap_svm_icon.png rename to AsBuiltReport.NetApp.ONTAP/icons/ontap_svm_icon.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f3bde6..cd1d749 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,54 @@ 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.12] - 2026-03-16 + +### Added + +- Add Vserver resources diagram showing SVM information, allocated aggregates, and network interfaces (LIFs) +- Add Network ports diagram showing all network ports and their associated LIFs +- Add Volume resources usage to the vserver diagram +- Add node owner (Home Node) to network interface tables (Vserver, Cluster, Management, Intercluster, and Data network interfaces) +- Add Health Check best practices for Network Broadcast Domains +- Add Health Check best practices for NTP configuration + - Recommend multiple NTP servers for redundancy +- Add Per Volume export policy information +- Add `Node Name` to FCP Interfaces section in FCP Vserver configuration +- Apply powershell best practices +- Add ConvertTo-HashToYN function +- Add EMS configuration setting health check +- Add support for charts + - Aggregate Usage + - Per Node Disk Assignment + +### Changed + +- Migrate from Diagrammer.Core to AsBuiltReport.Diagram for diagram generation +- Bump AsBuiltReport.Chart module requirement to v0.3.0 +- Bump AsBuiltReport.Core module requirement to v1.6.2 +- Bump NetApp.ONTAP module requirement to v9.18.1.2601 +- Bump module version to v0.6.12 +- Update github actions to use latest version +- Export diagrams by default +- Improved Cluster diagram to show Broadcast Domains and network ports per node +- Reorganize module structure - moved module files to AsBuiltReport.System.Resources/ subdirectory + +### Fixed + +- Fix snapshot reserve space health check to use correct calculation method +- 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 +- Fix diagram size not respecting document border size +- Fix HealthCheck - Volume without deduplication section displaying incorrect values +- Fix type conversion for volume usage percentage checks in Get-AbrOntapVserverVolume function +- Fix: Join management addresses into a comma-separated string in cluster and node diagrams + +### Removed + +- Removed Pwsh v5.1 support + ## [0.6.11] - 2025-11-07 ### Added diff --git a/README.md b/README.md index 27f4df1..a256f21 100755 --- a/README.md +++ b/README.md @@ -48,15 +48,15 @@ Below are the instructions on how to install, configure and generate a NetApp ON The ONTAP Storage As Built Report supports the following ONTAP versions; - ONTAP 9.x - - Tested on v9.5, 9.7, 9.8, 9.9.1, 9.10.1, 9.11.1, 9.12.1, 9.13.1, 9.14.1, 9.15.1, 9.16.1, 9.17.1 + - Tested on v9.5, 9.7, 9.8, 9.9.1, 9.10.1, 9.11.1, 9.12.1, 9.13.1, 9.14.1, 9.15.1, 9.16.1, 9.17.1, 9.18.1 ### **PowerShell** 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 @@ -64,17 +64,19 @@ Each of the following modules will be automatically installed by following the [ These modules may also be manually installed. -| Module Name | Minimum Required Version | PS Gallery | GitHub | -| ------------------ | :----------------------: | :-------------------------------------------------------------------: | :-------------------------------------------------------------------------: | -| PScribo | 0.10.0 | [Link](https://www.powershellgallery.com/packages/PScribo) | [Link](https://github.com/iainbrighton/PScribo/tree/master) | -| AsBuiltReport.Core | 1.5.0 | [Link](https://www.powershellgallery.com/packages/AsBuiltReport.Core) | [Link](https://github.com/AsBuiltReport/AsBuiltReport.Core/releases/latest) | -| Netapp.ONTAP | 9.17.1.2509 | [Link](https://www.powershellgallery.com/packages/NetApp.ONTAP) | | +| Module Name | Minimum Required Version | PS Gallery | GitHub | +| --------------------- | :----------------------: | :----------------------------------------------------------------------: | :-------------------------------------------------------------------------: | +| PScribo | 0.11.1 | [Link](https://www.powershellgallery.com/packages/PScribo) | [Link](https://github.com/iainbrighton/PScribo/tree/master) | +| AsBuiltReport.Core | 1.6.2 | [Link](https://www.powershellgallery.com/packages/AsBuiltReport.Core) | [Link](https://github.com/AsBuiltReport/AsBuiltReport.Core/releases/latest) | +| Netapp.ONTAP | 9.18.1.2601 | [Link](https://www.powershellgallery.com/packages/NetApp.ONTAP) | [Link](https://github.com/NetApp/ontap-powershell-modules) | +| AsBuiltReport.Chart | 0.3.0 | [Link](https://www.powershellgallery.com/packages/AsBuiltReport.Chart) | [Link](https://github.com/AsBuiltReport/AsBuiltReport.Chart) | +| AsBuiltReport.Diagram | 1.0.3 | [Link](https://www.powershellgallery.com/packages/AsBuiltReport.Diagram) | [Link](https://github.com/AsBuiltReport/AsBuiltReport.Diagram) | ## :package: Module Installation ### 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/Samples/Sample NetApp As-Built Report.html b/Samples/Sample NetApp As-Built Report.html index ddd6bfd..0921517 100755 --- a/Samples/Sample NetApp As-Built Report.html +++ b/Samples/Sample NetApp As-Built Report.html @@ -8,31 +8,31 @@ hr { margin-top: 1.0rem; } .portrait { background: white; width: 210mm; display: block; margin-top: 1rem; margin-left: auto; margin-right: auto; margin-bottom: 1rem; position: relative; border-style: solid; border-width: 1px; border-color: #c6c6c6; } .landscape { background: white; width: 297mm; display: block; margin-top: 1rem; margin-left: auto; margin-right: auto; margin-bottom: 1rem; position: relative; border-style: solid; border-width: 1px; border-color: #c6c6c6; } - .NOTOCHeading7 { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; font-style: italic; color: #00ebcd; } - .NOTOCHeading5 { font-family: 'Segoe Ui'; font-size: 0.92rem; text-align: left; font-weight: normal; color: #009684; } - .Caption { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; font-style: italic; color: #072e58; } - .TOC { font-family: 'Segoe Ui'; font-size: 1.33rem; text-align: left; font-weight: normal; color: #072e58; } + .NOTOCHeading6 { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #009683; } + .Footer { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: center; font-weight: normal; color: #565656; } .Heading4 { font-family: 'Segoe Ui'; font-size: 1.00rem; text-align: left; font-weight: normal; color: #958026; } + .Warning { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; background-color: #fff4c7; } + .Heading5 { font-family: 'Segoe Ui'; font-size: 0.92rem; text-align: left; font-weight: normal; color: #009684; } + .Heading3 { font-family: 'Segoe Ui'; font-size: 1.08rem; text-align: left; font-weight: normal; color: #395879; } + .Heading1 { font-family: 'Segoe Ui'; font-size: 1.33rem; text-align: left; font-weight: normal; color: #072e58; } + .Title { font-family: 'Segoe Ui'; font-size: 2.00rem; text-align: center; font-weight: normal; color: #072e58; } .Header { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: center; font-weight: normal; color: #565656; } + .TableDefaultHeading { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #fafafa; background-color: #072e58; } + .OK { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; background-color: #dff0d0; } + .Caption { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; font-style: italic; color: #072e58; } + .Title2 { font-family: 'Segoe Ui'; font-size: 1.50rem; text-align: center; font-weight: normal; color: #204369; } + .TableDefaultAltRow { font-family: 'Calibri','Candara','Segoe','Segoe UI','Optima','Arial','Sans-Serif'; font-size: 0.92rem; text-align: left; font-weight: normal; color: #000000; background-color: #d0ddee; } + .Heading6 { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #009683; } + .Normal { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; } + .TableDefaultRow { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; } .Heading2 { font-family: 'Segoe Ui'; font-size: 1.17rem; text-align: left; font-weight: normal; color: #204369; } + .TOC { font-family: 'Segoe Ui'; font-size: 1.33rem; text-align: left; font-weight: normal; color: #072e58; } .NOTOCHeading4 { font-family: 'Segoe Ui'; font-size: 1.00rem; text-align: left; font-weight: normal; color: #958026; } - .Normal { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; } - .Title3 { font-family: 'Segoe Ui'; font-size: 1.00rem; text-align: left; font-weight: normal; color: #395879; } .Info { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; background-color: #e3f5fc; } - .TableDefaultHeading { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #fafafa; background-color: #072e58; } - .Heading1 { font-family: 'Segoe Ui'; font-size: 1.33rem; text-align: left; font-weight: normal; color: #072e58; } - .Title { font-family: 'Segoe Ui'; font-size: 2.00rem; text-align: center; font-weight: normal; color: #072e58; } - .TableDefaultRow { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; } - .Title2 { font-family: 'Segoe Ui'; font-size: 1.50rem; text-align: center; font-weight: normal; color: #204369; } - .Footer { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: center; font-weight: normal; color: #565656; } - .Warning { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; background-color: #fff4c7; } + .NOTOCHeading5 { font-family: 'Segoe Ui'; font-size: 0.92rem; text-align: left; font-weight: normal; color: #009684; } + .Title3 { font-family: 'Segoe Ui'; font-size: 1.00rem; text-align: left; font-weight: normal; color: #395879; } + .NOTOCHeading7 { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; font-style: italic; color: #00ebcd; } .Critical { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; background-color: #feddd7; } - .Heading6 { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #009683; } - .TableDefaultAltRow { font-family: 'Calibri','Candara','Segoe','Segoe UI','Optima','Arial','Sans-Serif'; font-size: 0.92rem; text-align: left; font-weight: normal; color: #000000; background-color: #d0ddee; } - .NOTOCHeading6 { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #009683; } - .OK { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #565656; background-color: #dff0d0; } - .Heading5 { font-family: 'Segoe Ui'; font-size: 0.92rem; text-align: left; font-weight: normal; color: #009684; } - .Heading3 { font-family: 'Segoe Ui'; font-size: 1.08rem; text-align: left; font-weight: normal; color: #395879; } table.tabledefault { padding: 0.08rem 0.17rem 0.13rem 0.17rem; border-style: solid; border-width: 0.02rem; border-color: #072e58; border-collapse: collapse; } table.tabledefault th { font-family: 'Segoe Ui'; font-size: 0.83rem; text-align: left; font-weight: normal; color: #fafafa; background-color: #072e58; padding: 0.08rem 0.17rem 0.13rem 0.17rem; border-style: solid; border-width: 0.02rem; border-color: #072e58; border-collapse: collapse; } table.tabledefault td { padding: 0.08rem 0.17rem 0.13rem 0.17rem; border-style: solid; border-width: 0.02rem; border-color: #072e58; border-collapse: collapse; } @@ -49,401 +49,847 @@











AsBuiltReport Logo
-
NetApp ONTAP As Built Report

Acme Inc.






















- - +
NetApp ONTAP As Built Report

As Built Report






















Author:Jonathan Colon
Date:Friday, August 22, 2025
+ +
Author:As Built Report
Date:Tuesday, February 3, 2026
Version:1.0

NetApp ONTAP As Built Report - v1.0

Table of Contents

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1PHARMAX-HQ Cluster Report
1.1   PHARMAX-HQ Cluster Diagram
1.2   Cluster Information
1.2.1      Cluster HA Status
1.3   Node Information
1.3.1      Node Inventory
1.3.1.1         Node Vol0 Inventory
1.4   Storage Information
1.4.1      Aggregate Inventory
1.4.1.1         Storage Aggregate Diagram
1.4.1.2         Aggregate Spares
1.4.2      Disk Information
1.4.2.1         Per Node Disk Assignment
1.4.2.2         Disk Owned by Node PHARMAX-HQ-01
1.4.2.3         Disk Owned by Node PHARMAX-HQ-02
1.4.2.4         Disk Container Type
1.5   Licenses Information
1.5.1      PHARMAX-HQ-01 License Usage
1.5.2      PHARMAX-HQ-02 License Usage
1.6   Network Information
1.6.1      IPSpace
1.6.1.1         Network Ports
1.6.1.1.1            PHARMAX-HQ-01 Ports
1.6.1.1.2            PHARMAX-HQ-02 Ports
1.6.1.2         Network Link Aggregation Group
1.6.1.2.1            PHARMAX-HQ-01 IFGRP
1.6.1.2.2            PHARMAX-HQ-02 IFGRP
1.6.1.3         Network VLANs
1.6.1.3.1            PHARMAX-HQ-01 Vlans
1.6.1.3.2            PHARMAX-HQ-02 Vlans
1.6.1.4         Broadcast Domain
1.6.1.5         Failover Groups
1.6.1.6         PHARMAX-HQ Vserver Routes
1.6.1.7         NAS Vserver Routes
1.6.1.8         Network Interfaces
1.7   Vserver Information
1.7.1      NAS Vserver Configuration
1.7.1.1         Root Volume
1.7.1.2         Storage Volumes
1.7.1.3         Volumes Snapshot Configuration
1.7.1.4         Protocol Information
1.7.1.4.1            CIFS Services Information
1.7.2      SAN Vserver Configuration
1.7.2.1         Root Volume
1.7.2.2         Storage Volumes
1.7.2.3         Volumes Snapshot Configuration
1.7.2.4         Protocol Information
1.7.2.4.1            ISCSI Services
1.7.2.4.2            Lun Storage
1.8   Replication Information
1.8.1      Cluster Replication Diagram
1.8.2      Cluster Peer
1.8.3      Vserver Peer
1.8.3.1         SnapMirror Destinations
1.9   Efficiency Information
1.9.1      Aggregate Total Efficiency
1.9.1.1         HealthCheck - Volume with Disabled Deduplication
1.9.1.2         NAS Vserver Volume Deduplication
1.9.1.2.1            Volume Efficiency
1.9.1.3         SAN Vserver Volume Deduplication
1.9.1.3.1            Volume Efficiency
1.10   Security Information
1.10.1      PHARMAX-HQ Vserver Local User
1.10.2      NAS Vserver Local User
1.10.3      SAN Vserver Local User
1.10.4      Vserver SSL Certificate
1.10.4.1         Vserver SSL Certificate Details
1.10.5      Aggregate Encryption (NAE)
1.10.5.1         Volume Encryption (NVE)
1.10.6      Snaplock Compliance Clock
1.10.6.1         Aggregate Snaplock Type
1.10.6.1.1            Volume Snaplock Type
1.11   System Configuration Information
1.11.1      System Image Configuration
1.11.2      System Web Service
1.11.3      DNS Configuration
1.11.4      Configuration Backup Setting
1.11.5      EMS Configuration
1.11.5.1         Audit Settings
1.11.6      System Timezone Configuration
1.11.6.1         NTP Configuration
1PHARMAX-HQ Cluster Report
1.1   PHARMAX-HQ Cluster Diagram
1.2   Cluster Information
1.2.1      Cluster HA Status
1.2.2      Cluster AutoSupport Status
1.3   Nodes
1.3.1      Inventory
1.3.1.1         Root Volume Vol0
1.3.1.2         Service-Processor
1.4   Storage Information
1.4.1      Aggregates (Local Tiers)
1.4.1.1         Disk Spares
1.4.1.2         Aggregate Diagram
1.4.2      Disks
1.4.2.1         Per Node Disk Assignment
1.4.2.2         Disk Container Type
1.4.2.3         Failed Disk
1.4.2.4         Disk Inventory
1.5   Licenses Information
1.5.1      cluster-01 License Usage
1.5.2      cluster-02 License Usage
1.5.3      cluster-03 License Usage
1.5.4      cluster-04 License Usage
1.6   Networking Diagram
1.7   Network Information
1.7.1      IPSpace
1.7.1.1         Network Ports
1.7.1.1.1            cluster-01 Ports
1.7.1.1.2            cluster-02 Ports
1.7.1.1.3            cluster-03 Ports
1.7.1.1.4            cluster-04 Ports
1.7.1.2         Network Link Aggregation Group
1.7.1.2.1            cluster-01 IFGRP
1.7.1.2.2            cluster-02 IFGRP
1.7.1.2.3            cluster-03 IFGRP
1.7.1.2.4            cluster-04 IFGRP
1.7.1.3         Network VLANs
1.7.1.3.1            cluster-01 Vlans
1.7.1.3.2            cluster-02 Vlans
1.7.1.3.3            cluster-03 Vlans
1.7.1.3.4            cluster-04 Vlans
1.7.1.4         Broadcast Domains
1.7.1.5         Failover Groups
1.7.1.6         Network Subnets
1.7.1.7         PHARMAX-HQ Vserver Routes
1.7.1.8         CIFS Vserver Routes
1.7.1.9         FCP Vserver Routes
1.7.1.10         ISCSI Vserver Routes
1.7.1.11         NFS Vserver Routes
1.7.1.12         Network Interfaces
1.8   Vserver Information
1.8.1      CIFS Vserver Configuration
1.8.1.1         Root Volume
1.8.1.2         Interfaces (Lifs)
1.8.1.3         Storage Volumes
1.8.1.3.1            Per Volumes Export Policies
1.8.1.3.2            Flexcache Volumes
1.8.1.4         Volumes Snapshot Configuration
1.8.1.5         Qtrees
1.8.1.6         Volume Quota
1.8.1.7         Protocol Information
1.8.1.7.1            CIFS Services Information
1.8.2      FCP Vserver Configuration
1.8.2.1         Root Volume
1.8.2.2         Interfaces (Lifs)
1.8.2.3         Protocol Information
1.8.2.3.1            FCP Services Information
1.8.3      ISCSI Vserver Configuration
1.8.3.1         Root Volume
1.8.3.2         Aggregate Resource Allocation
1.8.3.3         Interfaces (Lifs)
1.8.3.4         Storage Volumes
1.8.3.4.1            Per Volumes Export Policies
1.8.3.5         Volumes Snapshot Configuration
1.8.3.6         Protocol Information
1.8.3.6.1            ISCSI Services
1.8.3.6.2            Lun Storage
1.8.4      NFS Vserver Configuration
1.8.4.1         Root Volume
1.8.4.2         Interfaces (Lifs)
1.8.4.3         Export Policies
1.8.4.4         Storage Volumes
1.8.4.4.1            Per Volumes Export Policies
1.8.4.4.2            Flexclone Volumes
1.8.4.5         Volumes Snapshot Configuration
1.8.4.5.1            HealthCheck - Volumes Snapshot
1.8.4.6         Protocol Information
1.8.4.6.1            NFS Services
1.9   Replication Information
1.9.1      Cluster Replication Diagram
1.9.2      Cluster Peer
1.9.3      Vserver Peer
1.9.3.1         SnapMirror Relationship
1.9.3.2         SnapMirror Destinations
1.10   Efficiency Information
1.10.1      Aggregate Total Efficiency
1.10.1.1         HealthCheck - Volume with Disabled Deduplication
1.10.1.2         CIFS Vserver Volume Deduplication
1.10.1.2.1            Volume Efficiency
1.10.1.3         ISCSI Vserver Volume Deduplication
1.10.1.3.1            Volume Efficiency
1.10.1.4         NFS Vserver Volume Deduplication
1.10.1.4.1            Volume Efficiency
1.11   Security Information
1.11.1      PHARMAX-HQ Vserver Local User
1.11.2      CIFS Vserver Local User
1.11.3      FCP Vserver Local User
1.11.4      ISCSI Vserver Local User
1.11.5      NFS Vserver Local User
1.11.6      Vserver SSL Certificate
1.11.6.1         Vserver SSL Certificate Details
1.11.7      Aggregate Encryption (NAE)
1.11.7.1         Volume Encryption (NVE)
1.11.8      Snaplock Compliance Clock
1.11.8.1         Aggregate Snaplock Type
1.11.8.1.1            Volume Snaplock Type
1.12   System Configuration Information
1.12.1      System Image Configuration
1.12.2      System Web Service
1.12.3      DNS Configuration
1.12.4      Configuration Backup Setting
1.12.5      EMS Configuration
1.12.5.1         Audit Settings
1.12.6      Timezone Configuration
1.12.6.1         NTP Configuration

-
NetApp ONTAP As Built Report - v1.0

1 PHARMAX-HQ Cluster Report

The following section provides a summary of the array configuration for PHARMAX-HQ.

1.1 PHARMAX-HQ Cluster Diagram

-NetApp Ontap Diagram +
NetApp ONTAP As Built Report - v1.0

1 PHARMAX-HQ Cluster Report

The following section provides a summary of the array configuration for PHARMAX-HQ.

1.1 PHARMAX-HQ Cluster Diagram

+NetApp Ontap Diagram
-
Image preview: Opens the image in a new tab to view it at full resolution.

1.2 Cluster Information

+

1.2 Cluster Information

- + - - - - - + + + + +
Cluster NamePHARMAX-HQ
Cluster UUID6a7cdc49-6fbd-11f0-9ce1-005056b06182
Cluster UUID8db621bf-d2cf-11f0-9194-005056b09767
Cluster Serial1-80-000011
Cluster Controller192.168.7.60
Cluster Contact-
Cluster Location-
Ontap VersionNetApp Release 9.16.1P4: Tue May 27 23:22:56 UTC 2025
Number of Aggregates4
Number of Volumes6
Cluster Contact--
Cluster Location--
Ontap VersionNetApp Release 9.18.1RC1: Sat Nov 08 06:50:56 UTC 2025
Number of Aggregates8
Number of Volumes17
Overall System HealthOK
Table 1 - Cluster Information - PHARMAX-HQ

-

1.2.1 Cluster HA Status

+

1.2.1 Cluster HA Status

- - -
NamePartnerTakeOver PossibleTakeOver StateHA ModeHA State
PHARMAX-HQ-01PHARMAX-HQ-02Yesnot_in_takeoverhaconnected
PHARMAX-HQ-02PHARMAX-HQ-01Yesnot_in_takeoverhaconnected
-
Table 2 - Cluster HA Status - PHARMAX-HQ

-

1.3 Node Information

The following section provides a summary of the Node on PHARMAX-HQ.

1.3.1 Node Inventory

The following section provides the node inventory on PHARMAX-HQ.

+ + + + +
cluster-01cluster-02Yesnot_in_takeoverhaconnected
cluster-02cluster-01Yesnot_in_takeoverhaconnected
cluster-03cluster-04Nonot_in_takeoverhaconnected
cluster-04cluster-03Nonot_in_takeoverhaconnected
+
Table 2 - Cluster AutoSupport Status - PHARMAX-HQ

+
Health Check:

Best Practice: 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.

Best Practice: One or more nodes have HA disabled while operating in HA mode. It is recommended to enable HA to ensure redundancy and high availability.

1.2.2 Cluster AutoSupport Status

+ + + + + +
Node NameProtocolEnabled
cluster-01httpsYes
cluster-02httpsYes
cluster-03httpsYes
cluster-04httpsYes
+
Table 3 - Cluster AutoSupport Status - PHARMAX-HQ

+

1.3 Nodes

The following section provides detailed information of nodes in cluster PHARMAX-HQ.

1.3.1 Inventory

- - -
NameModelIdSerialUptime
PHARMAX-HQ-01SIMBOX4082577507408236851100:42:12
PHARMAX-HQ-02SIMBOX4082577508403438906200:42:12
-
Table 3 - Nodes - PHARMAX-HQ

-

1.3.1.1 Node Vol0 Inventory

- - - -
NodeAggregateVolumeCapacityAvailableUsed
PHARMAX-HQ-01aggr0_PHARMAX_HQ_01vol09 GB3 GB65%
PHARMAX-HQ-02aggr0_PHARMAX_HQ_02vol09 GB3 GB64%
-
Table 4 - Node Storage - PHARMAX-HQ

-

1.4 Storage Information

The following section provides a summary of the storage hardware on PHARMAX-HQ.

1.4.1 Aggregate Inventory

The following section provides the Aggregates on PHARMAX-HQ.

1.4.1.1 Storage Aggregate Diagram

-NetApp Ontap Diagram -
-
Image preview: Opens the image in a new tab to view it at full resolution.
+ + + + +
cluster-01SIMBOX408211650762180300001700:26:30
cluster-02SIMBOX408211650862180300001800:26:31
cluster-03SIMBOX408271760772180300001300:26:30
cluster-04SIMBOX408271760872180300001400:26:30
+
Table 4 - Nodes - PHARMAX-HQ

+

1.3.1.1 Root Volume Vol0

+ + + + + +
NodeAggregateCapacityAvailableUsed
cluster-01aggr0_cluster_015.8 GB1.3 GB76%
cluster-02aggr0_cluster_025.3 GB928.2 MB81%
cluster-03aggr0_cluster_035.8 GB1.3 GB75%
cluster-04aggr0_cluster_045.3 GB1.2 GB76%
+
Table 5 - Node Storage - PHARMAX-HQ

+

1.3.1.2 Service-Processor

+ + + + + +
NameTypeIP AddressMAC AddressNetwork ConfiguredFirmwareStatus
cluster-01----------unknown
cluster-02----------unknown
cluster-03----------unknown
cluster-04----------unknown
+
Table 6 - Node Service-Processor - PHARMAX-HQ

+
Health Check:

Best Practice: Ensure that all service-processors are online, configured and functioning properly to maintain system management capabilities.

1.4 Storage Information

The following section provides detailed information about the storage configuration for cluster PHARMAX-HQ.

1.4.1 Aggregates (Local Tiers)

The following table summarises the aggregates in PHARMAX-HQ.

- - - - -
NameCapacityAvailableUsedDisk CountRootRaid TypeState
aggr0_PHARMAX_HQ_019 GB454 MB95%10YesRAID_DPonline
aggr0_PHARMAX_HQ_029 GB454 MB95%10YesRAID_DPonline
PHARMAX_HQ_01_SSD_187 GB54 GB38%23NoRAID_DPonline
PHARMAX_HQ_02_SSD_187 GB87 GB0%23NoRAID_DPonline
-
Table 5 - Aggregates - PHARMAX-HQ

-

1.4.1.2 Aggregate Spares

+ + + + + + + + +
aggr0_cluster_016.1 GB303.4 MB5.8 GB14YesRAID_DPonline
aggr0_cluster_025.6 GB278.3 MB5.3 GB13YesRAID_DPonline
aggr0_cluster_036.1 GB303.4 MB5.8 GB14YesRAID_DPonline
aggr0_cluster_045.6 GB278.3 MB5.3 GB13YesRAID_DPonline
cluster_01_SSD_190.6 GB80.5 GB10.1 GB35NoRAID_DPonline
cluster_02_SSD_175.0 GB43.2 GB31.8 GB30NoRAID_DPonline
cluster_03_SSD_190.6 GB60.4 GB30.2 GB35NoRAID_DPonline
cluster_04_SSD_175.0 GB42.9 GB32.1 GB30NoRAID_DPonline
+
Table 7 - Aggregates - PHARMAX-HQ

+

Aggragate Usage - Chart

+Aggragate Usage - Chart +
+

1.4.1.1 Disk Spares

- - - - - -
NameCapacityRoot UsableData UsableShared DiskDisk ZeroedOwner
VMw-1.1111 GB1 GB-YesYesPHARMAX-HQ-01
VMw-1.1211 GB1 GB-YesYesPHARMAX-HQ-01
VMw-1.2211 GB-5 GBYesYesPHARMAX-HQ-01
VMw-1.2111 GB1 GB-YesYesPHARMAX-HQ-02
VMw-1.2211 GB1 GB5 GBYesYesPHARMAX-HQ-02
-
Table 6 - Aggregates Spares - PHARMAX-HQ

-

1.4.2 Disk Information

The following section provides the disk summary information on controller PHARMAX-HQ.

1.4.2.1 Per Node Disk Assignment

The following section provides the number of disks assigned to each controller on PHARMAX-HQ.

+ + + + + + + + + + + +
VMw-1.197.1 GB627.5 MB--YesYescluster-01
VMw-1.77.1 GB627.3 MB--YesYescluster-01
VMw-1.127.1 GB627.3 MB--YesYescluster-02
VMw-1.197.1 GB--3.2 GBYesYescluster-02
VMw-1.247.1 GB627.3 MB--YesYescluster-02
VMw-1.437.1 GB627.3 MB--YesYescluster-03
VMw-1.557.1 GB----NoNocluster-03
VMw-1.667.1 GB627.3 MB--YesYescluster-03
VMw-1.477.1 GB627.3 MB--YesYescluster-04
VMw-1.677.1 GB627.3 MB--YesYescluster-04
VMw-1.707.1 GB--3.2 GBYesYescluster-04
+
Table 8 - Disk Spares - PHARMAX-HQ

+

1.4.1.2 Aggregate Diagram

+NetApp Ontap Diagram +
+

1.4.2 Disks

The following section provides a comprehensive summary of disk inventory and configuration across all controllers in the PHARMAX-HQ cluster.

1.4.2.1 Per Node Disk Assignment

- - -
NodeDisk Count
PHARMAX-HQ-0112
PHARMAX-HQ-0212
-
Table 7 - Assigned Disk - PHARMAX-HQ

-

1.4.2.2 Disk Owned by Node PHARMAX-HQ-01

+ + + + +
cluster-0121
cluster-0215
cluster-0321
cluster-0415
+
Table 9 - Assigned Disk - PHARMAX-HQ

+

Per Node Disk Assignment - Chart

+Per Node Disk Assignment - Chart +
+

cluster-01

+ + + + + + + + + + + + + + + + + + + + + + +
DiskOwner IdHomeHome IdType
VMw-1.14082116507cluster-014082116507SSD
VMw-1.134082116507cluster-014082116507SSD
VMw-1.144082116507cluster-014082116507SSD
VMw-1.154082116507cluster-014082116507SSD
VMw-1.164082116507cluster-014082116507SSD
VMw-1.174082116507cluster-014082116507SSD
VMw-1.184082116507cluster-014082116507SSD
VMw-1.194082116507cluster-014082116507SSD
VMw-1.24082116507cluster-014082116507SSD
VMw-1.254082116507cluster-014082116507SSD
VMw-1.264082116507cluster-014082116507SSD
VMw-1.274082116507cluster-014082116507SSD
VMw-1.284082116507cluster-014082116507SSD
VMw-1.294082116507cluster-014082116507SSD
VMw-1.34082116507cluster-014082116507SSD
VMw-1.304082116507cluster-014082116507SSD
VMw-1.314082116507cluster-014082116507SSD
VMw-1.44082116507cluster-014082116507SSD
VMw-1.54082116507cluster-014082116507SSD
VMw-1.64082116507cluster-014082116507SSD
VMw-1.74082116507cluster-014082116507SSD
+
Table 10 - Node Disk Owner - cluster-01

+

cluster-02

+ + + + + + + + + + + + + + + + +
DiskOwner IdHomeHome IdType
VMw-1.104082116508cluster-024082116508SSD
VMw-1.114082116508cluster-024082116508SSD
VMw-1.124082116508cluster-024082116508SSD
VMw-1.204082116508cluster-024082116508SSD
VMw-1.214082116508cluster-024082116508SSD
VMw-1.224082116508cluster-024082116508SSD
VMw-1.234082116508cluster-024082116508SSD
VMw-1.244082116508cluster-024082116508SSD
VMw-1.324082116508cluster-024082116508SSD
VMw-1.334082116508cluster-024082116508SSD
VMw-1.344082116508cluster-024082116508SSD
VMw-1.354082116508cluster-024082116508SSD
VMw-1.364082116508cluster-024082116508SSD
VMw-1.84082116508cluster-024082116508SSD
VMw-1.94082116508cluster-024082116508SSD
+
Table 11 - Node Disk Owner - cluster-02

+

cluster-03

- - - - - - - - - - - - -
DiskOwner IdHomeHome IdType
VMw-1.14082577507PHARMAX-HQ-014082577507SSD
VMw-1.104082577507PHARMAX-HQ-014082577507SSD
VMw-1.114082577507PHARMAX-HQ-014082577507SSD
VMw-1.124082577507PHARMAX-HQ-014082577507SSD
VMw-1.24082577507PHARMAX-HQ-014082577507SSD
VMw-1.34082577507PHARMAX-HQ-014082577507SSD
VMw-1.44082577507PHARMAX-HQ-014082577507SSD
VMw-1.54082577507PHARMAX-HQ-014082577507SSD
VMw-1.64082577507PHARMAX-HQ-014082577507SSD
VMw-1.74082577507PHARMAX-HQ-014082577507SSD
VMw-1.84082577507PHARMAX-HQ-014082577507SSD
VMw-1.94082577507PHARMAX-HQ-014082577507SSD
-
Table 8 - Node Disk Owner - PHARMAX-HQ-01

-

1.4.2.3 Disk Owned by Node PHARMAX-HQ-02

+ + + + + + + + + + + + + + + + + + + + + +
VMw-1.374082717607cluster-034082717607SSD
VMw-1.384082717607cluster-034082717607SSD
VMw-1.394082717607cluster-034082717607SSD
VMw-1.404082717607cluster-034082717607SSD
VMw-1.414082717607cluster-034082717607SSD
VMw-1.424082717607cluster-034082717607SSD
VMw-1.434082717607cluster-034082717607SSD
VMw-1.494082717607cluster-034082717607SSD
VMw-1.504082717607cluster-034082717607SSD
VMw-1.514082717607cluster-034082717607SSD
VMw-1.524082717607cluster-034082717607SSD
VMw-1.534082717607cluster-034082717607SSD
VMw-1.544082717607cluster-034082717607SSD
VMw-1.554082717607cluster-034082717607SSD
VMw-1.604082717607cluster-034082717607SSD
VMw-1.614082717607cluster-034082717607SSD
VMw-1.624082717607cluster-034082717607SSD
VMw-1.634082717607cluster-034082717607SSD
VMw-1.644082717607cluster-034082717607SSD
VMw-1.654082717607cluster-034082717607SSD
VMw-1.664082717607cluster-034082717607SSD
+
Table 12 - Node Disk Owner - cluster-03

+

cluster-04

- - - - - - - - - - - - -
DiskOwner IdHomeHome IdType
VMw-1.134082577508PHARMAX-HQ-024082577508SSD
VMw-1.144082577508PHARMAX-HQ-024082577508SSD
VMw-1.154082577508PHARMAX-HQ-024082577508SSD
VMw-1.164082577508PHARMAX-HQ-024082577508SSD
VMw-1.174082577508PHARMAX-HQ-024082577508SSD
VMw-1.184082577508PHARMAX-HQ-024082577508SSD
VMw-1.194082577508PHARMAX-HQ-024082577508SSD
VMw-1.204082577508PHARMAX-HQ-024082577508SSD
VMw-1.214082577508PHARMAX-HQ-024082577508SSD
VMw-1.224082577508PHARMAX-HQ-024082577508SSD
VMw-1.234082577508PHARMAX-HQ-024082577508SSD
VMw-1.244082577508PHARMAX-HQ-024082577508SSD
-
Table 9 - Node Disk Owner - PHARMAX-HQ-02

-

1.4.2.4 Disk Container Type

+ + + + + + + + + + + + + + + +
VMw-1.444082717608cluster-044082717608SSD
VMw-1.454082717608cluster-044082717608SSD
VMw-1.464082717608cluster-044082717608SSD
VMw-1.474082717608cluster-044082717608SSD
VMw-1.484082717608cluster-044082717608SSD
VMw-1.564082717608cluster-044082717608SSD
VMw-1.574082717608cluster-044082717608SSD
VMw-1.584082717608cluster-044082717608SSD
VMw-1.594082717608cluster-044082717608SSD
VMw-1.674082717608cluster-044082717608SSD
VMw-1.684082717608cluster-044082717608SSD
VMw-1.694082717608cluster-044082717608SSD
VMw-1.704082717608cluster-044082717608SSD
VMw-1.714082717608cluster-044082717608SSD
VMw-1.724082717608cluster-044082717608SSD
+
Table 13 - Node Disk Owner - cluster-04

+

1.4.2.2 Disk Container Type

- + + + + +
ContainerDisk Count
shared24
aggregate8
broken1
shared62
spare1
+
Table 14 - Disk Container Type - PHARMAX-HQ

+

Aggregate Spare Low Warning Per Node

+ + + + + +
NodeAggregate Spare Low
cluster-01Yes
cluster-02No
cluster-03No
cluster-04No
+
Table 15 - Aggregate Disk Spare Low - PHARMAX-HQ

+
Health Check:

Best Practice: Ensure that aggregate spare capacity is above the recommended threshold to maintain optimal performance and reliability.

1.4.2.3 Failed Disk

+ + +
Disk NameShelfBayPoolDisk Paths
VMw-1.1--00cluster-01:0b.0
cluster-02:0c.0
+
Table 16 - Failed Disk - PHARMAX-HQ

+
Health Check:

Best Practice: Review the failed disk information above. It is recommended to replace any broken disks promptly to maintain data integrity and system performance.

1.4.2.4 Disk Inventory

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Disk NameShelfBayCapacityModelTypeFirmware
VMw-1.1--08.6GVirtualdiskSSD2.0
VMw-1.10--108.6GVirtualdiskSSD2.0
VMw-1.11--118.6GVirtualdiskSSD2.0
VMw-1.12--128.6GVirtualdiskSSD2.0
VMw-1.13--08.6GVirtualdiskSSD2.0
VMw-1.14--18.6GVirtualdiskSSD2.0
VMw-1.15--28.6GVirtualdiskSSD2.0
VMw-1.16--38.6GVirtualdiskSSD2.0
VMw-1.17--48.6GVirtualdiskSSD2.0
VMw-1.18--58.6GVirtualdiskSSD2.0
VMw-1.19--68.6GVirtualdiskSSD2.0
VMw-1.2--18.6GVirtualdiskSSD2.0
VMw-1.20--88.6GVirtualdiskSSD2.0
VMw-1.21--98.6GVirtualdiskSSD2.0
VMw-1.22--108.6GVirtualdiskSSD2.0
VMw-1.23--118.6GVirtualdiskSSD2.0
VMw-1.24--128.6GVirtualdiskSSD2.0
VMw-1.25--08.6GVirtualdiskSSD2.0
VMw-1.26--18.6GVirtualdiskSSD2.0
VMw-1.27--28.6GVirtualdiskSSD2.0
VMw-1.28--38.6GVirtualdiskSSD2.0
VMw-1.29--48.6GVirtualdiskSSD2.0
VMw-1.3--28.6GVirtualdiskSSD2.0
VMw-1.30--58.6GVirtualdiskSSD2.0
VMw-1.31--68.6GVirtualdiskSSD2.0
VMw-1.32--88.6GVirtualdiskSSD2.0
VMw-1.33--98.6GVirtualdiskSSD2.0
VMw-1.34--108.6GVirtualdiskSSD2.0
VMw-1.35--118.6GVirtualdiskSSD2.0
VMw-1.36--128.6GVirtualdiskSSD2.0
VMw-1.37--08.6GVirtualdiskSSD2.0
VMw-1.38--18.6GVirtualdiskSSD2.0
VMw-1.39--28.6GVirtualdiskSSD2.0
VMw-1.4--38.6GVirtualdiskSSD2.0
VMw-1.40--38.6GVirtualdiskSSD2.0
VMw-1.41--48.6GVirtualdiskSSD2.0
VMw-1.42--58.6GVirtualdiskSSD2.0
VMw-1.43--68.6GVirtualdiskSSD2.0
VMw-1.44--88.6GVirtualdiskSSD2.0
VMw-1.45--98.6GVirtualdiskSSD2.0
VMw-1.46--108.6GVirtualdiskSSD2.0
VMw-1.47--128.6GVirtualdiskSSD2.0
VMw-1.48--118.6GVirtualdiskSSD2.0
VMw-1.49--08.6GVirtualdiskSSD2.0
VMw-1.5--48.6GVirtualdiskSSD2.0
VMw-1.50--18.6GVirtualdiskSSD2.0
VMw-1.51--28.6GVirtualdiskSSD2.0
VMw-1.52--38.6GVirtualdiskSSD2.0
VMw-1.53--48.6GVirtualdiskSSD2.0
VMw-1.54--58.6GVirtualdiskSSD2.0
VMw-1.55--68.6GVirtualdiskSSD2.0
VMw-1.56--98.6GVirtualdiskSSD2.0
VMw-1.57--88.6GVirtualdiskSSD2.0
VMw-1.58--108.6GVirtualdiskSSD2.0
VMw-1.59--118.6GVirtualdiskSSD2.0
VMw-1.6--58.6GVirtualdiskSSD2.0
VMw-1.60--08.6GVirtualdiskSSD2.0
VMw-1.61--18.6GVirtualdiskSSD2.0
VMw-1.62--28.6GVirtualdiskSSD2.0
VMw-1.63--38.6GVirtualdiskSSD2.0
VMw-1.64--48.6GVirtualdiskSSD2.0
VMw-1.65--58.6GVirtualdiskSSD2.0
VMw-1.66--68.6GVirtualdiskSSD2.0
VMw-1.67--128.6GVirtualdiskSSD2.0
VMw-1.68--88.6GVirtualdiskSSD2.0
VMw-1.69--108.6GVirtualdiskSSD2.0
VMw-1.7--68.6GVirtualdiskSSD2.0
VMw-1.70--118.6GVirtualdiskSSD2.0
VMw-1.71--128.6GVirtualdiskSSD2.0
VMw-1.72--98.6GVirtualdiskSSD2.0
VMw-1.8--88.6GVirtualdiskSSD2.0
VMw-1.9--98.6GVirtualdiskSSD2.0
+
Table 17 - Disk Inventory - PHARMAX-HQ

+

1.5 Licenses Information

The following section provides a summary of the license usage in PHARMAX-HQ.

1.5.1 cluster-01 License Usage

+ + + + + + + + + + + + +
LicenseTypeDescriptionRisk
CifsLicenseCIFS Licenselow
FcpLicenseFCP Licenselow
FlexcloneLicenseFlexClone Licenselow
IscsiLicenseiSCSI Licenselow
NfsLicenseNFS Licenselow
SnaplockLicenseSnapLock Licenselow
SnapmanagersuiteLicenseSnapCenter Licenselow
SnapmirrorLicenseSnapMirror Licenselow
SnaprestoreLicenseSnapRestore Licenselow
SnapvaultLicenseSnapVault Licenselow
TpmLicenseTrusted Platform Module License--
VeLicenseVolume Encryption License--
-
Table 10 - Disk Container Type - PHARMAX-HQ

-

1.5 Licenses Information

The following section provides a summary of the license usage on PHARMAX-HQ.

1.5.1 PHARMAX-HQ-01 License Usage

+
Table 18 - License Usage - cluster-01

+

1.5.2 cluster-02 License Usage

- - + +
LicenseTypeDescriptionRisk
CifsLicenseCIFS Licenselow
FcpLicenseFCP Licenselow
FlexcloneLicenseFlexClone Licenselow
Insight_BalanceLicenseOnCommand Balancelow
IscsiLicenseiSCSI Licenselow
NfsLicenseNFS Licenselow
SnaplockLicenseSnapLock Licenselow
SnapmanagersuiteLicenseSnapCenter Licenselow
SnapmirrorLicenseSnapMirror Licenselow
SnapprotectappsLicenseSnapProtectApp Licenselow
SnaprestoreLicenseSnapRestore Licenselow
SnapvaultLicenseSnapVault Licenselow
TpmLicenseTrusted Platform Module License--
VeLicenseVolume Encryption License--
-
Table 11 - License Usage - PHARMAX-HQ-01

-

1.5.2 PHARMAX-HQ-02 License Usage

+
Table 19 - License Usage - cluster-02

+

1.5.3 cluster-03 License Usage

- - + +
LicenseTypeDescriptionRisk
CifsLicenseCIFS Licenselow
FcpLicenseFCP Licenselow
FlexcloneLicenseFlexClone Licenselow
Insight_BalanceLicenseOnCommand Balancelow
IscsiLicenseiSCSI Licenselow
NfsLicenseNFS Licenselow
SnaplockLicenseSnapLock Licenselow
SnapmanagersuiteLicenseSnapCenter Licenselow
SnapmirrorLicenseSnapMirror Licenselow
SnapprotectappsLicenseSnapProtectApp Licenselow
SnaprestoreLicenseSnapRestore Licenselow
SnapvaultLicenseSnapVault Licenselow
TpmLicenseTrusted Platform Module License--
VeLicenseVolume Encryption License--
-
Table 12 - License Usage - PHARMAX-HQ-02

-

1.6 Network Information

The following section provides a summary of the networking features on PHARMAX-HQ.

1.6.1 IPSpace

The following section provides the IPSpace information on PHARMAX-HQ.

+
Table 20 - License Usage - cluster-03

+

1.5.4 cluster-04 License Usage

+ + + + + + + + + + + + + +
LicenseTypeDescriptionRisk
CifsLicenseCIFS Licenselow
FcpLicenseFCP Licenselow
FlexcloneLicenseFlexClone Licenselow
IscsiLicenseiSCSI Licenselow
NfsLicenseNFS Licenselow
SnaplockLicenseSnapLock Licenselow
SnapmanagersuiteLicenseSnapCenter Licenselow
SnapmirrorLicenseSnapMirror Licenselow
SnaprestoreLicenseSnapRestore Licenselow
SnapvaultLicenseSnapVault Licenselow
TpmLicenseTrusted Platform Module License--
VeLicenseVolume Encryption License--
+
Table 21 - License Usage - cluster-04

+

1.6 Networking Diagram

+NetApp Ontap Diagram +
+

1.7 Network Information

The following section provides a summary of the networking features in PHARMAX-HQ.

1.7.1 IPSpace

The following section provides the IPSpace information in PHARMAX-HQ.

- +
NameCluster
SVMCluster
PortsPHARMAX-HQ-02:e0a; PHARMAX-HQ-02:e0b; PHARMAX-HQ-01:e0a; PHARMAX-HQ-01:e0b
Portscluster-04:e0a; cluster-04:e0b; cluster-03:e0a; cluster-03:e0b; cluster-02:e0a; cluster-02:e0b; cluster-01:e0a; cluster-01:e0b
Broadcast DomainsCluster
-
Table 13 - Network IPSpace - Cluster

+
Table 22 - Network IPSpace - Cluster

- - - + + +
NameDefault
SVMSAN; NAS; PHARMAX-HQ
PortsPHARMAX-HQ-02:a0a; PHARMAX-HQ-02:a0a-11; PHARMAX-HQ-02:a0a-12; PHARMAX-HQ-02:a0a-5; PHARMAX-HQ-02:a0a-6; PHARMAX-HQ-02:a0a-7; PHARMAX-HQ-02:e0c; PHARMAX-HQ-02:e0d; PHARMAX-HQ-01:a0a; PHARMAX-HQ-01:a0a-11; PHARMAX-HQ-01:a0a-12; PHARMAX-HQ-01:a0a-5; PHARMAX-HQ-01:a0a-6; PHARMAX-HQ-01:a0a-7; PHARMAX-HQ-01:e0c; PHARMAX-HQ-01:e0d
Broadcast DomainsDefault; Default-1; Default-2; Default-3; Default-4; Default-5; Default-6; ISCSI-A; ISCSI-B
SVMNFS; ISCSI; CIFS; FCP; PHARMAX-HQ
Portscluster-04:a0a; cluster-04:a0a-12; cluster-04:a0a-5; cluster-04:a0a-6; cluster-04:a0a-7; cluster-04:a0b; cluster-04:a0b-24; cluster-04:e0c; cluster-04:e0d; cluster-04:e0f; cluster-04:e0g; cluster-04:e0h; cluster-03:a0a; cluster-03:a0a-12; cluster-03:a0a-5; cluster-03:a0a-6; cluster-03:a0a-7; cluster-03:a0b; cluster-03:a0b-24; cluster-03:e0c; cluster-03:e0d; cluster-03:e0f; cluster-03:e0g; cluster-03:e0h; cluster-02:a0a; cluster-02:a0a-12; cluster-02:a0a-5; cluster-02:a0a-6; cluster-02:a0a-7; cluster-02:a0b; cluster-02:a0b-24; cluster-02:e0c; cluster-02:e0d; cluster-02:e0f; cluster-02:e0g; cluster-02:e0h; cluster-01:a0a; cluster-01:a0a-12; cluster-01:a0a-5; cluster-01:a0a-6; cluster-01:a0a-7; cluster-01:a0b; cluster-01:a0b-24; cluster-01:e0c; cluster-01:e0d; cluster-01:e0f; cluster-01:e0g; cluster-01:e0h
Broadcast DomainsDefault; Default-1; Default-2; Default-3; Default-4; Default-5; ISCSI-A-6; ISCSI-B-12; MGMT-5; Replication-11; VM-Network-7
-
Table 14 - Network IPSpace - Default

-

1.6.1.1 Network Ports

The following section provides the physical network ports on PHARMAX-HQ.

1.6.1.1.1 PHARMAX-HQ-01 Ports
+
Table 23 - Network IPSpace - Default

+

1.7.1.1 Network Ports

The following section provides the physical network ports in PHARMAX-HQ.

1.7.1.1.1 cluster-01 Ports
- - - - -
Port NameRoleMac AddressMTULink StatusAdmin Status
e0aCluster00:50:56:b0:61:829000UpUp
e0bCluster00:50:56:b0:e4:9d9000UpUp
e0cNode_Mgmt02:50:56:b0:61:821500UpUp
e0dData02:50:56:b0:61:821500UpUp
-
Table 15 - Physical Port - PHARMAX-HQ-01

-
1.6.1.1.2 PHARMAX-HQ-02 Ports
+ + + + + + + +
e0aCluster00:50:56:b0:97:679000UpUp
e0bCluster00:50:56:b0:39:189000UpUp
e0cNode_Mgmt02:50:56:b0:97:679000UpUp
e0dData02:50:56:b0:97:679000UpUp
e0fData02:50:56:b0:39:189000UpUp
e0gData02:50:56:b0:39:189000UpUp
e0hData00:50:56:b0:fe:c41500UpUp
+
Table 24 - Physical Port - cluster-01

+
1.7.1.1.2 cluster-02 Ports
+ + + + + + + + +
Port NameRoleMac AddressMTULink StatusAdmin Status
e0aCluster00:50:56:b0:b8:949000UpUp
e0bCluster00:50:56:b0:0d:c59000UpUp
e0cNode_Mgmt02:50:56:b0:b8:949000UpUp
e0dData02:50:56:b0:b8:949000UpUp
e0fData02:50:56:b0:0d:c59000UpUp
e0gData02:50:56:b0:0d:c59000UpUp
e0hData00:50:56:b0:53:d31500UpUp
+
Table 25 - Physical Port - cluster-02

+
1.7.1.1.3 cluster-03 Ports
- - - - + + + + + + + +
Port NameRoleMac AddressMTULink StatusAdmin Status
e0aCluster00:50:56:b0:ea:5c9000UpUp
e0bCluster00:50:56:b0:5b:049000UpUp
e0cNode_Mgmt02:50:56:b0:ea:5c1500UpUp
e0dData02:50:56:b0:ea:5c1500UpUp
e0aCluster00:50:56:b0:22:fe9000UpUp
e0bCluster00:50:56:b0:50:bc9000UpUp
e0cNode_Mgmt02:50:56:b0:22:fe9000UpUp
e0dData02:50:56:b0:22:fe9000UpUp
e0fData02:50:56:b0:50:bc9000UpUp
e0gData02:50:56:b0:50:bc9000UpUp
e0hData00:50:56:b0:e5:da1500UpUp
+
Table 26 - Physical Port - cluster-03

+
1.7.1.1.4 cluster-04 Ports
+ + + + + + + + +
Port NameRoleMac AddressMTULink StatusAdmin Status
e0aCluster00:50:56:b0:39:579000UpUp
e0bCluster00:50:56:b0:8d:c29000UpUp
e0cNode_Mgmt02:50:56:b0:39:579000UpUp
e0dData02:50:56:b0:39:579000UpUp
e0fData02:50:56:b0:8d:c29000UpUp
e0gData02:50:56:b0:8d:c29000UpUp
e0hData00:50:56:b0:5f:4e1500UpUp
+
Table 27 - Physical Port - cluster-04

+

1.7.1.2 Network Link Aggregation Group

The following section provides per Node IFGRP Aggregated Ports in PHARMAX-HQ.

1.7.1.2.1 cluster-01 IFGRP
+ + + +
Port NameDistribution FunctionModePortMac AddressPort Participation
a0asequentialmultimodee0c e0d02:50:56:b0:97:67full
a0bsequentialmultimodee0f e0g02:50:56:b0:39:18full
+
Table 28 - Link Aggregation Group - cluster-01

+
1.7.1.2.2 cluster-02 IFGRP
+ + +
Port NameDistribution FunctionModePortMac AddressPort Participation
a0asequentialmultimodee0c e0d02:50:56:b0:b8:94full
a0bsequentialmultimodee0f e0g02:50:56:b0:0d:c5full
-
Table 16 - Physical Port - PHARMAX-HQ-02

-

1.6.1.2 Network Link Aggregation Group

The following section provides per Node IFGRP Aggregated Ports on PHARMAX-HQ.

1.6.1.2.1 PHARMAX-HQ-01 IFGRP
+
Table 29 - Link Aggregation Group - cluster-02

+
1.7.1.2.3 cluster-03 IFGRP
- + +
Port NameDistribution FunctionModePortMac AddressPort Participation
a0aipmultimodee0d02:50:56:b0:61:82full
a0asequentialmultimodee0c e0d02:50:56:b0:22:fefull
a0bsequentialmultimodee0f e0g02:50:56:b0:50:bcfull
-
Table 17 - Link Aggregation Group - PHARMAX-HQ-01

-
1.6.1.2.2 PHARMAX-HQ-02 IFGRP
+
Table 30 - Link Aggregation Group - cluster-03

+
1.7.1.2.4 cluster-04 IFGRP
- + +
Port NameDistribution FunctionModePortMac AddressPort Participation
a0aipmultimodee0d02:50:56:b0:ea:5cfull
a0asequentialmultimodee0c e0d02:50:56:b0:39:57full
a0bsequentialmultimodee0f e0g02:50:56:b0:8d:c2full
-
Table 18 - Link Aggregation Group - PHARMAX-HQ-02

-

1.6.1.3 Network VLANs

The following section provides Network VLAN information on PHARMAX-HQ.

1.6.1.3.1 PHARMAX-HQ-01 Vlans
+
Table 31 - Link Aggregation Group - cluster-04

+

1.7.1.3 Network VLANs

The following section provides Network VLAN information in PHARMAX-HQ.

1.7.1.3.1 cluster-01 Vlans
- +
Interface NameParent InterfaceVlan ID
a0a-11a0a11
a0a-12a0a12
a0b-24a0b24
a0a-5a0a5
a0a-6a0a6
a0a-7a0a7
-
Table 19 - Network VLAN - PHARMAX-HQ-01

-
1.6.1.3.2 PHARMAX-HQ-02 Vlans
+
Table 32 - Network VLAN - cluster-01

+
1.7.1.3.2 cluster-02 Vlans
- +
Interface NameParent InterfaceVlan ID
a0a-11a0a11
a0a-12a0a12
a0b-24a0b24
a0a-5a0a5
a0a-6a0a6
a0a-7a0a7
-
Table 20 - Network VLAN - PHARMAX-HQ-02

-

1.6.1.4 Broadcast Domain

+
Table 33 - Network VLAN - cluster-02

+
1.7.1.3.3 cluster-03 Vlans
+ + + + + + +
Interface NameParent InterfaceVlan ID
a0a-12a0a12
a0b-24a0b24
a0a-5a0a5
a0a-6a0a6
a0a-7a0a7
+
Table 34 - Network VLAN - cluster-03

+
1.7.1.3.4 cluster-04 Vlans
+ + + + + + +
Interface NameParent InterfaceVlan ID
a0a-12a0a12
a0b-24a0b24
a0a-5a0a5
a0a-6a0a6
a0a-7a0a7
+
Table 35 - Network VLAN - cluster-04

+

1.7.1.4 Broadcast Domains

- - - - - - - - - - -
NameIPSpaceFailover GroupsMTUPorts
ClusterClusterCluster9000PHARMAX-HQ-02:e0a
PHARMAX-HQ-02:e0b
PHARMAX-HQ-01:e0a
PHARMAX-HQ-01:e0b
DefaultDefaultDefault1500PHARMAX-HQ-02:a0a
PHARMAX-HQ-02:e0c
PHARMAX-HQ-01:a0a
PHARMAX-HQ-01:e0c
Default-1DefaultDefault-11500PHARMAX-HQ-01:a0a-5
Default-2DefaultDefault-21500PHARMAX-HQ-01:a0a-7
Default-3DefaultDefault-31500PHARMAX-HQ-01:a0a-11
Default-4DefaultDefault-41500PHARMAX-HQ-02:a0a-11
Default-5DefaultDefault-51500PHARMAX-HQ-02:a0a-5
Default-6DefaultDefault-61500PHARMAX-HQ-02:a0a-7
ISCSI-ADefaultISCSI-A1500PHARMAX-HQ-02:a0a-6
PHARMAX-HQ-01:a0a-6
ISCSI-BDefaultISCSI-B1500PHARMAX-HQ-02:a0a-12
PHARMAX-HQ-01:a0a-12
-
Table 21 - Network Broadcast Domain - PHARMAX-HQ

-

1.6.1.5 Failover Groups

+ + + + + + + + + + + + +
ClusterClusterCluster9000cluster-04:e0a
cluster-04:e0b
cluster-03:e0a
cluster-03:e0b
cluster-02:e0a
cluster-02:e0b
cluster-01:e0a
cluster-01:e0b
DefaultDefaultDefault1500cluster-04:a0a
cluster-03:a0a
cluster-02:a0a
cluster-01:a0a
Default-1DefaultDefault-19000cluster-01:a0b
Default-2DefaultDefault-29000cluster-02:a0b
Default-3DefaultDefault-39000cluster-03:a0b
Default-4DefaultDefault-49000cluster-04:a0b
Default-5DefaultDefault-59000cluster-04:a0b-24
cluster-03:a0b-24
cluster-02:a0b-24
cluster-01:a0b-24
ISCSI-A-6DefaultISCSI-A-69000cluster-04:a0a-6
cluster-03:a0a-6
cluster-02:a0a-6
cluster-01:a0a-6
ISCSI-B-12DefaultISCSI-B-129000cluster-04:a0a-12
cluster-03:a0a-12
cluster-02:a0a-12
cluster-01:a0a-12
MGMT-5DefaultMGMT-51500cluster-04:a0a-5
cluster-03:a0a-5
cluster-02:a0a-5
cluster-01:a0a-5
Replication-11DefaultReplication-111500cluster-04:e0h
cluster-03:e0h
cluster-02:e0h
cluster-01:e0h
VM-Network-7DefaultVM-Network-71500cluster-04:a0a-7
cluster-03:a0a-7
cluster-02:a0a-7
cluster-01:a0a-7
+
Table 36 - Network Broadcast Domain - PHARMAX-HQ

+

1.7.1.5 Failover Groups

- - - - - - - - - - -
NameVserverTarget
ClusterClusterPHARMAX-HQ-02:e0a
PHARMAX-HQ-02:e0b
PHARMAX-HQ-01:e0a
PHARMAX-HQ-01:e0b
DefaultPHARMAX-HQPHARMAX-HQ-02:a0a
PHARMAX-HQ-02:e0c
PHARMAX-HQ-01:a0a
PHARMAX-HQ-01:e0c
Default-1PHARMAX-HQPHARMAX-HQ-01:a0a-5
Default-2PHARMAX-HQPHARMAX-HQ-01:a0a-7
Default-3PHARMAX-HQPHARMAX-HQ-01:a0a-11
Default-4PHARMAX-HQPHARMAX-HQ-02:a0a-11
Default-5PHARMAX-HQPHARMAX-HQ-02:a0a-5
Default-6PHARMAX-HQPHARMAX-HQ-02:a0a-7
ISCSI-APHARMAX-HQPHARMAX-HQ-02:a0a-6
PHARMAX-HQ-01:a0a-6
ISCSI-BPHARMAX-HQPHARMAX-HQ-02:a0a-12
PHARMAX-HQ-01:a0a-12
-
Table 22 - Network Failover Group - PHARMAX-HQ

-

1.6.1.6 PHARMAX-HQ Vserver Routes

The following section provides the Routes information on PHARMAX-HQ.

+ + + + + + + + + + + + +
ClusterClustercluster-04:e0a
cluster-04:e0b
cluster-03:e0a
cluster-03:e0b
cluster-02:e0a
cluster-02:e0b
cluster-01:e0a
cluster-01:e0b
DefaultPHARMAX-HQcluster-04:a0a
cluster-03:a0a
cluster-02:a0a
cluster-01:a0a
Default-1PHARMAX-HQcluster-01:a0b
Default-2PHARMAX-HQcluster-02:a0b
Default-3PHARMAX-HQcluster-03:a0b
Default-4PHARMAX-HQcluster-04:a0b
Default-5PHARMAX-HQcluster-04:a0b-24
cluster-03:a0b-24
cluster-02:a0b-24
cluster-01:a0b-24
ISCSI-A-6PHARMAX-HQcluster-04:a0a-6
cluster-03:a0a-6
cluster-02:a0a-6
cluster-01:a0a-6
ISCSI-B-12PHARMAX-HQcluster-04:a0a-12
cluster-03:a0a-12
cluster-02:a0a-12
cluster-01:a0a-12
MGMT-5PHARMAX-HQcluster-04:a0a-5
cluster-03:a0a-5
cluster-02:a0a-5
cluster-01:a0a-5
Replication-11PHARMAX-HQcluster-04:e0h
cluster-03:e0h
cluster-02:e0h
cluster-01:e0h
VM-Network-7PHARMAX-HQcluster-04:a0a-7
cluster-03:a0a-7
cluster-02:a0a-7
cluster-01:a0a-7
+
Table 37 - Network Failover Group - PHARMAX-HQ

+

1.7.1.6 Network Subnets

+ + + + +
NameSubnetGatewayTotal IPUsed IPIp Ranges
DeptA-Client-VMnet4172.23.4.0/24172.23.4.254517172.23.4.100-172.23.4.150
ISCSI-A-6192.168.6.0/24--514192.168.6.100-192.168.6.150
ISCSI-B-12192.168.12.0/24--514192.168.12.100-192.168.12.150
+
Table 38 - Network Subnet - PHARMAX-HQ

+

1.7.1.7 PHARMAX-HQ Vserver Routes

The following section provides the Routes information in PHARMAX-HQ.

+
DestinationGatewayMetricAddress Family
0.0.0.0/0192.168.7.25420ipv4
0.0.0.0/0192.168.11.25420ipv4
-
Table 23 - Network Route - PHARMAX-HQ

-

1.6.1.7 NAS Vserver Routes

The following section provides the Routes information on PHARMAX-HQ.

+
Table 39 - Network Route - PHARMAX-HQ

+

1.7.1.8 CIFS Vserver Routes

The following section provides the Routes information in PHARMAX-HQ.

- +
DestinationGatewayMetricAddress Family
0.0.0.0/0192.168.7.25420ipv4
0.0.0.0/0172.23.4.25420ipv4
-
Table 24 - Network Route - NAS

-

1.6.1.8 Network Interfaces

The following section provides the Network Interfaces information on PHARMAX-HQ.

Cluster Network Interfaces

- - - - - +
Table 40 - Network Route - CIFS

+

1.7.1.9 FCP Vserver Routes

The following section provides the Routes information in PHARMAX-HQ.

Cluster InterfaceStatusData ProtocolsAddressVserver
PHARMAX-HQ-01_clus1UPnone169.254.97.130Cluster
PHARMAX-HQ-01_clus2UPnone169.254.228.157Cluster
PHARMAX-HQ-02_clus1UPnone169.254.234.92Cluster
PHARMAX-HQ-02_clus2UPnone169.254.91.4Cluster
+ + +
DestinationGatewayMetricAddress Family
0.0.0.0/0172.23.4.25420ipv4
+
Table 41 - Network Route - FCP

+

1.7.1.10 ISCSI Vserver Routes

The following section provides the Routes information in PHARMAX-HQ.

+ + +
DestinationGatewayMetricAddress Family
0.0.0.0/0172.23.4.25420ipv4
+
Table 42 - Network Route - ISCSI

+

1.7.1.11 NFS Vserver Routes

The following section provides the Routes information in PHARMAX-HQ.

+ +
DestinationGatewayMetricAddress Family
0.0.0.0/0192.168.5.25420ipv4
-
Table 25 - Cluster Network - PHARMAX-HQ

-

Management Network Interfaces

+
Table 43 - Network Route - NFS

+

1.7.1.12 Network Interfaces

The following section provides the Network Interfaces information in PHARMAX-HQ.

Cluster Network Interfaces

+ + + + + + + + + +
Cluster InterfaceStatusData ProtocolsAddressVserver
cluster-01_clus1UPnone169.254.151.103Cluster
cluster-01_clus2UPnone169.254.57.24Cluster
cluster-02_clus1UPnone169.254.184.148Cluster
cluster-02_clus2UPnone169.254.13.197Cluster
cluster-03_clus1UPnone169.254.34.254Cluster
cluster-03_clus2UPnone169.254.80.188Cluster
cluster-04_clus1UPnone169.254.57.87Cluster
cluster-04_clus2UPnone169.254.141.194Cluster
+
Table 44 - Cluster Network - PHARMAX-HQ

+

Management Network Interfaces

- - + + + +
MGMT InterfaceStatusData ProtocolsAddressVserver
cluster_mgmtUPnone192.168.7.60PHARMAX-HQ
PHARMAX-HQ-01_mgmt1UPnone192.168.7.61PHARMAX-HQ
PHARMAX-HQ-02_mgmt1UPnone192.168.7.62PHARMAX-HQ
cluster-01_mgmt1UPnone192.168.7.61PHARMAX-HQ
cluster-02_mgmt1UPnone192.168.7.62PHARMAX-HQ
cluster-03_mgmt1UPnone192.168.7.63PHARMAX-HQ
cluster-04_mgmt1UPnone192.168.7.64PHARMAX-HQ
-
Table 26 - Management Network - PHARMAX-HQ

-

Intercluster Network Interfaces

+
Table 45 - Management Network - PHARMAX-HQ

+

Intercluster Network Interfaces

- - + + + +
Intercluster InterfaceStatusData ProtocolsAddressVserver
PHARMAX-HQ-01_replication01UPnone192.168.11.61PHARMAX-HQ
PHARMAX-HQ-02_replication01UPnone192.168.11.62PHARMAX-HQ
lif_Default_2276UPnone192.168.11.63PHARMAX-HQ
lif_Default_374UPnone192.168.11.64PHARMAX-HQ
lif_Default_7971UPnone192.168.11.61PHARMAX-HQ
lif_Default_8739UPnone192.168.11.62PHARMAX-HQ
-
Table 27 - Intercluster Network - PHARMAX-HQ

-

Data Network Interfaces

+
Table 46 - Intercluster Network - PHARMAX-HQ

+

Data Network Interfaces

- - - - - - -
Data InterfaceStatusData ProtocolsAddressVserver
PHARMAX-HQ-01_nas01UPnfs cifs fcache192.168.7.63NAS
PHARMAX-HQ-02_nas01UPnfs cifs fcache192.168.7.64NAS
PHARMAX-HQ-01_iscsia01UPiscsi192.168.6.61SAN
PHARMAX-HQ-01_iscsib01UPiscsi192.168.12.61SAN
PHARMAX-HQ-02_iscsia01UPiscsi192.168.6.62SAN
PHARMAX-HQ-02_iscsib01UPiscsi192.168.12.62SAN
-
Table 28 - Data Network - PHARMAX-HQ

-

1.7 Vserver Information

The following section provides a summary of the vserver information on PHARMAX-HQ.

1.7.1 NAS Vserver Configuration

The following section provides the configuration of the vserver NAS.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
lif_CIFS_1728UPcifs172.23.4.102CIFS
lif_CIFS_2101UPcifs172.23.4.103CIFS
lif_CIFS_3310UPcifs172.23.4.101CIFS
lif_CIFS_4245UPnone172.23.4.105CIFS
lif_CIFS_4715UPcifs172.23.4.104CIFS
lif_FCP_1840UPfcp20:07:00:50:56:b0:39:57FCP
lif_FCP_206UPfcp20:08:00:50:56:b0:39:57FCP
lif_FCP_2670UPfcp20:04:00:50:56:b0:39:57FCP
lif_FCP_2920UPfcp20:05:00:50:56:b0:39:57FCP
lif_FCP_7769UPfcp20:01:00:50:56:b0:39:57FCP
lif_FCP_7889UPfcp20:06:00:50:56:b0:39:57FCP
lif_FCP_8085UPnone172.23.4.106FCP
lif_FCP_8379UPfcp20:03:00:50:56:b0:39:57FCP
lif_FCP_8389UPfcp20:02:00:50:56:b0:39:57FCP
lif_ISCSI_253UPiscsi192.168.6.102ISCSI
lif_ISCSI_4091UPiscsi192.168.6.101ISCSI
lif_ISCSI_4260UPiscsi192.168.12.102ISCSI
lif_ISCSI_4837UPnone172.23.4.100ISCSI
lif_ISCSI_6264UPiscsi192.168.12.100ISCSI
lif_ISCSI_6900UPiscsi192.168.6.100ISCSI
lif_ISCSI_7101UPiscsi192.168.12.101ISCSI
lif_ISCSI_8687UPiscsi192.168.6.103ISCSI
lif_ISCSI_8946UPiscsi192.168.12.103ISCSI
lif_NFS_331UPnfs192.168.5.62NFS
lif_NFS_6545UPnfs192.168.5.61NFS
lif_NFS_7087UPnfs192.168.5.64NFS
lif_NFS_9802UPnfs192.168.5.63NFS
+
Table 47 - Data Network - PHARMAX-HQ

+

1.8 Vserver Information

The following section provides a summary of the vserver information in PHARMAX-HQ.

1.8.1 CIFS Vserver Configuration

The following section provides the configuration of the vserver CIFS.

Vserver TypeAllowed ProtocolsDisallowed ProtocolsIPSpaceStatus
datanfs cifs fcp iscsi ndmp s3nvmeDefaultrunning
-
Table 29 - Information - NAS

-

1.7.1.1 Root Volume

+
Table 48 - Information - CIFS

+

1.8.1.1 Root Volume

- -
Root VolumeStatusTotal SizeUsedAvailableDedupAggregate
NAS_rootonline20 MB6%18 MBNoPHARMAX_HQ_02_SSD_1
-
Table 30 - Root Volume - NAS

-

1.7.1.2 Storage Volumes

+ +
CIFS_rootonline20.0 MB5%17.9 MBNocluster_01_SSD_1
+
Table 49 - Root Volume - CIFS

+

1.8.1.2 Interfaces (Lifs)

+ + + + + + +
Data InterfaceStatusData ProtocolsAddressIs Home
lif_CIFS_1728UPcifs172.23.4.102Yes
lif_CIFS_2101UPcifs172.23.4.103Yes
lif_CIFS_3310UPcifs172.23.4.101Yes
lif_CIFS_4245UPnone172.23.4.105Yes
lif_CIFS_4715UPcifs172.23.4.104Yes
+
Table 50 - Data Network - CIFS

+

1.8.1.3 Storage Volumes

- -
VolumeStatusCapacityAvailableUsedAggregate
DATAonline20 GB13 GB29%PHARMAX_HQ_01_SSD_1
-
Table 31 - Volume - NAS

-

1.7.1.3 Volumes Snapshot Configuration

+ + + +
DATAonline10.5 GB10.0 GB0%cluster_02_SSD_1
DATA_destonline128.0 MB121.3 MB0%cluster_03_SSD_1
Global_Documentsonline21.1 GB19.5 GB2%cluster_02_SSD_1
+
Table 51 - Volume - CIFS

+
1.8.1.3.1 Per Volumes Export Policies
+ + + + +
Volume NameExport Policy
DATAdefault
DATA_destdefault
Global_Documentsdefault
+
Table 52 - Per Volume Export Policy - CIFS

+
1.8.1.3.2 Flexcache Volumes
+ + +
Cache ClusterCache VserverCache VolumeOrigin VserverOrigin VolumeCapacity
PHARMAX-DRNAS_DRGlobal_DocumentsCIFSGlobal_Documents21.1 GB
+
Table 53 - Flexcache Volume Connected Cache - CIFS

+

1.8.1.4 Volumes Snapshot Configuration

- -
VolumeSnapshot EnabledReserve SizeReserve AvailableUsedPolicy
DATAYes1 GB1022 MB2 MBdefault
-
Table 32 - Volume SnapShot Configuration - NAS

-

1.7.1.4 Protocol Information

The following section provides a summary of the Vserver protocol information on NAS.

1.7.1.4.1 CIFS Services Information
The following section provides the CIFS Service Information on NAS.

+ + + +
DATAYes538.9 MB536.6 MB2.4 MBdefault
DATA_destNo6.4 MB6.2 MB188.0 KBnone
Global_DocumentsYes1.1 GB1.1 GB2.4 MBdefault
+
Table 54 - Volume SnapShot Configuration - CIFS

+
Health Check:

Best Practice: 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.

1.8.1.5 Qtrees

+ + + +
QtreeVolumeStatusSecurity StyleExport Policy
ITDATAnormalunixdefault
ITDATA_destreadonlyunixdefault
+
Table 55 - Volume Qtree - CIFS

+
Health Check:

Best Practice: Ensure all qtrees are in 'normal' status to maintain data integrity and accessibility.

1.8.1.6 Volume Quota

CIFS Vserver Volume Quota Status

The following section provides the CIFS Volumes Quota Status Information in PHARMAX-HQ.

+ + + + + +
VolumeStatusSubstatus
CIFS_rootoffnone
DATAonnone
DATA_destoffnone
Global_Documentsoffnone
+
Table 56 - Volume Quota Status - CIFS

+

1.8.1.7 Protocol Information

The following section provides a summary of the Vserver protocol information in CIFS.

1.8.1.7.1 CIFS Services Information
The following section provides the CIFS Service Information in CIFS.

- + - + - + - +
Node NamePHARMAX-HQ-01
Node Namecluster-01
Cifs Domain Namepharmax.local
Cifs NetBios NameNAS
Cifs NetBios NameCIFS
Cifs Domain IP192.168.7.1
AD Server Site 
AD Server Site--
Cifs Server StatusRunning
Status DetailsResponse time (msec): 2016
Status DetailsResponse time (msec): 4027
Statusup
-
Table 33 - CIFS Service - PHARMAX-HQ-01

+
Table 57 - CIFS Service - cluster-01

- + - - - + + + - +
Node NamePHARMAX-HQ-02
Node Namecluster-02
Cifs Domain Namepharmax.local
Cifs NetBios NameNAS
Cifs Domain IP192.168.7.1
AD Server Site 
Cifs NetBios NameCIFS
Cifs Domain IP192.168.5.1
AD Server Site--
Cifs Server StatusRunning
Status DetailsResponse time (msec): 2015
Status DetailsResponse time (msec): 9
Statusup
-
Table 34 - CIFS Service - PHARMAX-HQ-02

-

CIFS Local Group

+
Table 58 - CIFS Service - cluster-02

+
+ + + + + + + + + +
Node Namecluster-03
Cifs Domain Namepharmax.local
Cifs NetBios NameCIFS
Cifs Domain IP192.168.5.1
AD Server Site--
Cifs Server StatusRunning
Status DetailsResponse time (msec): 9
Statusup
+
Table 59 - CIFS Service - cluster-03

+
+ + + + + + + + + +
Node Namecluster-04
Cifs Domain Namepharmax.local
Cifs NetBios NameCIFS
Cifs Domain IP192.168.5.1
AD Server Site--
Cifs Server StatusRunning
Status DetailsResponse time (msec): 8
Statusup
+
Table 60 - CIFS Service - cluster-04

+

CIFS Local Group

@@ -451,162 +897,413 @@
Group NameDescription
BUILTIN\AdministratorsBuilt-in Administrators group
BUILTIN\Backup OperatorsBackup Operators group
BUILTIN\Power UsersRestricted administrative privileges
BUILTIN\UsersAll users
-
Table 35 - CIFS Connected Local Group - NAS

-

CIFS Local Group Members

+
Table 61 - CIFS Connected Local Group - CIFS

+

CIFS Local Group Members

- +
Group NameDescription
BUILTIN\AdministratorsNAS\Administrator
BUILTIN\AdministratorsCIFS\Administrator
BUILTIN\AdministratorsPHARMAX\Domain Admins
BUILTIN\GuestsPHARMAX\Domain Guests
BUILTIN\UsersPHARMAX\Domain Users
-
Table 36 - CIFS Connected Local Group Members - NAS

-

CIFS Share

+
Table 62 - CIFS Connected Local Group Members - CIFS

+

CIFS Share

- + - + +
Share NameVolumePath
c$NAS_root/
c$CIFS_root/
DATADATA/DATA
ipc$NAS_root/
Global_DocumentsGlobal_Documents/Global_Documents
ipc$CIFS_root/
-
Table 37 - CIFS Share - NAS

-

CIFS Share Configuration

+
Table 63 - CIFS Share - CIFS

+

CIFS Share Configuration

- - + + +
Share NameShare ACLShare Properties
c$BUILTIN\Administrators / Full Controloplocks, browsable, changenotify, show_previous_versions
DATAEveryone / Full Controloplocks, browsable, changenotify, show_previous_versions
ipc$ browsable
DATAEveryone / Full Controloplocks, browsable, showsnapshot, changenotify, continuously_available, access_based_enumeration, encrypt_data, show_previous_versions
Global_DocumentsEveryone / Full Controlbrowsable, show_previous_versions, oplocks, changenotify
ipc$--browsable
-
Table 38 - The CIFS Share Properties & Acl - NAS

-

1.7.2 SAN Vserver Configuration

The following section provides the configuration of the vserver SAN.

+
Table 64 - The CIFS Share Properties & Acl - CIFS

+

1.8.2 FCP Vserver Configuration

The following section provides the configuration of the vserver FCP.

Vserver TypeAllowed ProtocolsDisallowed ProtocolsIPSpaceStatus
datanfs cifs fcp iscsi ndmp s3nvmeDefaultrunning
-
Table 39 - Information - SAN

-

1.7.2.1 Root Volume

+
Table 65 - Information - FCP

+

1.8.2.1 Root Volume

- + +
Root VolumeStatusTotal SizeUsedAvailableDedupAggregate
SAN_rootonline20 MB7%18 MBNoPHARMAX_HQ_02_SSD_1
FCP_rootonline20.0 MB7%17.6 MBNocluster_04_SSD_1
+
Table 66 - Root Volume - FCP

+

1.8.2.2 Interfaces (Lifs)

+ + + + + + + + + + +
Data InterfaceStatusData ProtocolsAddressIs Home
lif_FCP_1840UPfcp20:07:00:50:56:b0:39:57Yes
lif_FCP_206UPfcp20:08:00:50:56:b0:39:57Yes
lif_FCP_2670UPfcp20:04:00:50:56:b0:39:57Yes
lif_FCP_2920UPfcp20:05:00:50:56:b0:39:57Yes
lif_FCP_7769UPfcp20:01:00:50:56:b0:39:57Yes
lif_FCP_7889UPfcp20:06:00:50:56:b0:39:57Yes
lif_FCP_8085UPnone172.23.4.106Yes
lif_FCP_8379UPfcp20:03:00:50:56:b0:39:57Yes
lif_FCP_8389UPfcp20:02:00:50:56:b0:39:57Yes
+
Table 67 - Data Network - FCP

+

1.8.2.3 Protocol Information

The following section provides a summary of the Vserver protocol information in FCP.

1.8.2.3.1 FCP Services Information
The following section provides the FCP Service Information in FCP.

+ + +
FCP WWNNStatus
20:00:00:50:56:b0:39:57Up
+
Table 68 - FCP Service - FCP

+

FCP Physical Adapter

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Node NameAdapterProtocolSpeedStatus
cluster-010afibre_channelautoUp
cluster-010bfibre_channelautoUp
cluster-010efibre_channelautoUp
cluster-010ffibre_channelautoUp
cluster-011afibre_channelautoUp
cluster-011bfibre_channelautoUp
cluster-020afibre_channelautoUp
cluster-020bfibre_channelautoUp
cluster-020efibre_channelautoUp
cluster-020ffibre_channelautoUp
cluster-021afibre_channelautoUp
cluster-021bfibre_channelautoUp
cluster-030afibre_channelautoUp
cluster-030bfibre_channelautoUp
cluster-030efibre_channelautoUp
cluster-030ffibre_channelautoUp
cluster-031afibre_channelautoUp
cluster-031bfibre_channelautoUp
cluster-040afibre_channelautoUp
cluster-040bfibre_channelautoUp
cluster-040efibre_channelautoUp
cluster-040ffibre_channelautoUp
cluster-041afibre_channelautoUp
cluster-041bfibre_channelautoUp
+
Table 69 - FCP Physical Adapter - PHARMAX-HQ

+

FCP Interfaces

+ + + + + + + + + +
Interface NameFCP WWPNNode NameHome Port
lif_FCP_776920:01:00:50:56:b0:39:57cluster-010a
lif_FCP_838920:02:00:50:56:b0:39:57cluster-010b
lif_FCP_267020:04:00:50:56:b0:39:57cluster-020b
lif_FCP_837920:03:00:50:56:b0:39:57cluster-020a
lif_FCP_292020:05:00:50:56:b0:39:57cluster-030a
lif_FCP_788920:06:00:50:56:b0:39:57cluster-030b
lif_FCP_184020:07:00:50:56:b0:39:57cluster-040a
lif_FCP_20620:08:00:50:56:b0:39:57cluster-040b
+
Table 70 - FCP Interface - FCP

+

1.8.3 ISCSI Vserver Configuration

The following section provides the configuration of the vserver ISCSI.

+ +
Vserver TypeAllowed ProtocolsDisallowed ProtocolsIPSpaceStatus
datanfs cifs fcp iscsi ndmp s3nvmeDefaultrunning
-
Table 40 - Root Volume - SAN

-

1.7.2.2 Storage Volumes

+
Table 71 - Information - ISCSI

+

1.8.3.1 Root Volume

+ + +
Root VolumeStatusTotal SizeUsedAvailableDedupAggregate
ISCSI_rootonline20.0 MB6%17.7 MBNocluster_03_SSD_1
+
Table 72 - Root Volume - ISCSI

+

1.8.3.2 Aggregate Resource Allocation

+ + + +
AggregateTypeSnapLock TypeAvailable
cluster_03_SSD_1ssdnon_snaplock60.4 GB
cluster_04_SSD_1ssdnon_snaplock42.9 GB
+
Table 73 - Aggregate Resource Allocation - ISCSI

+

1.8.3.3 Interfaces (Lifs)

+ + + + + + + + + + +
Data InterfaceStatusData ProtocolsAddressIs Home
lif_ISCSI_253UPiscsi192.168.6.102Yes
lif_ISCSI_4091UPiscsi192.168.6.101Yes
lif_ISCSI_4260UPiscsi192.168.12.102Yes
lif_ISCSI_4837UPnone172.23.4.100Yes
lif_ISCSI_6264UPiscsi192.168.12.100Yes
lif_ISCSI_6900UPiscsi192.168.6.100Yes
lif_ISCSI_7101UPiscsi192.168.12.101Yes
lif_ISCSI_8687UPiscsi192.168.6.103Yes
lif_ISCSI_8946UPiscsi192.168.12.103Yes
+
Table 74 - Data Network - ISCSI

+

1.8.3.4 Storage Volumes

- + +
VolumeStatusCapacityAvailableUsedAggregate
SQL_DATAonline13 GB2 GB84%PHARMAX_HQ_01_SSD_1
DBonline11.9 GB1.9 GB84%cluster_04_SSD_1
+
Table 75 - Volume - ISCSI

+
Health Check:

Best Practice: Ensure all volumes are below 95% usage to prevent capacity issues.

1.8.3.4.1 Per Volumes Export Policies
+ +
Volume NameExport Policy
DBdefault
-
Table 41 - Volume - SAN

-

1.7.2.3 Volumes Snapshot Configuration

+
Table 76 - Per Volume Export Policy - ISCSI

+

1.8.3.5 Volumes Snapshot Configuration

- +
VolumeSnapshot EnabledReserve SizeReserve AvailableUsedPolicy
SQL_DATAYes643 MB637 MB6 MBdefault
DBNo00196.0 KBnone
-
Table 42 - Volume SnapShot Configuration - SAN

-

1.7.2.4 Protocol Information

The following section provides a summary of the Vserver protocol information on SAN.

1.7.2.4.1 ISCSI Services
The following section provides the ISCSI Service Information on SAN.

+
Table 77 - Volume SnapShot Configuration - ISCSI

+

1.8.3.6 Protocol Information

The following section provides a summary of the Vserver protocol information in ISCSI.

1.8.3.6.1 ISCSI Services
The following section provides the ISCSI Service Information in ISCSI.

- - + +
IQN Nameiqn.1992-08.com.netapp:sn.5971f5526fe011f0aa34005056b06182:vs.3
Alias NameSAN
IQN Nameiqn.1992-08.com.netapp:sn.eb7e8829d2ff11f0bea5005056b09767:vs.6
Alias NameISCSI
Tcp Window Size131400
Max Cmds Per Session128
Max Conn Per Session4
Login Timeout15
StatusUp
-
Table 43 - ISCSI Service - SAN

-

ISCSI Interfaces

+
Table 78 - ISCSI Service - ISCSI

+

ISCSI Interfaces

- - - - -
Interface NameIP AddressPortStatus
PHARMAX-HQ-01_iscsia01192.168.6.613260Up
PHARMAX-HQ-01_iscsib01192.168.12.613260Up
PHARMAX-HQ-02_iscsia01192.168.6.623260Up
PHARMAX-HQ-02_iscsib01192.168.12.623260Up
-
Table 44 - ISCSI Interface - SAN

-
1.7.2.4.2 Lun Storage
The following section provides the Lun Storage Information on SAN.

+ + + + + + + + +
lif_ISCSI_253192.168.6.1023260Up
lif_ISCSI_4091192.168.6.1013260Up
lif_ISCSI_4260192.168.12.1023260Up
lif_ISCSI_6264192.168.12.1003260Up
lif_ISCSI_6900192.168.6.1003260Up
lif_ISCSI_7101192.168.12.1013260Up
lif_ISCSI_8687192.168.6.1033260Up
lif_ISCSI_8946192.168.12.1033260Up
+
Table 79 - ISCSI Interface - ISCSI

+
1.8.3.6.2 Lun Storage
The following section provides the Lun Storage Information in ISCSI.

- - - - + + + + - - - + + + - +
Lun NameSQL_DATA
Parent VolumeSQL_DATA
Path/vol/SQL_DATA/SQL_DATA
Serial NumberwpRkN]Yhbtn8
Lun NameDB
Parent VolumeDB
Path/vol/DB/DB
Serial Numberwp/Ie$ZKGTlF
Initiator GroupSQLLun
Home Node PHARMAX-HQ-01
Capacity10 GB
Available10 GB
Home Node cluster-04
Capacity10.0 GB
Available10.0 GB
Used0%
OS Typewindows_2008
Is ThinNo
Space AllocationEnabled
Space ReservationEnabled
Is MappedYes
StatusUp
StatusDown
-
Table 45 - Lun - SQL_DATA

-

Igroup Mapping

+
Table 80 - Lun - DB

+
Health Check:

Best Practice: Ensure that all LUNs are operational to maintain optimal storage connectivity.

Igroup Mapping

- - + + +
Igroup NameSQLLun
Typewindows
Protocolmixed
Initiatorsiqn.1991-05.com.microsoft:server-dc-01v.pharmax.local
Mapped LunSQL_DATA
Reporting NodesPHARMAX-HQ-01
PHARMAX-HQ-02
Mapped LunDB
Reporting NodesNone
+
Table 81 - Igroup - SQLLun

+

1.8.4 NFS Vserver Configuration

The following section provides the configuration of the vserver NFS.

+ +
Vserver TypeAllowed ProtocolsDisallowed ProtocolsIPSpaceStatus
datanfs cifs fcp iscsi ndmp s3nvmeDefaultrunning
-
Table 46 - Igroup - SQLLun

-

1.8 Replication Information

The following section provides a summary of the replication information on PHARMAX-HQ.

1.8.1 Cluster Replication Diagram

-NetApp Ontap Diagram +
Table 82 - Information - NFS

+

1.8.4.1 Root Volume

+ + +
Root VolumeStatusTotal SizeUsedAvailableDedupAggregate
NFS_rootonline20.0 MB7%17.6 MBNocluster_01_SSD_1
+
Table 83 - Root Volume - NFS

+

1.8.4.2 Interfaces (Lifs)

+ + + + + +
Data InterfaceStatusData ProtocolsAddressIs Home
lif_NFS_331UPnfs192.168.5.62Yes
lif_NFS_6545UPnfs192.168.5.61Yes
lif_NFS_7087UPnfs192.168.5.64Yes
lif_NFS_9802UPnfs192.168.5.63Yes
+
Table 84 - Data Network - NFS

+

1.8.4.3 Export Policies

+ + + + +
Policy NameRule IndexClient MatchProtocolRo RuleRw Rule
DAS10.0.0.0/0anyanynever
VM_DataStore10.0.0.0/0anyanyany
VM_DataStore2192.168.5.253nfs3, nfs4, nfsneverany
+
Table 85 - Export Policies - NFS

+

1.8.4.4 Storage Volumes

+ + + + + + +
VolumeStatusCapacityAvailableUsedAggregate
DASonline10.0 GB9.5 GB0%cluster_01_SSD_1
DAS_clone_515online1.1 GB1023.5 MB0%cluster_01_SSD_1
DATA1online20.0 GB19.0 GB0%cluster_04_SSD_1
DBs_destonline128.0 MB121.3 MB0%cluster_01_SSD_1
VM_DataStoreonline30.0 GB28.5 GB0%cluster_03_SSD_1
+
Table 86 - Volume - NFS

+
1.8.4.4.1 Per Volumes Export Policies
+ + + + + + +
Volume NameExport Policy
DASDAS
DAS_clone_515DAS
DATA1default
DBs_destdefault
VM_DataStoredefault
+
Table 87 - Per Volume Export Policy - NFS

+
1.8.4.4.2 Flexclone Volumes
+ + + + + + + + + + + +
VolumeDAS_clone_515
Parent VolumeDAS
Volume TypeRW
Parent Snapshotclone_DAS_clone_515.2025-12-21_214319.0
Space Reservenone
Space GuaranteeYes
Capacity1.1 GB
Available1.1 GB
Used480.0 KB
Aggregatecluster_01_SSD_1
+
Table 88 - Cloned Volumes - DAS_clone_515

+
Health Check:

Best Practice: Regularly monitor flexclone volumes to manage storage utilization effectively.

1.8.4.5 Volumes Snapshot Configuration

+ + + + + + +
VolumeSnapshot EnabledReserve SizeReserve AvailableUsedPolicy
DASYes512.0 MB510.0 MB2.0 MBdefault
DAS_clone_515Yes53.9 MB51.2 MB2.7 MBdefault
DATA1Yes1.0 GB1023.0 MB1.0 MBdefault
DBs_destNo6.4 MB6.2 MB188.0 KBnone
VM_DataStoreYes1.5 GB1.5 GB2.4 MBdefault
+
Table 89 - Volume SnapShot Configuration - NFS

+
Health Check:

Best Practice: 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.

1.8.4.5.1 HealthCheck - Volumes Snapshot
The following section provides the Vserver Volumes Snapshot HealthCheck in NFS.

+ + + +
Volume NameSnapshot NameCreated TimeUsed
DASclone_DAS_clone_515.2025-12-21_214319.012/21/2025 21:43:19200.0 KB
DAS_clone_515clone_DAS_clone_515.2025-12-21_214319.012/21/2025 21:43:19204.0 KB
+
Table 90 - HealthCheck - Volume Snapshot over 30 days - NFS

+

1.8.4.6 Protocol Information

The following section provides a summary of the Vserver protocol information in NFS.

1.8.4.6.1 NFS Services
The following section provides the NFS Service Information in NFS.

+ + +
Nfs v3Nfs v4Nfs v41General Access
EnabledEnabledEnabledYes
+
Table 91 - NFS Service - PHARMAX-HQ

+

NFS Volume Export

+ + + + +
Path NameExport Policy
/DASDAS
/vol/DASNone
/vol/DAS_clone_515None
+
Table 92 - NFS Service Volume Export - NFS

+

1.9 Replication Information

The following section provides a summary of the replication information in PHARMAX-HQ.

1.9.1 Cluster Replication Diagram

+NetApp Ontap Diagram
-
Image preview: Opens the image in a new tab to view it at full resolution.

1.8.2 Cluster Peer

The following section provides the Cluster Peer information on PHARMAX-HQ.

+

1.9.2 Cluster Peer

The following section provides the Cluster Peer information in PHARMAX-HQ.

- - +
Cluster PeerCluster NodesPeer AddressesCluster HealthIP SpaceStatus
PHARMAX-DRPHARMAX-DR-0110.10.36.14TrueDefaultavailable
PHARMAX-EDGEPHARMAX-EDGE-01172.23.9.14TrueDefaultavailable
PHARMAX-DRcluster-dr-01192.168.11.70YesDefaultavailable
-
Table 47 - Cluster Peer - PHARMAX-HQ

-

1.8.3 Vserver Peer

+
Table 93 - Cluster Peer - PHARMAX-HQ

+

1.9.3 Vserver Peer

- - + + +
VserverPeer VserverPeer ClusterApplicationsPeer State
NASNAS-EDGEPHARMAX-EDGEsnapmirror
flexcache
peered
SANSAN_DRPHARMAX-DRsnapmirror
flexcache
peered
CIFSNAS_DRPHARMAX-DRsnapmirror
flexcache
peered
ISCSINAS_DRPHARMAX-DRsnapmirrorpeered
NFSNAS_DRPHARMAX-DRsnapmirror
flexcache
peered
-
Table 48 - Peer - PHARMAX-HQ

-

1.8.3.1 SnapMirror Destinations

+
Table 94 - Peer - PHARMAX-HQ

+

1.9.3.1 SnapMirror Relationship

- - - - + + + + + + + - + + +
Destination VserverNAS-EDGE
Destination LocationNAS-EDGE:DATA
Source VserverNAS
Source LocationNAS:DATA
Source VserverCIFS
Source LocationCIFS:DATA
Destination VserverCIFS
Destination LocationCIFS:DATA_dest
Mirror Statesnapmirrored
Schedule--
Relationship TypeXDP
PolicyMirrorLatest
Policy Typeasync_mirror
StatusUnknown
Unhealthy ReasonNone
Lag Time1 days, 21 hrs, 53 mins, 1 secs
StatusIDLE
-
Table 49 - SnapMirror Destination (List-Destinations) - NAS-EDGE:DATA

+
Table 95 - SnapMirror relationship - CIFS:DATA

- - - - + + + + + + + + + + + + +
Destination VserverSAN_DR
Destination LocationSAN_DR:SQL_DATA_dest
Source VserverSAN
Source LocationSAN:SQL_DATA
Source VserverNAS_DR
Source LocationNAS_DR:DBs
Destination VserverNFS
Destination LocationNFS:DBs_dest
Mirror Statesnapmirrored
Schedule--
Relationship TypeXDP
PolicyMirrorLatest
Policy Typeasync_mirror
Unhealthy ReasonNone
Lag Time1 days, 21 hrs, 50 mins, 1 secs
StatusIDLE
+
Table 96 - SnapMirror relationship - NAS_DR:DBs

+

1.9.3.2 SnapMirror Destinations

+ + + + + + + + +
Destination VserverCIFS
Destination LocationCIFS:DATA_dest
Source VserverCIFS
Source LocationCIFS:DATA
Relationship TypeXDP
Policy Typeasync_mirror
StatusUnknown
+
Table 97 - SnapMirror Destination (List-Destinations) - CIFS:DATA_dest

+
Health Check:

Best Practice: Ensure that all SnapMirror relationships have a known status to maintain replication integrity.

+ + + + +
Destination VserverNAS_DR
Destination LocationNAS_DR:DB_dest2
Source VserverISCSI
Source LocationISCSI:DB
Relationship TypeXDP
Policy Typemirror_vault
Statusidle
-
Table 50 - SnapMirror Destination (List-Destinations) - SAN_DR:SQL_DATA_dest

-

1.9 Efficiency Information

The following section provides the Storage Efficiency Saving information on PHARMAX-HQ.

+
Table 98 - SnapMirror Destination (List-Destinations) - NAS_DR:DB_dest2

+

1.10 Efficiency Information

The following section provides the Storage Efficiency Saving information in PHARMAX-HQ.

- - + + + +
AggregateUsed %Capacity Tier UsedCompaction Saved %Deduplication Saved %Total Data Reduction
PHARMAX_HQ_01_SSD_138%00%0%10.99:1
PHARMAX_HQ_02_SSD_10%00%0%1.91:1
cluster_01_SSD_111%00%0%1.24:1
cluster_02_SSD_142%00%0%4.05:1
cluster_03_SSD_133%00%0%2.34:1
cluster_04_SSD_143%00%0%2.20:1
-
Table 51 - Storage Efficiency Savings - PHARMAX-HQ

-

1.9.1 Aggregate Total Efficiency

The following section provides the Aggregate Efficiency Saving information on PHARMAX-HQ.

+
Table 99 - Storage Efficiency Savings - PHARMAX-HQ

+

1.10.1 Aggregate Total Efficiency

The following section provides the Aggregate Efficiency Saving information in PHARMAX-HQ.

- - + + + +
AggregateLogical UsedPhysical UsedCompaction SavedData Reduction
PHARMAX_HQ_01_SSD_16 GB6 GB 1.00:1
PHARMAX_HQ_02_SSD_14 MB4 MB 1.00:1
cluster_01_SSD_116.6 MB16.6 MB--1.00:1
cluster_02_SSD_112.8 MB12.8 MB--1.00:1
cluster_03_SSD_15.6 MB5.6 MB--1.00:1
cluster_04_SSD_14.2 MB4.2 MB--1.00:1
-
Table 52 - Aggregate Efficiency Savings - PHARMAX-HQ

-

1.9.1.1 HealthCheck - Volume with Disabled Deduplication

The following table provides the Volume efficiency healthcheck Information on PHARMAX-HQ.

+
Table 100 - Aggregate Efficiency Savings - PHARMAX-HQ

+

1.10.1.1 HealthCheck - Volume with Disabled Deduplication

The following table provides the Volume efficiency healthcheck Information in PHARMAX-HQ.

- -
AggregateVolumes without Deduplication
PHARMAX_HQ_01_SSD_1DATA, SQL_DATA
-
Table 53 - HealthCheck - Volume without deduplication - PHARMAX-HQ

-

1.9.1.2 NAS Vserver Volume Deduplication

1.9.1.2.1 Volume Efficiency
+ + + +
cluster_01_SSD_1DAS, DAS_clone_515
cluster_03_SSD_1VM_DataStore
cluster_04_SSD_1DB, DATA1
+
Table 101 - HealthCheck - Volume without deduplication - PHARMAX-HQ

+
Health Check:

Best Practice: Ensure that deduplication is enabled on all volumes to maximize storage efficiency.

1.10.1.2 CIFS Vserver Volume Deduplication

+ + + + +
VolumeStateStatusSchedule Or PolicyProgress
DATADisabledidleautoIdle for 726:15:54
DATA_destEnabledidle-Idle for 45:53:27
Global_DocumentsDisabledidleautoIdle for 1411:48:56
+
Table 102 - Volume Deduplication - CIFS

+
Health Check:

Best Practice: Ensure that volume deduplication is enabled on volumes where data reduction is beneficial to optimize storage efficiency.

1.10.1.2.1 Volume Efficiency
- + + +
VolumeCapacityUsedSnapshot UsedTotal SavingsEffective UsedEfficiency Percent
DATA19 GB6 GB2 MB6 GB11 GB59.9%
DATA10.0 GB7.7 MB2.4 MB7.5 MB15.3 MB0.1%
DATA_dest121.6 MB356.0 KB188.0 KB168.0 KB524.0 KB0.4%
Global_Documents20.0 GB513.1 MB2.4 MB512.9 MB1.0 GB5.0%
-
Table 54 - Volume Efficiency Savings - NAS

-

1.9.1.3 SAN Vserver Volume Deduplication

1.9.1.3.1 Volume Efficiency
- - +
Table 103 - Volume Efficiency Savings - CIFS

+

1.10.1.3 ISCSI Vserver Volume Deduplication

VolumeCapacityUsedSnapshot UsedTotal SavingsEffective UsedEfficiency Percent
SQL_DATA12 GB10 GB6 MB10 GB20 GB168.3%
+ +
VolumeStateStatusSchedule Or PolicyProgress
DBDisabledidleautoIdle for 1413:08:28
-
Table 55 - Volume Efficiency Savings - SAN

-

1.10 Security Information

The following section provides the Security related information on PHARMAX-HQ.

1.10.1 PHARMAX-HQ Vserver Local User

The following section provides the Local User information on PHARMAX-HQ.

+
Table 104 - Volume Deduplication - ISCSI

+
Health Check:

Best Practice: Ensure that volume deduplication is enabled on volumes where data reduction is beneficial to optimize storage efficiency.

1.10.1.3.1 Volume Efficiency
+ + +
VolumeCapacityUsedSnapshot UsedTotal SavingsEffective UsedEfficiency Percent
DB11.9 GB10.0 GB196.0 KB10.0 GB20.1 GB168.3%
+
Table 105 - Volume Efficiency Savings - ISCSI

+

1.10.1.4 NFS Vserver Volume Deduplication

+ + + + + +
VolumeStateStatusSchedule Or PolicyProgress
DASDisabledidleautoIdle for 1051:42:04
DAS_clone_515DisabledidleautoIdle for 1051:42:04
DBs_destEnabledidle-Idle for 45:49:39
VM_DataStoreDisabledidleautoIdle for 1413:11:35
+
Table 106 - Volume Deduplication - NFS

+
Health Check:

Best Practice: Ensure that volume deduplication is enabled on volumes where data reduction is beneficial to optimize storage efficiency.

1.10.1.4.1 Volume Efficiency
+ + + + + + +
VolumeCapacityUsedSnapshot UsedTotal SavingsEffective UsedEfficiency Percent
DAS9.5 GB940.0 KB2.0 MB750.2 KB1.7 MB0.0%
DAS_clone_5151.0 GB480.0 KB2.7 MB549.8 KB1.0 MB0.1%
DATA119.0 GB736.0 KB1.0 MB589.1 KB1.3 MB0.0%
DBs_dest121.6 MB368.0 KB188.0 KB180.0 KB548.0 KB0.4%
VM_DataStore28.5 GB1.0 MB2.4 MB798.0 KB1.8 MB0.0%
+
Table 107 - Volume Efficiency Savings - NFS

+

1.11 Security Information

The following section provides the Security related information in PHARMAX-HQ.

1.11.1 PHARMAX-HQ Vserver Local User

The following section provides the Local User information in PHARMAX-HQ.

@@ -616,117 +1313,159 @@
User NameApplicationAuth MethodRole NameLocked
adminAmqppasswordadminNo
adminConsolepasswordadminNo
adminSshpasswordadminNo
autosupportConsolepasswordautosupportNo
-
Table 56 - Security Local Users - PHARMAX-HQ

-

1.10.2 NAS Vserver Local User

The following section provides the Local User information on NAS.

+
Table 108 - Security Local Users - PHARMAX-HQ

+

1.11.2 CIFS Vserver Local User

The following section provides the Local User information in CIFS.

- - - + + +
User NameApplicationAuth MethodRole NameLocked
vsadminHttppasswordvsadminYes
vsadminOntapipasswordvsadminYes
vsadminSshpasswordvsadminYes
vsadminHttppasswordvsadminNo
vsadminOntapipasswordvsadminNo
vsadminSshpasswordvsadminNo
-
Table 57 - Security Local Users - NAS

-

1.10.3 SAN Vserver Local User

The following section provides the Local User information on SAN.

+
Table 109 - Security Local Users - CIFS

+

1.11.3 FCP Vserver Local User

The following section provides the Local User information in FCP.

+ + + + +
User NameApplicationAuth MethodRole NameLocked
vsadminHttppasswordvsadminNo
vsadminOntapipasswordvsadminNo
vsadminSshpasswordvsadminNo
+
Table 110 - Security Local Users - FCP

+

1.11.4 ISCSI Vserver Local User

The following section provides the Local User information in ISCSI.

+ + + + +
User NameApplicationAuth MethodRole NameLocked
vsadminHttppasswordvsadminNo
vsadminOntapipasswordvsadminNo
vsadminSshpasswordvsadminNo
+
Table 111 - Security Local Users - ISCSI

+

1.11.5 NFS Vserver Local User

The following section provides the Local User information in NFS.

User NameApplicationAuth MethodRole NameLocked
vsadminHttppasswordvsadminYes
vsadminOntapipasswordvsadminYes
vsadminSshpasswordvsadminYes
-
Table 58 - Security Local Users - SAN

-

1.10.4 Vserver SSL Certificate

The following section provides the Vserver SSL Certificates information on PHARMAX-HQ.

+
Table 112 - Security Local Users - NFS

+

1.11.6 Vserver SSL Certificate

The following section provides the Vserver SSL Certificates information in PHARMAX-HQ.

- - - -
Common NameCertificate AuthorityClient AuthServer AuthSerial NumberVserver
NASNASNoYes185C5D33114F6D5DNAS
PHARMAX-HQPHARMAX-HQNoYes1857FFF41883F7A4PHARMAX-HQ
SANSANNoYes18580D938FAA5CCBSAN
-
Table 59 - Per Vserver SSL - PHARMAX-HQ

-

1.10.4.1 Vserver SSL Certificate Details

+ + + + + +
CIFSCIFSNoYes187ECA83103365B0CIFS
FCPFCPNoYes188366D9C772700CFCP
ISCSIISCSINoYes187EC5E9C5482D4AISCSI
CIFSCIFSNoYes187EC4E124A07BFDNFS
PHARMAX-HQPHARMAX-HQNoYes187EB31560CB29BDPHARMAX-HQ
+
Table 113 - Per Vserver SSL - PHARMAX-HQ

+

1.11.6.1 Vserver SSL Certificate Details

- - - -
Common NameProtocolHash FunctionSerial NumberExpirationVserver
NASsslSHA256185C5D33114F6D5D8/16/2026NAS
PHARMAX-HQsslSHA2561857FFF41883F7A48/2/2026PHARMAX-HQ
SANsslSHA25618580D938FAA5CCB8/2/2026SAN
-
Table 60 - SSL Detailed - PHARMAX-HQ

-

1.10.5 Aggregate Encryption (NAE)

The following section provides the Aggregate Encryption (NAE) information on PHARMAX-HQ.

+ + + + + +
CIFSsslSHA256187ECA83103365B012/6/2026CIFS
FCPsslSHA256188366D9C772700C12/21/2026FCP
ISCSIsslSHA256187EC5E9C5482D4A12/6/2026ISCSI
CIFSsslSHA256187EC4E124A07BFD12/6/2026NFS
PHARMAX-HQsslSHA256187EB31560CB29BD12/6/2026PHARMAX-HQ
+
Table 114 - SSL Detailed - PHARMAX-HQ

+

1.11.7 Aggregate Encryption (NAE)

The following section provides the Aggregate Encryption (NAE) information in PHARMAX-HQ.

- - - - -
AggregateAggregate EncryptionVolume CountState
aggr0_PHARMAX_HQ_01No1Online
aggr0_PHARMAX_HQ_02No1Online
PHARMAX_HQ_01_SSD_1No2Online
PHARMAX_HQ_02_SSD_1No2Online
-
Table 61 - Aggregate Encryption (NAE) - PHARMAX-HQ

-

1.10.5.1 Volume Encryption (NVE)

+ + + + + + + + +
aggr0_cluster_01No1Online
aggr0_cluster_02No1Online
aggr0_cluster_03No1Online
aggr0_cluster_04No1Online
cluster_01_SSD_1No5Online
cluster_02_SSD_1No2Online
cluster_03_SSD_1No3Online
cluster_04_SSD_1No3Online
+
Table 115 - Aggregate Encryption (NAE) - PHARMAX-HQ

+

1.11.7.1 Volume Encryption (NVE)

- - -
NameAggregateEncryptedState
DATAPHARMAX_HQ_01_SSD_1NoOnline
SQL_DATAPHARMAX_HQ_01_SSD_1NoOnline
-
Table 62 - Volume Encryption (NVE) - PHARMAX-HQ

-

1.10.6 Snaplock Compliance Clock

The following section provides the Snaplock Compliance Clock information on PHARMAX-HQ.

+ + + + + + + + + +
DATAcluster_02_SSD_1NoOnline
DATA_destcluster_03_SSD_1NoOnline
Global_Documentscluster_02_SSD_1NoOnline
DBcluster_04_SSD_1NoOnline
DAScluster_01_SSD_1NoOnline
DAS_clone_515cluster_01_SSD_1NoOnline
DATA1cluster_04_SSD_1NoOnline
DBs_destcluster_01_SSD_1NoOnline
VM_DataStorecluster_03_SSD_1NoOnline
+
Table 116 - Volume Encryption (NVE) - PHARMAX-HQ

+

1.11.8 Snaplock Compliance Clock

The following section provides the Snaplock Compliance Clock information in PHARMAX-HQ.

- - + + + +
Node NameCompliance Clock
PHARMAX-HQ-01ComplianceClock is not configured.
PHARMAX-HQ-02ComplianceClock is not configured.
cluster-01Sun Feb 01 23:20:10 AST 2026 -04:00
cluster-02Sun Feb 01 23:19:25 AST 2026 -04:00
cluster-03Sun Feb 01 23:19:16 AST 2026 -04:00
cluster-04Sun Feb 01 23:20:12 AST 2026 -04:00
-
Table 63 - Snaplock Compliance Clock - PHARMAX-HQ

-

1.10.6.1 Aggregate Snaplock Type

+
Table 117 - Snaplock Compliance Clock - PHARMAX-HQ

+

1.11.8.1 Aggregate Snaplock Type

- - + + + +
Aggregate NameSnaplock Type
PHARMAX_HQ_01_SSD_1Non_Snaplock
PHARMAX_HQ_02_SSD_1Non_Snaplock
cluster_01_SSD_1Non_Snaplock
cluster_02_SSD_1Non_Snaplock
cluster_03_SSD_1Non_Snaplock
cluster_04_SSD_1Non_Snaplock
-
Table 64 - Aggregate Snaplock Type - PHARMAX-HQ

-
1.10.6.1.1 Volume Snaplock Type
+
Table 118 - Aggregate Snaplock Type - PHARMAX-HQ

+
1.11.8.1.1 Volume Snaplock Type
- - -
VolumeAggregateSnaplock Type
DATAPHARMAX_HQ_01_SSD_1Non_Snaplock
SQL_DATAPHARMAX_HQ_01_SSD_1Non_Snaplock
-
Table 65 - Volume Snaplock Type - PHARMAX-HQ

-

1.11 System Configuration Information

The following section provides the Cluster System Configuration on PHARMAX-HQ.

1.11.1 System Image Configuration

+ + + + + + + + + +
DATAcluster_02_SSD_1Non_Snaplock
DATA_destcluster_03_SSD_1Non_Snaplock
Global_Documentscluster_02_SSD_1Non_Snaplock
DBcluster_04_SSD_1Non_Snaplock
DAScluster_01_SSD_1Non_Snaplock
DAS_clone_515cluster_01_SSD_1Non_Snaplock
DATA1cluster_04_SSD_1Non_Snaplock
DBs_destcluster_01_SSD_1Non_Snaplock
VM_DataStorecluster_03_SSD_1Non_Snaplock
+
Table 119 - Volume Snaplock Type - PHARMAX-HQ

+

1.12 System Configuration Information

The following section provides the Cluster System Configuration in PHARMAX-HQ.

1.12.1 System Image Configuration

- - - - + + + +
NodeLocationIs CurrentIs DefaultInstall TimeVersion
PHARMAX-HQ-01image1YesYes08/02/2025 14:35:489.16.1P4
PHARMAX-HQ-01image2NoNo08/02/2025 13:54:169.15.1P11
PHARMAX-HQ-02image1YesYes08/02/2025 14:37:089.16.1P4
PHARMAX-HQ-02image2NoNo08/02/2025 13:56:069.15.1P11
cluster-01image1YesYes--9.18.1RC1
cluster-02image1YesYes--9.18.1RC1
cluster-03image1YesYes--9.18.1RC1
cluster-04image1YesYes--9.18.1RC1
-
Table 66 - System Image - PHARMAX-HQ

-

1.11.2 System Web Service

+
Table 120 - System Image - PHARMAX-HQ

+

1.12.2 System Web Service

- - + + + +
NodeHttp EnabledHttp PortHttps PortExternalStatusStatus Code
PHARMAX-HQ-01No80443YesOnline200
PHARMAX-HQ-02No80443YesOnline200
cluster-01No80443YesOnline200
cluster-02No80443YesOnline200
cluster-03No80443YesOnline200
cluster-04No80443YesOnline200
-
Table 67 - System Web Service - PHARMAX-HQ

-

1.11.3 DNS Configuration

+
Table 121 - Web Service - PHARMAX-HQ

+

1.12.3 DNS Configuration

- - + +
VserverDns StateDomainsName ServersTimeout/s
NASEnabledpharmax.local192.168.5.12
PHARMAX-HQEnabledpharmax.local192.168.5.12
CIFSEnabledpharmax.local192.168.5.12
PHARMAX-HQEnabledpharmax.local192.168.5.12
-
Table 68 - System DNS Configuration - PHARMAX-HQ

-

1.11.4 Configuration Backup Setting

+
Table 122 - DNS Configuration - PHARMAX-HQ

+
Health Check:

Best Practice: It is recommended to configure at least two DNS name servers for redundancy and reliability.

1.12.4 Configuration Backup Setting

UrlUsername
Not ConfiguredNot Configured
-
Table 69 - System Configuration Backup Setting - PHARMAX-HQ

-

1.11.5 EMS Configuration

The following section provides the EMS Configuration on PHARMAX-HQ.

+
Table 123 - Configuration Backup Setting - PHARMAX-HQ

+
Health Check:

Best Practice: It is recommended to backup the system configuration to a remote location to ensure recovery in case of failures.

1.12.5 EMS Configuration

The following section provides the EMS Configuration in PHARMAX-HQ.

- - - - - -
NameEmail DestinationsSnmp TraphostSnmp CommunitySyslogSyslog Facility
allevents-----
asup-----
criticals-----
pager-----
traphost-----
-
Table 70 - System EMS Configuration Setting - PHARMAX-HQ

-

1.11.5.1 Audit Settings

The following section provides information about Audit Setting from PHARMAX-HQ.

+ + + + + +
allevents----------
asup----------
criticals----------
pager----------
traphost----------
+
Table 124 - EMS Configuration Setting - PHARMAX-HQ

+
Health Check:

Best Practice: It is recommended to configure at least one EMS destination (Email, SNMP, or Syslog) to ensure proper monitoring and alerting of system events.

1.12.5.1 Audit Settings

The following section provides information about Audit Setting from PHARMAX-HQ.

Enable HTTP Get requestNo
Enable ONTAPI Get requestNo
Enable CLI Get requestNo
-
Table 71 - Audit Settings - PHARMAX-HQ

-

1.11.6 System Timezone Configuration

The following section provides the System Timezone Configuration on PHARMAX-HQ.

+
Table 125 - Audit Settings - PHARMAX-HQ

+

1.12.6 Timezone Configuration

The following section provides the Timezone Configuration in PHARMAX-HQ.

- +
TimezoneTimezone UTCTimezone VersionCurrent Time
America/Puerto_Rico-04002024a08/22/2025 15:31:34
America/Puerto_Rico-04002024a02/03/2026 17:17:16
-
Table 72 - System TimeZone - PHARMAX-HQ

-

1.11.6.1 NTP Configuration

+
Table 126 - TimeZone - PHARMAX-HQ

+

1.12.6.1 NTP Configuration

- +
Server NameNTP VersionPreferredAuthentication Enabled
192.168.5.1AutoNoNo
192.168.5.1AutoNoNo
-
Table 73 - System Network Time Protocol - PHARMAX-HQ

-
-

+
Table 127 - Network Time Protocol - PHARMAX-HQ

+
Health Check:

Best Practice: It is recommended to configure multiple NTP servers for redundancy and reliability.

+

\ No newline at end of file diff --git a/Src/Private/Get-AbrOntapCluster.ps1 b/Src/Private/Get-AbrOntapCluster.ps1 deleted file mode 100755 index fc22942..0000000 --- a/Src/Private/Get-AbrOntapCluster.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -function Get-AbrOntapCluster { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP cluster information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.8 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP cluster information." - } - - process { - 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' = ConvertTo-EmptyToFiller $ClusterInfo.ClusterContact - 'Cluster Location' = ConvertTo-EmptyToFiller $ClusterInfo.ClusterLocation - 'Ontap Version' = $ClusterVersion.value - 'Number of Aggregates' = $ArrayAggr.count - 'Number of Volumes' = $ArrayVolumes.count - 'Overall System Health' = switch ([string]::IsNullOrEmpty($ClusterDiag.Status)) { - $true { '--' } - $false { $ClusterDiag.Status.ToUpper() } - default { 'Unknown' } - } - } - 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' - } - - $TableParams = @{ - Name = "Cluster Information - $($ClusterInfo.ClusterName)" - List = $true - ColumnWidths = 25, 75 - } - if ($Report.ShowTableCaptions) { - $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 - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapClusterASUP.ps1 b/Src/Private/Get-AbrOntapClusterASUP.ps1 deleted file mode 100755 index 51951e5..0000000 --- a/Src/Private/Get-AbrOntapClusterASUP.ps1 +++ /dev/null @@ -1,75 +0,0 @@ -function Get-AbrOntapClusterASUP { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP cluster autoSupport status from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP AutoSupport information." - } - - process { - try { - $AutoSupport = Get-NcAutoSupportConfig -Controller $Array -ErrorAction Continue - if ($AutoSupport) { - $Outobj = @() - foreach ($NodesAUTO in $AutoSupport) { - try { - $Inobj = [ordered] @{ - 'Node Name' = $NodesAUTO.NodeName - 'Protocol' = $NodesAUTO.Transport - 'Enabled' = ConvertTo-TextYN $NodesAUTO.IsEnabled - 'Last Time Stamp' = $NodesAUTO.LastTimestampDT - 'Last Subject' = $NodesAUTO.LastSubject - } - $Outobj = [PSCustomObject]$Inobj - - if ($Healthcheck.Cluster.AutoSupport) { - $Outobj | Where-Object { $_.'Enabled' -like 'No' } | Set-Style -Style Warning -Property 'Enabled' - } - - $TableParams = @{ - Name = "Cluster AutoSupport Status - $($NodesAUTO.NodeName)" - List = $true - ColumnWidths = 25, 75 - } - if ($Report.ShowTableCaptions) { - $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 - } - } - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapClusterDiagram.ps1 b/Src/Private/Get-AbrOntapClusterDiagram.ps1 deleted file mode 100644 index bd24e63..0000000 --- a/Src/Private/Get-AbrOntapClusterDiagram.ps1 +++ /dev/null @@ -1,189 +0,0 @@ -function Get-AbrOntapClusterDiagram { - <# - .SYNOPSIS - Used by As Built Report to built NetApp ONTAP cluster diagram - .DESCRIPTION - - .NOTES - Version: 0.6.8 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Generating Cluster Diagram for NetApp ONTAP." - # Used for DiagramDebug - if ($Options.EnableDiagramDebug) { - $EdgeDebug = @{style = 'filled'; color = 'red' } - $SubGraphDebug = @{style = 'dashed'; color = 'red' } - $NodeDebug = @{color = 'black'; style = 'red'; shape = 'plain' } - $NodeDebugEdge = @{color = 'black'; style = 'red'; shape = 'plain' } - $IconDebug = $true - } else { - $EdgeDebug = @{style = 'invis'; color = 'red' } - $SubGraphDebug = @{style = 'invis'; color = 'gray' } - $NodeDebug = @{color = 'transparent'; style = 'transparent'; shape = 'point' } - $NodeDebugEdge = @{color = 'transparent'; style = 'transparent'; shape = 'none' } - $IconDebug = $false - } - - if ($Options.DiagramTheme -eq 'Black') { - $Edgecolor = 'White' - $Fontcolor = 'White' - } elseif ($Options.DiagramTheme -eq 'Neon') { - $Edgecolor = 'gold2' - $Fontcolor = 'gold2' - } else { - $Edgecolor = '#71797E' - $Fontcolor = '#565656' - } - } - - process { - try { - $ClusterInfo = Get-NcCluster -Controller $Array - $NodeSum = Get-NcNode -Controller $Array - - # $NodeSum = @( - # [pscustomobject]@{ - # Node = "PHARMAX-HQ-01" - # NodeModel = "A400" - # NodeSystemId = "1234567890" - # NodeSerialNumber = "SN1234567890" - # }, - # [pscustomobject]@{ - # Node = "PHARMAX-HQ-02" - # NodeModel = "A400" - # NodeSystemId = "0987654321" - # NodeSerialNumber = "SN0987654321" - # }, - # [pscustomobject]@{ - # Node = "PHARMAX-HQ-03" - # NodeModel = "FAS2720" - # NodeSystemId = "0987654322" - # NodeSerialNumber = "SN0987654322" - # }, - # [pscustomobject]@{ - # Node = "PHARMAX-HQ-04" - # NodeModel = "FAS2720" - # NodeSystemId = "0987654323" - # NodeSerialNumber = "SN0987654323" - # } - # ) - # $ClusterHaObj = @( - # [pscustomobject]@{ - # Name = "PHARMAX-HQ-01" - # Partner = "PHARMAX-HQ-02" - # State = "connected" - # }, - # [pscustomobject]@{ - # Name = "PHARMAX-HQ-02" - # Partner = "PHARMAX-HQ-01" - # State = "connected" - # }, - # [pscustomobject]@{ - # Name = "PHARMAX-HQ-03" - # Partner = "PHARMAX-HQ-04" - # State = "connected" - # }, - # [pscustomobject]@{ - # Name = "PHARMAX-HQ-04" - # Partner = "PHARMAX-HQ-03" - # State = "connected" - # } - # ) - - SubGraph Cluster -Attributes @{Label = $ClusterInfo.ClusterName; fontsize = 22; penwidth = 1.5; labelloc = 't'; style = "dashed,rounded"; color = "gray" } { - SubGraph ClusterInfo -Attributes @{Label = "Management: $($ClusterInfo.NcController)"; fontsize = 12; penwidth = 1.5; labelloc = 'b'; labeljust = 'r'; style = "dashed,rounded"; color = "transparent" } { - try { - - if ($NodeSum.Count -eq 1) { - $NodeSumColumnSize = 1 - } elseif ($ColumnSize) { - $NodeSumColumnSize = $ColumnSize - } else { - $NodeSumColumnSize = $NodeSum.Count - } - - $HAObject = @() - - $NodeAdditionalInfo = @() - - foreach ($Node in $NodeSum) { - # $ClusterHa = $ClusterHaObj | Where-Object { $_.Name -eq $Node.Node } - $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 - - if ($ClusterHa.Name -notin $HAObject.Partner) { - $HAObject += [PSCustomObject][ordered]@{ - "Name" = $ClusterHa.Name - "Partner" = $ClusterHa.Partner - "HAState" = $ClusterHa.State - } - } - - $NodeAdditionalInfo += [PSCustomObject][ordered]@{ - 'NodeName' = $Node.Node - 'AdditionalInfo' = [PSCustomObject][ordered]@{ - "System Id" = $Node.NodeSystemId - "Serial" = $Node.NodeSerialNumber - "Model" = $Node.NodeModel - "Mgmt" = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { - $true { "Unknown" } - $false { $NodeMgmtAddress } - default { "Unknown" } - } - } - } - } - - if ($HAObject.Name -and $HAObject.Partner) { - foreach ($HA in $HAObject) { - $HAClusterName = Remove-SpecialChar -String "HA$($HA.Name)$($HA.Partner)" -SpecialChars '\-_' - SubGraph $HAClusterName -Attributes @{Label = "HA Pair"; fontsize = 14; penwidth = 1.5; labelloc = 't'; style = "dashed,rounded"; color = "gray"; labeljust = 'c' } { - - $HAName = Remove-SpecialChar -String $HA.Name -SpecialChars '\-_' - $HAPartner = Remove-SpecialChar -String $HA.Partner -SpecialChars '\-_' - - Node $HAName @{Label = Add-DiaNodeIcon -Name $HA.Name -AditionalInfo ($NodeAdditionalInfo | Where-Object { $_.NodeName -eq $HA.Name }).AdditionalInfo -ImagesObj $Images -IconType "Ontap_Node" -Align "Center" -IconDebug $IconDebug -FontSize 18; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } - - Node $HAPartner @{Label = Add-DiaNodeIcon -Name $HA.Partner -AditionalInfo ($NodeAdditionalInfo | Where-Object { $_.NodeName -eq $HA.Partner }).AdditionalInfo -ImagesObj $Images -IconType "Ontap_Node" -Align "Center" -IconDebug $IconDebug -FontSize 18; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } - - Rank $HAName, $HAPartner - - Edge -From $HAName -To $HAPartner -Attributes @{minlen = 2; label = "HA: $($HA.HAState)"; color = $Edgecolor; fontcolor = $Fontcolor; fontsize = 16; style = 'solid'; penwidth = 2; arrowhead = 'box'; arrowtail = 'box' } - } - } - } else { - foreach ($HA in $HAObject) { - $HAClusterName = Remove-SpecialChar -String "HA$($HA.Name)" -SpecialChars '\-_' - SubGraph $HAClusterName -Attributes @{Label = "Single Node Cluster"; fontsize = 12; penwidth = 1.5; labelloc = 't'; style = "dashed,rounded"; color = "gray"; labeljust = 'c' } { - $HAName = Remove-SpecialChar -String $HA.Name -SpecialChars '\-_' - Node $HAName @{Label = Add-DiaNodeIcon -Name $HA.Name -AditionalInfo ($NodeAdditionalInfo | Where-Object { $_.NodeName -eq $HA.Name }).AdditionalInfo -ImagesObj $Images -IconType "Ontap_Node" -Align "Center" -IconDebug $IconDebug -FontSize 18; shape = 'plain'; fillColor = 'transparent'; fontsize = 14 } - } - } - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - } - - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapClusterHA.ps1 b/Src/Private/Get-AbrOntapClusterHA.ps1 deleted file mode 100755 index 208d2b7..0000000 --- a/Src/Private/Get-AbrOntapClusterHA.ps1 +++ /dev/null @@ -1,100 +0,0 @@ -function Get-AbrOntapClusterHA { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP cluster HA information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.9 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP cluster high availability information." - } - - process { - try { - $NodeSum = Get-NcNode -Controller $Array | Where-Object { $null -ne $_.NodeModel } - if ($NodeSum) { - $NodeSummary = foreach ($Nodes in $NodeSum) { - try { - $ClusterHa = Get-NcClusterHa -Node $Nodes.Node -Controller $Array - [PSCustomObject] @{ - 'Name' = $Nodes.Node - '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)) { - 'True' { '-' } - 'False' { $ClusterHa.TakeoverState } - default { 'Unknwon' } - } - 'HA Mode' = $ClusterHa.CurrentMode - 'HA State' = $ClusterHa.State - } - } 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' -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 = @{ - Name = "Cluster HA Status - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 20, 20, 11, 19, 10, 20 - } - 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' }))) { - 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 - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapDiskAssign.ps1 b/Src/Private/Get-AbrOntapDiskAssign.ps1 deleted file mode 100755 index d4fe896..0000000 --- a/Src/Private/Get-AbrOntapDiskAssign.ps1 +++ /dev/null @@ -1,52 +0,0 @@ -function Get-AbrOntapDiskAssign { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP disk assign summary information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP disk assignment per node information." - } - - process { - try { - $NodeDiskCount = Get-NcDisk -Controller $Array | ForEach-Object { $_.DiskOwnershipInfo.HomeNodeName } | Group-Object - if ($NodeDiskCount) { - $DiskSummary = foreach ($Disks in $NodeDiskCount) { - [PSCustomObject] @{ - 'Node' = $Disks.Name - 'Disk Count' = $Disks | Select-Object -ExpandProperty Count - } - } - $TableParams = @{ - Name = "Assigned Disk - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 50, 50 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $DiskSummary | Table @TableParams - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapDiskInv.ps1 b/Src/Private/Get-AbrOntapDiskInv.ps1 deleted file mode 100755 index 3653e48..0000000 --- a/Src/Private/Get-AbrOntapDiskInv.ps1 +++ /dev/null @@ -1,72 +0,0 @@ -function Get-AbrOntapDiskInv { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP disk inventort information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP disk inventory per node." - } - - process { - try { - $DiskInv = Get-NcDisk -Controller $Array - $NodeDiskBroken = Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq "broken" } - if ($DiskInv) { - $DiskInventory = foreach ($Disks in $DiskInv) { - try { - $DiskType = Get-NcDisk -Controller $Array -Name $Disks.Name | ForEach-Object { $_.DiskInventoryInfo } - $DiskFailed = $NodeDiskBroken | Where-Object { $_.'Name' -eq $Disks.Name } - if ($DiskFailed.Name -eq $Disks.Name ) { - $Disk = " $($DiskFailed.Name)(*)" - } else { - $Disk = $Disks.Name - } - [PSCustomObject] @{ - 'Disk Name' = $Disk - 'Shelf' = $Disks.Shelf - 'Bay' = $Disks.Bay - 'Capacity' = $Disks.Capacity | ConvertTo-FormattedNumber -Type Disksize -ErrorAction SilentlyContinue - 'Model' = $Disks.Model - 'Serial Number' = $DiskType.SerialNumber - 'Type' = $DiskType.DiskType - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - if ($Healthcheck.Storage.DiskStatus) { - $DiskInventory | Where-Object { $_.'Disk Name' -like '*(*)' } | Set-Style -Style Critical -Property 'Disk Name' - } - $TableParams = @{ - Name = "Disk Inventory - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 15, 10, 10, 10, 25, 18, 12 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $DiskInventory | Table @TableParams - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapDiskShelf.ps1 b/Src/Private/Get-AbrOntapDiskShelf.ps1 deleted file mode 100755 index 5e5d2ec..0000000 --- a/Src/Private/Get-AbrOntapDiskShelf.ps1 +++ /dev/null @@ -1,78 +0,0 @@ -function Get-AbrOntapDiskShelf { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP disk shelf information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP disk shelf information." - } - - process { - try { - $NodeSum = Get-NcNode -Controller $Array - if ($NodeSum) { - $ShelfInventory = foreach ($Nodes in $NodeSum) { - try { - $Nodeshelf = Get-NcShelf -NodeName $Nodes.Node -Controller $Array - if ($Nodeshelf) { - [PSCustomObject] @{ - 'Node Name' = $Nodeshelf.NodeName - 'Channel' = $Nodeshelf.ChannelName - 'Shelf Name' = $Nodeshelf.ShelfName - 'Shelf ID' = $Nodeshelf.ShelfId - 'State' = $Nodeshelf.ShelfState - 'Type' = $Nodeshelf.ShelfType - 'Firmware' = $Nodeshelf.FirmwareRevA + $Nodeshelf.FirmwareRevB - 'Bay Count' = $Nodeshelf.ShelfBayCount - } - } - } 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' - } - $TableParams = @{ - Name = "Shelf Inventory - $($ClusterInfo.ClusterName)" - List = $true - ColumnWidths = 35, 65 - } - 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' })) { - 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 - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapDiskType.ps1 b/Src/Private/Get-AbrOntapDiskType.ps1 deleted file mode 100755 index d76f7ef..0000000 --- a/Src/Private/Get-AbrOntapDiskType.ps1 +++ /dev/null @@ -1,94 +0,0 @@ -function Get-AbrOntapDiskType { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP disk type information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP disk type per node information." - } - - process { - try { - $NodeDiskContainerType = Get-NcDisk -Controller $Array | ForEach-Object { $_.DiskRaidInfo.ContainerType } | Group-Object - if ($NodeDiskContainerType) { - $DiskType = foreach ($DiskContainers in $NodeDiskContainerType) { - try { - [PSCustomObject] @{ - 'Container' = $DiskContainers.Name - 'Disk Count' = $DiskContainers | Select-Object -ExpandProperty Count - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - if ($Healthcheck.Storage.DiskStatus) { - $DiskType | Where-Object { $_.'Container' -like 'broken' } | Set-Style -Style Critical -Property 'Disk Count' - } - $TableParams = @{ - Name = "Disk Container Type - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 50, 50 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $DiskType | 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) { - try { - $DiskSpareLow = Confirm-NcAggrSpareLow -Node $Item.Node - [PSCustomObject] @{ - 'Node' = $Item.Node - 'Aggregate Spare Low' = $DiskSpareLow.Value.ToString().Replace("True", "Yes").Replace("False", "No") - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - if ($Healthcheck.Storage.DiskStatus) { - $OutObj | Where-Object { $_.'Aggregate Spare Low' -like 'Yes' } | Set-Style -Style Critical -Property 'Node', 'Aggregate Spare Low' - } - $TableParams = @{ - Name = "HealthCheck - Aggregate Disk Spare Low - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 50, 50 - } - if ($Report.ShowTableCaptions) { - $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 - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 deleted file mode 100755 index 7b118a3..0000000 --- a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 +++ /dev/null @@ -1,295 +0,0 @@ -function Get-AbrOntapNetworkMgmt { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP network management interfaces information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP network management interface information." - } - - process { - try { - if (Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'cluster' }) { - 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' = switch ($Item.OpStatus) { - "" { "Unknown" } - $Null { "Unknown" } - default { $Item.OpStatus.ToString().ToUpper() } - } - 'Data Protocols' = $Item.DataProtocols - 'Address' = $Item.Address - 'Vserver' = $Item.Vserver - } - $ClusterObj += [pscustomobject]$inobj - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - 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 - } - } - } - } 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) { - foreach ($Item in $ClusterData) { - try { - $inObj = [ordered] @{ - 'MGMT Interface' = $Item.InterfaceName - 'Status' = switch ($Item.OpStatus) { - "" { "Unknown" } - $Null { "Unknown" } - default { $Item.OpStatus.ToString().ToUpper() } - } - 'Data Protocols' = $Item.DataProtocols - 'Address' = $Item.Address - 'Vserver' = $Item.Vserver - } - $ClusterObj += [pscustomobject]$inobj - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - if ($Healthcheck.Network.Interface) { - $ClusterObj | Where-Object { $_.'Status' -notlike 'UP' } | Set-Style -Style Warning -Property 'Status' - } - - $TableParams = @{ - Name = "Management 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 management network interfaces are operational (UP) to maintain proper management access to the cluster." - } - BlankLine - } - } - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - try { - if (Get-NcNetInterface -Controller $Array | Where-Object { $_.Role -eq 'intercluster' }) { - 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' = switch ($Item.OpStatus) { - "" { "Unknown" } - $Null { "Unknown" } - default { $Item.OpStatus.ToString().ToUpper() } - } - 'Data Protocols' = $Item.DataProtocols - 'Address' = $Item.Address - 'Vserver' = $Item.Vserver - } - $ClusterObj += [pscustomobject]$inobj - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - 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 - } - } - } - } - } 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) { - foreach ($Item in $ClusterData) { - try { - if ($Item.Wwpn) { - $AddressData = $Item.Wwpn - } else { $AddressData = $Item.Address } - $inObj = [ordered] @{ - 'Data Interface' = $Item.InterfaceName - 'Status' = switch ($Item.OpStatus) { - "" { "Unknown" } - $Null { "Unknown" } - default { $Item.OpStatus.ToString().ToUpper() } - } - 'Data Protocols' = [string]$Item.DataProtocols - 'Address' = $AddressData - 'Vserver' = $Item.Vserver - } - $ClusterObj += [pscustomobject]$inobj - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - if ($Healthcheck.Network.Interface) { - $ClusterObj | Where-Object { $_.'Status' -notlike 'UP' } | Set-Style -Style Warning -Property 'Status' - } - - $TableParams = @{ - Name = "Data Network - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 33, 10, 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 data network interfaces are operational (UP) to maintain optimal data access and performance." - } - BlankLine - } - } - } - } catch { - 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' { - 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' = switch ($Item.IsHome) { - "True" { 'Yes' } - "False" { "No" } - default { $Item.IsHome } - } - 'Vserver' = $Item.Vserver - } - $ClusterObj += [pscustomobject]$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' - } - - $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 { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapNodesHW.ps1 b/Src/Private/Get-AbrOntapNodesHW.ps1 deleted file mode 100755 index a4f821f..0000000 --- a/Src/Private/Get-AbrOntapNodesHW.ps1 +++ /dev/null @@ -1,89 +0,0 @@ -function Get-AbrOntapNodesHW { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP system nodes hardware information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP Node Hardware information." - } - - process { - try { - $NodeHW = Get-NcNodeInfo -Controller $Array -ErrorAction Continue - if ($NodeHW) { - $Outobj = @() - foreach ($NodeHWs in $NodeHW) { - try { - $NodeInfo = Get-NcNode -Node $NodeHWs.SystemName -Controller $Array - $Inobj = [ordered] @{ - 'Name' = $NodeHWs.SystemName - 'System Type' = $NodeHWs.SystemMachineType - 'CPU Count' = $NodeHWs.NumberOfProcessors - 'Total Memory' = "$($NodeHWs.MemorySize / 1024)GB" - 'Vendor' = $NodeHWs.VendorId - 'AFF/FAS' = $NodeHWs.ProdType - 'All Flash Optimized' = ConvertTo-TextYN $NodeInfo.IsAllFlashOptimized - 'Epsilon' = ConvertTo-TextYN $NodeInfo.IsEpsilonNode - 'System Healthy' = switch ($NodeInfo.IsNodeHealthy) { - "True" { "Healthy" } - "False" { "UnHealthy" } - default { $NodeInfo.IsNodeHealthy } - } - 'Failed Fan Count' = $NodeInfo.EnvFailedFanCount - 'Failed Fan Error' = $NodeInfo.EnvFailedFanMessage - 'Failed PowerSupply Count' = $NodeInfo.EnvFailedPowerSupplyCount - 'Failed PowerSupply Error' = $NodeInfo.EnvFailedPowerSupplyMessage - 'Over Temperature' = switch ($NodeInfo.EnvOverTemperature) { - "True" { "High Temperature" } - "False" { "Normal Temperature" } - default { $NodeInfo.EnvOverTemperature } - } - 'NVRAM Battery Healthy' = $NodeInfo.NvramBatteryStatus - } - $Outobj = [PSCustomObject]$Inobj - - if ($Healthcheck.Node.HW) { - $Outobj | Where-Object { $_.'System Healthy' -like 'UnHealthy' } | Set-Style -Style Critical -Property 'System Healthy' - $Outobj | Where-Object { $_.'Failed Fan Count' -gt 0 } | Set-Style -Style Critical -Property 'Failed Fan Count' - $Outobj | Where-Object { $_.'Failed PowerSupply Count' -gt 0 } | Set-Style -Style Critical -Property 'Failed PowerSupply Count' - $Outobj | Where-Object { $_.'Over Temperature' -like 'High Temperature' } | Set-Style -Style Critical -Property 'Over Temperature' - $Outobj | Where-Object { $_.'NVRAM Battery Healthy' -notlike 'battery_ok' } | Set-Style -Style Critical -Property 'NVRAM Battery Healthy' - } - - $TableParams = @{ - Name = "Node Hardware - $($NodeHWs.SystemName)" - List = $true - ColumnWidths = 40, 60 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $Outobj | Table @TableParams - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapNodesSP.ps1 b/Src/Private/Get-AbrOntapNodesSP.ps1 deleted file mode 100755 index f3240b3..0000000 --- a/Src/Private/Get-AbrOntapNodesSP.ps1 +++ /dev/null @@ -1,76 +0,0 @@ -function Get-AbrOntapNodesSP { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP system nodes service-processor information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP Node Service-Processor information." - } - - process { - try { - $ServiceProcessor = Get-NcServiceProcessor -Controller $Array - if ($ServiceProcessor) { - $NodeServiceProcessor = foreach ($NodeSPs in $ServiceProcessor) { - try { - [PSCustomObject] @{ - 'Name' = $NodeSPs.Node - 'Type' = $NodeSPs.Type - 'IP Address' = $NodeSPs.IpAddress - 'MAC Address' = $NodeSPs.MacAddress - 'Network Configured' = $NodeSPs.IsIpConfigured - 'Firmware' = $NodeSPs.FirmwareVersion - 'Status' = $NodeSPs.Status - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - if ($Healthcheck.Node.ServiceProcessor) { - $NodeServiceProcessor | Where-Object { $_.'Status' -like 'offline' -or $_.'Status' -like 'degraded' } | Set-Style -Style Critical -Property 'Status' - $NodeServiceProcessor | Where-Object { $_.'Status' -like 'unknown' -or $_.'Status' -like 'sp-daemon-offline' } | Set-Style -Style Warning -Property 'Status' - $NodeServiceProcessor | Where-Object { $_.'Network Configured' -like "false" } | Set-Style -Style Critical -Property 'Network Configured' - } - } - - $TableParams = @{ - Name = "Node Service-Processor - $($ClusterInfo.ClusterName)" - List = $true - ColumnWidths = 35, 65 - } - if ($Report.ShowTableCaptions) { - $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 - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapStorageAGGR.ps1 b/Src/Private/Get-AbrOntapStorageAGGR.ps1 deleted file mode 100755 index ffbd0b1..0000000 --- a/Src/Private/Get-AbrOntapStorageAGGR.ps1 +++ /dev/null @@ -1,203 +0,0 @@ -function Get-AbrOntapStorageAGGR { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP storage summary information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - Write-PScriboMessage "Collecting ONTAP storage aggregate information." - } - - process { - try { - $AggrSpace = Get-NcAggr -Controller $Array - if ($AggrSpace) { - $AggrSpaceSummary = foreach ($Aggr in $AggrSpace) { - try { - $RootAggr = Get-NcAggr $Aggr.Name -Controller $Array | ForEach-Object { $_.AggrRaidAttributes.HasLocalRoot } - [PSCustomObject] @{ - 'Name' = $Aggr.Name - '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)) { - $true { 'Unknown' } - $false { $Aggr.Available | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } - default { 'Unknown' } - } - '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)) { - $true { 'Unknown' } - $false { ($Aggr.RaidType.Split(",")[0]).ToUpper() } - default { 'Unknown' } - } - 'State' = $Aggr.State - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - if ($Healthcheck.Storage.Aggr) { - $AggrSpaceSummary | Where-Object { $_.'State' -eq 'failed' } | Set-Style -Style Critical -Property 'State' - $AggrSpaceSummary | Where-Object { $_.'State' -eq 'unknown' -or $_.'State' -eq 'offline' } | Set-Style -Style Warning -Property 'State' - $AggrSpaceSummary | Where-Object { $_.'Used' -ge 90 } | Set-Style -Style Critical -Property 'Used' - } - $TableParams = @{ - Name = "Aggregates - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 27, 10, 10, 10, 10, 8, 15, 10 - } - if ($Report.ShowTableCaptions) { - $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 - if ($AggrSpare) { - Section -Style Heading4 'Aggregate Spares' { - $AggrSpareSummary = foreach ($Spare in $AggrSpare) { - try { - [PSCustomObject] @{ - 'Name' = $Spare.Disk - 'Capacity' = switch ([string]::IsNullOrEmpty($Spare.TotalSize)) { - $true { '-' } - $false { $Spare.TotalSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } - default { '-' } - } - '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)) { - $true { '-' } - $false { $Spare.LocalUsableDataSize | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } - default { '-' } - } - 'Shared Disk' = ConvertTo-TextYN $Spare.IsDiskShared - 'Disk Zeroed' = ConvertTo-TextYN $Spare.IsDiskZeroed - 'Owner' = $Spare.OriginalOwner - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - if ($Healthcheck.Storage.Aggr) { - $AggrSpareSummary | Where-Object { $_.'Disk Zeroed' -eq 'No' } | Set-Style -Style Warning -Property 'Disk Zeroed' - } - $TableParams = @{ - Name = "Aggregates Spares - $($ClusterInfo.ClusterName)" - List = $false - ColumnWidths = 20, 12, 12, 12, 12, 12, 20 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $AggrSpareSummary | Table @TableParams - } - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - try { - if ($InfoLevel.Storage -ge 2) { - Section -Style Heading4 'Aggregate Options' { - $Aggregates = Get-NcAggr -Controller $Array | Where-Object { !$_.AggrRaidAttributes.HasLocalRoot } - foreach ($Aggregate in $Aggregates) { - try { - Section -Style Heading5 "$($Aggregate.Name) Options" { - $OutObj = @() - $Options = Get-NcAggrOption -Controller $Array -Name $Aggregate.Name - $Option = @{} - $Options | ForEach-Object { $Option.add($_.Name, $_.Value) } - $inObj = [ordered] @{ - 'azcs_read_optimization' = $TextInfo.ToTitleCase($Option.azcs_read_optimization) - 'dir_holes' = ConvertTo-TextYN $Option.dir_holes - 'dlog_hole_reserve' = $TextInfo.ToTitleCase($Option.dlog_hole_reserve) - 'enable_cold_data_reporting' = ConvertTo-TextYN $Option.enable_cold_data_reporting - 'encrypt_with_aggr_key' = ConvertTo-TextYN $Option.encrypt_with_aggr_key - 'free_space_realloc' = $TextInfo.ToTitleCase($Option.free_space_realloc) - 'fs_size_fixed' = $TextInfo.ToTitleCase($Option.fs_size_fixed) - 'ha_policy' = $TextInfo.ToTitleCase($Option.ha_policy) - 'hybrid_enabled' = ConvertTo-TextYN $Option.hybrid_enabled - 'ignore_inconsistent' = $TextInfo.ToTitleCase($Option.ignore_inconsistent) - 'logical_space_enforcement' = ConvertTo-TextYN $Option.logical_space_enforcement - 'logical_space_reporting' = ConvertTo-TextYN $Option.logical_space_reporting - 'max_write_alloc_blocks' = $TextInfo.ToTitleCase($Option.max_write_alloc_blocks) - 'nearly_full_threshold' = $TextInfo.ToTitleCase($Option.nearly_full_threshold) - 'no_delete_log' = $TextInfo.ToTitleCase($Option.no_delete_log) - 'no_i2p' = $TextInfo.ToTitleCase($Option.no_i2p) - 'nosnap' = $TextInfo.ToTitleCase($Option.nosnap) - 'percent_snapshot_space' = $TextInfo.ToTitleCase($Option.percent_snapshot_space) - 'raid_cv' = $TextInfo.ToTitleCase($Option.raid_cv) - 'raid_lost_write' = $TextInfo.ToTitleCase($Option.raid_lost_write) - 'raidsize' = $TextInfo.ToTitleCase($Option.raidsize) - 'raidtype' = $TextInfo.ToTitleCase($Option.raidtype) - 'resyncsnaptime' = $TextInfo.ToTitleCase($Option.resyncsnaptime) - 'single_instance_data_logging' = $TextInfo.ToTitleCase($Option.single_instance_data_logging) - 'snapmirrored' = $TextInfo.ToTitleCase($Option.snapmirrored) - 'snapshot_autodelete' = $TextInfo.ToTitleCase($Option.snapshot_autodelete) - 'striping' = $TextInfo.ToTitleCase($Option.striping) - 'thorough_scrub' = $TextInfo.ToTitleCase($Option.thorough_scrub) - } - $OutObj += [pscustomobject]$inobj - - $TableParams = @{ - Name = "Aggregates Options - $($Aggregate.Name)" - List = $true - ColumnWidths = 50, 50 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $OutObj | Table @TableParams - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - } - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - - end {} - -} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapVserverNFSExport.ps1 b/Src/Private/Get-AbrOntapVserverNFSExport.ps1 deleted file mode 100755 index 901e872..0000000 --- a/Src/Private/Get-AbrOntapVserverNFSExport.ps1 +++ /dev/null @@ -1,71 +0,0 @@ -function Get-AbrOntapVserverNFSExport { - <# - .SYNOPSIS - Used by As Built Report to retrieve NetApp ONTAP Vserver NFS Export information from the Cluster Management Network - .DESCRIPTION - - .NOTES - Version: 0.6.7 - Author: Jonathan Colon - Twitter: @jcolonfzenpr - Github: rebelinux - .EXAMPLE - - .LINK - - #> - param ( - [Parameter ( - Position = 0, - Mandatory)] - [string] - $Vserver - ) - - begin { - Write-PScriboMessage "Collecting ONTAP Vserver NFS Export information." - } - - process { - try { - $VserverData = Get-NcVserver -VserverContext $Vserver -Controller $Array | Where-Object { $_.VserverType -eq 'data' -and $_.AllowedProtocols -eq 'nfs' -and $_.State -eq 'running' } - $VserverObj = @() - if ($VserverData) { - foreach ($SVM in $VserverData) { - try { - $NFSVserver = Get-NcNfsExport -VS $SVM.Vserver -Controller $Array - foreach ($Item in $NFSVserver) { - try { - $inObj = [ordered] @{ - 'Vserver' = $SVM.Vserver - 'Path Name' = $Item.Pathname - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - $VserverObj += [pscustomobject]$inobj - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - - $TableParams = @{ - Name = "NFS Service Volume Export - $($Vserver)" - List = $false - ColumnWidths = 35, 65 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - if ($VserverObj) { - $VserverObj | Table @TableParams - } - } - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message - } - } - end {} - -} \ No newline at end of file diff --git a/Src/Private/SharedUtilsFunctions.ps1 b/Src/Private/SharedUtilsFunctions.ps1 deleted file mode 100644 index 73a097d..0000000 --- a/Src/Private/SharedUtilsFunctions.ps1 +++ /dev/null @@ -1,89 +0,0 @@ -function ConvertTo-TextYN { - <# - .SYNOPSIS - Used by As Built Report to convert true or false automatically to Yes or No. - .DESCRIPTION - - .NOTES - Version: 0.2.0 - Author: LEE DAILEY - - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - [OutputType([String])] - param - ( - [Parameter ( - Position = 0, - Mandatory)] - [AllowEmptyString()] - [string] - $TEXT - ) - - switch ([string]::IsNullOrEmpty($TEXT)) { - $true { '-' } - $false { - switch ($TEXT) { - "True" { "Yes"; break } - "False" { "No"; break } - default { $TEXT } - } - } - default { '-' } - } -} # end -function Get-UnixDate ($UnixDate) { - <# - .SYNOPSIS - Used by As Built Report to convert Date to a more nice format. - .DESCRIPTION - - .NOTES - Version: 0.2.0 - Author: LEE DAILEY - - .EXAMPLE - - .LINK - - #> - [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($UnixDate)) -} # end -function ConvertTo-EmptyToFiller { - <# - .SYNOPSIS - Used by As Built Report to convert empty culumns to "-". - .DESCRIPTION - - .NOTES - Version: 0.5.0 - Author: Jonathan Colon - - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - [OutputType([String])] - param - ( - [Parameter ( - Position = 0, - Mandatory)] - [AllowEmptyString()] - [string] - $TEXT - ) - - switch ([string]::IsNullOrEmpty($TEXT)) { - $true { "-"; break } - $false { $TEXT; break } - default { '-' } - } -} # end \ No newline at end of file diff --git a/Todo.md b/Todo.md new file mode 100644 index 0000000..e69de29