Training module · Draft
Microsoft Automation, Module 1: Graph and Azure Foundations
Learn which cloud’s endpoints a script calls, how it signs in without a secret, which permissions it asks for, and the four request patterns every Graph script has to get right, then prove each one on fixtures
Status — Draft
This page is still being written. Expect gaps and changes; it is not part of the workbook's production guidance. Last reviewed 2026-11-07.
Learning path: Microsoft Automation · Module 1 of 4 · 85 minutes · Code: examples/ms-automation · Developer workbook: Book 19, Chapter 02
Watch: the narrated deck for this module: Deck · Narrated deck (about 14 minutes, captions) · ▶ Watch · MP4 · Script · Captions.
Unit 1: Introduction
5 minutes, with the objectives and prerequisites
The books keep asking for evidence a script collects and for changes a pipeline makes: Conditional Access exported as code (Book 04, Chapter 10), device compliance read back for the access decision (Book 05, Chapter 10), and control evidence gathered on a schedule (Book 15, Chapter 08). Almost all of it goes through Microsoft Graph, and the Azure parts go through Azure Resource Manager.
Picture your first evidence collector. It works in a commercial test tenant, then fails, or sends its token to the wrong host, the day it points at a GCC High tenant. It reads the first page of users and reports a 100-user tenant. It signs in with a client secret that nobody rotates. This module covers what every such script has to get right before it does anything useful. The modules after it apply this to one product each.
| Module | Covers | Status |
|---|---|---|
| 1. Foundations (this page) | Clouds and endpoints, sign-in, permissions, tools, request patterns | Draft |
| 2. Microsoft Entra ID | Users, groups, Conditional Access, PIM, applications, logs, authentication methods | Draft |
| 3. Intune | Devices, compliance, configuration, Autopilot | Draft |
| 4. Azure Arc and Azure Resource Manager | Resource Manager versus Graph, Resource Graph, Arc machines and extensions, SQL Server, Azure Policy, product lifecycle | Draft |
| 5. Teams Phone and Teams administration | Calling, policies, the Teams PowerShell module | Planned |
| 6. Monitoring and evidence | Log Analytics and KQL, Defender, Sentinel | Planned |
The federal requirement. This module’s subject is the collector itself, so its requirements are the ones the collector’s identity has to meet. Least privilege (NIST SP 800-53 AC-6) means each script holds only the permissions its calls need. Authenticator management (IA-5) means no long-lived secret: ScubaGear’s application-credential policies, MS.AAD.5.5v1 and 5.6v1, apply to the program’s own automation too. And continuous monitoring (CA-7) depends on collectors that return complete results. BOD 25-01 requires the SCuBA assessment tools and continuous reporting for in-scope tenants. Don’t restate those here: Book 02, Appendix A has the directive and its mandatory policies, its NIST SP 800-53 control mapping has AC-6, IA-5 and CA-7, and the federal framework crosswalk lists every source.
The answer in brief
- Pick the cloud first. A Microsoft 365 GCC tenant uses the worldwide endpoints. GCC High and DoD use their own sign-in and Graph hosts, and an app has to be registered in the government tenant itself. One wrong host and the script fails, or sends a token where it shouldn’t.
- Sign in as a workload, without a secret. Use a managed identity where the script runs in Azure or on an Arc-enabled server, workload identity federation for pipelines such as GitHub Actions, and a CA-issued certificate otherwise. ScubaGear recommends blocking application passwords altogether (MS.AAD.5.5v1).
- Ask for the least-privileged application permissions each API page lists, and have an administrator with the right role consent to them.
- Use the current tools. These are the Microsoft Graph PowerShell SDK, the Python
msgraph-sdkwithazure-identity, Az PowerShell and the Azure CLI. The AzureAD and MSOnline modules are retired. - Every Graph script needs the same four patterns:
- follow
@odata.nextLink; - wait for
Retry-Afteron 429; - put at most 20 requests in a batch;
- keep the delta link to track changes.
- follow
Learning objectives
In this module, you’ll:
- Choose the sign-in host, Graph host and PowerShell environment for a commercial, GCC, GCC High or DoD tenant.
- Pick a credential for a scheduled script, in order of preference, and say who can consent to its permissions.
- Find the least-privileged application permission for a Graph call, and recognize what a narrow permission hides.
- Describe the four request patterns, and the advanced-query header, and what goes wrong without each.
- Run the example client’s cloud, permission and host checks on a laptop, in Python and PowerShell.
Prerequisites
- You can run commands in a terminal and read Python or PowerShell. You know what an access token is.
- For Lab 1: the lab tools. No tenant until Lab 2.
- Optional background: Book 10, Chapter 04 on what GCC is and isn’t.
Unit 2: Clouds and endpoints
10 minutes
Microsoft Graph and Microsoft Entra ID run as separate national cloud deployments. A script has to call the sign-in and Graph hosts of the cloud its tenant lives in.12
| Tenant | Sign-in (authority) | Microsoft Graph | Graph PowerShell -Environment |
Az PowerShell / Azure CLI |
|---|---|---|---|---|
| Commercial | https://login.microsoftonline.com |
https://graph.microsoft.com |
Global |
default |
| Microsoft 365 GCC | https://login.microsoftonline.com |
https://graph.microsoft.com |
Global |
default |
| Microsoft 365 GCC High | https://login.microsoftonline.us |
https://graph.microsoft.us |
USGov |
-Environment AzureUSGovernment / az cloud set --name AzureUSGovernment |
| Microsoft 365 DoD | https://login.microsoftonline.us |
https://dod-graph.microsoft.us |
USGovDoD |
as GCC High |
Sources: Microsoft’s Graph deployments page says a GCC environment should “continue using the worldwide endpoints”.3 The Graph PowerShell environment names come from Get-MgEnvironment.4 The Azure switches are Microsoft’s Azure Government connection guides.56 The Azure column applies to the Azure subscriptions paired with a GCC High or DoD tenant. Module 4 will cover Azure Resource Manager in detail.
What changes in a government cloud, beyond the hosts:
- The scope names the cloud. App-only tokens for GCC High use
https://graph.microsoft.us/.default, and for DoDhttps://dod-graph.microsoft.us/.default. Worldwide and GCC usehttps://graph.microsoft.com/.default, the form Microsoft’s client-credentials guide uses.78 - The Python credential needs the government authority.
azure-identitysigns in to the public cloud unless it’s givenauthority=AzureAuthorityHosts.AZURE_GOVERNMENT.9 The Graph SDK then needs the national-cloud host (NationalClouds.US_GOV).10 - Apps are registered per cloud. “Apps can only access organizational data through the national cloud endpoints”: an app registered in a commercial tenant can’t read a GCC High tenant’s data.11
- Graph Explorer isn’t supported on the GCC High, DoD or China endpoints.12 A query proved in Graph Explorer has to be retested against the government endpoint (design guidance).
- Each API page lists the clouds it works in. Every Graph API reference page has a national-cloud table. Most Entra APIs in Module 2 are available in the global service, US Government L4 and L5. Some, such as listing a user’s authentication methods, aren’t available in the China cloud.13 Check the table before relying on an API in a new cloud.
GCC uses the worldwide endpoints, but some features available in commercial tenants aren’t available in GCC. That’s a feature question, not an endpoint question; Book 10, Chapter 04 covers it, and Unit 6 covers what it means for this module.
Unit 3: Signing in as a workload
10 minutes
A scheduled script signs in as itself, not as a person: an app registration in Entra ID and its service principal in the tenant, with application permissions, using the OAuth 2.0 client-credentials flow.14 The question that matters is what the app proves its identity with. In order of preference (design guidance, from the sources cited):
| Credential | Use it when | Notes |
|---|---|---|
| Managed identity | The script runs on an Azure resource, or on an Azure Arc-enabled server | No credential to store or rotate, at no extra cost. A system-assigned identity’s service principal is created and deleted with the resource.15 Arc-enabled servers have one too.16 |
| Workload identity federation | The script runs in GitHub Actions, Kubernetes, or another platform that issues its own tokens | The app trusts the external platform’s tokens, so no secret is stored.1718 |
| Certificate | Anywhere else, such as an on-premises scheduler | Microsoft recommends “a trusted certificate issued by a certificate authority” over an application secret.19 The app signs a JWT assertion with it.20 The certificate’s lifetime follows Book 04, Chapter 05 (180 days), the app’s owner rotates it, and the choice of CA follows Book 07. |
| Client secret | Avoid | ScubaGear: application password addition should be blocked (MS.AAD.5.5v1), and lifetimes kept to 180 days (MS.AAD.5.6v1).21 |
Consent. Application permissions take effect only after tenant-wide admin consent. Microsoft Graph application permissions need a Privileged Role Administrator, the least privileged role listed; in practice this typically requires a Global Administrator, and it may not be enough (Book 04, Chapter 05). Cloud Application Administrator and Application Administrator can consent to anything except Microsoft Graph app roles.22 Plan for that approval step in the change process: it’s the moment someone with privilege decides what the script may read.
Unit 4: Permissions and tools
8 minutes
Permissions
Graph has two kinds of permission. Delegated permissions act for a signed-in user and are limited by what that user can do. Application permissions act as the app, across the tenant.23 Every API reference page lists the permissions in order from least to most privileged. Ask for the least-privileged one that does the job.2425 Two helpers in Graph PowerShell find them:
Find-MgGraphCommand -Uri '/users/{id}'lists the cmdlets for an API path and their permissions.26Find-MgGraphPermissionsearches permission names and shows their descriptions.27
Reading with a narrow permission. When a script lists members or other directory objects with a narrow permission, Graph still returns the objects it can’t fully read, but with only id and @odata.type filled in.28 Treat a null property as possibly “not permitted”, not “empty”.
Where a narrower permission exists, use it. For example, User.EnableDisableAccount.All plus User.Read.All is the least-privileged combination for enabling and disabling accounts; User.ReadWrite.All isn’t needed.29 Module 2 lists the least-privileged permission for every task it covers.
The example code keeps every call and its permission in one file, graph-calls.json, and a task can make only the calls listed for it. You’ll see that in Lab 1.
Tools
| Tool | Install | Use it for |
|---|---|---|
| Microsoft Graph PowerShell SDK | Install-Module Microsoft.Graph30 |
Interactive and scheduled administration; Invoke-MgGraphRequest for any endpoint |
| Microsoft Graph Python SDK | pip install msgraph-sdk31 |
Services and pipelines; Learn’s paging page shows a page iterator for the other SDK languages, not Python, so follow @odata.nextLink yourself32 |
azure-identity (Python) |
pip install azure-identity |
Managed identity, certificate and federated credentials, for Graph and Azure alike33 |
| Az PowerShell, Azure CLI | (Module 4) | Azure Resource Manager: subscriptions, Arc, Policy |
| AzureAD, AzureAD Preview, MSOnline | Don’t | Deprecated on March 30, 2024; Microsoft said they would work only until March 30, 2025, the announced date (the actual shut-off came later, as Book 02, Chapter 03 records), and recommends migrating to Microsoft Graph PowerShell3435 |
The example client calls the REST API directly with the standard library. That isn’t a recommendation against the SDKs, which handle paging and retries for you. It keeps every request visible, so the patterns below can be read and tested line by line (design guidance). Book 19, Chapter 02 starts from Microsoft’s own SDK snippets and explains each rule the client adds.
Unit 5: Four request patterns
12 minutes
1. Paging. Collections come back a page at a time. GET /users returns 100 users by default and up to 999 with $top, or 500 when signInActivity is selected.36 When more remain, the response carries @odata.nextLink. Call that URL, unchanged, until it stops appearing.37 A script that reads only the first page reports a tenant of 100 users and looks correct.
2. Throttling. When a client goes over a limit, Graph answers 429 Too Many Requests with a Retry-After header. Microsoft’s guidance is to wait that many seconds and retry, because retrying immediately keeps counting against the limit.38 The limits are layered, and the first one reached applies:
- Every service: 130,000 requests per 10 seconds per app, across all tenants.39
- Entra ID objects (users, groups, applications, service principals and other directory objects) use cost-based resource units instead:40
- per app and tenant: 3,500, 5,000 or 8,000 resource units per 10 seconds, for tenants under 50, 50 to 500, and over 500 users;
- writes: 3,000 per 2 minutes 30 seconds per app and tenant, and 18,000 per 5 minutes per tenant across all apps.
- What changes a request’s cost:41
$selectlowers the cost by 1;$expandraises it by 1;$topunder 20 lowers it by 1;- listing
groups/{id}/transitiveMemberscosts 5, against 3 formembers.
- Priority: a background job can send
x-ms-throttle-priority: Low. Microsoft recommends setting priority to High only for requests a user started.42
3. Batching. POST /$batch takes at most 20 requests. Each one is still evaluated, and throttled, on its own. dependsOn orders requests within the batch.43 A batch can succeed while some of its requests return 429, so check every response’s status.
4. Delta queries. Instead of re-reading everything, call an entity’s /delta function. Follow @odata.nextLink until the response carries @odata.deltaLink, then store that link. The next run calls it and gets only the changes.44 Users and groups also support $deltatoken=latest to start tracking from now without reading the full state first.45
Advanced queries. Some Entra ID queries, such as $count, $search, and some $filter and $orderby forms, need the ConsistencyLevel: eventual header, and $count too except for $search.46 Without them the request fails or returns a different result. These queries read an index that can lag slightly behind the directory.
What this means for the books
- Every evidence script states its cloud and its permissions. Book 15’s control automation should record the endpoint and the exact permissions for each collector, so a GCC High move (Book 10) is a configuration change, not a rewrite (design guidance).
- No collector uses a client secret. That puts ScubaGear’s application-credential policies (MS.AAD.5.5v1 to 5.7v1) and Book 04’s stricter rule (secrets blocked, certificates capped at 180 days) into practice for the program’s own automation.
- A collector that pages, retries and keeps delta links produces complete evidence at a predictable cost. One that doesn’t produces evidence that looks complete.
Unit 6: Where agencies are
7 minutes
The starting state this path assumes. A civilian agency at FedRAMP Moderate, most often with a Microsoft 365 GCC tenant and commercial Azure, as the developer workbook sets out. Its existing scripts are often older than the current tools: AzureAD or MSOnline cmdlets, a client secret in a scheduled task, and a host name written into the code. Some agencies, or some of their components, run a GCC High tenant with Azure Government.
Government-cloud availability for what this module relies on:
| What the module relies on | Commercial and GCC | GCC High and DoD | Source |
|---|---|---|---|
| Sign-in and Graph hosts | login.microsoftonline.com, graph.microsoft.com |
login.microsoftonline.us; graph.microsoft.us (GCC High) or dod-graph.microsoft.us (DoD) |
47 |
| App registration | Worldwide Microsoft Entra admin center | Registered in the government cloud itself | 48 |
| Graph Explorer | Supported | Not supported | 49 |
| Workload identities (managed identities, federation) | Available | Microsoft’s Azure Government roadmap lists Workload Identities as generally available at FedRAMP High, DoD IL4 and IL5 | 50 |
| A managed identity as an app’s federated credential | Audience api://AzureADTokenExchange |
Audience api://AzureADTokenExchangeUSGov (Entra ID for US Government) |
51 |
| Each Graph API | The page’s national cloud table | The page’s national cloud table: check it before relying on an API | 52 |
GCC needs no endpoint change, but it can lack features that commercial tenants have; Book 10 keeps that list (Chapter 04).
Interim paths (design guidance):
- Scripts still on AzureAD or MSOnline. Those modules are past their retirement date.53 Rewrite each one on Microsoft Graph PowerShell, using Microsoft’s migration guide,54 and use the rewrite to move it to app-only sign-in with its own least-privileged permissions.
- A collector that has to stay on premises for now. Use a CA-issued certificate, not a secret,55 and keep its lifetime to Book 04’s 180-day policy (Chapter 05), with the app’s owner rotating it and the CA chosen per Book 07. Move it to a managed identity on an Arc-enabled server when the server is onboarded.56
- A move from GCC to GCC High. Register a new app in the government tenant,57 and change the cloud name in the collector’s configuration. If the code names a host anywhere, that’s the defect to fix first.
Unit 7: Exercise: Lab 1 (fixtures, no tenant)
25 minutes
Every command in this lab, in order, from examples/ms-automation. Each step below says what it does and what to look for.
In a POSIX shell (Git Bash on Windows):
# Step 1
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import endpoints, scope_for; print(endpoints('gcc')); print(endpoints('gcchigh')); print(scope_for('gcc', 'arm')); print(scope_for('gcchigh'))"
# Step 2
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import endpoints; endpoints('GCCHigh')"
# Step 3
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import load_calls, permissions_for; print(permissions_for(load_calls('stale-users')))"
# Step 4
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import GraphClient, load_calls; GraphClient('gcc', lambda s: 't', calls=load_calls('ca-export')).request('GET', '/users')"
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import GraphClient; GraphClient('gcchigh', lambda s: 't').request('GET', 'https://graph.microsoft.com/v1.0/users')"
# Step 5
python -m pytest -q -p no:cacheprovider tests/python/test_graphkit_and_tasks.py -k "paging or next_link or 429 or retries or retry_after or batch or delta or advanced"
# Step 5
awk '/^def /{p = /test_batch_chunks_of_20_and_retries_throttled_items|test_delta_returns_items_and_new_link/} p' tests/python/test_graphkit_and_tasks.pyIn PowerShell 7:
# Step 6
Import-Module ./powershell/FmwGraph.psm1
(Get-FmwCloud gcchigh).Login
(Get-FmwCloud gcchigh).Graph
(Get-FmwCloud gcc).Arm
Get-FmwCallPermission -Task stale-users
Assert-FmwGraphCall -Method GET -Uri 'https://graph.microsoft.com/v1.0/users' -Cloud gcchigh
# Step 6
(Get-FmwCloud GCCHigh).Graph
Get-FmwCloud usgovIn a POSIX shell (Git Bash on Windows):
# Step 7
python -m pytest -q -p no:cacheprovider tests/python
pwsh -NoProfile -Command "Invoke-Pester -Path tests/powershell"You prove, on a laptop, that the example client picks the right cloud, refuses the wrong one, asks only for what a task needs, and pages, retries, batches and tracks deltas the way Microsoft documents. Work in examples/ms-automation. The developer workbook’s Chapter 02, Lab 1 runs the same client against Microsoft’s own SDK snippets; do it after this lab if you build Graph clients.
Print the endpoints for GCC and GCC High, and the scopes for Resource Manager and Graph.
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import endpoints, scope_for; print(endpoints('gcc')); print(endpoints('gcchigh')); print(scope_for('gcc', 'arm')); print(scope_for('gcchigh'))"Expected output:
{'login': 'https://login.microsoftonline.com', 'graph': 'https://graph.microsoft.com', 'arm': 'https://management.azure.com', 'ps_env': 'Global', 'azure_env': 'AzureCloud'} {'login': 'https://login.microsoftonline.us', 'graph': 'https://graph.microsoft.us', 'arm': 'https://management.usgovcloudapi.net', 'ps_env': 'USGov', 'azure_env': 'AzureUSGovernment'} https://management.azure.com/.default https://graph.microsoft.us/.defaultGCC has no
.ushost. Compare each value with the table in Unit 2.Ask for a cloud name the client doesn’t know.
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import endpoints; endpoints('GCCHigh')"The last line is
ValueError: unknown cloud 'GCCHigh'; one of ['dod', 'gcc', 'gcchigh', 'global']. An unknown name is an error, never a default.List the permissions a task needs, from the calls it declares.
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import load_calls, permissions_for; print(permissions_for(load_calls('stale-users')))"Expected:
['AuditLog.Read.All', 'User.Read.All'].Make a call the task doesn’t declare, then send a GCC High token to the worldwide host.
python -c "import sys; sys.path.insert(0, 'python'); from graphkit import GraphClient, load_calls; GraphClient('gcc', lambda s: 't', calls=load_calls('ca-export')).request('GET', '/users')" python -c "import sys; sys.path.insert(0, 'python'); from graphkit import GraphClient; GraphClient('gcchigh', lambda s: 't').request('GET', 'https://graph.microsoft.com/v1.0/users')"The first ends
PermissionError: undeclared call: GET /v1.0/users; add it to graph-calls.json with its permission. The second endsValueError: refusing to send the token to https://graph.microsoft.com/v1.0/users: not https://graph.microsoft.us. Nothing was sent in either case: the token here is the fake stringt.Run the tests for the four request patterns and the advanced-query header.
python -m pytest -q -p no:cacheprovider tests/python/test_graphkit_and_tasks.py -k "paging or next_link or 429 or retries or retry_after or batch or delta or advanced"Expected:
9 passed, 11 deselected. Now print two of those tests,test_batch_chunks_of_20_and_retries_throttled_itemsandtest_delta_returns_items_and_new_link:awk '/^def /{p = /test_batch_chunks_of_20_and_retries_throttled_items|test_delta_returns_items_and_new_link/} p' tests/python/test_graphkit_and_tasks.pyEach one feeds the client a fake transport and checks exactly what it sent.
The same rules in PowerShell. Start
pwshinexamples/ms-automation, then:Import-Module ./powershell/FmwGraph.psm1 (Get-FmwCloud gcchigh).Login (Get-FmwCloud gcchigh).Graph (Get-FmwCloud gcc).Arm Get-FmwCallPermission -Task stale-users Assert-FmwGraphCall -Method GET -Uri 'https://graph.microsoft.com/v1.0/users' -Cloud gcchighExpected output:
https://login.microsoftonline.us,https://graph.microsoft.us,https://management.azure.com, thenAuditLog.Read.AllandUser.Read.Allon two lines, then an error:Refusing to send the token to https://graph.microsoft.com/v1.0/users: not https://graph.microsoft.us. In PowerShell the cloud name is checked byValidateSet, which ignores case, so the first of these works there and the second fails:(Get-FmwCloud GCCHigh).Graph Get-FmwCloud usgovRun the kit’s full test suites.
python -m pytest -q -p no:cacheprovider tests/python pwsh -NoProfile -Command "Invoke-Pester -Path tests/powershell"Expected:
94 passed, thenTests Passed: 56, Failed: 0, Skipped: 0. The counts include Module 4’s Arc tests (24 in Python, 12 in Pester).
Check your work: for any tenant, you can name the hosts, the scope and the PowerShell environment, and show that the client refuses the wrong one.
Unit 8: Exercise: Lab 2 (your test tenant)
Not timed. Not run by the authors.
Every command in this lab, in order. Each step below says what it does and what to look for.
pip install azure-identity
python python/entra_tasks.py --cloud gcc --tenant <tenant-id> --client <app-id> --cert app.pem ca-export --out ca
rm -rf caYou register an app with one permission, run one read-only task, and remove the app. (The chapter’s later steps, which show the token check and the wrong-cloud refusal, add a second permission and aren’t part of this lab.) Follow the developer workbook’s Chapter 02, Lab 2, which uses the Conditional Access export because it needs one permission.
You need: a test tenant in the worldwide or GCC cloud, never production, with fictional data; an administrator who can grant tenant-wide admin consent to a Microsoft Graph application permission, which is a Privileged Role Administrator, and in practice typically a Global Administrator (Unit 3); Python with the
azure-identitypackage (the run below installs it), or Microsoft Graph PowerShell.You’ll replace:
<tenant-id>(the test tenant’s ID),<app-id>(the app’s application (client) ID);app.pemis the PEM file with the app’s certificate and private key.The app registration: a certificate credential, no secret, and the application permission
Policy.Read.All, with admin consent. Nothing else.The run, from
examples/ms-automation. It only reads:pip install azure-identity python python/entra_tasks.py --cloud gcc --tenant <tenant-id> --client <app-id> --cert app.pem ca-export --out caBack it out: remove the permissions, delete the app registration and its certificate, and delete the
cafolder, which holds the tenant’s policies. Step 7 of the chapter’s Lab 2 lists each one.rm -rf ca
Unit 9: Knowledge check
5 minutes
- Your agency’s tenant is Microsoft 365 GCC. Which Graph host does your collector call?
https://graph.microsoft.ushttps://graph.microsoft.comhttps://dod-graph.microsoft.us
- A collector runs nightly on an on-premises scheduler that isn’t connected to Azure Arc. Which credential should it use?
- A client secret with a 180-day lifetime.
- A managed identity.
- A certificate issued by a certificate authority.
- Which role can grant tenant-wide admin consent to a Microsoft Graph application permission?
- Application Administrator.
- Privileged Role Administrator.
- Cloud Application Administrator.
- A script lists users with
$top=999and gets 999 back. What must it do before it reports a count?- Nothing: 999 is the maximum, so that’s the tenant.
- Follow
@odata.nextLinkuntil the response no longer carries one. - Repeat the request with
ConsistencyLevel: eventual.
- A batch returns 200, but two of its 20 requests returned 429. What should the client do?
- Treat the batch as successful.
- Retry the whole batch at once.
- Check each response’s status and retry the throttled requests after their wait.
- b. A GCC tenant uses the worldwide endpoints. See Unit 2: Clouds and endpoints.
- c. Microsoft recommends a CA-issued certificate over a secret, and a managed identity needs an Azure resource or an Arc-enabled server. See Unit 3: Signing in as a workload.
- b. The two application administrator roles can consent to anything except Microsoft Graph app roles. See consent in Unit 3.
- b. More pages may remain; a script that reads only the first page looks correct and isn’t. See pattern 1 in Unit 5.
- c. Each request in a batch is throttled on its own, so a batch can succeed while some of its requests return 429. See pattern 3 in Unit 5, and the batch test in Lab 1, step 5.
Unit 10: Summary
3 minutes
You learned which hosts each cloud uses and why GCC is the worldwide service, how a script signs in without a secret and who consents to its permissions, how to find the least-privileged permission, and the four patterns that make a collector’s results complete. In Lab 1 you saw the example client refuse an unknown cloud, an undeclared call and the wrong host, in Python and PowerShell.
Evidence an ISSO keeps from this module: for each collector, its cloud, its endpoint, its app registration, its credential type (never a secret) and the exact permissions with the admin-consent record; graph-calls.json and its tests in the repository, which tie every call to its permission; and the record that retired modules are gone. Those support AC-6, IA-5 and CA-7 as Book 02, Appendix A maps them; the agency’s assessor decides whether a control is met. Before shipping a collector, work through the developer workbook’s Chapter 02 checklist.
Status and review
Draft. Every claim was checked against Microsoft Learn and the ScubaGear baseline on October 25, 2026. The government-cloud availability rows for workload identities and the federated-credential audience were added on November 1, 2026 and carry their own sources. Inferences and design guidance are labeled. The example client is tested against fixtures only, and the Lab 1 commands were run on November 1, 2026; the output shown is what they printed. The verification log lists the November 1 additions.
To move this page to In review: - a reviewer confirms the endpoint table; - someone runs the example client against a test tenant in each cloud the program uses.
To move it to Proved: record a GCC run and, if the program has one, a GCC High run here. Comments and corrections are welcome as issues on GitHub.
Related: Module 2: Microsoft Entra ID, Module 3: Intune, Module 4: Azure Arc, the Microsoft practice crosswalk, Book 04 — Access & Privilege and Book 15 — Day-2 Operations.
Footnotes
Microsoft Learn, “Microsoft Graph national cloud deployments” (updated January 30, 2025), https://learn.microsoft.com/en-us/graph/deployments, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Entra authentication & national clouds” (updated January 15, 2025), https://learn.microsoft.com/en-us/entra/identity-platform/authentication-national-cloud, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph national cloud deployments” (updated January 30, 2025), https://learn.microsoft.com/en-us/graph/deployments, accessed October 25, 2026.↩︎
Microsoft Learn, “Use Microsoft Graph PowerShell authentication commands” (Get-MgEnvironment; updated July 10, 2025), https://learn.microsoft.com/en-us/powershell/microsoftgraph/authentication-commands, accessed October 25, 2026.↩︎
Microsoft Learn, “Connect to Azure Government with PowerShell” (updated January 18, 2023), https://learn.microsoft.com/en-us/azure/azure-government/documentation-government-get-started-connect-with-ps, accessed October 25, 2026.↩︎
Microsoft Learn, “Connect to Azure Government with Azure CLI” (updated March 9, 2021), https://learn.microsoft.com/en-us/azure/azure-government/documentation-government-get-started-connect-with-cli, accessed October 25, 2026.↩︎
Microsoft Learn, “Access national cloud deployments with the Microsoft Graph SDKs” (updated November 7, 2024), https://learn.microsoft.com/en-us/graph/sdks/national-clouds, accessed October 25, 2026.↩︎
Microsoft Learn, “Get access without a user” (updated August 29, 2025), https://learn.microsoft.com/en-us/graph/auth-v2-service, accessed October 25, 2026.↩︎
Microsoft Learn, “Azure Identity client library for Python” (updated October 1, 2026), https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme, accessed October 25, 2026.↩︎
Microsoft Learn, “Access national cloud deployments with the Microsoft Graph SDKs” (updated November 7, 2024), https://learn.microsoft.com/en-us/graph/sdks/national-clouds, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph national cloud deployments” (updated January 30, 2025), https://learn.microsoft.com/en-us/graph/deployments, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph national cloud deployments” (updated January 30, 2025), https://learn.microsoft.com/en-us/graph/deployments, accessed October 25, 2026.↩︎
Microsoft Learn, “List methods” (authentication methods; national cloud table; updated September 13, 2024), https://learn.microsoft.com/en-us/graph/api/authentication-list-methods, accessed October 25, 2026.↩︎
Microsoft Learn, “Get access without a user” (updated August 29, 2025), https://learn.microsoft.com/en-us/graph/auth-v2-service, accessed October 25, 2026.↩︎
Microsoft Learn, “Managed identities for Azure resources” (updated August 19, 2025), https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview, accessed October 25, 2026.↩︎
Microsoft Learn, “Access Azure resources with managed identity on Azure Arc-enabled servers” (updated February 5, 2026), https://learn.microsoft.com/en-us/azure/azure-arc/servers/managed-identity-authentication, accessed October 25, 2026.↩︎
Microsoft Learn, “Workload identity federation” (updated April 9, 2025), https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation, accessed October 25, 2026.↩︎
Microsoft Learn, “Create a trust relationship between an app and an external identity provider” (updated December 13, 2024), https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-create-trust, accessed October 25, 2026.↩︎
Microsoft Learn, “Register a Microsoft Entra app and create a service principal” (updated May 26, 2025), https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft identity platform certificate credentials” (updated January 4, 2025), https://learn.microsoft.com/en-us/entra/identity-platform/certificate-credentials, accessed October 25, 2026.↩︎
CISA, ScubaGear Microsoft Entra ID baseline (
aad.md, released with v2.0.0), policies MS.AAD.5.5v1 and MS.AAD.5.6v1, https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/aad.md, accessed October 25, 2026.↩︎Microsoft Learn, “Grant tenant-wide admin consent to an application” (updated March 25, 2025), https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/grant-admin-consent, accessed October 25, 2026.↩︎
Microsoft Learn, “Overview of Microsoft Graph permissions” (updated December 26, 2025), https://learn.microsoft.com/en-us/graph/permissions-overview, accessed October 25, 2026.↩︎
Microsoft Learn, “Overview of Microsoft Graph permissions” (updated December 26, 2025), https://learn.microsoft.com/en-us/graph/permissions-overview, accessed October 25, 2026.↩︎
Microsoft Learn, “Best practices for working with Microsoft Graph” (updated November 7, 2024), https://learn.microsoft.com/en-us/graph/best-practices-concept, accessed October 25, 2026.↩︎
Microsoft Learn, “Use Find-MgGraphCommand” (updated January 22, 2025), https://learn.microsoft.com/en-us/powershell/microsoftgraph/find-mg-graph-command, accessed October 25, 2026.↩︎
Microsoft Learn, “Use Find-MgGraphPermission” (updated January 22, 2025), https://learn.microsoft.com/en-us/powershell/microsoftgraph/find-mg-graph-permission, accessed October 25, 2026.↩︎
Microsoft Learn, “Overview of Microsoft Graph permissions” (updated December 26, 2025), https://learn.microsoft.com/en-us/graph/permissions-overview, accessed October 25, 2026.↩︎
Microsoft Learn, “List users” (permissions, scenario permissions and page sizes; updated May 16, 2025), https://learn.microsoft.com/en-us/graph/api/user-list, accessed October 25, 2026.↩︎
Microsoft Learn, “Install a Microsoft Graph SDK” (updated November 7, 2024), https://learn.microsoft.com/en-us/graph/sdks/sdk-installation, accessed October 25, 2026.↩︎
Microsoft Learn, “Install a Microsoft Graph SDK” (updated November 7, 2024), https://learn.microsoft.com/en-us/graph/sdks/sdk-installation, accessed October 25, 2026.↩︎
Microsoft Learn, “Page through a collection using the Microsoft Graph SDKs” (updated November 7, 2024), https://learn.microsoft.com/en-us/graph/sdks/paging, accessed October 25, 2026.↩︎
Microsoft Learn, “Azure Identity client library for Python” (updated October 1, 2026), https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme, accessed October 25, 2026.↩︎
Microsoft Learn, “Azure AD PowerShell overview” (deprecation notice; updated April 25, 2024), https://learn.microsoft.com/en-us/powershell/azure/active-directory/overview, accessed October 25, 2026.↩︎
Microsoft Learn, “Upgrade from Azure AD PowerShell to Microsoft Graph PowerShell” (updated October 28, 2024), https://learn.microsoft.com/en-us/powershell/microsoftgraph/migration-steps, accessed October 25, 2026.↩︎
Microsoft Learn, “List users” (permissions, scenario permissions and page sizes; updated May 16, 2025), https://learn.microsoft.com/en-us/graph/api/user-list, accessed October 25, 2026.↩︎
Microsoft Learn, “Paging Microsoft Graph data in your app” (updated April 2, 2025), https://learn.microsoft.com/en-us/graph/paging, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph throttling guidance” (updated January 14, 2025), https://learn.microsoft.com/en-us/graph/throttling, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph service-specific throttling limits” (global limit, identity and access limits, request costs,
x-ms-throttle-priority; updated January 14, 2025), https://learn.microsoft.com/en-us/graph/throttling-limits, accessed October 25, 2026.↩︎Microsoft Learn, “Microsoft Graph service-specific throttling limits” (global limit, identity and access limits, request costs,
x-ms-throttle-priority; updated January 14, 2025), https://learn.microsoft.com/en-us/graph/throttling-limits, accessed October 25, 2026.↩︎Microsoft Learn, “Microsoft Graph service-specific throttling limits” (global limit, identity and access limits, request costs,
x-ms-throttle-priority; updated January 14, 2025), https://learn.microsoft.com/en-us/graph/throttling-limits, accessed October 25, 2026.↩︎Microsoft Learn, “Microsoft Graph service-specific throttling limits” (global limit, identity and access limits, request costs,
x-ms-throttle-priority; updated January 14, 2025), https://learn.microsoft.com/en-us/graph/throttling-limits, accessed October 25, 2026.↩︎Microsoft Learn, “Combine multiple HTTP requests using JSON batching” (updated February 21, 2025), https://learn.microsoft.com/en-us/graph/json-batching, accessed October 25, 2026.↩︎
Microsoft Learn, “Use delta query to track changes in Microsoft Graph data” (updated January 15, 2025), https://learn.microsoft.com/en-us/graph/delta-query-overview, accessed October 25, 2026.↩︎
Microsoft Learn, “Use delta query to track changes in Microsoft Graph data” (updated January 15, 2025), https://learn.microsoft.com/en-us/graph/delta-query-overview, accessed October 25, 2026.↩︎
Microsoft Learn, “Advanced query capabilities on Microsoft Entra ID objects” (updated August 29, 2025), https://learn.microsoft.com/en-us/graph/aad-advanced-queries, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph national cloud deployments” (updated January 30, 2025), https://learn.microsoft.com/en-us/graph/deployments, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph national cloud deployments” (updated January 30, 2025), https://learn.microsoft.com/en-us/graph/deployments, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph national cloud deployments” (updated January 30, 2025), https://learn.microsoft.com/en-us/graph/deployments, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Azure Government Product General Availability (GA) Roadmap” (Workload Identities row: generally available at FedRAMP High, DoD IL4 and IL5), https://learn.microsoft.com/en-us/azure/azure-government/documentation-government-product-roadmap, read November 1, 2026.↩︎
Microsoft Learn, “Configure an application to trust a managed identity” (audience values for the global service and for Entra ID for US Government), https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-config-app-trust-managed-identity, read November 1, 2026.↩︎
Microsoft Learn, “List methods” (authentication methods; national cloud table; updated September 13, 2024), https://learn.microsoft.com/en-us/graph/api/authentication-list-methods, accessed October 25, 2026.↩︎
Microsoft Learn, “Azure AD PowerShell overview” (deprecation notice; updated April 25, 2024), https://learn.microsoft.com/en-us/powershell/azure/active-directory/overview, accessed October 25, 2026.↩︎
Microsoft Learn, “Upgrade from Azure AD PowerShell to Microsoft Graph PowerShell” (updated October 28, 2024), https://learn.microsoft.com/en-us/powershell/microsoftgraph/migration-steps, accessed October 25, 2026.↩︎
Microsoft Learn, “Register a Microsoft Entra app and create a service principal” (updated May 26, 2025), https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal, accessed October 25, 2026.↩︎
Microsoft Learn, “Access Azure resources with managed identity on Azure Arc-enabled servers” (updated February 5, 2026), https://learn.microsoft.com/en-us/azure/azure-arc/servers/managed-identity-authentication, accessed October 25, 2026.↩︎
Microsoft Learn, “Microsoft Graph national cloud deployments” (updated January 30, 2025), https://learn.microsoft.com/en-us/graph/deployments, accessed October 25, 2026.↩︎