Skip to content

Control 1.8: Runtime Protection and External Threat Detection - PowerShell Setup

This playbook provides PowerShell automation guidance for Control 1.8.


Connect to Power Platform

Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -Force

# 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 Managed Environment Status

$Environments = Get-AdminPowerAppEnvironment

$EnvReport = @()
foreach ($Env in $Environments) {
    $EnvReport += [PSCustomObject]@{
        DisplayName = $Env.DisplayName
        EnvironmentName = $Env.EnvironmentName
        IsManaged = $Env.Properties.protectionLevel -eq "Standard"
        Location = $Env.Location
        EnvironmentType = $Env.EnvironmentType
    }
}

Write-Host "Managed Environment Status:" -ForegroundColor Cyan
$EnvReport | Format-Table -AutoSize

Create Webhook App Registration for Defender Integration

The following script automates the creation of an Entra app registration with Federated Identity Credentials (FIC) for Additional Threat Detection.

<#
.SYNOPSIS
    Creates Entra app registration for Copilot Studio Defender integration.

.DESCRIPTION
    This script:
    1. Creates an Entra app registration for webhook authentication
    2. Configures Federated Identity Credentials (FIC) for secure token exchange
    3. Outputs the Application ID for Power Platform configuration

.PARAMETER TenantId
    Your Microsoft Entra ID tenant ID (GUID format)

.PARAMETER WebhookEndpoint
    The full HTTPS URL of your security provider webhook

.PARAMETER DisplayName
    Optional display name for the app registration (default: CopilotStudio-ThreatDetection-Webhook)

.PARAMETER FICName
    Optional name for the Federated Identity Credential (default: CopilotStudio-FIC)

.EXAMPLE
    .\Create-CopilotWebhookApp.ps1 -TenantId "12345678-1234-1234-1234-123456789012" `
        -WebhookEndpoint "https://defender-webhook.azurewebsites.net/api/evaluate"

.EXAMPLE
    .\Create-CopilotWebhookApp.ps1 -TenantId "12345678-1234-1234-1234-123456789012" `
        -WebhookEndpoint "https://my-security-provider.com/webhook" `
        -DisplayName "Copilot-Defender-Prod" `
        -FICName "DefenderFIC-Prod"

.NOTES
    Last Updated: February 2026
    Related Control: Control 1.8 - Runtime Protection and External Threat Detection
    Requires: Microsoft.Graph PowerShell module with Application.ReadWrite.All permission
#>

param(
    [Parameter(Mandatory=$true)]
    [ValidatePattern('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')]
    [string]$TenantId,

    [Parameter(Mandatory=$true)]
    [ValidatePattern('^https://')]
    [string]$WebhookEndpoint,

    [Parameter(Mandatory=$false)]
    [string]$DisplayName = "CopilotStudio-ThreatDetection-Webhook",

    [Parameter(Mandatory=$false)]
    [string]$FICName = "CopilotStudio-FIC"
)

try {
    Write-Host "=== Creating Copilot Studio Defender Integration App ===" -ForegroundColor Cyan

    # Connect to Microsoft Graph
    Write-Host "`nStep 1: Connecting to Microsoft Graph..." -ForegroundColor White
    Connect-MgGraph -Scopes "Application.ReadWrite.All" -TenantId $TenantId

    # Create app registration
    Write-Host "`nStep 2: Creating app registration..." -ForegroundColor White
    $AppParams = @{
        DisplayName = $DisplayName
        SignInAudience = "AzureADMyOrg"
        Description = "Enables Copilot Studio to authenticate with external threat detection provider"
        Tags = @("CopilotStudio", "ThreatDetection", "FSI-AgentGov")
    }

    $App = New-MgApplication @AppParams

    Write-Host "  [DONE] App registration created" -ForegroundColor Green
    Write-Host "  Application ID: $($App.AppId)" -ForegroundColor Yellow
    Write-Host "  Object ID: $($App.Id)" -ForegroundColor Yellow

    # Encode values for FIC subject identifier
    Write-Host "`nStep 3: Encoding FIC subject identifier..." -ForegroundColor White
    $TenantIdBase64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($TenantId))
    $EndpointBase64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($WebhookEndpoint))

    Write-Host "  Tenant ID (Base64): $TenantIdBase64" -ForegroundColor Gray
    Write-Host "  Endpoint (Base64): $EndpointBase64" -ForegroundColor Gray

    # Configure Federated Identity Credential
    Write-Host "`nStep 4: Configuring Federated Identity Credential..." -ForegroundColor White
    $SubjectIdentifier = "/eid1/c/pub/t/$TenantIdBase64/a/m1WPnYRZpEaQKq1Cceg--g/$EndpointBase64"

    $FicParams = @{
        ApplicationId = $App.Id
        BodyParameter = @{
            Name = $FICName
            Issuer = "https://login.microsoftonline.com/$TenantId/v2.0"
            Subject = $SubjectIdentifier
            Audiences = @("api://AzureADTokenExchange")
            Description = "FIC for Power Platform Copilot Studio threat detection"
        }
    }

    New-MgApplicationFederatedIdentityCredential @FicParams

    Write-Host "  [DONE] Federated Identity Credential configured" -ForegroundColor Green

    # Output summary
    Write-Host "`n=== CONFIGURATION COMPLETE ===" -ForegroundColor Cyan
    Write-Host "Use these values in Power Platform Admin Center:" -ForegroundColor White
    Write-Host ""
    Write-Host "  Azure Entra App ID: $($App.AppId)" -ForegroundColor Yellow
    Write-Host "  Endpoint Link:      $WebhookEndpoint" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "Portal Path: Power Platform Admin Center > Security > Threat detection > Additional threat detection" -ForegroundColor Gray

    # Return app details for automation
    return [PSCustomObject]@{
        ApplicationId = $App.AppId
        ObjectId = $App.Id
        DisplayName = $DisplayName
        WebhookEndpoint = $WebhookEndpoint
        FICName = $FICName
        TenantId = $TenantId
    }
}
catch {
    Write-Host "[FAIL] Error: $($_.Exception.Message)" -ForegroundColor Red
    Write-Host "[INFO] Ensure you have Application.ReadWrite.All permission in Microsoft Graph" -ForegroundColor Yellow
    throw
}

Verify App Registration and FIC Configuration

<#
.SYNOPSIS
    Verifies existing Copilot Studio Defender integration app registration.

.DESCRIPTION
    Checks that the app registration and FIC are configured correctly.

.PARAMETER AppId
    The Application (client) ID to verify

.EXAMPLE
    .\Verify-CopilotWebhookApp.ps1 -AppId "12345678-1234-1234-1234-123456789012"
#>

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

try {
    Connect-MgGraph -Scopes "Application.Read.All"

    # Get app registration by AppId
    $App = Get-MgApplication -Filter "appId eq '$AppId'"

    if (-not $App) {
        Write-Host "[FAIL] App registration not found: $AppId" -ForegroundColor Red
        return
    }

    Write-Host "=== App Registration Verification ===" -ForegroundColor Cyan
    Write-Host "Display Name: $($App.DisplayName)" -ForegroundColor Green
    Write-Host "Application ID: $($App.AppId)" -ForegroundColor Green
    Write-Host "Object ID: $($App.Id)" -ForegroundColor Green
    Write-Host "Sign-In Audience: $($App.SignInAudience)" -ForegroundColor Green

    # Get Federated Identity Credentials
    $Fics = Get-MgApplicationFederatedIdentityCredential -ApplicationId $App.Id

    if ($Fics.Count -eq 0) {
        Write-Host "[WARN] No Federated Identity Credentials found" -ForegroundColor Yellow
    } else {
        Write-Host "`n=== Federated Identity Credentials ===" -ForegroundColor Cyan
        foreach ($Fic in $Fics) {
            Write-Host "Name: $($Fic.Name)" -ForegroundColor Green
            Write-Host "Issuer: $($Fic.Issuer)" -ForegroundColor Gray
            Write-Host "Subject: $($Fic.Subject)" -ForegroundColor Gray
            Write-Host "Audiences: $($Fic.Audiences -join ', ')" -ForegroundColor Gray
            Write-Host ""
        }
    }

    Write-Host "[PASS] App registration verification complete" -ForegroundColor Green
}
catch {
    Write-Host "[FAIL] Error: $($_.Exception.Message)" -ForegroundColor Red
}

Enable Additional Threat Detection via Power Platform API

For organizations wanting to automate threat detection configuration across multiple environments:

<#
.SYNOPSIS
    Configures Additional Threat Detection for Power Platform environments via API.

.DESCRIPTION
    Uses Power Platform Admin API to enable threat detection at environment level.
    Note: This is an advanced automation scenario. Portal configuration is recommended for initial setup.

.PARAMETER EnvironmentId
    The Power Platform environment ID (GUID)

.PARAMETER AppId
    The Entra app registration Application ID

.PARAMETER WebhookEndpoint
    The security provider webhook URL

.PARAMETER ErrorBehavior
    "Allow" or "Block" - behavior when provider is unavailable

.EXAMPLE
    .\Configure-ThreatDetection.ps1 -EnvironmentId "env-guid" -AppId "app-guid" `
        -WebhookEndpoint "https://webhook.example.com" -ErrorBehavior "Block"
#>

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

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

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

    [Parameter(Mandatory=$false)]
    [ValidateSet("Allow", "Block")]
    [string]$ErrorBehavior = "Block"
)

try {
    # Connect to Power Platform
    Add-PowerAppsAccount

    Write-Host "=== Configuring Additional Threat Detection ===" -ForegroundColor Cyan
    Write-Host "Environment: $EnvironmentId" -ForegroundColor White
    Write-Host "Error Behavior: $ErrorBehavior" -ForegroundColor White

    # Note: Direct API configuration requires Power Platform Admin API access
    # This example shows the configuration structure

    $ThreatDetectionConfig = @{
        isEnabled = $true
        enableDataSharing = $true
        applicationId = $AppId
        endpointUrl = $WebhookEndpoint
        errorBehavior = $ErrorBehavior
    }

    Write-Host "`nConfiguration to apply:" -ForegroundColor Yellow
    $ThreatDetectionConfig | Format-List

    # Note: No dedicated threat-detection cmdlet exists as of Feb 2026.
    # Use the Power Platform Admin Center UI or the admin connector REST API instead.

    Write-Host "`n[INFO] Use Power Platform Admin Center UI for initial configuration" -ForegroundColor Yellow
    Write-Host "[INFO] API automation is recommended for bulk deployment after initial validation" -ForegroundColor Yellow
}
catch {
    Write-Host "[FAIL] Error: $($_.Exception.Message)" -ForegroundColor Red
}

Audit Log Analysis for Threats

# Connect to Security & Compliance
Connect-IPPSSession

$StartDate = (Get-Date).AddDays(-7)
$EndDate = Get-Date

# Search for Copilot Studio security events
$SecurityEvents = Search-UnifiedAuditLog `
    -StartDate $StartDate `
    -EndDate $EndDate `
    -RecordType CopilotInteraction `
    -ResultSize 1000

Write-Host "Copilot interaction events found: $($SecurityEvents.Count)" -ForegroundColor Yellow

# Parse for security-relevant events
$SecurityAnalysis = $SecurityEvents | ForEach-Object {
    $AuditData = $_.AuditData | ConvertFrom-Json

    [PSCustomObject]@{
        Date = $_.CreationDate
        User = $_.UserIds
        Operation = $AuditData.Operation
        AppName = $AuditData.AppName
        Result = $AuditData.ResultStatus
        SecurityFlag = if ($AuditData.Operation -match "block|inject|jailbreak") { "ALERT" } else { "Normal" }
    }
}

# Identify potential threats
$Threats = $SecurityAnalysis | Where-Object { $_.SecurityFlag -eq "ALERT" }

if ($Threats.Count -gt 0) {
    Write-Host "POTENTIAL THREATS DETECTED:" -ForegroundColor Red
    $Threats | Format-Table
} else {
    Write-Host "No threat indicators found in period" -ForegroundColor Green
}

Check Connector Security

# Get connectors used by agents in managed environments
$Connectors = Get-AdminPowerAppConnector

$HighRiskConnectors = $Connectors | Where-Object {
    $_.Properties.displayName -match "HTTP|Custom|SQL|File"
}

if ($HighRiskConnectors.Count -gt 0) {
    Write-Host "High-risk connectors requiring review:" -ForegroundColor Yellow
    $HighRiskConnectors | Select-Object @{N='Name'; E={$_.Properties.displayName}}, ConnectorId | Format-Table
}

Generate Security Report

$Report = @{
    ReportDate = Get-Date
    AnalysisPeriod = "$StartDate to $EndDate"
    TotalCopilotEvents = $SecurityEvents.Count
    ThreatIndicators = $Threats.Count
    ManagedEnvironments = ($EnvReport | Where-Object { $_.IsManaged }).Count
    UnmanagedEnvironments = ($EnvReport | Where-Object { -not $_.IsManaged }).Count
}

Write-Host "=== RUNTIME PROTECTION SECURITY SUMMARY ===" -ForegroundColor Cyan
$Report | Format-List

# Export detailed report
$SecurityAnalysis | Export-Csv "RuntimeProtection-Analysis-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation

Sentinel Detection Rule (KQL)

// Prompt Injection Detection
PowerPlatformAdminActivity
| where Operation == "PromptInjectionDetected"
| extend AgentName = tostring(parse_json(ExtendedProperties).AgentName)
| project TimeGenerated, UserId, AgentName, ClientIP, Operation
| order by TimeGenerated desc

Complete Configuration Script

<#
.SYNOPSIS
    Configures Control 1.8 - Runtime Protection and External Threat Detection

.DESCRIPTION
    This script:
    1. Audits Managed Environment status across all environments
    2. Searches audit logs for security events
    3. Identifies high-risk connectors
    4. Generates security analysis report

.PARAMETER TenantId
    Microsoft Entra ID tenant ID for webhook configuration (optional)

.PARAMETER OutputPath
    Path for security reports (default: current directory)

.EXAMPLE
    .\Configure-Control-1.8.ps1 -OutputPath "C:\SecurityReports"

.NOTES
    Last Updated: February 2026
    Related Control: Control 1.8 - Runtime Protection and External Threat Detection
#>

param(
    [Parameter(Mandatory=$false)]
    [string]$TenantId,

    [Parameter(Mandatory=$false)]
    [string]$OutputPath = "."
)

try {
    # Connect to Power Platform
    Add-PowerAppsAccount

    Write-Host "=== Configuring Control 1.8: Runtime Protection ===" -ForegroundColor Cyan

    # Step 1: Get Managed Environment status for all environments
    Write-Host "`nStep 1: Auditing Managed Environment status..." -ForegroundColor White
    $Environments = Get-AdminPowerAppEnvironment

    $EnvReport = @()
    foreach ($Env in $Environments) {
        $EnvReport += [PSCustomObject]@{
            DisplayName = $Env.DisplayName
            EnvironmentName = $Env.EnvironmentName
            IsManaged = $Env.Properties.protectionLevel -eq "Standard"
            Location = $Env.Location
            EnvironmentType = $Env.EnvironmentType
        }
    }

    $managedCount = ($EnvReport | Where-Object { $_.IsManaged }).Count
    $unmanagedCount = ($EnvReport | Where-Object { -not $_.IsManaged }).Count

    Write-Host "  [DONE] Managed: $managedCount | Unmanaged: $unmanagedCount" -ForegroundColor Green
    $EnvReport | Format-Table DisplayName, IsManaged, EnvironmentType -AutoSize

    # Step 2: Connect to Security & Compliance and search for threat events
    Write-Host "`nStep 2: Searching for security events..." -ForegroundColor White
    Connect-IPPSSession

    $StartDate = (Get-Date).AddDays(-7)
    $EndDate = Get-Date

    $SecurityEvents = Search-UnifiedAuditLog `
        -StartDate $StartDate `
        -EndDate $EndDate `
        -RecordType CopilotInteraction `
        -ResultSize 1000

    Write-Host "  [DONE] Found $($SecurityEvents.Count) Copilot interaction events" -ForegroundColor Green

    # Step 3: Analyze security events
    Write-Host "`nStep 3: Analyzing for threat indicators..." -ForegroundColor White
    $SecurityAnalysis = $SecurityEvents | ForEach-Object {
        $AuditData = $_.AuditData | ConvertFrom-Json

        [PSCustomObject]@{
            Date = $_.CreationDate
            User = $_.UserIds
            Operation = $AuditData.Operation
            AppName = $AuditData.AppName
            Result = $AuditData.ResultStatus
            SecurityFlag = if ($AuditData.Operation -match "block|inject|jailbreak") { "ALERT" } else { "Normal" }
        }
    }

    $Threats = $SecurityAnalysis | Where-Object { $_.SecurityFlag -eq "ALERT" }

    if ($Threats.Count -gt 0) {
        Write-Host "  [ALERT] Potential threats detected: $($Threats.Count)" -ForegroundColor Red
        $Threats | Format-Table Date, User, Operation -AutoSize
    } else {
        Write-Host "  [PASS] No threat indicators found in period" -ForegroundColor Green
    }

    # Step 4: Check for high-risk connectors
    Write-Host "`nStep 4: Checking for high-risk connectors..." -ForegroundColor White
    $Connectors = Get-AdminPowerAppConnector

    $HighRiskConnectors = $Connectors | Where-Object {
        $_.Properties.displayName -match "HTTP|Custom|SQL|File"
    }

    if ($HighRiskConnectors.Count -gt 0) {
        Write-Host "  [WARN] High-risk connectors requiring review: $($HighRiskConnectors.Count)" -ForegroundColor Yellow
        $HighRiskConnectors | Select-Object @{N='Name'; E={$_.Properties.displayName}}, ConnectorId | Format-Table
    } else {
        Write-Host "  [PASS] No high-risk connectors detected" -ForegroundColor Green
    }

    # Step 5: Generate and export security report
    Write-Host "`nStep 5: Generating security report..." -ForegroundColor White
    $Report = @{
        ReportDate = Get-Date
        AnalysisPeriod = "$StartDate to $EndDate"
        TotalCopilotEvents = $SecurityEvents.Count
        ThreatIndicators = $Threats.Count
        ManagedEnvironments = $managedCount
        UnmanagedEnvironments = $unmanagedCount
        HighRiskConnectors = $HighRiskConnectors.Count
    }

    Write-Host "`n=== RUNTIME PROTECTION SECURITY SUMMARY ===" -ForegroundColor Cyan
    $Report | Format-List

    # Export detailed report
    $SecurityAnalysis | Export-Csv "$OutputPath\RuntimeProtection-Analysis-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
    $EnvReport | Export-Csv "$OutputPath\ManagedEnvironments-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation

    Write-Host "  [DONE] Reports exported to: $OutputPath" -ForegroundColor Green

    Write-Host "`n[PASS] Control 1.8 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 {
    # Disconnect from Security & Compliance Center
    Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue
}

Updated: February 2026 | Version: v1.3