Private/Test-AzCliAvailable.ps1
|
function Test-AzCliAvailable { <# .SYNOPSIS Tests if Azure CLI (az) is installed and available. Offers to download and install if missing. .DESCRIPTION Checks if the 'az' command is available on the system PATH. If not found, prompts the user to download and install the Azure CLI MSI (Windows x64). In non-interactive environments (CI/CD pipelines), throws immediately with installation instructions. .OUTPUTS Returns $true if az CLI is available. Throws if not available and user declines installation. #> [CmdletBinding()] [OutputType([bool])] param() # Quick check - is az already available? if (Get-Command 'az' -ErrorAction SilentlyContinue) { return $true } # az not found - determine if we're running interactively $isInteractive = [Environment]::UserInteractive -and -not $env:TF_BUILD -and -not $env:GITHUB_ACTIONS -and -not $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI if (-not $isInteractive) { throw "Azure CLI (az) is not installed. Install it from https://aka.ms/installazurecliwindowsx64 or run: winget install Microsoft.AzureCLI" } Write-Log -Message "" -Level Info Write-Log -Message "Azure CLI (az) is not installed on this system." -Level Error Write-Log -Message "The Azure CLI is required for this module to communicate with Azure." -Level Warning Write-Log -Message "Download URL: https://aka.ms/installazurecliwindowsx64" -Level Header Write-Log -Message "" -Level Info $response = Read-Host "Would you like to download and install the Azure CLI now? (y/n)" if ($response -notin @('y', 'Y', 'yes', 'Yes')) { throw "Azure CLI (az) is required but not installed. Install it from https://aka.ms/installazurecliwindowsx64 or run: winget install Microsoft.AzureCLI" } # Download and install $msiPath = Join-Path $env:TEMP 'AzureCLI.msi' try { Write-Log -Message "Downloading Azure CLI installer..." -Level Warning Invoke-WebRequest -Uri 'https://aka.ms/installazurecliwindowsx64' -OutFile $msiPath -UseBasicParsing Write-Log -Message "Installing Azure CLI (this may take a few minutes)..." -Level Warning $installProcess = Start-Process msiexec.exe -ArgumentList "/I `"$msiPath`" /quiet" -PassThru if (-not $installProcess.WaitForExit(1800000)) { # 30 minute safety timeout - prevents indefinite hangs in automation try { $installProcess.Kill() } catch { } throw "Azure CLI installation timed out after 30 minutes." } if ($installProcess.ExitCode -ne 0) { throw "MSI installer exited with code $($installProcess.ExitCode)" } # Refresh PATH so the current session can find az $machinePath = [Environment]::GetEnvironmentVariable('PATH', 'Machine') $userPath = [Environment]::GetEnvironmentVariable('PATH', 'User') $env:PATH = "$machinePath;$userPath" # Verify installation if (Get-Command 'az' -ErrorAction SilentlyContinue) { $azVersion = az version --query '\"azure-cli\"' -o tsv 2>$null Write-Log -Message "Azure CLI v$azVersion installed successfully." -Level Success Write-Log -Message "Run 'az login' to authenticate before using this module." -Level Warning return $true } else { throw "Azure CLI was installed but 'az' command is not found in PATH. Please restart your PowerShell session." } } catch { $errorMsg = $_.Exception.Message if ($errorMsg -notmatch 'not found in PATH|not installed') { Write-Log -Message "Failed to install Azure CLI: $errorMsg" -Level Error } throw "Azure CLI installation failed. Please install manually from https://aka.ms/installazurecliwindowsx64 - Error: $errorMsg" } finally { # Clean up MSI file if (Test-Path $msiPath) { Remove-Item $msiPath -Force -ErrorAction SilentlyContinue } } } |