Mojo UpDocs
Administration

Microsoft setup commands

Every command to run in your Microsoft tenant for Agent 365, Microsoft 365 grounding, Purview and Sentinel, in order, with the role ids filled in.

Every command an organisation runs in its own Microsoft tenant for AIOE's Microsoft features, in order: Agent 365 (Microsoft Agent 365), Microsoft 365 grounding through Work IQ (Memory), Purview (Microsoft Purview) and Sentinel. Run them as a Global Administrator, in a shell signed in to the organisation's tenant (az login --tenant <tenant id>; check with az account show). Enterprise edition only.

Two rules Microsoft enforces shape what follows:

  • A blueprint is barred from some calls whatever it holds. Graph answers it 403 UnknownError on the Agent 365 registry and Purview's labels, refuses it file permissions outright, and refuses it app-only observability tokens (AADSTS82001). AIOE makes those calls as the AIOE API application (the registration people sign in to AIOE with) or as an agent identity, so some roles go on more than one principal.
  • Assign roles straight to service principals. The blueprint's registration declares no permissions, so its admin-consent page fails with AADSTS1003031. An assignment needs no consent step. A new role only reaches tokens minted after it: allow a few minutes, then use the panel's Try again or Connect, which ask for fresh tokens.

0. The ids

TENANT=$(az account show --query tenantId -o tsv)
GRAPH_SP=$(az ad sp show --id 00000003-0000-0000-c000-000000000000 --query id -o tsv)   # Microsoft Graph in this tenant

# The AIOE API application: the console shows it as "API scope" under Settings (api://<id>/...).
API_APP=<AIOE API application (client) id>
API_SP=$(az ad sp show --id $API_APP --query id -o tsv)

# The deployment's managed identity (Azure): its principal (object) id.
MI_PRINCIPAL=$(az identity show -g <resource group> -n <identity name> --query principalId -o tsv)

# The person accountable for the agents (sponsor and owner).
SPONSOR=$(az ad user show --id <their UPN> --query id -o tsv)

# One helper for every application role below.
grant() {  # grant <principal sp id> <resource sp id> <app role id>
  az rest --method POST \
    --url "https://graph.microsoft.com/v1.0/servicePrincipals/$1/appRoleAssignments" \
    --body "{\"principalId\":\"$1\",\"resourceId\":\"$2\",\"appRoleId\":\"$3\"}" \
    --query appRoleId -o tsv
}

The application role ids are Microsoft's and the same in every tenant:

RoleResourceId
AgentRegistration.ReadWrite.AllMicrosoft Graph39fb8c64-7bd3-4107-8515-14d6e55ddda4
InformationProtectionPolicy.Read.AllMicrosoft Graph19da66cb-0fb0-4390-b071-ebc76a349482
ProtectionScopes.Compute.UserMicrosoft Graphfe696d63-5e1f-4515-8232-cccc316903c6
Content.Process.UserMicrosoft Graph24ceb246-ad29-4680-90b4-3e91ffad15eb
ContentActivity.WriteMicrosoft Graph2932e07a-3c29-44e4-bb36-6d0fc176387f
Files.ReadWrite.AllMicrosoft Graph75359482-378d-4052-8f01-80520e7db3cd
Agent365.Observability.OtelWriteAgent 365 observability (app 9b975845-388f-4429-889e-eab1ef63949c, shown as "maven-prod")8f71190c-00c8-461d-a63b-f74abde9ba52

1. Agent 365: the blueprint

Create it in the Entra admin centre (Entra ID, Agents, Agent blueprints, New agent blueprint), or:

BLUEPRINT_APP=$(az rest --method POST --url "https://graph.microsoft.com/v1.0/applications/microsoft.graph.agentIdentityBlueprint" \
  --headers "OData-Version=4.0" \
  --body "{\"displayName\":\"AIOE agents\",\"sponsors@odata.bind\":[\"https://graph.microsoft.com/v1.0/users/$SPONSOR\"],\"owners@odata.bind\":[\"https://graph.microsoft.com/v1.0/users/$SPONSOR\"]}" \
  --query appId -o tsv)
az rest --method POST --url "https://graph.microsoft.com/v1.0/serviceprincipals/microsoft.graph.agentIdentityBlueprintPrincipal" \
  --headers "OData-Version=4.0" --body "{\"appId\":\"$BLUEPRINT_APP\"}"
BLUEPRINT_SP=$(az ad sp show --id $BLUEPRINT_APP --query id -o tsv)

Give it the deployment's managed identity as its credential (no secret anywhere):

az rest --method POST \
  --url "https://graph.microsoft.com/v1.0/applications(appId='$BLUEPRINT_APP')/federatedIdentityCredentials" \
  --headers "OData-Version=4.0" \
  --body "{\"name\":\"aioe-prod\",\"issuer\":\"https://login.microsoftonline.com/$TENANT/v2.0\",\"subject\":\"$MI_PRINCIPAL\",\"audiences\":[\"api://AzureADTokenExchange\"]}"

Outside Azure, add a client secret instead (Entra admin centre, the blueprint, Certificates and secrets; needs the Agent ID Administrator role) and paste it into the panel.

2. Agent 365: the registry

Cards go as the AIOE API application, which the registry then records as their manager:

grant $API_SP $GRAPH_SP 39fb8c64-7bd3-4107-8515-14d6e55ddda4        # AgentRegistration.ReadWrite.All
grant $BLUEPRINT_SP $GRAPH_SP 39fb8c64-7bd3-4107-8515-14d6e55ddda4  # the same, for the blueprint's first try

Then in the console: Settings, Microsoft Agent 365, the blueprint's application id, This deployment's managed identity, Connect. Create an enterprise team on the Portfolio page; each agent member gets an identity and a card.

3. Agent 365: the licence row (optional)

A registered agent exports its runs without a further role. Only the panel's licence question needs the observability role, on each agent identity (the ids are shown on each member in the panel):

OBS_SP=$(az ad sp show --id 9b975845-388f-4429-889e-eab1ef63949c --query id -o tsv)
for AGENT in <agent identity id> <agent identity id>; do
  grant $AGENT $OBS_SP 8f71190c-00c8-461d-a63b-f74abde9ba52
done

4. Microsoft 365 grounding (Work IQ)

az ad sp create --id fdcc1f02-fc51-4226-8753-f668596af7f7          # Work IQ's service principal, once per tenant
az ad app permission add --id $API_APP --api fdcc1f02-fc51-4226-8753-f668596af7f7 \
  --api-permissions 0b1715fd-f4bf-4c63-b16d-5be31f9847c2=Scope       # WorkIQAgent.Ask (delegated)
az ad app permission admin-consent --id $API_APP

Set a Copilot Credits spending policy in the Microsoft 365 admin centre, then Settings, Microsoft 365 Grounding, Switch on.

5. Purview: labels, verdicts and activity

The four on both principals; the platform tries the blueprint and falls back to the API application:

for ROLE in 19da66cb-0fb0-4390-b071-ebc76a349482 fe696d63-5e1f-4515-8232-cccc316903c6 \
            24ceb246-ad29-4680-90b4-3e91ffad15eb 2932e07a-3c29-44e4-bb36-6d0fc176387f; do
  grant $BLUEPRINT_SP $GRAPH_SP $ROLE
  grant $API_SP $GRAPH_SP $ROLE
done

Then Settings, Microsoft Purview, Connect, and map the labels.

6. Purview: encrypting labels through SharePoint (optional)

grant $API_SP $GRAPH_SP 75359482-378d-4052-8f01-80520e7db3cd        # Files.ReadWrite.All (the blueprint is refused it)

# Microsoft meters assignSensitivityLabel: link the API application to a subscription in the same tenant.
az provider register --namespace Microsoft.GraphServices
az provider show -n Microsoft.GraphServices --query registrationState -o tsv   # repeat until "Registered"
az rest --method PUT \
  --url "https://management.azure.com/subscriptions/$(az account show --query id -o tsv)/resourceGroups/<resource group>/providers/Microsoft.GraphServices/accounts/aioe-api-graph-billing?api-version=2023-04-13" \
  --body "{\"location\":\"global\",\"properties\":{\"appId\":\"$API_APP\"}}"

Authorization_IdentityNotFound on the last call means the provider is still registering: wait and repeat it. Then tick Offer the SharePoint route in the panel and set a site.

7. Purview: Ask Purview itself (optional)

Turn on Purview pay-as-you-go once: the Purview portal, the rocket icon at the top right (or Settings, Account details), Get Started, a subscription and resource group in the same tenant. It takes a few hours.

The DLP policy is PowerShell only (the portal's policies cover Microsoft 365, not an app like this). Windows PowerShell, or PowerShell 7 (pwsh) anywhere; not bash:

Install-Module ExchangeOnlineManagement -Scope CurrentUser
Connect-IPPSSession -UserPrincipalName <admin UPN>       # in WSL or a terminal without a browser: Connect-IPPSSession -Device

$appId = "<blueprint application id>"
$locations = "[{`"Workload`":`"Applications`",`"Location`":`"$appId`",`"LocationDisplayName`":`"Mojo Up AI Workbench`",`"LocationSource`":`"Entra`",`"LocationType`":`"Individual`",`"Inclusions`":[{`"Type`":`"Tenant`",`"Identity`":`"All`"}]}]"
New-DlpCompliancePolicy -Name "AI Workbench prompts" -Mode Enable -Locations $locations -EnforcementPlanes @("Application")
New-DlpComplianceRule -Name "Block credentials in prompts" -Policy "AI Workbench prompts" `
  -ContentContainsSensitiveInformation @{Name = "All Credential Types"} `
  -RestrictAccess @(@{setting = "UploadText"; value = "Block"}) -GenerateAlert $true

Get-DlpCompliancePolicy "AI Workbench prompts" | Format-List Name, Mode, Locations   # check

Allow an hour, then check it with Try a prompt in the panel (under Ask Purview itself): paste a fake credential and expect "In scope of a DLP policy" and "Blocked", naming the policy. Then set Ask Purview itself to "Prompts to hosted models". Optionally, in DSPM for AI (classic), Recommendations, Secure interactions from enterprise apps.

8. Sentinel (optional)

Deploy the table, data collection rule and detections from AI Workbench's docs/integrations/microsoft-sentinel, then let the blueprint write to the rule:

DCR_ID=$(az monitor data-collection rule show -g <resource group> -n <rule name> --query id -o tsv)
az role assignment create --assignee-object-id $BLUEPRINT_SP --assignee-principal-type ServicePrincipal \
  --role "Monitoring Metrics Publisher" --scope $DCR_ID

Then Settings, Microsoft Sentinel: the logs ingestion endpoint and the rule's immutable id.

Check what is granted

for SP in $BLUEPRINT_SP $API_SP; do
  echo "== $SP"
  az rest --method GET --url "https://graph.microsoft.com/v1.0/servicePrincipals/$SP/appRoleAssignments" \
    --query "value[].{role:appRoleId,resource:resourceDisplayName}" -o table
done

When something is refused

MessageMeaningWhat to do
AADSTS1003031 on the consent pageThe blueprint's registration declares no permissionsUse the grant commands; no consent page is needed
cannot be granted to agent identity blueprint principalsA role Entra never gives a blueprint (files)Grant it to the AIOE API application
UnknownError (Graph answered 403) as the blueprintGraph bars the blueprint from that endpointExpected: AIOE retries as the API application; grant the role there
The same 403 as the API application, minutes after a grantThe token predates the grantWait a few minutes, then Try again
You do not have permission to create an agent registration managed by another AppIdA card naming another app as its managerFixed in AIOE 0.5.2: update
AADSTS82001An agentic application asked for an app-only observability tokenExpected: AIOE asks as an agent identity
Licence row: Microsoft did not answer (403)The agent identities lack the observability roleOptional: step 3
Install-Module: command not foundPowerShell commands run in bashRun them in PowerShell
Authorization_IdentityNotFound on the billing accountMicrosoft.GraphServices is still registeringWait for "Registered", repeat

On this page