Private/Checks/VCenter/Test-VcfVcenterDetectHcxplugin.ps1

# Copyright (c) 2026 Broadcom. All Rights Reserved.
# Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc.
# and/or its subsidiaries.
#
# =============================================================================
#
# SOFTWARE LICENSE AGREEMENT
#
# Copyright (c) CA, Inc. All rights reserved.
#
# You are hereby granted a non-exclusive, worldwide, royalty-free license
# under CA, Inc.'s copyrights to use, copy, modify, and distribute this
# software in source code or binary form for use in connection with CA, Inc.
# products.
#
# This copyright notice shall be included in all copies or substantial
# portions of the software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# =============================================================================
function Test-VcfVcenterDetectHcxplugin {

    <#
        .SYNOPSIS
        Detects whether the HCX plugin is registered as a vCenter extension.

        .DESCRIPTION
        Discovers whether the HCX plugin is registered as a vCenter extension using the
        Get-VcfCheckVCenterExtension wrapper (see Private/InventoryHelpers.ps1). Matches
        extensions whose Key or Description contains "hcx" (case-insensitive substring, not a
        hardcoded exact key). Reports Skipped (not Fail) when absent, since HCX not being present
        is a normal, valid environment state.

        When present, the registered extension's Version is parsed and compared against 9.1:
        Pass (no action needed) when already at or above 9.1, Warning when below 9.1 (HCX must be
        upgraded to HCX 9.1 before upgrading to VCF 9.1), and Warning with a "verify manually"
        remediation when the version string cannot be parsed as a [Version] - erring toward
        surfacing the requirement rather than silently passing an unrecognized version string.

        New-VcfCheckResult (via New-VcfCheckPerDomainResults) falls back to the catalog's
        remediation text whenever a result's Remediation isn't explicitly set, regardless of that
        result's own Status - so relying on that fallback here would leak the HCX-9.1 remediation
        onto Skipped/Pass outcomes too. Remediation is therefore set explicitly per outcome after
        New-VcfCheckPerDomainResults returns, populated only for outcomes that actually need it.

        Iterates every vCenter attached to SDDC Manager (Get-VcfCheckAllVCenterFqdns) and
        turns the per-vCenter outcomes into one result per vCenter domain via
        New-VcfCheckPerDomainResults.

        .PARAMETER Context
        The VcfCheck.Context object. Must already be connected to SDDC Manager.

        .OUTPUTS
        [PSObject] a VcfCheck.Result.
    #>


    [CmdletBinding()]
    [OutputType([PSObject])]
    Param (
        [Parameter(Mandatory = $true)] [PSObject]$Context,
        [Parameter(Mandatory = $false)] [String]$DisplayName = ''
    )

    $startedAt = Get-Date
    $checkId = 'vcenter_detect_hcxplugin'
    $catalogEntry = (Get-VcfCheckCatalog)[$checkId]
    $displayName = if ([String]::IsNullOrEmpty($DisplayName)) { $catalogEntry.displayName } else { $DisplayName }
    $blocking = Get-VcfCheckBlockingStatusFromCatalog -CheckId $checkId
    $validationCriteria = $catalogEntry.validationCriteria
    $remediation = $catalogEntry.remediation
    $minimumSupportedVersion = [Version]'9.1'

    try {
        $vcenterFqdns = Get-VcfCheckAllVCenterFqdns -Context $Context
    } catch {
        return New-VcfCheckResult -CheckId $checkId -Area vCenter -Status Error `
            -Exception $_.Exception.Message -ValidationCriteria $validationCriteria -StartedAt $startedAt -CompletedAt (Get-Date) -DisplayName $displayName
    }

    $outcomes = foreach ($vcenterFqdn in $vcenterFqdns) {
        $iterationStartedAt = Get-Date
        $outcome = try {
            Connect-VcfCheckVCenter -Context $Context -Fqdn $vcenterFqdn
            $extensions = Get-VcfCheckVCenterExtension -Server $vcenterFqdn
            $hcxExtension = $extensions | Where-Object {
                $_.Key -match 'hcx' -or $_.Description.Label -match 'HCX'
            } | Select-Object -First 1

            if (-not $hcxExtension) {
                [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Skipped'; Detail = 'HCX plugin is not registered as a vCenter extension.'; SkipReasonTag = 'HCX not installed'; Blocking = $blocking; Rows = @(); Remediation = $null }
            } else {
                $rows = @([PSCustomObject]@{
                    Key = $hcxExtension.Key
                    Description = $hcxExtension.Description.Label
                    Version = $hcxExtension.Version
                })
                $parsedVersion = $null
                $versionParsed = [Version]::TryParse($hcxExtension.Version, [ref]$parsedVersion)

                if ($versionParsed -and $parsedVersion -ge $minimumSupportedVersion) {
                    [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Pass'; Detail = "HCX plugin detected: extension key `"$($hcxExtension.Key)`", version $($hcxExtension.Version) (meets the HCX 9.1 minimum required for VCF 9.1)."; Blocking = $blocking; Rows = $rows; Remediation = $null }
                } elseif ($versionParsed) {
                    [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Warning'; Detail = "HCX plugin detected: extension key `"$($hcxExtension.Key)`", version $($hcxExtension.Version) (below the HCX 9.1 minimum required for VCF 9.1)."; Blocking = $blocking; Rows = $rows; Remediation = $remediation }
                } else {
                    [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Warning'; Detail = "HCX plugin detected: extension key `"$($hcxExtension.Key)`", version `"$($hcxExtension.Version)`" could not be parsed to confirm it meets the HCX 9.1 minimum required for VCF 9.1 - verify manually."; Blocking = $blocking; Rows = $rows; Remediation = $remediation }
                }
            }
        } catch {
            [PSCustomObject]@{ VCenterFqdn = $vcenterFqdn; Status = 'Error'; Detail = $_.Exception.Message; Blocking = $blocking; Rows = @(); Remediation = $null }
        }
        $outcome | Add-Member -NotePropertyName StartedAt -NotePropertyValue $iterationStartedAt -Force
        $outcome | Add-Member -NotePropertyName CompletedAt -NotePropertyValue (Get-Date) -Force
        $outcome
    }

    $results = New-VcfCheckPerDomainResults -Context $Context -PerVCenterOutcome $outcomes -CheckId $checkId -Area vCenter `
        -ValidationCriteria $validationCriteria -StartedAt $startedAt -DisplayName $displayName

    foreach ($result in $results) {
        $outcomeRemediation = ($outcomes | Where-Object { $_.VCenterFqdn -eq $result.TargetComponent } | Select-Object -First 1).Remediation
        $result.Remediation = $outcomeRemediation
    }

    return $results
}