使用 Microsoft Graph SDK for Powershell 将角色分配给应用服务主体?

Using Microsoft Graph SDK for Powershell to Assign Role to App Service Principal?

我正在使用 https://github.com/microsoftgraph/msgraph-sdk-powershell,因为我的脚本需要 Powershell 7 支持,AzureAD 模块在我发现的 Windows 上除了 Powershell 5 之外还有很多问题。基本上,我正在尝试在 B2C 租户中创建应用程序注册。我遇到的问题是我的脚本看起来不错,但我无法授予任何管理员对定义的任何范围的同意。然后我注意到了这个问题 - 当您在门户中创建应用程序注册时,它会自动获取服务主体,New-MgApplication 不会。

我有以下有效的脚本,直到我尝试使用 New-MgServicePrincipalAppRoleAssignment 将服务主体分配给我的应用程序,它因错误而崩溃:New-MgServicePrincipalAppRoleAssignment_CreateExpanded: Not a valid reference update.

我不确定这个功能是否适合我的需要,或者 New-MgRoleManagementDirectoryRoleAssignment 是否是正确的功能。

function Upsert-AppRegistration {
    Param(
        [string] $TemplateParametersFile,
        [string] $ResourceGroupName
    )

    $templateParameters = Get-Content $TemplateParametersFile | ConvertFrom-Json
    $customerName = $templateParameters.parameters.customerName.value
    $deploymentIdentifier = $templateParameters.parameters.deploymentIdentifier.value
    $b2cTenantId = $templateParameters.parameters.b2cTenantId.value
    $b2cTenantName = $templateParameters.parameters.b2cTenantName.value

    $GraphConnection = Connect-Graph -TenantId $b2cTenantId -Scopes "User.Read","User.ReadWrite.All","Mail.ReadWrite",`
            "Directory.ReadWrite.All","Chat.ReadWrite", "People.Read", `
            "Group.Read.All", "Directory.AccessAsUser.All", "Tasks.ReadWrite", `
            "Sites.Manage.All"

    [string[]]$webRedirectUris = 
        "https://localhost:5050/LoginView",
        "https://localhost:5050/DashboardView",
        "https://localhost:5050/UsersView",
        "https://localhost:5050/OrdersView"

    # Our custom app.login scope for delegated permissions from front-end login
    $oauth2PermissionScopes = @{
        "Id" = [guid]::NewGuid().guid
        "Value" = "app.login"
        "AdminConsentDescription" = "This will provide the application access to login"
        "AdminConsentDisplayName" = "Admin delegated login"
        "IsEnabled" = $true
        "Type" = "Admin"
    }

    [object[]]$appLoginScope = @{
        "Id" = $oauth2PermissionScopes.Id
        "Type" = "Scope"
    }

    # Microsoft.Graph ResourceAccess scopes and roles
    $mgOfflineAccessScope = @{
        "Id" = "7427e0e9-2fba-42fe-b0c0-848c9e6a8182"
        "Type" = "Scope"
    }

    $mgOpenidScope = @{
        "Id" = "37f7f235-527c-4136-accd-4a02d197296e"
        "Type" = "Scope"
    }

    $mgDirectoryReadWriteAllRole = @{
        "Id" = "19dbc75e-c2e2-444c-a770-ec69d8559fc7"
        "Type" = "Role"
    }

    $mgResourceAccess = $mgOfflineAccessScope, $mgOpenidScope, $mgDirectoryReadWriteAllRole

    [object[]]$requiredResourceAccess = @{
        "ResourceAppId" = "00000003-0000-0000-c000-000000000000"
        "ResourceAccess" = $mgResourceAccess
    }
    $mgApplicationParams = @{
        "DisplayName" = "${customerName}-${deploymentIdentifier}"
        "ApiOauth2PermissionScopes" = $oauth2PermissionScopes
        "ApiRequestedAccessTokenVersion" = 2
        "ImplicitGrantSettingEnableAccessTokenIssuance" = $true
        "ImplicitGrantSettingEnableIdTokenIssuance" = $true
        "RequiredResourceAccess" = $requiredResourceAccess
        "WebLogoutUrl" = "https://localhost:5050/LogoutView"
        "WebRedirectUris" = $webRedirectUris
        "IdentifierUris" = "https://$b2cTenantName.onmicrosoft.com/app"
    }

    # We need to create our application before we can add permissions to our custom scope
    $mgApplication = New-MgApplication @mgApplicationParams

    # Now our application has an Id so we can finish setting up the RequiredResourceAccess

    $newRequiredResourceAccess =  $requiredResourceAccess + @{
        "ResourceAppId" = $mgApplication.AppId
        "ResourceAccess" = $appLoginScope
    }

    # Azure doesn't always update immediately, make sure app exists before we try to update its config
    $appExists = $false
    while (!$appExists) {
        Start-Sleep -Seconds 2
        $appExists = Get-MgApplication -ApplicationId $mgApplication.Id
    }

    $mgApplicationParams.Add("ApplicationId", $mgApplication.Id)
    $mgApplicationParams.RequiredResourceAccess = $newRequiredResourceAccess
    Update-MgApplication @mgApplicationParams

    $appServicePrincipal = New-MgServicePrincipal -AppId $mgApplication.AppId -Tags @("WindowsAzureActiveDirectoryIntegratedApp")

    $result = New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $appServicePrincipal.Id `
        -AppRoleId 19dbc75e-c2e2-444c-a770-ec69d8559fc7 `
        -ResourceId 429a2356-9cdc-475e-8caf-cfe8b7c77db8 `
        -PrincipalType "ServicePrincipal"

    # @TODO Generate app client secret 
    $appClientSecret = "--SECRET--"

    Write-Host "Created the app registration ${customerName}-${deploymentIdentifier} with client Id:",
        $mgApplication.AppId -ForegroundColor Yellow

    @{
        "appClientId" = $mgApplication.AppId
        "appClientSecret" = $appClientSecret
    }
}

事实证明,我不需要为我的服务主体分配角色,因为它可以正常工作并且所有内容都可以正确显示。这是 Azure UI 滞后和关键是在服务主体中添加标签的组合,当我发布这个时我还没有测试过。