skip to Main Content

Have created a custom PowerShell script to export all of my azure registered apps API application permissions and delegated permissions. Some of my apps have either API permissions of Type equal to delegated or application. I followed the step by step guide answered in this question Similar question. It was shown for only single app, in my case its multiple apps.

What is working and not working

The script have created is able to export the application permissions assigned to any app registration, but unable to export delegated permissions. The script returns without errors but I don’t get the csv for delegated permissions created and populated with apps that have delegated permissions including the permissions information.

I tried to separately export delegated permissions only, but still the same issue, the csv is not created with the data.

My main goal is to be able to retrieve and export into a csv file all API permissions(both application permissions and delegated permissions) assigned to all app registrations I’m using Azure-AD module.

Below is the script.

# Add your azure ad global administrator password here
$password_ = ""
$password = ConvertTo-SecureString $password_ -AsPlainText -Force

# Add your azure ad global administrator login UPN
$upn = ""

$export_application_permission = "C:tempapplication_perms.csv"
$export_delegated_permission = "C:tempdelegated_perms.csv"

# Automated login to azure ad
$AppCredential = New-Object System.Management.Automation.PSCredential($upn, $password)
Connect-azureAD -Credential $AppCredential

$apps = Get-AzureADApplication -All $true
foreach ($app in $apps){

    $perms = $app.requiredResourceAccess
    foreach($perm in $perms){

        # Grab all the ResourceAppId from requiredResourceAccess array
        $res_app_id = $perm.ResourceAppId
        foreach($res_access in $perm.ResourceAccess){
            # Check if the resourceAccess Type is Role, which means its application permissions
            if($res_access.Type -eq "Role"){


                # Grab the resource id
                $res_ac = $res_access.Id
                
                # Calling azure-AD module
                Connect-azureAD -Credential $AppCredential

                # Grab all applications assigned application permissions only
                $sps = Get-AzureADServicePrincipal -All $true | Where-Object {$_.AppId -eq $res_app_id}

                foreach($sp in $sps){

                # Grab application permissions details now
                $roles = $sp.AppRoles | Where-Object {$_.Id -eq $res_ac}
                
                
                foreach($rol in $roles.value){

                $record = New-Object PSObject
                $record | Add-Member NoteProperty -Name "Application Display Name" -Value $app.displayName
                $record | Add-Member NoteProperty -Name "Permission Type" -Value $res_access.Type
                $record | Add-Member NoteProperty -Name "Permission Value" -Value $rol

                $record | Export-CSV $export_application_permission -NoTypeInformation -Append

                }

                }
                # Check if the resourceAccess Type is Scope, which means its delegated permissions
            }elseif ($res_access.Type -eq "Scope") {
                <# Action when this condition is true #>
                $res_ac = $res_access.Id
                Connect-azureAD -Credential $AppCredential
                $sps = Get-AzureADServicePrincipal -All $true | Where-Object {$_.AppId -eq $res_app_id}

                foreach($sp in $sps){

                # Grab delegated permissions details now
                $delegated_perms = $sp.oauth2PermissionScopes | Where-Object {$_.Id -eq $res_ac}
                

                foreach($rol in $delegated_perms.value){

                $record = New-Object PSObject
                $record | Add-Member NoteProperty -Name "Application Display Name" -Value $app.displayName
                $record | Add-Member NoteProperty -Name "Permission Type" -Value $res_access.Type
                $record | Add-Member NoteProperty -Name "Permission Value" -Value $rol

                $record | Export-CSV $export_delegated_permission -NoTypeInformation -Append

                }

                }
            } else {
                Write-host "Retreating........."
            }                 
        }  
    }

}


The csv file for application permissions outputs well as shown below.
enter image description here

I’m expecting similar output for all apps with delegated permissions

What i’m i doing wrong or missing?

2

Answers


  1. Here is how I would get all the application permissions / delegated permissions for all apps while tracking ownership context.

    This will produce something like your sample CSV output.

    Code

    Connect-azureAD 
    
    $Apps = Get-AzureADApplication -All $true
    $ServicePrincipals = Get-AzureADServicePrincipal -All $true
    
    $export_application_permission = ""
    $export_delegated_permission = "C:tempdelegated_perms.csv"
    
    
    $PermissionsList = $ServicePrincipals.Oauth2Permissions | Select-Object  Id, Value
    $RolesList = $ServicePrincipals.AppRoles | Select-Object Id, Value
    
    
    
    $app.RequiredResourceAccess
    $Data = Foreach ($App in $Apps) {
        foreach ($Access in $App.RequiredResourceAccess) {
            foreach ($Permission in $Access.ResourceAccess) {
    
                switch ($Permission.Type) {
                    'Scope' {
                        $PermissionName = ($PermissionsList | Where Id -eq $Permission.Id).Value 
                        break
                    }
                    'Role' {
                        $PermissionName = ($RolesList | Where Id -eq $Permission.Id).Value 
                        break
                    }
                }
    
                if (!$PermissionName) { $PermissionName = $Permission.Id }
                
                [PSCustomObject]@{
                    'Application Display Name' = $App.DisplayName
                    'Permission Type'          = $Permission.Type
                    'Permission Value'         = $PermissionName
                }
            }
        }
    }
    
    $Data | Where-Object 'Permission Type' -eq Role | Export-Csv -Path $export_application_permission -NoTypeInformation
    $Data | Where-Object 'Permission Type' -eq Scope | Export-Csv -Path $export_delegated_permission -NoTypeInformation
    
    

    Caveat

    Checking just for the permission value (eg: User.Read.All) can be misleading as a custom app that also expose a permission with the same name would result in a situation where you get the permissions name, but you don’t know which API is behind that permission (eg: Is it graph, a custom app, another Microsoft API that share some of the permissions name, etc…)

    A couple of notes regarding your original code

    There is a couple of inefficiencies in your original sample.

    • Connect-AzureAd. you only need to connect once before entering the loop and not at multiple points like you do.
    • Get-AzureADServicePrincipal can be called once before the loop at the same time you get all your azure AD apps. In the loops, you just select what you need from the initial results instead of calling the cmdlet again and again.
    • Export-CSV -Append. I would discourage the use of this and rather use it after the loop so instead of accessing the file dozen, hundred or thgousands times, you access it once.
    • Perfomance wise, it is faster (and cleaner IMO) to use the hashtable cast to PSCustomObject rather than creating a PSObject and using Add-member
    # This
    $record = [PSCustomObject]@{
        "Application Display Name" = $app.displayName
        "Permission Type"          = $res_access.Type
        "Permission Value"         = $rol
    }
    
    #Instead of this
    $record = New-Object PSObject
    $record | Add-Member NoteProperty -Name "Application Display Name" -Value $app.displayName
    $record | Add-Member NoteProperty -Name "Permission Type" -Value $res_access.Type
    $record | Add-Member NoteProperty -Name "Permission Value" -Value $rol
    
    Login or Signup to reply.
  2. Line 65 needs to say $sp.Oauth2Permissions:

    $delegated_perms = $sp.Oauth2Permissions | Where-Object {$_.Id -eq $res_ac}
    

    You have:

    $delegated_perms = $sp.oauth2PermissionScopes | Where-Object {$_.Id -eq $res_ac}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search