#azure-ad-b2c
Hi All,
I have created a powershell script that I'm using in the release pipeline to do the custom policies deployment. The script is as below -
param (
[string]$b2cTenant,
[string]$clientId,
[string]$clientSecret,
[string]$repoPath
)
# Function to deploy policy using Microsoft Graph API
function Deploy-Policy {
param (
[string]$PolicyPath,
[string]$AccessToken
)
$policyName = [System.IO.Path]::GetFileNameWithoutExtension($PolicyPath)
Write-Host "Uploading policy: $policyName"
# Microsoft Graph API URL for custom policy upload
$url = "https://graph.microsoft.com/beta/trustFramework/policies/$policyName/`$value"
# Read XML file content
try {
$xmlContent = Get-Content -Path $PolicyPath -Raw
} catch {
Write-Host "Failed to read policy file: $PolicyPath"
Write-Host "Error: $_"
return
}
# Set HTTP headers
$headers = @{
Authorization = "Bearer $AccessToken"
"Content-Type" = "application/xml"
}
# Upload policy using PUT request
try {
Invoke-RestMethod -Uri $url -Headers $headers -Method PUT -Body $xmlContent
Write-Host "Successfully deployed policy: $policyName"
} catch {
Write-Host "Failed to deploy policy: $policyName"
Write-Host "Error: $_"
}
}
# Debug: Output the received variables for validation
Write-Host "B2C_TENANT_NAME: $b2cTenant"
Write-Host "CLIENT_ID: $clientId"
Write-Host "CLIENT_SECRET: $clientSecret"
Write-Host "Repository Path: $repoPath"
# Ensure B2C_TENANT_NAME is correct (adding .onmicrosoft.com suffix)
$tenantDomain = "$b2cTenant"
Write-Host "Tenant Domain: $tenantDomain"
# Ensure Az Module is available
Write-Host "Checking Az PowerShell Module..."
$AzModule = Get-Module -ListAvailable Az
if (-not $AzModule) {
Write-Host "Az module not found. Installing Az module..."
Install-Module -Name Az -Scope CurrentUser -Force -AllowClobber
if ($?) {
Write-Host "Az module installed successfully."
} else {
Write-Host "Failed to install Az module."
exit 1
}
}
# Import Az module to the session
Import-Module Az -Global
# Authentication to Azure using Service Principal (Ensure this is correct)
Write-Host "Authenticating to Azure AD..."
# Login to Azure using Service Principal and Secret
$securePassword = ConvertTo-SecureString $clientSecret -AsPlainText -Force
$psCredential = New-Object System.Management.Automation.PSCredential($clientId, $securePassword)
try {
Connect-AzAccount -ServicePrincipal -Credential $psCredential -TenantId $tenantDomain
Write-Host "Service Principal Login is successful"
} catch {
Write-Host "❌ Service Principal Login failed."
Write-Host "Error: $_"
exit 1
}
##Connect-AzAccount -ServicePrincipal -Tenant $tenantDomain -ApplicationId $clientId -Credential $clientSecret
# Define the path to your custom policies
$basePoliciesPath = "$repoPath\Base"
$customPoliciesPath = "$repoPath\Custom"
# Check if base and custom policy directories exist
if (!(Test-Path $basePoliciesPath)) {
Write-Host "Error: Base policies folder does not exist at: $basePoliciesPath"
exit 1
}
if (!(Test-Path $customPoliciesPath)) {
Write-Host "Error: Custom policies folder does not exist at: $customPoliciesPath"
exit 1
}
# Authenticate to Azure AD & Fetch Access Token
Write-Host "Fetching Access Token..."
try {
$tokenResponse = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$b2cTenant/oauth2/v2.0/token" -ContentType "application/x-www-form-urlencoded" -Body @{
client_id = $clientId
client_secret = $clientSecret
scope = "https://graph.microsoft.com/.default"
grant_type = "client_credentials"
}
$accessToken = $tokenResponse.access_token
if (-not $accessToken) {
Write-Host "Error: Failed to obtain access token."
exit 1
}
Write-Host "Access Token Retrieved Successfully."
} catch {
Write-Host "❌ Error while fetching access token."
Write-Host "Error: $_"
exit 1
}
# Define base policy files in required order
$basePolicies = @(
"TrustFrameworkBase.xml",
"TrustFrameworkLocalization.xml",
"TrustFrameworkExtensions.xml"
)
# Deploy Base Policies in sequence
Write-Host "Deploying Base Policies..."
foreach ($policy in $basePolicies) {
$policyPath = "$basePoliciesPath\$policy"
if (Test-Path $policyPath) {
Write-Host "Deploying Base Policy: $policy"
Deploy-Policy -PolicyPath $policyPath -AccessToken $accessToken
} else {
Write-Host "Warning: Base policy '$policy' not found, skipping."
}
}
# Track changes for custom policies
$trackingFile = "$customPoliciesPath\deployedPolicies.json"
$previouslyDeployed = @{}
if (Test-Path $trackingFile) {
$previouslyDeployed = Get-Content -Raw -Path $trackingFile | ConvertFrom-Json
}
Write-Host "Deploying Custom Policies..."
$customPolicies = Get-ChildItem -Path $customPoliciesPath -Filter "*.xml"
$deployedPolicies = @{}
foreach ($policy in $customPolicies) {
$policyName = $policy.Name
$policyPath = "$customPoliciesPath\$policyName"
# Compute file hash to detect changes
try {
$hash = Get-FileHash -Path $policyPath -Algorithm SHA256 | Select-Object -ExpandProperty Hash
} catch {
Write-Host "Error: Failed to calculate hash for policy: $policyName"
Write-Host "Error: $_"
continue
}
# Deploy only if new or modified
if (-not $previouslyDeployed.ContainsKey($policyName) -or $previouslyDeployed[$policyName] -ne $hash) {
Write-Host "Deploying Custom Policy: $policyName (New/Updated)"
Deploy-Policy -PolicyPath $policyPath -AccessToken $accessToken
$deployedPolicies[$policyName] = $hash
} else {
Write-Host "Skipping: $policyName (No changes detected)"
}
}
# Save deployed policies state
$deployedPolicies | ConvertTo-Json | Set-Content -Path $trackingFile
Write-Host "Azure B2C policy deployment completed successfully."
However, when I am executing the pipeline I'm getting below error message -
2025-04-01T00:08:58.4338769Z Checking Az PowerShell Module...
2025-04-01T00:08:58.4695442Z Az module not found. Installing Az module...
2025-04-01T00:11:51.0404314Z Az module installed successfully.
2025-04-01T00:12:24.7101821Z WARNING: The names of some imported commands from the module 'Az.DevCenterdata.custom' include unapproved verbs that
2025-04-01T00:12:24.7102756Z might make them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with
2025-04-01T00:12:24.7103555Z the Verbose parameter. For a list of approved verbs, type Get-Verb.
2025-04-01T00:12:25.0317150Z WARNING: The names of some imported commands from the module 'Az.DevCenter' include unapproved verbs that might make
2025-04-01T00:12:25.0317920Z them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the
2025-04-01T00:12:25.0318644Z Verbose parameter. For a list of approved verbs, type Get-Verb.
2025-04-01T00:13:32.5256509Z WARNING: The names of some imported commands from the module 'Microsoft.Azure.PowerShell.Cmdlets.Network' include
2025-04-01T00:13:32.5260642Z unapproved verbs that might make them less discoverable. To find the commands with unapproved verbs, run the
2025-04-01T00:13:32.5261556Z Import-Module command again with the Verbose parameter. For a list of approved verbs, type Get-Verb.
2025-04-01T00:13:33.1477638Z WARNING: The names of some imported commands from the module 'Az.Network' include unapproved verbs that might make them
2025-04-01T00:13:33.1478573Z less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the Verbose
2025-04-01T00:13:33.1478834Z parameter. For a list of approved verbs, type Get-Verb.
2025-04-01T00:13:34.5479832Z WARNING: The names of some imported commands from the module 'Az.NetworkCloud.private' include unapproved verbs that
2025-04-01T00:13:34.5500617Z might make them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with
2025-04-01T00:13:34.5525199Z the Verbose parameter. For a list of approved verbs, type Get-Verb.
2025-04-01T00:13:34.5868581Z WARNING: The names of some imported commands from the module 'Az.NetworkCloud.private' include unapproved verbs that
2025-04-01T00:13:34.5869175Z might make them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with
2025-04-01T00:13:34.5906439Z the Verbose parameter. For a list of approved verbs, type Get-Verb.
2025-04-01T00:13:34.6062144Z WARNING: The names of some imported commands from the module 'Az.NetworkCloud.private' include unapproved verbs that
2025-04-01T00:13:34.6063251Z might make them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with
2025-04-01T00:13:34.6107418Z the Verbose parameter. For a list of approved verbs, type Get-Verb.
2025-04-01T00:13:37.3030557Z WARNING: The names of some imported commands from the module 'Az.NetworkCloud' include unapproved verbs that might make
2025-04-01T00:13:37.3031024Z them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the
2025-04-01T00:13:37.3076581Z Verbose parameter. For a list of approved verbs, type Get-Verb.
2025-04-01T00:15:51.9247607Z Authenticating to Azure AD...
2025-04-01T00:15:53.8892439Z
2025-04-01T00:15:54.0597949Z Service Principal Login is successful
2025-04-01T00:15:54.0613405Z Fetching Access Token...
2025-04-01T00:15:54.2606203Z Access Token Retrieved Successfully.
2025-04-01T00:15:54.2627127Z Deploying Base Policies...
2025-04-01T00:15:54.2670202Z Deploying Base Policy: TrustFrameworkBase.xml
2025-04-01T00:15:54.2815028Z Uploading policy: TrustFrameworkBase
2025-04-01T00:15:54.6743958Z Failed to deploy policy: TrustFrameworkBase
2025-04-01T00:15:54.6769211Z Error: The remote server returned an error: (400) Bad Request.
2025-04-01T00:15:54.6844004Z Deploying Base Policy: TrustFrameworkLocalization.xml
2025-04-01T00:15:54.6878298Z Uploading policy: TrustFrameworkLocalization
2025-04-01T00:15:54.7732254Z Failed to deploy policy: TrustFrameworkLocalization
2025-04-01T00:15:54.7769176Z Error: The remote server returned an error: (400) Bad Request.
2025-04-01T00:15:54.7793920Z Deploying Base Policy: TrustFrameworkExtensions.xml
2025-04-01T00:15:54.7886487Z Uploading policy: TrustFrameworkExtensions
2025-04-01T00:15:54.8916777Z Failed to deploy policy: TrustFrameworkExtensions
2025-04-01T00:15:54.8942658Z Error: The remote server returned an error: (400) Bad Request.
2025-04-01T00:15:54.9641256Z Deploying Custom Policies...
2025-04-01T00:15:54.9913974Z Deploying Custom Policy: PasswordReset.xml (New/Updated)
2025-04-01T00:15:54.9985185Z Uploading policy: PasswordReset
2025-04-01T00:15:55.0902182Z Failed to deploy policy: PasswordReset
2025-04-01T00:15:55.1012247Z Error: The remote server returned an error: (400) Bad Request.
2025-04-01T00:15:55.1034452Z Deploying Custom Policy: SignUpOrSignin.xml (New/Updated)
2025-04-01T00:15:55.1170474Z Uploading policy: SignUpOrSignin
2025-04-01T00:15:55.1711556Z Failed to deploy policy: SignUpOrSignin
2025-04-01T00:15:55.1822532Z Error: The remote server returned an error: (400) Bad Request.
2025-04-01T00:15:55.2597288Z Azure B2C policy deployment completed successfully.
2025-04-01T00:15:55.2757613Z Subscription name Tenant
2025-04-01T00:15:55.2758408Z ----------------- ------
2025-04-01T00:15:55.2759048Z xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
2025-04-01T00:15:55.2759306Z
2025-04-01T00:15:55.2759565Z
Note: I have created the Service Principal in Azure B2C and have given all the required permissions as -
offline_accessDelegatedMaintain access to data you have given it access toNoGranted for modioffline_accessDelegatedMaintain access to data you have given it access toNoGranted for modiopenidDelegatedSign users inNoGranted for modiPolicy.ReadWrite.IdentityProtectionApplicationRead and write your organization’s identity protection policyYesGranted for modiPolicy.ReadWrite.TrustFrameworkDelegatedRead and write your organization's trust framework policiesYesGranted for modiPolicy.ReadWrite.TrustFrameworkApplicationRead and write your organization's trust framework policiesYesGranted for modiUser.ReadWrite.AllApplicationRead and write all users' full profilesYesGranted for modiKindly suggest what should I do to fix this error message?
Any help is much appreciated,
Thank you,
Regards,