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.
-
For best results, use Azure Cloud Shell in PowerShell mode.
To run locally, install
Az.Accounts,Az.Resources, andAz.CognitiveServices, then authenticate withConnect-AzAccount. -
Select the intended subscription with
Set-AzContext -SubscriptionId '<subscription-id>'. You need permission to update account authentication settings and resource tags. -
Copy a script below and run it. Enter
0for all listed accounts, or comma-separated numbers such as1,3for individual accounts. Review the selection and typeAPPLYto 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.
# 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.
# 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.'
}
}