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 { } } |