@@ -127,6 +127,42 @@ function Retry([scriptblock] $Action, [int] $Attempts = 5)
127
127
}
128
128
}
129
129
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
+
130
166
function LoadCloudConfig ([string ] $env )
131
167
{
132
168
$configPath = " $PSScriptRoot /clouds/$env .json"
@@ -522,8 +558,8 @@ try {
522
558
# If no test application ID was specified during an interactive session, create a new service principal.
523
559
if (! $CI -and ! $TestApplicationId ) {
524
560
# 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 ) '"
527
563
$AzureTestPrincipal
528
564
} else {
529
565
Log " TestApplicationId was not specified; creating a new service principal in subscription '$SubscriptionId '"
@@ -537,19 +573,17 @@ try {
537
573
$displayName = " $ ( $baseName ) $suffix .test-resources.azure.sdk"
538
574
}
539
575
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
543
577
544
- $global :AzureTestPrincipal = $servicePrincipal
578
+ $global :AzureTestPrincipal = $servicePrincipalWrapper
545
579
$global :AzureTestSubscription = $SubscriptionId
546
580
547
- Log " Created service principal '$ ( $AzureTestPrincipal.ApplicationId ) '"
548
- $AzureTestPrincipal
581
+ Log " Created service principal. AppId: '$ ( $AzureTestPrincipal.AppId ) ' ObjectId: ' $ ( $AzureTestPrincipal .Id ) '"
582
+ $servicePrincipalWrapper
549
583
$resourceGroupRoleAssigned = $true
550
584
}
551
585
552
- $TestApplicationId = $servicePrincipal.ApplicationId
586
+ $TestApplicationId = $servicePrincipal.AppId
553
587
$TestApplicationOid = $servicePrincipal.Id
554
588
$TestApplicationSecret = (ConvertFrom-SecureString $servicePrincipal.Secret - AsPlainText)
555
589
}
@@ -886,7 +920,7 @@ Bicep templates, test-resources.bicep.env.
886
920
887
921
. PARAMETER SuppressVsoCommands
888
922
By 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
890
924
stress test clusters), this flag can be set to $false to avoid printing out these secrets to the logs.
891
925
892
926
. EXAMPLE
0 commit comments