Skip to content

Control 1.11: Conditional Access and Phishing-Resistant MFA - PowerShell Setup

This playbook provides PowerShell automation guidance for Control 1.11.


Connect to Microsoft Graph

# Install Microsoft Graph module if needed
Install-Module Microsoft.Graph -Force -AllowClobber

# Connect with appropriate scopes
Connect-MgGraph -Scopes "Policy.Read.All","Policy.ReadWrite.ConditionalAccess","Directory.Read.All","AuditLog.Read.All"

# Verify connection
Get-MgContext

Get Conditional Access Policies

# List all Conditional Access policies
Get-MgIdentityConditionalAccessPolicy |
    Select-Object DisplayName, State, CreatedDateTime, ModifiedDateTime |
    Format-Table

# Get details of a specific policy
$policy = Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq 'Require MFA for Agent Creators'"
$policy | ConvertTo-Json -Depth 10

Get Authentication Strengths

# List available authentication strengths
Get-MgPolicyAuthenticationStrengthPolicy |
    Select-Object Id, DisplayName, Description, PolicyType |
    Format-Table -AutoSize

# Get phishing-resistant strength ID
$phishingResistant = Get-MgPolicyAuthenticationStrengthPolicy |
    Where-Object { $_.DisplayName -match "phishing" -or $_.DisplayName -match "resistant" } |
    Select-Object -First 1

$phishingResistant | Format-List Id, DisplayName, Description

Create Conditional Access Policy

# Discover phishing-resistant Authentication Strength policy Id
$phishingResistantStrengthId = (Get-MgPolicyAuthenticationStrengthPolicy |
    Where-Object { $_.DisplayName -match "phishing" -and $_.DisplayName -match "resistant" } |
    Select-Object -First 1).Id

if (-not $phishingResistantStrengthId) {
    throw "Could not find phishing-resistant Authentication Strength policy."
}

# Define policy for enterprise agent creators
$params = @{
    DisplayName = "FSI-Enterprise-Agent-Creators-PhishingResistantMFA"
    State = "enabledForReportingButNotEnforced"  # Start in report-only
    Conditions = @{
        Users = @{
            IncludeGroups = @("sg-enterprise-agent-creators")
            ExcludeGroups = @("sg-emergency-access")
        }
        Applications = @{
            IncludeApplications = @("All")
        }
        ClientAppTypes = @("all")
    }
    GrantControls = @{
        Operator = "OR"
        BuiltInControls = @()
        AuthenticationStrength = @{
            Id = $phishingResistantStrengthId
        }
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Configure Named Locations

# Create a named location for corporate offices
$namedLocationParams = @{
    "@odata.type" = "#microsoft.graph.ipNamedLocation"
    DisplayName = "Corporate Offices"
    IsTrusted = $true
    IpRanges = @(
        @{
            "@odata.type" = "#microsoft.graph.iPv4CidrRange"
            CidrAddress = "203.0.113.0/24"
        },
        @{
            "@odata.type" = "#microsoft.graph.iPv4CidrRange"
            CidrAddress = "198.51.100.0/24"
        }
    )
}

New-MgIdentityConditionalAccessNamedLocation -BodyParameter $namedLocationParams

# List named locations
Get-MgIdentityConditionalAccessNamedLocation |
    Select-Object DisplayName, IsTrusted, CreatedDateTime |
    Format-Table

Audit Agent Sign-In Activity

# Get sign-in logs for agents (requires Graph beta endpoint)
$agentSignIns = Get-MgBetaAuditLogSignIn -Filter "isInteractive eq false and signInEventTypes/any(t: t eq 'nonInteractiveUser')" -Top 100

# Filter for agent-related sign-ins
$agentSignIns | Where-Object { $_.AppDisplayName -match "Copilot|Agent|Bot" } |
    Select-Object CreatedDateTime, UserDisplayName, AppDisplayName, Status, ConditionalAccessStatus |
    Format-Table

# Export agent sign-in report
$agentSignIns | Export-Csv -Path "Agent-SignIn-Report.csv" -NoTypeInformation

Monitor CA Policy Enforcement

# Get CA policy application results from sign-in logs
$caResults = Get-MgBetaAuditLogSignIn -Filter "createdDateTime ge $(Get-Date).AddDays(-7).ToString('yyyy-MM-ddTHH:mm:ssZ')" -Top 500

# Analyze CA enforcement
$caResults | ForEach-Object {
    foreach ($caPolicy in $_.AppliedConditionalAccessPolicies) {
        [PSCustomObject]@{
            Date = $_.CreatedDateTime
            User = $_.UserDisplayName
            PolicyName = $caPolicy.DisplayName
            Result = $caPolicy.Result
            GrantControls = ($caPolicy.GrantControls -join ", ")
        }
    }
} | Group-Object PolicyName, Result |
    Select-Object Name, Count |
    Sort-Object Count -Descending |
    Format-Table

# Export CA enforcement report
$caResults | Export-Csv -Path "CA-Enforcement-Report.csv" -NoTypeInformation

Export Policies for Evidence

# Export all CA policies as JSON
$policies = Get-MgIdentityConditionalAccessPolicy
$policies | ConvertTo-Json -Depth 10 | Out-File "CA-Policies-Export-$(Get-Date -Format 'yyyyMMdd').json"

# Export authentication strengths
$strengths = Get-MgPolicyAuthenticationStrengthPolicy
$strengths | ConvertTo-Json -Depth 10 | Out-File "AuthStrengths-Export-$(Get-Date -Format 'yyyyMMdd').json"

Complete Configuration Script

<#
.SYNOPSIS
    Configures Control 1.11 - Conditional Access and Phishing-Resistant MFA

.DESCRIPTION
    This script configures Conditional Access policies for AI agent creators,
    including phishing-resistant MFA requirements and named locations.

.PARAMETER PolicyName
    The name for the Conditional Access policy

.PARAMETER IncludeGroups
    Security groups to include in the policy

.PARAMETER ExcludeGroups
    Security groups to exclude (e.g., emergency access)

.EXAMPLE
    .\Configure-Control-1.11.ps1 -PolicyName "FSI-Agent-Creators-MFA" -IncludeGroups @("sg-agent-creators")

.NOTES
    Last Updated: January 2026
    Related Control: Control 1.11 - Conditional Access and Phishing-Resistant MFA
#>

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

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

    [string[]]$ExcludeGroups = @("sg-emergency-access")
)

try {
    # Connect to Microsoft Graph
    Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Cyan
    Connect-MgGraph -Scopes "Policy.Read.All","Policy.ReadWrite.ConditionalAccess","Directory.Read.All"

    Write-Host "Configuring Control 1.11: Conditional Access and Phishing-Resistant MFA" -ForegroundColor Cyan

    # Step 1: Get phishing-resistant authentication strength
    Write-Host "`n[Step 1] Discovering phishing-resistant authentication strength..." -ForegroundColor Yellow
    $phishingResistantStrength = Get-MgPolicyAuthenticationStrengthPolicy |
        Where-Object { $_.DisplayName -match "phishing" -and $_.DisplayName -match "resistant" } |
        Select-Object -First 1

    if (-not $phishingResistantStrength) {
        throw "Could not find phishing-resistant Authentication Strength policy."
    }
    Write-Host "  Found: $($phishingResistantStrength.DisplayName)" -ForegroundColor Green

    # Step 2: Create Conditional Access policy
    Write-Host "`n[Step 2] Creating Conditional Access policy..." -ForegroundColor Yellow
    $params = @{
        DisplayName = $PolicyName
        State = "enabledForReportingButNotEnforced"
        Conditions = @{
            Users = @{
                IncludeGroups = $IncludeGroups
                ExcludeGroups = $ExcludeGroups
            }
            Applications = @{
                IncludeApplications = @("All")
            }
            ClientAppTypes = @("all")
        }
        GrantControls = @{
            Operator = "OR"
            BuiltInControls = @()
            AuthenticationStrength = @{
                Id = $phishingResistantStrength.Id
            }
        }
    }

    $policy = New-MgIdentityConditionalAccessPolicy -BodyParameter $params
    Write-Host "  Created policy: $($policy.DisplayName)" -ForegroundColor Green

    # Step 3: Export configuration for evidence
    Write-Host "`n[Step 3] Exporting configuration for compliance evidence..." -ForegroundColor Yellow
    $exportPath = "CA-Policy-Export-$(Get-Date -Format 'yyyyMMdd-HHmmss').json"
    $policy | ConvertTo-Json -Depth 10 | Out-File $exportPath
    Write-Host "  Exported to: $exportPath" -ForegroundColor Green

    Write-Host "`n[PASS] Control 1.11 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 Microsoft Graph" -ForegroundColor Gray
    }
}

Updated: January 2026 | Version: v1.2