diff --git a/.github/workflows/PSScriptAnalyzer.yml b/.github/workflows/PSScriptAnalyzer.yml index a73694f..edf12f4 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@v5 + - 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..3d90aae 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -1,61 +1,61 @@ name: Publish PowerShell Module on: - release: - types: [published] + release: + types: [published] jobs: - publish-to-gallery: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - name: Set PSRepository to Trusted for PowerShell Gallery - shell: pwsh - run: | - Set-PSRepository -Name PSGallery -InstallationPolicy Trusted - - name: Install AsBuiltReport.Core module - shell: pwsh - run: | - Install-Module -Name AsBuiltReport.Core -Repository PSGallery -Force - - name: Install NetApp.ONTAP module - shell: pwsh - run: | - Install-Module -Name NetApp.ONTAP -Repository PSGallery -Force - - name: Install Diagrammer.Core module - shell: pwsh - run: | - Install-Module -Name Diagrammer.Core -Repository PSGallery -Force - - name: Test Module Manifest - shell: pwsh - run: | - Test-ModuleManifest .\AsBuiltReport.NetApp.ONTAP.psd1 - - name: Publish module to PowerShell Gallery - shell: pwsh - run: | - Publish-Module -Path ./ -NuGetApiKey ${{ secrets.PSGALLERY_API_KEY }} -Verbose - tweet: - needs: publish-to-gallery - runs-on: ubuntu-latest - steps: - - uses: Eomm/why-don-t-you-tweet@v2 - # We don't want to tweet if the repository is not a public one - if: ${{ !github.event.repository.private }} - with: - # GitHub event payload - # https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#release - tweet-message: "[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: - TWITTER_CONSUMER_API_KEY: ${{ secrets.TWITTER_CONSUMER_API_KEY }} - TWITTER_CONSUMER_API_SECRET: ${{ secrets.TWITTER_CONSUMER_API_SECRET }} - TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} - TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} - bsky-post: - needs: publish-to-gallery - runs-on: ubuntu-latest - steps: - - uses: zentered/bluesky-post-action@v0.3.0 - with: - 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 + publish-to-gallery: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Set PSRepository to Trusted for PowerShell Gallery + shell: pwsh + run: | + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + - name: Install AsBuiltReport.Core module + shell: pwsh + run: | + Install-Module -Name AsBuiltReport.Core -Repository PSGallery -Force + - name: Install NetApp.ONTAP module + shell: pwsh + run: | + Install-Module -Name NetApp.ONTAP -Repository PSGallery -Force + - name: Install Diagrammer.Core module + shell: pwsh + run: | + Install-Module -Name Diagrammer.Core -Repository PSGallery -Force + - name: Test Module Manifest + shell: pwsh + run: | + Test-ModuleManifest .\AsBuiltReport.NetApp.ONTAP.psd1 + - name: Publish module to PowerShell Gallery + shell: pwsh + run: | + Publish-Module -Path ./ -NuGetApiKey ${{ secrets.PSGALLERY_API_KEY }} -Verbose + tweet: + needs: publish-to-gallery + runs-on: ubuntu-latest + steps: + - uses: Eomm/why-don-t-you-tweet@v2 + # We don't want to tweet if the repository is not a public one + if: ${{ !github.event.repository.private }} + with: + # GitHub event payload + # https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#release + tweet-message: "[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: + TWITTER_CONSUMER_API_KEY: ${{ secrets.TWITTER_CONSUMER_API_KEY }} + TWITTER_CONSUMER_API_SECRET: ${{ secrets.TWITTER_CONSUMER_API_SECRET }} + TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} + TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + bsky-post: + needs: publish-to-gallery + runs-on: ubuntu-latest + steps: + - uses: zentered/bluesky-post-action@v0.3.0 + with: + 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 }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a2aeb0f..f64bb63 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@v5 - - 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@v3 + with: + sarif_file: results.sarif diff --git a/AsBuiltReport.NetApp.ONTAP.Style.ps1 b/AsBuiltReport.NetApp.ONTAP.Style.ps1 index 91ce353..888d644 100755 --- a/AsBuiltReport.NetApp.ONTAP.Style.ps1 +++ b/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.json index 73f269f..ec53809 100755 --- a/AsBuiltReport.NetApp.ONTAP.json +++ b/AsBuiltReport.NetApp.ONTAP.json @@ -25,7 +25,8 @@ "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.psd1 index 55a542e..3e5fd51 100755 --- a/AsBuiltReport.NetApp.ONTAP.psd1 +++ b/AsBuiltReport.NetApp.ONTAP.psd1 @@ -12,7 +12,7 @@ RootModule = 'AsBuiltReport.NetApp.ONTAP.psm1' # Version number of this module. - ModuleVersion = '0.6.11' + ModuleVersion = '0.6.12' # Supported PSEditions # CompatiblePSEditions = @() @@ -54,7 +54,7 @@ RequiredModules = @( @{ ModuleName = 'AsBuiltReport.Core'; - ModuleVersion = '1.5.0' + ModuleVersion = '1.5.1' }, @{ ModuleName = 'NetApp.ONTAP'; @@ -62,7 +62,7 @@ }, @{ ModuleName = 'Diagrammer.Core'; - ModuleVersion = '0.2.33' + ModuleVersion = '0.2.36' } ) diff --git a/AsBuiltReport.NetApp.ONTAP.psm1 b/AsBuiltReport.NetApp.ONTAP.psm1 index e22b0dc..0ceac63 100755 --- a/AsBuiltReport.NetApp.ONTAP.psm1 +++ b/AsBuiltReport.NetApp.ONTAP.psm1 @@ -1,3 +1,31 @@ +# Get assemblies files and import them +$assemblyName = switch ($PSVersionTable.PSEdition) { + 'Core' { + if ($IsMacOS) { + @(Get-ChildItem -Path ("$PSScriptRoot{0}Src{0}Bin{0}Assemblies{0}net90{0}osx-x64{0}*.dll" -f [System.IO.Path]::DirectorySeparatorChar) -ErrorAction SilentlyContinue) + } elseif ($IsLinux) { + @(Get-ChildItem -Path ("$PSScriptRoot{0}Src{0}Bin{0}Assemblies{0}net90{0}linux-x64{0}*.dll" -f [System.IO.Path]::DirectorySeparatorChar) -ErrorAction SilentlyContinue) + } elseif ($IsWindows) { + @(Get-ChildItem -Path ("$PSScriptRoot{0}Src{0}Bin{0}Assemblies{0}net90{0}win-x64{0}*.dll" -f [System.IO.Path]::DirectorySeparatorChar) -ErrorAction SilentlyContinue) + } + } + 'Desktop' { + @(Get-ChildItem -Path ("$PSScriptRoot{0}Src{0}Bin{0}Assemblies{0}net48{0}*.dll" -f [System.IO.Path]::DirectorySeparatorChar) -ErrorAction SilentlyContinue) + } + default { + Write-Verbose -Message 'Unable to find compatible assemblies.' + } +} + +foreach ($Assembly in $assemblyName) { + try { + Write-Verbose -Message "Loading assembly '$($Assembly.Name)'." + Add-Type -Path $Assembly.FullName -Verbose + } catch { + Write-Error -Message "Failed to add assembly $($Assembly.FullName): $_" + } +} + # Get public and private function definition files and dot source them $Public = @(Get-ChildItem -Path $PSScriptRoot\Src\Public\*.ps1 -ErrorAction SilentlyContinue) $Private = @(Get-ChildItem -Path $PSScriptRoot\Src\Private\*.ps1 -ErrorAction SilentlyContinue) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f3bde6..0591fad 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,35 @@ 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] - Unreleased + +### Added + +- 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 + +### Changed + +- Bump Diagrammer.Core module requirement to v0.2.36 +- Bump module version to v0.6.12 + +### 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 + +### Removed + +- Removed Pwsh v5.1 support + ## [0.6.11] - 2025-11-07 ### Added diff --git a/Src/Bin/Assemblies/net90/linux-x64/AsBuiltReportChart.dll b/Src/Bin/Assemblies/net90/linux-x64/AsBuiltReportChart.dll new file mode 100644 index 0000000..9d66ea2 Binary files /dev/null and b/Src/Bin/Assemblies/net90/linux-x64/AsBuiltReportChart.dll differ diff --git a/Src/Bin/Assemblies/net90/linux-x64/HarfBuzzSharp.dll b/Src/Bin/Assemblies/net90/linux-x64/HarfBuzzSharp.dll new file mode 100755 index 0000000..ee75381 Binary files /dev/null and b/Src/Bin/Assemblies/net90/linux-x64/HarfBuzzSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/linux-x64/ScottPlot.dll b/Src/Bin/Assemblies/net90/linux-x64/ScottPlot.dll new file mode 100755 index 0000000..2eaec68 Binary files /dev/null and b/Src/Bin/Assemblies/net90/linux-x64/ScottPlot.dll differ diff --git a/Src/Bin/Assemblies/net90/linux-x64/SkiaSharp.HarfBuzz.dll b/Src/Bin/Assemblies/net90/linux-x64/SkiaSharp.HarfBuzz.dll new file mode 100755 index 0000000..362cbf4 Binary files /dev/null and b/Src/Bin/Assemblies/net90/linux-x64/SkiaSharp.HarfBuzz.dll differ diff --git a/Src/Bin/Assemblies/net90/linux-x64/SkiaSharp.dll b/Src/Bin/Assemblies/net90/linux-x64/SkiaSharp.dll new file mode 100755 index 0000000..40b5f96 Binary files /dev/null and b/Src/Bin/Assemblies/net90/linux-x64/SkiaSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/linux-x64/libHarfBuzzSharp.so b/Src/Bin/Assemblies/net90/linux-x64/libHarfBuzzSharp.so new file mode 100755 index 0000000..2d442dc Binary files /dev/null and b/Src/Bin/Assemblies/net90/linux-x64/libHarfBuzzSharp.so differ diff --git a/Src/Bin/Assemblies/net90/linux-x64/libSkiaSharp.so b/Src/Bin/Assemblies/net90/linux-x64/libSkiaSharp.so new file mode 100755 index 0000000..4b81dc9 Binary files /dev/null and b/Src/Bin/Assemblies/net90/linux-x64/libSkiaSharp.so differ diff --git a/Src/Bin/Assemblies/net90/osx-arm64/AsBuiltReportChart.dll b/Src/Bin/Assemblies/net90/osx-arm64/AsBuiltReportChart.dll new file mode 100644 index 0000000..ed2697c Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-arm64/AsBuiltReportChart.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-arm64/HarfBuzzSharp.dll b/Src/Bin/Assemblies/net90/osx-arm64/HarfBuzzSharp.dll new file mode 100755 index 0000000..ee75381 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-arm64/HarfBuzzSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-arm64/ScottPlot.dll b/Src/Bin/Assemblies/net90/osx-arm64/ScottPlot.dll new file mode 100755 index 0000000..2eaec68 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-arm64/ScottPlot.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-arm64/SkiaSharp.HarfBuzz.dll b/Src/Bin/Assemblies/net90/osx-arm64/SkiaSharp.HarfBuzz.dll new file mode 100755 index 0000000..362cbf4 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-arm64/SkiaSharp.HarfBuzz.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-arm64/SkiaSharp.dll b/Src/Bin/Assemblies/net90/osx-arm64/SkiaSharp.dll new file mode 100755 index 0000000..40b5f96 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-arm64/SkiaSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-arm64/libHarfBuzzSharp.dylib b/Src/Bin/Assemblies/net90/osx-arm64/libHarfBuzzSharp.dylib new file mode 100755 index 0000000..3305506 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-arm64/libHarfBuzzSharp.dylib differ diff --git a/Src/Bin/Assemblies/net90/osx-arm64/libSkiaSharp.dylib b/Src/Bin/Assemblies/net90/osx-arm64/libSkiaSharp.dylib new file mode 100755 index 0000000..fcde75a Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-arm64/libSkiaSharp.dylib differ diff --git a/Src/Bin/Assemblies/net90/osx-x64/AsBuiltReportChart.dll b/Src/Bin/Assemblies/net90/osx-x64/AsBuiltReportChart.dll new file mode 100644 index 0000000..52f6f74 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-x64/AsBuiltReportChart.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-x64/HarfBuzzSharp.dll b/Src/Bin/Assemblies/net90/osx-x64/HarfBuzzSharp.dll new file mode 100755 index 0000000..ee75381 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-x64/HarfBuzzSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-x64/ScottPlot.dll b/Src/Bin/Assemblies/net90/osx-x64/ScottPlot.dll new file mode 100755 index 0000000..2eaec68 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-x64/ScottPlot.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-x64/SkiaSharp.HarfBuzz.dll b/Src/Bin/Assemblies/net90/osx-x64/SkiaSharp.HarfBuzz.dll new file mode 100755 index 0000000..362cbf4 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-x64/SkiaSharp.HarfBuzz.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-x64/SkiaSharp.dll b/Src/Bin/Assemblies/net90/osx-x64/SkiaSharp.dll new file mode 100755 index 0000000..40b5f96 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-x64/SkiaSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/osx-x64/libHarfBuzzSharp.dylib b/Src/Bin/Assemblies/net90/osx-x64/libHarfBuzzSharp.dylib new file mode 100755 index 0000000..3305506 Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-x64/libHarfBuzzSharp.dylib differ diff --git a/Src/Bin/Assemblies/net90/osx-x64/libSkiaSharp.dylib b/Src/Bin/Assemblies/net90/osx-x64/libSkiaSharp.dylib new file mode 100755 index 0000000..fcde75a Binary files /dev/null and b/Src/Bin/Assemblies/net90/osx-x64/libSkiaSharp.dylib differ diff --git a/Src/Bin/Assemblies/net90/win-x64/AsBuiltReportChart.dll b/Src/Bin/Assemblies/net90/win-x64/AsBuiltReportChart.dll new file mode 100644 index 0000000..b59036d Binary files /dev/null and b/Src/Bin/Assemblies/net90/win-x64/AsBuiltReportChart.dll differ diff --git a/Src/Bin/Assemblies/net90/win-x64/HarfBuzzSharp.dll b/Src/Bin/Assemblies/net90/win-x64/HarfBuzzSharp.dll new file mode 100755 index 0000000..ee75381 Binary files /dev/null and b/Src/Bin/Assemblies/net90/win-x64/HarfBuzzSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/win-x64/ScottPlot.dll b/Src/Bin/Assemblies/net90/win-x64/ScottPlot.dll new file mode 100755 index 0000000..2eaec68 Binary files /dev/null and b/Src/Bin/Assemblies/net90/win-x64/ScottPlot.dll differ diff --git a/Src/Bin/Assemblies/net90/win-x64/SkiaSharp.HarfBuzz.dll b/Src/Bin/Assemblies/net90/win-x64/SkiaSharp.HarfBuzz.dll new file mode 100755 index 0000000..362cbf4 Binary files /dev/null and b/Src/Bin/Assemblies/net90/win-x64/SkiaSharp.HarfBuzz.dll differ diff --git a/Src/Bin/Assemblies/net90/win-x64/SkiaSharp.dll b/Src/Bin/Assemblies/net90/win-x64/SkiaSharp.dll new file mode 100755 index 0000000..40b5f96 Binary files /dev/null and b/Src/Bin/Assemblies/net90/win-x64/SkiaSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/win-x64/libHarfBuzzSharp.dll b/Src/Bin/Assemblies/net90/win-x64/libHarfBuzzSharp.dll new file mode 100755 index 0000000..2bb6849 Binary files /dev/null and b/Src/Bin/Assemblies/net90/win-x64/libHarfBuzzSharp.dll differ diff --git a/Src/Bin/Assemblies/net90/win-x64/libSkiaSharp.dll b/Src/Bin/Assemblies/net90/win-x64/libSkiaSharp.dll new file mode 100755 index 0000000..036745b Binary files /dev/null and b/Src/Bin/Assemblies/net90/win-x64/libSkiaSharp.dll differ diff --git a/Src/Private/ConvertTo-HashToYN.ps1 b/Src/Private/ConvertTo-HashToYN.ps1 new file mode 100644 index 0000000..02be54f --- /dev/null +++ b/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/Src/Private/ConvertTo-TextYN.ps1 b/Src/Private/ConvertTo-TextYN.ps1 new file mode 100644 index 0000000..07cd0bf --- /dev/null +++ b/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/Src/Private/Export-AbrOntapDiagram.ps1 index 0bfa14e..eab9f82 100644 --- a/Src/Private/Export-AbrOntapDiagram.ps1 +++ b/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,10 +100,10 @@ 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" + Write-PScriboMessage -Message 'Saving NetApp Ontap diagram' $Diagram = New-Diagrammer @DiagramParams -InputObject $Graph if ($Diagram) { foreach ($OutputFormat in $DiagramFormat) { @@ -117,15 +117,15 @@ function Export-AbrOntapDiagram { } try { $DiagramParams.Remove('Format') - $DiagramParams.Add('Format', "base64") + $DiagramParams.Add('Format', 'base64') $Graph = $DiagramObject $Diagram = New-Diagrammer @DiagramParams -InputObject $Graph if ($Diagram) { if ((Get-DiaImagePercent -GraphObj $Diagram).Width -gt 600) { $ImagePrty = 40 } else { $ImagePrty = 30 } 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' -Percent $ImagePrty -Align Center + Paragraph 'Image preview: Opens the image in a new tab to view it at full resolution.' -Tabs 2 } } } catch { diff --git a/Src/Private/Get-AbrOntapCluster.ps1 b/Src/Private/Get-AbrOntapCluster.ps1 index fc22942..4c0be9c 100755 --- a/Src/Private/Get-AbrOntapCluster.ps1 +++ b/Src/Private/Get-AbrOntapCluster.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapCluster { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapCluster { ) begin { - Write-PScriboMessage "Collecting ONTAP cluster information." + Write-PScriboMessage 'Collecting ONTAP cluster information.' } process { @@ -35,16 +35,12 @@ function Get-AbrOntapCluster { 'Cluster UUID' = $ClusterInfo.ClusterUuid 'Cluster Serial' = $ClusterInfo.ClusterSerialNumber 'Cluster Controller' = $ClusterInfo.NcController - 'Cluster Contact' = ConvertTo-EmptyToFiller $ClusterInfo.ClusterContact - 'Cluster Location' = ConvertTo-EmptyToFiller $ClusterInfo.ClusterLocation + 'Cluster Contact' = $ClusterInfo.ClusterContact + 'Cluster Location' = $ClusterInfo.ClusterLocation 'Ontap Version' = $ClusterVersion.value 'Number of Aggregates' = $ArrayAggr.count 'Number of Volumes' = $ArrayVolumes.count - 'Overall System Health' = switch ([string]::IsNullOrEmpty($ClusterDiag.Status)) { - $true { '--' } - $false { $ClusterDiag.Status.ToUpper() } - default { 'Unknown' } - } + 'Overall System Health' = ${ClusterDiag}?.Status?.ToUpper() } if ($Healthcheck.Cluster.Summary) { $ClusterSummary | Where-Object { $_.'Overall System Health' -like 'OK' } | Set-Style -Style OK -Property 'Overall System Health' @@ -61,11 +57,11 @@ function Get-AbrOntapCluster { } $ClusterSummary | Table @TableParams if ($Healthcheck.Cluster.Summary -and ($ClusterSummary | Where-Object { $_.'Overall System Health' -notlike 'OK' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + 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 } diff --git a/Src/Private/Get-AbrOntapClusterASUP.ps1 b/Src/Private/Get-AbrOntapClusterASUP.ps1 index 51951e5..6dfdf83 100755 --- a/Src/Private/Get-AbrOntapClusterASUP.ps1 +++ b/Src/Private/Get-AbrOntapClusterASUP.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapClusterASUP { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapClusterASUP { ) begin { - Write-PScriboMessage "Collecting ONTAP AutoSupport information." + Write-PScriboMessage 'Collecting ONTAP AutoSupport information.' } process { @@ -32,11 +32,11 @@ function Get-AbrOntapClusterASUP { $Inobj = [ordered] @{ 'Node Name' = $NodesAUTO.NodeName 'Protocol' = $NodesAUTO.Transport - 'Enabled' = ConvertTo-TextYN $NodesAUTO.IsEnabled + 'Enabled' = $NodesAUTO.IsEnabled 'Last Time Stamp' = $NodesAUTO.LastTimestampDT 'Last Subject' = $NodesAUTO.LastSubject } - $Outobj = [PSCustomObject]$Inobj + $Outobj = [pscustomobject](ConvertTo-HashToYN $inObj) if ($Healthcheck.Cluster.AutoSupport) { $Outobj | Where-Object { $_.'Enabled' -like 'No' } | Set-Style -Style Warning -Property 'Enabled' @@ -52,11 +52,11 @@ function Get-AbrOntapClusterASUP { } $Outobj | Table @TableParams if ($Healthcheck.Cluster.AutoSupport -and ($Outobj | Where-Object { $_.'Enabled' -like 'No' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + 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 } diff --git a/Src/Private/Get-AbrOntapClusterDiagram.ps1 b/Src/Private/Get-AbrOntapClusterDiagram.ps1 index bd24e63..ff49cfe 100644 --- a/Src/Private/Get-AbrOntapClusterDiagram.ps1 +++ b/Src/Private/Get-AbrOntapClusterDiagram.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapClusterDiagram { .DESCRIPTION .NOTES - Version: 0.6.8 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapClusterDiagram { ) begin { - Write-PScriboMessage "Generating Cluster Diagram for NetApp ONTAP." + Write-PScriboMessage 'Generating Cluster Diagram for NetApp ONTAP.' # Used for DiagramDebug if ($Options.EnableDiagramDebug) { $EdgeDebug = @{style = 'filled'; color = 'red' } @@ -101,8 +101,8 @@ function Get-AbrOntapClusterDiagram { # } # ) - 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" } { + 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) { @@ -126,22 +126,22 @@ function Get-AbrOntapClusterDiagram { 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.NodeModel - "Mgmt" = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { - $true { "Unknown" } + 'System Id' = $Node.NodeSystemId + 'Serial' = $Node.NodeSerialNumber + 'Model' = $Node.NodeModel + 'Mgmt' = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { + $true { 'Unknown' } $false { $NodeMgmtAddress } - default { "Unknown" } + default { 'Unknown' } } } } @@ -150,14 +150,14 @@ function Get-AbrOntapClusterDiagram { 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' } { + 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 $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 } + 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 @@ -167,9 +167,9 @@ function Get-AbrOntapClusterDiagram { } 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' } { + 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 } + 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 } } } } diff --git a/Src/Private/Get-AbrOntapClusterHA.ps1 b/Src/Private/Get-AbrOntapClusterHA.ps1 index 208d2b7..1f40b8e 100755 --- a/Src/Private/Get-AbrOntapClusterHA.ps1 +++ b/Src/Private/Get-AbrOntapClusterHA.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapClusterHA { .DESCRIPTION .NOTES - Version: 0.6.9 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapClusterHA { ) begin { - Write-PScriboMessage "Collecting ONTAP cluster high availability information." + Write-PScriboMessage 'Collecting ONTAP cluster high availability information.' } process { @@ -31,17 +31,9 @@ function Get-AbrOntapClusterHA { $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' } - } + 'Partner' = $ClusterHa.Partner ?? '--' + 'TakeOver Possible' = $ClusterHa.TakeoverPossible + 'TakeOver State' = $ClusterHa.TakeoverState ?? '--' 'HA Mode' = $ClusterHa.CurrentMode 'HA State' = $ClusterHa.State } @@ -51,8 +43,8 @@ function Get-AbrOntapClusterHA { } if ($Healthcheck.Cluster.HA) { $NodeSummary | Where-Object { $_.'TakeOver State' -like 'in_takeover' } | Set-Style -Style Warning -Property 'TakeOver State' - $NodeSummary | Where-Object { $_.'HA 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' + $NodeSummary | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' } | Set-Style -Style Warning -Property 'HA State' + $NodeSummary | Where-Object { $_.'TakeOver Possible' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' } | Set-Style -Style Warning -Property 'TakeOver Possible' } $TableParams = @{ @@ -64,27 +56,27 @@ function Get-AbrOntapClusterHA { $TableParams['Caption'] = "- $($TableParams.Name)" } $NodeSummary | Table @TableParams - if ($Healthcheck.Cluster.HA -and (($NodeSummary | Where-Object { $_.'TakeOver State' -like 'in_takeover' } ) -or ($NodeSummary | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' }) -or ($NodeSummary | Where-Object { $_.'TakeOver Possible' -eq 'No' }))) { - Paragraph "Health Check:" -Bold -Underline + if ($Healthcheck.Cluster.HA -and (($NodeSummary | Where-Object { $_.'TakeOver State' -like 'in_takeover' } ) -or ($NodeSummary | Where-Object { $_.'HA Mode' -ne 'non_ha' -and $_.'HA State' -notlike 'connected' }) -or ($NodeSummary | Where-Object { $_.'TakeOver Possible' -eq 'No' -and $_.'HA Mode' -ne 'non_ha' }))) { + 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." + 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." + 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." + 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 } diff --git a/Src/Private/Get-AbrOntapClusterLicense.ps1 b/Src/Private/Get-AbrOntapClusterLicense.ps1 index ef3abf6..965c9cd 100755 --- a/Src/Private/Get-AbrOntapClusterLicense.ps1 +++ b/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,16 +27,16 @@ 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) { + $License = Get-NcLicense -Owner $Node -Controller $Array + if ($License) { + Section -Style Heading3 "$Node License Usage" { $LicenseSummary = foreach ($Licenses in $License) { $EntitlementRisk = try { Get-NcLicenseEntitlementRisk -Package $Licenses.Package -Controller $Array -ErrorAction SilentlyContinue } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } [PSCustomObject] @{ '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 ?? '--' } } if ($Healthcheck.License.RiskSummary) { @@ -53,11 +53,11 @@ function Get-AbrOntapClusterLicense { } $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 + 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/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 index 4c14837..8bf97f8 100755 --- a/Src/Private/Get-AbrOntapClusterLicenseUsage.ps1 +++ b/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,7 +19,7 @@ function Get-AbrOntapClusterLicenseUsage { ) begin { - Write-PScriboMessage "Collecting ONTAP cluster license usage information." + Write-PScriboMessage 'Collecting ONTAP cluster license usage information.' } process { @@ -30,10 +30,7 @@ function Get-AbrOntapClusterLicenseUsage { [PSCustomObject] @{ 'Name' = $NodeLFs.FeatureName 'Status' = $NodeLFs.Status - 'Notes' = Switch ($NodeLFs.Notes) { - "-" { 'None' } - default { $NodeLFs.Notes } - } + 'Notes' = $NodeLFs.Notes } } $TableParams = @{ diff --git a/Src/Private/Get-AbrOntapClusterReplicationDiagram.ps1 b/Src/Private/Get-AbrOntapClusterReplicationDiagram.ps1 index af2d044..664a8ef 100644 --- a/Src/Private/Get-AbrOntapClusterReplicationDiagram.ps1 +++ b/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,35 @@ 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" } + 'Management' = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { + $true { 'Unknown' } $false { $NodeMgmtAddress } - Default { "Unknown" } + 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-DiaHtmlNodeTable -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-DiaHtmlSubGraph -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 +114,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 +136,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-DiaHtmlNodeTable -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,7 +147,7 @@ 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-DiaHtmlSubGraph -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 } @@ -182,8 +182,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 +193,7 @@ function Get-AbrOntapClusterReplicationDiagram { } } } - Default { "Unknown" } + default { 'Unknown' } } } $Num++ @@ -201,12 +201,12 @@ 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-DiaHtmlNodeTable -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) { @@ -215,7 +215,7 @@ function Get-AbrOntapClusterReplicationDiagram { 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.' } } @@ -227,7 +227,7 @@ function Get-AbrOntapClusterReplicationDiagram { $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-DiaHtmlNodeTable -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 +238,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-DiaHtmlSubGraph -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' } } 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/Src/Private/Get-AbrOntapDiskAssign.ps1 b/Src/Private/Get-AbrOntapDiskAssign.ps1 index d4fe896..79c1d88 100755 --- a/Src/Private/Get-AbrOntapDiskAssign.ps1 +++ b/Src/Private/Get-AbrOntapDiskAssign.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapDiskAssign { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapDiskAssign { ) begin { - Write-PScriboMessage "Collecting ONTAP disk assignment per node information." + Write-PScriboMessage 'Collecting ONTAP disk assignment per node information.' } process { diff --git a/Src/Private/Get-AbrOntapDiskBroken.ps1 b/Src/Private/Get-AbrOntapDiskBroken.ps1 index 9639afb..c9496cf 100755 --- a/Src/Private/Get-AbrOntapDiskBroken.ps1 +++ b/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,12 +19,12 @@ 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] @{ @@ -48,11 +48,11 @@ function Get-AbrOntapDiskBroken { } $DiskFailed | Table @TableParams if ($Healthcheck.Storage.DiskStatus -and ($DiskFailed)) { - Paragraph "Health Check:" -Bold -Underline + 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/Src/Private/Get-AbrOntapDiskInv.ps1 b/Src/Private/Get-AbrOntapDiskInv.ps1 index 3653e48..d6d810e 100755 --- a/Src/Private/Get-AbrOntapDiskInv.ps1 +++ b/Src/Private/Get-AbrOntapDiskInv.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapDiskInv { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,13 +19,13 @@ function Get-AbrOntapDiskInv { ) begin { - Write-PScriboMessage "Collecting ONTAP disk inventory per node." + 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" } + $NodeDiskBroken = Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq 'broken' } if ($DiskInv) { $DiskInventory = foreach ($Disks in $DiskInv) { try { @@ -40,7 +40,7 @@ function Get-AbrOntapDiskInv { 'Disk Name' = $Disk 'Shelf' = $Disks.Shelf 'Bay' = $Disks.Bay - 'Capacity' = $Disks.Capacity | ConvertTo-FormattedNumber -Type Disksize -ErrorAction SilentlyContinue + 'Capacity' = ($Disks.Capacity | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Disksize) ?? '--' 'Model' = $Disks.Model 'Serial Number' = $DiskType.SerialNumber 'Type' = $DiskType.DiskType diff --git a/Src/Private/Get-AbrOntapDiskOwner.ps1 b/Src/Private/Get-AbrOntapDiskOwner.ps1 index 2ca44a3..a31c104 100755 --- a/Src/Private/Get-AbrOntapDiskOwner.ps1 +++ b/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,7 +24,7 @@ function Get-AbrOntapDiskOwner { ) begin { - Write-PScriboMessage "Collecting ONTAP disk owned per node information." + Write-PScriboMessage 'Collecting ONTAP disk owned per node information.' } process { @@ -32,8 +32,7 @@ function Get-AbrOntapDiskOwner { if ($Node) { $DiskSummary = foreach ($Owner in $Node) { try { - $DiskOwner = Get-NcDiskOwner -Node $Owner -Controller $Array - foreach ($Disk in $DiskOwner) { + foreach ($Disk in (Get-NcDiskOwner -Node $Owner -Controller $Array)) { [PSCustomObject] @{ 'Disk' = $Disk.Name 'Owner Id' = $Disk.OwnerId diff --git a/Src/Private/Get-AbrOntapDiskShelf.ps1 b/Src/Private/Get-AbrOntapDiskShelf.ps1 index 5e5d2ec..5a5021f 100755 --- a/Src/Private/Get-AbrOntapDiskShelf.ps1 +++ b/Src/Private/Get-AbrOntapDiskShelf.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapDiskShelf { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapDiskShelf { ) begin { - Write-PScriboMessage "Collecting ONTAP disk shelf information." + Write-PScriboMessage 'Collecting ONTAP disk shelf information.' } process { @@ -59,11 +59,11 @@ function Get-AbrOntapDiskShelf { } $ShelfInventory | Table @TableParams if ($Healthcheck.Storage.ShelfStatus -and ($ShelfInventory | Where-Object { $_.'State' -like 'offline' -or $_.'State' -like 'missing' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure all disk shelves are online and operational. Investigate any shelves marked as offline or missing.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapDiskType.ps1 b/Src/Private/Get-AbrOntapDiskType.ps1 index d76f7ef..fa3429f 100755 --- a/Src/Private/Get-AbrOntapDiskType.ps1 +++ b/Src/Private/Get-AbrOntapDiskType.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapDiskType { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,14 +19,13 @@ function Get-AbrOntapDiskType { ) begin { - Write-PScriboMessage "Collecting ONTAP disk type per node information." + 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) { + $DiskType = foreach ($DiskContainers in (Get-NcDisk -Controller $Array | ForEach-Object { $_.DiskRaidInfo.ContainerType } | Group-Object)) { try { [PSCustomObject] @{ 'Container' = $DiskContainers.Name @@ -49,14 +48,13 @@ function Get-AbrOntapDiskType { } $DiskType | Table @TableParams } - $Node = Get-NcNode | Where-Object { $_.IsNodeHealthy -eq "True" } - if ($Node -and (Confirm-NcAggrSpareLow | Where-Object { $_.Value -eq "True" })) { + $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") + 'Aggregate Spare Low' = (Confirm-NcAggrSpareLow -Node $Item.Node).Value.ToString().Replace('True', 'Yes').Replace('False', 'No') } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message @@ -75,11 +73,11 @@ function Get-AbrOntapDiskType { } $OutObj | Table @TableParams if ($Healthcheck.Storage.DiskStatus -and ($OutObj | Where-Object { $_.'Aggregate Spare Low' -like 'Yes' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that aggregate spare capacity is above the recommended threshold to maintain optimal performance and reliability.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 b/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 index 5898951..430ac48 100755 --- a/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Physical Used' = ($Saving.AggrPhysicalUsed | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Compaction Saved' = ($Saving.AggrCompactionSaved | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Data Reduction' = ${Saving}?.AggrDataReductionStorageEfficiencyRatio } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -63,13 +63,13 @@ function Get-AbrOntapEfficiencyAggr { 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/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 index f20c2c5..fe1986a 100755 --- a/Src/Private/Get-AbrOntapEfficiencyConfig.ps1 +++ b/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,17 @@ 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 + $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 + 'Used %' = ($Saving.PercentUsedCapacity | ConvertTo-FormattedNumber -Type Percent) ?? '--' + 'Capacity Tier Used' = ($Saving.CapacityTierUsed | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Compaction Saved %' = ($Saving.DataCompactionSpaceSavedPercent | ConvertTo-FormattedNumber -Type Percent) ?? '--' + 'Deduplication Saved %' = ($Saving.SisSpaceSavedPercent | ConvertTo-FormattedNumber -Type Percent) ?? '--' 'Total Data Reduction' = $TotalStorageEfficiencyRatio.TotalStorageEfficiencyRatio } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapEfficiencyVol.ps1 b/Src/Private/Get-AbrOntapEfficiencyVol.ps1 index f2e2e1f..aefe9a0 100755 --- a/Src/Private/Get-AbrOntapEfficiencyVol.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Saving.Used | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Snapshot Used' = ($Saving.SnapshotUsed | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Total Savings' = ($Saving.Returns.Total | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Effective Used' = ($Saving.EffectiveUsed | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Efficiency Percent' = ($Saving.EfficiencyPercent | ConvertTo-FormattedNumber -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/Src/Private/Get-AbrOntapEfficiencyVolDetailed.ps1 index c745d29..e2d0b06 100755 --- a/Src/Private/Get-AbrOntapEfficiencyVolDetailed.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Dedupe Savings' = ($Saving.Returns.Dedupe | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Compression Savings' = ($Saving.Returns.Compression | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Snapshot Savings' = ($Saving.Returns.Snapshot | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Cloning Savings' = ($Saving.Returns.Cloning | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Efficiency %' = ($Saving.EfficiencyPercent | ConvertTo-FormattedNumber -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 -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/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 index fb8ae4d..919e961 100755 --- a/Src/Private/Get-AbrOntapEfficiencyVolSisStatus.ps1 +++ b/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/Src/Private/Get-AbrOntapNetworkBdomain.ps1 index 26a6201..7b64d3f 100755 --- a/Src/Private/Get-AbrOntapNetworkBdomain.ps1 +++ b/Src/Private/Get-AbrOntapNetworkBdomain.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkBdomain { .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/Src/Private/Get-AbrOntapNetworkFailoverGroup.ps1 index d855ead..831570f 100755 --- a/Src/Private/Get-AbrOntapNetworkFailoverGroup.ps1 +++ b/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/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 index a02298b..50e79bb 100755 --- a/Src/Private/Get-AbrOntapNetworkIfgrp.ps1 +++ b/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/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 index 34eb286..8c0ff0a 100755 --- a/Src/Private/Get-AbrOntapNetworkIpSpace.ps1 +++ b/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/Src/Private/Get-AbrOntapNetworkMGMT.ps1 b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 index 7b118a3..541e68c 100755 --- a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 +++ b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNetworkMgmt { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapNetworkMgmt { ) begin { - Write-PScriboMessage "Collecting ONTAP network management interface information." + Write-PScriboMessage 'Collecting ONTAP network management interface information.' } process { @@ -34,16 +34,12 @@ function Get-AbrOntapNetworkMgmt { try { $inObj = [ordered] @{ 'Cluster Interface' = $Item.InterfaceName - 'Status' = switch ($Item.OpStatus) { - "" { "Unknown" } - $Null { "Unknown" } - default { $Item.OpStatus.ToString().ToUpper() } - } + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() 'Data Protocols' = $Item.DataProtocols 'Address' = $Item.Address 'Vserver' = $Item.Vserver } - $ClusterObj += [pscustomobject]$inobj + $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -62,11 +58,11 @@ function Get-AbrOntapNetworkMgmt { } $ClusterObj | Table @TableParams if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all cluster network interfaces are operational (UP) to maintain cluster connectivity and performance.' } BlankLine } @@ -85,16 +81,12 @@ function Get-AbrOntapNetworkMgmt { try { $inObj = [ordered] @{ 'MGMT Interface' = $Item.InterfaceName - 'Status' = switch ($Item.OpStatus) { - "" { "Unknown" } - $Null { "Unknown" } - default { $Item.OpStatus.ToString().ToUpper() } - } + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() 'Data Protocols' = $Item.DataProtocols 'Address' = $Item.Address 'Vserver' = $Item.Vserver } - $ClusterObj += [pscustomobject]$inobj + $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -113,11 +105,11 @@ function Get-AbrOntapNetworkMgmt { } $ClusterObj | Table @TableParams if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all management network interfaces are operational (UP) to maintain proper management access to the cluster.' } BlankLine } @@ -136,16 +128,12 @@ function Get-AbrOntapNetworkMgmt { try { $inObj = [ordered] @{ 'Intercluster Interface' = $Item.InterfaceName - 'Status' = switch ($Item.OpStatus) { - "" { "Unknown" } - $Null { "Unknown" } - default { $Item.OpStatus.ToString().ToUpper() } - } + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() 'Data Protocols' = $Item.DataProtocols 'Address' = $Item.Address 'Vserver' = $Item.Vserver } - $ClusterObj += [pscustomobject]$inobj + $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -164,11 +152,11 @@ function Get-AbrOntapNetworkMgmt { } $ClusterObj | Table @TableParams if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all intercluster network interfaces are operational (UP) to maintain cluster-to-cluster communication.' } BlankLine } @@ -190,16 +178,12 @@ function Get-AbrOntapNetworkMgmt { } else { $AddressData = $Item.Address } $inObj = [ordered] @{ 'Data Interface' = $Item.InterfaceName - 'Status' = switch ($Item.OpStatus) { - "" { "Unknown" } - $Null { "Unknown" } - default { $Item.OpStatus.ToString().ToUpper() } - } + 'Status' = ${Item}?.OpStatus?.ToString()?.ToUpper() 'Data Protocols' = [string]$Item.DataProtocols 'Address' = $AddressData 'Vserver' = $Item.Vserver } - $ClusterObj += [pscustomobject]$inobj + $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -218,11 +202,11 @@ function Get-AbrOntapNetworkMgmt { } $ClusterObj | Table @TableParams if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'Status' -notlike 'UP' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all data network interfaces are operational (UP) to maintain optimal data access and performance.' } BlankLine } @@ -232,27 +216,23 @@ function Get-AbrOntapNetworkMgmt { Write-PScriboMessage -IsWarning $_.Exception.Message } try { - if ((Get-NcNetInterface -Controller $Array | Where-Object { $_.DataProtocols -ne 'fcp' -and $_.IsHome -like "False" }) -and $Healthcheck.Network.Interface) { + 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" } + $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 } - } + 'Home Port' = $Item.HomeNode + ':' + $Item.HomePort + 'Current Port' = $Item.CurrentNode + ':' + $Item.CurrentPort + 'IsHome' = ($Item.IsHome -eq $True) ? 'Yes': 'No' 'Vserver' = $Item.Vserver } - $ClusterObj += [pscustomobject]$inobj + $ClusterObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -271,11 +251,11 @@ function Get-AbrOntapNetworkMgmt { } $ClusterObj | Table @TableParams if ($Healthcheck.Network.Interface -and ($ClusterObj | Where-Object { $_.'IsHome' -ne 'Yes' })) { - Paragraph "Health Check:" -Bold -Underline + 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." + Text 'Best Practice:' -Bold + Text 'Ensure that all network interfaces are on their designated home ports to maintain optimal network performance and reliability.' } BlankLine } diff --git a/Src/Private/Get-AbrOntapNetworkPorts.ps1 b/Src/Private/Get-AbrOntapNetworkPorts.ps1 index 9deb02d..447bb55 100755 --- a/Src/Private/Get-AbrOntapNetworkPorts.ps1 +++ b/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,7 +23,7 @@ function Get-AbrOntapNetworkPort { ) begin { - Write-PScriboMessage "Collecting ONTAP physical interface information." + Write-PScriboMessage 'Collecting ONTAP physical interface information.' } process { @@ -38,11 +38,7 @@ function Get-AbrOntapNetworkPort { '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' } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message @@ -62,10 +58,10 @@ function Get-AbrOntapNetworkPort { } $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 + 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/Src/Private/Get-AbrOntapNetworkRoute.ps1 index e682990..316d6fc 100755 --- a/Src/Private/Get-AbrOntapNetworkRoute.ps1 +++ b/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/Src/Private/Get-AbrOntapNetworkRouteLifs.ps1 index cfdf15f..42399f7 100755 --- a/Src/Private/Get-AbrOntapNetworkRouteLifs.ps1 +++ b/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/Src/Private/Get-AbrOntapNetworkSubnet.ps1 index b046cd1..cee259c 100755 --- a/Src/Private/Get-AbrOntapNetworkSubnet.ps1 +++ b/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/Src/Private/Get-AbrOntapNetworkVlans.ps1 index dba8b79..cb19877 100755 --- a/Src/Private/Get-AbrOntapNetworkVlans.ps1 +++ b/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/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 index 10f40eb..c44eec2 100644 --- a/Src/Private/Get-AbrOntapNodeAggrDiagram.ps1 +++ b/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" } + 'System Id' = $Node.NodeSystemId + 'Serial' = $Node.NodeSerialNumber + 'Model' = $Node.NodeModel + 'Mgmt' = switch ([string]::IsNullOrEmpty($NodeMgmtAddress)) { + $true { 'Unknown' } $false { $NodeMgmtAddress } - default { "Unknown" } + 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-DiaHtmlNodeTable -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-DiaHtmlNodeTable -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-DiaHtmlSubGraph -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-DiaHtmlSubGraph -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/Src/Private/Get-AbrOntapNodeNetworkDiagram.ps1 b/Src/Private/Get-AbrOntapNodeNetworkDiagram.ps1 new file mode 100644 index 0000000..f3061ee --- /dev/null +++ b/Src/Private/Get-AbrOntapNodeNetworkDiagram.ps1 @@ -0,0 +1,245 @@ +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 = @() + + 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 } + 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' } + } + } + } + } + } + + # Cluster Network Diagram + $ClusterNetwork = Add-DiaNodeImage -Name 'ClusterSwitch1' -ImagesObj $Images -IconType 'Ontap_Cluster_Network' -IconDebug $IconDebug -TableBackgroundColor '#a1e3fd' + + Add-DiaHtmlSubGraph -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-DiaNodeIcon -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-DiaNodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 + } else { + Add-DiaNodeIcon -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-DiaNodeText -Name "$($Port.NodeName)_$($Port.PortName)_NoLifs" -Text 'No LIFs Assigned' -IconDebug $IconDebug -FontSize 14 -FontBold + } + + if ($PerPortLifs.Count -eq 1) { $PerPortLifsColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $PerPortLifsColumnSize = $Options.DiagramColumnSize } else { $PerPortLifsColumnSize = $PerPortLifs.Count } + + $ClusterPortObj += Add-DiaHtmlSubGraph -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-DiaHtmlSubGraph -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 + + Edge -From 'ClusterNetwork' -To "$($Port.NodeName)ClusterPorts" @{color = $Edgecolor; fontcolor = $Fontcolor; fontsize = 12; style = 'dashed'; penwidth = 1; arrowhead = 'box'; arrowtail = 'box' } + + Edge -From "$($Port.NodeName)ClusterPorts" -To $Node.NodeName @{minlen = 1; color = $Edgecolor; fontcolor = $Fontcolor; fontsize = 12; style = 'dashed'; penwidth = 1; arrowhead = 'box'; arrowtail = 'box' } + + # 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-DiaNodeIcon -Name $Lif.InterfaceName -ImagesObj $Images -Align 'Center' -IconType 'Ontap_Network_Nic' -IconDebug $IconDebug -AditionalInfo $Lif.AdditionalInfo -ImageSizePercent 50 -IconPath $IconPath -FontSize 12 + } else { + Add-DiaNodeIcon -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-DiaNodeText -Name "$($Port.NodeName)_$($Port.PortName)_NoLifs" -Text 'No LIFs Assigned' -IconDebug $IconDebug -FontSize 14 -FontBold + } + + if ($PerPortLifs.Count -eq 1) { $PerPortLifsColumnSize = 1 } elseif ($Options.DiagramColumnSize) { $PerPortLifsColumnSize = $Options.DiagramColumnSize } else { $PerPortLifsColumnSize = $PerPortLifs.Count } + + Add-DiaHtmlSubGraph -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 + + Edge -From $Node.NodeName -To "$($Port.NodeName)$($Port.PortName)_Lifs" @{minlen = 1; color = $Edgecolor; fontcolor = $Fontcolor; fontsize = 12; style = 'dashed'; penwidth = 1; arrowhead = 'box'; arrowtail = 'box' } + } + + # foreach ($Port in ($NetPortInfo | Where-Object { $_.Nodename -eq $Node.Nodename -and $_.AdditionalInfo.'Ifgrp Port' -notin @('None', 'Unknown') })) { + # Add-DiaNodeIcon -Name "$($Port.NodeName)_$($Port.PortName)" -LabelName "$($Port.PortName)" -ImagesObj $Images -Align "Center" -IconType "Ontap_Network_Port" -IconDebug $IconDebug -AditionalInfo $Port.AdditionalInfo -NodeObject + + # Edge -From $Node.NodeName -To "$($Port.NodeName)_$($Port.PortName)" @{minlen = 1; color = $Edgecolor; fontcolor = $Fontcolor; fontsize = 12; style = 'dashed'; penwidth = 1; arrowhead = 'box'; arrowtail = 'box' } + # } + } + } + + foreach ($HA in $HAObject) { + if ($HA.Partner) { + Edge -From $HA.Name -To $HA.Partner @{tailport = $HA.Name; headport = $HA.Partner; minlen = 3; label = "HA: $($HA.HAState)"; color = $Edgecolor; fontcolor = $Fontcolor; fontsize = 16; style = 'solid'; penwidth = 2; arrowhead = 'box'; arrowtail = 'box' } + 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/Src/Private/Get-AbrOntapNodeStorage.ps1 index af6f9ff..36e81c9 100755 --- a/Src/Private/Get-AbrOntapNodeStorage.ps1 +++ b/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 { @@ -33,11 +33,11 @@ function Get-AbrOntapNodeStorage { '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 -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Available' = ($Item.Available | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Used' = ($Item.Used | ConvertTo-FormattedNumber -Type Percent) ?? '--' } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -57,11 +57,11 @@ function Get-AbrOntapNodeStorage { } $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/Src/Private/Get-AbrOntapNodes.ps1 index a4f5eeb..2128044 100755 --- a/Src/Private/Get-AbrOntapNodes.ps1 +++ b/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,7 +19,7 @@ function Get-AbrOntapNode { ) begin { - Write-PScriboMessage "Collecting ONTAP node information." + Write-PScriboMessage 'Collecting ONTAP node information.' } process { diff --git a/Src/Private/Get-AbrOntapNodesHW.ps1 b/Src/Private/Get-AbrOntapNodesHW.ps1 index a4f821f..70c1988 100755 --- a/Src/Private/Get-AbrOntapNodesHW.ps1 +++ b/Src/Private/Get-AbrOntapNodesHW.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNodesHW { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,7 +19,7 @@ function Get-AbrOntapNodesHW { ) begin { - Write-PScriboMessage "Collecting ONTAP Node Hardware information." + Write-PScriboMessage 'Collecting ONTAP Node Hardware information.' } process { @@ -28,54 +28,47 @@ function Get-AbrOntapNodesHW { 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 } + 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 + '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 } - '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 + $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' - } + 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)" + $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 } - $Outobj | Table @TableParams - } catch { - Write-PScriboMessage -IsWarning $_.Exception.Message } } } diff --git a/Src/Private/Get-AbrOntapNodesSP.ps1 b/Src/Private/Get-AbrOntapNodesSP.ps1 index f3240b3..ec2e360 100755 --- a/Src/Private/Get-AbrOntapNodesSP.ps1 +++ b/Src/Private/Get-AbrOntapNodesSP.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapNodesSP { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,16 +19,56 @@ function Get-AbrOntapNodesSP { ) begin { - Write-PScriboMessage "Collecting ONTAP Node Service-Processor information." + 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) { - $NodeServiceProcessor = foreach ($NodeSPs in $ServiceProcessor) { + $SPObj = @() + foreach ($NodeSPs in $ServiceProcessor) { try { - [PSCustomObject] @{ + $inObj = [ordered] @{ 'Name' = $NodeSPs.Node 'Type' = $NodeSPs.Type 'IP Address' = $NodeSPs.IpAddress @@ -40,32 +80,35 @@ function Get-AbrOntapNodesSP { } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } + + $SPObj += [pscustomobject](ConvertTo-HashToYN $inObj) } 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' + $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 = $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." + $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 } - BlankLine } + } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-AbrOntapRepClusterPeer.ps1 b/Src/Private/Get-AbrOntapRepClusterPeer.ps1 index f4989dc..0aadaf9 100755 --- a/Src/Private/Get-AbrOntapRepClusterPeer.ps1 +++ b/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/Src/Private/Get-AbrOntapRepDestinations.ps1 index 58f942b..fc3d05c 100755 --- a/Src/Private/Get-AbrOntapRepDestinations.ps1 +++ b/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/Src/Private/Get-AbrOntapRepHistory.ps1 index 980c566..d8def2d 100755 --- a/Src/Private/Get-AbrOntapRepHistory.ps1 +++ b/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/Src/Private/Get-AbrOntapRepMediator.ps1 index d815a33..5a92cad 100755 --- a/Src/Private/Get-AbrOntapRepMediator.ps1 +++ b/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/Src/Private/Get-AbrOntapRepRelations.ps1 index b67d4fc..6662e66 100755 --- a/Src/Private/Get-AbrOntapRepRelations.ps1 +++ b/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/Src/Private/Get-AbrOntapRepVserverPeer.ps1 index 9ee1ed9..76f7d37 100755 --- a/Src/Private/Get-AbrOntapRepVserverPeer.ps1 +++ b/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/Src/Private/Get-AbrOntapSecurityKMS.ps1 index 4980d0e..1453007 100755 --- a/Src/Private/Get-AbrOntapSecurityKMS.ps1 +++ b/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/Src/Private/Get-AbrOntapSecurityKMSExt.ps1 index c772041..699473a 100755 --- a/Src/Private/Get-AbrOntapSecurityKMSExt.ps1 +++ b/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/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 index a13772e..25582c9 100755 --- a/Src/Private/Get-AbrOntapSecurityKMSExtStatus.ps1 +++ b/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/Src/Private/Get-AbrOntapSecurityMAP.ps1 index c4fd05c..999dd86 100755 --- a/Src/Private/Get-AbrOntapSecurityMAP.ps1 +++ b/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/Src/Private/Get-AbrOntapSecurityMAPRule.ps1 index ce0329c..b380cc5 100755 --- a/Src/Private/Get-AbrOntapSecurityMAPRule.ps1 +++ b/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/Src/Private/Get-AbrOntapSecurityNAE.ps1 index 8379cda..3fa21f8 100755 --- a/Src/Private/Get-AbrOntapSecurityNAE.ps1 +++ b/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/Src/Private/Get-AbrOntapSecurityNVE.ps1 index 3615aec..a31c33d 100755 --- a/Src/Private/Get-AbrOntapSecurityNVE.ps1 +++ b/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/Src/Private/Get-AbrOntapSecuritySSLDetailed.ps1 index f34bec7..b2af76a 100755 --- a/Src/Private/Get-AbrOntapSecuritySSLDetailed.ps1 +++ b/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/Src/Private/Get-AbrOntapSecuritySSLVserver.ps1 index 58b2a9d..e4d6c68 100755 --- a/Src/Private/Get-AbrOntapSecuritySSLVserver.ps1 +++ b/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/Src/Private/Get-AbrOntapSecuritySnapLockAggr.ps1 index 3c52902..aa1a234 100755 --- a/Src/Private/Get-AbrOntapSecuritySnapLockAggr.ps1 +++ b/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/Src/Private/Get-AbrOntapSecuritySnapLockClock.ps1 index 2e5e159..847f8c5 100755 --- a/Src/Private/Get-AbrOntapSecuritySnapLockClock.ps1 +++ b/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/Src/Private/Get-AbrOntapSecuritySnapLockVol.ps1 index 21459b8..c34cba4 100755 --- a/Src/Private/Get-AbrOntapSecuritySnapLockVol.ps1 +++ b/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/Src/Private/Get-AbrOntapSecuritySnapLockVollAttr.ps1 index dda9191..a55de44 100755 --- a/Src/Private/Get-AbrOntapSecuritySnapLockVollAttr.ps1 +++ b/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/Src/Private/Get-AbrOntapSecurityUsers.ps1 index 22e2309..be2a554 100755 --- a/Src/Private/Get-AbrOntapSecurityUsers.ps1 +++ b/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/Src/Private/Get-AbrOntapStorageAGGR.ps1 b/Src/Private/Get-AbrOntapStorageAGGR.ps1 index ffbd0b1..8d0fa22 100755 --- a/Src/Private/Get-AbrOntapStorageAGGR.ps1 +++ b/Src/Private/Get-AbrOntapStorageAGGR.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapStorageAGGR { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -19,69 +19,94 @@ function Get-AbrOntapStorageAGGR { ) begin { - Write-PScriboMessage "Collecting ONTAP storage aggregate information." + 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' } + try { + $ObjectData = Get-NcAggr -Controller $Array + if ($ObjectData) { + $ObjectDataInfo = @() + foreach ($Data in $ObjectData) { + try { + $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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = ($Data.Available | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = (($Data.Totalsize - $Data.Available ) | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Disk Count' = $Data.Disks + 'Root' = ((Get-NcAggr -Name $Data.Name -Controller $Array | ForEach-Object { $_.AggrRaidAttributes.HasLocalRoot }) -eq 'False') ? 'No': 'Yes' + 'Raid Type' = (($Data.RaidType.Split(',')[0]).ToUpper()) ?? '--' + 'Raid Size' = $Data.RaidSize + 'Volumes in Aggregate' = $Data.Volumes + 'State' = $Data.State } - 'Used' = switch ([string]::IsNullOrEmpty($Aggr.Used)) { - $true { 'Unknown' } - $false { $Aggr.Used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue } - default { 'Unknown' } + $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 $($Data.Name) aggregate configuration." + 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 + } } - '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' } + } + } 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.' } - 'State' = $Aggr.State + BlankLine } - } 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 - } + } catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) } try { $AggrSpare = Get-NcAggrSpare -Controller $Array @@ -91,23 +116,11 @@ function Get-AbrOntapStorageAGGR { 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 + 'Capacity' = ($Spare.TotalSize | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Root Usable' = ($Spare.LocalUsableRootSize | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Data Usable' = ($Spare.LocalUsableDataSize | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Shared Disk' = $Spare.IsDiskShared + 'Disk Zeroed' = $Spare.IsDiskZeroed 'Owner' = $Spare.OriginalOwner } } catch { @@ -144,17 +157,17 @@ function Get-AbrOntapStorageAGGR { $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 + 'dir_holes' = $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 + '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' = ConvertTo-TextYN $Option.hybrid_enabled + 'hybrid_enabled' = $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 + '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) @@ -172,7 +185,7 @@ function Get-AbrOntapStorageAGGR { 'striping' = $TextInfo.ToTitleCase($Option.striping) 'thorough_scrub' = $TextInfo.ToTitleCase($Option.thorough_scrub) } - $OutObj += [pscustomobject]$inobj + $OutObj += [pscustomobject](ConvertTo-HashToYN $inObj) $TableParams = @{ Name = "Aggregates Options - $($Aggregate.Name)" diff --git a/Src/Private/Get-AbrOntapStorageFabricPool.ps1 b/Src/Private/Get-AbrOntapStorageFabricPool.ps1 index b05d8bf..cdd4cd9 100755 --- a/Src/Private/Get-AbrOntapStorageFabricPool.ps1 +++ b/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 -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/Src/Private/Get-AbrOntapStorageFabricPoolConfig.ps1 index efcec6f..80ee4f0 100755 --- a/Src/Private/Get-AbrOntapStorageFabricPoolConfig.ps1 +++ b/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 -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/Src/Private/Get-AbrOntapSysConfigBackup.ps1 index e8d515a..a4be4f4 100755 --- a/Src/Private/Get-AbrOntapSysConfigBackup.ps1 +++ b/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 -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/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 index 3cbd415..fd004d7 100755 --- a/Src/Private/Get-AbrOntapSysConfigBackupURL.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigDNS.ps1 index 908be39..90c718e 100755 --- a/Src/Private/Get-AbrOntapSysConfigDNS.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigEMS.ps1 index b1bf68e..98de35b 100755 --- a/Src/Private/Get-AbrOntapSysConfigEMS.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 index 085490d..6d0ad43 100755 --- a/Src/Private/Get-AbrOntapSysConfigEMSSettings.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigImage.ps1 index 25e2347..8fd901c 100755 --- a/Src/Private/Get-AbrOntapSysConfigImage.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigNTP.ps1 index d4a7bd4..dea13fa 100755 --- a/Src/Private/Get-AbrOntapSysConfigNTP.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 index 4a3b5e1..8695606 100755 --- a/Src/Private/Get-AbrOntapSysConfigNTPHost.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 index eb7fe3f..df9ff94 100755 --- a/Src/Private/Get-AbrOntapSysConfigSNMP.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigTZ.ps1 index b58f82a..42d8759 100755 --- a/Src/Private/Get-AbrOntapSysConfigTZ.ps1 +++ b/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/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 index f6e9ee8..52f3227 100755 --- a/Src/Private/Get-AbrOntapSysConfigWebStatus.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCGLun.ps1 index ca307e9..8cfe032 100755 --- a/Src/Private/Get-AbrOntapVserverCGLun.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.space.used | ConvertTo-FormattedNumber -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/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 index 1989c4b..bb1adb5 100755 --- a/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.space.used | ConvertTo-FormattedNumber -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/Src/Private/Get-AbrOntapVserverCGSummary.ps1 index 597232d..871ccbb 100755 --- a/Src/Private/Get-AbrOntapVserverCGSummary.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = ($Item.space.available | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.space.used | ConvertTo-FormattedNumber -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/Src/Private/Get-AbrOntapVserverCIFSDC.ps1 index 2136918..b8166d4 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSDC.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCIFSLGMembers.ps1 index 73e02db..82c8daf 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSLGMembers.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCIFSLocalGroup.ps1 index 70350fd..df6a837 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSLocalGroup.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCIFSOptions.ps1 index 5a1d499..51517f5 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSOptions.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCIFSSecurity.ps1 index 9220a3e..d1b47ca 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSSecurity.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCIFSSession.ps1 index 3c434d1..4b1c5b9 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSSession.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCIFSShare.ps1 index e617292..51c9b29 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSShare.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCIFSShareProp.ps1 index 85c0406..1b9c8ca 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSShareProp.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 index 038995e..4c33532 100755 --- a/Src/Private/Get-AbrOntapVserverCIFSSummary.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverExportPolicy.ps1 b/Src/Private/Get-AbrOntapVserverExportPolicy.ps1 new file mode 100755 index 0000000..42c905b --- /dev/null +++ b/Src/Private/Get-AbrOntapVserverExportPolicy.ps1 @@ -0,0 +1,67 @@ +function Get-AbrOntapVserverExportPolicy { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver 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 export policy information.' + } + + process { + try { + $VserverData = Get-NcExportRule -VserverContext $Vserver -Controller $Array + $VserverObj = @() + if ($VserverData) { + foreach ($Item in $VserverData) { + try { + $inObj = [ordered] @{ + 'Policy Name' = $Item.PolicyName + 'Rule Index' = $Item.RuleIndex + 'Client Match' = $Item.ClientMatch + 'Protocol' = $Item.Protocol -join ', ' + 'Ro Rule' = $Item.RoRule + 'Rw Rule' = $Item.RwRule + } + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + $TableParams = @{ + Name = "Export Policies - $($Vserver)" + List = $false + ColumnWidths = 20, 15, 20, 15, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $VserverObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 b/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 index 813c0e8..45ce34c 100755 --- a/Src/Private/Get-AbrOntapVserverFcpAdapter.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverFcpInterface.ps1 index e200fd3..99b789e 100755 --- a/Src/Private/Get-AbrOntapVserverFcpInterface.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 index 9ef7a26..7c5d4c8 100755 --- a/Src/Private/Get-AbrOntapVserverFcpSummary.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverIscsiInitiator.ps1 index 793bab6..a53cd7e 100755 --- a/Src/Private/Get-AbrOntapVserverIscsiInitiator.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 index 7119480..7564713 100755 --- a/Src/Private/Get-AbrOntapVserverIscsiInterface.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 index 8b6d4a2..3e7007d 100755 --- a/Src/Private/Get-AbrOntapVserverIscsiSummary.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 index f92f660..85e00f8 100755 --- a/Src/Private/Get-AbrOntapVserverLunIgroup.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverLunStorage.ps1 index 5762b94..f2b3ceb 100755 --- a/Src/Private/Get-AbrOntapVserverLunStorage.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = (($Item.Size - $Item.SizeUsed) | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ((($Item.SizeUsed / $Item.Size) * 100) | ConvertTo-FormattedNumber -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/Src/Private/Get-AbrOntapVserverNFSExport.ps1 b/Src/Private/Get-AbrOntapVserverNFSExport.ps1 index 901e872..e1daa28 100755 --- a/Src/Private/Get-AbrOntapVserverNFSExport.ps1 +++ b/Src/Private/Get-AbrOntapVserverNFSExport.ps1 @@ -5,7 +5,7 @@ function Get-AbrOntapVserverNFSExport { .DESCRIPTION .NOTES - Version: 0.6.7 + Version: 0.6.12 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -23,44 +23,37 @@ function Get-AbrOntapVserverNFSExport { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver NFS Export information." + 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) { + $NFSVserver = Get-NcNfsExport -VS $Vserver -Controller $Array + if ($NFSVserver ) { + foreach ($Item in $NFSVserver) { 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 - } + $inObj = [ordered] @{ + 'Path Name' = $Item.Pathname + 'Export Policy' = (((Get-NcVol -VS $Vserver -Controller $Array | Where-Object { $_.JunctionPath -eq $Item.Pathname }).VolumeExportAttributes).Policy) ?? 'None' } - $VserverObj += [pscustomobject]$inobj } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } + } - $TableParams = @{ - Name = "NFS Service Volume Export - $($Vserver)" - List = $false - ColumnWidths = 35, 65 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - if ($VserverObj) { - $VserverObj | Table @TableParams - } + $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 diff --git a/Src/Private/Get-AbrOntapVserverNFSOptions.ps1 b/Src/Private/Get-AbrOntapVserverNFSOptions.ps1 index 154a408..cc1078e 100755 --- a/Src/Private/Get-AbrOntapVserverNFSOptions.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 index 030269b..cbaf343 100755 --- a/Src/Private/Get-AbrOntapVserverNFSSummary.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 index 57f13d1..ca54861 100755 --- a/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Available' = (($Item.Size - $Item.SizeUsed) | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ((($Item.SizeUsed / $Item.Size) * 100) | ConvertTo-FormattedNumber -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/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 b/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 new file mode 100644 index 0000000..d14dd01 --- /dev/null +++ b/Src/Private/Get-AbrOntapVserverNetworkInterface.ps1 @@ -0,0 +1,79 @@ +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 + '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' + } + + $TableParams = @{ + Name = "Data Network - $($Vserver)" + 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 + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 b/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 index fdd9129..d6eb756 100755 --- a/Src/Private/Get-AbrOntapVserverNonMappedLun.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 index 8090e74..29fac33 100755 --- a/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 index cdf77e8..ecfa5d1 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeFcAdapter.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 index e510d6d..5b5f4fb 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeInterface.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 index ca01d90..863e86c 100755 --- a/Src/Private/Get-AbrOntapVserverNvmeTcpAdapter.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverS3Bucket.ps1 index 799cc1d..d9d8f43 100755 --- a/Src/Private/Get-AbrOntapVserverS3Bucket.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.logical_used_size | ConvertTo-FormattedNumber -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/Src/Private/Get-AbrOntapVserverS3Summary.ps1 index 25b1c07..69fd8d6 100755 --- a/Src/Private/Get-AbrOntapVserverS3Summary.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverSubsystem.ps1 index b00710d..38ddb93 100755 --- a/Src/Private/Get-AbrOntapVserverSubsystem.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverSummary.ps1 index 7d4a542..b5d4252 100755 --- a/Src/Private/Get-AbrOntapVserverSummary.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($Item.Used | ConvertTo-FormattedNumber -Type Percent) ?? '--' + 'Available' = ($Item.Available | ConvertTo-FormattedNumber -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 -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/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 index 3a10b87..a020fdc 100755 --- a/Src/Private/Get-AbrOntapVserverVolumeSnapshot.ps1 +++ b/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 -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Reserve Available' = ($SnapReserve.SnapshotReserveAvailable | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type Datasize) ?? '--' + 'Used' = ($SnapReserve.SizeUsedBySnapshots | ConvertTo-FormattedNumber -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'.split()[0] -gt $_.'Reserve Size'.split()[0] } | 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/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 index c810933..2a5401b 100755 --- a/Src/Private/Get-AbrOntapVserverVolumeSnapshotHealth.ps1 +++ b/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 -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/Src/Private/Get-AbrOntapVserverVolumes.ps1 index 04d2a04..d1b58bf 100755 --- a/Src/Private/Get-AbrOntapVserverVolumes.ps1 +++ b/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,12 +36,12 @@ 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 -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Available' = ($Item.Available | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Used' = ($Item.Used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue) ?? '--' 'Aggregate' = $Item.Aggregate } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } @@ -61,10 +61,10 @@ function Get-AbrOntapVserverVolume { } $VserverObj | Table @TableParams if ($Healthcheck.Vserver.Status -and ($VserverObj | 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 volumes are in 'online' status and monitor volume usage to prevent capacity issues." } BlankLine diff --git a/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 b/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 index d0a2554..604b3f3 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 +++ b/Src/Private/Get-AbrOntapVserverVolumesExportPolicy.ps1 @@ -1,11 +1,11 @@ function Get-AbrOntapVserverVolumesExportPolicy { <# .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 per volumes 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,39 +23,35 @@ function Get-AbrOntapVserverVolumesExportPolicy { ) begin { - Write-PScriboMessage "Collecting ONTAP Vserver volumes export policy information." + Write-PScriboMessage 'Collecting ONTAP Vserver per volumes export policy information.' } process { try { - $VserverData = Get-NcExportRule -VserverContext $Vserver -Controller $Array - $VserverObj = @() - if ($VserverData) { - foreach ($Item in $VserverData) { + $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] @{ - 'Policy Name' = $Item.PolicyName - 'Rule Index' = $Item.RuleIndex - 'Client Match' = $Item.ClientMatch - 'Protocol' = $Item.Protocol -join ", " - 'Ro Rule' = $Item.RoRule - 'Rw Rule' = $Item.RwRule + 'Volume Name' = $Volume.Name + 'Export Policy' = (((Get-NcVol -VS $Vserver -Controller $Array | Where-Object { $_.Name -eq $Volume.Name }).VolumeExportAttributes).Policy) ?? 'None' } - $VserverObj += [pscustomobject]$inobj + $VolumeObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } } $TableParams = @{ - Name = "Volume Export Policy - $($Vserver)" + Name = "Per Volume Export Policy - $($Vserver)" List = $false - ColumnWidths = 20, 15, 20, 15, 15, 15 + ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } - $VserverObj | Table @TableParams + $VolumeObj | Table @TableParams } } catch { Write-PScriboMessage -IsWarning $_.Exception.Message diff --git a/Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 b/Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 index 3ff0c21..fe36b4f 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesFlexcache.ps1 +++ b/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 -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 -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/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 index 7315427..6abfbc1 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesFlexclone.ps1 +++ b/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 -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Available' = ($Item.Size - $Item.Used | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Used' = ($Item.Used | ConvertTo-FormattedNumber -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/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 index 2b18794..4e97a88 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesFlexgroup.ps1 +++ b/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 -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/Src/Private/Get-AbrOntapVserverVolumesQos.ps1 b/Src/Private/Get-AbrOntapVserverVolumesQos.ps1 index fb4d293..c839444 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQos.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverVolumesQosGPAdaptive.ps1 index e0143db..1f68801 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQosGPAdaptive.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverVolumesQosGPFixed.ps1 index 9e631cb..f05976b 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQosGPFixed.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 index 2bb0a03..093e998 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQtree.ps1 +++ b/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/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 index 0b75970..40492b5 100755 --- a/Src/Private/Get-AbrOntapVserverVolumesQuota.ps1 +++ b/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 -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'File Limit' = ($Item.FileLimit | ConvertTo-FormattedNumber -Type Count) ?? '--' + 'Soft Disk Limit' = ($Item.SoftDiskLimit | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Soft File Limit' = ($Item.SoftFileLimit | ConvertTo-FormattedNumber -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 -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Soft Disk Limit' = ($Item.SoftDiskLimit | ConvertTo-FormattedNumber -NumberFormatString 0.0 -Type DataSize) ?? '--' + 'Disk Used' = ($Item.DiskUsed | ConvertTo-FormattedNumber -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 -Type Count) ?? '--' + 'Soft File Limit' = ($Item.SoftFileLimit | ConvertTo-FormattedNumber -Type Count) ?? '--' + 'Files Used' = ($Item.FilesUsed | ConvertTo-FormattedNumber -Type Count) ?? '--' } - $VserverObj += [pscustomobject]$inobj + $VserverObj += [pscustomobject](ConvertTo-HashToYN $inObj) } catch { Write-PScriboMessage -IsWarning $_.Exception.Message } diff --git a/Src/Private/Get-NetAppOntapAPI.ps1 b/Src/Private/Get-NetAppOntapAPI.ps1 index efc0e2e..8d6e12c 100644 --- a/Src/Private/Get-NetAppOntapAPI.ps1 +++ b/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/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/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 index ff05765..7b3b3f5 100755 --- a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 +++ b/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,22 +31,40 @@ 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:" + # Check the version of the dependency modules + 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 + + if ($Options.UpdateCheck) { + Write-Host ' - Getting dependency information:' + # Check the version of the dependency modules + $ModuleArray = @('AsBuiltReport.Netapp.ONTAP', 'Diagrammer.Core') + 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 + } + } + } # Check the version of the dependency modules $ModuleArray = @('AsBuiltReport.Netapp.ONTAP', 'Diagrammer.Core') @@ -73,6 +93,9 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { # 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 +124,20 @@ 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' } $script:ColumnSize = $Options.DiagramColumnSize @@ -122,9 +150,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) { @@ -153,16 +181,16 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Paragraph "The following section provides the node inventory in $($ClusterInfo.ClusterName)." BlankLine Get-AbrOntapNode - Section -Style Heading4 'Node Vol0 Inventory' { + Section -Style Heading4 'Node Vol0' { Get-AbrOntapNodeStorage } if ($InfoLevel.Node -ge 2) { - Section -Style Heading4 'Node Hardware Inventory' { + Section -Style Heading4 'Node Hardware' { 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 'Node Service-Processor' { Get-AbrOntapNodesSP } } @@ -179,17 +207,15 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Paragraph "The following section provides a summary of the storage hardware in $($ClusterInfo.ClusterName)." BlankLine Section -Style Heading3 'Aggregate Inventory' { - Paragraph "The following section provides the Aggregates in $($ClusterInfo.ClusterName)." - BlankLine 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' { @@ -221,7 +247,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Section -Style Heading4 'Disk Container Type' { Get-AbrOntapDiskType } - if (Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq "broken" }) { + if (Get-NcDisk -Controller $Array | Where-Object { $_.DiskRaidInfo.ContainerType -eq 'broken' }) { Section -Style Heading4 'Failed Disk' { Get-AbrOntapDiskBroken } @@ -264,6 +290,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 @@ -320,7 +353,7 @@ 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" { @@ -328,7 +361,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { BlankLine Get-AbrOntapNetworkRoute -Vserver $SVM if ($InfoLevel.Network -ge 2) { - Section -Style Heading5 "Network Interface Routes" { + Section -Style Heading5 'Network Interface Routes' { Get-AbrOntapNetworkRouteLif -Vserver $SVM } } @@ -349,16 +382,23 @@ 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 (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 ($InfoLevel.Vserver -ge 2) { if (Get-NcVol -Controller $Array | Select-Object -ExpandProperty VolumeQosAttributes) { Section -Style Heading4 'Volumes QoS Policy' { @@ -372,74 +412,79 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } } - if (Get-NcVol -VserverContext $SVM -Controller $Array | Where-Object { $_.JunctionPath -ne '/' -and $_.Name -ne 'vol0' }) { - Section -Style Heading4 "Storage Volumes" { + if (Get-NcExportRule -VserverContext $SVM -Controller $Array) { + Section -Style Heading4 'Export Policies' { + Get-AbrOntapVserverExportPolicy -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 + } + } if ($InfoLevel.Vserver -ge 2) { if (Get-NcVol -VserverContext $SVM -Controller $Array | Select-Object -ExpandProperty VolumeQosAttributes) { - Section -Style Heading5 "Per Volumes QoS Policy" { + Section -Style Heading5 'Per Volumes QoS Policies' { 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" { + 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" { + 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" { + Section -Style Heading4 'Flexcache Volumes' { Get-AbrOntapVserverVolumesFlexcache -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" { + Section -Style Heading4 'Volumes Snapshot Configuration' { Get-AbrOntapVserverVolumeSnapshot -Vserver $SVM if ($HealthCheck.Vserver.Snapshot) { Get-AbrOntapVserverVolumeSnapshotHealth -Vserver $SVM } } } - 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" { + Section -Style Heading4 'Qtrees' { Get-AbrOntapVserverVolumesQtree -Vserver $SVM } } if (Get-NcQuota -VserverContext $SVM -Controller $Array) { - Section -Style Heading4 "Volume Quota" { + Section -Style Heading4 'Volume Quota' { Get-AbrOntapVserverVolumesQuota -Vserver $SVM } } } - Section -Style Heading4 "Protocol Information" { + 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" { + 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" { + 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" { + Section -ExcludeFromTOC -Style Heading6 'NFS Volume Export' { Get-AbrOntapVserverNFSExport -Vserver $SVM } } @@ -449,7 +494,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { # 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" { + Section -Style Heading5 'CIFS Services Information' { Paragraph "The following section provides the CIFS Service Information in $($SVM)." BlankLine Get-AbrOntapVserverCIFSSummary -Vserver $SVM @@ -461,22 +506,28 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Get-AbrOntapVserverCIFSDC -Vserver $SVM } } - Section -ExcludeFromTOC -Style Heading6 'CIFS Local Group' { - Get-AbrOntapVserverCIFSLocalGroup -Vserver $SVM + if (Get-NcCifsLocalGroup -VserverContext $SVM -Controller $Array) { + Section -ExcludeFromTOC -Style Heading6 'CIFS Local Group' { + Get-AbrOntapVserverCIFSLocalGroup -Vserver $SVM + } } - Section -ExcludeFromTOC -Style Heading6 'CIFS Local Group Members' { - Get-AbrOntapVserverCIFSLGMember -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 } } - Section -ExcludeFromTOC -Style Heading6 'CIFS Share' { - Get-AbrOntapVserverCIFSShare -Vserver $SVM - } - Section -ExcludeFromTOC -Style Heading6 'CIFS Share Configuration' { - Get-AbrOntapVserverCIFSShareProp -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) { @@ -513,18 +564,18 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { #---------------------------------------------------------------------------------------------# # ISCSI Section # #---------------------------------------------------------------------------------------------# - if ( Get-NcIscsiService -Controller $Array | Where-Object { $_.Vserver -eq $SVM } ) { - Section -Style Heading5 "ISCSI Services" { + 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" { + Section -ExcludeFromTOC -Style Heading6 'ISCSI Interfaces' { Get-AbrOntapVserverIscsiInterface -Vserver $SVM } $ISCSIClientInitiators = Get-AbrOntapVserverIscsiInitiator -Vserver $SVM if ($ISCSIClientInitiators) { - Section -ExcludeFromTOC -Style Heading6 "ISCSI Client Initiators" { + Section -ExcludeFromTOC -Style Heading6 'ISCSI Client Initiators' { $ISCSIClientInitiators } } @@ -647,9 +698,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 +725,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 +739,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,15 +750,15 @@ 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") } + $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" { + Section -Style Heading5 'Volume Efficiency' { Get-AbrOntapEfficiencyVol -Vserver $SVM } if ($InfoLevel.Efficiency -ge 2) { - Section -Style Heading5 "Detailed Volume Efficiency" { + Section -Style Heading5 'Detailed Volume Efficiency' { Get-AbrOntapEfficiencyVolDetailed -Vserver $SVM } } @@ -724,7 +775,7 @@ 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 @@ -737,7 +788,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } } - $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 +845,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 } @@ -858,7 +909,7 @@ 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)) { + 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 } diff --git a/Src/Tools/Fonts/ARIAL.TTF b/Src/Tools/Fonts/ARIAL.TTF new file mode 100644 index 0000000..8682d94 Binary files /dev/null and b/Src/Tools/Fonts/ARIAL.TTF differ diff --git a/Todo.md b/Todo.md new file mode 100644 index 0000000..9b32492 --- /dev/null +++ b/Todo.md @@ -0,0 +1,45 @@ +- [] Migrate [PSCustomObject] @{ to $inObj +- [] Network Port Diagram + - [] Cluster Network Ports: + - [] Document all ports and lifs used by the cluster nodes for cluster communication. + - [] Network Ports: + - [] Ifgrps: + - [] Document all ifgrps used in the cluster and their associated ports. + - [] Vlan Interface Ports: + - [] Document all ports used by management access to the cluster nodes. + - [] Document all ports used for replication traffic. + +- [] Vserver Diagram + - [] Document all vservers running on the cluster. + - [] Document the purpose of each vserver. + - [] Document the data access methods used by each vserver (NFS, SMB, iSCSI, etc.). + - [] Document the storage resources allocated to each vserver. + - [] Data Network Ports: + - [] Document all ports used for data access to the vservers running on the cluster + +- [x] Add Per Volumes Export Policies +- [] Implement InfoLevel 1/2 on every section + - Example + - Aggegate Option + - Volumes Options + - Lun Summary vs Lun Full Information + +- [] Vserver Information + - [x] Add Vserver Lifs + - [] IP + - [] Add healthcheck for no route in vserver + - [] Configure at least one route to ensure accurate client can assess the vserver services. + + +```powershell +$password = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force +$Cred = New-Object System.Management.Automation.PSCredential ("admin", $password) + +Connect-NcController 192.168.7.60 -Credential $Cred + +Import-Module AsBuiltReport.NetApp.ONTAP -Force +Import-Module NetApp.ONTAP -Force +Import-Module Diagrammer.Core -Force + +New-AsBuiltReport -Report NetApp.ONTAP -AsBuiltConfigFilePath "$($env:HOME)\script\AsBuiltReport.json" -OutputFolderPath "$($env:HOME)\" -Target 192.168.7.60 -Format HTML -EnableHealthCheck -Credential $Cred -ReportConfigFilePath "$($env:HOME)\script\AsBuiltReport.NetApp.ONTAP.json" +``` diff --git a/icons/network-switch.png b/icons/network-switch.png new file mode 100644 index 0000000..a51e7e1 Binary files /dev/null and b/icons/network-switch.png differ diff --git a/icons/network_port.png b/icons/network_port.png new file mode 100644 index 0000000..fa6b0d6 Binary files /dev/null and b/icons/network_port.png differ diff --git a/icons/nic_port.png b/icons/nic_port.png new file mode 100644 index 0000000..dd984ba Binary files /dev/null and b/icons/nic_port.png differ diff --git a/icons/ontap_single_switch.png b/icons/ontap_single_switch.png new file mode 100644 index 0000000..f6f8add Binary files /dev/null and b/icons/ontap_single_switch.png differ diff --git a/icons/ontap_stack_switch.png b/icons/ontap_stack_switch.png new file mode 100644 index 0000000..ace130f Binary files /dev/null and b/icons/ontap_stack_switch.png differ