Azure Resources API doesn't give me all fields - azure

I can't make the Azure Resources API return the full list of fields as it promises to do. The address of the API:
https://learn.microsoft.com/en-us/rest/api/resources/resources/list
I'm calling:
https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resources?api-version=2019-10-01&%24filter=resourceType%20eq%20'Microsoft.Compute%2FvirtualMachines'
which gives me the list in a form:
{
"value": [
{
"type": "Microsoft.Compute/virtualMachines",
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/xxx-x-xxx-xxxxxxx/providers/Microsoft.Compute/virtualMachines/xxx-x-xxx-xxxxx",
"name": "xxx-x-xxx-xxxxx",
"location": "xxxxxxx",
"zones": [
"1"
],
"plan": {
"name": "xxxxxxx",
"product": "xxxxxxx",
"publisher": "xxxxxxx"
},
"tags": {
"MYID": "xxxxxxx"
}
}
What I miss is information about e.g. VM size (inside SKU).
I tried adding $expand parameter, but it only works for parameters which have
This is only present if requested via the $expand query parameter.
in their description. Examples are: createdTime and changedTime.
I understand that the rest of the parameters should always be returned. But they are not.
Does anyone know what I'm doing wrong?

I believe by default the REST API specification / schema of Resources - List doesn't capture VMsize / SKU. You may leverage Virtual Machines - List All which provides VMsize / SKU in the output format like shown below.
{
"name": "xxxxxxxxxxxx",
"id": "/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/xxxxxxxxxxxxxxxxxxx/providers/Microsoft.Compute/virtualMachines/xxxxxxxxxxxx",
"type": "Microsoft.Compute/virtualMachines",
"location": "xxxxxxxxxxxx",
"tags": {
"xxxxxxxxxxxx": "xxxxxxxxxxxx",
},
"properties": {
"vmId": "xxxxxxxxxxxxxxxxxxxxxxxxx",
"hardwareProfile": {
"vmSize": "xxxxxxxxxxxx"
},
...
...
...
}
}

Related

ARM template for API Connection to Service Bus using Managed Identity

To create an API Connection to Azure Service Bus using Managed Identity I'm using the following template:
"resources": [
{
"type": "MICROSOFT.WEB/CONNECTIONS",
"apiVersion": "2018-07-01-preview",
"name": "[parameters('connections_servicebus_name')]",
"location": "[parameters('connections_servicebus_location')]",
"kind": "V1",
"properties": {
"alternativeParameterValues": {},
"displayName": "[parameters('connections_servicebus_displayname')]",
"api": {
"name": "[parameters('connections_servicebus_name')]",
"displayName": "[parameters('connections_servicebus_displayname')]",
"id": "[concat(subscription().id, '/providers/Microsoft.Web/locations/', parameters('connections_servicebus_location'), '/managedApis/', 'servicebus')]",
"type": "Microsoft.Web/locations/managedApis"
},
"customParameterValues": {},
"parameterValueSet": {
"name": "managedIdentityAuth",
"values": {}
}
}
}
]
that is actually working except for the fact that the 'NamespaceEndpoint' information (like: sb://mySBNS.servicebus.windows.net) is not provided anywhere and so the field appear empty on Azure portal:
After adding it manually, the connection and the LogicApp that is using it, start to work.
What is the json field to provide that information??
You can refer to this question for full details:
"parameterValueSet": {
"name": "managedIdentityAuth",
"values": {
"namespaceEndpoint": {
"value": "sb://<servicebus-namespace-name>.servicebus.windows.net/"
}
}
}

Set Tenant ID on Bot Channels Registration Connection using Arm Template

When using an ARM template to create a new Connection for a bot channels registration I use the following resource as part of Microsoft.BotService/botServices;
{
"type": "Microsoft.BotService/botServices/Connections",
"apiVersion": "2018-07-12",
"name": "[concat(parameters('botName'), '/ActiveDirectory')]",
"dependsOn": [
"[resourceId('Microsoft.BotService/botServices', parameters('botName'))]"
],
"location": "global",
"tags": "[parameters('resourceTags')]",
"properties": {
"clientId": "[parameters('appId')]",
"clientSecret": "[parameters('appSecret')]",
"scopes": "[parameters('scopes')]",
"serviceProviderId": "30dd229c-58e3-4a48-bdfd-91ec48eb906c",
"serviceProviderDisplayName": "Azure Active Directory v2",
"parameters": []
}
}
That gets me all the fields except Token Exchange Url & Tenant ID, which I do need to fill in;
I checked the documentation and could not find anything about this. I tried adding the following parameter to test;
"parameters": [
{
"key": "tenantID",
"value": "customValue"
}
]
That did not do anything, also just guessing here what the key should be..
How can I set these two fields using an Arm template?
The parameters were the way to go. However when using parameters, the clientID & clientSecret also need to be a parameter, as they are not picked up anymore as properties when a parameter is present. Below the resource Json the way it worked for me;
{
"type": "Microsoft.BotService/botServices/Connections",
"apiVersion": "2018-07-12",
"name": "[concat(parameters('botName'), '/ActiveDirectory')]",
"condition": "[equals(parameters('oauthEnabled'), 'True')]",
"dependsOn": [
"[resourceId('Microsoft.BotService/botServices', parameters('botName'))]"
],
"location": "global",
"tags": "[parameters('resourceTags')]",
"properties": {
"serviceProviderId": "30dd229c-58e3-4a48-bdfd-91ec48eb906c",
"serviceProviderDisplayName": "Azure Active Directory v2",
"parameters": [
{
"key": "clientId",
"value": "[parameters('appId')]"
},
{
"key": "clientSecret",
"value": "[parameters('appSecret')]"
},
{
"key": "scopes",
"value": "[parameters('scopes')]"
},
{
"key": "tenantID",
"value": "common"
},
{
"key": "tokenExchangeUrl",
"value": "[concat('api://botid-', parameters('appId'))]"
}
]
}
}

How can I link Azure insights/actionGroups to AutomationRunBook

I'm going around in circles since few days. I would like to link, via ARM Template, my resource "microsoft.insights/actionGroups" to a resource "Microsoft.Automation/automationAccounts/webhooks"
The webhook and the action group are both created via ARM Template. The problem is that when creating the webhook nothing can keep the uri produced by ARM. Then on my resource group the "automationRunbookReceivers" property requests the "serviceUri" parameter which is mandatory. If I refer to my webhook via the resource the uri I get is empty ...
resourceId ('Microsoft.Automation / automationAccounts / webhooks', parameters ('AzureAutomationName'), 'RunBookName')
how could I automate this process?
This is the templates I've used to generate my resources :
{
"name": "[concat(variables('automationAccountName'), '/WebHookName')]",
"type": "Microsoft.Automation/automationAccounts/webhooks",
"apiVersion": "2015-10-31",
"dependsOn": [
"[concat('Microsoft.Automation/automationAccounts/', variables('automationAccountName'), '/runbooks/', 'RunBookName')]"
],
"properties": {
"isEnabled": "true",
"expiryTime": "2026-11-20",
"runbook": {
"name": "RunBookName"
}
}
},
{
"name": "[variables('ActionGroupName')]",
"type": "microsoft.insights/actionGroups",
"apiVersion": "2019-06-01",
"location": "Global",
"tags": {
"displayName": "ActionGroupName"
},
"properties": {
"groupShortName": "[variables('ActionGroupShortName')]",
"enabled": true,
"automationRunbookReceivers": [
{
"name": "MyRunBookReceiver",
"automationAccountId": "[resourceId('microsoft.insights/components', parameters('AzureTelemetryName'))]",
"runbookName": "RunBookName",
"webhookResourceId": "[resourceId('Microsoft.Automation/automationAccounts/webhooks', parameters('AzureAutomationName'), 'WebHookName')]",
"isGlobalRunbook": false,
"serviceUri": "listCallbackURL? resourceId? reference? other? ?????????"
}
]
}
}
I desperately need help!
Thank you!
[reference(resourceId('Microsoft.Automation/automationAccounts/webhooks', parameters('AzureAutomationName'), 'WebHookName'), '2015-10-31')].uri
return empty string
As far as I know, we only can see the url of webhook when we create it. You can use Powershell to create it and you can see url of outputs
#bit is correct - the webhook URI is only retrievable at the time of webhook creation and the property is nulled thereafter. Since you're creating both the actionGroup and the webhook in the same template, though, the deployment happens synchronously and you can refer to the webhook's URI using its .uri property.
The official Microsoft documentation has an example: https://learn.microsoft.com/en-us/azure/automation/automation-webhooks#create-runbook-and-webhook-with-arm-template
Your ARM template could be modified as follows:
{
"name": "[concat(variables('automationAccountName'), '/WebHookName')]",
"type": "Microsoft.Automation/automationAccounts/webhooks",
"apiVersion": "2015-10-31",
"dependsOn": [
"[concat('Microsoft.Automation/automationAccounts/', variables('automationAccountName'), '/runbooks/', 'RunBookName')]"
],
"properties": {
"isEnabled": "true",
"expiryTime": "2026-11-20",
"runbook": {
"name": "RunBookName"
}
}
},
{
"name": "[variables('ActionGroupName')]",
"type": "microsoft.insights/actionGroups",
"apiVersion": "2019-06-01",
"location": "Global",
"tags": {
"displayName": "ActionGroupName"
},
"properties": {
"groupShortName": "[variables('ActionGroupShortName')]",
"enabled": true,
"automationRunbookReceivers": [
{
"name": "MyRunBookReceiver",
"automationAccountId": "[resourceId('microsoft.insights/components', parameters('AzureTelemetryName'))]",
"runbookName": "RunBookName",
"webhookResourceId": "[resourceId('Microsoft.Automation/automationAccounts/webhooks', parameters('AzureAutomationName'), 'WebHookName')]",
"isGlobalRunbook": false,
"serviceUri": "[reference(concat(variables('automationAccountName'), '/WebHookName')).uri]"
}
]
}
}
As an aside, that Microsoft doc uses an "outputs": { } object to emit the webhook URI. That's a really bad idea because the plaintext value of the URI will be recorded in the resource group deployment metadata. If you need to create the webhook and its clients asynchronously, one solution is to store the webhook URI in a Key Vault secret in the template that creates the webhook, and then consume the Key Vault secret value when deploying the webhook client.

Arm Template conditional output parameters

I have an ARM template which conditionally creates a resource:
{
"type": "Microsoft.Storage/storageAccounts",
"sku": {
"name": "Standard_GRS",
"tier": "Standard"
},
"kind": "BlobStorage",
"name": "[variables('storageAccounts_name')]",
"condition": "[equals(parameters('is_Not_Development'), 'True')]",
"apiVersion": "2017-06-01",
"location": "[resourceGroup().location]",
"scale": null,
"properties": {
"accessTier": "Hot"
},
"dependsOn": []
},
In my output parameters I have the following which causes an error if the resource is not created:
"storageAccountConnectionString": {
"type": "string",
"value": "[Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
I have tried this:
"storageAccountConnectionString": {
"type": "string",
"condition": "[equals(parameters('is_Not_Development'), 'True')]",
"value": "[Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
with the condition clause but this is not recognised. How can I make the output parameter conditional?
UPDATE:
I have tried the following:
"storageAccountConnectionString": {
"type": "string",
"value": "[if(equals(parameters('is_Not_Development'),'False'),'null',Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value))]"
},
but it gives me the same error message, it must be evaluating both true and false conditions.
There is a trick to solve this issue and we use it successfully.
Let's see for example how the following template returns a value only if the corresponding resource has been deployed.
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appInsightsLocation": {
"type": "string",
"defaultValue": "",
"allowedValues": [
"",
"northeurope",
"westeurope"
]
}
},
"variables": {
"appInsightsName": "exampleAppInsights",
"planName": "example-plan",
"appInsightsEnabled": "[if(greater(length(parameters('appInsightsLocation')), 0), 'true', 'false')]",
"appInsightsOrPlanResource": "[if(bool(variables('appInsightsEnabled')), concat('Microsoft.Insights/components/', variables('appInsightsName')), concat('Microsoft.Web/serverFarms/', variables('planName')))]",
"appInsightsKeyOrPlanName": "[if(bool(variables('appInsightsEnabled')), 'InstrumentationKey', 'name')]"
},
"resources": [
{
"comments": "The example service plan",
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"name": "[variables('planName')]",
"sku": {
"name": "B1",
"capacity": 1
},
"properties": {
"numberOfWorkers": 1,
"name": "[variables('planName')]"
}
},
{
"comments": "The application insights instance",
"apiVersion": "2014-04-01",
"condition": "[bool(variables('appInsightsEnabled'))]",
"type": "Microsoft.Insights/components",
"location": "[parameters('appInsightsLocation')]",
"name": "[variables('appInsightsName')]",
"properties": {}
}
],
"outputs": {
"appInsightsKey": {
"value": "[if(bool(variables('appInsightsEnabled')), reference(variables('appInsightsOrPlanResource'))[variables('appInsightsKeyOrPlanName')], '')]",
"type": "string"
}
}
The template declares two resources. One app service plan and one Application Insights instance. The AppInsights instance is deployed only if the location parameter is not empty string. So the instrumentation key of this instance is also returned only if it has been created.
To achieve this we also need a resource that is always present. In our case this is the service plan. We use this resource to get the reference when AppInsights is not deployed. This could be any azure resource of course.
The trick happens on the two variables appInsightsOrPlanResource and appInsightsKeyOrPlanName we declare. When appInsightsLocation is provided then those two variables end up referencing the key of the instance which is returned from the output.
When appInsightsLocation is not provided on the other hand those two variables contain a valid reference to the service plan that is not used but it's valid. We need to do this one because if function evaluates always both sides. An empty string is returned from the output in this case though.
I know this is an old question, but in case anyone arrives here, it looks like MSFT has fixed this in two ways now.
In Feb 2019 they fixed the 'if' evaluation to only evaluate the true side.
https://feedback.azure.com/forums/281804-azure-resource-manager/suggestions/31538470-arm-template-if-function-should-not-evaluate-both
In August 2019 they added support for condition: in the outputs.
https://feedback.azure.com/forums/281804-azure-resource-manager/suggestions/19492006-conditional-output-from-arm-template
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authoring-templates#outputs
Looks like as long as you're at Azure CLI version 2.0.72 you'll have access to these changes. I just tested both on 2.0.76 and they appear to work.

Generate or Specify Azure Service Bus Namespace SAS Token with ARM Template

I'm using Azure ARM templates in order to make sure that I can repeatedly deploy uniform infrastructure and services. My ARM template consists of an App Service, Web App, Service Bus Queue, and Azure SQL database. On top of this, I'm setting up continuous deployment through VSTS.
Everything is working well EXCEPT I am not sure how to set a Service Bus SAS token at the Namespace level. I don't see a way in the Service Bus ARM template to specify one, so I cannot pre-generate a token and place it in my web.config file. I also don't see a way to have one generated on my behalf, then pull the values back to my web.config file. Any suggestions would be greatly appreciated.
I believe you have two options:
1) Get generated key from the output:
"outputs": {
"eh:Endpoint": {
"value": "[listKeys(resourceId('Microsoft.EventHub/namespaces/authorizationRules', variables('eventHubNamespaceName'), 'SendOnlyKey'),'2015-08-01').primaryKey]",
"type": "string"
},
}
And incorporate it in your build/release process.
2) Try to push a key with a template:
{
"apiVersion": "[parameters('eventHubVersion')]",
"name": "[variables('eventHubNamespaceName')]",
"type": "Microsoft.EventHub/namespaces",
"location": "[resourceGroup().location]",
"resources": [
{
"apiVersion": "2014-09-01",
"name": "[variables('eventHubName')]",
"type": "eventHubs",
"dependsOn": [
"[concat('Microsoft.EventHub/namespaces/', variables('eventHubNamespaceName'))]"
],
"properties": {
"path": "[variables('eventHubName')]",
"MessageRetentionInDays": "[parameters('messageRetentionInDays')]",
"PartitionCount": "[parameters('partitionCount')]"
},
"resources": [
{
"apiVersion": "[parameters('eventHubVersion')]",
"name": "StorageRetention",
"type": "consumergroups",
"dependsOn": [
"[variables('eventHubName')]",
"[concat('Microsoft.EventHub/namespaces/', variables('eventHubNamespaceName'))]"
],
"tags": {
"displayName": "eh"
}
}
]
},
{
"apiVersion": "[parameters('eventHubVersion')]",
"name": "[concat(variables('eventHubNamespaceName'),'/SendOnlyKey')]",
"type": "Microsoft.EventHub/namespaces/authorizationRules",
"dependsOn": [
"[concat('Microsoft.EventHub/namespaces/', variables('eventHubNamespaceName'))]"
],
"location": "[resourceGroup().location]",
"properties": {
"KeyName": "SendOnlyKey",
"ClaimType": "SendSharedAccessKey",
"ClaimValue": "None",
"PrimaryKey": "[parameters('eventHubSendPrimaryKey')]",
"SecondaryKey": "your_key",
"Rights": [ "Send" ],
"Revision": -1
}
},
{
"apiVersion": "[parameters('eventHubVersion')]",
"name": "[concat(variables('eventHubNamespaceName'),'/ListenOnlyKey')]",
"type": "Microsoft.EventHub/namespaces/authorizationRules",
"dependsOn": [
"[concat('Microsoft.EventHub/namespaces/', variables('eventHubNamespaceName'))]"
],
"location": "[resourceGroup().location]",
"properties": {
"KeyName": "ListenOnlyKey",
"ClaimType": "ReceiveSharedAccessKey",
"ClaimValue": "None",
"PrimaryKey": "your_key",
"SecondaryKey": "your_key",
"Rights": [ "Listen" ],
"Revision": -1
}
}
]
}
However note that the second solutions works only for an older version of API and sooner or later will be deprecated. Additionally I tested it only for pushing keys for a hub, not a namespace.
This might help others arriving at this answer
In EastUS using API_VERSION = 2017-04-01
The following will work to obtain references to primarykey and related fields
- connectionString: "[concat('',listKeys(resourceId('Microsoft.EventHub/namespaces/eventhubs/authorizationRules','{{ eh_namespace }}', '{{ eventhub_name }}','fw'), '2017-04-01').primaryConnectionString,'')]"

Resources