Public/Reconnaissance/Invoke-MSGraph.ps1

function Invoke-MsGraph {
    [cmdletbinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $false)]
        [string]$relativeUrl,

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false)]
        [switch]$NoBatch,

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false)]
        [int]$MaxRetries = 3,  # Maximum number of retries

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false)]
        [int]$RetryDelaySeconds = 5 # Initial delay in seconds
    )

    begin {
        $MyInvocation.MyCommand.Name | Invoke-BlackCat -ResourceTypeName 'MSGraph'
    }

    process {
        $retries = 0
        do {
            try {
                if ($NoBatch) {
                    $uri = "$($sessionVariables.graphUri)/$relativeUrl" -replace 'applications/\(', 'applications('
                    Write-Verbose "Invoking Microsoft Graph API: $uri"
                    $requestParam = @{
                        Headers = $script:graphHeader
                        Uri     = $uri
                        Method  = 'GET'
                        UserAgent = $($sessionVariables.userAgent)
                    }
                }
                else {

                    $payload = @{
                        requests = @(
                            @{
                                id     = "List"
                                method = 'GET'
                                url    = '/{0}' -f "$relativeUrl"
                            }
                        )
                    }

                    $requestParam = @{
                        Headers     = $script:graphHeader
                        Uri         = '{0}/$batch' -f $sessionVariables.graphUri
                        Method      = 'POST'
                        ContentType = 'application/json'
                        Body        = $payload | ConvertTo-Json -Depth 10
                        UserAgent   = $($sessionVariables.userAgent)
                    }
                }

                $initialResponse = (Invoke-RestMethod @requestParam)

                if ($NoBatch) {
                    return $initialResponse
                }

                # Check for throttling headers
                if ($initialResponse.Headers."Retry-After") {
                    $retryAfter = [int]$initialResponse.Headers."Retry-After"
                    Write-Warning "Throttled! Waiting $($retryAfter) seconds before retrying."
                    Start-Sleep -Seconds $retryAfter
                    $retries++ # Increment retries, important to track
                    continue  # Skip the rest of the loop and retry
                }

                $allItems = Get-AllPages -ProcessLink $initialResponse
                return $allItems

            }
            catch {
                if ($_.Exception.Message -contains "*429*") { # Check for specific throttling error
                    $retries++
                    $retryAfter = $RetryDelaySeconds * ($retries) # Exponential backoff
                    Write-Warning "Throttled! Retry $($retries) of $($MaxRetries). Waiting $($retryAfter) seconds before retrying."
                    Start-Sleep -Seconds $retryAfter
                }
                elseif ($_.Exception.Message -contains "*401") {
                    Write-Message -FunctionName $($MyInvocation.MyCommand.Name) -Message "Unauthorized access to the Graph API." -Severity 'Error'
                    break # No point in retrying if unauthorized
                }
                 else {
                    Write-Message -FunctionName $($MyInvocation.MyCommand.Name) -Message $($_.Exception.Message) -Severity 'Error'
                     break # Break out of the retry loop for other errors
                }
            }
        } while ($retries -lt $MaxRetries)

        if ($retries -ge $MaxRetries) {
            Write-Error "Max retries reached. Failed to execute request after $($MaxRetries) attempts."
        }
    }
    <#
    .SYNOPSIS
        Invokes a request to the Microsoft Graph API.

    .DESCRIPTION
        This function sends a request to the Microsoft Graph API using the specified parameters.
        It handles authentication and constructs the appropriate headers for the request.

    .EXAMPLE
        Invoke-MSGraph -relativeUrl "applications"

        This example sends a GET request to the Microsoft Graph API to retrieve information about the applications.
#>

}