Skip to main content
Connectors

Bring your own Microsoft app registration: the provisioning script and permission tiers

The PowerShell script that registers your organization's own multitenant Entra app for the Microsoft Graph and Azure connectors, the redirect URLs it registers, and the delegated permission list for the Full, Standard and Read-only tiers.

Written By Christopher Scaminaci

Last updated 15 days ago

Some organizations prefer to consent to an application they own: their name on the consent screen, their control over the permission list, their secret to rotate. StackJack supports that for the Microsoft Graph and Microsoft Azure connectors. This page carries the provisioning script and the delegated permission list for each tier.

What the script does

Run it signed in to your own Entra tenant as a Global Administrator or Application Administrator. It creates a multitenant app registration that carries StackJack's three redirect URLs (Web platform), requests the delegated permission set for the tier you pick, and prints the Application (client) ID and a client secret once at the end. Paste those into StackJack under Connectors, Microsoft Graph (or Microsoft Azure), Advanced, use your own app registration, then use Connect with Microsoft.

Prerequisites

  • PowerShell 7 with the Az.Accounts module (Install-Module Az.Accounts).
  • Connect-AzAccount -TenantId <your tenant id> as Global Administrator or Application Administrator.
  • Your StackJack Portal host: portal.stackjack.io for the US region, portal-eu.stackjack.io for the EU region.

Run it

.\provision-byo-microsoft-appreg.ps1 -PortalHost portal.stackjack.io -PermissionTier Full

Parameters: -PortalHost (required), -PermissionTier Full | Standard | Read (default Full), -DisplayName (default "StackJack Connector"), -AppId (update an existing registration instead of creating one), -SecretYears (1 to 5, default 2).

The registration carries these redirect URLs for the US region (replace the host for the EU region):

  • https://portal.stackjack.io/connector-callback/msgraph
  • https://portal.stackjack.io/connector-callback/azure
  • https://portal.stackjack.io/consent-complete

The third one is required: the per-customer-tenant consent links StackJack generates for GDAP need it, or Microsoft answers with a reply-address error.

Notes on the -AppId update path. The update adds the three redirect URLs for the -PortalHost you pass and keeps every Web redirect URL already registered on the app, so you can run it once per Portal host your organization signs in to, and it is safe on an app that carries redirect URLs of your own. Three things are not additive: a re-run adds a new client secret next to the old one (remove superseded secrets in the Entra portal), the requested permission list is replaced with the -PermissionTier you pass, and the display name is replaced with -DisplayName (pass the app's current name to keep it).

The script

Save the block below as provision-byo-microsoft-appreg.ps1.

#Requires -Modules Az.Accounts
<#
.SYNOPSIS
    Creates YOUR ORGANIZATION'S OWN Entra app registration for the StackJack Microsoft Graph and
    Azure connectors ("bring your own app registration", 2026-08-26).

.DESCRIPTION
    Run this signed in (Connect-AzAccount) to YOUR OWN Entra tenant as a Global Administrator or
    Application Administrator. It creates a MULTITENANT app registration that:
      - carries StackJack's redirect URLs (Web platform), so StackJack's connect flow can
        complete against your app;
      - requests the delegated permission set for the tier you choose (Full | Standard | Read) —
        the same tiers StackJack's connect flow offers;
      - gets a client secret, printed ONCE at the end.

    Paste the printed Application (client) ID and client secret into StackJack under
    Connectors → Microsoft Graph (or Microsoft Azure) → "Advanced — use your own app
    registration", then use Connect with Microsoft. Deploying via automation: this script IS the
    automation — run it from any pipeline that can Connect-AzAccount; a CIPP app-deployment
    template can apply the same manifest values.

    The permission lists below match what StackJack's connect flow asks for, as of 2026-08-26. If
    StackJack adds permissions later, re-run this script (it PATCHes the existing app when -AppId
    is supplied) or approve the new permissions on the next consent prompt.

.PARAMETER PortalHost
    The StackJack Portal host your organization signs into (no scheme), e.g. portal.example.com.
    The three redirect URLs are registered under it. If your people sign in to more than one
    StackJack region, run the script again with -AppId and the other Portal host: the second run
    ADDS that host's three URLs and keeps the first host's.

.PARAMETER PermissionTier
    Full (default) — every capability. Standard — everything except directory-privileged writes
    (their read-only forms are still requested). Read — the read-only form of every capability the
    connector ships.

.PARAMETER DisplayName
    The app registration's display name. Default: "StackJack Connector".

.PARAMETER AppId
    Optional: an existing app registration (client id) to UPDATE instead of creating a new one.
    The update ADDS the three StackJack redirect URLs for this -PortalHost and KEEPS every Web
    redirect URL already registered on the app, so it is safe to run once per Portal host your
    organization signs in to, and safe on an app that carries redirect URLs of your own.
    Three update-path behaviors that are NOT additive, so that you can plan for them: a re-run
    ADDS a new client secret alongside the old one (remove superseded secrets in the Entra
    portal), the requested permission list is REPLACED with the -PermissionTier set you pass, and
    the display name is REPLACED with -DisplayName (pass the app's current name to keep it).

.PARAMETER SecretYears
    Client-secret lifetime in years (default 2). You must rotate it in StackJack before it
    expires; users reconnect after a rotation.
#>
param(
    [Parameter(Mandatory)][string]$PortalHost,
    [ValidateSet('Full', 'Standard', 'Read')][string]$PermissionTier = 'Full',
    [string]$DisplayName = 'StackJack Connector',
    [string]$AppId,
    [ValidateRange(1, 5)][int]$SecretYears = 2
)
$ErrorActionPreference = 'Stop'

function Invoke-Graph {
    param([string]$Method = 'GET', [Parameter(Mandatory)][string]$Uri, $Body)
    $p = @{ Method = $Method; Uri = $Uri }
    if ($null -ne $Body) { $p.Payload = ($Body | ConvertTo-Json -Depth 10) }
    $r = Invoke-AzRestMethod @p
    if ($r.StatusCode -ge 300) { throw "Graph $Method $Uri -> HTTP $($r.StatusCode): $($r.Content)" }
    if ($r.Content) { return ($r.Content | ConvertFrom-Json) }
}

function Get-ResourceSp {
    param([Parameter(Mandatory)][string]$WellKnownAppId)
    $f = [uri]::EscapeDataString("appId eq '$WellKnownAppId'")
    $sp = (Invoke-Graph -Uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$filter=$f&`$select=id,appId,displayName,oauth2PermissionScopes").value | Select-Object -First 1
    if (-not $sp) {
        Write-Host "Service principal for appId $WellKnownAppId not present in tenant - instantiating it."
        Invoke-Graph -Method POST -Uri 'https://graph.microsoft.com/v1.0/servicePrincipals' -Body @{ appId = $WellKnownAppId } | Out-Null
        Start-Sleep -Seconds 5
        $sp = (Invoke-Graph -Uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$filter=$f&`$select=id,appId,displayName,oauth2PermissionScopes").value | Select-Object -First 1
    }
    if (-not $sp) { throw "Could not resolve service principal (appId='$WellKnownAppId')." }
    return $sp
}

# ---- Canonical Graph roster (transcribed 2026-08-26; MUST track BuildMicrosoftScope) ----
$graphScopesFull = @(
    'openid'; 'profile'; 'email'; 'offline_access'
    'User.Read'; 'User.ReadWrite.All'; 'Group.ReadWrite.All'; 'Directory.ReadWrite.All'
    'AdministrativeUnit.ReadWrite.All'; 'AppRoleAssignment.ReadWrite.All'
    'Directory.AccessAsUser.All'
    'Device.Read.All'; 'Application.ReadWrite.All'; 'RoleManagement.ReadWrite.Directory'
    'Policy.Read.All'; 'Policy.ReadWrite.ConditionalAccess'; 'Policy.ReadWrite.AuthenticationMethod'
    'AuditLog.Read.All'; 'Reports.Read.All'; 'Organization.ReadWrite.All'; 'Domain.ReadWrite.All'
    'IdentityRiskyUser.ReadWrite.All'; 'IdentityRiskEvent.Read.All'
    'Mail.ReadWrite'; 'Mail.Send'; 'Calendars.ReadWrite'; 'Files.ReadWrite.All'; 'Sites.ReadWrite.All'
    'MailboxSettings.ReadWrite'
    'Contacts.ReadWrite'
    'Mail.ReadWrite.Shared'; 'Calendars.ReadWrite.Shared'; 'Contacts.ReadWrite.Shared'
    'Mail.Send.Shared'
    'Team.ReadBasic.All'; 'Channel.ReadBasic.All'; 'ChannelMessage.Read.All'; 'TeamMember.ReadWrite.All'
    'Team.Create'; 'TeamSettings.ReadWrite.All'; 'Channel.Create'; 'ChannelSettings.ReadWrite.All'
    'ChannelMessage.Send'; 'Chat.ReadWrite'; 'Presence.Read.All'
    'SecurityEvents.ReadWrite.All'; 'SecurityAlert.ReadWrite.All'; 'SecurityIncident.ReadWrite.All'
    'ThreatHunting.Read.All'
    'DeviceManagementManagedDevices.PrivilegedOperations.All'
    'DeviceManagementManagedDevices.ReadWrite.All'
    'DeviceManagementConfiguration.ReadWrite.All'; 'DeviceManagementApps.ReadWrite.All'
    'DeviceManagementServiceConfig.ReadWrite.All'; 'DeviceManagementRBAC.Read.All'
    'DeviceManagementRBAC.ReadWrite.All'; 'DeviceManagementScripts.ReadWrite.All'
    'DelegatedAdminRelationship.ReadWrite.All'
    'UserAuthenticationMethod.ReadWrite.All'
)
if ($graphScopesFull.Count -ne 59) { throw 'Scope transcription drift - expected 59 Graph scopes.' }

# MUST mirror MicrosoftScopeTier.StandardTierRemovals.
$standardRemovals = @(
    'Directory.AccessAsUser.All'
    'RoleManagement.ReadWrite.Directory'
    'Application.ReadWrite.All'
    'AppRoleAssignment.ReadWrite.All'
    'Policy.ReadWrite.ConditionalAccess'
    'Policy.ReadWrite.AuthenticationMethod'
    'UserAuthenticationMethod.ReadWrite.All'
    'IdentityRiskyUser.ReadWrite.All'
    'DeviceManagementManagedDevices.PrivilegedOperations.All'
    'Domain.ReadWrite.All'
    'Organization.ReadWrite.All'
    'DelegatedAdminRelationship.ReadWrite.All'
)
# MUST mirror MicrosoftScopeTier.StandardTierReadBackfill.
$standardReadBackfill = @(
    'RoleManagement.Read.Directory'; 'Application.Read.All'
    'UserAuthenticationMethod.Read.All'; 'IdentityRiskyUser.Read.All'
    'Domain.Read.All'; 'Organization.Read.All'; 'DelegatedAdminRelationship.Read.All'
)
# MUST mirror MicrosoftScopeTier's read-tier output over the canonical roster (transcribed 2026-08-26).
$graphScopesRead = @(
    'openid'; 'profile'; 'email'; 'offline_access'; 'User.Read'
    'User.Read.All'; 'Group.Read.All'; 'Directory.Read.All'; 'AdministrativeUnit.Read.All'
    'Device.Read.All'; 'Application.Read.All'; 'RoleManagement.Read.Directory'
    'Policy.Read.All'; 'AuditLog.Read.All'; 'Reports.Read.All'
    'Organization.Read.All'; 'Domain.Read.All'
    'IdentityRiskyUser.Read.All'; 'IdentityRiskEvent.Read.All'
    'Mail.Read'; 'Calendars.Read'; 'Files.Read.All'; 'Sites.Read.All'
    'MailboxSettings.Read'; 'Contacts.Read'
    'Mail.Read.Shared'; 'Calendars.Read.Shared'; 'Contacts.Read.Shared'
    'Team.ReadBasic.All'; 'Channel.ReadBasic.All'; 'ChannelMessage.Read.All'
    'TeamMember.Read.All'; 'TeamSettings.Read.All'; 'ChannelSettings.Read.All'
    'Chat.Read'; 'Presence.Read.All'
    'SecurityEvents.Read.All'; 'SecurityAlert.Read.All'; 'SecurityIncident.Read.All'
    'ThreatHunting.Read.All'
    'DeviceManagementManagedDevices.Read.All'; 'DeviceManagementConfiguration.Read.All'
    'DeviceManagementApps.Read.All'; 'DeviceManagementServiceConfig.Read.All'
    'DeviceManagementRBAC.Read.All'
    'DelegatedAdminRelationship.Read.All'; 'UserAuthenticationMethod.Read.All'
)

$graphScopes = switch ($PermissionTier) {
    'Full'     { $graphScopesFull }
    'Standard' { @($graphScopesFull | Where-Object { $_ -notin $standardRemovals }) + $standardReadBackfill }
    'Read'     { $graphScopesRead }
}
# Not "N of 59" - a narrower tier is not a subset. Read and Standard both request read-only forms
# of capabilities that Full requests only as writes, so their counts are not drawn from Full's list.
Write-Host "Tier '$PermissionTier': requesting $(@($graphScopes).Count) Graph permissions (Full requests $($graphScopesFull.Count))."

# ---- Resolve resources + permission GUIDs ----
$graphSp = Get-ResourceSp -WellKnownAppId '00000003-0000-0000-c000-000000000000'   # Microsoft Graph
$armSp   = Get-ResourceSp -WellKnownAppId '797f4846-ba00-4fd7-ba43-dac1f8f63013'   # Azure Service Management

function Resolve-ScopeIds {
    param($Sp, [string[]]$Names)
    $map = @{}; foreach ($s in $Sp.oauth2PermissionScopes) { $map[$s.value] = $s.id }
    $missing = @(); $access = @()
    foreach ($n in $Names) {
        if ($map.ContainsKey($n)) { $access += @{ id = $map[$n]; type = 'Scope' } }
        elseif ($n -notin @('openid', 'profile', 'email', 'offline_access')) { $missing += $n }
    }
    if ($missing.Count) { throw "UNRESOLVED on $($Sp.displayName): $($missing -join ', ')" }
    return $access
}

$rra = @(
    @{ resourceAppId = $graphSp.appId; resourceAccess = @(Resolve-ScopeIds $graphSp $graphScopes) }
    @{ resourceAppId = $armSp.appId;   resourceAccess = @(Resolve-ScopeIds $armSp   @('user_impersonation')) }
)
$probe = @{ requiredResourceAccess = $rra } | ConvertTo-Json -Depth 10
if ($probe -notmatch '"resourceAccess":\s*\[') { throw 'Serialization sanity check failed - resourceAccess not an array.' }

function Merge-RedirectUris {
    # Append-only: every URL already on the app stays, in its order; each wanted URL that is not
    # there yet (compared case-insensitively) is added after them. Nothing is ever removed.
    #
    # This is what makes a SECOND run safe (Featurebase #228, 2026-09-18). The update path used to
    # PATCH web.redirectUris wholesale, so a customer who ran the script again with the other
    # region's -PortalHost lost the first region's three URLs, and anyone whose app carried a
    # redirect URL of their own lost that too - with no error, because Graph accepts the smaller
    # list happily and the breakage only shows up at the next sign-in.
    #
    # It takes everything it needs through parameters and reads no script variable, so the parity
    # test can evaluate this function alone out of the file's syntax tree.
    param([string[]]$Existing, [string[]]$Wanted)
    $merged = [System.Collections.Generic.List[string]]::new()
    foreach ($uri in @($Existing) + @($Wanted)) {
        if ([string]::IsNullOrWhiteSpace($uri)) { continue }
        if (-not ($merged | Where-Object { $_ -ieq $uri })) { $merged.Add($uri) }
    }
    # The leading comma keeps the array whole across the caller's assignment: without it PowerShell
    # unrolls the result, and a one-element or empty merge would arrive as a bare string or $null.
    return , $merged.ToArray()
}

$redirectUris = @(
    "https://$PortalHost/connector-callback/msgraph"
    "https://$PortalHost/connector-callback/azure"
    "https://$PortalHost/consent-complete"
)

$appBody = @{
    displayName            = $DisplayName
    signInAudience         = 'AzureADMultipleOrgs'   # multitenant: required for GDAP customer-tenant consent
    web                    = @{ redirectUris = $redirectUris }
    requiredResourceAccess = $rra
}

if ($AppId) {
    # Select `web` as well: the merge needs the app's CURRENT redirect URLs, and a PATCH that sent
    # only this run's three would silently drop every other one.
    $app = Invoke-Graph -Uri "https://graph.microsoft.com/v1.0/applications(appId='$AppId')?`$select=id,appId,displayName,web"
    $mergedRedirectUris = Merge-RedirectUris -Existing @($app.web.redirectUris) -Wanted $redirectUris
    $appBody.web = @{ redirectUris = @($mergedRedirectUris) }
    # Same sanity check as resourceAccess above, and it rejects BOTH ways this value can go wrong:
    # a single URL unwrapped to a bare string, and a nested array. The create path needs no probe -
    # its value is the three-element literal built above.
    $webProbe = @{ web = $appBody.web } | ConvertTo-Json -Depth 10
    if ($webProbe -notmatch '"redirectUris":\s*\[\s*"') { throw 'Serialization sanity check failed - redirectUris not an array of URL strings.' }
    Invoke-Graph -Method PATCH -Uri "https://graph.microsoft.com/v1.0/applications/$($app.id)" -Body $appBody
    Write-Host "UPDATED existing app '$($app.displayName)' ($($app.appId)). It now carries $(@($mergedRedirectUris).Count) redirect URL(s); the ones already registered were kept."
} else {
    $app = Invoke-Graph -Method POST -Uri 'https://graph.microsoft.com/v1.0/applications' -Body $appBody
    Write-Host "CREATED app '$($app.displayName)' ($($app.appId))."
}

$secret = Invoke-Graph -Method POST -Uri "https://graph.microsoft.com/v1.0/applications/$($app.id)/addPassword" -Body @{
    passwordCredential = @{
        displayName = "StackJack connector secret ($PermissionTier tier)"
        endDateTime = (Get-Date).AddYears($SecretYears).ToUniversalTime().ToString('o')
    }
}

Write-Host ''
Write-Host '==== PASTE THESE INTO STACKJACK (Connectors -> Microsoft Graph / Azure -> Advanced) ===='
Write-Host "Application (client) ID : $($app.appId)"
Write-Host "Client secret           : $($secret.secretText)"
Write-Host "Secret expires          : $($secret.endDateTime)  (rotate in StackJack before then; users reconnect after a rotation)"
Write-Host ''
Write-Host "Pick the SAME permission tier ($($PermissionTier.ToLower())) in StackJack's dropdown so the consent prompt matches this registration."
Write-Host 'The secret above is shown ONCE. Store it in your password manager.'

Delegated permissions per tier

The script resolves each permission from your own tenant's Microsoft Graph service principal at run time, so it never prints the names. The lists below are what each tier requests, for building a matching permission set in a tool such as CIPP. The Azure connector requests one delegated scope, https://management.azure.com/user_impersonation, plus openid, profile, email and offline_access, on every tier.

You pick the tier again in StackJack when you connect. That choice sets what the Microsoft consent prompt asks for. It does not revoke permissions your organization already consented to, and it does not narrow a customer-tenant consent link, which grants whatever the application's own registration lists.

Full (59 scopes)

  • openid
  • profile
  • email
  • offline_access
  • User.Read
  • User.ReadWrite.All
  • Group.ReadWrite.All
  • Directory.ReadWrite.All
  • AdministrativeUnit.ReadWrite.All
  • AppRoleAssignment.ReadWrite.All
  • Directory.AccessAsUser.All
  • Device.Read.All
  • Application.ReadWrite.All
  • RoleManagement.ReadWrite.Directory
  • Policy.Read.All
  • Policy.ReadWrite.ConditionalAccess
  • Policy.ReadWrite.AuthenticationMethod
  • AuditLog.Read.All
  • Reports.Read.All
  • Organization.ReadWrite.All
  • Domain.ReadWrite.All
  • IdentityRiskyUser.ReadWrite.All
  • IdentityRiskEvent.Read.All
  • Mail.ReadWrite
  • Mail.Send
  • Calendars.ReadWrite
  • Files.ReadWrite.All
  • Sites.ReadWrite.All
  • MailboxSettings.ReadWrite
  • Contacts.ReadWrite
  • Mail.ReadWrite.Shared
  • Mail.Send.Shared
  • Calendars.ReadWrite.Shared
  • Contacts.ReadWrite.Shared
  • Team.ReadBasic.All
  • Channel.ReadBasic.All
  • ChannelMessage.Read.All
  • TeamMember.ReadWrite.All
  • Team.Create
  • TeamSettings.ReadWrite.All
  • Channel.Create
  • ChannelSettings.ReadWrite.All
  • ChannelMessage.Send
  • Chat.ReadWrite
  • Presence.Read.All
  • SecurityEvents.ReadWrite.All
  • SecurityAlert.ReadWrite.All
  • SecurityIncident.ReadWrite.All
  • ThreatHunting.Read.All
  • DeviceManagementManagedDevices.PrivilegedOperations.All
  • DeviceManagementManagedDevices.ReadWrite.All
  • DeviceManagementConfiguration.ReadWrite.All
  • DeviceManagementApps.ReadWrite.All
  • DeviceManagementServiceConfig.ReadWrite.All
  • DeviceManagementRBAC.Read.All
  • DeviceManagementRBAC.ReadWrite.All
  • DeviceManagementScripts.ReadWrite.All
  • DelegatedAdminRelationship.ReadWrite.All
  • UserAuthenticationMethod.ReadWrite.All

Standard (54 scopes)

Everything except directory-privileged writes. The read-only forms of those areas are still requested, so listing delegated customers, domains, the organization and directory roles keeps working.

  • openid
  • profile
  • email
  • offline_access
  • User.Read
  • User.ReadWrite.All
  • Group.ReadWrite.All
  • Directory.ReadWrite.All
  • AdministrativeUnit.ReadWrite.All
  • Device.Read.All
  • Policy.Read.All
  • AuditLog.Read.All
  • Reports.Read.All
  • IdentityRiskEvent.Read.All
  • Mail.ReadWrite
  • Mail.Send
  • Calendars.ReadWrite
  • Files.ReadWrite.All
  • Sites.ReadWrite.All
  • MailboxSettings.ReadWrite
  • Contacts.ReadWrite
  • Mail.ReadWrite.Shared
  • Mail.Send.Shared
  • Calendars.ReadWrite.Shared
  • Contacts.ReadWrite.Shared
  • Team.ReadBasic.All
  • Channel.ReadBasic.All
  • ChannelMessage.Read.All
  • TeamMember.ReadWrite.All
  • Team.Create
  • TeamSettings.ReadWrite.All
  • Channel.Create
  • ChannelSettings.ReadWrite.All
  • ChannelMessage.Send
  • Chat.ReadWrite
  • Presence.Read.All
  • SecurityEvents.ReadWrite.All
  • SecurityAlert.ReadWrite.All
  • SecurityIncident.ReadWrite.All
  • ThreatHunting.Read.All
  • DeviceManagementManagedDevices.ReadWrite.All
  • DeviceManagementConfiguration.ReadWrite.All
  • DeviceManagementApps.ReadWrite.All
  • DeviceManagementServiceConfig.ReadWrite.All
  • DeviceManagementRBAC.Read.All
  • DeviceManagementRBAC.ReadWrite.All
  • DeviceManagementScripts.ReadWrite.All
  • RoleManagement.Read.Directory
  • Application.Read.All
  • UserAuthenticationMethod.Read.All
  • IdentityRiskyUser.Read.All
  • Domain.Read.All
  • Organization.Read.All
  • DelegatedAdminRelationship.Read.All

Read-only (47 scopes)

The read-only form of every capability the connector ships.

  • openid
  • profile
  • email
  • offline_access
  • User.Read
  • User.Read.All
  • Group.Read.All
  • Directory.Read.All
  • AdministrativeUnit.Read.All
  • Device.Read.All
  • Application.Read.All
  • RoleManagement.Read.Directory
  • Policy.Read.All
  • AuditLog.Read.All
  • Reports.Read.All
  • Organization.Read.All
  • Domain.Read.All
  • IdentityRiskyUser.Read.All
  • IdentityRiskEvent.Read.All
  • Mail.Read
  • Calendars.Read
  • Files.Read.All
  • Sites.Read.All
  • MailboxSettings.Read
  • Contacts.Read
  • Mail.Read.Shared
  • Calendars.Read.Shared
  • Contacts.Read.Shared
  • Team.ReadBasic.All
  • Channel.ReadBasic.All
  • ChannelMessage.Read.All
  • TeamMember.Read.All
  • TeamSettings.Read.All
  • ChannelSettings.Read.All
  • Chat.Read
  • Presence.Read.All
  • SecurityEvents.Read.All
  • SecurityAlert.Read.All
  • SecurityIncident.Read.All
  • ThreatHunting.Read.All
  • DeviceManagementManagedDevices.Read.All
  • DeviceManagementConfiguration.Read.All
  • DeviceManagementApps.Read.All
  • DeviceManagementServiceConfig.Read.All
  • DeviceManagementRBAC.Read.All
  • DelegatedAdminRelationship.Read.All
  • UserAuthenticationMethod.Read.All