Skip to content

PowerShell Setup: Control 1.18 - Application-Level Authorization and RBAC

Last Updated: January 2026 Modules Required: Microsoft.Graph, Microsoft.PowerApps.Administration.PowerShell

Prerequisites

Install-Module -Name Microsoft.Graph -Force -Scope CurrentUser
Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -Force -Scope CurrentUser

Automated Scripts

Export Security Role Assignments

<#
.SYNOPSIS
    Exports security role assignments for compliance audit

.EXAMPLE
    .\Export-SecurityRoles.ps1 -EnvironmentId "env-guid"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$EnvironmentId,
    [string]$OutputPath = ".\SecurityRoleExport.csv"
)

Write-Host "=== Security Role Export ===" -ForegroundColor Cyan

# Connect to Power Platform (interactive authentication)
Add-PowerAppsAccount

# For automated/unattended scenarios, use service principal authentication:
# $appId = "<Application-Client-ID>"
# $secret = "<Client-Secret>"
# $tenantId = "<Tenant-ID>"
# Add-PowerAppsAccount -ApplicationId $appId -ClientSecret $secret -TenantID $tenantId

# Get environment users and roles
$users = Get-AdminPowerAppEnvironmentRoleAssignment -EnvironmentName $EnvironmentId

$export = @()
foreach ($user in $users) {
    $export += [PSCustomObject]@{
        PrincipalDisplayName = $user.PrincipalDisplayName
        PrincipalEmail = $user.PrincipalEmail
        PrincipalType = $user.PrincipalType
        RoleType = $user.RoleType
        EnvironmentName = $user.EnvironmentName
        ExportDate = Get-Date
    }
}

$export | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "Export saved to: $OutputPath" -ForegroundColor Green

Create Security Groups

<#
.SYNOPSIS
    Creates FSI security groups for Copilot Studio access

.EXAMPLE
    .\New-FSISecurityGroups.ps1 -Environment "Prod"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$Environment
)

Write-Host "=== Create FSI Security Groups ===" -ForegroundColor Cyan

Connect-MgGraph -Scopes "Group.ReadWrite.All"

$groups = @(
    @{Name="SG-PowerPlatform-Admins-$Environment"; Description="Power Platform Administrators for $Environment"},
    @{Name="SG-CopilotStudio-Makers-$Environment"; Description="Copilot Studio agent creators for $Environment"},
    @{Name="SG-CopilotStudio-Viewers-$Environment"; Description="Copilot Studio read-only users for $Environment"},
    @{Name="SG-CopilotStudio-Testers-$Environment"; Description="Copilot Studio testers for $Environment"}
)

foreach ($group in $groups) {
    $existing = Get-MgGroup -Filter "displayName eq '$($group.Name)'"
    if ($existing) {
        Write-Host "Group already exists: $($group.Name)" -ForegroundColor Yellow
    } else {
        $newGroup = New-MgGroup -DisplayName $group.Name `
            -Description $group.Description `
            -MailEnabled:$false `
            -SecurityEnabled:$true `
            -MailNickname $group.Name.Replace("-","")

        Write-Host "Created: $($group.Name)" -ForegroundColor Green
    }
}

Disconnect-MgGraph

Validation Script

<#
.SYNOPSIS
    Validates Control 1.18 - RBAC configuration

.EXAMPLE
    .\Validate-Control-1.18.ps1 -EnvironmentId "env-guid"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$EnvironmentId
)

Write-Host "=== Control 1.18 Validation ===" -ForegroundColor Cyan

Add-PowerAppsAccount
Connect-MgGraph -Scopes "Group.Read.All"

# Check 1: Security groups exist
Write-Host "`n[Check 1] Security Groups" -ForegroundColor Cyan
$requiredGroups = @("SG-PowerPlatform-Admins", "SG-CopilotStudio-Makers", "SG-CopilotStudio-Viewers")
foreach ($groupName in $requiredGroups) {
    $group = Get-MgGroup -Filter "startsWith(displayName,'$groupName')"
    if ($group) {
        Write-Host "[PASS] Found: $($group.DisplayName)" -ForegroundColor Green
    } else {
        Write-Host "[FAIL] Missing: $groupName" -ForegroundColor Red
    }
}

# Check 2: Role assignments
Write-Host "`n[Check 2] Environment Role Assignments" -ForegroundColor Cyan
$roles = Get-AdminPowerAppEnvironmentRoleAssignment -EnvironmentName $EnvironmentId
Write-Host "Total assignments: $($roles.Count)"

# Check 3: PIM (manual)
Write-Host "`n[Check 3] PIM Configuration" -ForegroundColor Cyan
Write-Host "[INFO] Verify PIM is configured in Entra admin center"

Disconnect-MgGraph

Write-Host "`n=== Validation Complete ===" -ForegroundColor Cyan

Complete Configuration Script

<#
.SYNOPSIS
    Configures Control 1.18 - Application-Level Authorization and RBAC

.DESCRIPTION
    This script creates security groups for Copilot Studio access control,
    exports role assignments, and validates RBAC configuration.

.PARAMETER EnvironmentId
    The GUID of the target Power Platform environment

.PARAMETER EnvironmentSuffix
    Suffix for security group names (e.g., "Prod", "Test")

.PARAMETER ExportPath
    Path for exports (default: current directory)

.EXAMPLE
    .\Configure-Control-1.18.ps1 -EnvironmentId "env-guid" -EnvironmentSuffix "Prod"

.NOTES
    Last Updated: January 2026
    Related Control: Control 1.18 - Application-Level Authorization and RBAC
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$EnvironmentId,

    [Parameter(Mandatory=$true)]
    [string]$EnvironmentSuffix,

    [string]$ExportPath = "."
)

try {
    # Connect to services
    Write-Host "Connecting to Microsoft Graph and Power Platform..." -ForegroundColor Cyan
    Connect-MgGraph -Scopes "Group.ReadWrite.All"
    Add-PowerAppsAccount

    Write-Host "Configuring Control 1.18: Application-Level Authorization and RBAC" -ForegroundColor Cyan

    # Step 1: Create security groups
    Write-Host "`n[Step 1] Creating security groups..." -ForegroundColor Yellow
    $groups = @(
        @{Name="SG-PowerPlatform-Admins-$EnvironmentSuffix"; Description="Power Platform Administrators for $EnvironmentSuffix"},
        @{Name="SG-CopilotStudio-Makers-$EnvironmentSuffix"; Description="Copilot Studio agent creators for $EnvironmentSuffix"},
        @{Name="SG-CopilotStudio-Viewers-$EnvironmentSuffix"; Description="Copilot Studio read-only users for $EnvironmentSuffix"},
        @{Name="SG-CopilotStudio-Testers-$EnvironmentSuffix"; Description="Copilot Studio testers for $EnvironmentSuffix"}
    )

    $createdGroups = @()
    foreach ($group in $groups) {
        $existing = Get-MgGroup -Filter "displayName eq '$($group.Name)'" -ErrorAction SilentlyContinue
        if ($existing) {
            Write-Host "  [EXISTS] $($group.Name)" -ForegroundColor Yellow
            $createdGroups += $existing
        } else {
            $newGroup = New-MgGroup -DisplayName $group.Name `
                -Description $group.Description `
                -MailEnabled:$false `
                -SecurityEnabled:$true `
                -MailNickname $group.Name.Replace("-","")
            Write-Host "  [CREATED] $($group.Name)" -ForegroundColor Green
            $createdGroups += $newGroup
        }
    }

    # Step 2: Export current role assignments
    Write-Host "`n[Step 2] Exporting current role assignments..." -ForegroundColor Yellow
    $users = Get-AdminPowerAppEnvironmentRoleAssignment -EnvironmentName $EnvironmentId

    $roleExport = @()
    foreach ($user in $users) {
        $roleExport += [PSCustomObject]@{
            PrincipalDisplayName = $user.PrincipalDisplayName
            PrincipalEmail = $user.PrincipalEmail
            PrincipalType = $user.PrincipalType
            RoleType = $user.RoleType
            EnvironmentName = $user.EnvironmentName
            ExportDate = Get-Date
        }
    }
    $roleFile = Join-Path $ExportPath "RoleAssignments-$(Get-Date -Format 'yyyyMMdd').csv"
    $roleExport | Export-Csv -Path $roleFile -NoTypeInformation
    Write-Host "  Role assignments exported to: $roleFile" -ForegroundColor Green

    # Step 3: Validate required groups exist
    Write-Host "`n[Step 3] Validating security group configuration..." -ForegroundColor Yellow
    $requiredGroups = @("SG-PowerPlatform-Admins", "SG-CopilotStudio-Makers", "SG-CopilotStudio-Viewers")
    $allFound = $true
    foreach ($groupName in $requiredGroups) {
        $group = Get-MgGroup -Filter "startsWith(displayName,'$groupName')" -ErrorAction SilentlyContinue
        if ($group) {
            Write-Host "  [PASS] Found: $($group.DisplayName)" -ForegroundColor Green
        } else {
            Write-Host "  [FAIL] Missing: $groupName" -ForegroundColor Red
            $allFound = $false
        }
    }

    # Step 4: Export group configuration
    Write-Host "`n[Step 4] Exporting group configuration..." -ForegroundColor Yellow
    $groupFile = Join-Path $ExportPath "SecurityGroups-$(Get-Date -Format 'yyyyMMdd').csv"
    $createdGroups | Select-Object DisplayName, Id, Description, CreatedDateTime |
        Export-Csv -Path $groupFile -NoTypeInformation
    Write-Host "  Group configuration exported to: $groupFile" -ForegroundColor Green

    Write-Host "`n[PASS] Control 1.18 configuration completed successfully" -ForegroundColor Green
}
catch {
    Write-Host "[FAIL] Error: $($_.Exception.Message)" -ForegroundColor Red
    Write-Host "[INFO] Stack trace: $($_.ScriptStackTrace)" -ForegroundColor Yellow
    exit 1
}
finally {
    # Cleanup connections
    if (Get-MgContext) {
        Disconnect-MgGraph -ErrorAction SilentlyContinue
    }
    Write-Host "`nDisconnected from services" -ForegroundColor Gray
}

Back to Control 1.18 | Portal Walkthrough | Verification Testing | Troubleshooting