Src/Public/Invoke-AsBuiltReport.Nutanix.PrismElement.ps1
function Invoke-AsBuiltReport.Nutanix.PrismElement { <# .SYNOPSIS PowerShell script to document the configuration of Nutanix Prism infrastucture in Word/HTML/Text formats .DESCRIPTION Documents the configuration of Nutanix Prism infrastucture in Word/HTML/Text formats using PScribo. .NOTES Version: 1.2.1 Author: Tim Carman Twitter: @tpcarman Github: tpcarman Credits: Iain Brighton (@iainbrighton) - PScribo module .LINK https://github.com/AsBuiltReport/AsBuiltReport.Nutanix.PrismElement #> param ( [String[]] $Target, [PSCredential] $Credential ) # Import Report Configuration $Report = $ReportConfig.Report $InfoLevel = $ReportConfig.InfoLevel $Options = $ReportConfig.Options # Used to set values to TitleCase where required $TextInfo = (Get-Culture).TextInfo foreach ($NtnxPE in $Target) { #region API Collections Write-PScriboMessage "Performing API reference calls" $NtnxCluster = Get-NtnxApi -Version 2 -Uri '/cluster' $NtnxVMs = (Get-NtnxApi -Version 1 -Uri '/vms').entities $NtnxVirtualDisks = (Get-NtnxApi -Version 1 -Uri '/virtual_disks').entities $NtnxSnapshots = (Get-NtnxApi -Version 2 -Uri '/snapshots').entities $NtnxContainers = (Get-NtnxApi -Version 2 -Uri '/storage_containers').entities | Sort-Object Name $NtnxHosts = (Get-NtnxApi -Version 2 -Uri '/hosts').entities | Sort-Object Name $NtnxNetworks = (Get-NtnxApi -Version 2 -Uri '/networks').entities | Sort-Object Name $NtnxStoragePools = (Get-NtnxApi -Version 1 -Uri '/storage_pools').entities | Sort-Object Name $NtnxFtStatus = (Get-NtnxApi -Version 2 -Uri '/cluster/domain_fault_tolerance_status') $NtnxCVMs = (Get-NtnxApi -Version 1 -Uri '/vms').entities | Where-Object { $_.controllerVm } $NtnxWitness = Get-NtnxApi -Version 2 -Uri '/cluster/metro_witness' $NtnxNfsWhitelist = Get-NtnxApi -Version 2 -Uri '/cluster/nfs_whitelist' $NtnxAuthConfig = Get-NtnxApi -Version 2 -Uri '/authconfig' $NtnxImagesConfig = (Get-NtnxApi -Version 2 -Uri '/images').entities | Sort-Object Name $NtnxSmtpConfig = Get-NtnxApi -Version 2 -Uri '/cluster/smtp' $NtnxAlertsConfig = Get-NtnxApi -Version 2 -Uri 'alerts/configuration' $NtnxSnmpConfig = Get-NtnxApi -Version 2 -Uri '/snmp' $NtnxLicense = Get-NtnxApi -Version 1 -Uri '/license/' $NtnxHealthChecks = (Get-NtnxApi -Version 2 -Uri '/health_checks').entities | Sort-Object name $NtnxDisks = (Get-NtnxApi -Version 2 -Uri '/disks').entities | Sort-Object Id $NtnxVolumeGroups = (Get-NtnxApi -Version 2 -Uri '/volume_groups').entities | Sort-Object Name $NtnxProtectionDomains = (Get-NtnxApi -Version 2 -Uri '/protection_domains').entities $NtnxRemoteSites = Get-NtnxApi -Version 1 -Uri '/remote_sites' $NtnxPDReplications = (Get-NtnxApi -Version 2 -Uri '/protection_domains/replications').entities $NtnxDrSnapshots = (Get-NtnxApi -Version 2 -Uri '/remote_sites/dr_snapshots').entities $NtnxUnprotectedVMs = (Get-NtnxApi -Version 2 -Uri '/protection_domains/unprotected_vms').entities if ($NtnxCluster.hypervisor_types -contains 'kVMware') { $NtnxDatastores = Get-NtnxApi -Version 2 -Uri '/storage_containers/datastores' | Sort-Object datastore_name } #endregion API Collections #region Lookups Write-PScriboMessage "Creating Container Hashtable Lookup" $NtnxContainerLookup = @{} foreach ($NtnxContainer in $NtnxContainers) { $NtnxContainerLookup.($NtnxContainer.storage_container_uuid) = $NtnxContainer.Name } Write-PScriboMessage "Creating Host Hashtable Lookup" $NtnxHostLookup = @{} foreach ($NtnxHost in $NtnxHosts) { $NtnxHostLookup.($NtnxHost.uuid) = $NtnxHost.hypervisor_address } Write-PScriboMessage "Creating Network Hashtable Lookup" $NtnxNetworkLookup = @{} $NtnxNetworkVlanLookup = @{} foreach ($NtnxNetwork in $NtnxNetworks) { $NtnxNetworkLookup.($NtnxNetwork.uuid) = $NtnxNetwork.name $NtnxNetworkVlanLookup.($NtnxNetwork.uuid) = $NtnxNetwork.vlan_id } Write-PScriboMessage "Creating Storage Pool Hashtable Lookup" $NtnxStoragePoolLookup = @{} foreach ($NtnxStoragePool in $NtnxStoragePools) { foreach ($DiskUuid in $NtnxStoragePool.diskUuids) { $NtnxStoragePoolLookup.($DiskUuid) = $NtnxStoragePool.name } } # Excludes CVMs and VMs not running on a container Write-PScriboMessage "Creating VM Hashtable Lookup" $NtnxVirtualMachines = $NtnxVMs | Where-Object { ($_.controllervm -eq $false) -and ($_.runningOnNdfs -eq $true) } | Sort-Object vmName $NtnxVirtualMachineLookup = @{} foreach ($NtnxVirtualMachine in $NtnxVirtualMachines) { $NtnxVirtualMachineLookup.($NtnxVirtualMachine.uuid) = $NtnxVirtualMachine.vmName } #endregion Lookups Section -Style Heading1 $($NtnxCluster.Name) { Write-PScriboMessage "Cluster InfoLevel set at $($InfoLevel.Cluster)." #region Cluster Section if ($InfoLevel.Cluster -gt 0) { if ($NtnxCluster) { Section -Style Heading2 'Cluster' { #region Hardware Section -Style Heading3 'Hardware' { $NtnxFtDomainStatus = $NtnxFtStatus | Where-Object { $_.domain_type -eq $NtnxCluster.fault_tolerance_domain_type } $ClusterSummary = [PSCustomObject]@{ 'Cluster Name' = $NtnxCluster.Name 'Storage Type' = Switch ($NtnxCluster.storage_type) { 'all_flash' { 'All Flash' } 'all_hdd' { 'All HDD' } 'mixed' { 'Hybrid' } } 'Hypervisor Types' = ($NtnxCluster.hypervisor_types).TrimStart('k').Replace('Kvm', 'AHV').Replace('VMware', 'ESXi') -join ', ' 'Number of Nodes' = $NtnxCluster.num_nodes 'Number of Blocks' = ($NtnxCluster.block_serials | Select-Object -Unique).count 'Block Serial(s)' = ($NtnxCluster.block_serials | Sort-Object) -join ', ' 'Fault Tolerance Domain Type' = $TextInfo.ToTitleCase(($NtnxCluster.fault_tolerance_domain_type.ToLower())) 'Data Resiliency Status' = if ($NtnxFtDomainStatus.component_fault_tolerance_status.static_configuration.number_of_failures_tolerable -gt 0) { "OK" } else { "Critical" } "Desired Redundancy Factor" = "RF $($NtnxCluster.cluster_redundancy_state.desired_redundancy_factor)" 'Version' = $NtnxCluster.version 'NCC Version' = ($NtnxCluster.ncc_version).TrimStart("ncc-") 'Timezone' = $NtnxCluster.timezone } if ($Healthcheck.Cluster.Timezone) { $ClusterSummary | Where-Object { $_.'Timezone' -ne $Healthcheck.Cluster.TimezoneSetting } | Set-Style -Style Warning -Property 'Timezone' } if ($Healthcheck.Cluster.DataResiliency) { $ClusterSummary | Where-Object { $_.'Data Resiliency Status' -eq 'OK' } | Set-Style -Style OK -Property 'Data Resiliency Status' $ClusterSummary | Where-Object { $_.'Data Resiliency Status' -ne 'OK' } | Set-Style -Style Critical -Property 'Data Resiliency Status' } $TableParams = @{ Name = "Cluster Summary - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $ClusterSummary | Table @TableParams } #endregion Hardware #region Network Section -Style Heading3 'Network' { $Networks = [PSCustomObject]@{ 'Virtual IP Address' = $NtnxCluster.cluster_external_ipaddress 'iSCSI Data Services IP Address' = Switch ($NtnxCluster.cluster_external_data_services_ipaddress) { $null { '--' } default { $NtnxCluster.cluster_external_data_services_ipaddress } } 'External Subnet' = $NtnxCluster.external_subnet 'Internal Subnet' = $NtnxCluster.internal_subnet 'DNS Server(s)' = $NtnxCluster.name_servers -join ', ' 'NTP Server(s)' = ($NtnxCluster.ntp_servers | Sort-Object) -join ', ' } $TableParams = @{ Name = "Network - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $Networks | Table @TableParams } #endregion Network #region Controller VMs Section -Style Heading3 'Controller VMs' { $ControllerVMs = foreach ($NtnxCVM in $NtnxCVMs) { [PSCustomObject]@{ 'Name' = $NtnxCVM.vmName 'Power State' = $TextInfo.ToTitleCase($NtnxCVM.powerState) 'Host' = $NtnxCVM.hostName 'IP Address' = $NtnxCVM.ipAddresses[0] 'Cores' = $NtnxCVM.numVCPUs 'Memory' = "$([math]::Round(($NtnxCVM.memoryCapacityinBytes) / 1073741824, 2)) GiB" } } if ($Healthcheck.CVM.PowerState) { $ControllerVMs | Where-Object { $_.'Power State' -ne 'on' } | Set-Style -Style Critical -Property 'Power State' } $TableParams = @{ Name = "Controller VMs - $($NtnxCluster.Name)" ColumnWidths = 28, 10, 20, 20, 10, 12 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $ControllerVMs | Sort-Object Host | Table @TableParams } #endregion Controller VMs #region Witness if ($NtnxWitness) { Section -Style Heading3 'Witness Server' { $Witness = [PSCustomObject]@{ 'Witness Name' = $NtnxWitness.witness_name 'IP Address' = $NtnxWitness.ip_addresses -join ', ' } $TableParams = @{ Name = "Witness Server - $($NtnxCluster.Name)" ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $Witness | Table @TableParams } } #endregion Witness } } } #endregion Cluster Section #region System Section Write-PScriboMessage "System InfoLevel set at $($InfoLevel.System)." if ($InfoLevel.System -gt 0) { Section -Style Heading2 'System' { #region Global Filesystem Whitelists if ($NtnxNfsWhitelist) { Section -Style Heading3 'Global Filesystem Whitelists' { $NtnxNfsWhitelists = [PSCustomObject]@{ 'Global Filesystem Whitelists' = $NtnxNfsWhitelist -join [Environment]::NewLine } $TableParams = @{ Name = "Filesystem Whitelists - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NtnxNfsWhitelists | Table @TableParams } } #endregion Global Filesystem Whitelists #region Authentication if ($NtnxAuthConfig) { Section -Style Heading3 'Authentication' { Section -Style Heading4 -ExcludeFromTOC 'Authentication Types' { $AuthenticationTypes = [PSCustomObject]@{ 'Authentication Types' = $TextInfo.ToTitleCase(($NtnxAuthConfig.auth_type_list.Replace('_', ' ') -join ', ').ToLower()) } $TableParams = @{ Name = "Authentication Types - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $AuthenticationTypes | Table @TableParams } if ($NtnxAuthConfig.directory_list) { Section -Style Heading4 -ExcludeFromTOC 'Directory List' { $DirectoryList = [PSCustomObject]@{ 'Directory Type' = $TextInfo.ToTitleCase(($NtnxAuthConfig.directory_list.directory_type).ToLower()).Replace("_"," ") 'Directory Name' = $NtnxAuthConfig.directory_list.name 'Domain' = $NtnxAuthConfig.directory_list.domain 'URL' = $NtnxAuthConfig.directory_list.directory_url 'Connection Type' = $NtnxAuthConfig.directory_list.connection_type 'Group Search Type' = $TextInfo.ToTitleCase(($NtnxAuthConfig.directory_list.group_search_type).ToLower()).Replace("_"," ") } $TableParams = @{ Name = "Directory List - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $DirectoryList | Table @TableParams } } } } #endregion Authentication #region Image Configurations if ($NtnxImagesConfig) { Section -Style Heading3 'Image Configuration' { $Images = foreach ($NtnxImage in $NtnxImagesConfig) { [PSCustomObject]@{ 'Image Name' = $NtnxImage.name 'Annotation' = $NtnxImage.annotation 'Type' = Switch ($NtnxImage.image_type) { 'DISK_IMAGE' { 'DISK' } 'ISO_IMAGE' { 'ISO' } } 'State' = $TextInfo.ToTitleCase(($NtnxImage.image_state).ToLower()) 'Size' = Switch ($NtnxImage.vm_disk_size) { $null { '--' } default { "$([math]::Round(($NtnxImage.vm_disk_size) / 1073741824, 2)) GiB" } } } } if ($Healthcheck.System.ImageState) { $Images | Where-Object { $_.'State' -ne 'Active' } | Set-Style -Style Warning #-Property 'State' } $TableParams = @{ Name = "Image Configuration - $($NtnxCluster.Name)" ColumnWidths = 20, 20, 20, 20, 20 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $Images | Table @TableParams } } #endregion Image Configuration #region SMTP if ($NtnxSmtpConfig.Address) { Section -Style Heading3 'SMTP Server' { $SmtpConfig = [PSCustomObject]@{ 'Address' = $NtnxSmtpConfig.address 'Port' = $NtnxSmtpConfig.port 'Username' = Switch ($NtnxSmtpConfig.username) { $null { "None" } default { $NtnxSmtpConfig.username } } 'Password' = Switch ($NtnxSmtpConfig.password) { $null { "None" } default { $NtnxSmtpConfig.password } } 'Secure Mode' = $TextInfo.ToTitleCase(($NtnxSmtpConfig.secure_mode).ToLower()) 'From Email Address' = $NtnxSmtpConfig.from_email_address } $TableParams = @{ Name = "SMTP Server - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $SmtpConfig | Table @TableParams } } #endregion SMTP #region Alerts Configuration if ($NtnxAlertConfig) { Section -Style Heading3 'Alert Email Configuration' { $AlertConfig = [PSCustomObject]@{ 'Email Every Alert' = Switch ($NtnxAlertsConfig.enable) { $true { 'Yes' } $false { 'No' } } 'Email Daily Alert' = Switch ($NtnxAlertsConfig.enable_email_digest) { $true { 'Yes' } $false { 'No' } } 'Nutanix Support Email' = $NtnxAlertsConfig.default_nutanix_email 'Additional Email Recipients' = $NtnxAlertsConfig.email_contact_list -join ', ' } $TableParams = @{ Name = "Alert Email Configuration - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $AlertConfig | Table @TableParams } } #endregion Alerts Configuration #region SNMP Configuration if ($NtnxSnmpConfig.Enabled) { Section -Style Heading3 'SNMP Configuration' { $SnmpConfig = [PSCustomObject]@{ 'Enabled' = Switch ($NtnxSnmpConfig.enabled) { $true { 'Yes' } $false { 'No' } } 'Transports' = Switch ($NtnxSnmpConfig.snmp_transports) { $null { 'Not configured' } default { $NtnxSnmpConfig.snmp_transports -join ',' } } 'Users' = Switch ($NtnxSnmpConfig.snmp_users) { $null { 'Not configured' } default { $NtnxSnmpConfig.snmp_users -join ',' } } 'Traps' = Switch ($NtnxSnmpConfig.snmp_traps) { $null { 'Not configured' } default { $NtnxSnmpConfig.snmp_traps -join ',' } } } $TableParams = @{ Name = "SNMP Configuration - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $SnmpConfig | Table @TableParams } } #endregion SNMP Configuration #region Syslog Configuration <# if ($NtnxSyslogConfig) { Section -Style Heading3 'Syslog Configuration' { # ToDo: Syslog Configuration } } #> #endregion Syslog Configuration #region Licensing if ($NtnxLicense.LicenseDTO) { $NtnxLicense = $NtnxLicense.LicenseDTO } if ($NtnxLicense) { Section -Style Heading3 'Licensing' { $Licensing = [PSCustomObject]@{ 'Cluster' = $NtnxCluster.name 'License' = ($NtnxLicense.category).Replace('_',' ') } if ($Healthcheck.System.Licensing) { $Licensing | Where-Object { $_.'License' -eq 'No License' } | Set-Style -Style Warning -Property 'License' } $TableParams = @{ Name = "Licensing - $($NtnxCluster.Name)" ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $Licensing | Table @TableParams if ($InfoLevel.System -gt 2) { #region Licensing Features Section -Style Heading4 -ExcludeFromTOC 'Features' { $NtnxLicenseAllowanceMap = $NtnxLicense.allowanceMap foreach ($NtnxLicenseType in $NtnxLicenseAllowanceMap[0].PSObject.Properties) { Set-Variable -Name ('__{0}' -f $NtnxLicenseType.Name) -Value ($NtnxLicenseAllowanceMap | Select-Object -ExpandProperty $($NtnxLicenseType.Name)) } $NtnxLicenseValues = Get-Variable -Name '__*' $LicensingFeatures = foreach ($NtnxLicenseValue in $NtnxLicenseValues.value) { [PSCustomObject]@{ 'Feature' = $NtnxLicenseValue.displayname 'Permitted' = Switch ($NtnxLicenseValue.allowancesType) { 'BOOLEAN' { Switch ($NtnxLicenseValue.BoolValue.BoolValue) { $true { 'Yes' } $false { 'No' } } } 'INTEGER_LIST' { ($NtnxLicenseValue.intValues).intValue } } } } $TableParams = @{ Name = "Licensing Features - $($NtnxCluster.Name)" ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $LicensingFeatures | Sort-Object 'Feature' | Table @TableParams } #endregion Licensing Features } } } #endregion Licensing #region Health Checks if ($NtnxHealthChecks) { Section -Style Heading3 'Health Checks' { #region Health Checks Summary Information if ($InfoLevel.System -lt 4) { $HealthChecks = [PSCustomObject]@{ 'All Checks' = $NtnxHealthChecks.Count #'Passed' = '' #'Failed' = '' #'Warning' = '' #'Error' = '' #'Off' = '' 'Scheduled' = ($NtnxHealthChecks | Where-Object {$_.check_type -eq 'scheduled'}).Count 'Not Scheduled' = ($NtnxHealthChecks | Where-Object {$_.check_type -eq 'not_scheduled'}).Count 'Event Triggered' = ($NtnxHealthChecks | Where-Object {$_.check_type -eq 'event_driven'}).Count } $TableParams = @{ Name = "Health Checks - $($NtnxCluster.Name)" ColumnWidths = 25, 25, 25, 25 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $HealthChecks | Table @TableParams } #endregion Health Checks Summary Information #region Health Checks Comprehensive Information if ($InfoLevel.System -eq 4) { foreach ($NtnxHealthCheck in $NtnxHealthChecks) { Section -Style Heading4 -ExcludeFromTOC "$($NtnxHealthCheck.name)" { $HealthChecksFull = [PSCustomObject]@{ 'Health Check' = $NtnxHealthCheck.name 'Description' = $NtnxHealthCheck.description 'Enabled' = Switch ($NtnxHealthCheck.enabled) { $true { 'Yes' } $false { 'No' } } 'Auto Resolve' = Switch ($NtnxHealthCheck.auto_resolve) { $true { 'Yes' } $false { 'No' } } 'Check Type' = $NtnxHealthCheck.check_type 'Schedule Interval (secs)' = $NtnxHealthCheck.schedule_interval_in_secs 'Affected Entities' = ($NtnxHealthCheck.affected_entity_types | Sort-Object) -join ', ' 'Classifications' = ($NtnxHealthCheck.classifications | Sort-Object) -join ', ' 'Causes' = $NtnxHealthCheck.causes 'Resolutions' = $NtnxHealthCheck.resolutions 'Scope' = ($NtnxHealthCheck.scope).TrimStart('k') } $TableParams = @{ Name = "Health Check $($NtnxHealthCheck.name) - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $HealthChecksFull | Table @TableParams } } } #endregion Health Checks Comprehensive Information } } #endregion Health Checks } } #endregion System Section #region Hosts Section Write-PScriboMessage "Hosts InfoLevel set at $($InfoLevel.Hosts)." if (($InfoLevel.Hosts -gt 0) -and ($NtnxHosts)) { Section -Style Heading2 'Hosts' { #region Host Hardware Summary if ($InfoLevel.Hosts -eq 1) { Section -Style Heading3 'Hardware Summary' { $NtnxHostSummary = [PSCustomObject]@{ 'Hosts' = ($NtnxHosts | Where-Object { $_.Serial | Select-Object -Unique }).Count 'Blocks' = ($NtnxHosts | Where-Object { $_.Block_Serial | Select-Object -Unique }).Count 'Total CPU GHz' = [math]::Round(($NtnxHosts | Measure-Object -Property 'cpu_capacity_in_hz' -Sum).Sum / 1000000000, 1) 'Total Memory GiB' = [math]::Round(($NtnxHosts | Measure-Object -Property 'memory_capacity_in_bytes' -Sum).Sum / 1073741824, 2) #ToDo: Total # Disks (SSD/HDD) #ToDo: # of Network Switches } $TableParams = @{ Name = "Hardware Summary - $($NtnxCluster.Name)" ColumnWidths = 25, 25, 25, 25 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NtnxHostSummary | Table @TableParams } } #endregion Host Hardware Summary #region Host Hardware Detailed if ($InfoLevel.Hosts -ge 2) { #region NtnxHost ForEach Loop foreach ($NtnxHost in $NtnxHosts) { #region Host Information Section -Style Heading3 $NtnxHost.Name { #region Host Hardware Section -Style Heading4 'Hardware' { $NtnxHostConfig = [PSCustomObject]@{ 'Host Name' = $NtnxHost.name 'Host Type' = $TextInfo.ToTitleCase(($NtnxHost.host_type).ToLower()).Replace("_"," ") 'Node Serial' = $NtnxHost.serial 'Block Serial' = $NtnxHost.block_serial 'Block Model' = $NtnxHost.block_model_name #'BMC Version' = $NtnxHost.bmc_version #'BIOS Version' = $NtnxHost.bios_version 'Storage Capacity' = "$([math]::Round(($NtnxHost.usage_stats.'storage.capacity_bytes') / 1099511627776, 2)) TiB" 'Memory' = "$([math]::Round(($NtnxHost.memory_capacity_in_bytes) / 1073741824, 2)) GiB" 'CPU Capacity' = "$([math]::Round(($NtnxHost.cpu_capacity_in_hz) / 1000000000, 1)) GHz" 'CPU Model' = $NtnxHost.cpu_model 'Number of CPU Cores' = $NtnxHost.num_cpu_cores 'Number of Sockets' = $NtnxHost.num_cpu_sockets #ToDo: 'Number of Disks' #ToDo: 'Number of NICs' 'Number of VMs' = $NtnxHost.num_vms 'Oplog Disk %' = "$($NtnxHost.oplog_disk_pct) %" 'Oplog Disk Size' = "$([math]::Round(($NtnxHost.oplog_disk_size) / 1073741824, 1)) GiB" 'Monitored' = Switch ($NtnxHost.monitored) { $True { 'Yes' } $False { 'No' } } 'Hypervisor' = $NtnxHost.hypervisor_full_name #ToDo: 'Datastores' 'Secure Boot Enabled' = Switch ($NtnxHost.is_secure_booted) { $True { 'Yes' } $False { 'No' } } } $TableParams = @{ Name = "Host Hardware Specifications - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NtnxHostConfig | Table @TableParams } #endregion Host Hardware #region Host Network Section -Style Heading4 'Network' { $NtnxHostNetworks = [PSCustomObject]@{ 'Hypervisor IP Address' = $NtnxHost.hypervisor_address 'CVM IP Address' = $NtnxHost.service_vmexternal_ip 'IPMI IP Address' = Switch ($NtnxHost.ipmi_address) { $null { '--' } default { $NtnxHost.ipmi_address } } } $TableParams = @{ Name = "Host Network Specifications - $($NtnxCluster.Name)" ColumnWidths = 33, 34, 33 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NtnxHostNetworks | Table @TableParams } #endregion Host Network #region Host Disks $NtnxHostDisks = $NtnxDisks | Where-Object { $_.node_uuid -eq $NtnxHost.uuid } | Sort-Object 'Location' if ($NtnxHostDisks) { Section -Style Heading5 'Disks' { $HostDisks = foreach ($NtnxHostDisk in $NtnxHostDisks) { [PSCustomObject]@{ 'Location' = $NtnxHostDisk.location 'Disk ID' = (($NtnxHostDisk.id) -split ('::'))[1] 'Serial Number' = $NtnxHostDisk.disk_hardware_config.serial_number 'Vendor' = $NtnxHostDisk.disk_hardware_config.vendor 'Model' = $NtnxHostDisk.disk_hardware_config.model 'Firmware' = $NtnxHostDisk.disk_hardware_config.current_firmware_version 'Storage Tier' = $NtnxHostDisk.storage_tier_name 'Used (Physical)' = "$([math]::Round(($NtnxHostDisk.usage_stats.'storage.usage_bytes') / 1073741824, 2)) GiB" 'Capacity (Logical)' = "$([math]::Round(($NtnxHostDisk.disk_size) / 1099511627776, 2)) TiB" 'Host Name' = $NtnxHost.name 'Hypervisor' = $NtnxHostDisk.host_name 'Storage Pool' = $NtnxStoragePoolLookup."$($NtnxHostDisk.disk_uuid)" 'Self Encryption Drive' = Switch ($NtnxHostDisk.self_encrypting_drive) { $true { 'Present' } $false { 'Not Present' } } 'Status' = $TextInfo.ToTitleCase(($NtnxHostDisk.disk_status).ToLower()) 'Mode' = Switch ($NtnxHostDisk.online) { $true { 'Online' } $false { 'Offline' } } } } if ($Healthcheck.Hardware.DiskStatus) { $HostDisks | Where-Object { $_.'Status' -ne 'normal' } | Set-Style -Style Critical -Property 'Status' } if ($Healthcheck.Hardware.DiskMode) { $HostDisks | Where-Object { $_.'Mode' -ne 'Online' } | Set-Style -Style Critical -Property 'Mode' } if ($InfoLevel.Hosts -ge 3) { foreach ($NtnxHostDisk in $HostDisks) { Section -Style Heading5 -ExcludeFromTOC "Disk $($NtnxHostDisk.Location)" { $TableParams = @{ Name = "Host Disk $($NtnxHostDisk.Location) Specifications - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NtnxHostDisk | Table @TableParams } } } else { $TableParams = @{ Name = "Host Disk Specifications - $($NtnxCluster.Name)" Columns = 'Location', 'Disk ID', 'Serial Number', 'Firmware', 'Storage Tier', 'Capacity (Logical)', 'Status', 'Mode' ColumnWidths = 10, 10, 25, 12, 10, 13, 10, 10 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $HostDisks | Table @TableParams } } } #endregion Host Disks #region Host Datastores (VMware Hosts Only) if (($NtnxDatastores) -and ($NtnxHost.hypervisor_type -eq 'kVMware')) { Section -Style Heading4 'Datastores' { $NtnxHostDatastores = $NtnxDatastores | Where-Object { $_.host_uuid -eq $NtnxHost.uuid } $NtnxHostDatastoreInfo = foreach ($NtnxHostDatastore in $NtnxHostDatastores) { [PSCustomObject]@{ 'Datastore' = $NtnxHostDatastore.datastore_name 'Container' = $NtnxHostDatastore.storage_container_name 'Free Capacity TiB' = [math]::Round(($NtnxHostDatastore.free_space) / 1099511627776, 2) 'Used Capacity TiB' = [math]::Round((($NtnxHostDatastore.capacity) - ($NtnxHostDatastore.free_space)) / 1099511627776, 2) 'Maximum Capacity TiB' = [math]::Round(($NtnxHostDatastore.capacity) / 1099511627776, 2) 'VMs' = ($NtnxHostDatastore.vm_names).Count } } $TableParams = @{ Name = "Host Datastores - $($NtnxCluster.Name)" ColumnWidths = 18, 18, 18, 18, 18, 10 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NtnxHostDatastoreInfo | Sort-Object 'Datastore' | Table @TableParams } } #endregion Host Datastores } #endregion Host Information } #endregion NtnxHost ForEach Loop } #endregion Host Hardware Detailed } } #endregion Hosts Section #region Storage Section Write-PScriboMessage "Storage InfoLevel set at $($InfoLevel.Storage)." if ($InfoLevel.Storage -gt 0) { Section -Style Heading2 'Storage' { #region Containers if ($NtnxContainers) { Section -Style Heading3 'Containers' { $Containers = foreach ($NtnxContainer in $NtnxContainers) { [PSCustomObject]@{ 'Container' = $NtnxContainer.name 'Replication Factor' = "RF $($NtnxContainer.replication_factor)" #ToDo: 'Protection Domain' #ToDo: 'Datastore' 'Compression' = Switch ($NtnxContainer.compression_enabled) { $true { 'On' } $false { 'Off' } } 'Compression Delay' = Switch ($NtnxContainer.compression_delay_in_secs) { $null { '' } default { "$(($NtnxContainer.compression_delay_in_secs)*60) mins" } } 'Cache Deduplication' = $TextInfo.ToTitleCase($NtnxContainer.finger_print_on_write) 'Capacity Deduplication' = $TextInfo.ToTitleCase(($NtnxContainer.on_disk_dedup).ToLower()) 'Erasure Coding' = $TextInfo.ToTitleCase($NtnxContainer.erasure_code) 'Free Capacity (Logical) TiB' = [math]::Round(($NtnxContainer.usage_stats.'storage.user_unreserved_free_bytes') / 1099511627776, 2) 'Used Capacity TiB' = [math]::Round((($NtnxContainer.usage_stats.'storage.user_capacity_bytes') - ($NtnxContainer.usage_stats.'storage.user_unreserved_free_bytes')) / 1099511627776, 2) 'Maximum Capacity TiB' = [math]::Round((($NtnxContainer.usage_stats.'storage.user_capacity_bytes') - ($NtnxContainer.usage_stats.'storage.reserved_capacity_bytes')) / 1099511627776, 2) #ToDo: 'Reserved Capacity' 'Advertised Capacity TiB' = [math]::Round(($NtnxContainer.advertised_capacity) / 1099511627776, 2) #ToDo: 'Data Reduction Ratio' #ToDo: 'Data Reduction Savings' #ToDo: 'Effective Free' #ToDo: 'Overall Efficiency' 'Filesystem Whitelists Inherited' = $NtnxContainer.nfs_whitelist_inherited 'Filesystem Whitelists' = $NtnxContainer.nfs_whitelist -join ', ' } } if ($Healthcheck.Storage.Compression) { $Containers | Where-Object { $_.'Compression' -ne 'on' } | Set-Style -Style Warning -Property 'Compression' } if ($Healthcheck.Storage.CacheDedupe) { $Containers | Where-Object { $_.'Cache Deduplication' -ne 'on' } | Set-Style -Style Warning -Property 'Cache Deduplication' } if ($Healthcheck.Storage.CapacityDedupe) { $Containers | Where-Object { $_.'Capacity Deduplication' -ne 'on' } | Set-Style -Style Warning -Property 'Capacity Deduplication' } if ($Healthcheck.Storage.ErasureCoding) { $Containers | Where-Object { $_.'Erasure Coding' -ne 'on' } | Set-Style -Style Warning -Property 'Erasure Coding' } if ($InfoLevel.Storage -gt 2) { foreach ($Container in $Containers) { Section -Style Heading4 -ExcludeFromTOC "$($Container.Container)" { $TableParams = @{ Name = "Containers - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $Container | Table @TableParams } } } else { $TableParams = @{ Name = "Containers - $($NtnxCluster.Name)" Columns = 'Container' , 'Replication Factor', 'Compression', 'Cache Deduplication', 'Capacity Deduplication', 'Erasure Coding', 'Free Capacity (Logical) TiB', 'Used Capacity TiB', 'Maximum Capacity TiB' } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $Containers | Table @TableParams } } } #endregion Containers #region Volume Groups if ($NtnxVolumeGroups) { Section -Style Heading3 'Volume Groups' { $VolumeGroups = foreach ($NtnxVolumeGroup in $NtnxVolumeGroups) { [PSCustomObject]@{ 'Volume Group' = $NtnxVolumeGroup.Name 'Number of Virtual Disks' = ($NtnxVolumeGroup.disk_list).Count 'Flash Mode' = Switch ($NtnxVolumeGroup.flash_mode_enabled) { $true { 'Enabled' } default { 'Disabled' } } 'Initiators' = $($NtnxVolumeGroups.attachment_list.iscsi_initiator_name | Sort-Object) -join ', ' 'Target IQN Prefix' = $NtnxVolumeGroup.iscsi_target } } if ($InfoLevel.Storage -eq 1) { $TableParams = @{ Name = "Volume Groups - $($NtnxCluster.Name)" ColumnWidths = 22, 16, 12, 25, 25 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $VolumeGroups | Table @TableParams } else { foreach ($NtnxVolumeGroup in $NtnxVolumeGroups) { Section -Style Heading4 -ExcludeFromTOC $($NtnxVolumeGroup.Name) { $VolumeGroup = [PSCustomObject]@{ 'Volume Group' = $NtnxVolumeGroup.Name 'Number of Virtual Disks' = ($NtnxVolumeGroup.disk_list).Count 'Flash Mode' = Switch ($NtnxVolumeGroup.flash_mode_enabled) { $true { 'Enabled' } default { 'Disabled' } } 'Initiators' = $($NtnxVolumeGroups.attachment_list.iscsi_initiator_name | Sort-Object) -join ', ' 'Target IQN Prefix' = $NtnxVolumeGroup.iscsi_target } $TableParams = @{ Name = "Volume Group $($NtnxVolumeGroup.Name) - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $VolumeGroup | Table @TableParams if ($InfoLevel.Storage -ge 3) { Section -Style Heading4 -ExcludeFromTOC 'Virtual Disks' { $VirtualGroupDisks = $NtnxVolumeGroup.disk_list | Sort-Object Index $NtnxVirtualGroupDisks = foreach ($VirtualGroupDisk in $VirtualGroupDisks) { [PSCustomObject]@{ 'Virtual Disk' = $VirtualGroupDisk.Index 'Total Capacity GiB' = [math]::Round(($VirtualGroupDisk.vmdisk_size_bytes) / 1073741824, 0) 'Container' = $NtnxContainerLookup."$($VirtualGroupDisk.storage_container_uuid)" 'Disk Path' = $VirtualGroupDisk.vmdisk_path } } $TableParams = @{ Name = "Virtual Disks - $($NtnxVolumeGroup.Name)" ColumnWidths = 15, 15, 35, 35 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NtnxVirtualGroupDisks | Table @TableParams } } } } } } } #endregion Volume Groups #region Storage Pools if ($NtnxStoragePools) { Section -Style Heading3 'Storage Pools' { $StoragePools = foreach ($NtnxStoragePool in $NtnxStoragePools) { [PSCustomObject]@{ 'Storage Pool' = $NtnxStoragePool.name 'Disks' = ($NtnxStoragePool.disks).count 'Free Capacity TiB' = [math]::Round((($NtnxStoragePool.capacity) - ($NtnxStoragePool.usageStats.'storage.disk_physical_usage_bytes')) / 1099511627776, 2) 'Used Capacity TiB' = [math]::Round(($NtnxStoragePool.usageStats.'storage.disk_physical_usage_bytes') / 1099511627776, 2) 'Maximum Capacity TiB' = [math]::Round(($NtnxStoragePool.capacity) / 1099511627776, 2) } } $TableParams = @{ Name = "Storage Pools - $($NtnxCluster.Name)" ColumnWidths = 22, 12, 22, 22, 22 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $StoragePools | Sort-Object 'Storage Pool' | Table @TableParams } } #endregion Storage Pools #region VMware Datastores if ($NtnxDatastores) { Section -Style Heading3 'VMware Datastores' { $NfsDatastores = foreach ($NtnxDatastore in $NtnxDatastores) { [PSCustomObject]@{ 'Datastore' = $NtnxDatastore.datastore_name 'Host' = $NtnxDatastore.host_ip_address 'Container' = $NtnxDatastore.storage_container_name 'Free Capacity TiB' = [math]::Round(($NtnxDatastore.free_space) / 1099511627776, 2) 'Used Capacity TiB' = [math]::Round((($NtnxDatastore.capacity) - ($NtnxDatastore.free_space)) / 1099511627776, 2) 'Maximum Capacity TiB' = [math]::Round(($NtnxDatastore.capacity) / 1099511627776, 2) 'Number of VMs' = ($NtnxDatastore.vm_names).Count 'Virtual Machines' = Switch (($NtnxDatastore.vm_names).Count -gt 0) { $true { ($NtnxDatastore.vm_names | Sort-Object) -join ', ' } $false { '--' } } } } if ($InfoLevel.Storage -eq 1) { $TableParams = @{ Name = "VMware Datastores - $($NtnxCluster.Name)" Columns = 'Datastore', 'Host', 'Container', 'Free Capacity TiB', 'Used Capacity TiB', 'Maximum Capacity TiB', 'Number of VMs' ColumnWidths = 15, 15, 15, 15, 15, 15, 10 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NfsDatastores | Sort-Object Datastore, Host | Table @TableParams } else { foreach ($NfsDatastore in ($NfsDatastores | Sort-Object Datastore | Sort-Object Host)) { Section -Style Heading4 -ExcludeFromTOC $($NfsDatastore.Datastore) { $TableParams = @{ Name = "Datastore $($NfsDatastore.Datastore) - $($NfsDatastore.Host)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NfsDatastore | Sort-Object Datastore, Host | Table @TableParams } } } } } #endregion VMware Datastores } } #endregion Storage Section #region Virtual Machines Section Write-PScriboMessage "VM InfoLevel set at $($InfoLevel.VM)." if (($InfoLevel.VM -gt 0) -and ($NtnxVirtualMachines)) { Section -Style Heading2 'Virtual Machines' { #region VM Summary Information if ($InfoLevel.VM -eq 1) { $VMSummary = foreach ($NtnxVM in $NtnxVirtualMachines) { [PSCustomObject]@{ 'VM Name' = $NtnxVM.vmName 'Power State' = $TextInfo.ToTitleCase($NtnxVM.powerState) 'Cores' = $NtnxVM.numVCpus 'Memory' = "$([math]::Round(($NtnxVM.memoryCapacityInBytes) / 1073741824, 0)) GiB" 'IP Addresses' = $NtnxVM.ipAddresses -join ', ' 'Disk Capacity' = "$([math]::Round(($NtnxVM.diskCapacityinBytes) / 1073741824, 2)) GiB" } } if ($Healthcheck.VM.PowerState) { $VMSummary | Where-Object { $_.'Power State' -eq 'off' } | Set-Style -Style Warning -Property 'Power State' } $TableParams = @{ Name = "Virtual Machines - $($NtnxCluster.Name)" ColumnWidths = 24, 11, 11, 11, 28, 15 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $VMSummary | Table @TableParams } #endregion VM Summary Information #region VM Detailed Information if ($InfoLevel.VM -ge 2) { foreach ($NtnxVM in $NtnxVirtualMachines) { Section -Style Heading3 "$($NtnxVM.vmName)" { $VirtualMachines = [PSCustomObject]@{ 'VM Name' = $NtnxVM.vmName 'Description' = Switch ($NtnxVM.description) { $null { '--' } default { $NtnxVM.description } } 'Power State' = $TextInfo.ToTitleCase($NtnxVM.powerState) 'Host' = Switch ($NtnxVM.hostName) { $null { '--' } default { $NtnxVM.hostName } } 'Host IP' = Switch ($NtnxHostLookup."$($NtnxVM.hostUuid)") { $null { '--' } default { $NtnxHostLookup."$($NtnxVM.hostUuid)" } } 'Memory' = "$([math]::Round(($NtnxVM.memoryCapacityInBytes) / 1073741824, 0)) GiB" 'Cores' = $NtnxVM.numVCpus 'Network Adapters' = $NtnxVM.numNetworkAdapters 'Operating System' = Switch ($NtnxVM.guestOperatingSystem) { $null { '--' } default { $NtnxVM.guestOperatingSystem } } 'IP Addresses' = $NtnxVM.ipAddresses -join ', ' 'Storage Container' = $NtnxContainerLookup."$($NtnxVM.containerUuids)" 'Virtual Disks' = ($NtnxVM.nutanixVirtualDisks).Count 'Disk Capacity' = "$([math]::Round(($NtnxVM.diskCapacityinBytes) / 1073741824, 2)) GiB" #ToDo: Total Logical Capacity 'NGT Enabled' = Switch ($NtnxVM.nutanixGuestTools.enabled) { $true { 'Yes' } $false { 'No' } } 'NGT Mounted' = Switch ($NtnxVM.nutanixGuestTools.toolsMounted) { $true { 'Yes' } $false { 'No' } } 'Protection Domain' = Switch ($NtnxVM.protectionDomainName) { $null { '--' } default { $NtnxVM.protectionDomainName } } } if ($Healthcheck.VM.PowerState) { $VirtualMachines | Where-Object { $_.'Power State' -eq 'off' } | Set-Style -Style Warning -Property 'Power State' } $TableParams = @{ Name = "$($NtnxVM.vmName) - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $VirtualMachines | Table @TableParams #region VM Virtual Disks $NtnxVMVirtualDisks = $NtnxVirtualDisks | Where-Object {$_.attachedVMName -eq $($NtnxVM.vmName)} | Sort-Object diskAddress if ($NtnxVMVirtualDisks) { Section -Style Heading4 -ExcludeFromTOC 'Virtual Disks' { $VMVirtualDisks = foreach ($NtnxVMVirtualDisk in $NtnxVMVirtualDisks) { [PSCustomObject]@{ 'Virtual Disk' = $NtnxVMVirtualDisk.diskAddress 'Total Capacity' = "$([math]::Round(($NtnxVMVirtualDisk.diskCapacityInBytes) / 1073741824, 0)) GiB" #ToDo: Total Logical Capacity #ToDo: Add Container results for Hyper-V 'Container' = Switch ( $NtnxVM.hypervisorType ) { 'kKVM' { $NtnxContainerLookup."$($NtnxVMVirtualDisk.containerUuid)" } 'kVMware' { ($NtnxVMVirtualDisk.nutanixNFSFilePath).Split('/')[1] } } #'Flash Mode' } } $TableParams = @{ Name = "Virtual Disks - $($NtnxVM.vmName)" ColumnWidths = 33, 34, 33 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $VMVirtualDisks | Table @TableParams } } #endregion VM Virtual Disks #region VM NICs $NtnxVMNics = (Get-NtnxApi -Version 2 -Uri $('/vms/' + $($NtnxVM.uuid) + '/nics')).entities | Sort-Object network_uuid if ($NtnxVMNics) { Section -Style Heading4 -ExcludeFromTOC 'VM NICs' { $VMNics = foreach ($NtnxVMNic in $NtnxVMNics) { [PSCustomObject]@{ #ToDo: Find a way to get the 'Port Name' for VMware 'Network Name' = $NtnxNetworkLookup."$($NtnxVMNic.network_uuid)" 'Adapter Type' = $NtnxVMNic.adapter_type 'VLAN ID' = $NtnxNetworkVlanLookup."$($NtnxVMNic.network_uuid)" 'MAC Address' = $NtnxVMNic.mac_address 'IP Address' = ($NtnxVMNic.ip_address | Sort-Object) -join ', ' 'IP Addresses' = ($NtnxVMNic.ip_addresses | Sort-Object) -join ', ' 'Connected' = Switch ($NtnxVMNic.is_connected) { $true { 'Yes' } $false { 'No' } } } } if ($Healthcheck.VM.NicConnectionState) { $VMNics | Where-Object { $_.'Connected' -ne 'Yes' } | Set-Style -Style Warning #-Property 'Connected' } $TableParams = @{ Name = "VM NICs - $($NtnxVM.vmName)" } # Build different table format based on hypervisor type Switch ( $NtnxVM.hypervisorType ) { 'kVMware' { $TableParams['Columns'] = 'Adapter Type', 'MAC Address', 'IP Address', 'Connected' $TableParams['ColumnWidths'] = 25, 25, 25, 25 } 'kKVM' { $TableParams['Columns'] = 'Network Name', 'VLAN ID', 'MAC Address', 'IP Addresses', 'Connected' $TableParams['ColumnWidths'] = 20, 20, 20, 20, 20 } } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $VMNics | Sort-Object 'Network Name' | Table @TableParams } } #endregion VM NICs #region VM Snapshots $NtnxVMSnapshots = $NtnxSnapshots | Where-Object {$_.vm_uuid -eq $NtnxVM.uuid} if ($NtnxVMSnapshots) { Section -Style Heading3 'VM Snapshots' { $VMSnapshots = foreach ($NtnxVMSnapshot in $NtnxVMSnapshots) { $NtnxVMSnapshotTime = $NtnxVMSnapshot.created_time/1000 $NtnxVMSnapshotDateTime = (Get-Date '1/1/1970').AddMilliseconds($NtnxVMSnapshotTime) [PSCustomObject]@{ 'Create Time' = $NtnxVMSnapshotDateTime 'Snapshot Name' = $NtnxVMSnapshot.snapshot_name #'VM' = $NtnxVirtualMachineLookup."$($NtnxVMSnapshot.vm_uuid)" } } $TableParams = @{ Name = "VM Snapshots - $($NtnxVM.vmName)" ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $VMSnapshots | Table @TableParams } } #endregion VM Snapshots } } } #endregion VM Detailed Information } } #endregion Virtual Machines Section #region Data Protection Section Write-PScriboMessage "Data Protection InfoLevel set at $($InfoLevel.DataProtection)." if (($InfoLevel.DataProtection -gt 0) -and ($NtnxProtectionDomains -or $NtnxRemoteSites)) { Section -Style Heading2 'Data Protection' { #region Protection Domains if ($NtnxProtectionDomains) { Section -Style Heading3 'Protection Domains' { $ProtectionDomains = foreach ($NtnxProtectionDomain in $NtnxProtectionDomains) { [PSCustomObject]@{ 'Name' = $NtnxProtectionDomain.name 'Active' = Switch ($NtnxProtectionDomain.active) { $true { 'Yes' } $false { 'No' } } 'Remote Site(s)' = $NtnxProtectionDomain.replication_links.remote_site_name 'Pending Replications' = $NtnxProtectionDomain.pending_replication_count 'Ongoing Replications' = $NtnxProtectionDomain.ongoing_replication_count 'Written Bytes' = $NtnxProtectionDomain.total_user_written_bytes } } $TableParams = @{ Name = "Protection Domains - $($NtnxCluster.Name)" ColumnWidths = 36, 10, 15, 13, 13, 13 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $ProtectionDomains | Sort-Object 'Name' | Table @TableParams } } #endregion Protection Domains #region Protection Domain Replication if (($InfoLevel.DataProtection -eq 3) -and ($NtnxPDReplications)) { Section -Style Heading3 'Protection Domain Replication' { $ProtectionDomainReplications = foreach ($NtnxPDReplication in $NtnxPDReplications) { [PSCustomObject]@{ 'Name' = $NtnxPDReplication.protection_domain_name 'Remote Sites' = $NtnxPDReplication.remote_site_name -join ', ' 'Snapshot ID' = $NtnxPDReplication.snapshot_id 'Data Completed' = "$([math]::Round(($NtnxPDReplication.completed_bytes) / 1099511627776, 2)) TiB" '% Complete' = $NtnxPDReplication.completed_percentage 'Minutes to Complete' = [math]::Round(($NtnxPDReplication.replication_time_to_complete_secs) / 60, 2) } } $TableParams = @{ Name = "Protection Domain Replication - $($NtnxCluster.Name)" ColumnWidths = 25, 15, 15, 15, 15, 15 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $ProtectionDomainReplications | Sort-Object 'Name' | Table @TableParams } } #endregion Protection Domain Replication #region Protection Domain Snapshots if (($InfoLevel.DataProtection -eq 3) -and ($NtnxDrSnapshots)) { Section -Style Heading3 'Protection Domain Snapshots' { $ProtectionDomainSnapshots = foreach ($NtnxDrSnapshot in $NtnxDrSnapshots) { [PSCustomObject]@{ 'Protection Domain' = $NtnxDrSnapshot.protection_domain_name 'State' = ($NtnxDrSnapshot.state).ToLower() 'Snapshot ID' = $NtnxDrSnapshot.snapshot_id 'Consistency Groups' = $NtnxDrSnapshot.consistency_groups -join ', ' 'Remote Site(s)' = $NtnxDrSnapshot.remote_site_names -join ', ' 'Size in Bytes' = $NtnxDrSnapshot.size_in_bytes } } $TableParams = @{ Name = "Protection Domain Snapshots - $($NtnxCluster.Name)" ColumnWidths = 15, 15, 15, 25, 15, 15 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $ProtectionDomainSnapshots | Sort-Object 'Protection Domain' | Table @TableParams } } #endregion Protection Domain Snapshots #region Unprotected VMs if ($NtnxUnprotectedVMs) { Section -Style Heading3 'Unprotected VMs' { $UnprotectedVMs = foreach ($NtnxUnprotectedVM in $NtnxUnprotectedVMs) { [PSCustomObject]@{ 'VM Name' = $NtnxUnprotectedVM.vm_name 'Power State' = $TextInfo.ToTitleCase($NtnxUnprotectedVM.power_state) 'Operating System' = Switch ($NtnxUnprotectedVM.guest_operating_system) { $null { '--' } default { $NtnxUnprotectedVM.guest_operating_system } } 'Cores' = $NtnxUnprotectedVM.num_vcpus 'Network Adapters' = $NtnxUnprotectedVM.num_network_adapters 'Disk Capacity' = "$([math]::Round(($NtnxUnprotectedVM.disk_capacity_in_bytes) / 1073741824, 2)) GiB" 'Host' = $NtnxUnprotectedVM.host_name } } $TableParams = @{ Name = "Unprotected VMs - $($NtnxCluster.Name)" ColumnWidths = 22, 10, 19, 10, 10, 10, 19 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $UnprotectedVMs | Sort-Object 'VM Name' | Table @TableParams } } #endregion Unprotected VMs #region Remote Sites if ($NtnxRemoteSites) { Section -Style Heading3 'Remote Sites' { $RemoteSites = foreach ($NtnxRemoteSite in $NtnxRemoteSites) { [PSCustomObject]@{ 'Name' = $NtnxRemoteSite.name 'Capabilities' = ($TextInfo.ToTitleCase(($NtnxRemoteSite.capabilities).ToLower()) | Sort-Object) -join ', ' 'Remote Addresses' = "$(($NtnxRemoteSite.remoteIpPorts | Get-Member -MemberType NoteProperty).Name):2020" 'Metro Ready' = Switch ($NtnxRemoteSite.metroReady) { $true { 'Yes' } $false { 'No' } } 'Use SSH Tunnel' = Switch ($NtnxRemoteSite.sshEnabled) { $true { 'Yes' } $false { 'No' } } 'Compress On Wire' = Switch ($NtnxRemoteSite.compressionEnabled) { $true { 'On' } $false { 'Off' } } 'Enable Proxy' = Switch ($NtnxRemoteSite.proxyEnabled) { $true { 'On' } $false { 'Off' } } 'Bandwidth Throttling' = Switch ($NtnxRemoteSite.bandwidthPolicyEnabled) { $true { 'On' } $false { 'Off' } } } } if ($Healthcheck.DataProtection.CompressOnWire) { $RemoteSites | Where-Object { $_.'Compress On Wire' -eq 'On' } | Set-Style -Style Warning -Property 'Compress On Wire' } if ($Healthcheck.DataProtection.CompressOnWire) { $RemoteSites | Where-Object { $_.'Enable Proxy' -eq 'On' } | Set-Style -Style Warning -Property 'Enable Proxy' } if ($Healthcheck.DataProtection.CompressOnWire) { $RemoteSites | Where-Object { $_.'Bandwidth Throttling' -eq 'On' } | Set-Style -Style Warning -Property 'Bandwidth Throttling' } $TableParams = @{ Name = "Remote Sites - $($NtnxCluster.Name)" List = $true ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $RemoteSites | Sort-Object 'Name' | Table @TableParams } } #endregion Remote Sites } } #endregion Data Protection Section } } } |