functions/Get-XdrIdentityIdentity.ps1
|
function Get-XdrIdentityIdentity { <# .SYNOPSIS Retrieves identities from Microsoft Defender for Identity. .DESCRIPTION Gets identities from Microsoft Defender for Identity with support for pagination, sorting, and search filtering. This function includes caching support with a 10-minute TTL to reduce API calls. .PARAMETER SortByField The field to sort results by. Valid values are "RepresentableName", "AccountDomain", and "CreatedDateTime". Default is "RepresentableName". .PARAMETER SortDirection The sort direction. Valid values are "Asc" (ascending) and "Dsc" (descending). Default is "Asc". .PARAMETER PageSize The number of identities to retrieve per page. Default is 20. Maximum is 100. .PARAMETER Skip The number of identities to skip. Used for pagination. Default is 0. .PARAMETER SearchText Text to search for in identities. Only non-special characters are allowed. .PARAMETER IdentityProvider Filters identities by identity provider. Valid values are "ActiveDirectory", "EntraID", and "Hybrid". Multiple values can be specified. .PARAMETER IdentityEnvironment Filters identities by primary identity provider. Valid values are "ActiveDirectory", "EntraID", and "Hybrid". Multiple values can be specified. .PARAMETER All Retrieves all identities by automatically paging through all results. When specified, PageSize and Skip parameters are ignored. .PARAMETER Force Bypasses the cache and forces a fresh retrieval from the API. .EXAMPLE Get-XdrIdentityIdentity Retrieves the first 20 identities sorted by RepresentableName in ascending order. .EXAMPLE Get-XdrIdentityIdentity -SortByField CreatedDateTime -SortDirection Dsc Retrieves identities sorted by creation date in descending order (newest first). .EXAMPLE Get-XdrIdentityIdentity -PageSize 50 -Skip 100 Retrieves 50 identities, skipping the first 100 (for pagination). .EXAMPLE Get-XdrIdentityIdentity -SearchText "admin" Retrieves identities matching the search text "admin". .EXAMPLE Get-XdrIdentityIdentity -SortByField AccountDomain -PageSize 100 -SearchText "contoso" Retrieves up to 100 identities containing "contoso", sorted by account domain. .EXAMPLE Get-XdrIdentityIdentity -IdentityProvider ActiveDirectory Retrieves identities from Active Directory only. .EXAMPLE Get-XdrIdentityIdentity -IdentityProvider ActiveDirectory, EntraID Retrieves identities from both Active Directory and Entra ID. .EXAMPLE Get-XdrIdentityIdentity -IdentityEnvironment ActiveDirectory Retrieves identities with Active Directory as primary identity provider. .EXAMPLE Get-XdrIdentityIdentity -IdentityEnvironment ActiveDirectory, EntraID Retrieves identities with Active Directory or Entra ID as primary identity provider. .EXAMPLE Get-XdrIdentityIdentity -SearchText "bob" -IdentityEnvironment ActiveDirectory Retrieves identities matching "bob" from Active Directory only. .EXAMPLE Get-XdrIdentityIdentity -Force Forces a fresh retrieval of identities, bypassing the cache. .EXAMPLE Get-XdrIdentityIdentity -All Retrieves all identities by automatically paging through all results. .EXAMPLE Get-XdrIdentityIdentity -All -SearchText "admin" Retrieves all identities matching "admin" by paging through all results. .OUTPUTS Object Returns the identities data from the API. #> [OutputType([System.Object[]])] [CmdletBinding(DefaultParameterSetName = 'Paged')] param ( [Parameter()] [ValidateSet('RepresentableName', 'AccountDomain', 'CreatedDateTime')] [string]$SortByField = 'RepresentableName', [Parameter()] [ValidateSet('Asc', 'Dsc')] [string]$SortDirection = 'Asc', [Parameter(ParameterSetName = 'Paged')] [ValidateRange(1, 500)] [int]$PageSize = 20, [Parameter(ParameterSetName = 'Paged')] [int]$Skip = 0, [Parameter()] [ValidatePattern('^[a-zA-Z0-9\s]*$')] [string]$SearchText = '', [Parameter()] [ValidateSet('ActiveDirectory', 'EntraID', 'Hybrid')] [string[]]$IdentityProvider, [Parameter()] [ValidateSet('ActiveDirectory', 'EntraID', 'Hybrid')] [string[]]$IdentityEnvironment, [Parameter(ParameterSetName = 'All', Mandatory)] [switch]$All, [Parameter()] [switch]$Force ) begin { Update-XdrConnectionSettings } process { # Build filters first as they're needed for caching and API calls $filters = @{} # Add IdentityProvider filter if specified if ($PSBoundParameters.ContainsKey('IdentityProvider')) { Write-Verbose "Filtering by IdentityProvider: $($IdentityProvider -join ', ')" # Translate EntraID to AzureActiveDirectory for API $translatedIdentityProvider = $IdentityProvider | ForEach-Object { if ($_ -eq 'EntraID') { 'AzureActiveDirectory' } else { $_ } } $filters['IdentityProviders'] = @{ has = @($translatedIdentityProvider) } } # Add IdentityEnvironment filter if specified if ($PSBoundParameters.ContainsKey('IdentityEnvironment')) { Write-Verbose "Filtering by IdentityEnvironment: $($IdentityEnvironment -join ', ')" # Translate EntraID to AzureActiveDirectory for API $translatedIdentityEnvironment = $IdentityEnvironment | ForEach-Object { if ($_ -eq 'EntraID') { 'AzureActiveDirectory' } else { $_ } } $filters['PrimaryIdentityProvider'] = @{ eq = @($translatedIdentityEnvironment) } } # If All switch is specified, retrieve all identities through pagination if ($All) { Write-Verbose "Retrieving all identities with pagination" # Create cache key for All parameter $identityProviderKey = if ($PSBoundParameters.ContainsKey('IdentityProvider')) { ($IdentityProvider | Sort-Object) -join '-' } else { 'All' } $primaryIdentityProviderKey = if ($PSBoundParameters.ContainsKey('IdentityEnvironment')) { ($IdentityEnvironment | Sort-Object) -join '-' } else { 'All' } $cacheKeySuffix = "All-$SortByField-$SortDirection-$SearchText-$identityProviderKey-$primaryIdentityProviderKey" $cacheKey = "XdrIdentityIdentity-$cacheKeySuffix" # Check cache first $currentCacheValue = Get-XdrCache -CacheKey $cacheKey -ErrorAction SilentlyContinue if (-not $Force -and $currentCacheValue.NotValidAfter -gt (Get-Date)) { Write-Verbose "Using cached XDR identities (All)" return $currentCacheValue.Value } elseif ($Force) { Write-Verbose "Force parameter specified, bypassing cache" Clear-XdrCache -CacheKey $cacheKey } else { Write-Verbose "XDR identities cache (All) is missing or expired" } # Get the total count $totalCount = Get-XdrIdentityIdentityCount -Filters $filters -SearchText $SearchText Write-Verbose "Total identities to retrieve: $totalCount" if ($totalCount -eq 0) { Write-Verbose "No identities found matching the criteria" $emptyResult = @() Set-XdrCache -CacheKey $cacheKey -Value $emptyResult -TTLMinutes 5 return $emptyResult } # Use maximum page size for efficiency $pageSizeForAll = 500 $allResults = [System.Collections.Generic.List[object]]::new() $currentSkip = 0 while ($currentSkip -lt $totalCount) { Write-Verbose "Retrieving page: Skip=$currentSkip, PageSize=$pageSizeForAll" # Build the request body for this page $body = @{ PageSize = $pageSizeForAll Skip = $currentSkip SortBy = @{ Field = $SortByField Direction = $SortDirection } Filters = $filters SearchText = $SearchText } try { $Uri = "https://security.microsoft.com/apiproxy/mdi/identity/userapiservice/identities" $result = Invoke-RestMethod -Uri $Uri -Method Post -ContentType "application/json" -Body ($body | ConvertTo-Json -Depth 10) -WebSession $script:session -Headers $script:headers $pageData = $result | Select-Object -ExpandProperty data } catch { Write-Error "Failed to retrieve identities: $_" return } if ($null -ne $pageData -and $pageData.Count -gt 0) { $allResults.AddRange([array]$pageData) Write-Verbose "Retrieved $($pageData.Count) identities (Total so far: $($allResults.Count))" } $currentSkip += $pageSizeForAll # Safety check to prevent infinite loops if ($pageData.Count -eq 0) { Write-Verbose "No more data returned, stopping pagination" break } } Write-Verbose "Completed retrieving all identities: $($allResults.Count) total" # Add type name for custom formatting foreach ($item in $allResults) { $item.PSObject.TypeNames.Insert(0, 'XdrIdentityIdentity') } # Cache the complete result $finalResult = $allResults.ToArray() Set-XdrCache -CacheKey $cacheKey -Value $finalResult -TTLMinutes 30 return $finalResult } # Standard single-page retrieval with caching # Create cache key based on parameters $identityProviderKey = if ($PSBoundParameters.ContainsKey('IdentityProvider')) { ($IdentityProvider | Sort-Object) -join '-' } else { 'All' } $primaryIdentityProviderKey = if ($PSBoundParameters.ContainsKey('IdentityEnvironment')) { ($IdentityEnvironment | Sort-Object) -join '-' } else { 'All' } $cacheKeySuffix = "$SortByField-$SortDirection-$PageSize-$Skip-$SearchText-$identityProviderKey-$primaryIdentityProviderKey" $cacheKey = "XdrIdentityIdentity-$cacheKeySuffix" $currentCacheValue = Get-XdrCache -CacheKey $cacheKey -ErrorAction SilentlyContinue if (-not $Force -and $currentCacheValue.NotValidAfter -gt (Get-Date)) { Write-Verbose "Using cached XDR identities" return $currentCacheValue.Value } elseif ($Force) { Write-Verbose "Force parameter specified, bypassing cache" Clear-XdrCache -CacheKey $cacheKey } else { Write-Verbose "XDR identities cache is missing or expired" } # Build the request body $body = @{ PageSize = $PageSize Skip = $Skip SortBy = @{ Field = $SortByField Direction = $SortDirection } Filters = $filters SearchText = $SearchText } try { $Uri = "https://security.microsoft.com/apiproxy/mdi/identity/userapiservice/identities" Write-Verbose "Retrieving XDR identities (SortBy: $SortByField $SortDirection, PageSize: $PageSize, Skip: $Skip, SearchText: '$SearchText', IdentityProvider: '$identityProviderKey', IdentityEnvironment: '$primaryIdentityProviderKey')" $result = Invoke-RestMethod -Uri $Uri -Method Post -ContentType "application/json" -Body ($body | ConvertTo-Json -Depth 10) -WebSession $script:session -Headers $script:headers $result = $result | Select-Object -ExpandProperty data } catch { Write-Error "Failed to retrieve identities: $_" return } if ($null -eq $result) { $result = @() } # Add type name for custom formatting foreach ($item in $result) { $item.PSObject.TypeNames.Insert(0, 'XdrIdentityIdentity') } Set-XdrCache -CacheKey $cacheKey -Value $result -TTLMinutes 10 return $result } end { } } |