Bypass connector consent cards for an agent

When an agent uses a connector for the first time on behalf of a user, the agent presents a consent card in the conversation. Administrators can bypass those consent cards for a specific agent by using the connector consent-bypass setting in the Power Platform API.

This article explains the one-time tenant setup and the PowerShell commands used to read or change the connector consent-bypass setting for a Copilot Studio agent.

Note

Disabling consent applies only to agents powered by the standard harness. It doesn't apply to the GitHub Copilot harness.

Prerequisites

  • The ConsentBypass-CopilotStudio.ps1 script is available on the computer that runs the commands. The script is provided in PowerShell script.
  • The signed-in account has one of these Microsoft Entra roles:
    • Power Platform Administrator (least privilege of the listed roles)
    • AI Administrator
    • Global Administrator
  • A single-tenant Microsoft Entra application is configured for interactive authentication.
  • The application has the CopilotStudio.AdminActions.Invoke delegated Power Platform API permission.

Part A: One-time tenant setup

If the application registration is already configured in the tenant, skip to Part B: Run the commands.

Step 1: Register the Microsoft Entra application

  1. Sign in to the Azure portal and go to Microsoft Entra ID > App registrations.

  2. Select New registration.

  3. Configure the application:

    Setting Value
    Name CopilotStudioConsentBypassPS
    Supported account types Accounts in this organizational directory only (single tenant)
    Redirect URI platform Public client/native (mobile and desktop)
    Redirect URI http://localhost
  4. Select Register.

  5. Copy the Application (client) ID from the application overview page.

Step 2: Add Power Platform API permissions

  1. Open the app registration and select API permissions > Add a permission.

  2. Select APIs my organization uses.

  3. Search for Power Platform API. Its production application ID is:

    8578e004-a5c6-46e7-913e-12f58912df43
    
  4. Select Delegated permissions.

  5. Add this permission:

    CopilotStudio.AdminActions.Invoke
    
  6. Complete any consent action that your tenant's policies require.

Step 3: Assign an administrator role

A Global Administrator must assign one of the supported roles to each user who runs the script. Power Platform Administrator is the least-privilege option of the three supported roles.

In the Azure portal, go to Microsoft Entra ID > Roles and administrators, select the role, and then add the user under Assignments.

Part B: Run the commands

Step 4: Find the environment ID and agent ID

Open the agent in Copilot Studio. Its URL contains the environment and agent identifiers, in a form similar to:

https://copilotstudio.microsoft.com/environments/{environmentId}/bots/{botId}/overview

The examples in this article use these sample values:

Identifier Value
Tenant ID b7f2c418-6d9a-4e31-8a52-1c3f7d90e6ab
Application (client) ID c3a7f921-84de-4b65-9f12-6d0e8a42b7c5
Environment ID 7d91e4b2-a638-4f0c-b527-9e6a13d8c045
Bot ID e6b4c2a9-17f3-48d5-8c01-2a9f7e63b4d8

These values aren't functional. Replace them with the tenant, application, environment, and agent IDs for your setup.

Step 5: Allow the script to run

Open PowerShell and change to the folder that contains the script. If the execution policy blocks unsigned scripts, allow them for the current PowerShell process only:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force

This setting resets when the PowerShell window closes. If Windows marked the downloaded file as blocked, also run:

Unblock-File -Path .\ConsentBypass-CopilotStudio.ps1

Step 6: Load the functions and sign in

  1. Dot-source the script to load its functions into the current PowerShell session:

    . .\ConsentBypass-CopilotStudio.ps1
    
  2. Connect using the tenant and client IDs:

    Connect-CopilotStudioAdmin -TenantId "b7f2c418-6d9a-4e31-8a52-1c3f7d90e6ab" -ClientId "c3a7f921-84de-4b65-9f12-6d0e8a42b7c5"
    

    A browser window opens for interactive sign-in. Sign in with an account that has one of the required administrator roles, and accept the permission prompt if one appears.

The authentication token is cached only for the current PowerShell session. Repeat steps 5 and 6 after you open a new PowerShell window.

Step 7: Read the current setting

This command only reads the setting. It doesn't change the setting.

Get-AdminCopilotStudioBotConnectorConsentBypass -EnvironmentId "7d91e4b2-a638-4f0c-b527-9e6a13d8c045" -BotId "e6b4c2a9-17f3-48d5-8c01-2a9f7e63b4d8"

The returned AdminConsentBypass value indicates the current state:

  • True: Consent cards are bypassed.
  • False: Consent cards are shown.
Set-AdminCopilotStudioBotConnectorConsentBypass -EnvironmentId "7d91e4b2-a638-4f0c-b527-9e6a13d8c045" -BotId "e6b4c2a9-17f3-48d5-8c01-2a9f7e63b4d8" -BypassConsent $true

Use $false to restore the normal consent-card behavior:

Set-AdminCopilotStudioBotConnectorConsentBypass -EnvironmentId "7d91e4b2-a638-4f0c-b527-9e6a13d8c045" -BotId "e6b4c2a9-17f3-48d5-8c01-2a9f7e63b4d8" -BypassConsent $false

Run the command in Step 7: Read the current setting again to confirm the resulting state.

Troubleshooting

Message or status Resolution
Not authenticated. Run Connect-CopilotStudioAdmin first. Run the connection command in the same PowerShell session.
Script execution is turned off Run the process-scoped execution-policy command in step 5.
The downloaded script is blocked Run the Unblock-File command in step 5.

PowerShell script

  1. Copy the entire contents of the following PowerShell code block.
  2. Save the contents in a file named ConsentBypass-CopilotStudio.ps1.
  3. Make sure that you save the file with the .ps1 extension, not .txt.
  4. Place the file in the folder from which you run the commands in this article.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

$script:EnvConfig = @{
    Prod    = @{
        EnvApiDomain  = "environment.api.powerplatform.com"
        Scopes        = @(
            "https://api.powerplatform.com/copilotstudio.adminactions.invoke"
        )
    }
}

$script:AuthToken       = $null
$script:AuthEnvironment = $null
$script:AuthAccount     = $null

function Connect-CopilotStudioAdmin {

    [CmdletBinding()]
    param(
        [Parameter()]
        [string]$TenantId = "",

        [Parameter(Mandatory)]
        [string]$ClientId
    )

    CsAdmin_EnsureMsalPs

    $Environment = "Prod"
    $cfg = $script:EnvConfig[$Environment]
    $tenantToUse = if ($TenantId) { $TenantId } else { "organizations" }

    Write-Host ""
    Write-Host "  Copilot Studio Admin -- Connect ($Environment)" -ForegroundColor Cyan
    Write-Host "  Client : $ClientId" -ForegroundColor DarkGray
    Write-Host "  Tenant : $tenantToUse" -ForegroundColor DarkGray
    Write-Host "  Scopes : $($cfg.Scopes -join ', ')" -ForegroundColor DarkGray
    Write-Host "  (A browser window will open for sign-in)" -ForegroundColor DarkGray
    Write-Host ""

    try {
        $result = Get-MsalToken -ClientId $ClientId -TenantId $tenantToUse -Scopes $cfg.Scopes -Interactive -RedirectUri "http://localhost"
    }
    catch {
        Write-Host "[AUTH ERROR] $($_.Exception.Message)" -ForegroundColor Red
        throw
    }

    $script:AuthToken       = $result.AccessToken
    $script:AuthEnvironment = $Environment
    $script:AuthAccount     = $result.Account.Username

    Write-Host "  Authenticated as : $($script:AuthAccount)" -ForegroundColor Green
    Write-Host "  Token expires    : $($result.ExpiresOn.LocalDateTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Green
    Write-Host "  Scopes granted   : $($result.Scopes -join ' ')" -ForegroundColor DarkGray
    Write-Host ""
}

function Get-AdminCopilotStudioBotConnectorConsentBypass {

    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [string]$EnvironmentId,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [string]$BotId
    )

    CsAdmin_AssertConnected

    $url     = CsAdmin_BuildPpapiUrl -EnvironmentId $EnvironmentId -BotId $BotId
    $headers = CsAdmin_BuildHeaders

    Write-Host "[GET] $url" -ForegroundColor DarkCyan
    Write-Host "[AUTH] Account: $script:AuthAccount  Environment: $script:AuthEnvironment" -ForegroundColor DarkGray

    try {
        $response = Invoke-RestMethod -Method GET -Uri $url -Headers $headers
        Write-Host "[200] OK" -ForegroundColor Green
        Write-Host "[BODY] $($response | ConvertTo-Json -Compress)" -ForegroundColor DarkGray
        [PSCustomObject]@{
            EnvironmentId    = $EnvironmentId
            BotId            = $BotId
            AdminConsentBypass = [bool]$response.adminConsentBypass
        }
    }
    catch {
        CsAdmin_WriteHttpError -ErrorRecord $_
    }
}

function Set-AdminCopilotStudioBotConnectorConsentBypass {

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Medium")]
    param(
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [string]$EnvironmentId,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [string]$BotId,

        [Parameter(Mandatory)]
        [bool]$BypassConsent
    )

    CsAdmin_AssertConnected

    $action = if ($BypassConsent) { "ENABLE (bypass consent cards)" } else { "DISABLE (restore consent cards)" }
    if (-not $PSCmdlet.ShouldProcess("Bot '$BotId' in environment '$EnvironmentId'", $action)) {
        return
    }

    $url     = CsAdmin_BuildPpapiUrl -EnvironmentId $EnvironmentId -BotId $BotId
    $headers = CsAdmin_BuildHeaders
    $body    = @{ adminConsentBypass = $BypassConsent } | ConvertTo-Json -Compress

    Write-Host "[PUT] $url" -ForegroundColor DarkCyan
    Write-Host "[AUTH] Account: $script:AuthAccount  Environment: $script:AuthEnvironment" -ForegroundColor DarkGray
    Write-Host "[BODY] $body" -ForegroundColor DarkGray

    try {
        $response = Invoke-RestMethod -Method PUT -Uri $url -Headers $headers -Body $body -ContentType "application/json"
        Write-Host "[200] OK" -ForegroundColor Green
        Write-Host "[BODY] $($response | ConvertTo-Json -Compress)" -ForegroundColor DarkGray
        [PSCustomObject]@{
            EnvironmentId    = $EnvironmentId
            BotId            = $BotId
            AdminConsentBypass = [bool]$response.adminConsentBypass
        }
    }
    catch {
        CsAdmin_WriteHttpError -ErrorRecord $_
    }
}

function CsAdmin_EnsureMsalPs {
    if (-not (Get-Module -ListAvailable -Name MSAL.PS -ErrorAction SilentlyContinue)) {
        Write-Host "[auth] Installing MSAL.PS from PSGallery..." -ForegroundColor Yellow
        Install-Module -Name MSAL.PS -Scope CurrentUser -Force -AllowClobber
    }
    Import-Module MSAL.PS -ErrorAction Stop
}

function CsAdmin_AssertConnected {
    if (-not $script:AuthToken) {
        throw "Not authenticated. Run Connect-CopilotStudioAdmin first."
    }
}

function CsAdmin_BuildPpapiUrl {
    param(
        [string]$EnvironmentId,
        [string]$BotId
    )
    $cfg = $script:EnvConfig[$script:AuthEnvironment]

    $normalized = $EnvironmentId.ToLower() -replace '-', ''
    $subdomain  = $normalized.Substring(0, $normalized.Length - 1)
    $island     = $normalized[$normalized.Length - 1]
    return "https://api.powerplatform.com/copilotstudio/environments/$EnvironmentId/bots/$BotId/api/connectorConsentBypass?api-version=2022-03-01-preview"
}

function CsAdmin_BuildHeaders {
    return @{
        "Authorization" = "Bearer $($script:AuthToken)"
        "Content-Type"  = "application/json"
        "Accept"        = "application/json"
    }
}

function CsAdmin_WriteHttpError {

    param(
        [Parameter(Mandatory)]
        $ErrorRecord
    )

    $statusCode = $null
    $respBody   = $null

    if ($ErrorRecord.ErrorDetails -and $ErrorRecord.ErrorDetails.Message) {
        $respBody = $ErrorRecord.ErrorDetails.Message
    }
    try {
        $webResp = $ErrorRecord.Exception.Response
        if ($webResp) {
            $statusCode = [int]$webResp.StatusCode
            if (-not $respBody) {
                try {
                    $reader = New-Object System.IO.StreamReader($webResp.GetResponseStream())
                    $respBody = $reader.ReadToEnd()
                } catch { $respBody = "(could not read response body)" }
            }
        }
    } catch { }

    Write-Host "[ERROR] HTTP $statusCode" -ForegroundColor Red
    Write-Host "[ERROR BODY] $respBody" -ForegroundColor Red
    Write-Host "[EXCEPTION] $($ErrorRecord.Exception.Message)" -ForegroundColor Red

    switch ($statusCode) {
        400     { Write-Error "Bad request (400). Verify EnvironmentId and BotId are valid GUIDs." }
        403     { Write-Error "Access denied (403). Ensure your account has GlobalAdministrator, PowerPlatformAdministrator, or AIAdministrator role." }
        404     { Write-Error "Not found (404). Check that EnvironmentId and BotId are correct GUIDs and the bot belongs to this environment." }
        405     { Write-Error "Method not allowed (405). Disabling consent through this script is not supported for this environment/realm" }
        default { Write-Error "Request failed (HTTP $statusCode): $($ErrorRecord.Exception.Message)" }
    }
}