Src/Public/Invoke-AsBuiltReport.VMware.ESXi.ps1

function Invoke-AsBuiltReport.VMware.ESXi {
    <#
    .SYNOPSIS
        PowerShell script to document the configuration of VMware ESXi servers in Word/HTML/XML/Text formats
    .DESCRIPTION
        Documents the configuration of VMware ESXi servers in Word/HTML/XML/Text formats using PScribo.
    .NOTES
        Version: 1.1.0
        Author: Tim Carman
        Twitter: @tpcarman
        Github: tpcarman
        Credits: Iain Brighton (@iainbrighton) - PScribo module
    .LINK
        https://github.com/AsBuiltReport/AsBuiltReport.VMware.ESXi
    #>


    param (
        [String[]] $Target,
        [PSCredential] $Credential
    )

    # Check if the required version of VMware PowerCLI is installed
    Get-RequiredModule -Name 'VMware.PowerCLI' -Version '12.3'

    # Import Report Configuration
    $Report = $ReportConfig.Report
    $InfoLevel = $ReportConfig.InfoLevel
    $Options = $ReportConfig.Options
    # Used to set values to TitleCase where required
    $TextInfo = (Get-Culture).TextInfo

    #region Script Body
    #---------------------------------------------------------------------------------------------#
    # SCRIPT BODY #
    #---------------------------------------------------------------------------------------------#
    # Connect to ESXi Server using supplied credentials
    foreach ($VIServer in $Target) {
        try {
            Write-PScriboMessage "Connecting to ESXi Server '$VIServer'."
            $ESXi = Connect-VIServer $VIServer -Credential $Credential -Protocol https -ErrorAction Stop
        } catch {
            Write-Error $_
        }
        #region Generate ESXi report
        if ($ESXi) {
            # Create a lookup hashtable to quickly link VM MoRefs to Names
            # Exclude VMware Site Recovery Manager placeholder VMs
            Write-PScriboMessage 'Creating VM lookup hashtable.'
            $VMs = Get-VM -Server $ESXi | Where-Object {
                $_.ExtensionData.Config.ManagedBy.ExtensionKey -notlike 'com.vmware.vcDr*'
            } | Sort-Object Name
            $VMLookup = @{ }
            foreach ($VM in $VMs) {
                $VMLookup.($VM.Id) = $VM.Name
            }

            # Create a lookup hashtable to link Host MoRefs to Names
            # Exclude VMware HCX hosts and ESX/ESXi versions prior to vSphere 5.0 from VMHost lookup
            Write-PScriboMessage 'Creating VMHost lookup hashtable.'
            $VMHost = Get-VMHost -Server $ESXi | Where-Object { $_.Model -notlike "*VMware Mobility Platform" -and $_.Version -gt 5 } | Sort-Object Name
            $VMHostLookup = @{ }
            $VMHostLookup.($VMHost.Id) = $VMHost.ExtensionData.Name

            # Create a lookup hashtable to link Datastore MoRefs to Names
            Write-PScriboMessage 'Creating Datastore lookup hashtable.'
            $Datastores = Get-Datastore -Server $ESXi | Where-Object { ($_.State -eq 'Available') -and ($_.CapacityGB -gt 0) } | Sort-Object Name
            $DatastoreLookup = @{ }
            foreach ($Datastore in $Datastores) {
                $DatastoreLookup.($Datastore.Id) = $Datastore.Name
            }

            # Create a lookup hashtable to link VDS Port Groups MoRefs to Names
            Write-PScriboMessage 'Creating VDPortGroup lookup hashtable.'
            $VDPortGroups = Get-VDPortgroup -Server $ESXi | Sort-Object Name
            $VDPortGroupLookup = @{ }
            foreach ($VDPortGroup in $VDPortGroups) {
                $VDPortGroupLookup.($VDPortGroup.Key) = $VDPortGroup.Name
            }

            Write-PScriboMessage "VMHost InfoLevel set at $($InfoLevel.VMHost)."
            #region Hosts Section
            if ($VMHost | Where-Object { $_.ConnectionState -eq 'Connected' -or $_.ConnectionState -eq 'Maintenance' }) {
                #region ESXi Host Detailed Information
                Section -Style Heading1 $($VMHost.ExtensionData.Name) {
                    Paragraph "The following sections detail the configuration of VMware ESXi host $($VMHost.ExtensionData.Name)."
                    # TODO: Host Certificate, Swap File Location
                    if ($InfoLevel.VMHost -ge 1) {
                        #region ESXi Host Hardware Section
                        Section -Style Heading2 'Hardware' {
                            Paragraph "The following section details the host hardware configuration for $($VMHost.ExtensionData.Name)."
                            BlankLine

                            #region ESXi Host Specifications
                            $VMHostUptime = Get-Uptime -VMHost $VMHost
                            $esxcli = Get-EsxCli -VMHost $VMHost -V2
                            $VMHostLicense = Get-VMHostLicense -VMHost $VMHost
                            $ScratchLocation = Get-AdvancedSetting -Entity $VMHost | Where-Object { $_.Name -eq 'ScratchConfig.CurrentScratchLocation' }
                            $VMHostDetail = [PSCustomObject]@{
                                'Host' = $VMHost.ExtensionData.Name
                                'Connection State' = Switch ($VMHost.ConnectionState) {
                                    'NotResponding' { 'Not Responding' }
                                    default { $VMHost.ConnectionState }
                                }
                                'ID' = $VMHost.Id
                                'Manufacturer' = $VMHost.Manufacturer
                                'Model' = $VMHost.Model
                                'Serial Number' = Switch ($VMHost.ExtensionData.Hardware.SystemInfo.SerialNumber) {
                                    $null { '--' }
                                    default { $VMHost.ExtensionData.Hardware.SystemInfo.SerialNumber }
                                }
                                'Asset Tag' = Switch ($VMHost.ExtensionData.Summary.Hardware.OtherIdentifyingInfo[0].IdentifierValue) {
                                    '' { 'Unknown' }
                                    $null  { 'Unknown' }
                                    default { $VMHost.ExtensionData.Summary.Hardware.OtherIdentifyingInfo[0].IdentifierValue }
                                }
                                'Processor Type' = $VMHost.Processortype
                                'HyperThreading' = Switch ($VMHost.HyperthreadingActive) {
                                    $true { 'Enabled' }
                                    $false { 'Disabled' }
                                }
                                'Number of CPU Sockets' = $VMHost.ExtensionData.Hardware.CpuInfo.NumCpuPackages
                                'Number of CPU Cores' = $VMHost.ExtensionData.Hardware.CpuInfo.NumCpuCores
                                'Number of CPU Threads' = $VMHost.ExtensionData.Hardware.CpuInfo.NumCpuThreads
                                'CPU Total / Used' = "$([math]::Round(($VMHost.CpuTotalMhz) / 1000, 2)) GHz / $([math]::Round(($VMHost.CpuUsageMhz) / 1000, 2)) GHz"
                                'Memory Total / Used' = "$([math]::Round($VMHost.MemoryTotalGB, 2)) GB / $([math]::Round($VMHost.MemoryUsageGB, 2)) GB"
                                'NUMA Nodes' = $VMHost.ExtensionData.Hardware.NumaInfo.NumNodes
                                'Number of NICs' = $VMHost.ExtensionData.Summary.Hardware.NumNics
                                'Number of Datastores' = $VMHost.ExtensionData.Datastore.Count
                                'Number of VMs' = $VMHost.ExtensionData.VM.Count
                                'Power Management Policy' = $VMHost.ExtensionData.Hardware.CpuPowerManagementInfo.CurrentPolicy
                                'Scratch Location' = $ScratchLocation.Value
                                'Bios Version' = $VMHost.ExtensionData.Hardware.BiosInfo.BiosVersion
                                'Bios Release Date' = $VMHost.ExtensionData.Hardware.BiosInfo.ReleaseDate
                                'ESXi Version' = $VMHost.Version
                                'ESXi Build' = $VMHost.build
                                'Product' = $VMHostLicense.Product -join ', '
                                'License Key' = $VMHostLicense.LicenseKey
                                'License Expiration' = $VMHostLicense.Expiration
                                'Boot Time' = ($VMHost.ExtensionData.Runtime.Boottime).ToLocalTime()
                                'Uptime Days' = $VMHostUptime.UptimeDays
                            }
                            if ($Healthcheck.VMHost.ConnectionState) {
                                $VMHostDetail | Where-Object { $_.'Connection State' -eq 'Maintenance' } | Set-Style -Style Warning -Property 'Connection State'
                            }
                            if ($Healthcheck.VMHost.HyperThreading) {
                                $VMHostDetail | Where-Object { $_.'HyperThreading' -eq 'Disabled' } | Set-Style -Style Warning -Property 'Disabled'
                            }
                            if ($Healthcheck.VMHost.Licensing) {
                                $VMHostDetail | Where-Object { $_.'Product' -like '*Evaluation*' } | Set-Style -Style Warning -Property 'Product'
                                $VMHostDetail | Where-Object { $_.'License Key' -like '*-00000-00000' } | Set-Style -Style Warning -Property 'License Key'
                                $VMHostDetail | Where-Object { $_.'License Expiration' -eq 'Expired' } | Set-Style -Style Critical -Property 'License Expiration'
                            }
                            if ($Healthcheck.VMHost.ScratchLocation) {
                                $VMHostDetail | Where-Object { $_.'Scratch Location' -eq '/tmp/scratch' } | Set-Style -Style Warning -Property 'Scratch Location'
                            }
                            if ($Healthcheck.VMHost.UpTimeDays) {
                                $VMHostDetail | Where-Object { $_.'Uptime Days' -ge 275 -and $_.'Uptime Days' -lt 365 } | Set-Style -Style Warning -Property 'Uptime Days'
                                $VMHostDetail | Where-Object { $_.'Uptime Days' -ge 365 } | Set-Style -Style Critical -Property 'Uptime Days'
                            }
                            $TableParams = @{
                                Name = "ESXi Host Configuration - $($VMHost.ExtensionData.Name)"
                                List = $true
                                ColumnWidths = 50, 50
                            }
                            if ($Report.ShowTableCaptions) {
                                $TableParams['Caption'] = "- $($TableParams.Name)"
                            }
                            $VMHostDetail | Table @TableParams
                            #endregion ESXi Host Specifications

                            #region ESXi Host Boot Device
                            Section -Style Heading3 'Boot Device' {
                                $ESXiBootDevice = Get-ESXiBootDevice -VMHost $VMHost
                                $VMHostBootDevice = [PSCustomObject]@{
                                    'Host' = $ESXiBootDevice.Host
                                    'Device' = $ESXiBootDevice.Device
                                    'Boot Type' = $ESXiBootDevice.BootType
                                    'Vendor' = $ESXiBootDevice.Vendor
                                    'Model' = $ESXiBootDevice.Model
                                    'Size' = "$([math]::Round($ESXiBootDevice.SizeMB / 1024, 2)) GB"
                                    'Is SAS' = $ESXiBootDevice.IsSAS
                                    'Is SSD' = $ESXiBootDevice.IsSSD
                                    'Is USB' = $ESXiBootDevice.IsUSB
                                }
                                $TableParams = @{
                                    Name = "Boot Device - $($VMHost.ExtensionData.Name)"
                                    List = $true
                                    ColumnWidths = 50, 50
                                }
                                if ($Report.ShowTableCaptions) {
                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                }
                                $VMHostBootDevice | Table @TableParams
                            }
                            #endregion ESXi Host Boot Devices

                            #region ESXi Host PCI Devices
                            Section -Style Heading3 'PCI Devices' {
                                $PciHardwareDevices = $esxcli.hardware.pci.list.Invoke() | Where-Object { $_.VMkernelName -match 'vmhba|vmnic|vmgfx' -and $_.ModuleName -ne 'None'} | Sort-Object -Property VMkernelName
                                $VMHostPciDevices = foreach ($PciHardwareDevice in $PciHardwareDevices) {
                                    [PSCustomObject]@{
                                        'Device' = $PciHardwareDevice.VMkernelName
                                        'PCI Address' = $PciHardwareDevice.Address
                                        'Device Class' = $PciHardwareDevice.DeviceClassName
                                        'Device Name' = $PciHardwareDevice.DeviceName
                                        'Vendor Name' = $PciHardwareDevice.VendorName
                                        'Slot Description' = $PciHardwareDevice.SlotDescription
                                    }
                                }
                                $TableParams = @{
                                    Name = "PCI Devices - $($VMHost.ExtensionData.Name)"
                                    ColumnWidths = 12, 13, 15, 25, 20, 15
                                }
                                if ($Report.ShowTableCaptions) {
                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                }
                                $VMHostPciDevices | Table @TableParams
                            }
                            #endregion ESXi Host PCI Devices

                            #region ESXi Host PCI Devices Drivers & Firmware
                            Section -Style Heading3 'PCI Devices Drivers & Firmware' {
                                $VMHostPciDevicesDetails = Get-PciDeviceDetail -Server $ESXi -esxcli $esxcli | Sort-Object 'Device'
                                $TableParams = @{
                                    Name = "PCI Devices Drivers & Firmware - $($VMHost.ExtensionData.Name)"
                                    ColumnWidths = 12, 20, 11, 19, 11, 11, 16
                                }
                                if ($Report.ShowTableCaptions) {
                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                }
                                $VMHostPciDevicesDetails | Table @TableParams
                            }
                            #endregion ESXi Host PCI Devices Drivers & Firmware
                            #>
                        }
                        #endregion ESXi Host Hardware Section

                        #region ESXi Host System Section
                        Section -Style Heading2 'System' {
                            Paragraph "The following section details the host system configuration for $($VMHost.ExtensionData.Name)."
                            #region ESXi Host Image Profile Information
                            Section -Style Heading3 'Image Profile' {
                                $installdate = Get-InstallDate
                                $esxcli = Get-EsxCli -VMHost $VMHost -V2
                                $ImageProfile = $esxcli.software.profile.get.Invoke()
                                $SecurityProfile = [PSCustomObject]@{
                                    'Image Profile' = $ImageProfile.Name
                                    'Vendor' = $ImageProfile.Vendor
                                    'Installation Date' = $InstallDate.InstallDate
                                }
                                $TableParams = @{
                                    Name = "Image Profile - $($VMHost.ExtensionData.Name)"
                                    #ColumnWidths = 50, 25, 25
                                }
                                if ($Report.ShowTableCaptions) {
                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                }
                                $SecurityProfile | Table @TableParams
                            }
                            #endregion ESXi Host Image Profile Information

                            #region ESXi Host Time Configuration
                            Section -Style Heading3 'Time Configuration' {
                                $VMHostTimeSettings = [PSCustomObject]@{
                                    'Time Zone' = $VMHost.timezone
                                    'NTP Service' = Switch ((Get-VMHostService -VMHost $VMHost | Where-Object { $_.key -eq 'ntpd' }).Running) {
                                        $true { 'Running' }
                                        $false { 'Stopped' }
                                    }
                                    'NTP Server(s)' = (Get-VMHostNtpServer -VMHost $VMHost | Sort-Object) -join ', '
                                }
                                if ($Healthcheck.VMHost.NTP) {
                                    $VMHostTimeSettings | Where-Object { $_.'NTP Service' -eq 'Stopped' } | Set-Style -Style Critical -Property 'NTP Service'
                                }
                                $TableParams = @{
                                    Name = "Time Configuration - $($VMHost.ExtensionData.Name)"
                                    ColumnWidths = 30, 30, 40
                                }
                                if ($Report.ShowTableCaptions) {
                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                }
                                $VMHostTimeSettings | Table @TableParams
                            }
                            #endregion ESXi Host Time Configuration

                            #region ESXi Host Syslog Configuration
                            $SyslogConfig = $VMHost | Get-VMHostSysLogServer
                            if ($SyslogConfig) {
                                Section -Style Heading3 'Syslog Configuration' {
                                    # TODO: Syslog Rotate & Size, Log Directory (Adv Settings)
                                    $SyslogConfig = $SyslogConfig | Select-Object @{L = 'SysLog Server'; E = { $_.Host } }, Port
                                    $TableParams = @{
                                        Name = "Syslog Configuration - $($VMHost.ExtensionData.Name)"
                                        ColumnWidths = 50, 50
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $SyslogConfig | Table @TableParams
                                }
                            }
                            #endregion ESXi Host Syslog Configuration

                            #region ESXi Host Comprehensive Information Section
                            if ($InfoLevel.VMHost -ge 5) {
                                #region ESXi Host Advanced System Settings
                                Section -Style Heading3 'Advanced System Settings' {
                                    $AdvSettings = $VMHost | Get-AdvancedSetting | Select-Object Name, Value
                                    $TableParams = @{
                                        Name = "Advanced System Settings - $($VMHost.ExtensionData.Name)"
                                        ColumnWidths = 50, 50
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $AdvSettings | Sort-Object Name | Table @TableParams
                                }
                                #endregion ESXi Host Advanced System Settings

                                #region ESXi Host Software VIBs
                                Section -Style Heading3 'Software VIBs' {
                                    $esxcli = Get-EsxCli -VMHost $VMHost -V2
                                    $VMHostVibs = $esxcli.software.vib.list.Invoke()
                                    $VMHostVibs = foreach ($VMHostVib in $VMHostVibs) {
                                        [PSCustomObject]@{
                                            'VIB' = $VMHostVib.Name
                                            'ID' = $VMHostVib.Id
                                            'Version' = $VMHostVib.Version
                                            'Acceptance Level' = $VMHostVib.AcceptanceLevel
                                            'Creation Date' = $VMHostVib.CreationDate
                                            'Install Date' = $VMHostVib.InstallDate
                                        }
                                    }
                                    $TableParams = @{
                                        Name = "Software VIBs - $($VMHost.ExtensionData.Name)"
                                        ColumnWidths = 15, 25, 15, 15, 15, 15
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $VMHostVibs | Sort-Object 'Install Date' -Descending | Table @TableParams
                                }
                                #endregion ESXi Host Software VIBs
                            }
                            #endregion ESXi Host Comprehensive Information Section
                        }
                        #endregion ESXi Host System Section

                        #region ESXi Host Storage Section
                        if ($InfoLevel.Storage -ge 1) {
                            Section -Style Heading2 'Storage' {
                                Paragraph "The following section details the host storage configuration for $($VMHost.ExtensionData.Name)."

                                #region Datastore Section
                                Write-PScriboMessage "Storage InfoLevel set at $($InfoLevel.Storage)."

                                if ($Datastores) {
                                    Section -Style Heading3 'Datastores' {
                                        #region Datastore Infomative Information
                                        if (($InfoLevel.Storage -ge 1) -and ($InfoLevel.Storage -lt 3)) {
                                            $DatastoreInfo = foreach ($Datastore in $Datastores) {
                                                [PSCustomObject]@{
                                                    'Datastore' = $Datastore.Name
                                                    'Type' = $Datastore.Type
                                                    'Version' = Switch ($Datastore.FileSystemVersion) {
                                                        $null { '--' }
                                                        default { $Datastore.FileSystemVersion }
                                                    }
                                                    '# of VMs' = $Datastore.ExtensionData.VM.Count
                                                    'Total Capacity GB' = [math]::Round($Datastore.CapacityGB, 2)
                                                    'Used Capacity GB' = [math]::Round((($Datastore.CapacityGB) - ($Datastore.FreeSpaceGB)), 2)
                                                    'Free Space GB' = [math]::Round($Datastore.FreeSpaceGB, 2)
                                                    '% Used' = [math]::Round((100 - (($Datastore.FreeSpaceGB) / ($Datastore.CapacityGB) * 100)), 2)
                                                }
                                            }
                                            if ($Healthcheck.Datastore.CapacityUtilization) {
                                                $DatastoreInfo | Where-Object { $_.'% Used' -ge 90 } | Set-Style -Style Critical -Property '% Used'
                                                $DatastoreInfo | Where-Object { $_.'% Used' -ge 75 -and $_.'% Used' -lt 90 } | Set-Style -Style Warning -Property '% Used'
                                            }
                                            $TableParams = @{
                                                Name = "Datastores - $($VMHost.ExtensionData.Name)"
                                                ColumnWidths = 20, 8, 9, 8, 15, 15, 15, 10
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $DatastoreInfo | Sort-Object 'Datastore' | Table @TableParams
                                        }
                                        #endregion Datastore Advanced Summary

                                        #region Datastore Detailed Information
                                        if ($InfoLevel.Storage -ge 3) {
                                            foreach ($Datastore in $Datastores) {
                                                #region Datastore Section
                                                Section -Style Heading4 $Datastore.Name {
                                                    $DatastoreDetail = [PSCustomObject]@{
                                                        'Datastore' = $Datastore.Name
                                                        'ID' = $Datastore.Id
                                                        'Type' = $Datastore.Type
                                                        'Version' = Switch ($Datastore.FileSystemVersion) {
                                                            $null { '--' }
                                                            default { $Datastore.FileSystemVersion }
                                                        }
                                                        'State' = $Datastore.State
                                                        'Number of VMs' = $Datastore.ExtensionData.VM.Count
                                                        'Storage I/O Control' = Switch ($Datastore.StorageIOControlEnabled) {
                                                            $true { 'Enabled' }
                                                            $false { 'Disabled' }
                                                        }
                                                        'Congestion Threshold' = Switch ($Datastore.CongestionThresholdMillisecond) {
                                                            $null { '--' }
                                                            default { "$($Datastore.CongestionThresholdMillisecond) ms" }
                                                        }
                                                        'Total Capacity' = "$([math]::Round($Datastore.CapacityGB, 2)) GB"
                                                        'Used Capacity' = "$([math]::Round((($Datastore.CapacityGB) - ($Datastore.FreeSpaceGB)), 2)) GB"
                                                        'Free Space' = "$([math]::Round($Datastore.FreeSpaceGB, 2)) GB"
                                                        '% Used' = [math]::Round((100 - (($Datastore.FreeSpaceGB) / ($Datastore.CapacityGB) * 100)), 2)
                                                    }
                                                    if ($Healthcheck.Datastore.CapacityUtilization) {
                                                        $DatastoreDetail | Where-Object { $_.'% Used' -ge 90 } | Set-Style -Style Critical -Property '% Used'
                                                        $DatastoreDetail | Where-Object { $_.'% Used' -ge 75 -and
                                                            $_.'% Used' -lt 90 } | Set-Style -Style Warning -Property '% Used'
                                                    }

                                                    #region Datastore Advanced Detailed Information
                                                    if ($InfoLevel.Storage -ge 4) {
                                                        $MemberProps = @{
                                                            'InputObject' = $DatastoreDetail
                                                            'MemberType' = 'NoteProperty'
                                                        }
                                                        $DatastoreVMs = foreach ($DatastoreVM in $Datastore.ExtensionData.VM) {
                                                            $VMLookup."$($DatastoreVM.Type)-$($DatastoreVM.Value)"
                                                        }
                                                        Add-Member @MemberProps -Name 'Virtual Machines' -Value (($DatastoreVMs | Sort-Object) -join ', ')
                                                    }
                                                    #endregion Datastore Advanced Detailed Information
                                                    $TableParams = @{
                                                        Name = "Datastore $($Datastore.Name) - $($VMHost.ExtensionData.Name)"
                                                        List = $true
                                                        ColumnWidths = 50, 50
                                                    }
                                                    if ($Report.ShowTableCaptions) {
                                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                                    }
                                                    $DatastoreDetail | Sort-Object Datacenter, Datastore | Table @TableParams

                                                    # Get VMFS volumes. Ignore local SCSILuns.
                                                    if (($Datastore.Type -eq 'VMFS') -and ($Datastore.ExtensionData.Info.Vmfs.Local -eq $false)) {
                                                        #region SCSI LUN Information Section
                                                        Section -Style Heading4 'SCSI LUNs' {
                                                            $ScsiLuns = foreach ($DatastoreHost in $Datastore.ExtensionData.Host.Key) {
                                                                $DiskName = $Datastore.ExtensionData.Info.Vmfs.Extent.DiskName
                                                                $ScsiDeviceDetailProps = @{
                                                                    'VMHosts' = $VMHost
                                                                    'VMHostMoRef' = "$($DatastoreHost.Type)-$($DatastoreHost.Value)"
                                                                    'DatastoreDiskName' = $DiskName
                                                                }
                                                                $ScsiDeviceDetail = Get-ScsiDeviceDetail @ScsiDeviceDetailProps

                                                                [PSCustomObject]@{
                                                                    'Host' = $VMHostLookup."$($DatastoreHost.Type)-$($DatastoreHost.Value)"
                                                                    'Canonical Name' = $DiskName
                                                                    'Capacity GB' = $ScsiDeviceDetail.CapacityGB
                                                                    'Vendor' = $ScsiDeviceDetail.Vendor
                                                                    'Model' = $ScsiDeviceDetail.Model
                                                                    'Is SSD' = $ScsiDeviceDetail.Ssd
                                                                    'Multipath Policy' = $ScsiDeviceDetail.MultipathPolicy
                                                                    'Paths' = $ScsiDeviceDetail.Paths
                                                                }
                                                            }
                                                            $TableParams = @{
                                                                Name = "SCSI LUNs - $($VMHost.ExtensionData.Name)"
                                                                ColumnWidths = 18, 18, 10, 14, 12, 8, 12, 8
                                                            }
                                                            if ($Report.ShowTableCaptions) {
                                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                                            }
                                                            $ScsiLuns | Sort-Object Host | Table @TableParams
                                                        }
                                                        #endregion SCSI LUN Information Section
                                                    }
                                                }
                                                #endregion Datastore Section
                                            }
                                        }
                                        #endregion Datastore Detailed Information
                                    }
                                }
                                #endregion Datastore Section

                                #region ESXi Host Storage Adapter Information
                                $VMHostHbas = $VMHost | Get-VMHostHba | Sort-Object Device
                                if ($VMHostHbas) {
                                    #region ESXi Host Storage Adapters Section
                                    Section -Style Heading3 'Storage Adapters' {
                                        if ($InfoLevel.VMHost -ge 3) {
                                            foreach ($VMHostHba in $VMHostHbas) {
                                                $Target = ((Get-View $VMHostHba.VMhost).Config.StorageDevice.ScsiTopology.Adapter | Where-Object { $_.Adapter -eq $VMHostHba.Key }).Target
                                                $LUNs = Get-ScsiLun -Hba $VMHostHba -LunType "disk" -ErrorAction SilentlyContinue
                                                $Paths = ($Target | ForEach-Object { $_.Lun.Count } | Measure-Object -Sum)
                                                Section -Style Heading4 "$($VMHostHba.Device)" {
                                                    $VMHostStorageAdapter = [PSCustomObject]@{
                                                        'Adapter' = $VMHostHba.Device
                                                        'Type' = Switch ($VMHostHba.Type) {
                                                            'FibreChannel' { 'Fibre Channel' }
                                                            'IScsi' { 'iSCSI' }
                                                            'ParallelScsi' { 'Parallel SCSI' }
                                                            default { $TextInfo.ToTitleCase($VMHostHba.Type) }
                                                        }
                                                        'Model' = $VMHostHba.Model
                                                        'Status' = $TextInfo.ToTitleCase($VMHostHba.Status)
                                                        'Targets' = $Target.Count
                                                        'Devices' = $LUNs.Count
                                                        'Paths' = $Paths.Sum
                                                    }
                                                    $MemberProps = @{
                                                        'InputObject' = $VMHostStorageAdapter
                                                        'MemberType' = 'NoteProperty'
                                                    }
                                                    if ($VMHostStorageAdapter.Type -eq 'iSCSI') {
                                                        $iScsiAuthenticationMethod = Switch ($VMHostHba.ExtensionData.AuthenticationProperties.ChapAuthenticationType) {
                                                            'chapProhibited' { 'None' }
                                                            'chapPreferred' { 'Use unidirectional CHAP unless prohibited by target' }
                                                            'chapDiscouraged' { 'Use unidirectional CHAP if required by target' }
                                                            'chapRequired' {
                                                                Switch ($VMHostHba.ExtensionData.AuthenticationProperties.MutualChapAuthenticationType) {
                                                                    'chapProhibited' { 'Use unidirectional CHAP' }
                                                                    'chapRequired' { 'Use bidirectional CHAP' }
                                                                }
                                                            }
                                                            default { $VMHostHba.ExtensionData.AuthenticationProperties.ChapAuthenticationType }
                                                        }
                                                        Add-Member @MemberProps -Name 'iSCSI Name' -Value $VMHostHba.IScsiName
                                                        if ($VMHostHba.IScsiAlias) {
                                                            Add-Member @MemberProps -Name 'iSCSI Alias' -Value $VMHostHba.IScsiAlias
                                                        } else {
                                                            Add-Member @MemberProps -Name 'iSCSI Alias' -Value '--'
                                                        }
                                                        if ($VMHostHba.CurrentSpeedMb) {
                                                            Add-Member @MemberProps -Name 'Speed' -Value "$($VMHostHba.CurrentSpeedMb) Mb"
                                                        } else {
                                                            Add-Member @MemberProps -Name 'Speed' -Value '--'
                                                        }
                                                        if ($VMHostHba.ExtensionData.ConfiguredSendTarget) {
                                                            Add-Member @MemberProps -Name 'Dynamic Discovery' -Value (($VMHostHba.ExtensionData.ConfiguredSendTarget | ForEach-Object { "$($_.Address)" + ":" + "$($_.Port)" }) -join [Environment]::NewLine)
                                                        } else {
                                                            Add-Member @MemberProps -Name 'Dynamic Discovery' -Value '--'
                                                        }
                                                        if ($VMHostHba.ExtensionData.ConfiguredStaticTarget) {
                                                            Add-Member @MemberProps -Name 'Static Discovery' -Value (($VMHostHba.ExtensionData.ConfiguredStaticTarget | ForEach-Object { "$($_.Address)" + ":" + "$($_.Port)" + " " + "$($_.IScsiName)" }) -join [Environment]::NewLine)
                                                        } else {
                                                            Add-Member @MemberProps -Name 'Static Discovery' -Value '--'
                                                        }
                                                        if ($iScsiAuthenticationMethod -eq 'None') {
                                                            Add-Member @MemberProps -Name 'Authentication Method' -Value $iScsiAuthenticationMethod
                                                        } elseif ($iScsiAuthenticationMethod -eq 'Use bidirectional CHAP') {
                                                            Add-Member @MemberProps -Name 'Authentication Method' -Value $iScsiAuthenticationMethod
                                                            Add-Member @MemberProps -Name 'Outgoing CHAP Name' -Value $VMHostHba.ExtensionData.AuthenticationProperties.ChapName
                                                            Add-Member @MemberProps -Name 'Incoming CHAP Name' -Value $VMHostHba.ExtensionData.AuthenticationProperties.MutualChapName
                                                        } else {
                                                            Add-Member @MemberProps -Name 'Authentication Method' -Value $iScsiAuthenticationMethod
                                                            Add-Member @MemberProps -Name 'Outgoing CHAP Name' -Value $VMHostHba.ExtensionData.AuthenticationProperties.ChapName
                                                        }
                                                        if ($InfoLevel.VMHost -eq 4) {
                                                            Add-Member @MemberProps -Name 'Advanced Options' -Value (($VMHostHba.ExtensionData.AdvancedOptions | ForEach-Object { "$($_.Key) = $($_.Value)" }) -join [Environment]::NewLine)
                                                        }
                                                    }
                                                    if ($VMHostStorageAdapter.Type -eq 'Fibre Channel') {
                                                        Add-Member @MemberProps -Name 'Node WWN' -Value (([String]::Format("{0:X}", $VMHostHba.NodeWorldWideName) -split "(\w{2})" | Where-Object { $_ -ne "" }) -join ":")
                                                        Add-Member @MemberProps -Name 'Port WWN' -Value (([String]::Format("{0:X}", $VMHostHba.PortWorldWideName) -split "(\w{2})" | Where-Object { $_ -ne "" }) -join ":")
                                                        Add-Member @MemberProps -Name 'Speed' -Value $VMHostHba.Speed
                                                    }
                                                    if ($Healthcheck.VMHost.StorageAdapter) {
                                                        $VMHostStorageAdapter | Where-Object { $_.'Status' -ne 'Online' } | Set-Style -Style Warning -Property 'Status'
                                                        $VMHostStorageAdapter | Where-Object { $_.'Status' -eq 'Offline' } | Set-Style -Style Critical -Property 'Status'
                                                    }
                                                    $TableParams = @{
                                                        Name = "Storage Adapter $($VMHostStorageAdapter.Adapter) - $($VMHost.ExtensionData.Name)"
                                                        List = $true
                                                        ColumnWidths = 25, 75
                                                    }
                                                    if ($Report.ShowTableCaptions) {
                                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                                    }
                                                    $VMHostStorageAdapter | Table @TableParams
                                                }
                                            }
                                        } else {
                                            $VMHostStorageAdapters = foreach ($VMHostHba in $VMHostHbas) {
                                                [PSCustomObject]@{
                                                    'Adapter' = $VMHostHba.Device
                                                    'Type' = Switch ($VMHostHba.Type) {
                                                        'FibreChannel' { 'Fibre Channel' }
                                                        'IScsi' { 'iSCSI' }
                                                        'ParallelScsi' { 'Parallel SCSI' }
                                                        default { $TextInfo.ToTitleCase($VMHostHba.Type) }
                                                    }
                                                    'Model' = $VMHostHba.Model
                                                    'Status' = $TextInfo.ToTitleCase($VMHostHba.Status)
                                                }
                                            }
                                            if ($Healthcheck.VMHost.StorageAdapter) {
                                                $VMHostStorageAdapters | Where-Object { $_.'Status' -ne 'Online' } | Set-Style -Style Warning -Property 'Status'
                                                $VMHostStorageAdapters | Where-Object { $_.'Status' -eq 'Offline' } | Set-Style -Style Critical -Property 'Status'
                                            }
                                            $TableParams = @{
                                                Name = "Storage Adapters - $($VMHost.ExtensionData.Name)"
                                                ColumnWidths = 25, 25, 25, 25
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VMHostStorageAdapters | Table @TableParams
                                        }
                                    }
                                    #endregion ESXi Host Storage Adapters Section
                                }
                                #endregion ESXi Host Storage Adapter Information
                            }
                        }
                        #endregion ESXi Host Storage Section
                    }

                    #region ESXi Host Network Section
                    if ($InfoLevel.Network -ge 1) {
                        Section -Style Heading2 'Network' {
                            Paragraph "The following section details the host network configuration for $($VMHost.ExtensionData.Name)."
                            BlankLine
                            #region ESXi Host Network Configuration
                            $VMHostNetwork = $VMHost.ExtensionData.Config.Network
                            $VMHostVirtualSwitch = @()
                            $VMHostVss = foreach ($vSwitch in $VMHost.ExtensionData.Config.Network.Vswitch) {
                                $VMHostVirtualSwitch += $vSwitch.Name
                            }
                            $VMHostDvs = foreach ($dvSwitch in $VMHost.ExtensionData.Config.Network.ProxySwitch) {
                                $VMHostVirtualSwitch += $dvSwitch.DvsName
                            }
                            $VMHostNetworkDetail = [PSCustomObject]@{
                                'Host' = $($VMHost.ExtensionData.Name)
                                'Virtual Switches' = ($VMHostVirtualSwitch | Sort-Object) -join ', '
                                'VMkernel Adapters' = ($VMHostNetwork.Vnic.Device | Sort-Object) -join ', '
                                'Physical Adapters' = ($VMHostNetwork.Pnic.Device | Sort-Object) -join ', '
                                'VMkernel Gateway' = $VMHostNetwork.IpRouteConfig.DefaultGateway
                                'IPv6' = Switch ($VMHostNetwork.IPv6Enabled) {
                                    $true { 'Enabled' }
                                    $false { 'Disabled' }
                                }
                                'VMkernel IPv6 Gateway' = Switch ($VMHostNetwork.IpRouteConfig.IpV6DefaultGateway) {
                                    $null { '--' }
                                    default { $VMHostNetwork.IpRouteConfig.IpV6DefaultGateway }
                                }
                                'DNS Servers' = ($VMHostNetwork.DnsConfig.Address | Sort-Object) -join ', '
                                'Host Name' = $VMHostNetwork.DnsConfig.HostName
                                'Domain Name' = $VMHostNetwork.DnsConfig.DomainName
                                'Search Domain' = ($VMHostNetwork.DnsConfig.SearchDomain | Sort-Object) -join ', '
                            }
                            if ($Healthcheck.VMHost.IPv6) {
                                $VMHostNetworkDetail | Where-Object { $_.'IPv6' -eq $false } | Set-Style -Style Warning -Property 'IPv6'
                            }
                            $TableParams = @{
                                Name = "Network Configuration - $($VMHost.ExtensionData.Name)"
                                List = $true
                                ColumnWidths = 50, 50
                            }
                            if ($Report.ShowTableCaptions) {
                                $TableParams['Caption'] = "- $($TableParams.Name)"
                            }
                            $VMHostNetworkDetail | Table @TableParams
                            #endregion ESXi Host Network Configuration

                            #region ESXi Host Physical Adapters
                            Section -Style Heading3 'Physical Adapters' {
                                $PhysicalNetAdapters = $VMHost.ExtensionData.Config.Network.Pnic | Sort-Object Device
                                $VMHostPhysicalNetAdapters = foreach ($PhysicalNetAdapter in $PhysicalNetAdapters) {
                                    [PSCustomObject]@{
                                        'Adapter' = $PhysicalNetAdapter.Device
                                        'Status' = Switch ($PhysicalNetAdapter.Linkspeed) {
                                            $null { 'Disconnected' }
                                            default { 'Connected' }
                                        }
                                        'Virtual Switch' = $(
                                            if ($VMHost.ExtensionData.Config.Network.Vswitch.Pnic -contains $PhysicalNetAdapter.Key) {
                                                ($VMHost.ExtensionData.Config.Network.Vswitch | Where-Object { $_.Pnic -eq $PhysicalNetAdapter.Key }).Name
                                            } elseif ($VMHost.ExtensionData.Config.Network.ProxySwitch.Pnic -contains $PhysicalNetAdapter.Key) {
                                                ($VMHost.ExtensionData.Config.Network.ProxySwitch | Where-Object { $_.Pnic -eq $PhysicalNetAdapter.Key }).DvsName
                                            } else {
                                                '--'
                                            }
                                        )
                                        'MAC Address' = $PhysicalNetAdapter.Mac
                                        'Actual Speed, Duplex' = Switch ($PhysicalNetAdapter.LinkSpeed.SpeedMb) {
                                            $null { 'Down' }
                                            default {
                                                if ($PhysicalNetAdapter.LinkSpeed.Duplex) {
                                                    "$($PhysicalNetAdapter.LinkSpeed.SpeedMb) Mbps, Full Duplex"
                                                } else {
                                                    'Auto negotiate'
                                                }
                                            }
                                        }
                                        'Configured Speed, Duplex' = Switch ($PhysicalNetAdapter.Spec.LinkSpeed) {
                                            $null { 'Auto negotiate' }
                                            default {
                                                if ($PhysicalNetAdapter.Spec.LinkSpeed.Duplex) {
                                                    "$($PhysicalNetAdapter.Spec.LinkSpeed.SpeedMb) Mbps, Full Duplex"
                                                } else {
                                                    "$($PhysicalNetAdapter.Spec.LinkSpeed.SpeedMb) Mbps"
                                                }
                                            }
                                        }
                                        'Wake on LAN' = Switch ($PhysicalNetAdapter.WakeOnLanSupported) {
                                            $true { 'Supported' }
                                            $false { 'Not Supported' }
                                        }
                                    }
                                }
                                if ($Healthcheck.VMHost.NetworkAdapter) {
                                    $VMHostPhysicalNetAdapters | Where-Object { $_.'Status' -ne 'Connected' } | Set-Style -Style Critical -Property 'Status'
                                    $VMHostPhysicalNetAdapters | Where-Object { $_.'Actual Speed, Duplex' -eq 'Down' } | Set-Style -Style Critical -Property 'Actual Speed, Duplex'
                                }
                                if ($InfoLevel.VMHost -ge 4) {
                                    foreach ($VMHostPhysicalNetAdapter in $VMHostPhysicalNetAdapters) {
                                        Section -Style Heading4 "$($VMHostPhysicalNetAdapter.Adapter)" {
                                            $TableParams = @{
                                                Name = "Physical Adapter $($VMHostPhysicalNetAdapter.Adapter) - $($VMHost.ExtensionData.Name)"
                                                List = $true
                                                ColumnWidths = 50, 50
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VMHostPhysicalNetAdapter | Table @TableParams
                                        }
                                    }
                                } else {
                                    $TableParams = @{
                                        Name = "Physical Adapters - $($VMHost.ExtensionData.Name)"
                                        ColumnWidths = 11, 13, 15, 19, 14, 14, 14
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $VMHostPhysicalNetAdapters | Table @TableParams
                                }
                            }
                            #endregion ESXi Host Physical Adapters

                            #region ESXi Host Cisco Discovery Protocol
                            $VMHostNetworkAdapterCDP = $VMHost | Get-VMHostNetworkAdapterDP | Where-Object { $_.Status -eq 'Connected' } | Sort-Object Device
                            if ($VMHostNetworkAdapterCDP) {
                                Section -Style Heading3 'Cisco Discovery Protocol' {
                                    if ($InfoLevel.VMHost -ge 4) {
                                        foreach ($VMHostNetworkAdapter in $VMHostNetworkAdapterCDP) {
                                            Section -Style Heading5 "$($VMHostNetworkAdapter.Device)" {
                                                $VMHostCDP = [PSCustomObject]@{
                                                    'Status' = $VMHostNetworkAdapter.Status
                                                    'System Name' = $VMHostNetworkAdapter.SystemName
                                                    'Hardware Platform' = $VMHostNetworkAdapter.HardwarePlatform
                                                    'Switch ID' = $VMHostNetworkAdapter.SwitchId
                                                    'Software Version' = $VMHostNetworkAdapter.SoftwareVersion
                                                    'Management Address' = $VMHostNetworkAdapter.ManagementAddress
                                                    'Address' = $VMHostNetworkAdapter.Address
                                                    'Port ID' = $VMHostNetworkAdapter.PortId
                                                    'VLAN' = $VMHostNetworkAdapter.Vlan
                                                    'MTU' = $VMHostNetworkAdapter.Mtu
                                                }
                                                $TableParams = @{
                                                    Name = "Network Adapter $($VMHostNetworkAdapter.Device) CDP Information - $($VMHost.ExtensionData.Name)"
                                                    List = $true
                                                    ColumnWidths = 50, 50
                                                }
                                                if ($Report.ShowTableCaptions) {
                                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                                }
                                                $VMHostCDP | Table @TableParams
                                            }
                                        }
                                    } else {
                                        $VMHostCDP = foreach ($VMHostNetworkAdapter in $VMHostNetworkAdapterCDP) {
                                            [PSCustomObject]@{
                                                'Adapter' = $VMHostNetworkAdapter.Device
                                                'Status' = $VMHostNetworkAdapter.Status
                                                'Hardware Platform' = $VMHostNetworkAdapter.HardwarePlatform
                                                'Switch ID' = $VMHostNetworkAdapter.SwitchId
                                                'Address' = $VMHostNetworkAdapter.Address
                                                'Port ID' = $VMHostNetworkAdapter.PortId
                                            }
                                        }
                                        $TableParams = @{
                                            Name = "Network Adapter CDP Information - $($VMHost.ExtensionData.Name)"
                                            ColumnWidths = 11, 13, 26, 22, 17, 11
                                        }
                                        if ($Report.ShowTableCaptions) {
                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                        }
                                        $VMHostCDP | Table @TableParams
                                    }
                                }
                            }
                            #endregion ESXi Host Cisco Discovery Protocol

                            #region ESXi Host Link Layer Discovery Protocol
                            $VMHostNetworkAdapterLLDP = $VMHost | Get-VMHostNetworkAdapterDP | Where-Object { $null -ne $_.ChassisId } | Sort-Object Device
                            if ($VMHostNetworkAdapterLLDP) {
                                Section -Style Heading3 'Link Layer Discovery Protocol' {
                                    if ($InfoLevel.VMHost -ge 4) {
                                        foreach ($VMHostNetworkAdapter in $VMHostNetworkAdapterLLDP) {
                                            Section -Style Heading5 "$($VMHostNetworkAdapter.Device)" {
                                                $VMHostLLDP = [PSCustomObject]@{
                                                    'Chassis ID' = $VMHostNetworkAdapter.ChassisId
                                                    'Port ID' = $VMHostNetworkAdapter.PortId
                                                    'Time to live' = $VMHostNetworkAdapter.TimeToLive
                                                    'TimeOut' = $VMHostNetworkAdapter.TimeOut
                                                    'Samples' = $VMHostNetworkAdapter.Samples
                                                    'Management Address' = $VMHostNetworkAdapter.ManagementAddress
                                                    'Port Description' = $VMHostNetworkAdapter.PortDescription
                                                    'System Description' = $VMHostNetworkAdapter.SystemDescription
                                                    'System Name' = $VMHostNetworkAdapter.SystemName
                                                }
                                                $TableParams = @{
                                                    Name = "Network Adapter $($VMHostNetworkAdapter.Device) LLDP Information - $($VMHost.ExtensionData.Name)"
                                                    List = $true
                                                    ColumnWidths = 50, 50
                                                }
                                                if ($Report.ShowTableCaptions) {
                                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                                }
                                                $VMHostLLDP | Table @TableParams
                                            }
                                        }
                                    } else {
                                        $VMHostLLDP = foreach ($VMHostNetworkAdapter in $VMHostNetworkAdapterLLDP) {
                                            [PSCustomObject]@{
                                                'Adapter' = $VMHostNetworkAdapter.Device
                                                'Chassis ID' = $VMHostNetworkAdapter.ChassisId
                                                'Port ID' = $VMHostNetworkAdapter.PortId
                                                'Management Address' = $VMHostNetworkAdapter.ManagementAddress
                                                'Port Description' = $VMHostNetworkAdapter.PortDescription
                                                'System Name' = $VMHostNetworkAdapter.SystemName
                                            }
                                        }
                                        $TableParams = @{
                                            Name = "Network Adapter LLDP Information - $($VMHost.ExtensionData.Name)"
                                            ColumnWidths = 11, 19, 16, 19, 18, 17
                                        }
                                        if ($Report.ShowTableCaptions) {
                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                        }
                                        $VMHostLLDP | Table @TableParams
                                    }
                                }
                            }
                            #endregion ESXi Host Link Layer Discovery Protocol

                            #region ESXi Host VMkernel Adapaters
                            Section -Style Heading3 'VMkernel Adapters' {
                                $VMkernelAdapters = $VMHost | Get-View | ForEach-Object -Process {
                                    $esx = $_
                                    $netSys = Get-View -Id $_.ConfigManager.NetworkSystem
                                    $vnicMgr = Get-View -Id $_.ConfigManager.VirtualNicManager
                                    $netSys.NetworkInfo.Vnic |
                                    ForEach-Object -Process {
                                        $device = $_.Device
                                        [PSCustomObject]@{
                                            'Adapter' = $_.Device
                                            'Port Group' = & {
                                                if ($_.Spec.Portgroup) {
                                                    $script:pg = $_.Spec.Portgroup
                                                } else {
                                                    $script:pg = Get-View -ViewType DistributedVirtualPortgroup -Property Name, Key -Filter @{'Key' = "$($_.Spec.DistributedVirtualPort.PortgroupKey)" } |
                                                    Select-Object -ExpandProperty Name
                                                }
                                                $script:pg
                                            }
                                            'Virtual Switch' = & {
                                                if ($_.Spec.Portgroup) {
                                                    (Get-VirtualPortGroup -Standard -Name $script:pg -VMHost $VMHost).VirtualSwitchName
                                                } else {
                                                    (Get-VDPortgroup -Name $script:pg).VDSwitch.Name | Select-Object -Unique
                                                }
                                            }
                                            'TCP/IP Stack' = Switch ($_.Spec.NetstackInstanceKey) {
                                                'defaultTcpipStack' { 'Default' }
                                                'vSphereProvisioning' { 'Provisioning' }
                                                'vmotion' { 'vMotion' }
                                                'vxlan' { 'nsx-overlay' }
                                                'hyperbus' { 'nsx-hyperbus' }
                                                $null { 'Not Applicable' }
                                                default { $_.Spec.NetstackInstanceKey }
                                            }
                                            'Enabled Services' = Switch ( $vnicMgr.Info.NetConfig | Where-Object { $_.SelectedVnic -match $device } | ForEach-Object { $_.NicType } ) {
                                                'vmotion' { 'vMotion' }
                                                'vSphereProvisioning' { 'Provisioning' }
                                                'faultToleranceLogging' { 'FT Logging' }
                                                'management' { 'Management' }
                                                'vSphereReplication' { 'vSphere Replication' }
                                                'vSphereReplicationNFC' { 'vSphere Replication NFC' }
                                                'vsan' { 'vSAN' }
                                                'vsanWitness' { 'vSAN Witness' }
                                            }
                                            'MTU' = $_.Spec.Mtu
                                            'MAC Address' = $_.Spec.Mac
                                            'DHCP' = Switch ($_.Spec.Ip.Dhcp) {
                                                $true { 'Enabled' }
                                                $false { 'Disabled' }
                                            }
                                            'IP Address' = & {
                                                if ($_.Spec.IP.IPAddress) {
                                                    $script:ip = $_.Spec.IP.IPAddress
                                                } else {
                                                    $script:ip = '--'
                                                }
                                                $script:ip
                                            }
                                            'Subnet Mask' = & {
                                                if ($_.Spec.IP.SubnetMask) {
                                                    $script:netmask = $_.Spec.IP.SubnetMask
                                                } else {
                                                    $script:netmask = '--'
                                                }
                                                $script:netmask
                                            }
                                            'Default Gateway' = Switch ($_.Spec.IpRouteSpec.IpRouteConfig.DefaultGateway) {
                                                $null { '--' }
                                                default { $_.Spec.IpRouteSpec.IpRouteConfig.DefaultGateway }
                                            }
                                        }
                                    }
                                }

                                if ($InfoLevel.VMHost -ge 3) {
                                    foreach ($VMkernelAdapter in ($VMkernelAdapters | Sort-Object 'Adapter')) {
                                        Section -Style Heading4 "$($VMkernelAdapter.Adapter)" {
                                            $TableParams = @{
                                                Name = "VMkernel Adapter $($VMkernelAdapter.Adapter) - $($VMHost.ExtensionData.Name)"
                                                List = $true
                                                ColumnWidths = 50, 50
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VMkernelAdapter | Table @TableParams
                                        }
                                    }
                                } else {
                                    $TableParams = @{
                                        Name = "VMkernel Adapters - $($VMHost.ExtensionData.Name)"
                                        Columns = 'Adapter', 'Port Group', 'TCP/IP Stack', 'Enabled Services','IP Address'
                                        ColumnWidths = 11, 35, 18, 18, 18
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $VMkernelAdapters | Sort-Object 'Adapter' | Table @TableParams
                                }
                            }
                            #endregion ESXi Host VMkernel Adapaters

                            #region ESXi Host Standard Virtual Switches
                            $VSSwitches = $VMHost | Get-VirtualSwitch -Standard | Sort-Object Name
                            if ($VSSwitches) {
                                #region Section Standard Virtual Switches
                                Section -Style Heading5 'Standard Virtual Switches' {
                                    Paragraph "The following section details the standard virtual switch configuration for $VMHost."
                                    BlankLine
                                    $VSSwitchNicTeaming = $VSSwitches | Get-NicTeamingPolicy
                                    #region ESXi Host Standard Virtual Switch Properties
                                    $VSSProperties = foreach ($VSSwitchNicTeam in $VSSwitchNicTeaming) {
                                        [PSCustomObject]@{
                                            'Virtual Switch' = $VSSwitchNicTeam.VirtualSwitch
                                            'MTU' = $VSSwitchNicTeam.VirtualSwitch.Mtu
                                            'Number of Ports' = $VSSwitchNicTeam.VirtualSwitch.NumPorts
                                            'Number of Ports Available' = $VSSwitchNicTeam.VirtualSwitch.NumPortsAvailable
                                        }
                                    }
                                    $TableParams = @{
                                        Name = "Standard Virtual Switches - $($VMHost.ExtensionData.Name)"
                                        ColumnWidths = 25, 25, 25, 25
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $VSSProperties | Table @TableParams
                                    #endregion ESXi Host Standard Virtual Switch Properties

                                    #region ESXi Host Virtual Switch Security Policy
                                    $VssSecurity = $VSSwitches | Get-SecurityPolicy
                                    if ($VssSecurity) {
                                        #region Virtual Switch Security Policy
                                        Section -Style Heading5 'Virtual Switch Security' {
                                            $VssSecurity = foreach ($VssSec in $VssSecurity) {
                                                [PSCustomObject]@{
                                                    'Virtual Switch' = $VssSec.VirtualSwitch
                                                    'Promiscuous Mode' = Switch ($VssSec.AllowPromiscuous) {
                                                        $true { 'Accept' }
                                                        $false { 'Reject' }
                                                    }
                                                    'MAC Address Changes' = Switch ($VssSec.MacChanges) {
                                                        $true { 'Accept' }
                                                        $false { 'Reject' }
                                                    }
                                                    'Forged Transmits' = Switch ($VssSec.ForgedTransmits) {
                                                        $true { 'Accept' }
                                                        $false { 'Reject' }
                                                    }
                                                }
                                            }
                                            $TableParams = @{
                                                Name = "Virtual Switch Security Policy - $($VMHost.ExtensionData.Name)"
                                                ColumnWidths = 25, 25, 25, 25
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VssSecurity | Sort-Object 'Virtual Switch' | Table @TableParams
                                        }
                                        #endregion Virtual Switch Security Policy
                                    }
                                    #endregion ESXi Host Virtual Switch Security Policy

                                    #region ESXi Host Virtual Switch Traffic Shaping Policy
                                    Section -Style Heading5 'Virtual Switch Traffic Shaping' {
                                        $VssTrafficShapingPolicy = foreach ($VSSwitch in $VSSwitches) {
                                            [PSCustomObject]@{
                                                'Virtual Switch' = $VSSwitch.Name
                                                'Status' = Switch ($VSSwitch.ExtensionData.Spec.Policy.ShapingPolicy.Enabled) {
                                                    $True { 'Enabled' }
                                                    $False { 'Disabled' }
                                                }
                                                'Average Bandwidth (kbit/s)' = $VSSwitch.ExtensionData.Spec.Policy.ShapingPolicy.AverageBandwidth
                                                'Peak Bandwidth (kbit/s)' = $VSSwitch.ExtensionData.Spec.Policy.ShapingPolicy.PeakBandwidth
                                                'Burst Size (KB)' = $VSSwitch.ExtensionData.Spec.Policy.ShapingPolicy.BurstSize
                                            }
                                        }
                                        $TableParams = @{
                                            Name = "Virtual Switch Traffic Shaping Policy - $($VMHost.ExtensionData.Name)"
                                            ColumnWidths = 25, 15, 20, 20, 20
                                        }
                                        if ($Report.ShowTableCaptions) {
                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                        }
                                        $VssTrafficShapingPolicy | Sort-Object 'Virtual Switch' | Table @TableParams
                                    }
                                    #endregion ESXi Host Virtual Switch Traffic Shaping Policy

                                    #region ESXi Host Virtual Switch Teaming & Failover
                                    $VssNicTeamingPolicy = $VSSwitches | Get-NicTeamingPolicy
                                    if ($VssNicTeamingPolicy) {
                                        #region Virtual Switch Teaming & Failover Section
                                        Section -Style Heading5 'Virtual Switch Teaming & Failover' {
                                            $VssNicTeaming = foreach ($VssNicTeam in $VssNicTeamingPolicy) {
                                                [PSCustomObject]@{
                                                    'Virtual Switch' = $VssNicTeam.VirtualSwitch
                                                    'Load Balancing' = Switch ($VssNicTeam.LoadBalancingPolicy) {
                                                        'LoadbalanceSrcId' { 'Route based on the originating port ID' }
                                                        'LoadbalanceSrcMac' { 'Route based on source MAC hash' }
                                                        'LoadbalanceIP' { 'Route based on IP hash' }
                                                        'ExplicitFailover' { 'Explicit Failover' }
                                                        default { $VssNicTeam.LoadBalancingPolicy }
                                                    }
                                                    'Network Failure Detection' = Switch ($VssNicTeam.NetworkFailoverDetectionPolicy) {
                                                        'LinkStatus' { 'Link status only' }
                                                        'BeaconProbing' { 'Beacon probing' }
                                                        default { $VssNicTeam.NetworkFailoverDetectionPolicy }
                                                    }
                                                    'Notify Switches' = Switch ($VssNicTeam.NotifySwitches) {
                                                        $true { 'Yes' }
                                                        $false { 'No' }
                                                    }
                                                    'Failback' = Switch ($VssNicTeam.FailbackEnabled) {
                                                        $true { 'Yes' }
                                                        $false { 'No' }
                                                    }
                                                    'Active NICs' = ($VssNicTeam.ActiveNic | Sort-Object) -join [Environment]::NewLine
                                                    'Standby NICs' = ($VssNicTeam.StandbyNic | Sort-Object) -join [Environment]::NewLine
                                                    'Unused NICs' = ($VssNicTeam.UnusedNic | Sort-Object) -join [Environment]::NewLine
                                                }
                                            }
                                            $TableParams = @{
                                                Name = "Virtual Switch Teaming & Failover - $($VMHost.ExtensionData.Name)"
                                                ColumnWidths = 20, 17, 12, 11, 10, 10, 10, 10
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VssNicTeaming | Sort-Object 'Virtual Switch' | Table @TableParams
                                        }
                                        #endregion Virtual Switch Teaming & Failover Section
                                    }
                                    #endregion ESXi Host Virtual Switch Teaming & Failover

                                    #region ESXi Host Virtual Switch Port Groups
                                    $VssPortgroups = $VSSwitches | Get-VirtualPortGroup -Standard
                                    if ($VssPortgroups) {
                                        Section -Style Heading5 'Virtual Switch Port Groups' {
                                            $VssPortgroups = foreach ($VssPortgroup in $VssPortgroups) {
                                                [PSCustomObject]@{
                                                    'Port Group' = $VssPortgroup.Name
                                                    'VLAN ID' = $VssPortgroup.VLanId
                                                    'Virtual Switch' = $VssPortgroup.VirtualSwitchName
                                                    '# of VMs' = ($VssPortgroup | Get-VM).Count
                                                }
                                            }
                                            $TableParams = @{
                                                Name = "Virtual Switch Port Group Information - $($VMHost.ExtensionData.Name)"
                                                ColumnWidths = 40, 10, 40, 10
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VssPortgroups | Sort-Object 'Port Group', 'VLAN ID', 'Virtual Switch' | Table @TableParams
                                        }
                                        #endregion ESXi Host Virtual Switch Port Groups

                                        #region ESXi Host Virtual Switch Port Group Security Policy
                                        $VssPortgroupSecurity = $VSSwitches | Get-VirtualPortGroup | Get-SecurityPolicy
                                        if ($VssPortgroupSecurity) {
                                            #region Virtual Port Group Security Policy Section
                                            Section -Style Heading5 'Virtual Switch Port Group Security' {
                                                $VssPortgroupSecurity = foreach ($VssPortgroupSec in $VssPortgroupSecurity) {
                                                    [PSCustomObject]@{
                                                        'Port Group' = $VssPortgroupSec.VirtualPortGroup
                                                        'Virtual Switch' = $VssPortgroupSec.virtualportgroup.virtualswitchname
                                                        'Promiscuous Mode' = Switch ($VssPortgroupSec.AllowPromiscuous) {
                                                            $true { 'Accept' }
                                                            $false { 'Reject' }
                                                        }
                                                        'MAC Changes' = Switch ($VssPortgroupSec.MacChanges) {
                                                            $true { 'Accept' }
                                                            $false { 'Reject' }
                                                        }
                                                        'Forged Transmits' = Switch ($VssPortgroupSec.ForgedTransmits) {
                                                            $true { 'Accept' }
                                                            $false { 'Reject' }
                                                        }
                                                    }
                                                }
                                                $TableParams = @{
                                                    Name = "Virtual Switch Port Group Security Policy - $($VMHost.ExtensionData.Name)"
                                                    ColumnWidths = 27, 25, 16, 16, 16
                                                }
                                                if ($Report.ShowTableCaptions) {
                                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                                }
                                                $VssPortgroupSecurity | Sort-Object 'Port Group', 'Virtual Switch' | Table @TableParams
                                            }
                                            #endregion Virtual Port Group Security Policy Section
                                        }
                                        #endregion ESXi Host Virtual Switch Port Group Security Policy

                                        #region ESXi Host Virtual Switch Port Group Traffic Shaping Policy
                                        Section -Style Heading5 'Virtual Switch Port Group Traffic Shaping' {
                                            $VssPortgroupTrafficShapingPolicy = foreach ($VssPortgroup in $VssPortgroups) {
                                                [PSCustomObject]@{
                                                    'Port Group' = $VssPortgroup.Name
                                                    'Virtual Switch' = $VssPortgroup.VirtualSwitchName
                                                    'Status' = Switch ($VssPortgroup.ExtensionData.Spec.Policy.ShapingPolicy.Enabled) {
                                                        $True { 'Enabled' }
                                                        $False { 'Disabled' }
                                                        $null { 'Inherited' }
                                                    }
                                                    'Average Bandwidth (kbit/s)' = $VssPortgroup.ExtensionData.Spec.Policy.ShapingPolicy.AverageBandwidth
                                                    'Peak Bandwidth (kbit/s)' = $VssPortgroup.ExtensionData.Spec.Policy.ShapingPolicy.PeakBandwidth
                                                    'Burst Size (KB)' = $VssPortgroup.ExtensionData.Spec.Policy.ShapingPolicy.BurstSize
                                                }
                                            }
                                            $TableParams = @{
                                                Name = "Virtual Switch Port Group Traffic Shaping Policy - $($VMHost.ExtensionData.Name)"
                                                ColumnWidths = 19, 19, 11, 17, 17, 17
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VssPortgroupTrafficShapingPolicy | Sort-Object 'Port Group', 'Virtual Switch' | Table @TableParams
                                        }
                                        #endregion ESXi Host Virtual Switch Port Group Traffic Shaping Policy

                                        #region ESXi Host Virtual Switch Port Group Teaming & Failover
                                        $VssPortgroupNicTeaming = $VSSwitches | Get-VirtualPortGroup | Get-NicTeamingPolicy
                                        if ($VssPortgroupNicTeaming) {
                                            #region Virtual Switch Port Group Teaming & Failover Section
                                            Section -Style Heading5 'Virtual Switch Port Group Teaming & Failover' {
                                                $VssPortgroupNicTeaming = foreach ($VssPortgroupNicTeam in $VssPortgroupNicTeaming) {
                                                    [PSCustomObject]@{
                                                        'Port Group' = $VssPortgroupNicTeam.VirtualPortGroup
                                                        'Virtual Switch' = $VssPortgroupNicTeam.virtualportgroup.virtualswitchname
                                                        'Load Balancing' = Switch ($VssPortgroupNicTeam.LoadBalancingPolicy) {
                                                            'LoadbalanceSrcId' { 'Route based on the originating port ID' }
                                                            'LoadbalanceSrcMac' { 'Route based on source MAC hash' }
                                                            'LoadbalanceIP' { 'Route based on IP hash' }
                                                            'ExplicitFailover' { 'Explicit Failover' }
                                                            default { $VssPortgroupNicTeam.LoadBalancingPolicy }
                                                        }
                                                        'Network Failure Detection' = Switch ($VssPortgroupNicTeam.NetworkFailoverDetectionPolicy) {
                                                            'LinkStatus' { 'Link status only' }
                                                            'BeaconProbing' { 'Beacon probing' }
                                                            default { $VssPortgroupNicTeam.NetworkFailoverDetectionPolicy }
                                                        }
                                                        'Notify Switches' = Switch ($VssPortgroupNicTeam.NotifySwitches) {
                                                            $true { 'Yes' }
                                                            $false { 'No' }
                                                        }
                                                        'Failback' = Switch ($VssPortgroupNicTeam.FailbackEnabled) {
                                                            $true { 'Yes' }
                                                            $false { 'No' }
                                                        }
                                                        'Active NICs' = ($VssPortgroupNicTeam.ActiveNic | Sort-Object) -join [Environment]::NewLine
                                                        'Standby NICs' = ($VssPortgroupNicTeam.StandbyNic | Sort-Object) -join [Environment]::NewLine
                                                        'Unused NICs' = ($VssPortgroupNicTeam.UnusedNic | Sort-Object) -join [Environment]::NewLine
                                                    }
                                                }
                                                $TableParams = @{
                                                    Name = "Virtual Switch Port Group Teaming & Failover - $($VMHost.ExtensionData.Name)"
                                                    ColumnWidths = 12, 11, 11, 11, 11, 11, 11, 11, 11
                                                }
                                                if ($Report.ShowTableCaptions) {
                                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                                }
                                                $VssPortgroupNicTeaming | Sort-Object 'Port Group', 'Virtual Switch' | Table @TableParams
                                            }
                                            #endregion Virtual Switch Port Group Teaming & Failover Section
                                        }
                                        #endregion ESXi Host Virtual Switch Port Group Teaming & Failover
                                    }
                                }
                                #endregion Section Standard Virtual Switches
                            }
                            #endregion ESXi Host Standard Virtual Switches

                            #region Distributed Virtual Switch Section
                            # Create Distributed Switch Section if they exist
                            $VDSwitches = Get-VDSwitch -Server $ESXi
                            if ($VDSwitches) {
                                Section -Style Heading3 'Distributed Virtual Switches' {
                                    #region Distributed Virtual Switch Advanced Summary
                                    if ($InfoLevel.Network -le 2) {
                                        $VDSInfo = foreach ($VDS in $VDSwitches) {
                                            [PSCustomObject]@{
                                                'Distributed Switch' = $VDS.Name
                                                'Number of Ports' = $VDS.NumPorts
                                                'Number of Port Groups' = ($VDS.ExtensionData.Summary.PortGroupName).Count
                                                'MTU' = $VDS.Mtu
                                                'Discovery Protocol Type' = $VDS.LinkDiscoveryProtocol
                                                'Discovery Protocol Operation' = $VDS.LinkDiscoveryProtocolOperation
                                            }
                                        }
                                        $TableParams = @{
                                            Name = "Distributed Switch Information - $($VMHost.ExtensionData.Name)"
                                            ColumnWidths = 25, 15, 15, 15, 15, 15
                                        }
                                        if ($Report.ShowTableCaptions) {
                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                        }
                                        $VDSInfo | Table @TableParams
                                    }
                                    #endregion Distributed Switch Advanced Summary

                                    #region Distributed Switch Detailed Information
                                    if ($InfoLevel.Network -ge 3) {
                                        # TODO: LACP, NetFlow, NIOC
                                        foreach ($VDS in ($VDSwitches)) {
                                            $VdsVmCount = ($VDS | Get-VM).Count
                                            #region VDS Section
                                            Section -Style Heading4 $VDS {
                                                #region Distributed Switch General Properties
                                                $VDSwitchDetail = [PSCustomObject]@{
                                                    'Distributed Switch' = $VDS.Name
                                                    'ID' = $VDS.Id
                                                    'Number of Ports' = $VDS.NumPorts
                                                    'Number of Port Groups' = ($VDS.ExtensionData.Summary.PortGroupName).Count
                                                    'Number of VMs' = $VdsVmCount
                                                    'MTU' = $VDS.Mtu
                                                    'Network I/O Control' = Switch ($VDS.ExtensionData.Config.NetworkResourceManagementEnabled) {
                                                        $true { 'Enabled' }
                                                        $false { 'Disabled' }
                                                    }
                                                    'Discovery Protocol' = $VDS.LinkDiscoveryProtocol
                                                    'Discovery Protocol Operation' = $VDS.LinkDiscoveryProtocolOperation
                                                }
                                                # TODO: Fix this, incorrect reporting!
                                                #region Network Advanced Detail Information
                                                if ($InfoLevel.Network -ge 4) {
                                                    $VDSwitchVMs = $VDS | Get-VM | Sort-Object
                                                    Add-Member -InputObject $VDSwitchDetail -MemberType NoteProperty -Name 'Virtual Machines' -Value ($VDSwitchVMs.Name -join ', ')
                                                }
                                                #endregion Network Advanced Detail Information
                                                $TableParams = @{
                                                    Name = "$VDS Distributed Switch General Properties - $($VMHost.ExtensionData.Name)"
                                                    List = $true
                                                    ColumnWidths = 50, 50
                                                }
                                                if ($Report.ShowTableCaptions) {
                                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                                }
                                                $VDSwitchDetail | Table @TableParams
                                                #endregion Distributed Switch General Properties

                                                #region Distributed Switch Uplink Ports
                                                $VdsUplinks = $VDS | Get-VDPortgroup | Where-Object { $_.IsUplink -eq $true } | Get-VDPort
                                                if ($VdsUplinks) {
                                                    Section -Style Heading4 'Distributed Switch Uplink Ports' {
                                                        $VdsUplinkDetail = foreach ($VdsUplink in $VdsUplinks) {
                                                            [PSCustomObject]@{
                                                                'Distributed Switch' = $VdsUplink.Switch
                                                                'Uplink Name' = $VdsUplink.Name
                                                                'Physical Network Adapter' = $VdsUplink.ConnectedEntity
                                                                'Uplink Port Group' = $VdsUplink.Portgroup
                                                            }
                                                        }
                                                        $TableParams = @{
                                                            Name = "$VDS Distributed Switch Uplink Ports - $($VMHost.ExtensionData.Name)"
                                                            ColumnWidths = 30, 20, 20, 30
                                                        }
                                                        if ($Report.ShowTableCaptions) {
                                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                                        }
                                                        $VdsUplinkDetail | Sort-Object 'Distributed Switch', 'Uplink Name' | Table @TableParams
                                                    }
                                                }
                                                #endregion Distributed Virtual Switch Uplink Ports

                                                #region Distributed Switch Port Groups
                                                $VDSPortgroups = $VDS | Get-VDPortgroup
                                                if ($VDSPortgroups) {
                                                    Section -Style Heading4 'Distributed Switch Port Groups' {
                                                        $VDSPortgroupDetail = foreach ($VDSPortgroup in $VDSPortgroups) {
                                                            [PSCustomObject]@{
                                                                'Port Group' = $VDSPortgroup.Name
                                                                'Distributed Switch' = $VDSPortgroup.VDSwitch.Name
                                                                'VLAN Configuration' = Switch ($VDSPortgroup.VlanConfiguration) {
                                                                    $null { '--' }
                                                                    default { $VDSPortgroup.VlanConfiguration }
                                                                }
                                                                'Port Binding' = $VDSPortgroup.PortBinding
                                                            }
                                                        }
                                                        $TableParams = @{
                                                            Name = "$VDS Distributed Switch Port Groups - $($VMHost.ExtensionData.Name)"
                                                            ColumnWidths = 35, 35, 15, 15
                                                        }
                                                        if ($Report.ShowTableCaptions) {
                                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                                        }
                                                        $VDSPortgroupDetail | Sort-Object 'Port Group' | Table @TableParams
                                                    }
                                                }
                                                #endregion Distributed Switch Port Groups

                                                #region Distributed Switch Private VLANs
                                                $VDSwitchPrivateVLANs = $VDS | Get-VDSwitchPrivateVlan
                                                if ($VDSwitchPrivateVLANs) {
                                                    Section -Style Heading4 'Distributed Switch Private VLANs' {
                                                        $VDSPvlan = foreach ($VDSwitchPrivateVLAN in $VDSwitchPrivateVLANs) {
                                                            [PSCustomObject]@{
                                                                'Primary VLAN ID' = $VDSwitchPrivateVLAN.PrimaryVlanId
                                                                'Private VLAN Type' = $VDSwitchPrivateVLAN.PrivateVlanType
                                                                'Secondary VLAN ID' = $VDSwitchPrivateVLAN.SecondaryVlanId
                                                            }
                                                        }
                                                        $TableParams = @{
                                                            Name = "$VDS Distributed Switch Private VLANs - $($VMHost.ExtensionData.Name)"
                                                            ColumnWidths = 33, 34, 33
                                                        }
                                                        if ($Report.ShowTableCaptions) {
                                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                                        }
                                                        $VDSPvlan | Sort-Object 'Primary VLAN ID', 'Secondary VLAN ID' | Table @TableParams
                                                    }
                                                }
                                                #endregion Distributed Switch Private VLANs
                                            }
                                            #endregion VDS Section
                                        }
                                    }
                                    #endregion Distributed Virtual Switch Detailed Information
                                }
                            }
                            #endregion Distributed Virtual Switch Section
                        }
                    }
                    #endregion ESXi Host Network Section

                    #region ESXi Host Security Section
                    if ($InfoLevel.VMHost -ge 1) {
                        Section -Style Heading2 'Security' {
                            Paragraph "The following section details the host security configuration for $($VMHost.ExtensionData.Name)."
                            #region ESXi Host Lockdown Mode
                            if ($VMHost.ExtensionData.Config.LockdownMode -ne $null) {
                                Section -Style Heading3 'Lockdown Mode' {
                                    $LockdownMode = [PSCustomObject]@{
                                        'Lockdown Mode' = Switch ($VMHost.ExtensionData.Config.LockdownMode) {
                                            'lockdownDisabled' { 'Disabled' }
                                            'lockdownNormal' { 'Enabled (Normal)' }
                                            'lockdownStrict' { 'Enabled (Strict)' }
                                            default { $VMHost.ExtensionData.Config.LockdownMode }
                                        }
                                    }
                                    if ($Healthcheck.VMHost.LockdownMode) {
                                        $LockdownMode | Where-Object { $_.'Lockdown Mode' -eq 'Disabled' } | Set-Style -Style Warning -Property 'Lockdown Mode'
                                    }
                                    $TableParams = @{
                                        Name = "Lockdown Mode - $($VMHost.ExtensionData.Name)"
                                        List = $true
                                        ColumnWidths = 50, 50
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $LockdownMode | Table @TableParams
                                }
                            }
                            #endregion ESXi Host Lockdown Mode

                            #region ESXi Host Services
                            Section -Style Heading3 'Services' {
                                $VMHostServices = $VMHost | Get-VMHostService
                                $Services = foreach ($VMHostService in $VMHostServices) {
                                    [PSCustomObject]@{
                                        'Service' = $VMHostService.Label
                                        'Daemon' = Switch ($VMHostService.Running) {
                                            $true { 'Running' }
                                            $false { 'Stopped' }
                                        }
                                        'Startup Policy' = Switch ($VMHostService.Policy) {
                                            'automatic' { 'Start and stop with port usage' }
                                            'on' { 'Start and stop with host' }
                                            'off' { 'Start and stop manually' }
                                            default { $VMHostService.Policy }
                                        }
                                    }
                                }
                                if ($Healthcheck.VMHost.NTP) {
                                    $Services | Where-Object { ($_.'Service' -eq 'NTP Daemon') -and ($_.Daemon -eq 'Stopped') } | Set-Style -Style Critical -Property 'Daemon'
                                    $Services | Where-Object { ($_.'Service' -eq 'NTP Daemon') -and ($_.'Startup Policy' -ne 'Start and stop with host') } | Set-Style -Style Critical -Property 'Startup Policy'
                                }
                                if ($Healthcheck.VMHost.SSH) {
                                    $Services | Where-Object { ($_.'Service' -eq 'SSH') -and ($_.Daemon -eq 'Running') } | Set-Style -Style Warning -Property 'Daemon'
                                    $Services | Where-Object { ($_.'Service' -eq 'SSH') -and ($_.'Startup Policy' -ne 'Start and stop manually') } | Set-Style -Style Warning -Property 'Startup Policy'
                                }
                                if ($Healthcheck.VMHost.ESXiShell) {
                                    $Services | Where-Object { ($_.'Service' -eq 'ESXi Shell') -and ($_.Daemon -eq 'Running') } | Set-Style -Style Warning -Property 'Daemon'
                                    $Services | Where-Object { ($_.'Service' -eq 'ESXi Shell') -and ($_.'Startup Policy' -ne 'Start and stop manually') } | Set-Style -Style Warning -Property 'Startup Policy'
                                }
                                $TableParams = @{
                                    Name = "Services - $($VMHost.ExtensionData.Name)"
                                    ColumnWidths = 40, 20, 40
                                }
                                if ($Report.ShowTableCaptions) {
                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                }
                                $Services | Sort-Object 'Service' | Table @TableParams
                            }
                            #endregion ESXi Host Services

                            #region ESXi Host Advanced Detail Information
                            if ($InfoLevel.VMHost -ge 4) {
                                #region ESXi Host Firewall
                                $VMHostFirewallExceptions = $VMHost | Get-VMHostFirewallException
                                if ($VMHostFirewallExceptions) {
                                    #region Friewall Section
                                    Section -Style Heading3 'Firewall' {
                                        $VMHostFirewall = foreach ($VMHostFirewallException in $VMHostFirewallExceptions) {
                                            [PScustomObject]@{
                                                'Service' = $VMHostFirewallException.Name
                                                'Status' = Switch ($VMHostFirewallException.Enabled) {
                                                    $true { 'Enabled' }
                                                    $false { 'Disabled' }
                                                }
                                                'Incoming Ports' = $VMHostFirewallException.IncomingPorts
                                                'Outgoing Ports' = $VMHostFirewallException.OutgoingPorts
                                                'Protocols' = $VMHostFirewallException.Protocols
                                                'Daemon' = Switch ($VMHostFirewallException.ServiceRunning) {
                                                    $true { 'Running' }
                                                    $false { 'Stopped' }
                                                    $null { 'N/A' }
                                                    default { $VMHostFirewallException.ServiceRunning }
                                                }
                                            }
                                        }
                                        $TableParams = @{
                                            Name = "Firewall Configuration - $($VMHost.ExtensionData.Name)"
                                            ColumnWidths = 22, 12, 21, 21, 12, 12
                                        }
                                        if ($Report.ShowTableCaptions) {
                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                        }
                                        $VMHostFirewall | Sort-Object 'Service' | Table @TableParams
                                    }
                                    #endregion Friewall Section
                                }
                                #endregion ESXi Host Firewall

                                #region ESXi Host Authentication
                                $AuthServices = $VMHost | Get-VMHostAuthentication
                                if ($AuthServices.DomainMembershipStatus) {
                                    Section -Style Heading3 'Authentication Services' {
                                        $AuthServices = $AuthServices | Select-Object Domain, @{L = 'Domain Membership'; E = { $_.DomainMembershipStatus } }, @{L = 'Trusted Domains'; E = { $_.TrustedDomains } }
                                        $TableParams = @{
                                            Name = "Authentication Services - $($VMHost.ExtensionData.Name)"
                                            ColumnWidths  = 25, 25, 50
                                        }
                                        if ($Report.ShowTableCaptions) {
                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                        }
                                        $AuthServices | Table @TableParams
                                    }
                                }
                                #endregion ESXi Host Authentication
                            }
                            #endregion ESXi Host Advanced Detail Information
                        }
                    }
                    #endregion ESXi Host Security Section

                    #region Virtual Machine Section
                    Write-PScriboMessage "VM InfoLevel set at $($InfoLevel.VM)."
                    if ($InfoLevel.VM -ge 1) {
                        if ($VMs) {
                            Section -Style Heading2 'Virtual Machines' {
                                Paragraph "The following section details the configuration of virtual machines managed by $($VMHost.ExtensionData.Name)."
                                #region Virtual Machine Summary Information
                                if ($InfoLevel.VM -eq 1) {
                                    BlankLine
                                    $VMSummary = [PSCustomObject]@{
                                        'Total VMs' = $VMs.Count
                                        'Total vCPUs' = ($VMs | Measure-Object -Property NumCpu -Sum).Sum
                                        'Total Memory' = "$([math]::Round(($VMs | Measure-Object -Property MemoryGB -Sum).Sum, 2)) GB"
                                        'Total Provisioned Space' = "$([math]::Round(($VMs | Measure-Object -Property ProvisionedSpaceGB -Sum).Sum, 2)) GB"
                                        'Total Used Space' = "$([math]::Round(($VMs | Measure-Object -Property UsedSpaceGB -Sum).Sum, 2)) GB"
                                        'VMs Powered On' = ($VMs | Where-Object { $_.PowerState -eq 'PoweredOn' }).Count
                                        'VMs Powered Off' = ($VMs | Where-Object { $_.PowerState -eq 'PoweredOff' }).Count
                                        'VMs Suspended' = ($VMs | Where-Object { $_.PowerState -eq 'Suspended' }).Count
                                        'VMs with Snapshots' = ($VMs | Where-Object { $_.ExtensionData.Snapshot }).Count
                                        'Guest Operating System Types' = (($VMs | Get-View).Summary.Config.GuestFullName | Select-Object -Unique).Count
                                        'VM Tools OK' = ($VMs | Where-Object { $_.ExtensionData.Guest.ToolsStatus -eq 'toolsOK' }).Count
                                        'VM Tools Old' = ($VMs | Where-Object { $_.ExtensionData.Guest.ToolsStatus -eq 'toolsOld' }).Count
                                        'VM Tools Not Running' = ($VMs | Where-Object { $_.ExtensionData.Guest.ToolsStatus -eq 'toolsNotRunning' }).Count
                                        'VM Tools Not Installed' = ($VMs | Where-Object { $_.ExtensionData.Guest.ToolsStatus -eq 'toolsNotInstalled' }).Count
                                    }
                                    $TableParams = @{
                                        Name = "VM Summary - $($VMHost.ExtensionData.Name)"
                                        List = $true
                                        ColumnWidths  = 50, 50
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $VMSummary | Table @TableParams
                                }
                                #endregion Virtual Machine Summary Information

                                #region Virtual Machine Advanced Summary
                                if ($InfoLevel.VM -eq 2) {
                                    BlankLine
                                    $VMSnapshotList = $VMs.Extensiondata.Snapshot.RootSnapshotList
                                    $VMInfo = foreach ($VM in $VMs) {
                                        $VMView = $VM | Get-View
                                        [PSCustomObject]@{
                                            'Virtual Machine' = $VM.Name
                                            'Power State' = Switch ($VM.PowerState) {
                                                'PoweredOn' { 'On' }
                                                'PoweredOff' { 'Off' }
                                                default { $VM.PowerState }
                                            }
                                            'IP Address' = Switch ($VMView.Guest.IpAddress) {
                                                $null { '--' }
                                                default { $VMView.Guest.IpAddress }
                                            }
                                            'vCPUs' = $VM.NumCpu
                                            'Memory GB' = [math]::Round(($VM.MemoryGB), 0)
                                            'Provisioned GB' = [math]::Round(($VM.ProvisionedSpaceGB), 0)
                                            'Used GB' = [math]::Round(($VM.UsedSpaceGB), 0)
                                            'HW Version' = ($VM.HardwareVersion).Replace('vmx-', 'v')
                                            'VM Tools Status' = Switch ($VMView.Guest.ToolsStatus) {
                                                'toolsOld' { 'Old' }
                                                'toolsOK' { 'OK' }
                                                'toolsNotRunning' { 'Not Running' }
                                                'toolsNotInstalled' { 'Not Installed' }
                                                default { $VMView.Guest.ToolsStatus }
                                            }
                                        }
                                    }
                                    if ($Healthcheck.VM.VMToolsStatus) {
                                        $VMInfo | Where-Object { $_.'VM Tools Status' -ne 'OK' } | Set-Style -Style Warning -Property 'VM Tools Status'
                                    }
                                    if ($Healthcheck.VM.PowerState) {
                                        $VMInfo | Where-Object { $_.'Power State' -ne 'On' } | Set-Style -Style Warning -Property 'Power State'
                                    }
                                    $TableParams = @{
                                        Name = "VM Advanced Summary - $($VMHost.ExtensionData.Name)"
                                        ColumnWidths = 21, 8, 16, 9, 9, 9, 9, 9, 10
                                    }
                                    if ($Report.ShowTableCaptions) {
                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                    }
                                    $VMInfo | Table @TableParams

                                    #region VM Snapshot Information
                                    if ($VMSnapshotList -and $Options.ShowVMSnapshots) {
                                        Section -Style Heading3 'Snapshots' {
                                            $VMSnapshotInfo = foreach ($VMSnapshot in $VMSnapshotList) {
                                                [PSCustomObject]@{
                                                    'Virtual Machine' = $VMLookup."$($VMSnapshot.VM)"
                                                    'Snapshot Name' = $VMSnapshot.Name
                                                    'Description' = $VMSnapshot.Description
                                                    'Days Old' = ((Get-Date).ToUniversalTime() - $VMSnapshot.CreateTime).Days
                                                }
                                            }
                                            if ($Healthcheck.VM.VMSnapshots) {
                                                $VMSnapshotInfo | Where-Object { $_.'Days Old' -ge 7 } | Set-Style -Style Warning
                                                $VMSnapshotInfo | Where-Object { $_.'Days Old' -ge 14 } | Set-Style -Style Critical
                                            }
                                            $TableParams = @{
                                                Name = "VM Snapshot Information - $($VMHost.ExtensionData.Name)"
                                                ColumnWidths = 30, 30, 30, 10
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VMSnapshotInfo | Table @TableParams
                                        }
                                    }
                                    #endregion VM Snapshot Information
                                }
                                #endregion Virtual Machine Advanced Summary

                                #region Virtual Machine Detailed Information
                                if ($InfoLevel.VM -ge 3) {
                                    foreach ($VM in $VMs) {
                                        Section -Style Heading3 $VM.name {
                                            $VMUptime = @()
                                            $VMUptime = Get-Uptime -VM $VM
                                            $VMSpbmPolicy = $VMSpbmConfig | Where-Object { $_.entity -eq $vm }
                                            $VMView = $VM | Get-View
                                            $VMSnapshotList = $vmview.Snapshot.RootSnapshotList
                                            $VMDetail = [PSCustomObject]@{
                                                'Virtual Machine' = $VM.Name
                                                'ID' = $VM.Id
                                                'Operating System' = $VMView.Summary.Config.GuestFullName
                                                'Hardware Version' = ($VM.HardwareVersion).Replace('vmx-', 'v')
                                                'Power State' = Switch ($VM.PowerState) {
                                                    'PoweredOn' { 'On' }
                                                    'PoweredOff' { 'Off' }
                                                    default { $VM.PowerState }
                                                }
                                                'Connection State' = $TextInfo.ToTitleCase($VM.ExtensionData.Runtime.ConnectionState)
                                                'VM Tools Status' = Switch ($VMView.Guest.ToolsStatus) {
                                                    'toolsOld' { 'Old' }
                                                    'toolsOK' { 'OK' }
                                                    'toolsNotRunning' { 'Not Running' }
                                                    'toolsNotInstalled' { 'Not Installed' }
                                                    default { $VMView.Guest.ToolsStatus }
                                                }
                                                'Fault Tolerance State' = Switch ($VMView.Runtime.FaultToleranceState) {
                                                    'notConfigured' { 'Not Configured' }
                                                    'needsSecondary' { 'Needs Secondary' }
                                                    'running' { 'Running' }
                                                    'disabled' { 'Disabled' }
                                                    'starting' { 'Starting' }
                                                    'enabled' { 'Enabled' }
                                                    default { $VMview.Runtime.FaultToleranceState }
                                                }
                                                'vCPUs' = $VM.NumCpu
                                                'Cores per Socket' = $VM.CoresPerSocket
                                                'CPU Shares' = "$($VM.VMResourceConfiguration.CpuSharesLevel) / $($VM.VMResourceConfiguration.NumCpuShares)"
                                                'CPU Reservation' = $VM.VMResourceConfiguration.CpuReservationMhz
                                                'CPU Limit' = "$($VM.VMResourceConfiguration.CpuReservationMhz) MHz"
                                                'CPU Hot Add' = Switch ($VMView.Config.CpuHotAddEnabled) {
                                                    $true { 'Enabled' }
                                                    $false { 'Disabled' }
                                                }
                                                'CPU Hot Remove' = Switch ($VMView.Config.CpuHotRemoveEnabled) {
                                                    $true { 'Enabled' }
                                                    $false { 'Disabled' }
                                                }
                                                'Memory Allocation' = "$([math]::Round(($VM.memoryGB), 2)) GB"
                                                'Memory Shares' = "$($VM.VMResourceConfiguration.MemSharesLevel) / $($VM.VMResourceConfiguration.NumMemShares)"
                                                'Memory Hot Add' = Switch ($VMView.Config.MemoryHotAddEnabled) {
                                                    $true { 'Enabled' }
                                                    $false { 'Disabled' }
                                                }
                                                'vNICs' = $VMView.Summary.Config.NumEthernetCards
                                                'DNS Name' = if ($VMView.Guest.HostName) {
                                                    $VMView.Guest.HostName
                                                } else {
                                                    '--'
                                                }
                                                'Networks' = if ($VMView.Guest.Net.Network) {
                                                    (($VMView.Guest.Net | Where-Object { $_.Network -ne $null } | Select-Object Network | Sort-Object Network).Network -join ', ')
                                                } else {
                                                    '--'
                                                }
                                                'IP Address' = if ($VMView.Guest.Net.IpAddress) {
                                                    (($VMView.Guest.Net | Where-Object { ($_.Network -ne $null) -and ($_.IpAddress -ne $null) } | Select-Object IpAddress | Sort-Object IpAddress).IpAddress -join ', ')
                                                } else {
                                                    '--'
                                                }
                                                'MAC Address' = if ($VMView.Guest.Net.MacAddress) {
                                                    (($VMView.Guest.Net | Where-Object { $_.Network -ne $null } | Select-Object -Property MacAddress).MacAddress -join ', ')
                                                } else {
                                                    '--'
                                                }
                                                'vDisks' = $VMView.Summary.Config.NumVirtualDisks
                                                'Provisioned Space' = "$([math]::Round(($VM.ProvisionedSpaceGB), 2)) GB"
                                                'Used Space' = "$([math]::Round(($VM.UsedSpaceGB), 2)) GB"
                                                'Changed Block Tracking' = Switch ($VMView.Config.ChangeTrackingEnabled) {
                                                    $true { 'Enabled' }
                                                    $false { 'Disabled' }
                                                }
                                            }
                                            $MemberProps = @{
                                                'InputObject' = $VMDetail
                                                'MemberType' = 'NoteProperty'
                                            }
                                            #if ($VMView.Config.CreateDate) {
                                            # Add-Member @MemberProps -Name 'Creation Date' -Value ($VMView.Config.CreateDate).ToLocalTime()
                                            #}
                                            if ($VM.Notes) {
                                                Add-Member @MemberProps -Name 'Notes' -Value $VM.Notes
                                            }
                                            if ($VMView.Runtime.BootTime) {
                                                Add-Member @MemberProps -Name 'Boot Time' -Value ($VMView.Runtime.BootTime).ToLocalTime()
                                            }
                                            if ($VMUptime.UptimeDays) {
                                                Add-Member @MemberProps -Name 'Uptime Days' -Value $VMUptime.UptimeDays
                                            }

                                            #region VM Health Checks
                                            if ($Healthcheck.VM.VMToolsStatus) {
                                                $VMDetail | Where-Object { $_.'VM Tools Status' -ne 'OK' } | Set-Style -Style Warning -Property 'VM Tools Status'
                                            }
                                            if ($Healthcheck.VM.PowerState) {
                                                $VMDetail | Where-Object { $_.'Power State' -ne 'On' } | Set-Style -Style Warning -Property 'Power State'
                                            }
                                            if ($Healthcheck.VM.ConnectionState) {
                                                $VMDetail | Where-Object { $_.'Connection State' -ne 'Connected' } | Set-Style -Style Critical -Property 'Connection State'
                                            }
                                            if ($Healthcheck.VM.CpuHotAdd) {
                                                $VMDetail | Where-Object { $_.'CPU Hot Add' -eq 'Enabled' } | Set-Style -Style Warning -Property 'CPU Hot Add'
                                            }
                                            if ($Healthcheck.VM.CpuHotRemove) {
                                                $VMDetail | Where-Object { $_.'CPU Hot Remove' -eq 'Enabled' } | Set-Style -Style Warning -Property 'CPU Hot Remove'
                                            }
                                            if ($Healthcheck.VM.MemoryHotAdd) {
                                                $VMDetail | Where-Object { $_.'Memory Hot Add' -eq 'Enabled' } | Set-Style -Style Warning -Property 'Memory Hot Add'
                                            }
                                            if ($Healthcheck.VM.ChangeBlockTracking) {
                                                $VMDetail | Where-Object { $_.'Changed Block Tracking' -eq 'Disabled' } | Set-Style -Style Warning -Property 'Changed Block Tracking'
                                            }
                                            #endregion VM Health Checks
                                            $TableParams = @{
                                                Name = "$($VM.Name) VM Configuration - $($VMHost.ExtensionData.Name)"
                                                List = $true
                                                ColumnWidths = 50, 50
                                            }
                                            if ($Report.ShowTableCaptions) {
                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                            }
                                            $VMDetail | Table @TableParams

                                            if ($InfoLevel.VM -ge 4) {
                                                $VMnics = $VM.Guest.Nics | Where-Object { $_.Device -ne $null } | Sort-Object Device
                                                $VMHdds = $VMHardDisks | Where-Object { $_.ParentId -eq $VM.Id } | Sort-Object Name
                                                $SCSIControllers = $VMView.Config.Hardware.Device | Where-Object { $_.DeviceInfo.Label -match "SCSI Controller" }
                                                $VMGuestVols = $VM.Guest.Disks | Sort-Object Path
                                                if ($VMnics) {
                                                    Section -Style Heading4 "Network Adapters" {
                                                        $VMnicInfo = foreach ($VMnic in $VMnics) {
                                                            [PSCustomObject]@{
                                                                'Adapter' = $VMnic.Device
                                                                'Connected' = $VMnic.Connected
                                                                'Network Name' = Switch -wildcard ($VMnic.Device.NetworkName) {
                                                                    'dvportgroup*' { $VDPortgroupLookup."$($VMnic.Device.NetworkName)" }
                                                                    default { $VMnic.Device.NetworkName }
                                                                }
                                                                'Adapter Type' = $VMnic.Device.Type
                                                                'IP Address' = $VMnic.IpAddress -join [Environment]::NewLine
                                                                'MAC Address' = $VMnic.Device.MacAddress
                                                            }
                                                        }
                                                        $TableParams = @{
                                                            Name = "$($VM.Name) Network Adapters - $($VMHost.ExtensionData.Name)"
                                                            ColumnWidths = 20, 12, 16, 12, 20, 20
                                                        }
                                                        if ($Report.ShowTableCaptions) {
                                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                                        }
                                                        $VMnicInfo | Table @TableParams
                                                    }
                                                }
                                                if ($SCSIControllers) {
                                                    Section -Style Heading4 "SCSI Controllers" {
                                                        $VMScsiControllers = foreach ($VMSCSIController in $SCSIControllers) {
                                                            [PSCustomObject]@{
                                                                'Device' = $VMSCSIController.DeviceInfo.Label
                                                                'Controller Type' = $VMSCSIController.DeviceInfo.Summary
                                                                'Bus Sharing' = Switch ($VMSCSIController.SharedBus) {
                                                                    'noSharing' { 'None' }
                                                                    default { $VMSCSIController.SharedBus }
                                                                }
                                                            }
                                                        }
                                                        $TableParams = @{
                                                            Name = "$($VM.Name) SCSI Controllers - $($VMHost.ExtensionData.Name)"
                                                            ColumnWidths = 33, 34, 33
                                                        }
                                                        if ($Report.ShowTableCaptions) {
                                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                                        }
                                                        $VMScsiControllers | Sort-Object 'Device' | Table @TableParams
                                                    }
                                                }
                                                if ($VMHdds) {
                                                    Section -Style Heading4 "Hard Disks" {
                                                        If ($InfoLevel.VM -eq 4) {
                                                            $VMHardDiskInfo = foreach ($VMHdd in $VMHdds) {
                                                                $SCSIDevice = $VMView.Config.Hardware.Device | Where-Object { $_.Key -eq $VMHdd.ExtensionData.Key -and $_.Backing.FileName -eq $VMHdd.FileName }
                                                                $SCSIController = $SCSIControllers | Where-Object { $SCSIDevice.ControllerKey -eq $_.Key }
                                                                [PSCustomObject]@{
                                                                    'Disk' = $VMHdd.Name
                                                                    'Datastore' = $VMHdd.FileName.Substring($VMHdd.Filename.IndexOf("[") + 1, $VMHdd.Filename.IndexOf("]") - 1)
                                                                    'Capacity' = "$([math]::Round(($VMHdd.CapacityGB), 2)) GB"
                                                                    'Disk Provisioning' = Switch ($VMHdd.StorageFormat) {
                                                                        'EagerZeroedThick' { 'Thick Eager Zeroed' }
                                                                        'LazyZeroedThick' { 'Thick Lazy Zeroed' }
                                                                        $null { '--' }
                                                                        default { $VMHdd.StorageFormat }
                                                                    }
                                                                    'Disk Type' = Switch ($VMHdd.DiskType) {
                                                                        'RawPhysical' { 'Physical RDM' }
                                                                        'RawVirtual' { "Virtual RDM" }
                                                                        'Flat' { 'VMDK' }
                                                                        default { $VMHdd.DiskType }
                                                                    }
                                                                    'Disk Mode' = Switch ($VMHdd.Persistence) {
                                                                        'IndependentPersistent' { 'Independent - Persistent' }
                                                                        'IndependentNonPersistent' { 'Independent - Nonpersistent' }
                                                                        'Persistent' { 'Dependent' }
                                                                        default { $VMHdd.Persistence }
                                                                    }
                                                                }
                                                            }
                                                            $TableParams = @{
                                                                Name = "$($VM.Name) Hard Disks - $($VMHost.ExtensionData.Name)"
                                                                ColumnWidths = 15, 25, 15, 15, 15, 15
                                                            }
                                                            if ($Report.ShowTableCaptions) {
                                                                $TableParams['Caption'] = "- $($TableParams.Name)"
                                                            }
                                                            $VMHardDiskInfo | Table @TableParams
                                                        } else {
                                                            foreach ($VMHdd in $VMHdds) {
                                                                Section -Style Heading4 "$($VMHdd.Name)" {
                                                                    $SCSIDevice = $VMView.Config.Hardware.Device | Where-Object { $_.Key -eq $VMHdd.ExtensionData.Key -and $_.Backing.FileName -eq $VMHdd.FileName }
                                                                    $SCSIController = $SCSIControllers | Where-Object { $SCSIDevice.ControllerKey -eq $_.Key }
                                                                    $VMHardDiskInfo = [PSCustomObject]@{
                                                                        'Datastore' = $VMHdd.FileName.Substring($VMHdd.Filename.IndexOf("[") + 1, $VMHdd.Filename.IndexOf("]") - 1)
                                                                        'Capacity' = "$([math]::Round(($VMHdd.CapacityGB), 2)) GB"
                                                                        'Disk Path' = $VMHdd.Filename.Substring($VMHdd.Filename.IndexOf("]") + 2)
                                                                        'Disk Shares' = "$($TextInfo.ToTitleCase($VMHdd.ExtensionData.Shares.Level)) / $($VMHdd.ExtensionData.Shares.Shares)"
                                                                        'Disk Limit IOPs' = Switch ($VMHdd.ExtensionData.StorageIOAllocation.Limit) {
                                                                            '-1' { 'Unlimited' }
                                                                            default { $VMHdd.ExtensionData.StorageIOAllocation.Limit }
                                                                        }
                                                                        'Disk Provisioning' = Switch ($VMHdd.StorageFormat) {
                                                                            'EagerZeroedThick' { 'Thick Eager Zeroed' }
                                                                            'LazyZeroedThick' { 'Thick Lazy Zeroed' }
                                                                            $null { '--' }
                                                                            default { $VMHdd.StorageFormat }
                                                                        }
                                                                        'Disk Type' = Switch ($VMHdd.DiskType) {
                                                                            'RawPhysical' { 'Physical RDM' }
                                                                            'RawVirtual' { "Virtual RDM" }
                                                                            'Flat' { 'VMDK' }
                                                                            default { $VMHdd.DiskType }
                                                                        }
                                                                        'Disk Mode' = Switch ($VMHdd.Persistence) {
                                                                            'IndependentPersistent' { 'Independent - Persistent' }
                                                                            'IndependentNonPersistent' { 'Independent - Nonpersistent' }
                                                                            'Persistent' { 'Dependent' }
                                                                            default { $VMHdd.Persistence }
                                                                        }
                                                                        'SCSI Controller' = $SCSIController.DeviceInfo.Label
                                                                        'SCSI Address' = "$($SCSIController.BusNumber):$($VMHdd.ExtensionData.UnitNumber)"
                                                                    }
                                                                    $TableParams = @{
                                                                        Name = "$($VM.Name) $($VMHdd.Name) HDD Configuration - $($VMHost.ExtensionData.Name)"
                                                                        List = $true
                                                                        ColumnWidths = 25, 75
                                                                    }
                                                                    if ($Report.ShowTableCaptions) {
                                                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                                                    }
                                                                    $VMHardDiskInfo | Table @TableParams
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                                if ($VMGuestVols) {
                                                    Section -Style Heading4 "Guest Volumes" {
                                                        $VMGuestDiskInfo = foreach ($VMGuestVol in $VMGuestVols) {
                                                            [PSCustomObject]@{
                                                                'Path' = $VMGuestVol.Path
                                                                'Capacity' = "$([math]::Round(($VMGuestVol.CapacityGB), 2)) GB"
                                                                'Used Space' = "$([math]::Round((($VMGuestVol.CapacityGB) - ($VMGuestVol.FreeSpaceGB)), 2)) GB"
                                                                'Free Space' = "$([math]::Round($VMGuestVol.FreeSpaceGB, 2)) GB"
                                                            }
                                                        }
                                                        $TableParams = @{
                                                            Name = "$($VM.Name) Guest Volumes - $($VMHost.ExtensionData.Name)"
                                                            ColumnWidths = 25, 25, 25, 25
                                                        }
                                                        if ($Report.ShowTableCaptions) {
                                                            $TableParams['Caption'] = "- $($TableParams.Name)"
                                                        }
                                                        $VMGuestDiskInfo | Table @TableParams
                                                    }
                                                }
                                            }


                                            if ($VMSnapshotList -and $Options.ShowVMSnapshots) {
                                                Section -Style Heading4 "Snapshots" {
                                                    $VMSnapshots = foreach ($VMSnapshot in $VMSnapshotList) {
                                                        [PSCustomObject]@{
                                                            'Snapshot Name' = $VMSnapshot.Name
                                                            'Description' = $VMSnapshot.Description
                                                            'Days Old' = ((Get-Date).ToUniversalTime() - $VMSnapshot.CreateTime).Days
                                                        }
                                                    }
                                                    if ($Healthcheck.VM.VMSnapshots) {
                                                        $VMSnapshots | Where-Object { $_.'Days Old' -ge 7 } | Set-Style -Style Warning
                                                        $VMSnapshots | Where-Object { $_.'Days Old' -ge 14 } | Set-Style -Style Critical
                                                    }
                                                    $TableParams = @{
                                                        Name = "$($VM.Name) VM Snapshots - $($VMHost.ExtensionData.Name)"
                                                        ColumnWidths = 45, 45, 10
                                                    }
                                                    if ($Report.ShowTableCaptions) {
                                                        $TableParams['Caption'] = "- $($TableParams.Name)"
                                                    }
                                                    $VMSnapshots | Table @TableParams
                                                }
                                            }
                                        }
                                    }
                                }
                                #endregion Virtual Machine Detailed Information
                            }
                        }
                    }
                    #endregion Virtual Machine Section

                    #region ESXi Host VM Autostart Information
                    if ($InfoLevel.VMHost -ge 1) {
                        $VMStartPolicy = $VMHost | Get-VMStartPolicy | Sort-Object VirtualMachineName
                        if ($VMStartPolicy) {
                            #region VM Autostart Section
                            Section -Style Heading2 'VM Autostart' {
                                Paragraph "The following section details the VM autostart configuration for $($VMHost.ExtensionData.Name)."
                                BlankLine
                                $VMStartPolicies = foreach ($VMStartPol in $VMStartPolicy) {
                                    [PSCustomObject]@{
                                        'Virtual Machine' = $VMStartPol.VirtualMachineName
                                        'Autostart Enabled' = Switch ($VMStartPol.StartAction) {
                                            'PowerOn' { 'Yes' }
                                            'None' { 'No' }
                                            default { $VMStartPol.StartAction }
                                        }
                                        'Autostart Order' = Switch ($VMStartPol.StartOrder) {
                                            $null { 'Unset' }
                                            default { $VMStartPol.StartOrder }
                                        }
                                        'Shutdown Behavior' = Switch ($VMStartPol.StopAction) {
                                            'PowerOff' { 'Power Off' }
                                            'GuestShutdown' { 'Shutdown' }
                                            default { $VMStartPol.StopAction }
                                        }
                                        'Start Delay' = "$($VMStartPol.StartDelay) sec"
                                        'Stop Delay' = "$($VMStartPol.StopDelay) sec"
                                        'Wait for Heartbeat' = Switch ($VMStartPol.WaitForHeartbeat) {
                                            $true { 'Yes' }
                                            $false { 'No' }
                                        }
                                    }
                                }
                                $TableParams = @{
                                    Name = "VM Autostart Policy - $($VMHost.ExtensionData.Name)"
                                    ColumnWidths = 25, 12, 13, 15, 12, 12, 11
                                }
                                if ($Report.ShowTableCaptions) {
                                    $TableParams['Caption'] = "- $($TableParams.Name)"
                                }
                                $VMStartPolicies | Table @TableParams
                            }
                            #endregion VM Autostart Section
                        }
                    }
                    #endregion ESXi Host VM Autostart Information
                }
                #endregion ESXi Host Detailed Information
            }
            #endregion Hosts Section
        } # end if ($ESXi)

        # Disconnect ESXi Server
        $Null = Disconnect-VIServer -Server $ESXi -Confirm:$false -ErrorAction SilentlyContinue

        #region Variable cleanup
        Clear-Variable -Name ESXi
        #endregion Variable cleanup

    } # end foreach ($VIServer in $Target)
}