diff --git a/src/ALZ/ALZ.psm1 b/src/ALZ/ALZ.psm1 index f676807..698265b 100644 --- a/src/ALZ/ALZ.psm1 +++ b/src/ALZ/ALZ.psm1 @@ -4,6 +4,7 @@ Write-Verbose "Discovering Public & Private src." $itemSplat = @{ Filter = '*.ps1' Recurse = $true + Force = $true ErrorAction = 'Stop' } try { diff --git a/src/ALZ/Private/Config-Helpers/Edit-ALZConfigurationFilesInPlace.ps1 b/src/ALZ/Private/Config-Helpers/Edit-ALZConfigurationFilesInPlace.ps1 index 3111bcb..7de05d5 100644 --- a/src/ALZ/Private/Config-Helpers/Edit-ALZConfigurationFilesInPlace.ps1 +++ b/src/ALZ/Private/Config-Helpers/Edit-ALZConfigurationFilesInPlace.ps1 @@ -15,12 +15,12 @@ function Edit-ALZConfigurationFilesInPlace { foreach ($location in $locations) { $bicepModules = Join-Path $alzEnvironmentDestination $location - $files += @(Get-ChildItem -Path $bicepModules -Recurse -Filter *.parameters.*.json) + $files += @(Get-ChildItem -Path $bicepModules -Recurse -Filter *.parameters.*.json -Force) } foreach ($file in $files) { Write-Verbose "Checking Bicep parameter file: $($file.Name)" - $bicepConfiguration = Get-Content $file.FullName | ConvertFrom-Json -AsHashtable + $bicepConfiguration = Get-Content $file.FullName -Force | ConvertFrom-Json -AsHashtable $modified = $false foreach ($configKey in $configuration.PsObject.Properties) { diff --git a/src/ALZ/Private/Config-Helpers/Get-ALZConfig.ps1 b/src/ALZ/Private/Config-Helpers/Get-ALZConfig.ps1 index 4e23bc8..76bd022 100644 --- a/src/ALZ/Private/Config-Helpers/Get-ALZConfig.ps1 +++ b/src/ALZ/Private/Config-Helpers/Get-ALZConfig.ps1 @@ -18,11 +18,11 @@ function Get-ALZConfig { } # Import the config and transform it to a PowerShell object - $extension = (Get-Item -Path $configFilePath).Extension.ToLower() + $extension = (Get-Item -Path $configFilePath -Force).Extension.ToLower() $config = $null if ($extension -eq ".yml" -or $extension -eq ".yaml") { try { - $config = [PSCustomObject](Get-Content -Path $configFilePath | ConvertFrom-Yaml -Ordered) + $config = [PSCustomObject](Get-Content -Path $configFilePath -Force | ConvertFrom-Yaml -Ordered) } catch { $errorMessage = "Failed to parse YAML inputs. Please check the YAML file for errors and try again. $_" Write-ToConsoleLog $errorMessage -IsError @@ -31,7 +31,7 @@ function Get-ALZConfig { } elseif ($extension -eq ".json") { try { - $config = [PSCustomObject](Get-Content -Path $configFilePath | ConvertFrom-Json) + $config = [PSCustomObject](Get-Content -Path $configFilePath -Force | ConvertFrom-Json) } catch { $errorMessage = "Failed to parse JSON inputs. Please check the JSON file for errors and try again. $_" Write-ToConsoleLog $errorMessage -IsError diff --git a/src/ALZ/Private/Config-Helpers/Get-AzureRegionData.ps1 b/src/ALZ/Private/Config-Helpers/Get-AzureRegionData.ps1 index c473cf5..c695a0d 100644 --- a/src/ALZ/Private/Config-Helpers/Get-AzureRegionData.ps1 +++ b/src/ALZ/Private/Config-Helpers/Get-AzureRegionData.ps1 @@ -49,7 +49,7 @@ function Get-AzureRegionData { Invoke-Terraform -moduleFolderPath $regionFolder -autoApprove -output "regions_and_zones" -outputFilePath $outputFilePath -silent - $json = Get-Content $outputFilePath + $json = Get-Content $outputFilePath -Force $regionsAndZones = ConvertFrom-Json $json $zonesSupport = @() diff --git a/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AcceleratorFolderConfiguration.ps1 b/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AcceleratorFolderConfiguration.ps1 index 8c24ac4..00e86c9 100644 --- a/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AcceleratorFolderConfiguration.ps1 +++ b/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AcceleratorFolderConfiguration.ps1 @@ -67,7 +67,7 @@ function Get-AcceleratorFolderConfiguration { # Try to read and validate inputs.yaml try { - $inputsContent = Get-Content -Path $inputsYamlPath -Raw + $inputsContent = Get-Content -Path $inputsYamlPath -Raw -Force $inputsYaml = $inputsContent | ConvertFrom-Yaml $result.InputsContent = $inputsContent diff --git a/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AzureContext.ps1 b/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AzureContext.ps1 index 2e9f8f0..41a208a 100644 --- a/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AzureContext.ps1 +++ b/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AzureContext.ps1 @@ -40,11 +40,11 @@ function Get-AzureContext { # Check if valid cache exists if (Test-Path $cacheFilePath) { - $cacheFile = Get-Item $cacheFilePath + $cacheFile = Get-Item $cacheFilePath -Force $cacheAge = (Get-Date) - $cacheFile.LastWriteTime if ($cacheAge.TotalHours -lt $cacheExpirationHours) { try { - $cachedContext = Get-Content -Path $cacheFilePath -Raw | ConvertFrom-Json -AsHashtable + $cachedContext = Get-Content -Path $cacheFilePath -Raw -Force | ConvertFrom-Json -AsHashtable Write-ToConsoleLog "Using cached Azure context (cached $([math]::Round($cacheAge.TotalMinutes)) minutes ago). Use -clearCache to refresh." Write-ToConsoleLog "Found $($cachedContext.ManagementGroups.Count) management groups, $($cachedContext.Subscriptions.Count) subscriptions, and $($cachedContext.Regions.Count) regions" return $cachedContext @@ -60,7 +60,7 @@ function Get-AzureContext { Regions = @() } - Write-ToConsoleLog "Querying Azure for management groups, subscriptions, and regions..." + Write-ToConsoleLog "Querying Azure for management groups, subscriptions, and regions... (this can take up to 30 seconds)" try { # Get the current tenant ID diff --git a/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-ModuleVersionData.ps1 b/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-ModuleVersionData.ps1 index e839489..f1bf9e4 100644 --- a/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-ModuleVersionData.ps1 +++ b/src/ALZ/Private/Deploy-Accelerator-Helpers/Get-ModuleVersionData.ps1 @@ -12,7 +12,7 @@ function Get-ModuleVersionData { $dataFilePath = Join-Path $targetDirectory ".alz-version-data.json" if (Test-Path $dataFilePath) { - $data = Get-Content $dataFilePath | ConvertFrom-Json + $data = Get-Content $dataFilePath -Force | ConvertFrom-Json $versionKey = "$($moduleType)Version" return $data.$versionKey } diff --git a/src/ALZ/Private/Deploy-Accelerator-Helpers/New-Bootstrap.ps1 b/src/ALZ/Private/Deploy-Accelerator-Helpers/New-Bootstrap.ps1 index 3c28fdd..1f1d30c 100644 --- a/src/ALZ/Private/Deploy-Accelerator-Helpers/New-Bootstrap.ps1 +++ b/src/ALZ/Private/Deploy-Accelerator-Helpers/New-Bootstrap.ps1 @@ -132,7 +132,7 @@ function New-Bootstrap { $bootstrapParameters = [PSCustomObject]@{} Write-Verbose "Getting the bootstrap configuration..." - $terraformFiles = Get-ChildItem -Path $bootstrapModulePath -Filter "*.tf" -File + $terraformFiles = Get-ChildItem -Path $bootstrapModulePath -Filter "*.tf" -File -Force foreach ($terraformFile in $terraformFiles) { $bootstrapParameters = Convert-HCLVariablesToInputConfig -targetVariableFile $terraformFile.FullName -hclParserToolPath $hclParserToolPath -appendToObject $bootstrapParameters } @@ -145,7 +145,7 @@ function New-Bootstrap { if ($hasStarter) { Write-Verbose "Getting the starter configuration..." if ($iac -eq "terraform") { - $terraformFiles = Get-ChildItem -Path $starterRootModuleFolderPath -Filter "*.tf" -File + $terraformFiles = Get-ChildItem -Path $starterRootModuleFolderPath -Filter "*.tf" -File -Force foreach ($terraformFile in $terraformFiles) { $starterParameters = Convert-HCLVariablesToInputConfig -targetVariableFile $terraformFile.FullName -hclParserToolPath $hclParserToolPath -appendToObject $starterParameters } @@ -215,7 +215,7 @@ function New-Bootstrap { if ($iac -eq "terraform") { if ($starterFoldersToRetain.Length -gt 0) { Write-Verbose "Removing unwanted folders from the starter module..." - $folders = Get-ChildItem -Path $starterModulePath -Directory + $folders = Get-ChildItem -Path $starterModulePath -Directory -Force foreach ($folder in $folders) { if ($starterFoldersToRetain -notcontains $folder.Name) { Write-Verbose "Removing folder: $($folder.FullName)" diff --git a/src/ALZ/Private/Deploy-Accelerator-Helpers/New-ModuleSetup.ps1 b/src/ALZ/Private/Deploy-Accelerator-Helpers/New-ModuleSetup.ps1 index fad1292..08e5d79 100644 --- a/src/ALZ/Private/Deploy-Accelerator-Helpers/New-ModuleSetup.ps1 +++ b/src/ALZ/Private/Deploy-Accelerator-Helpers/New-ModuleSetup.ps1 @@ -177,7 +177,7 @@ function New-ModuleSetup { if (!$firstRun) { Write-Verbose "Checking for state files at: $previousStatePath" - $previousStateFiles = Get-ChildItem $previousVersionPath -Filter "terraform.tfstate" -Recurse | Select-Object -First 1 | ForEach-Object { $_.FullName } + $previousStateFiles = Get-ChildItem $previousVersionPath -Filter "terraform.tfstate" -Recurse -Force | Select-Object -First 1 | ForEach-Object { $_.FullName } if ($previousStateFiles.Count -gt 0) { foreach ($stateFile in $previousStateFiles) { diff --git a/src/ALZ/Private/Deploy-Accelerator-Helpers/Request-ALZConfigurationValue.ps1 b/src/ALZ/Private/Deploy-Accelerator-Helpers/Request-ALZConfigurationValue.ps1 index e17a884..17cb8b9 100644 --- a/src/ALZ/Private/Deploy-Accelerator-Helpers/Request-ALZConfigurationValue.ps1 +++ b/src/ALZ/Private/Deploy-Accelerator-Helpers/Request-ALZConfigurationValue.ps1 @@ -178,7 +178,7 @@ function Request-ALZConfigurationValue { Write-ToConsoleLog "Schema file not found at $schemaPath. Proceeding without descriptions." -IsWarning $schema = $null } else { - $schema = Get-Content -Path $schemaPath -Raw | ConvertFrom-Json + $schema = Get-Content -Path $schemaPath -Raw -Force | ConvertFrom-Json } # Define the configuration files to process @@ -192,7 +192,7 @@ function Request-ALZConfigurationValue { Write-ToConsoleLog "For more information, see: https://aka.ms/alz/acc/phase0" # Read the raw content to preserve comments and ordering - $inputsYamlContent = Get-Content -Path $inputsYamlPath -Raw + $inputsYamlContent = Get-Content -Path $inputsYamlPath -Raw -Force $inputsConfig = $inputsYamlContent | ConvertFrom-Yaml -Ordered $inputsUpdated = $false $sensitiveEnvVars = @{} diff --git a/src/ALZ/Private/Deploy-Accelerator-Helpers/Request-AcceleratorConfigurationInput.ps1 b/src/ALZ/Private/Deploy-Accelerator-Helpers/Request-AcceleratorConfigurationInput.ps1 index 670153e..9ec52c7 100644 --- a/src/ALZ/Private/Deploy-Accelerator-Helpers/Request-AcceleratorConfigurationInput.ps1 +++ b/src/ALZ/Private/Deploy-Accelerator-Helpers/Request-AcceleratorConfigurationInput.ps1 @@ -162,7 +162,7 @@ function Request-AcceleratorConfigurationInput { # Prompt for scenario number (Terraform only) if ($selectedIacType -eq "terraform") { $scenariosJsonPath = Join-Path $PSScriptRoot "TerraformScenarios.json" - $scenarioOptions = Get-Content -Path $scenariosJsonPath -Raw | ConvertFrom-Json + $scenarioOptions = Get-Content -Path $scenariosJsonPath -Raw -Force | ConvertFrom-Json $selectedScenarioNumber = Read-MenuSelection ` -Title "Select the Terraform scenario (see https://aka.ms/alz/acc/scenarios):" ` diff --git a/src/ALZ/Private/Deploy-Accelerator-Helpers/Set-ModuleVersionData.ps1 b/src/ALZ/Private/Deploy-Accelerator-Helpers/Set-ModuleVersionData.ps1 index 807eb92..d42bdbb 100644 --- a/src/ALZ/Private/Deploy-Accelerator-Helpers/Set-ModuleVersionData.ps1 +++ b/src/ALZ/Private/Deploy-Accelerator-Helpers/Set-ModuleVersionData.ps1 @@ -17,7 +17,7 @@ function Set-ModuleVersionData { # Load existing data or create new if (Test-Path $dataFilePath) { - $data = Get-Content $dataFilePath | ConvertFrom-Json + $data = Get-Content $dataFilePath -Force | ConvertFrom-Json } else { $data = [PSCustomObject]@{ bootstrapVersion = $null diff --git a/src/ALZ/Private/Shared/Get-GithubRelease.ps1 b/src/ALZ/Private/Shared/Get-GithubRelease.ps1 index c4f07ec..1447490 100644 --- a/src/ALZ/Private/Shared/Get-GithubRelease.ps1 +++ b/src/ALZ/Private/Shared/Get-GithubRelease.ps1 @@ -101,7 +101,7 @@ function Get-GithubRelease { Write-Verbose "===> Checking if any content exists inside of $targetVersionPath" - $contentTargetVersionPath = Get-ChildItem -Path $targetVersionPath -Recurse -ErrorAction SilentlyContinue + $contentTargetVersionPath = Get-ChildItem -Path $targetVersionPath -Recurse -Force -ErrorAction SilentlyContinue if ($null -eq $contentTargetVersionPath) { Write-Verbose "===> Pulling and extracting release $releaseTag into $targetVersionPath" @@ -139,7 +139,7 @@ function Get-GithubRelease { $extractedSubFolder = $targetPathForExtractedZip if($releaseArtifactName -eq "") { - $extractedSubFolder = (Get-ChildItem -Path $targetPathForExtractedZip -Directory).FullName + $extractedSubFolder = (Get-ChildItem -Path $targetPathForExtractedZip -Directory -Force).FullName } Write-Verbose "===> Copying all extracted contents into $targetVersionPath from $($extractedSubFolder)/$moduleSourceFolder/*." @@ -157,7 +157,7 @@ function Get-GithubRelease { $envFilePath = Join-Path -Path $parentDirectory -ChildPath ".env" if (Test-Path $envFilePath) { Write-Verbose "===> Replacing the .env file release version with $releaseTag" - (Get-Content $envFilePath) -replace "UPSTREAM_RELEASE_VERSION=.*", "UPSTREAM_RELEASE_VERSION=$releaseTag" | Set-Content $envFilePath + (Get-Content $envFilePath -Force) -replace "UPSTREAM_RELEASE_VERSION=.*", "UPSTREAM_RELEASE_VERSION=$releaseTag" | Set-Content $envFilePath -Force } return $releaseTag diff --git a/src/ALZ/Private/Shared/Get-GithubReleaseTag.ps1 b/src/ALZ/Private/Shared/Get-GithubReleaseTag.ps1 index 00e2123..e143afe 100644 --- a/src/ALZ/Private/Shared/Get-GithubReleaseTag.ps1 +++ b/src/ALZ/Private/Shared/Get-GithubReleaseTag.ps1 @@ -76,6 +76,12 @@ function Get-GithubReleaseTag { throw "The release $release does not exist in the GitHub repository $githubRepoUrl - $repoReleaseUrl" } + if ($statusCode -eq 401 -or $statusCode -eq 403) { + $message = "Unable to query repository version from $repoReleaseUrl. HTTP status code: $statusCode (Forbidden/Unauthorized). This is most often caused by an expired or invalid GitHub CLI authentication token, or by GitHub API rate limiting on anonymous requests. If you have the GitHub CLI (gh) installed, run 'gh auth login' (or 'gh auth logout' followed by 'gh auth login') to refresh your credentials, then re-run the command. If you do not use the GitHub CLI, wait a few minutes for the rate limit to reset before retrying." + Write-ToConsoleLog $message -IsError + throw $message + } + if ($statusCode -ne 200) { Write-ToConsoleLog "Unable to query repository version from $repoReleaseUrl. HTTP status code: $statusCode" -IsError throw "Unable to query repository version, please check your internet connection and try again..." diff --git a/src/ALZ/Private/Shared/Invoke-GitHubApiRequest.ps1 b/src/ALZ/Private/Shared/Invoke-GitHubApiRequest.ps1 index d57ed14..43fc2f7 100644 --- a/src/ALZ/Private/Shared/Invoke-GitHubApiRequest.ps1 +++ b/src/ALZ/Private/Shared/Invoke-GitHubApiRequest.ps1 @@ -74,6 +74,7 @@ function Invoke-GitHubApiRequest { # Build auth headers from gh CLI if available $headers = @{} + $usedGhToken = $false $ghCommand = Get-Command "gh" -ErrorAction SilentlyContinue if ($null -ne $ghCommand) { $null = & gh auth status 2>&1 @@ -81,6 +82,7 @@ function Invoke-GitHubApiRequest { $token = & gh auth token 2>&1 if ($LASTEXITCODE -eq 0 -and -not [string]::IsNullOrWhiteSpace($token)) { $headers["Authorization"] = "Bearer $($token.Trim())" + $usedGhToken = $true Write-Verbose "GitHub CLI authentication token found. Using authenticated requests." } } else { @@ -106,9 +108,37 @@ function Invoke-GitHubApiRequest { $retryParams["Headers"] = $headers } + # If the gh CLI token is rejected (401/403), the token is likely expired or + # has insufficient scopes. Drop the Authorization header so the next attempt + # is anonymous (subject to lower rate limits) and warn the user to refresh + # their gh credentials with `gh auth login`. + function Disable-AuthAndWarn { + param([int] $StatusCode) + Write-ToConsoleLog "GitHub API request to $Uri was rejected with status $StatusCode while using the GitHub CLI authentication token. The token may be expired or have insufficient scopes. Retrying without authentication. To resolve this permanently, run 'gh auth login' (or 'gh auth logout' followed by 'gh auth login') to refresh your GitHub CLI credentials." -IsWarning + $retryParams.Remove("Headers") + } + + function Get-StatusCodeFromError { + param($ErrorRecord) + if ($ErrorRecord.Exception.Response) { + return [int]$ErrorRecord.Exception.Response.StatusCode + } + return $null + } + # File download — delegate directly if (-not [string]::IsNullOrEmpty($OutputFile)) { - Invoke-HttpRequestWithRetry @retryParams -OutFile $OutputFile + try { + Invoke-HttpRequestWithRetry @retryParams -OutFile $OutputFile + } catch { + $statusCode = Get-StatusCodeFromError $_ + if ($usedGhToken -and ($statusCode -eq 401 -or $statusCode -eq 403)) { + Disable-AuthAndWarn -StatusCode $statusCode + Invoke-HttpRequestWithRetry @retryParams -OutFile $OutputFile + } else { + throw + } + } return } @@ -116,6 +146,11 @@ function Invoke-GitHubApiRequest { if ($SkipHttpErrorCheck) { $response = Invoke-HttpRequestWithRetry @retryParams -SkipHttpErrorCheck -ReturnStatusCode + if ($usedGhToken -and ($response.StatusCode -eq 401 -or $response.StatusCode -eq 403)) { + Disable-AuthAndWarn -StatusCode $response.StatusCode + $response = Invoke-HttpRequestWithRetry @retryParams -SkipHttpErrorCheck -ReturnStatusCode + } + $parsed = $null if (-not [string]::IsNullOrWhiteSpace($response.Result.Content)) { $parsed = $response.Result.Content | ConvertFrom-Json @@ -128,7 +163,17 @@ function Invoke-GitHubApiRequest { } # Standard API call — parse JSON and return the object - $response = Invoke-HttpRequestWithRetry @retryParams + try { + $response = Invoke-HttpRequestWithRetry @retryParams + } catch { + $statusCode = Get-StatusCodeFromError $_ + if ($usedGhToken -and ($statusCode -eq 401 -or $statusCode -eq 403)) { + Disable-AuthAndWarn -StatusCode $statusCode + $response = Invoke-HttpRequestWithRetry @retryParams + } else { + throw + } + } if (-not [string]::IsNullOrWhiteSpace($response.Content)) { return ($response.Content | ConvertFrom-Json) } diff --git a/src/ALZ/Private/Tools/Checks/Test-NetworkConnectivity.ps1 b/src/ALZ/Private/Tools/Checks/Test-NetworkConnectivity.ps1 index 2700ff1..bd29118 100644 --- a/src/ALZ/Private/Tools/Checks/Test-NetworkConnectivity.ps1 +++ b/src/ALZ/Private/Tools/Checks/Test-NetworkConnectivity.ps1 @@ -18,19 +18,32 @@ function Test-NetworkConnectivity { Write-Verbose "Checking network connectivity to required endpoints" $endpoints = @( - @{ Uri = "https://api.github.com"; Description = "GitHub API (release lookups)" }, - @{ Uri = "https://github.com"; Description = "GitHub (module downloads)" }, - @{ Uri = "https://api.releases.hashicorp.com"; Description = "HashiCorp Releases API (Terraform version)" }, - @{ Uri = "https://releases.hashicorp.com"; Description = "HashiCorp Releases (Terraform binary download)" }, - @{ Uri = "https://management.azure.com"; Description = "Azure Management API" }, - @{ Uri = "https://www.powershellgallery.com"; Description = "PowerShell Gallery (module installs/updates)" } + @{ Uri = "https://api.github.com"; Description = "GitHub API (root)" }, + @{ Uri = "https://api.github.com/repos/Azure/accelerator-bootstrap-modules/releases/latest"; Description = "GitHub API (accelerator-bootstrap-modules latest release)" }, + @{ Uri = "https://github.com"; Description = "GitHub (module downloads)" }, + @{ Uri = "https://api.releases.hashicorp.com"; Description = "HashiCorp Releases API (Terraform version)" }, + @{ Uri = "https://releases.hashicorp.com"; Description = "HashiCorp Releases (Terraform binary download)" }, + @{ Uri = "https://management.azure.com"; Description = "Azure Management API" }, + @{ Uri = "https://www.powershellgallery.com"; Description = "PowerShell Gallery (module installs/updates)" } ) foreach ($endpoint in $endpoints) { Write-Verbose "Testing network connectivity to $($endpoint.Uri)" try { - if ($endpoint.Uri -eq "https://api.github.com") { - Invoke-GitHubApiRequest -Uri $endpoint.Uri -Method Head -SkipHttpErrorCheck -MaxRetryCount $HttpRequestMaxRetryCount -RetryIntervalSeconds $HttpRequestRetryIntervalSeconds -TimeoutSec $HttpRequestTimeoutSeconds | Out-Null + if ($endpoint.Uri.StartsWith("https://api.github.com")) { + $response = Invoke-GitHubApiRequest -Uri $endpoint.Uri -Method Head -SkipHttpErrorCheck -MaxRetryCount $HttpRequestMaxRetryCount -RetryIntervalSeconds $HttpRequestRetryIntervalSeconds -TimeoutSec $HttpRequestTimeoutSeconds + $statusCode = $null + if ($null -ne $response) { + $statusCode = $response.StatusCode + } + if ($statusCode -eq 401 -or $statusCode -eq 403) { + $results += @{ + message = "GitHub API ($($endpoint.Uri)) returned HTTP $statusCode. This is most often caused by an expired or invalid GitHub CLI authentication token, or by GitHub API rate limiting. If you have the GitHub CLI (gh) installed, run 'gh auth login' (or 'gh auth logout' followed by 'gh auth login') to refresh your credentials. Otherwise wait a few minutes for the rate limit to reset before retrying." + result = "Failure" + } + $hasFailure = $true + continue + } } else { Invoke-HttpRequestWithRetry -Uri $endpoint.Uri -Method Head -TimeoutSec $HttpRequestTimeoutSeconds -SkipHttpErrorCheck -MaxRetryCount $HttpRequestMaxRetryCount -RetryIntervalSeconds $HttpRequestRetryIntervalSeconds | Out-Null } diff --git a/src/ALZ/Public/New-AcceleratorFolderStructure.ps1 b/src/ALZ/Public/New-AcceleratorFolderStructure.ps1 index ed43b0d..feb2720 100644 --- a/src/ALZ/Public/New-AcceleratorFolderStructure.ps1 +++ b/src/ALZ/Public/New-AcceleratorFolderStructure.ps1 @@ -131,7 +131,7 @@ function New-AcceleratorFolderStructure { # Copy the platform landing zone configuration files based on scenario number or specific file path if ($repo.hasScenarios) { $scenariosJsonPath = Join-Path $PSScriptRoot ".." "Private" "Deploy-Accelerator-Helpers" "TerraformScenarios.json" - $scenarioOptions = Get-Content -Path $scenariosJsonPath -Raw | ConvertFrom-Json + $scenarioOptions = Get-Content -Path $scenariosJsonPath -Raw -Force | ConvertFrom-Json $scenarios = @{} foreach ($scenario in $scenarioOptions) { $scenarios[[int]$scenario.value] = $scenario.path diff --git a/src/ALZ/Public/Remove-AzureDevOpsAccelerator.ps1 b/src/ALZ/Public/Remove-AzureDevOpsAccelerator.ps1 index 00a67aa..81896db 100644 --- a/src/ALZ/Public/Remove-AzureDevOpsAccelerator.ps1 +++ b/src/ALZ/Public/Remove-AzureDevOpsAccelerator.ps1 @@ -341,7 +341,7 @@ function Remove-AzureDevOpsAccelerator { if($PlanMode) { Write-ToConsoleLog "Plan mode enabled, no changes were made." -IsWarning - $planLogContents = Get-Content -Path $TempLogFileForPlan -Raw + $planLogContents = Get-Content -Path $TempLogFileForPlan -Raw -Force Write-ToConsoleLog @("Plan mode log contents:", $planLogContents) -Color Gray Remove-Item -Path $TempLogFileForPlan -Force } diff --git a/src/ALZ/Public/Remove-GitHubAccelerator.ps1 b/src/ALZ/Public/Remove-GitHubAccelerator.ps1 index 2e0eb07..0c8c3da 100644 --- a/src/ALZ/Public/Remove-GitHubAccelerator.ps1 +++ b/src/ALZ/Public/Remove-GitHubAccelerator.ps1 @@ -397,7 +397,7 @@ function Remove-GitHubAccelerator { if($PlanMode) { Write-ToConsoleLog "Plan mode enabled, no changes were made." -IsWarning - $planLogContents = Get-Content -Path $TempLogFileForPlan -Raw + $planLogContents = Get-Content -Path $TempLogFileForPlan -Raw -Force Write-ToConsoleLog @("Plan mode log contents:", $planLogContents) -Color Gray Remove-Item -Path $TempLogFileForPlan -Force } diff --git a/src/ALZ/Public/Remove-PlatformLandingZone.ps1 b/src/ALZ/Public/Remove-PlatformLandingZone.ps1 index 2379332..a9035c1 100644 --- a/src/ALZ/Public/Remove-PlatformLandingZone.ps1 +++ b/src/ALZ/Public/Remove-PlatformLandingZone.ps1 @@ -1329,7 +1329,7 @@ function Remove-PlatformLandingZone { if($PlanMode) { Write-ToConsoleLog "Plan mode enabled, no changes were made." -IsWarning - $planLogContents = Get-Content -Path $TempLogFileForPlan -Raw + $planLogContents = Get-Content -Path $TempLogFileForPlan -Raw -Force Write-ToConsoleLog @("Plan mode log contents:", $planLogContents) -Color Gray Remove-Item -Path $TempLogFileForPlan -Force } diff --git a/src/Tests/Unit/Private/Test-NetworkConnectivity.Tests.ps1 b/src/Tests/Unit/Private/Test-NetworkConnectivity.Tests.ps1 index 53cb338..bacf953 100644 --- a/src/Tests/Unit/Private/Test-NetworkConnectivity.Tests.ps1 +++ b/src/Tests/Unit/Private/Test-NetworkConnectivity.Tests.ps1 @@ -40,9 +40,9 @@ InModuleScope 'ALZ' { } } - It 'returns one result per endpoint (6 total)' { + It 'returns one result per endpoint (7 total)' { $result = Test-NetworkConnectivity - $result.Results.Count | Should -Be 6 + $result.Results.Count | Should -Be 7 } } @@ -64,7 +64,7 @@ InModuleScope 'ALZ' { It 'returns a Failure result for the unreachable endpoint' { $result = Test-NetworkConnectivity $failureResults = @($result.Results | Where-Object { $_.result -eq "Failure" }) - $failureResults.Count | Should -Be 1 + $failureResults.Count | Should -Be 2 } It 'includes the error message in the Failure result' { @@ -103,15 +103,15 @@ InModuleScope 'ALZ' { } } - It 'returns one result per endpoint (6 total)' { + It 'returns one result per endpoint (7 total)' { $result = Test-NetworkConnectivity - $result.Results.Count | Should -Be 6 + $result.Results.Count | Should -Be 7 } It 'checks all endpoints and does not stop at the first failure' { $result = Test-NetworkConnectivity Should -Invoke -CommandName Invoke-HttpRequestWithRetry -Times 5 -Scope It - Should -Invoke -CommandName Invoke-GitHubApiRequest -Times 1 -Scope It + Should -Invoke -CommandName Invoke-GitHubApiRequest -Times 2 -Scope It } } }