Skip to content

PowerShell Setup: Control 2.15 - Environment Routing and Auto-Provisioning

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

Prerequisites

# Install Power Platform admin module
Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -Force -Scope CurrentUser

# 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

Configuration Scripts

List All Environment Groups

# Note: Environment Groups management is primarily done through PPAC portal
# PowerShell can be used for environment inventory and validation

# List all environments with group information
$environments = Get-AdminPowerAppEnvironment

$envReport = $environments | ForEach-Object {
    [PSCustomObject]@{
        Name = $_.DisplayName
        EnvironmentId = $_.EnvironmentName
        Type = $_.EnvironmentType
        Region = $_.Location
        State = $_.States.Runtime
        IsManagedEnv = if ($_.Properties.protectionLevel -eq "Standard") { "No" } else { "Yes" }
    }
}

$envReport | Format-Table

Validate Environment Routing Configuration

<#
.SYNOPSIS
    Validates that environments are properly configured for routing

.DESCRIPTION
    Checks that target environments for routing are:
    - Managed Environments
    - In US region
    - In appropriate state

.EXAMPLE
    .\Validate-EnvironmentRouting.ps1
#>

# 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

Write-Host "=== Environment Routing Validation ===" -ForegroundColor Cyan

# Get all environments
$environments = Get-AdminPowerAppEnvironment

# Check each environment
$validationResults = $environments | ForEach-Object {
    $isManaged = $_.Properties.protectionLevel -ne "Standard"
    $isUSRegion = $_.Location -match "unitedstates|US"
    $isActive = $_.States.Runtime -eq "Enabled"

    [PSCustomObject]@{
        Name = $_.DisplayName
        Type = $_.EnvironmentType
        IsManaged = $isManaged
        IsUSRegion = $isUSRegion
        IsActive = $isActive
        RoutingReady = ($isManaged -and $isUSRegion -and $isActive)
    }
}

# Display results
Write-Host "`n=== Routing Readiness ===" -ForegroundColor Cyan
$validationResults | Format-Table Name, Type, IsManaged, IsUSRegion, IsActive, RoutingReady

# Summary
$readyCount = ($validationResults | Where-Object { $_.RoutingReady }).Count
$totalCount = $validationResults.Count

Write-Host "`nRouting Ready: $readyCount / $totalCount environments"

# Flag environments not ready
$notReady = $validationResults | Where-Object { -not $_.RoutingReady }
if ($notReady) {
    Write-Host "`n=== Environments NOT Ready for Routing ===" -ForegroundColor Yellow
    $notReady | Format-Table Name, Type, IsManaged, IsUSRegion, IsActive
}

Export Environment Group Configuration

<#
.SYNOPSIS
    Exports environment configuration for documentation

.DESCRIPTION
    Creates a JSON export of all environments for routing documentation

.EXAMPLE
    .\Export-EnvironmentConfig.ps1
#>

# 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 all environments
$environments = Get-AdminPowerAppEnvironment

# Build configuration export
$config = @{
    ExportDate = Get-Date -Format "yyyy-MM-dd HH:mm"
    TotalEnvironments = $environments.Count
    Environments = @()
}

foreach ($env in $environments) {
    $envConfig = @{
        Name = $env.DisplayName
        EnvironmentId = $env.EnvironmentName
        Type = $env.EnvironmentType
        Region = $env.Location
        State = $env.States.Runtime
        IsManaged = $env.Properties.protectionLevel -ne "Standard"
        CreatedDate = $env.Properties.createdTime
        CreatedBy = $env.Properties.createdBy.displayName
    }
    $config.Environments += $envConfig
}

# Export to JSON
$config | ConvertTo-Json -Depth 3 | Out-File -FilePath "Environment-Config-$(Get-Date -Format 'yyyyMMdd').json"
Write-Host "Configuration exported to Environment-Config-$(Get-Date -Format 'yyyyMMdd').json"

Validation Script

<#
.SYNOPSIS
    Validates Control 2.15 - Environment Routing configuration

.DESCRIPTION
    Checks environment routing prerequisites and configuration

.EXAMPLE
    .\Validate-Control-2.15.ps1
#>

Write-Host "=== Control 2.15 Validation ===" -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

# Check 1: Verify environments exist for routing
Write-Host "`n[Check 1] Production Environments Available" -ForegroundColor Cyan
$prodEnvs = Get-AdminPowerAppEnvironment | Where-Object { $_.EnvironmentType -eq "Production" }
if ($prodEnvs.Count -gt 0) {
    Write-Host "[PASS] Found $($prodEnvs.Count) production environments" -ForegroundColor Green
    $prodEnvs | ForEach-Object { Write-Host "  - $($_.DisplayName)" }
} else {
    Write-Host "[WARN] No production environments found" -ForegroundColor Yellow
}

# Check 2: Verify Managed Environment status
Write-Host "`n[Check 2] Managed Environment Status" -ForegroundColor Cyan
$managedEnvs = $prodEnvs | Where-Object { $_.Properties.protectionLevel -ne "Standard" }
if ($managedEnvs.Count -eq $prodEnvs.Count) {
    Write-Host "[PASS] All production environments are Managed Environments" -ForegroundColor Green
} else {
    Write-Host "[WARN] Not all production environments are Managed" -ForegroundColor Yellow
    $unmanaged = $prodEnvs | Where-Object { $_.Properties.protectionLevel -eq "Standard" }
    $unmanaged | ForEach-Object { Write-Host "  - $($_.DisplayName) is NOT managed" -ForegroundColor Yellow }
}

# Check 3: Verify US region
Write-Host "`n[Check 3] US Region Compliance" -ForegroundColor Cyan
$usEnvs = $prodEnvs | Where-Object { $_.Location -match "unitedstates|US" }
if ($usEnvs.Count -eq $prodEnvs.Count) {
    Write-Host "[PASS] All production environments are in US region" -ForegroundColor Green
} else {
    Write-Host "[WARN] Some environments may not be in US region" -ForegroundColor Yellow
}

Write-Host "`n=== Validation Complete ===" -ForegroundColor Cyan
Write-Host "Note: Environment Groups and Routing Rules must be verified in PPAC portal"

Complete Configuration Script

<#
.SYNOPSIS
    Complete environment routing configuration for Control 2.15

.DESCRIPTION
    Executes end-to-end environment routing setup including:
    - Environment inventory collection
    - Routing readiness validation
    - Configuration export for documentation

.PARAMETER OutputPath
    Path for output reports

.EXAMPLE
    .\Configure-Control-2.15.ps1 -OutputPath ".\EnvironmentRouting"

.NOTES
    Last Updated: January 2026
    Related Control: Control 2.15 - Environment Routing and Auto-Provisioning
#>

param(
    [string]$OutputPath = ".\EnvironmentRouting-Report"
)

try {
    Write-Host "=== Control 2.15: Environment Routing Configuration ===" -ForegroundColor Cyan

    # Connect to Power Platform
    Add-PowerAppsAccount

    # Ensure output directory exists
    New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null

    # Get all environments
    $environments = Get-AdminPowerAppEnvironment
    Write-Host "[INFO] Found $($environments.Count) environments" -ForegroundColor Cyan

    # Build routing readiness report
    $routingReport = $environments | ForEach-Object {
        $isManaged = $_.Properties.protectionLevel -ne "Standard"
        $isUSRegion = $_.Location -match "unitedstates|US"
        $isActive = $_.States.Runtime -eq "Enabled"
        $isProduction = $_.EnvironmentType -eq "Production"

        [PSCustomObject]@{
            Name = $_.DisplayName
            EnvironmentId = $_.EnvironmentName
            Type = $_.EnvironmentType
            Region = $_.Location
            State = $_.States.Runtime
            IsManaged = $isManaged
            IsUSRegion = $isUSRegion
            IsActive = $isActive
            RoutingReady = ($isManaged -and $isUSRegion -and $isActive)
            CreatedDate = $_.Properties.createdTime
            CreatedBy = $_.Properties.createdBy.displayName
        }
    }

    # Export full inventory
    $routingReport | Export-Csv -Path "$OutputPath\EnvironmentInventory.csv" -NoTypeInformation

    # Display readiness summary
    Write-Host "`n=== Routing Readiness Summary ===" -ForegroundColor Cyan
    $readyCount = ($routingReport | Where-Object { $_.RoutingReady }).Count
    $prodCount = ($routingReport | Where-Object { $_.Type -eq "Production" }).Count
    $managedCount = ($routingReport | Where-Object { $_.IsManaged }).Count

    Write-Host "Total Environments: $($routingReport.Count)"
    Write-Host "Production Environments: $prodCount"
    Write-Host "Managed Environments: $managedCount"
    Write-Host "Routing Ready: $readyCount"

    # Flag environments not ready
    $notReady = $routingReport | Where-Object { $_.Type -eq "Production" -and -not $_.RoutingReady }
    if ($notReady.Count -gt 0) {
        Write-Host "`n[WARN] Production environments NOT ready for routing:" -ForegroundColor Yellow
        $notReady | Select-Object Name, IsManaged, IsUSRegion, IsActive | Format-Table -AutoSize
        $notReady | Export-Csv -Path "$OutputPath\NotRoutingReady.csv" -NoTypeInformation
    } else {
        Write-Host "`n[PASS] All production environments are routing-ready" -ForegroundColor Green
    }

    # Export configuration for documentation
    $config = @{
        ExportDate = Get-Date -Format "yyyy-MM-dd HH:mm"
        TotalEnvironments = $environments.Count
        ProductionEnvironments = $prodCount
        ManagedEnvironments = $managedCount
        RoutingReadyEnvironments = $readyCount
    }
    $config | ConvertTo-Json | Out-File -FilePath "$OutputPath\RoutingConfig.json"

    Write-Host "`n[PASS] Control 2.15 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 applicable
    # Note: Add-PowerAppsAccount does not require explicit disconnect
}

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