|
3 | 3 | [string]$billingScope, |
4 | 4 | [string]$subscriptionNamePrefix = "accelerator-bootstrap-modules", |
5 | 5 | [string[]]$subscriptionTypes = @("connectivity", "management", "identity", "security", "bootstrap"), |
| 6 | + [string[]]$resourceProviders = @("Microsoft.Security"), |
6 | 7 | [int]$maxRetries = 5, |
7 | 8 | [int]$throttleLimit = 2, |
| 9 | + [int]$resourceProviderThrottleLimit = 10, |
8 | 10 | [switch]$planOnly |
9 | 11 | ) |
10 | 12 |
|
@@ -95,101 +97,149 @@ if ($existingSubscriptions.Count -gt 0) { |
95 | 97 | Write-Host "" |
96 | 98 | if ($subscriptionsToCreate.Count -eq 0) { |
97 | 99 | Write-Host "No new subscriptions to create. All aliases already exist." -ForegroundColor Green |
98 | | - return |
99 | 100 | } |
100 | 101 |
|
101 | | -Write-Host "=== Subscriptions to Create ===" -ForegroundColor Cyan |
102 | | -foreach ($sub in $subscriptionsToCreate) { |
103 | | - Write-Host " - $sub" -ForegroundColor Yellow |
| 102 | +if ($subscriptionsToCreate.Count -gt 0) { |
| 103 | + Write-Host "=== Subscriptions to Create ===" -ForegroundColor Cyan |
| 104 | + foreach ($sub in $subscriptionsToCreate) { |
| 105 | + Write-Host " - $sub" -ForegroundColor Yellow |
| 106 | + } |
| 107 | + Write-Host "" |
| 108 | + Write-Host "Total: $($subscriptionsToCreate.Count) subscription(s) to create" -ForegroundColor Cyan |
| 109 | + Write-Host "" |
104 | 110 | } |
105 | | -Write-Host "" |
106 | | -Write-Host "Total: $($subscriptionsToCreate.Count) subscription(s) to create" -ForegroundColor Cyan |
107 | | -Write-Host "" |
108 | 111 |
|
109 | 112 | if ($planOnly) { |
110 | 113 | Write-Host "Plan only mode - no subscriptions will be created." -ForegroundColor Magenta |
111 | 114 | return |
112 | 115 | } |
113 | 116 |
|
114 | | -# Prompt for confirmation before creating |
115 | | -$createConfirmation = Read-Host "Do you want to create these $($subscriptionsToCreate.Count) subscription(s)? (y/n)" |
116 | | -if ($createConfirmation -ine 'y') { |
117 | | - Write-Host "Operation cancelled by user." -ForegroundColor Red |
118 | | - return |
119 | | -} |
| 117 | +if ($subscriptionsToCreate.Count -gt 0) { |
| 118 | + # Prompt for confirmation before creating |
| 119 | + $createConfirmation = Read-Host "Do you want to create these $($subscriptionsToCreate.Count) subscription(s)? (y/n)" |
| 120 | + if ($createConfirmation -ine 'y') { |
| 121 | + Write-Host "Operation cancelled by user." -ForegroundColor Red |
| 122 | + return |
| 123 | + } |
120 | 124 |
|
121 | | -Write-Host "" |
| 125 | + Write-Host "" |
122 | 126 |
|
123 | | -# Create a thread-safe hashtable to track rate limiting across parallel tasks |
124 | | -$rateLimitState = [hashtable]::Synchronized(@{ |
125 | | - WaitUntil = [DateTime]::MinValue |
126 | | -}) |
127 | | - |
128 | | -# Create the subscriptions in parallel with retry logic |
129 | | -Write-Host "Creating subscriptions (throttle: $throttleLimit)..." -ForegroundColor Cyan |
130 | | - |
131 | | -$results = $subscriptionsToCreate | ForEach-Object -Parallel { |
132 | | - $subscriptionName = $_ |
133 | | - $scope = $using:billingScope |
134 | | - $retries = $using:maxRetries |
135 | | - $state = $using:rateLimitState |
136 | | - $VerbosePreference = $using:VerbosePreference |
137 | | - $retryCount = 0 |
138 | | - $success = $false |
139 | | - |
140 | | - while (-not $success -and $retryCount -lt $retries) { |
141 | | - # Check if we're in a rate limit wait period |
142 | | - $waitUntil = $state.WaitUntil |
143 | | - if ($waitUntil -gt [DateTime]::Now) { |
144 | | - $waitSeconds = [math]::Ceiling(($waitUntil - [DateTime]::Now).TotalSeconds) |
145 | | - Write-Host "Rate limit active. $subscriptionName waiting $waitSeconds seconds..." -ForegroundColor Yellow |
146 | | - Start-Sleep -Seconds $waitSeconds |
147 | | - } |
| 127 | + # Create a thread-safe hashtable to track rate limiting across parallel tasks |
| 128 | + $rateLimitState = [hashtable]::Synchronized(@{ |
| 129 | + WaitUntil = [DateTime]::MinValue |
| 130 | + }) |
| 131 | + |
| 132 | + # Create the subscriptions in parallel with retry logic |
| 133 | + Write-Host "Creating subscriptions (throttle: $throttleLimit)..." -ForegroundColor Cyan |
| 134 | + |
| 135 | + $results = $subscriptionsToCreate | ForEach-Object -Parallel { |
| 136 | + $subscriptionName = $_ |
| 137 | + $scope = $using:billingScope |
| 138 | + $retries = $using:maxRetries |
| 139 | + $state = $using:rateLimitState |
| 140 | + $VerbosePreference = $using:VerbosePreference |
| 141 | + $retryCount = 0 |
| 142 | + $success = $false |
| 143 | + |
| 144 | + while (-not $success -and $retryCount -lt $retries) { |
| 145 | + # Check if we're in a rate limit wait period |
| 146 | + $waitUntil = $state.WaitUntil |
| 147 | + if ($waitUntil -gt [DateTime]::Now) { |
| 148 | + $waitSeconds = [math]::Ceiling(($waitUntil - [DateTime]::Now).TotalSeconds) |
| 149 | + Write-Host "Rate limit active. $subscriptionName waiting $waitSeconds seconds..." -ForegroundColor Yellow |
| 150 | + Start-Sleep -Seconds $waitSeconds |
| 151 | + } |
148 | 152 |
|
149 | | - Write-Host "Creating subscription: $subscriptionName (Attempt $($retryCount + 1) of $retries)" -ForegroundColor Yellow |
150 | | - $result = az account alias create --name "$subscriptionName" --billing-scope "$scope" --display-name "$subscriptionName" --workload "Production" 2>&1 |
| 153 | + Write-Host "Creating subscription: $subscriptionName (Attempt $($retryCount + 1) of $retries)" -ForegroundColor Yellow |
| 154 | + $result = az account alias create --name "$subscriptionName" --billing-scope "$scope" --display-name "$subscriptionName" --workload "Production" 2>&1 |
151 | 155 |
|
152 | | - if ($LASTEXITCODE -eq 0) { |
153 | | - $success = $true |
154 | | - Write-Host "Successfully created: $subscriptionName" -ForegroundColor Green |
155 | | - } else { |
156 | | - $errorMessage = $result | Out-String |
157 | | - if ($errorMessage -match "TooManyRequests.*Retry in (\d{2}):(\d{2}):(\d{2})") { |
158 | | - $hours = [int]$Matches[1] |
159 | | - $minutes = [int]$Matches[2] |
160 | | - $seconds = [int]$Matches[3] |
161 | | - $waitSeconds = ($hours * 3600) + ($minutes * 60) + $seconds + (1 * 60) # Add 60 second buffer |
162 | | - Write-Verbose $errorMessage |
163 | | - |
164 | | - # Set the shared rate limit wait time |
165 | | - $newWaitUntil = [DateTime]::Now.AddSeconds($waitSeconds) |
166 | | - if ($newWaitUntil -gt $state.WaitUntil) { |
167 | | - $state.WaitUntil = $newWaitUntil |
168 | | - Write-Host "Rate limit hit! All tasks will wait until $($newWaitUntil.ToString('HH:mm:ss'))" -ForegroundColor Red |
169 | | - } |
170 | | - |
171 | | - Write-Host "Rate limited for $subscriptionName. Waiting $waitSeconds seconds before retry..." -ForegroundColor Yellow |
172 | | - Start-Sleep -Seconds $waitSeconds |
173 | | - $retryCount++ |
| 156 | + if ($LASTEXITCODE -eq 0) { |
| 157 | + $success = $true |
| 158 | + Write-Host "Successfully created: $subscriptionName" -ForegroundColor Green |
174 | 159 | } else { |
175 | | - Write-Host "Failed to create $subscriptionName : $errorMessage" -ForegroundColor Red |
176 | | - break |
| 160 | + $errorMessage = $result | Out-String |
| 161 | + if ($errorMessage -match "TooManyRequests.*Retry in (\d{2}):(\d{2}):(\d{2})") { |
| 162 | + $hours = [int]$Matches[1] |
| 163 | + $minutes = [int]$Matches[2] |
| 164 | + $seconds = [int]$Matches[3] |
| 165 | + $waitSeconds = ($hours * 3600) + ($minutes * 60) + $seconds + (1 * 60) # Add 60 second buffer |
| 166 | + Write-Verbose $errorMessage |
| 167 | + |
| 168 | + # Set the shared rate limit wait time |
| 169 | + $newWaitUntil = [DateTime]::Now.AddSeconds($waitSeconds) |
| 170 | + if ($newWaitUntil -gt $state.WaitUntil) { |
| 171 | + $state.WaitUntil = $newWaitUntil |
| 172 | + Write-Host "Rate limit hit! All tasks will wait until $($newWaitUntil.ToString('HH:mm:ss'))" -ForegroundColor Red |
| 173 | + } |
| 174 | + |
| 175 | + Write-Host "Rate limited for $subscriptionName. Waiting $waitSeconds seconds before retry..." -ForegroundColor Yellow |
| 176 | + Start-Sleep -Seconds $waitSeconds |
| 177 | + $retryCount++ |
| 178 | + } else { |
| 179 | + Write-Host "Failed to create $subscriptionName : $errorMessage" -ForegroundColor Red |
| 180 | + break |
| 181 | + } |
177 | 182 | } |
178 | 183 | } |
179 | | - } |
180 | 184 |
|
181 | | - [PSCustomObject]@{ |
182 | | - Name = $subscriptionName |
183 | | - Success = $success |
| 185 | + [PSCustomObject]@{ |
| 186 | + Name = $subscriptionName |
| 187 | + Success = $success |
| 188 | + } |
| 189 | + } -ThrottleLimit $throttleLimit |
| 190 | + |
| 191 | + $successCount = ($results | Where-Object { $_.Success }).Count |
| 192 | + $failCount = ($results | Where-Object { -not $_.Success }).Count |
| 193 | + |
| 194 | + Write-Host "" |
| 195 | + Write-Host "Subscription creation complete." -ForegroundColor Green |
| 196 | + Write-Host " Successful: $successCount" -ForegroundColor Green |
| 197 | + if ($failCount -gt 0) { |
| 198 | + Write-Host " Failed: $failCount" -ForegroundColor Red |
184 | 199 | } |
185 | | -} -ThrottleLimit $throttleLimit |
| 200 | +} |
186 | 201 |
|
187 | | -$successCount = ($results | Where-Object { $_.Success }).Count |
188 | | -$failCount = ($results | Where-Object { -not $_.Success }).Count |
| 202 | +# Register resource providers for all subscriptions |
| 203 | +if ($resourceProviders.Count -gt 0 -and -not $planOnly) { |
| 204 | + Write-Host "" |
| 205 | + Write-Host "=== Registering Resource Providers ===" -ForegroundColor Cyan |
| 206 | + Write-Host "Providers: $($resourceProviders -join ', ')" -ForegroundColor Yellow |
| 207 | + |
| 208 | + $allSubscriptionNames = $subscriptionsToCreate + $existingSubscriptions |
| 209 | + |
| 210 | + # Get subscription IDs for all aliases and register providers |
| 211 | + $allSubscriptionNames | ForEach-Object -Parallel { |
| 212 | + $subscriptionName = $_ |
| 213 | + $providers = $using:resourceProviders |
| 214 | + $VerbosePreference = $using:VerbosePreference |
| 215 | + |
| 216 | + # Get the subscription ID from the alias |
| 217 | + $aliasInfo = az account alias show --name "$subscriptionName" --output json 2>$null | ConvertFrom-Json |
| 218 | + |
| 219 | + if ($aliasInfo -and $aliasInfo.properties.subscriptionId) { |
| 220 | + $subscriptionId = $aliasInfo.properties.subscriptionId |
| 221 | + |
| 222 | + foreach ($provider in $providers) { |
| 223 | + # Check if provider is already registered |
| 224 | + $providerState = az provider show --namespace $provider --subscription $subscriptionId --query "registrationState" --output tsv 2>$null |
| 225 | + |
| 226 | + if ($providerState -ine "Registered") { |
| 227 | + Write-Host "Registering $provider for $subscriptionName ($subscriptionId)..." -ForegroundColor Yellow |
| 228 | + az provider register --namespace $provider --subscription $subscriptionId --output none --wait |
| 229 | + if ($LASTEXITCODE -eq 0) { |
| 230 | + Write-Host " Registration initiated: $provider for $subscriptionName" -ForegroundColor Green |
| 231 | + } else { |
| 232 | + Write-Host " Failed to register: $provider for $subscriptionName" -ForegroundColor Red |
| 233 | + } |
| 234 | + } else { |
| 235 | + Write-Host " Already registered: $provider for $subscriptionName" -ForegroundColor Gray |
| 236 | + } |
| 237 | + } |
| 238 | + } else { |
| 239 | + Write-Host " Could not get subscription ID for alias: $subscriptionName" -ForegroundColor Red |
| 240 | + } |
| 241 | + } -ThrottleLimit $resourceProviderThrottleLimit |
189 | 242 |
|
190 | | -Write-Host "" |
191 | | -Write-Host "Subscription creation complete." -ForegroundColor Green |
192 | | -Write-Host " Successful: $successCount" -ForegroundColor Green |
193 | | -if ($failCount -gt 0) { |
194 | | - Write-Host " Failed: $failCount" -ForegroundColor Red |
| 243 | + Write-Host "" |
| 244 | + Write-Host "Resource provider registration complete." -ForegroundColor Green |
195 | 245 | } |
0 commit comments