@@ -127,6 +127,42 @@ function Retry([scriptblock] $Action, [int] $Attempts = 5)
127127 }
128128}
129129
130+ # NewServicePrincipalWrapper creates an object from an AAD graph or Microsoft Graph service principal object type.
131+ # This is necessary to work around breaking changes introduced in Az version 7.0.0:
132+ # https://azure.microsoft.com/en-us/updates/update-your-apps-to-use-microsoft-graph-before-30-june-2022/
133+ function NewServicePrincipalWrapper ([string ]$subscription , [string ]$resourceGroup , [string ]$displayName )
134+ {
135+ $servicePrincipal = Retry {
136+ New-AzADServicePrincipal - Role " Owner" - Scope " /subscriptions/$SubscriptionId /resourceGroups/$ResourceGroupName " - DisplayName $displayName
137+ }
138+ $spPassword = " "
139+ $appId = " "
140+ if (Get-Member - Name " Secret" - InputObject $servicePrincipal - MemberType property) {
141+ Write-Verbose " Using legacy PSADServicePrincipal object type from AAD graph API"
142+ # Secret property exists on PSADServicePrincipal type from AAD graph in Az # module versions < 7.0.0
143+ $spPassword = $servicePrincipal.Secret
144+ $appId = $servicePrincipal.ApplicationId
145+ } else {
146+ Write-Verbose " Creating password for service principal via MS Graph API"
147+ # Microsoft graph objects (Az version >= 7.0.0) do not provision a secret # on creation so it must be added separately.
148+ # Submitting a password credential object without specifying a password will result in one being generated on the server side.
149+ $password = New-Object - TypeName " Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential"
150+ $password.DisplayName = " Password for $displayName "
151+ $credential = Retry { New-AzADSpCredential - PasswordCredentials $password - ServicePrincipalObject $servicePrincipal }
152+ $spPassword = ConvertTo-SecureString $credential.SecretText - AsPlainText - Force
153+ $appId = $servicePrincipal.AppId
154+ }
155+
156+ return @ {
157+ AppId = $appId
158+ ApplicationId = $appId
159+ # This is the ObjectId/OID but most return objects use .Id so keep it consistent to prevent confusion
160+ Id = $servicePrincipal.Id
161+ DisplayName = $servicePrincipal.DisplayName
162+ Secret = $spPassword
163+ }
164+ }
165+
130166function LoadCloudConfig ([string ] $env )
131167{
132168 $configPath = " $PSScriptRoot /clouds/$env .json"
@@ -522,8 +558,8 @@ try {
522558 # If no test application ID was specified during an interactive session, create a new service principal.
523559 if (! $CI -and ! $TestApplicationId ) {
524560 # Cache the created service principal in this session for frequent reuse.
525- $servicePrincipal = if ($AzureTestPrincipal -and (Get-AzADServicePrincipal - ApplicationId $AzureTestPrincipal.ApplicationId ) -and $AzureTestSubscription -eq $SubscriptionId ) {
526- Log " TestApplicationId was not specified; loading cached service principal '$ ( $AzureTestPrincipal.ApplicationId ) '"
561+ $servicePrincipal = if ($AzureTestPrincipal -and (Get-AzADServicePrincipal - ApplicationId $AzureTestPrincipal.AppId ) -and $AzureTestSubscription -eq $SubscriptionId ) {
562+ Log " TestApplicationId was not specified; loading cached service principal '$ ( $AzureTestPrincipal.AppId ) '"
527563 $AzureTestPrincipal
528564 } else {
529565 Log " TestApplicationId was not specified; creating a new service principal in subscription '$SubscriptionId '"
@@ -537,19 +573,17 @@ try {
537573 $displayName = " $ ( $baseName ) $suffix .test-resources.azure.sdk"
538574 }
539575
540- $servicePrincipal = Retry {
541- New-AzADServicePrincipal - Role " Owner" - Scope " /subscriptions/$SubscriptionId /resourceGroups/$ResourceGroupName " - DisplayName $displayName
542- }
576+ $servicePrincipalWrapper = NewServicePrincipalWrapper - subscription $SubscriptionId - resourceGroup $ResourceGroupName - displayName $DisplayName
543577
544- $global :AzureTestPrincipal = $servicePrincipal
578+ $global :AzureTestPrincipal = $servicePrincipalWrapper
545579 $global :AzureTestSubscription = $SubscriptionId
546580
547- Log " Created service principal '$ ( $AzureTestPrincipal.ApplicationId ) '"
548- $AzureTestPrincipal
581+ Log " Created service principal. AppId: '$ ( $AzureTestPrincipal.AppId ) ' ObjectId: ' $ ( $AzureTestPrincipal .Id ) '"
582+ $servicePrincipalWrapper
549583 $resourceGroupRoleAssigned = $true
550584 }
551585
552- $TestApplicationId = $servicePrincipal.ApplicationId
586+ $TestApplicationId = $servicePrincipal.AppId
553587 $TestApplicationOid = $servicePrincipal.Id
554588 $TestApplicationSecret = (ConvertFrom-SecureString $servicePrincipal.Secret - AsPlainText)
555589 }
@@ -886,7 +920,7 @@ Bicep templates, test-resources.bicep.env.
886920
887921. PARAMETER SuppressVsoCommands
888922By default, the -CI parameter will print out secrets to logs with Azure Pipelines log
889- commands that cause them to be redacted. For CI environments that don't support this (like
923+ commands that cause them to be redacted. For CI environments that don't support this (like
890924stress test clusters), this flag can be set to $false to avoid printing out these secrets to the logs.
891925
892926. EXAMPLE
0 commit comments