2
votes

I am figure out the commands in Azure PowerShell to add an the User.Read Ape Permission to my App Registration in Azure.

An existing application

I can find some examples using *Azure, but would prefer one that uses the *Az commands, e.g. https://docs.microsoft.com/en-us/powershell/azure/?view=azps-2.8.0.

Wonder if anybody knows how to do this? Thanks!

2
I think you need Get-AzADAppCredential and Get-AzADApplication, changing the verb to New if you need to amend them. - Ash

2 Answers

7
votes

This can currently only be achieved using the Azure AD PowerShell. Please note that there is a difference between Azure AD PowerShell and Azure PowerShell. The Azure AD PowerShell is not simply the old Azure PowerShell module. Azure AD PowerShell is a separate module. There is no "AZ*" for Azure AD yet. Only couple of most commonly used commands, that have Azure Resource Provider implementation. Azure PowerShell has a limited set of features for working with Azure AD. If you need more features, like the one you mention, you must use Azure AD PowerShell. Azure AD PowerShell is not depricated and is the officially supported PowerShell module for working with Azure AD.

You can manage these required permissions by the Set-AzureAdApplication cmdlet and passing proper -RequiredResourceAccess object.

In order to construct this object, you must first get a reference to "exposed" permissions. Because permissions are exposed by other service principals.

as I cannot upload whole file, here is a PowerShell script that creates a sample application with required permission to some MS Graph and some Power BI permissions.

Function GetToken
{
    param(
        [String] $authority = "https://login.microsoftonline.com/dayzure.com/oauth2/token",
        [String] $clientId,
        [String] $clientSecret,
        [String] $resourceId = "https://graph.windows.net"
    )
    $scope = [System.Web.HttpUtility]::UrlEncode($resourceId) 
    $encSecret = [System.Web.HttpUtility]::UrlEncode($clientSecret) 
    $body = "grant_type=client_credentials&resource=$($scope)&client_id=$($clientId)&client_secret=$($encSecret)"
    $res = Invoke-WebRequest -Uri $authority -Body $body -Method Post
    $authResult = $res.Content | ConvertFrom-Json
    return $authResult.access_token
}

#`
#            -RequiredResourceAccess @($requiredResourceAccess)
#

Function CreateChildApp
{
    param (
        [string] $displayName,
        [string] $tenantName
        )
    # create your new application
    Write-Output -InputObject ('Creating App Registration {0}' -f $displayName)
    if (!(Get-AzureADApplication -SearchString $displayName)) {
        $app = New-AzureADApplication -DisplayName $displayName `
            -Homepage "https://localhost" `
            -ReplyUrls "https://localhost" `
            -IdentifierUris ('https://{0}/{1}' -f $tenantName, $displayName) 

        # create SPN for App Registration
        Write-Output -InputObject ('Creating SPN for App Registration {0}' -f $displayName)

        # create a password (spn key)
        $appPwd = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId
        $appPwd

        # create a service principal for your application
        # you need this to be able to grant your application the required permission
        $spForApp = New-AzureADServicePrincipal -AppId $app.AppId -PasswordCredentials @($appPwd)
    }
    else {
        Write-Output -InputObject ('App Registration {0} already exists' -f $displayName)
        $app = Get-AzureADApplication -SearchString $displayName
    }
    #endregion

    return $app
}

Function GrantAllThePermissionsWeWant
{
    param
    (
        [string] $targetServicePrincipalName,
        $appPermissionsRequired,
        $childApp,
        $spForApp
    )

    $targetSp = Get-AzureADServicePrincipal -Filter "DisplayName eq '$($targetServicePrincipalName)'"

    # Iterate Permissions array
    Write-Output -InputObject ('Retrieve Role Assignments objects')
    $RoleAssignments = @()
    Foreach ($AppPermission in $appPermissionsRequired) {
        $RoleAssignment = $targetSp.AppRoles | Where-Object { $_.Value -eq $AppPermission}
        $RoleAssignments += $RoleAssignment
    }

    $ResourceAccessObjects = New-Object 'System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess]'
    foreach ($RoleAssignment in $RoleAssignments) {
        $resourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess"
        $resourceAccess.Id = $RoleAssignment.Id
        $resourceAccess.Type = 'Role'
        $ResourceAccessObjects.Add($resourceAccess)
    }
    $requiredResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
    $requiredResourceAccess.ResourceAppId = $targetSp.AppId
    $requiredResourceAccess.ResourceAccess = $ResourceAccessObjects

    # set the required resource access
    Set-AzureADApplication -ObjectId $childApp.ObjectId -RequiredResourceAccess $requiredResourceAccess
    Start-Sleep -s 1

    # grant the required resource access
    foreach ($RoleAssignment in $RoleAssignments) {
        Write-Output -InputObject ('Granting admin consent for App Role: {0}' -f $($RoleAssignment.Value))
        New-AzureADServiceAppRoleAssignment -ObjectId $spForApp.ObjectId -Id $RoleAssignment.Id -PrincipalId $spForApp.ObjectId -ResourceId $targetSp.ObjectId
        Start-Sleep -s 1
    }
}

cls

#globaladminapp
$clientID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
$key = "****"


$tenantId = "aaaaaaaa-bbbb-xxxx-yyyy-aaaaaaaaaaaa";
$TenantName = "customdomain.com";
$AppRegName = "globaladminChild-0003";

$token = GetToken -clientId $clientID -clientSecret $key

Disconnect-AzureAD
Connect-AzureAD -AadAccessToken $token -AccountId $clientID -TenantId $tenantId

$appPermissionsRequired = @('Application.ReadWrite.OwnedBy', 'Device.ReadWrite.All', 'Domain.ReadWrite.All')
$targetServicePrincipalName = 'Windows Azure Active Directory'

#$appPermissionsRequired = @('Files.ReadWrite.All','Sites.FullControl.All','Notes.ReadWrite.All')
#$targetServicePrincipalName = 'Microsoft Graph'

$app = CreateChildApp -displayName $AppRegName -tenantName $TenantName
$spForApp = Get-AzureADServicePrincipal -Filter "DisplayName eq '$($AppRegName)'"


$appPermissionsRequired = @('Tenant.ReadWrite.All')
$targetServicePrincipalName = 'Power BI Service'
GrantAllThePermissionsWeWant -targetServicePrincipalName $targetServicePrincipalName -appPermissionsRequired $appPermissionsRequired -childApp $app -spForApp $spForApp

$appPermissionsRequired = @('Files.ReadWrite.All','Sites.FullControl.All','Notes.ReadWrite.All')
$targetServicePrincipalName = 'Microsoft Graph'
GrantAllThePermissionsWeWant -targetServicePrincipalName $targetServicePrincipalName -appPermissionsRequired $appPermissionsRequired -childApp $app -spForApp $spForApp

The interesting parts are around "apppermissionrequired" and "targetserviceprincipalname" variables.

1
votes

I can't reply to Rolfo's comment directly as I don't have enough clout yet. While it's true it's not dead simple, it's possible to use both in the same session as of July 2021. Not sure this was always the case, or something was updated to allow it.

#Import modules if needed
$mList = @("AzureAD","Az.Resources","Az.Accounts")
foreach($m in $mList){if ((gmo -l $m).Count -eq 0){Install-Module -Name $m -AllowClobber -Scope CurrentUser -Force}}

#Authentication Popup
Connect-AzAccount

#Use authentication context cached from above to authenticate to AAD graph
$IDObject = Get-AzAccessToken -Resource "https://graph.windows.net"
Connect-AzureAD -AadAccessToken $IDObject.token -AccountId $IDObject.UserId