Add "Az Powershell" commands for data operations
I am trying to consume this Azure service in my service implementation but I can't integrate it into our release pipelines process. I have PowerShell scripts that run after our ARM deployments to do final setups and I was hoping I can add all the settings and key vault endpoints needed for the service but only az appconfig is supported at this time. Running az appconfig within PoweShell scripts is not ideal, a proper Az Cmdlet would be much better.
While we're waiting on Az module support, here is the equivalent command using the Azure CLI:
az appconfig kv set
Full docs here:
https://docs.microsoft.com/en-us/cli/azure/appconfig/kv?view=azure-cli-latest
And a useful article that goes into more detail on how else you can interact with an App Configuration Service instance:
https://zimmergren.net/introduction-azure-app-configuration-store-csharp-dotnetcore/
How can a token be fetched via Get-AzAccessToken for use with HTTP requests to configure store endpoints?
Get-AzAccessToken only supports Azure resource management (management plane) endpoints. Please log feature request to https://github.com/Azure/azure-powershell/issues/new/choose
Any news on this request? It seems like it should be something that's just there.
When can we have this? I can't use Get-AzAccessToken, I can't mix azure cli with azure pwsh in pipeline without a load of faff. It's been a long while since it was requested, az cli has it, how long before pwsh gets it too?
Can we have a workaround that doesn't involve az cli, please?
Get-AzAccessTokenonly supports Azure resource management (management plane) endpoints. Please log feature request to https://github.com/Azure/azure-powershell/issues/new/choose
I'm not sure this is really true. I've used it for a bunch of other data plane stuff, I'm sure.
Hi @mattboothman ,
We are visiting Invoke-AzRestMethod now. Idea is cmdlet will analyze the domain of input URL and find the correct name of resource (resourceId) to use in further data plane request. The limitation is we only can support data plane API which resourceId and domain suffix have been declared in Azure Environment Get-AzEnvironment
Can it cover your requirement?
Thanks, Dingmeng
This original request is now 2 years old. This seems like plenty of time to implement data plane cmdlets for App Configuration. Every other Azure resource I work with regularly has full support for native PowerShell actions, for both management and data plane operations. Why is this not forthcoming for App Configuration?
At this point should users assume this will just never happen? If so, can this be closed as "won't fix" so we can at least know what to expect, or more correctly, to not expect it?
In case it helps someone else, here's an example of how to use Get-AzAccessToken with App Configuration to get a list of keys and add a new key/value pair.
$accessToken = Get-AzAccessToken -ResourceUrl 'https://azconfig.io'
# Get a list of keys
Invoke-RestMethod -Authentication Bearer -Token (ConvertTo-SecureString -AsPlainText $accessToken.Token -Force) -Uri "https://$appConfigName.azconfig.io/keys?api-version=1.0"
# Insert a new key/value pair
$keyValue = @{ value = 'Some Value'; content_type = 'text/plain', tags=@{ 'tag1' = 'value1', 'tag2' = 'value2' } }
Invoke-RestMethod -Authentication Bearer -Token (ConvertTo-SecureString -AsPlainText $accessToken.Token -Force) -Uri "https://$appConfigName.azconfig.io/kv/testKey?api-version=1.0" -Method Put -Body (ConvertTo-Json $keyValue) -ContentType 'application/vnd.microsoft.appconfig.kv+json'
NB: While it's fine for this example, when passing more complex objects to ConvertTo-Json you may need to pass -Depth N because the default depth is only 2, meaning anything more than two levels deep in the object hierarchy will be ignored.
While we're waiting on Az module support, here is the equivalent command using the Azure CLI:
az appconfig kv setFull docs here:
https://docs.microsoft.com/en-us/cli/azure/appconfig/kv?view=azure-cli-latest
And a useful article that goes into more detail on how else you can interact with an App Configuration Service instance:
https://zimmergren.net/introduction-azure-app-configuration-store-csharp-dotnetcore/
Using az cli requires a separate login to Azure as it does not detect the existing login done with Connect-AzAccount
We are on the way to support AppConfiguration data plane feature. Since Az 9, you can use Invoke-AzRestMethod to send request to data plane of AppConfiguration directly. Az.Accounts will handle token automatically according to URL.
Here's an example for reading key-values from App Configuration, although using a connection string instead of access token for authentication.
Keys can contain slash characters, so they need to be URL-encoded using [System.Net.WebUtility]::UrlEncode($Key) when building a $RequestUri.
function Invoke-AppConfigRequest {
param(
[Parameter(Mandatory = $true)] [string] $ConnectionString, # 'Endpoint=...;Id=...;Secret=...'
[Parameter(Mandatory = $true)] [string] $RequestUri, # '/kv?api-version=1.0&key=some-url-encoded-key&label=*'
[Parameter(Mandatory = $false)] [string] $Method = 'GET', # 'GET', 'POST'
[Parameter(Mandatory = $false)] [object] $Body = $null # Accepts [object] to avoid implicit conversion of $null to empty string
)
$ConnectionStringValues = $ConnectionString -split ';' | ForEach-Object { $Tokens = $_ -split '=',2; @{ Key = $Tokens[0]; Value = $Tokens[1] } }
$Endpoint = ($ConnectionStringValues | Where-Object { $_.Key -eq 'Endpoint' }).Value
$Credential = ($ConnectionStringValues | Where-Object { $_.Key -eq 'Id' }).Value
$Secret = ($ConnectionStringValues | Where-Object { $_.Key -eq 'Secret' }).Value
if ([string]::IsNullOrWhitespace($Endpoint) -or [string]::IsNullOrWhitespace($Credential) -or [string]::IsNullOrWhitespace($Secret)) {
throw "Invalid App Configuration connection string"
}
$UtcNow = (Get-Date).ToUniversalTime().ToString('ddd, d MMM yyyy HH:mm:ss \G\M\T')
$EndpointHost = $Endpoint -replace '^https?://(.*)$','$1'
$ContentHash = [Convert]::ToBase64String(
[System.Security.Cryptography.HashAlgorithm]::Create('sha256').ComputeHash(
[System.Text.Encoding]::UTF8.GetBytes($(if ($Body -ne $null) { "$Body" } else { '' }))
)
)
$StringToSign = "$Method`n$RequestUri`n$UtcNow;$EndpointHost;$ContentHash"
$HmacSha256 = New-Object System.Security.Cryptography.HMACSHA256
$HmacSha256.Key = [Convert]::FromBase64String($Secret)
$Signature = [Convert]::ToBase64String(
$HmacSha256.ComputeHash(
[System.Text.Encoding]::UTF8.GetBytes($StringToSign)
)
)
$Headers = @{
'Host' = $EndpointHost;
'x-ms-date' = $UtcNow;
'x-ms-content-sha256' = $ContentHash;
'Accept' = 'application/vnd.microsoft.appconfig.kv+json, application/json, application/problem+json';
'Authorization' = "HMAC-SHA256 Credential=$Credential&SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=$Signature";
}
$Uri = "$Endpoint$RequestUri"
$Response = Invoke-WebRequest -Method $Method -Uri $Uri -Headers $Headers -Body $Body
if ($Response.StatusCode -eq 200) {
[System.Text.Encoding]::UTF8.GetString($Response.Content) | ConvertFrom-Json
}
}
Example invocation:
function Get-AppConfigKeyValue {
param(
[Parameter(Mandatory = $true)] [string] $ConnectionString,
[Parameter(Mandatory = $true)] [string] $Key,
[Parameter(Mandatory = $false)] [string] $Label = ''
)
$UrlEncodedKey = [System.Net.WebUtility]::UrlEncode($Key)
$UrlEncodedLabel = [System.Net.WebUtility]::UrlEncode($Label)
# https://learn.microsoft.com/azure/azure-app-configuration/rest-api-key-value
$Method = 'GET'
$ApiVersion = '1.0'
$RequestUri = '/kv'
#if (![string]::IsNullOrWhitespace($UrlEncodedKey)) {
# $RequestUri += "/$UrlEncodedKey" # Strict key/label matching, no support for wildcards like *.
#}
$RequestUri += "?api-version=$ApiVersion"
if (![string]::IsNullOrWhitespace($UrlEncodedKey)) {
$RequestUri += "&key=$UrlEncodedKey" # Key filter, accepts "*" to match all keys.
}
if (![string]::IsNullOrWhitespace($UrlEncodedLabel)) {
$RequestUri += "&label=$UrlEncodedLabel" # Label filter, accepts "*" to match all labels.
} else {
$RequestUri += "&label=%00" # Matches KV without a label.
}
(Invoke-AppConfigRequest -ConnectionString $ConnectionString -RequestUri $RequestUri).items
}
@dingmeng-xue thanks for the hot tip.
We are on the way to support AppConfiguration data plane feature. Since Az 9, you can use
Invoke-AzRestMethodto send request to data plane of AppConfiguration directly. Az.Accounts will handle token automatically according to URL.
PS> Invoke-AzRestMethod -Uri "https://appcg-tlkappsettings.azconfig.io"
Invoke-AzRestMethod: The given key 'AzureAppConfigurationEndpointSuffix' was not present in the dictionary.
I upgraded to Az 9.1.1 after reading your comment but encountered the above error. It worked fine after running Connect-AzAccount to refresh my context. 👍 Very easy way to get at the data plane's REST interface! All the docs claim that Invoke-AzRestMethod is for control plane operations only, quite confusing.
@t-l-k , That endpoint suffix was introduced recently. If your Azure context was built for a while, environment variable list doesn't contain new endpoint. Please try to Clear-AzContext and login again.
3 years and counting now, is there going to be any priority for support Azure PowerShell?
Hello all, data-plane cmdlets are now available in the latest realase of Az.AppConfiguration (version 10.2.0)
Get-AzAppConfigurationKey Get-AzAppConfigurationKeyValue Get-AzAppConfigurationLabel Get-AzAppConfigurationRevision Remove-AzAppConfigurationKeyValue Set-AzAppConfigurationKeyValue
These are now available -- closing.