functions/Get-XdrVulnerabilityManagementBaseline.ps1

function Get-XdrVulnerabilityManagementBaseline {
    <#
    .SYNOPSIS
        Retrieves security baseline assessment data from Microsoft Defender XDR.

    .DESCRIPTION
        Retrieves various security baseline profile information including compliance status, statistics,
        settings, and device data. Supports multiple endpoint variants for comprehensive baseline assessment.
        This function includes caching support with a 30-minute TTL to reduce API calls.

    .PARAMETER ProfilesStatistics
        Retrieves statistics for all baseline profiles.

    .PARAMETER ProfilesCompliance
        Retrieves compliance data for all baseline profiles with pagination support.

    .PARAMETER TopFailingDevices
        Retrieves the top devices failing baseline assessments.

    .PARAMETER AllSettingsResults
        Retrieves results for all settings across all profiles with filtering and ordering.

    .PARAMETER AllSettingsFilters
        Retrieves available filters for all settings queries.

    .PARAMETER AllSettingsStatistics
        Retrieves statistical data for all settings.

    .PARAMETER Profiles
        Retrieves a list of all baseline profiles.

    .PARAMETER ProfileFilters
        Retrieves available filters for profile queries (from orgsettings).

    .PARAMETER ProfileId
        The GUID of a specific baseline profile to query. Required when using profile-specific switches.

    .PARAMETER ProfileStatistics
        Retrieves statistics for a specific profile. Requires -ProfileId.

    .PARAMETER ProfileDetails
        Retrieves detailed information for a specific profile. Requires -ProfileId.

    .PARAMETER ProfileSettings
        Retrieves settings for a specific profile. Requires -ProfileId.

    .PARAMETER ProfileDevices
        Retrieves devices associated with a specific profile. Requires -ProfileId.

    .PARAMETER ProfileComplianceStatus
        Retrieves compliance status for a specific profile. Requires -ProfileId.

    .PARAMETER OrgSettingsProfile
        Retrieves organization settings for a specific profile. Requires -ProfileId.

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

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

    .EXAMPLE
        Get-XdrVulnerabilityManagementBaseline -ProfilesStatistics
        Retrieves statistics for all baseline profiles.

    .EXAMPLE
        Get-XdrVulnerabilityManagementBaseline -Profiles
        Retrieves a list of all baseline profiles.

    .EXAMPLE
        Get-XdrVulnerabilityManagementBaseline -Profiles -Top 10
        Retrieves the first 10 baseline profiles.

    .EXAMPLE
        Get-XdrVulnerabilityManagementBaseline -ProfileId "e0ee318e-5f4a-4a41-a49f-d899b25759ba" -ProfileDetails
        Retrieves detailed information for a specific profile.

    .EXAMPLE
        Get-XdrVulnerabilityManagementBaseline -ProfileId "e0ee318e-5f4a-4a41-a49f-d899b25759ba" -ProfileStatistics
        Retrieves statistics for a specific profile.

    .EXAMPLE
        Get-XdrVulnerabilityManagementBaseline -ProfileId "e0ee318e-5f4a-4a41-a49f-d899b25759ba" -ProfileDevices
        Retrieves all devices for a specific profile with automatic pagination.

    .EXAMPLE
        Get-XdrVulnerabilityManagementBaseline -AllSettingsResults
        Retrieves results for all settings with default filtering.

    .EXAMPLE
        Get-XdrVulnerabilityManagementBaseline -TopFailingDevices
        Retrieves the top devices failing baseline assessments.

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

    .OUTPUTS
        System.Management.Automation.PSCustomObject
        Returns a single object for non-paginated endpoints (statistics, details, filters).
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Switch parameters are used via $PSCmdlet.ParameterSetName')]
    [CmdletBinding(DefaultParameterSetName = 'ProfilesStatistics')]
    [OutputType([System.Object[]])]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param (
        [Parameter(ParameterSetName = 'ProfilesStatistics')]
        [switch]$ProfilesStatistics,

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

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

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

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

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

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

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

        [Parameter(ParameterSetName = 'ProfileStatistics', Mandatory = $true)]
        [Parameter(ParameterSetName = 'ProfileDetails', Mandatory = $true)]
        [Parameter(ParameterSetName = 'ProfileSettings', Mandatory = $true)]
        [Parameter(ParameterSetName = 'ProfileDevices', Mandatory = $true)]
        [Parameter(ParameterSetName = 'ProfileComplianceStatus', Mandatory = $true)]
        [Parameter(ParameterSetName = 'OrgSettingsProfile', Mandatory = $true)]
        [string]$ProfileId,

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

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

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

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

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

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

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

        [Parameter()]
        [switch]$Force
    )

    begin {
        Update-XdrConnectionSettings

        # Prepare TVM headers (baseline API requires api-version header)
        $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) {
            'ProfilesStatistics' {
                @{
                    CacheKey = "XdrVulnerabilityManagementBaseline_ProfilesStatistics"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/profilesStatistics"
                }
            }
            'ProfilesCompliance' {
                @{
                    CacheKey    = "XdrVulnerabilityManagementBaseline_ProfilesCompliance"
                    DisplayName = "profiles compliance"
                    BuildUri    = { param($p) "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/profilesCompliance/?pageIndex=$p&pageSize=25" }
                }
            }
            'TopFailingDevices' {
                @{
                    CacheKey    = "XdrVulnerabilityManagementBaseline_TopFailingDevices"
                    DisplayName = "top failing devices"
                    BuildUri    = { param($p) "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/topFailingDevices/?pageIndex=$p&pageSize=25" }
                }
            }
            'AllSettingsResults' {
                @{
                    CacheKey    = "XdrVulnerabilityManagementBaseline_AllSettingsResults"
                    DisplayName = "all settings results"
                    BuildUri    = { param($p) "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/allSettings/allSettingsResults?pageIndex=$p&pageSize=25&`$filter=(compliantDevices+ne+-1)&`$orderby=compliancePct+asc,name+asc" }
                }
            }
            'AllSettingsFilters' {
                @{
                    CacheKey = "XdrVulnerabilityManagementBaseline_AllSettingsFilters"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/allSettings/filters"
                }
            }
            'AllSettingsStatistics' {
                @{
                    CacheKey = "XdrVulnerabilityManagementBaseline_AllSettingsStatistics"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/allSettings/statistics"
                }
            }
            'Profiles' {
                @{
                    CacheKey    = "XdrVulnerabilityManagementBaseline_Profiles"
                    DisplayName = "baseline profiles"
                    BuildUri    = { param($p) "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/profiles?pageIndex=$p&pageSize=25" }
                }
            }
            'ProfileFilters' {
                @{
                    CacheKey = "XdrVulnerabilityManagementBaseline_ProfileFilters"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/orgsettings/baseline/profiles/filters"
                }
            }
            'ProfileStatistics' {
                @{
                    CacheKey = "XdrVulnerabilityManagementBaseline_ProfileStatistics_$ProfileId"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/profilesStatistics/$ProfileId?profileId=$ProfileId"
                }
            }
            'ProfileDetails' {
                @{
                    CacheKey = "XdrVulnerabilityManagementBaseline_ProfileDetails_$ProfileId"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/profiles/$ProfileId"
                }
            }
            'ProfileSettings' {
                @{
                    CacheKey    = "XdrVulnerabilityManagementBaseline_ProfileSettings_$ProfileId"
                    DisplayName = "profile settings"
                    BuildUri    = { param($p) "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/profiles/$ProfileId/settings?pageIndex=$p&pageSize=25" }.GetNewClosure()
                }
            }
            'ProfileDevices' {
                @{
                    CacheKey    = "XdrVulnerabilityManagementBaseline_ProfileDevices_$ProfileId"
                    DisplayName = "profile devices"
                    BuildUri    = { param($p) "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/profiles/$ProfileId/devices?pageIndex=$p&pageSize=25" }.GetNewClosure()
                }
            }
            'ProfileComplianceStatus' {
                @{
                    CacheKey = "XdrVulnerabilityManagementBaseline_ProfileComplianceStatus_$ProfileId"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/analytics/baseline/profiles/$ProfileId/complianceStatus"
                }
            }
            'OrgSettingsProfile' {
                @{
                    CacheKey = "XdrVulnerabilityManagementBaseline_OrgSettingsProfile_$ProfileId"
                    Simple   = $true
                    Endpoint = "https://security.microsoft.com/apiproxy/mtp/tvm/orgsettings/baseline/profiles/$ProfileId"
                }
            }
        }

        # 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 $($PSCmdlet.ParameterSetName) data"

            if ($config.Simple) {
                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 "Cache for $($PSCmdlet.ParameterSetName) 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 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 baseline data: $_"
        }
    }

    end {
    }
}