functions/azure/azcli/Invoke-AzCli.ps1
# <copyright file="Invoke-AzCli.ps1" company="Endjin Limited"> # Copyright (c) Endjin Limited. All rights reserved. # </copyright> <# .SYNOPSIS Invokes azure-cli commands and returns the results. .DESCRIPTION Provides a wrapper for invokes an azure-cli commands. .PARAMETER Command The azure-cli command you want to execute, excluding the 'az' reference. .PARAMETER AsJson Controls whether you expect the command to have a JSON response that you want returned as output. .PARAMETER ExpectedExitCodes An array of exit codes that will not be treated as signifying an error. .PARAMETER SuppressConnectionValidation When specified, the normal connection validation will not be performed. This is useful when issuing commands before a connection has been established. .PARAMETER UseLegacyNativeCommandArgumentPassing When specified, '$PSNativeCommandArgumentPassing' will be set to 'Legacy'. This is useful to maintain backwards-compatibility with versions of PowerShell (pre-7.3) for scenarios where Azure CLI command-line arguments require the use of escaped quotation marks. Ref: https://learn.microsoft.com/en-us/powershell/scripting/learn/experimental-features?view=powershell-7.4#psnativecommandargumentpassing .OUTPUTS When the '-AsJson' parameter is supplied, the JSON output from azure-cli will be returned as a hashtable. #> function Invoke-AzCli { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] $Command, [switch] $AsJson, [array] $ExpectedExitCodes = @(0), [switch] $SuppressConnectionValidation, [switch] $UseLegacyNativeCommandArgumentPassing ) # Ensure the AzureCLI is installed and available if (!(Get-Command "az")) { throw "The AzureCLI could not be found. If recently installed, you may need to restart your session to update your PATH configuration." } # Ensure we have a validation AzureCLI connection, unless explicitly suppressed # (e.g. when this module is trying to login) if ( $SuppressConnectionValidation -or (_EnsureAzureConnection -AzureCli) ) { # If passed an array of command arguments, concatenate them into single comnmand-line string if ($Command -is [array]) { $Command = ($Command -join " ") } $cmd = "az $Command" if ($asJson) { $cmd = "$cmd -o json" } Write-Verbose "azcli cmd: $cmd" # Execute the azure-cli and capture the results and any StdErr output $res,$azCliStdErr = _invokeAzCli $cmd $diagnosticInfo = @" StdOut: $($res -join "`n") StdErr: $($azCliStdErr -join "`n") "@ if ($expectedExitCodes -inotcontains $LASTEXITCODE) { Write-Warning "azure-cli error diagnostic information:`nCommand: $cmd`n$diagnosticInfo" Write-Error "azure-cli failed with exit code: $LASTEXITCODE - check previous logs for more details" } Write-Verbose $diagnosticInfo if ($asJson) { return ($res | ConvertFrom-Json -Depth 30 -AsHashtable) } return $res,$azCliStdErr } } # Extract function for mocking purposes function _invokeAzCli { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string] $CommandLine ) # PowerShell 7.2.0 introduced a bug when using -ErrorVariable to capture errors, so we # have fallen back to using file-based redirection $azCliErrorLog = New-TemporaryFile try { # Provide a mechanism to use the legacy native command argument passing. The override # will fall out of scope when the function exits. if ($UseLegacyNativeCommandArgumentPassing) { $PSNativeCommandArgumentPassing = "Legacy" } $output = Invoke-Expression $CommandLine 2> $($azCliErrorLog.FullName) $stdErr = Get-Content -Raw $azCliErrorLog return $output,$stdErr } finally { Remove-Item -Path $azCliErrorLog -Force } } |