en-US/about_pt.EntraGraphUtils_GraphBatching.help.txt

TOPIC
    about_pt.EntraGraphUtils_GraphBatching

SHORT DESCRIPTION
    How and why to use Microsoft Graph JSON batching with Invoke-ptGraphBatchRequest.

LONG DESCRIPTION

  WHAT IS GRAPH JSON BATCHING?

    Microsoft Graph supports a special endpoint -- POST /{version}/$batch -- that accepts
    up to 20 individual API sub-requests bundled into a single HTTP call. Graph executes all
    sub-requests server-side and returns a single response payload containing the results of
    each one. This is called JSON batching.

    Reference: https://learn.microsoft.com/graph/json-batching


  WHY USE BATCHING?

    1. Fewer HTTP round trips
       Each HTTP call has fixed overhead: TLS handshake amortisation, network latency,
       server-side queuing. With 20 requests per batch you can reduce the number of outbound
       calls by up to 95%, which translates directly into faster scripts.

    2. Lower throttling risk
       Microsoft Graph enforces per-application and per-user throttle limits measured in
       requests per second. Batching counts as ONE request from the HTTP-call perspective,
       so you can issue far more logical Graph operations within the same rate window.
       Note: individual sub-requests inside a batch still consume service-side quota; batching
       does not bypass Graph service throttling, it only reduces client-side call frequency.

    3. Simpler parallelism without threading complexity
       Collecting results from 100 independent lookups normally requires either a loop
       (slow) or PowerShell jobs/runspaces (complex). Batching lets you fan out up to 20
       requests per call with a plain array -- no threads needed.

    4. Practical scenarios where batching shines
       - Fetch properties for a list of user UPNs or object IDs
       - Enumerate members of many groups in one pass
       - Bulk-read settings or license details for a large user set
       - Run mixed read/write operations (GET + PATCH) in one call


  HOW Invoke-ptGraphBatchRequest WORKS

    Step 1 -- Build request items with New-ptGraphRequestItem:

        $items = @(
            New-ptGraphRequestItem -id 'user1' -url '/users/alice@contoso.com'
            New-ptGraphRequestItem -id 'user2' -url '/users/bob@contoso.com'
            New-ptGraphRequestItem -id 'grp' -url '/groups' -pageSize 50
        )

    Step 2 -- Pass the array to Invoke-ptGraphBatchRequest:

        Invoke-ptGraphBatchRequest -BatchItems $items -pagination auto

    Internally the function:
    - Places all items in a thread-safe queue
    - Drains the queue in chunks of up to -BatchSize (default 20)
    - POSTs each chunk to /{ApiVersion}/$batch
    - For each sub-response:
        - HTTP 429 (rate limit): records the retry-after delay, re-queues the item, and
          sleeps for the required duration before the next batch
        - HTTP 2xx: extracts the body and outputs results (or follows @odata.nextLink
          if pagination is 'auto')
        - Other errors: writes a non-terminating error and continues


  OUTPUT MODES

    Standard (default)
        Each result object is emitted to the pipeline individually. Use with -pagination auto
        to stream all pages as objects arrive. Optionally add -EnrichOutput to attach a
        '@batchMetadata' property (requestId + OData context) to each item.

    GroupById (-GroupById switch)
        Returns a hashtable keyed by request ID. Each key maps to an array containing all
        result objects for that sub-request (pagination is always 'auto' in this mode).

            $r = Invoke-ptGraphBatchRequest -BatchItems $items -GroupById
            $r['user1'] # properties for alice
            $r['grp'] # all group objects

    RawOutput (-RawOutput switch)
        Returns the complete batch response objects from Graph without unpacking the body.
        Useful when you need HTTP status codes, headers, or response metadata.


  PAGINATION IN BATCHES

    When a sub-request returns an @odata.nextLink the function updates that item's URL
    and keeps it in the processing loop until all pages are consumed (pagination 'auto'),
    or removes the item after the first page (pagination 'none'), or removes it and emits
    a warning (default, no -pagination specified).


  DEPENDENCY ORDERING

    When one sub-request depends on the result of another within the same batch, pass the
    prerequisite request's ID to -dependsOn:

        $create = New-ptGraphRequestItem -id 'new-grp' -url '/groups' -method POST -body @{
            displayName = 'Temp Group'
            mailEnabled = $false
            securityEnabled = $true
            mailNickname = 'tempgrp'
        }
        $read = New-ptGraphRequestItem -id 'read-grp' -url '/groups/new-grp' -dependsOn 'new-grp'

        Invoke-ptGraphBatchRequest -BatchItems @($create, $read)

    Graph will not execute 'read-grp' until 'new-grp' has completed successfully.


  BATCH vs INDIVIDUAL REQUESTS -- WHEN TO USE WHICH

    Use Invoke-ptGraphBatchRequest when:
    - You have 2 or more independent requests to make
    - You are iterating over a list (users, groups, devices) and fetching properties
    - Throughput or latency matters

    Use Invoke-ptGraphRequest when:
    - You have a single request
    - Requests are sequential and each depends on the previous result
    - Simplicity is more important than throughput


  EXAMPLE: LOOK UP 40 USERS IN TWO BATCH CALLS

    $upns = 1..40 | ForEach-Object { "user$_@contoso.com" }

    $items = $upns | ForEach-Object {
        New-ptGraphRequestItem -id $_ -url "/users/$_" -Property 'id,displayName,mail'
    }

    # 40 items -> 2 batches of 20 -> 2 HTTP calls instead of 40
    $results = Invoke-ptGraphBatchRequest -BatchItems $items -GroupById

    $results.Keys | ForEach-Object { $results[$_] }

KEYWORDS
    Batch, JsonBatching, Graph, MicrosoftGraph, Throttling, Performance, Pagination