Private/AzStackHci.HardwareOEM.Helpers.ps1

# ////////////////////////////////////////////////////////////////////////////
# Function to test if the hardware OEM manufacturer supports SBE packages
# This function checks the hardware against a list of OEM vendors that support SBE
Function Test-HardwareOEMSupportsSBE {
    <#
    .SYNOPSIS
        Test if the hardware manufacturer matches predefined list of OEM vendors that support SBE packages.
    .DESCRIPTION
        # This function checks the hardware against a list of OEM vendors that support SBE
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [string]$HardwareManufacturer,

        [Parameter(Mandatory=$false)]
        [switch]$TestAll
    )

    begin {
        # Write-Debug "Test-HardwareOEMSupportsSBE: Beginning OEM URL retrieval for '$OEM'"
        [int]$SBEEndpointsAdded = 0
    }

    process {

        if($TestAll.IsPresent) {
            [string]$OEMName = "TestAll"
        
        } else {
            # Initialize the OEM name variable as "Not Supported", before checking for a match
            [string]$OEMName = "Not Supported"

            # Determine a match for the OEMs that support SBEsm based on the hardware manufacturer passed to the function
            switch -Wildcard ($HardwareManufacturer) {
                "*DataON*" { $OEMName = "DataOn" }
                "*Dell*" { $OEMName = "Dell" }
                "*HPE*" { $OEMName = "HPE" }
                "*Hitachi*" { $OEMName = "Hitachi" }
                "*Lenovo*" { $OEMName = "Lenovo" }
                Default { 
                    Write-Verbose "Hardware manufacturer: '$HardwareManufacturer' does not support Solution Builder Extension (SBE) packages."
                    $OEMName = "Not Supported"
                }
            }
        }

    } # End of process block

    end {
        # Write-Debug "Test-HardwareOEMSupportsSBE: OEM URL retrieval process completed"

        if($TestAll.IsPresent) {
            # TestAll switch is present
            # Call the internal function to get OEM SBE URLs that require testing
            # Use the -TestAll switch
            $SBEEndpointsAdded = Get-HardwareOEMUrlContent -TestAll

        } elseif($OEMName -ne "Not Supported") {
            # Call the internal function to get OEM SBE URLs that require testing
            $SBEEndpointsAdded = Get-HardwareOEMUrlContent -OEMName $OEMName

        } else {
            # Do nothing, OEM is unknown
            Write-Verbose "No SBE endpoints to add for hardware OEM: '$OEMName'"
        }

        # Return the count of added SBE endpoints
        Return $SBEEndpointsAdded

    } # End of end block

} # End of Function Test-HardwareOEMSupportsSBE


# ////////////////////////////////////////////////////////////////////////////
# Function to get the Hardware OEM URLs to be tested for SBE support
# This function retrieves the OEM URLs for the hardware based on the OEM name
Function Get-HardwareOEMUrlContent {

    [CmdletBinding(DefaultParameterSetName='ByOEM')]
    param (
        [Parameter(Mandatory=$true, ParameterSetName='ByOEM')]
        [ValidateNotNullOrEmpty()]
        [string]$OEMName,

        [Parameter(Mandatory=$false, ParameterSetName='All')]
        [switch]$TestAll

    )

    begin {
        # Write-Debug "Get-HardwareOEMUrlContent: Beginning OEM URL content retrieval for '$OEMName'"
        # OEM endpoint URLs are defined centrally in AzStackHci.Constants.ps1
        [hashtable]$OEMUrls = $script:OEM_ENDPOINT_URLS
    }

    process {

        # Initialize a counter for the number of SBE endpoints found
        [int]$SBEEndpointCount = 0

        # Initialize an array to store the OEM endpoint URLs
        [array]$OEMEndpointUrls = @()
        # Check if TestAll switch is present:
        if($TestAll.IsPresent) {
            # If the TestAll switch is present, return all OEM URLs for testing
            Write-HostAzS "`nTestAll is present for hardware OEMs, adding all SBE endpoints." -ForegroundColor Yellow
            foreach ($oem in $OEMUrls.Keys) {
                $oemUrl = $OEMUrls[$oem]
                $OEMEndpointUrls += $oemUrl
            }
        } else {
            # Lookup the individual OEM SBE markdown page based on the OEM name
            if($OEMUrls.ContainsKey($OEMName)) {
                $OEMEndpointUrls = $OEMUrls[$OEMName]
            } else {
                # If the OEM name is not found in the hashtable, return a default URL or null
                Write-HostAzS "OEM manufacture '$OEMName' does not have SBE endpoints defined in GitHub repository." -ForegroundColor Yellow
                # Return zero
                Return 0
            }
        }

        # Loop the OEMEndpointUrls if multiple URLs are present
        foreach ($OEMEndpointUrl in $OEMEndpointUrls) {

            # Populate OEMName name from the URL endpoint, as not present when using TestAll switch
            $OEMName = $OEMEndpointUrl.Split('/')[-2]

            Write-Verbose "Retrieving SBE endpoints for OEM: $OEMName using URL: $OEMEndpointUrl"
        
            Remove-Variable SBEURLDownloadError -ErrorAction SilentlyContinue
            try {
                $endpointsContent = Invoke-WebRequest -Uri $OEMEndpointUrl -UseBasicParsing -ErrorAction SilentlyContinue -ErrorVariable SBEURLDownloadError
            } catch {
                Write-HostAzS "Failed to download $OEMName SBE endpoints from GitHub page: $OEMEndpointUrl - Error: $($_.Exception.Message)" -ForegroundColor Yellow
            }

            # If download fails, use cached URLs from module base path
            if($SBEURLDownloadError) {

                # Load the cached GitHub endpoints included in the module.
                Write-HostAzS "Using cached GitHub $OEMName SBE endpoints from module." -ForegroundColor Yellow
                # Check if the module is installed
                # Get the latest cached URL file, using the module base path and GitHub-URI-Cache_* folder to find the latest cached URLs
                [string]$UrlCacheFolderPatternMatch = "GitHub-URI-Cache_*"
                # Get the latest cached URL file using module base path and GitHub-URI-Cache_* folder wildcard
                try {
                    [string]$DiagnosticSettingsBasePath = (Get-Module -Name "AzStackHci.DiagnosticSettings" -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).ModuleBase
                    if ([string]::IsNullOrWhiteSpace($DiagnosticSettingsBasePath)) {
                        Throw "Module 'AzStackHci.DiagnosticSettings' not found. Please check the module is installed correctly."
                    }
                    [System.IO.DirectoryInfo]$UrlCacheLocation = Get-ChildItem -Path "$DiagnosticSettingsBasePath\$UrlCacheFolderPatternMatch" -ErrorAction Stop | Sort-Object LastWriteTime -Descending | Select-Object -First 1
                } catch {
                    Write-Error "Failed to locate cached GitHub endpoint files for SBE '$OEMName': $($_.Exception.Message)"
                    Return
                }
                # Check if the UrlCacheLocation variable is empty
                if(-not($UrlCacheLocation)){
                    Write-Error "No cached folder found for GitHub endpoints within in module installation folder: '$DiagnosticSettingsBasePath', please check the module is installed correctly?"
                    Return
                } else {
                    # Found cached URLs
                    Write-HostAzS "Using module cached versions of GitHub endpoints from date: '$($UrlCacheLocation.Name.Split('_')[-1])' for SBE: $OEMName" -ForegroundColor Yellow
                }
                # Get the cached endpoint file name, using the region name from the GitHub markdown files names.
                [string]$SBECacheFileName = "$($UrlCacheLocation.FullName)\OEMEndpoints\$($($OEMEndpointUrl.Split('/')[-1]))"
                Remove-Variable SBECacheFileReadError -ErrorAction SilentlyContinue
                $UrlCacheFileContents = Get-Content -Path $SBECacheFileName -ErrorAction SilentlyContinue -ErrorVariable SBECacheFileReadError
                    
                if($null -eq $UrlCacheFileContents){
                    Write-Debug "No cached file contents found for GitHub SBE endpoints file in path: '$SBECacheFileName' - Error: '$($SBECacheFileReadError.Exception.Message)'"
                    Throw "No SBE endpoints found in module cached file location for GitHub SBE endpoints: expected file path: '$SBECacheFileName' - Error: '$($SBECacheFileReadError.Exception.Message)'"
                } else {
                    # Split the cached file contents into a string array of lines
                    [string[]]$lines = $UrlCacheFileContents -split "`n"
                }

            } else {
                # Download successful
                Write-HostAzS "Successfully downloaded $OEMName SBE endpoints from GitHub page: $OEMEndpointUrl" -ForegroundColor Green
                # Split the downloaded file contents into a string array of lines
                [string[]]$lines = $endpointsContent.Content -split "`n"
            }

            # Remove any empty lines from the array
            if($lines) {
                $lines = $lines | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
            }
            # Validate that lines array is not empty before parsing
            if($lines -and $lines.Count -gt 0) {
                # Call the internal function to parse the endpoints from the markdown lines
                Write-Verbose "Parsing SBE endpoints from OEM markdown content for '$OEMName'"
                [int]$SBEsAdded = Get-EndpointsFromMarkdown -InputMarkdown $lines -Source "$OEMName SBE"
                $SBEEndpointCount += $SBEsAdded
            } else {
                Write-Error "No content found to parse SBE endpoints for OEM: '$OEMName'"
            }

            Write-Debug "Completed retrieval and parsing of SBE endpoints for OEM: '$OEMName' added $SBEsAdded endpoints to results array for processing."
        } # End foreach OEMEndpointUrl

    } # End of process block

    end {   
        # Write-Debug "Get-HardwareOEMUrlContent: OEM URL content retrieval process completed"
        # Return count of SBE endpoints added to results
        Return $SBEEndpointCount
    }

} # End of Function Get-HardwareOEMUrlContent


# ////////////////////////////////////////////////////////////////////////////
# Function to detect hardare make and model using WMI query against Win32_ComputerSystem class
Function Invoke-HardwareOEMDetection {
    <#
    .SYNOPSIS
        Detect the OEM of the hardware and return the OEM name.
    .DESCRIPTION
        This function detects the OEM of the hardware using WMI to return the "Manufacturer" property from the Win32_ComputerSystem class.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false)]
        [string]$OEMName = "Unknown"
    )

    begin {
        # Write-Debug "Starting function Invoke-HardwareOEMDetection"
    }

    process {

        try {
            # Get the OEM name from the Win32_ComputerSystem class
            $WMIHardwareQuery = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction SilentlyContinue
        } catch {
            Write-HostAzS "Error: Failed to retrieve hardware information from CIM." -ForegroundColor Red
            Write-HostAzS "Error: $($_.Exception.Message)`n" -ForegroundColor Red
        }
        if($WMIHardwareQuery) {
            # Get the OEM name from the Win32_ComputerSystem class
            $OEMName = $WMIHardwareQuery.Manufacturer
        } else {
            $OEMName = "Unknown"
        }

    } # End of process block

    end {
        # Write-Debug "Invoke-HardwareOEMDetection"
        # Return the OEM name
        Return $OEMName
    }

} # End of Function Invoke-HardwareOEMDetection