functions/Get-XdrVulnerabilityManagementCertificates.ps1

function Get-XdrVulnerabilityManagementCertificates {
    <#
    .SYNOPSIS
        Retrieves certificates from Vulnerability Management.

    .DESCRIPTION
        Gets certificate inventory data from TVM in Microsoft Defender XDR.
        This includes information about server certificates, machine certificates, certificate issues, and issuers.
        This function includes caching support with a 30-minute TTL to reduce API calls.

    .PARAMETER Force
        Bypasses the cache and forces a fresh retrieval from the API.

    .PARAMETER Top
        Limits the number of results returned for paginated endpoints. Useful for previewing data.

    .PARAMETER ServerCertificateIssues
        Retrieves server certificate issues.

    .PARAMETER MachineCertificateIssues
        Retrieves machine certificate issues.

    .PARAMETER PrivateCaCertificateIssues
        Retrieves private CA certificate issues.

    .PARAMETER ServerIssuers
        Retrieves server certificate issuers.

    .PARAMETER MachineIssuers
        Retrieves machine certificate issuers.

    .PARAMETER CountOnly
        Retrieves only the total count of certificates.

    .PARAMETER CountByExpirationDate
        Retrieves certificate count grouped by expiration date.

    .PARAMETER AggregatedMachineCertificates
        Retrieves aggregated machine certificate data from the aggregatedCertificate endpoint.

    .EXAMPLE
        Get-XdrVulnerabilityManagementCertificates
        Retrieves all certificates using cached data if available.

    .EXAMPLE
        Get-XdrVulnerabilityManagementCertificates -Force
        Forces a fresh retrieval of certificate inventory, bypassing the cache.

    .EXAMPLE
        Get-XdrVulnerabilityManagementCertificates -Top 10
        Retrieves only the first 10 certificates.

    .EXAMPLE
        Get-XdrVulnerabilityManagementCertificates -ServerCertificateIssues
        Retrieves server certificate issues.

    .EXAMPLE
        Get-XdrVulnerabilityManagementCertificates -CountOnly
        Returns only the total count of certificates.

    .EXAMPLE
        Get-XdrVulnerabilityManagementCertificates -AggregatedMachineCertificates
        Retrieves aggregated machine certificate data.

    .OUTPUTS
        System.Object[]
        Returns an array of certificate objects for paginated endpoints.

    .OUTPUTS
        System.Int64
        When -CountOnly is specified, returns the total count as an integer.

    .OUTPUTS
        System.Management.Automation.PSCustomObject
        Returns a single object for non-paginated endpoints (issues, issuers, counts).
    #>

    # Suppress false positive: Switch parameters are used via $PSCmdlet.ParameterSetName, not direct reference
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')]
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    [OutputType([System.Object[]])]
    [OutputType([System.Int64], ParameterSetName = 'CountOnly')]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param (
        [Parameter()]
        [switch]$Force,

        [Parameter()]
        [ValidateRange(1, 10000)]
        [int]$Top,

        [Parameter(ParameterSetName = 'ServerCertificateIssues')]
        [switch]$ServerCertificateIssues,

        [Parameter(ParameterSetName = 'MachineCertificateIssues')]
        [switch]$MachineCertificateIssues,

        [Parameter(ParameterSetName = 'PrivateCaCertificateIssues')]
        [switch]$PrivateCaCertificateIssues,

        [Parameter(ParameterSetName = 'ServerIssuers')]
        [switch]$ServerIssuers,

        [Parameter(ParameterSetName = 'MachineIssuers')]
        [switch]$MachineIssuers,

        [Parameter(ParameterSetName = 'CountOnly')]
        [switch]$CountOnly,

        [Parameter(ParameterSetName = 'CountByExpirationDate')]
        [switch]$CountByExpirationDate,

        [Parameter(ParameterSetName = 'AggregatedMachineCertificates')]
        [switch]$AggregatedMachineCertificates
    )

    begin {
        Update-XdrConnectionSettings

        # Prepare TVM headers
        $tvmHeaders = $script:headers.Clone()
        $tvmHeaders["api-version"] = "1.0"

        # Helper function for paginated requests
        function Invoke-PaginatedRequest {
            param (
                [scriptblock]$BuildUri,
                [string]$DisplayName,
                [string]$CountProperty = 'numOfResults',
                [int]$MaxResults = 0,
                [int]$PageSize = 25
            )

            $maxPages = 1000
            $pageNum = 1

            try {
                # Get first page
                $uri = & $BuildUri $pageNum
                Write-Verbose "Fetching $DisplayName page 1"
                $response = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -WebSession $script:session -Headers $tvmHeaders

                $totalResults = $response.$CountProperty
                if ($null -eq $totalResults) { $totalResults = 0 }
                $targetResults = if ($MaxResults -gt 0 -and $MaxResults -lt $totalResults) { $MaxResults } else { $totalResults }
                Write-Information "Total $DisplayName`: $totalResults$(if ($MaxResults -gt 0 -and $MaxResults -lt $totalResults) { " (fetching $targetResults)" })" -InformationAction Continue

                # Collect results with pagination
                $allResults = [System.Collections.Generic.List[object]]::new()
                if ($response.results) { $allResults.AddRange($response.results) }
                $pageNum = 2

                # Show progress for larger result sets (more than one page)
                $showProgress = $targetResults -gt $PageSize

                while ($allResults.Count -lt $targetResults -and $pageNum -le $maxPages) {
                    if ($showProgress) {
                        $percentComplete = [math]::Min(100, [math]::Round(($allResults.Count / $targetResults) * 100))
                        Write-Progress -Activity "Retrieving $DisplayName" -Status "$($allResults.Count) of $targetResults" -PercentComplete $percentComplete
                    }

                    $uri = & $BuildUri $pageNum
                    Write-Verbose "Fetching $DisplayName page $pageNum"
                    $response = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -WebSession $script:session -Headers $tvmHeaders
                    if ($response.results) { $allResults.AddRange($response.results) }
                    Write-Verbose "Retrieved $($allResults.Count) of $targetResults $DisplayName"
                    $pageNum++
                }

                if ($showProgress) {
                    Write-Progress -Activity "Retrieving $DisplayName" -Completed
                }

                # Trim to MaxResults if specified
                $finalResults = if ($MaxResults -gt 0 -and $allResults.Count -gt $MaxResults) {
                    $allResults.GetRange(0, $MaxResults).ToArray()
                } else {
                    $allResults.ToArray()
                }

                return [PSCustomObject]@{
                    Count   = $totalResults
                    Results = $finalResults
                }
            } catch {
                Write-Progress -Activity "Retrieving $DisplayName" -Completed
                throw "Failed to retrieve $DisplayName`: $_"
            }
        }
    }

    process {
        # Define endpoint configuration based on parameter set
        $config = switch ($PSCmdlet.ParameterSetName) {
            'ServerCertificateIssues' {
                @{
                    CacheKey = "XdrVulnerabilityManagementCertificates_ServerCertificateIssues"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/certificates/serverCertificateIssues"
                }
            }
            'MachineCertificateIssues' {
                @{
                    CacheKey = "XdrVulnerabilityManagementCertificates_MachineCertificateIssues"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/certificates/machineCertificateIssues"
                }
            }
            'PrivateCaCertificateIssues' {
                @{
                    CacheKey = "XdrVulnerabilityManagementCertificates_PrivateCaCertificateIssues"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/certificates/privateCaCertificateIssues"
                }
            }
            'ServerIssuers' {
                @{
                    CacheKey = "XdrVulnerabilityManagementCertificates_ServerIssuers"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/certificates/serverIssuers"
                }
            }
            'MachineIssuers' {
                @{
                    CacheKey = "XdrVulnerabilityManagementCertificates_MachineIssuers"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/certificates/machineIssuers"
                }
            }
            'CountOnly' {
                @{
                    CacheKey  = "XdrVulnerabilityManagementCertificates_Count"
                    Simple    = $true
                    Endpoint  = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/certificates/count"
                    CountOnly = $true
                }
            }
            'CountByExpirationDate' {
                @{
                    CacheKey = "XdrVulnerabilityManagementCertificates_CountByExpirationDate"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/certificates/countByExpirationDate"
                }
            }
            'AggregatedMachineCertificates' {
                @{
                    CacheKey    = "XdrVulnerabilityManagementCertificates_AggregatedMachineCertificates"
                    DisplayName = "aggregated machine certificates"
                    BuildUri    = { param($p) "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/aggregatedCertificate/machineCertificates?pageIndex=$p&pageSize=25" }
                }
            }
            default {
                @{
                    CacheKey    = "XdrVulnerabilityManagementCertificates"
                    DisplayName = "certificates"
                    BuildUri    = { param($p) "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/certificates?pageIndex=$p&pageSize=25" }
                }
            }
        }

        # Check cache first (skip if -Top is specified as we may need subset)
        $useCache = -not $Top -or $Top -eq 0
        $currentCacheValue = Get-XdrCache -CacheKey $config.CacheKey -ErrorAction SilentlyContinue

        if ($useCache -and -not $Force -and $currentCacheValue.NotValidAfter -gt (Get-Date)) {
            Write-Verbose "Using cached TVM certificates data"

            if ($config.Simple) {
                if ($config.CountOnly) {
                    Write-Information "Total certificates: $($currentCacheValue.Value)" -InformationAction Continue
                }
                return $currentCacheValue.Value
            }

            Write-Information "Total $($config.DisplayName): $($currentCacheValue.Value.numOfResults)" -InformationAction Continue
            return $currentCacheValue.Value.results
        }

        if ($Force) {
            Write-Verbose "Force parameter specified, bypassing cache"
            Clear-XdrCache -CacheKey $config.CacheKey
        } elseif (-not $useCache) {
            Write-Verbose "Top parameter specified, fetching fresh data"
        } else {
            Write-Verbose "TVM certificates cache is missing or expired"
        }

        try {
            # Handle simple (non-paginated) endpoints
            if ($config.Simple) {
                Write-Verbose "Retrieving from: $($config.Endpoint)"
                $result = Invoke-RestMethod -Uri $config.Endpoint -Method Get -ContentType "application/json" -WebSession $script:session -Headers $tvmHeaders

                # Handle CountOnly - extract just the count value
                if ($config.CountOnly) {
                    $countValue = if ($result.count) { $result.count } else { $result }
                    Write-Information "Total certificates: $countValue" -InformationAction Continue
                    Set-XdrCache -CacheKey $config.CacheKey -Value $countValue -TTLMinutes 30
                    return $countValue
                }

                # Handle null/empty results gracefully
                if ($null -eq $result) { $result = @{} }
                Set-XdrCache -CacheKey $config.CacheKey -Value $result -TTLMinutes 30
                return $result
            }

            # Handle paginated endpoints
            $paginatedResult = Invoke-PaginatedRequest -DisplayName $config.DisplayName -BuildUri $config.BuildUri -MaxResults $Top

            # Cache the full response only if we fetched everything
            if (-not $Top -or $Top -eq 0) {
                $cacheValue = [PSCustomObject]@{
                    numOfResults = $(if ($null -ne $paginatedResult.Count) { $paginatedResult.Count } else { 0 })
                    results      = $(if ($null -ne $paginatedResult.Results) { $paginatedResult.Results } else { @() })
                }
                Set-XdrCache -CacheKey $config.CacheKey -Value $cacheValue -TTLMinutes 30
            }

            # Return empty array if results are null
            if ($null -eq $paginatedResult.Results -or $paginatedResult.Results.Count -eq 0) {
                return
            }
            return $paginatedResult.Results

        } catch {
            Write-Error "Failed to retrieve TVM certificates: $_"
        }
    }

    end {
    }
}