Foundry Auth Policy

Manage Microsoft Entra ID-only authentication for Foundry (AIServices) and Azure OpenAI (OpenAI) accounts in the selected subscription. These scripts run in your Azure PowerShell session, not in this application.

  1. For best results, use Azure Cloud Shell in PowerShell mode. To run locally, install Az.Accounts, Az.Resources, and Az.CognitiveServices, then authenticate with Connect-AzAccount.
  2. Select the intended subscription with Set-AzContext -SubscriptionId '<subscription-id>'. You need permission to update account authentication settings and resource tags.
  3. Copy a script below and run it. Enter 0 for all listed accounts, or comma-separated numbers such as 1,3 for individual accounts. Review the selection and type APPLY to confirm.

These scripts update existing account settings; they do not create or remove Azure Policy assignments. SecurityControl=Ignore is an organization-specific tag convention, not a universal policy exemption. Your organization's policies may still block changes.

Enable Foundry Authentication Policy

Azure Shell

Sets DisableLocalAuth to $true, then removes the SecurityControl=Ignore tag if present, preserving other tags. API-key clients will stop working. Configure Microsoft Entra ID access first.

PowerShell
# Enable Foundry Authentication Policy.
# For best results, run in Azure Cloud Shell (PowerShell).
# Local setup (run before this script):
# Install-Module Az.Accounts, Az.Resources, Az.CognitiveServices -Scope CurrentUser
# Connect-AzAccount
# Select the intended subscription before running:
# Set-AzContext -SubscriptionId '<subscription-id>'

& {
    $ErrorActionPreference = 'Stop'
    $enablePolicy = $true
    $action = 'Enable'

    Import-Module Az.Accounts, Az.Resources, Az.CognitiveServices -ErrorAction Stop | Out-Null
    Disable-AzContextAutosave -Scope Process -ErrorAction Stop | Out-Null
    $context = Get-AzContext -ErrorAction Stop
    if (-not $context -or -not $context.Subscription.Id) {
        throw 'No subscription is selected. Run Connect-AzAccount and Set-AzContext, then rerun this script.'
    }

    Write-Host ("Subscription: {0} ({1})" -f $context.Subscription.Name, $context.Subscription.Id)
    $accounts = @(
        Get-AzCognitiveServicesAccount -DefaultProfile $context -ErrorAction Stop |
            Where-Object { $_.AccountType -in @('AIServices', 'OpenAI') } |
            Sort-Object ResourceGroupName, AccountName
    )

    if ($accounts.Count -eq 0) {
        Write-Warning 'No Foundry or Azure OpenAI accounts were found in this subscription. Nothing changed.'
        return
    }
    if (@($accounts | Where-Object { -not $_.AccountName -or -not $_.ResourceGroupName -or -not $_.Id }).Count -gt 0) {
        throw 'An account has incomplete resource details. No changes were made. Refresh the account list and retry.'
    }

    for ($i = 0; $i -lt $accounts.Count; $i++) {
        $account = $accounts[$i]
        Write-Host ("{0}. {1} (resource group: {2}; kind: {3}; DisableLocalAuth: {4})" -f
            ($i + 1), $account.AccountName, $account.ResourceGroupName, $account.AccountType, $account.DisableLocalAuth)
    }

    Write-Host ''
    Write-Host "Enter 0 to $($action.ToLowerInvariant()) the policy for all listed accounts."
    Write-Host 'Or enter account numbers separated by commas (for example: 1,3).'
    while ($true) {
        $selection = ([string](Read-Host 'Selection')).Trim()
        if ($selection -eq '0') {
            $selectedAccounts = $accounts
            break
        }

        $numbers = @()
        $valid = $true
        foreach ($token in ($selection -split ',')) {
            $number = 0
            if ($token.Trim() -notmatch '^[0-9]+$' -or
                -not [int]::TryParse($token.Trim(), [ref]$number) -or
                $number -lt 1 -or $number -gt $accounts.Count) {
                $valid = $false
                break
            }
            $numbers += $number
        }

        if (-not $valid) {
            Write-Warning "Invalid selection. Enter 0 alone, or comma-separated numbers from 1 to $($accounts.Count)."
            continue
        }

        $selectedAccounts = @($numbers | Sort-Object -Unique | ForEach-Object { $accounts[$_ - 1] })
        break
    }

    Write-Host ("Selected accounts: {0}" -f (($selectedAccounts | ForEach-Object {
        "$($_.ResourceGroupName)/$($_.AccountName)"
    }) -join ', '))
    if ($enablePolicy) {
        Write-Warning 'API-key clients will stop working. Ensure Microsoft Entra ID access is configured first.'
    } else {
        Write-Warning 'This permits API-key authentication and adds SecurityControl=Ignore. Follow your organization policy.'
    }
    $confirmation = Read-Host "Type APPLY to $($action.ToLowerInvariant()) the policy on $($selectedAccounts.Count) account(s)"
    if ($confirmation -cne 'APPLY') {
        Write-Host 'Cancelled. No accounts changed.'
        return
    }

    $succeeded = 0
    $failed = 0
    foreach ($account in $selectedAccounts) {
        $label = "$($account.ResourceGroupName)/$($account.AccountName)"
        $step = 'updating authentication'
        try {
            if (-not $enablePolicy) {
                $step = 'merging SecurityControl=Ignore'
                Write-Host "[$label] $step..."
                Update-AzTag -ResourceId $account.Id -Tag @{ SecurityControl = 'Ignore' } -Operation Merge `
                    -DefaultProfile $context -ErrorAction Stop | Out-Null
            }

            $step = "setting DisableLocalAuth=$enablePolicy"
            Write-Host "[$label] $step..."
            Set-AzCognitiveServicesAccount -ResourceGroupName $account.ResourceGroupName -Name $account.AccountName `
                -DisableLocalAuth $enablePolicy -DefaultProfile $context -ErrorAction Stop | Out-Null

            if ($enablePolicy -and $account.Tags -and $account.Tags['SecurityControl'] -ceq 'Ignore') {
                $step = 'removing SecurityControl=Ignore'
                Write-Host "[$label] $step..."
                # Delete only this name/value pair; preserve all other tags.
                Update-AzTag -ResourceId $account.Id -Tag @{ SecurityControl = 'Ignore' } -Operation Delete `
                    -DefaultProfile $context -ErrorAction Stop | Out-Null
            }

            $succeeded++
            Write-Host "[$label] Done."
        } catch {
            $failed++
            Write-Warning "[$label] FAILED while ${step}: $($_.Exception.Message)"
        }
    }

    Write-Host ("Succeeded: {0}; failed: {1}." -f $succeeded, $failed)
    if ($failed -gt 0) {
        throw 'Some accounts failed. Earlier changes are not rolled back. Review the messages before retrying.'
    }
}

Disable Foundry Authentication Policy

Azure Shell

Merges the SecurityControl=Ignore tag before setting DisableLocalAuth to $false, following the reference script. API-key authentication becomes available again; Microsoft Entra ID remains available. Use only where your organization permits local authentication.

PowerShell
# Disable Foundry Authentication Policy.
# For best results, run in Azure Cloud Shell (PowerShell).
# Local setup (run before this script):
# Install-Module Az.Accounts, Az.Resources, Az.CognitiveServices -Scope CurrentUser
# Connect-AzAccount
# Select the intended subscription before running:
# Set-AzContext -SubscriptionId '<subscription-id>'

& {
    $ErrorActionPreference = 'Stop'
    $enablePolicy = $false
    $action = 'Disable'

    Import-Module Az.Accounts, Az.Resources, Az.CognitiveServices -ErrorAction Stop | Out-Null
    Disable-AzContextAutosave -Scope Process -ErrorAction Stop | Out-Null
    $context = Get-AzContext -ErrorAction Stop
    if (-not $context -or -not $context.Subscription.Id) {
        throw 'No subscription is selected. Run Connect-AzAccount and Set-AzContext, then rerun this script.'
    }

    Write-Host ("Subscription: {0} ({1})" -f $context.Subscription.Name, $context.Subscription.Id)
    $accounts = @(
        Get-AzCognitiveServicesAccount -DefaultProfile $context -ErrorAction Stop |
            Where-Object { $_.AccountType -in @('AIServices', 'OpenAI') } |
            Sort-Object ResourceGroupName, AccountName
    )

    if ($accounts.Count -eq 0) {
        Write-Warning 'No Foundry or Azure OpenAI accounts were found in this subscription. Nothing changed.'
        return
    }
    if (@($accounts | Where-Object { -not $_.AccountName -or -not $_.ResourceGroupName -or -not $_.Id }).Count -gt 0) {
        throw 'An account has incomplete resource details. No changes were made. Refresh the account list and retry.'
    }

    for ($i = 0; $i -lt $accounts.Count; $i++) {
        $account = $accounts[$i]
        Write-Host ("{0}. {1} (resource group: {2}; kind: {3}; DisableLocalAuth: {4})" -f
            ($i + 1), $account.AccountName, $account.ResourceGroupName, $account.AccountType, $account.DisableLocalAuth)
    }

    Write-Host ''
    Write-Host "Enter 0 to $($action.ToLowerInvariant()) the policy for all listed accounts."
    Write-Host 'Or enter account numbers separated by commas (for example: 1,3).'
    while ($true) {
        $selection = ([string](Read-Host 'Selection')).Trim()
        if ($selection -eq '0') {
            $selectedAccounts = $accounts
            break
        }

        $numbers = @()
        $valid = $true
        foreach ($token in ($selection -split ',')) {
            $number = 0
            if ($token.Trim() -notmatch '^[0-9]+$' -or
                -not [int]::TryParse($token.Trim(), [ref]$number) -or
                $number -lt 1 -or $number -gt $accounts.Count) {
                $valid = $false
                break
            }
            $numbers += $number
        }

        if (-not $valid) {
            Write-Warning "Invalid selection. Enter 0 alone, or comma-separated numbers from 1 to $($accounts.Count)."
            continue
        }

        $selectedAccounts = @($numbers | Sort-Object -Unique | ForEach-Object { $accounts[$_ - 1] })
        break
    }

    Write-Host ("Selected accounts: {0}" -f (($selectedAccounts | ForEach-Object {
        "$($_.ResourceGroupName)/$($_.AccountName)"
    }) -join ', '))
    if ($enablePolicy) {
        Write-Warning 'API-key clients will stop working. Ensure Microsoft Entra ID access is configured first.'
    } else {
        Write-Warning 'This permits API-key authentication and adds SecurityControl=Ignore. Follow your organization policy.'
    }
    $confirmation = Read-Host "Type APPLY to $($action.ToLowerInvariant()) the policy on $($selectedAccounts.Count) account(s)"
    if ($confirmation -cne 'APPLY') {
        Write-Host 'Cancelled. No accounts changed.'
        return
    }

    $succeeded = 0
    $failed = 0
    foreach ($account in $selectedAccounts) {
        $label = "$($account.ResourceGroupName)/$($account.AccountName)"
        $step = 'updating authentication'
        try {
            if (-not $enablePolicy) {
                $step = 'merging SecurityControl=Ignore'
                Write-Host "[$label] $step..."
                Update-AzTag -ResourceId $account.Id -Tag @{ SecurityControl = 'Ignore' } -Operation Merge `
                    -DefaultProfile $context -ErrorAction Stop | Out-Null
            }

            $step = "setting DisableLocalAuth=$enablePolicy"
            Write-Host "[$label] $step..."
            Set-AzCognitiveServicesAccount -ResourceGroupName $account.ResourceGroupName -Name $account.AccountName `
                -DisableLocalAuth $enablePolicy -DefaultProfile $context -ErrorAction Stop | Out-Null

            if ($enablePolicy -and $account.Tags -and $account.Tags['SecurityControl'] -ceq 'Ignore') {
                $step = 'removing SecurityControl=Ignore'
                Write-Host "[$label] $step..."
                # Delete only this name/value pair; preserve all other tags.
                Update-AzTag -ResourceId $account.Id -Tag @{ SecurityControl = 'Ignore' } -Operation Delete `
                    -DefaultProfile $context -ErrorAction Stop | Out-Null
            }

            $succeeded++
            Write-Host "[$label] Done."
        } catch {
            $failed++
            Write-Warning "[$label] FAILED while ${step}: $($_.Exception.Message)"
        }
    }

    Write-Host ("Succeeded: {0}; failed: {1}." -f $succeeded, $failed)
    if ($failed -gt 0) {
        throw 'Some accounts failed. Earlier changes are not rolled back. Review the messages before retrying.'
    }
}
An unhandled error has occurred. Reload 🗙