powershell-az.psm1
if (!(Get-Command -Name az -CommandType Application -ErrorAction SilentlyContinue)) { throw "AzureCLI is not installed or the az command cannot be found." } $AzCommand = (Get-Command -Name az -CommandType Application | Select-Object -First 1).Path New-Alias -Name az -Value Invoke-AzCommand -Force function Invoke-Az { & $AzCommand $args *>&1 } function Invoke-AzCommand { begin { if ($DebugPreference -ne 'SilentlyContinue' -and !($args | Where-Object {$_ -eq '--debug'})) { $args += '--debug' $args = $args | Where-Object {$_ -ne '--only-show-errors'} } if ($VerbosePreference -ne 'SilentlyContinue' -and !($args | Where-Object {$_ -eq '--verbose'})) { $args += '--verbose' $args = $args | Where-Object {$_ -ne '--only-show-errors'} } $_DebugPreference = $DebugPreference $_VerbosePreference = $VerbosePreference if ($args | Where-Object {$_ -eq '--debug'}) { $DebugPreference = 'Continue' $args = $args | Where-Object {$_ -ne '--only-show-errors'} } if ($args | Where-Object {$_ -eq '--verbose'}) { $VerbosePreference = 'Continue' $args = $args | Where-Object {$_ -ne '--only-show-errors'} } $IsJson = ($args -notcontains '--output' -and $args -notcontains '-o') -or ($args -join ' ' -match '\b?(-o|--output)\s+jsonc?\b?') $IsHelp = $args -contains '-h' -or $args -contains '--help' if ($env:TF_BUILD -or $env:GITHUB_ACTIONS) { Write-Host "$($env:TF_BUILD ? '##[command]' : ($env:GITHUB_ACTIONS ? '::group::' : ''))az $(($args | ForEach-Object { if ($_ -match '\s') { '"{0}"' -f ($_ -replace '"','\"') } else { $_ } }) -join ' ')" } $OutputStream = @() } process { $_ErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = 'Continue' $LastStreamType = $null $StreamErrorMessages = @() $StreamMessages = @() $StreamConverters = @{ 'WARNING' = { Write-Warning -Message $args[0] } 'INFO' = { Write-Verbose -Message $args[0] } 'DEBUG' = { Write-Debug -Message $args[0] } 'VERBOSE' = { Write-Verbose -Message $args[0] } } try { Invoke-Az @Args | ForEach-Object { $IsErrorRecord = $_ -is [System.Management.Automation.ErrorRecord] if (!$IsErrorRecord) { if ($StreamMessages -and $LastStreamType -ne 'ERROR') { & $StreamConverters[$LastStreamType] $($StreamMessages | Out-String) $StreamMessages = @() $LastStreamType = $null } if (!$IsHelp -and $IsJson) { $OutputStream += $_ } else { Write-Output $_ } } else { $Message = $_.Exception.Message if ($IsHelp) { Write-Host -Message $Message } else { $StreamType = $Message -replace '^(WARNING|ERROR|INFO|DEBUG|VERBOSE)?(?:\: )?.*$','$1' if ($StreamType) { $Message = $Message.Substring($StreamType.Length + 2) } $IsProgress = $Message -match '^(Alive\[|Finished\[)' if (!$IsProgress) { if ($LastStreamType -and $StreamType -and $StreamType -ne $LastStreamType -and $StreamMessages -and $LastStreamType -ne 'ERROR') { & $StreamConverters[$LastStreamType] $($StreamMessages | Out-String) $StreamMessages = @() } if (!$StreamType -or $StreamType -ne 'ERROR') { $StreamMessages += $Message } else { $StreamErrorMessages += $Message } if ($StreamType) { $LastStreamType = $StreamType } } } } } } finally { try { if ($StreamMessages) { if ($LastStreamType -eq 'ERROR') { $StreamErrorMessages += $StreamMessages } else { & $StreamConverters[$LastStreamType] $($StreamMessages | Out-String) } } if ($StreamErrorMessages) { if ($args) { $FirstArg = $args | Where-Object {$_ -like '-*'} | Select-Object -First 1 $FirstArgIndex = $args.IndexOf($FirstArg) if ($FirstArgIndex -lt 0) { $FirstArgIndex = $args.Length } $TargetCommand = $args[0..($FirstArgIndex-1)] } else { $TargetCommand = @() } $Command = "az $($TargetCommand)" $Message = "$Command failed: $($StreamErrorMessages -join "`n")" $ErrorRecord = [System.Management.Automation.ErrorRecord]::new([System.Management.Automation.RemoteException]::new($Message), "NativeCommandErrorMessage", [System.Management.Automation.ErrorCategory]::NotSpecified, $Command) Write-Error -ErrorRecord $ErrorRecord -ErrorAction $_ErrorActionPreference } } finally { $DebugPreference = $_DebugPreference $VerbosePreference = $_VerbosePreference if ($env:GITHUB_ACTIONS) { Write-Host '::endgroup::' } } } } end { if ($IsJson -and $OutputStream) { try { $OutputStream | ConvertFrom-Json -AsHashtable } catch { $OutputStream | Write-Output } } } } function ConvertTo-AzJson { [CmdletBinding()] param ( [Parameter(Mandatory, Position=0, ValueFromPipeline)] $InputObject, [ValidateRange(1, 100)] [int] $Depth = 100, [switch] $AsArray = $false ) begin { $Items = @() } process { $Items += $InputObject } end { ($Items | ConvertTo-Json -AsArray:$AsArray -Compress -Depth $Depth | ConvertTo-Json) -replace '^"|"$' } } function Out-AzJsonFile { [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory, Position=0, ValueFromPipeline)] $InputObject, [ValidateNotNullOrEmpty()] [string] $Path = $([System.IO.Path]::GetTempFileName()), [ValidateRange(1, 100)] [int] $Depth = 100, [switch] $AsArray = $false ) begin { $Items = @() } process { $Items += $InputObject } end { $Items | ConvertTo-Json -AsArray:$AsArray -Depth $Depth | Out-File -FilePath $Path -Encoding utf8 $Path } } function Out-AzDeploymentParameters { [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory, Position=0, ValueFromPipeline)] $InputObject, [ValidateNotNullOrEmpty()] [string] $Path = $([System.IO.Path]::GetTempFileName()), [ValidateRange(1, 100)] [int] $Depth = 100 ) begin { $Values = @{} } process { $InputObject.GetEnumerator() | ForEach-Object { $Values[$_.Key] = @{value=$_.Value} } } end { @{ '$schema' = 'https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#' contentVersion = '1.0.0.0' parameters = $Values } | ConvertTo-Json -Depth $Depth | Out-File -FilePath $Path -Encoding utf8 $Path } } function Get-AzUniqueString { [CmdletBinding()] param ( [Parameter(Mandatory, Position=0, ValueFromPipeline)] [string] $InputObject, [ValidateRange(1, [byte]::MaxValue)] [byte] $Length = 13 ) begin { $Strings = @() } process { $Strings += $InputObject } end { $Value = $Strings -join '-' if ($Value.Length -gt 131072) { throw 'Literal limit exceeded maximum length of 131,072 characters.' } [Azure.BuiltinFunctions]::UniqueString($Value) } } $BuiltinFunctionsCSharp = @' using System; using System.Text; namespace Azure { public static class BuiltinFunctions { public static string UniqueString(string text) { return Base32Encode(MurmurHash64(text)); } private static string Base32Encode(ulong input) { string text = "abcdefghijklmnopqrstuvwxyz234567"; StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < 13; i++) { stringBuilder.Append(text[(int)(input >> 59)]); input <<= 5; } return stringBuilder.ToString(); } private static ulong MurmurHash64(string str, uint seed = 0u) { return MurmurHash64(Encoding.UTF8.GetBytes(str), seed); } private static ulong MurmurHash64(byte[] data, uint seed = 0u) { int length = data.Length; uint h1 = seed; uint h2 = seed; int index; for (index = 0; index + 7 < length; index += 8) { uint k1 = (uint)(data[index] | (data[index + 1] << 8) | (data[index + 2] << 16) | (data[index + 3] << 24)); uint k3 = (uint)(data[index + 4] | (data[index + 5] << 8) | (data[index + 6] << 16) | (data[index + 7] << 24)); k1 *= 597399067; k1 = k1.RotateLeft32(15); k1 *= 2869860233u; h1 ^= k1; h1 = h1.RotateLeft32(19); h1 += h2; h1 = h1 * 5 + 1444728091; k3 *= 2869860233u; k3 = k3.RotateLeft32(17); k3 *= 597399067; h2 ^= k3; h2 = h2.RotateLeft32(13); h2 += h1; h2 = h2 * 5 + 197830471; } int tail = length - index; if (tail > 0) { uint k2 = ((tail >= 4) ? ((uint)(data[index] | (data[index + 1] << 8) | (data[index + 2] << 16) | (data[index + 3] << 24))) : (tail switch { 2 => (uint)(data[index] | (data[index + 1] << 8)), 3 => (uint)(data[index] | (data[index + 1] << 8) | (data[index + 2] << 16)), _ => data[index], })); k2 *= 597399067; k2 = k2.RotateLeft32(15); k2 *= 2869860233u; h1 ^= k2; if (tail > 4) { uint k4 = (uint)(tail switch { 6 => data[index + 4] | (data[index + 5] << 8), 7 => data[index + 4] | (data[index + 5] << 8) | (data[index + 6] << 16), _ => data[index + 4], } * -1425107063); k4 = k4.RotateLeft32(17); k4 *= 597399067; h2 ^= k4; } } h1 ^= (uint)length; h2 ^= (uint)length; h1 += h2; h2 += h1; h1 ^= h1 >> 16; h1 *= 2246822507u; h1 ^= h1 >> 13; h1 *= 3266489909u; h1 ^= h1 >> 16; h2 ^= h2 >> 16; h2 *= 2246822507u; h2 ^= h2 >> 13; h2 *= 3266489909u; h2 ^= h2 >> 16; h1 += h2; h2 += h1; return ((ulong)h2 << 32) | h1; } private static uint RotateLeft32(this uint value, int count) { return (value << count) | (value >> 32 - count); } } } '@ Add-Type -TypeDefinition $BuiltinFunctionsCSharp -Language CSharp |