2021-07-26 19:41:48 +03:00
<#
. SYNOPSIS
2021-07-29 15:37:25 +03:00
Returns all the apps and service principles that currently use Azure AD Graph
2021-07-26 19:41:48 +03:00
. EXAMPLE
2021-07-29 15:21:41 +03:00
PS C: \ > . \ Get-AzureADGraphApps . ps1
2021-07-29 15:20:21 +03:00
Returns a collection of all the apps that have Azure AD Graph permissions assigned to them
2021-07-26 19:41:48 +03:00
#>
2021-07-30 05:20:25 +03:00
[ cmdletbinding ( ) ]
param ( )
2021-07-26 19:41:48 +03:00
function Load-Module ( $m ) {
2021-07-30 05:20:25 +03:00
Write-Progress -Activity " Loading dependencies... "
2021-07-26 19:41:48 +03:00
# If module is imported say that and do nothing
if ( Get-Module | Where-Object { $_ . Name -eq $m } ) {
2021-07-29 15:20:21 +03:00
Write-Verbose " Module $m is already imported. "
2021-07-26 19:41:48 +03:00
}
else {
# If module is not imported, but available on disk then import
if ( Get-Module -ListAvailable | Where-Object { $_ . Name -eq $m } ) {
Import-Module $m
}
else {
# If module is not imported, not available on disk, but is in online gallery then install and import
if ( Find-Module -Name $m | Where-Object { $_ . Name -eq $m } ) {
Install-Module -Name $m -Force -Scope CurrentUser
Import-Module $m
}
else {
# If module is not imported, not available and not in online gallery then abort
2021-07-29 15:20:21 +03:00
Write-Host " Module $m not imported, not available and not in online gallery, exiting. "
2021-07-26 19:41:48 +03:00
EXIT 1
}
}
}
}
2021-07-29 15:20:21 +03:00
function Get-MSCloudIdConsentGrantList
2021-07-26 19:41:48 +03:00
{
# An in-memory cache of objects by {object ID} andy by {object class, object ID}
$script:ObjectByObjectId = @ { }
$script:ObjectByObjectClassId = @ { }
# Function to add an object to the cache
function CacheObject($Object ) {
if ( $Object ) {
if ( -not $script:ObjectByObjectClassId . ContainsKey ( $Object . ObjectType ) ) {
$script:ObjectByObjectClassId [ $Object . ObjectType ] = @ { }
}
$script:ObjectByObjectClassId [ $Object . ObjectType ] [ $Object . ObjectId ] = $Object
$script:ObjectByObjectId [ $Object . ObjectId ] = $Object
}
}
# Function to retrieve an object from the cache (if it's there), or from Azure AD (if not).
function GetObjectByObjectId($ObjectId ) {
if ( -not $script:ObjectByObjectId . ContainsKey ( $ObjectId ) ) {
Write-Verbose ( " Querying Azure AD for object '{0}' " -f $ObjectId )
try {
$object = Get-AzureADObjectByObjectId -ObjectId $ObjectId
CacheObject -Object $object
} catch {
Write-Verbose " Object not found. "
}
}
return $script:ObjectByObjectId [ $ObjectId ]
}
# Get all ServicePrincipal objects and add to the cache
2021-07-29 15:37:25 +03:00
Write-Progress -Activity " Retrieving Service Principal objects. Please wait... "
2021-07-26 19:41:48 +03:00
$servicePrincipals = Get-AzureADServicePrincipal -All $true
$Oauth2PermGrants = @ ( )
$count = 0
foreach ( $sp in $servicePrincipals )
{
CacheObject -Object $sp
$spPermGrants = Get-AzureADServicePrincipalOAuth2PermissionGrant -ObjectId $sp . ObjectId -All $true
$Oauth2PermGrants + = $spPermGrants
$count + +
2021-07-29 15:37:25 +03:00
Write-Progress -Activity " Getting Service Principal Delegate Permissions... " -Status " $count of $( $servicePrincipals . Count ) - $( $sp . DisplayName ) " -percentComplete ( ( $count / $servicePrincipals . Count ) * 100 )
2021-07-26 19:41:48 +03:00
2021-07-29 15:20:21 +03:00
if ( $sp . AppId -eq " 00000002-0000-0000-c000-000000000000 " ) #Azure Active Directory Graph API app
{
$aadGraphSp = $sp
}
}
2021-07-26 19:41:48 +03:00
# Get all existing OAuth2 permission grants, get the client, resource and scope details
2021-07-29 15:37:25 +03:00
Write-Progress -Activity " Checking Delegated Permission Grants... "
2021-07-26 19:41:48 +03:00
foreach ( $grant in $Oauth2PermGrants )
{
2021-07-29 15:20:21 +03:00
if ( $grant . ResourceId -eq $aadGraphSp . ObjectId -and $grant . Scope )
2021-07-26 19:41:48 +03:00
{
2021-07-29 15:20:21 +03:00
$grant . Scope . Split ( " " ) | Where-Object { $_ } | ForEach-Object {
2021-07-26 19:41:48 +03:00
$scope = $_
$client = GetObjectByObjectId -ObjectId $grant . ClientId
2021-07-29 15:37:25 +03:00
Write-Progress -Activity " Checking Delegate Permissions - $( $client . DisplayName ) "
2021-07-29 15:20:21 +03:00
2021-07-26 19:41:48 +03:00
# Determine if the object comes from the Microsoft Services tenant, and flag it if true
$MicrosoftRegisteredClientApp = @ ( )
if ( $client . AppOwnerTenantId -eq " f8cdef31-a31e-4b4a-93e4-5f571e91255a " -or $client . AppOwnerTenantId -eq " 72f988bf-86f1-41af-91ab-2d7cd011db47 " ) {
$MicrosoftRegisteredClientApp = $true
} else {
$MicrosoftRegisteredClientApp = $false
}
$resource = GetObjectByObjectId -ObjectId $grant . ResourceId
if ( $grant . ConsentType -eq " AllPrincipals " ) {
$simplifiedgranttype = " Delegated-AllPrincipals "
} elseif ( $grant . ConsentType -eq " Principal " ) {
$simplifiedgranttype = " Delegated-Principal "
}
New-Object PSObject -Property ( [ ordered ] @ {
2021-07-29 15:20:21 +03:00
" ObjectId " = $grant . ClientId
" DisplayName " = $client . DisplayName
" ApplicationId " = $client . AppId
2021-07-26 19:41:48 +03:00
" PermissionType " = $simplifiedgranttype
2021-07-29 15:20:21 +03:00
" Resource " = $resource . DisplayName
2021-07-26 19:41:48 +03:00
" Permission " = $scope
2021-07-29 15:20:21 +03:00
" MicrosoftApp " = $MicrosoftRegisteredClientApp
2021-07-26 19:41:48 +03:00
} )
}
}
}
# Iterate over all ServicePrincipal objects and get app permissions
2021-07-29 15:37:25 +03:00
Write-Progress -Activity " Getting Application Permission Grants... "
2021-07-26 19:41:48 +03:00
$script:ObjectByObjectClassId [ 'ServicePrincipal' ] . GetEnumerator ( ) | ForEach-Object {
$sp = $_ . Value
2021-07-29 15:37:25 +03:00
Write-Progress -Activity " Checking Application Permissions - $( $sp . DisplayName ) "
2021-07-26 19:41:48 +03:00
Get-AzureADServiceAppRoleAssignedTo -ObjectId $sp . ObjectId -All $true `
2021-07-29 15:20:21 +03:00
| Where-Object { $_ . PrincipalType -eq " ServicePrincipal " -and $_ . ResourceId -eq $aadGraphSp . ObjectId } | ForEach-Object {
2021-07-26 19:41:48 +03:00
$assignment = $_
$client = GetObjectByObjectId -ObjectId $assignment . PrincipalId
2021-07-29 15:20:21 +03:00
2021-07-26 19:41:48 +03:00
# Determine if the object comes from the Microsoft Services tenant, and flag it if true
$MicrosoftRegisteredClientApp = @ ( )
if ( $client . AppOwnerTenantId -eq " f8cdef31-a31e-4b4a-93e4-5f571e91255a " -or $client . AppOwnerTenantId -eq " 72f988bf-86f1-41af-91ab-2d7cd011db47 " ) {
$MicrosoftRegisteredClientApp = $true
} else {
$MicrosoftRegisteredClientApp = $false
}
$resource = GetObjectByObjectId -ObjectId $assignment . ResourceId
$appRole = $resource . AppRoles | Where-Object { $_ . Id -eq $assignment . Id }
New-Object PSObject -Property ( [ ordered ] @ {
2021-07-29 15:20:21 +03:00
" ObjectId " = $assignment . PrincipalId
" DisplayName " = $client . DisplayName
" ApplicationId " = $client . AppId
2021-07-26 19:41:48 +03:00
" PermissionType " = " Application "
2021-07-29 15:20:21 +03:00
" Resource " = $resource . DisplayName
2021-07-26 19:41:48 +03:00
" Permission " = $appRole . Value
2021-07-29 15:20:21 +03:00
" MicrosoftApp " = $MicrosoftRegisteredClientApp
2021-07-26 19:41:48 +03:00
} )
}
}
}
Load-Module " AzureAD "
2021-07-29 15:20:21 +03:00
Connect-AzureAD
2021-07-26 19:41:48 +03:00
2021-07-29 15:20:21 +03:00
Get-MSCloudIdConsentGrantList