I'm working on an Azure Logic App which is triggered everytime a JSON-file is added to a BLOB-storage. The JSON-file contains a CustomerId and based on this Id I want to sent the contents of the JSON-file to a different endpoint using an HTTP-request.
My Azure Logic App currently looks like this;
I've been researching and trying a lot of things for the entire morning, but I can't get my head around this. I've tried things like;
json(body('Get_blob_content_using_path'))
and
decodeBase64(body('Get_blob_content_using_path'))
and just the default option like visible in the screenshot. But I can't figure out how to do this. All I want is go left or right based on the CustomerId.
So for clarity. The problem lies within the condition-step of the Logic App. I can retrieve the BLOB-file from the storage, but the issue is with parsing the CustomerId from the JSON so I can validate it within the condition. Does anybody has an idea on how I can fix this?
In the end I was able to solve the issue by adding a compose step before the condition and after the steps which will get me the content of the BLOB-file. The compose get's the content of the blob-file which I then can validate against the CustomerId I want. This topic got me in the right direction for my solution.
UPDATE:
The final logic app looks like this;
Which is begin created with the following logic app code;
{
"$connections": {
"value": {
"azureblob": {
"connectionId": "<snip>",
"connectionName": "azureblob",
"id": "<snip>"
},
"slack": {
"connectionId": "<snip>",
"connectionName": "slack",
"id": "<snip>"
}
}
},
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Compose": {
"inputs": "#base64ToString(body('Get_blob_content').$content)",
"runAfter": {
"Get_blob_content": [
"Succeeded"
]
},
"type": "Compose"
},
"Condition_2": {
"actions": {
"Condition_3": {
"actions": {
"Delete_blob_3": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "delete",
"path": "/datasets/default/files/#{encodeURIComponent(encodeURIComponent(triggerBody()?['Id']))}"
},
"runAfter": {},
"type": "ApiConnection"
}
},
"else": {
"actions": {
"Copy_blob_2": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "post",
"path": "/datasets/default/copyFile",
"queries": {
"destination": "/<some-blob-container>/#{triggerBody()?['Name']}",
"overwrite": false,
"queryParametersSingleEncoded": true,
"source": "#triggerBody()?['Path']"
}
},
"runAfter": {
"Post_message_2": [
"Succeeded"
]
},
"type": "ApiConnection"
},
"Delete_blob_4": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "delete",
"path": "/datasets/default/files/#{encodeURIComponent(encodeURIComponent(triggerBody()?['Id']))}"
},
"runAfter": {
"Copy_blob_2": [
"Succeeded"
]
},
"type": "ApiConnection"
},
"Post_message_2": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['slack']['connectionId']"
}
},
"method": "post",
"path": "/chat.postMessage",
"queries": {
"channel": "<snip>",
"text": "<some-message>"
}
},
"runAfter": {},
"type": "ApiConnection"
}
}
},
"expression": {
"or": [
{
"equals": [
"#outputs('HTTP_2')['statusCode']",
200
]
},
{
"equals": [
"#outputs('HTTP_2')['statusCode']",
202
]
}
]
},
"runAfter": {
"HTTP_2": [
"Succeeded",
"Failed"
]
},
"type": "If"
},
"HTTP_2": {
"inputs": {
"authentication": {
"password": "<some-password>",
"type": "Basic",
"username": "<some-username>"
},
"body": "#outputs('Compose')",
"headers": {
"Content-Type": "application/json"
},
"method": "POST",
"uri": "<some-url>"
},
"runAfter": {},
"type": "Http"
}
},
"else": {
"actions": {
"Condition_4": {
"actions": {
"Delete_blob_5": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "delete",
"path": "/datasets/default/files/#{encodeURIComponent(encodeURIComponent(triggerBody()?['Id']))}"
},
"runAfter": {},
"type": "ApiConnection"
}
},
"else": {
"actions": {
"Copy_blob_3": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "post",
"path": "/datasets/default/copyFile",
"queries": {
"destination": "/<some-blob-container>/#{triggerBody()?['Name']}",
"overwrite": false,
"queryParametersSingleEncoded": true,
"source": "#triggerBody()?['Path']"
}
},
"runAfter": {
"Post_message_3": [
"Succeeded"
]
},
"type": "ApiConnection"
},
"Delete_blob_6": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "delete",
"path": "/datasets/default/files/#{encodeURIComponent(encodeURIComponent(triggerBody()?['Id']))}"
},
"runAfter": {
"Copy_blob_3": [
"Succeeded"
]
},
"type": "ApiConnection"
},
"Post_message_3": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['slack']['connectionId']"
}
},
"method": "post",
"path": "/chat.postMessage",
"queries": {
"channel": "<snip>",
"text": "<some-message>"
}
},
"runAfter": {},
"type": "ApiConnection"
}
}
},
"expression": {
"or": [
{
"equals": [
"#outputs('HTTP_3')['statusCode']",
200
]
},
{
"equals": [
"#outputs('HTTP_3')['statusCode']",
202
]
}
]
},
"runAfter": {
"HTTP_3": [
"Succeeded"
]
},
"type": "If"
},
"HTTP_3": {
"inputs": {
"authentication": {
"password": "<some-password>",
"type": "Basic",
"username": "<some-username>"
},
"body": "#outputs('Compose')",
"headers": {
"Content-Type": "application/json"
},
"method": "POST",
"uri": "<some-url>"
},
"runAfter": {},
"type": "Http"
}
}
},
"expression": {
"and": [
{
"contains": [
"#outputs('Compose')",
"\"CustomerId\":\"00000000-0000-0000-0000-000000000000\""
]
}
]
},
"runAfter": {
"Compose": [
"Succeeded"
]
},
"type": "If"
},
"Get_blob_content": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/datasets/default/files/#{encodeURIComponent(encodeURIComponent(triggerBody()?['Path']))}/content",
"queries": {
"inferContentType": true
}
},
"runAfter": {},
"type": "ApiConnection"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"When_a_blob_is_added_or_modified_(properties_only)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/datasets/default/triggers/batch/onupdatedfile",
"queries": {
"folderId": "<some-generated-folderid>",
"maxFileCount": 100
}
},
"metadata": {
"<some-generated-folderid>": "/<some-blob-container>"
},
"recurrence": {
"frequency": "Minute",
"interval": 1
},
"splitOn": "#triggerBody()",
"type": "ApiConnection"
}
}
}
}
Related
I have a logic app that I want to run once a line item appears in a table each day. once that line item appear, i don't want the logic app to run anymore that day. Can't quite think of how to accomplish this.
Apart from using the related triggers you can use Terminate action to stop the flow.
After using Get entities (V2) I'm trying to Parse the result to get the timestamp of that particular entity to check if the table has an added row or not for that day
After parsing below is the condition that I'm using
{
"contains": [
"#formatDateTime(body('Parse_JSON')?[0]?['Timestamp'],'dd-MM-yyyy')",
"#formatDateTime(utcNow(),'dd-MM-yyyy')"]
}
Below is the complete flow of my Logic App
RESULTS:
To reproduce the same in your Logic App you can use the below code view
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Condition": {
"actions": {
"Terminate": {
"inputs": {
"runStatus": "Succeeded"
},
"runAfter": {},
"type": "Terminate"
}
},
"else": {
"actions": {
"Delay": {
"inputs": {
"interval": {
"count": 2,
"unit": "Hour"
}
},
"runAfter": {},
"type": "wait"
},
"HTTP": {
"inputs": {
"method": "POST",
"uri": "<URI>"
},
"runAfter": {
"Delay": [
"Succeeded"
]
},
"type": "Http"
}
}
},
"expression": {
"and": [
{
"contains": [
"#formatDateTime(body('Parse_JSON')?[0]?['Timestamp'],'dd-MM-yyyy')",
"#formatDateTime(utcNow(),'dd-MM-yyyy')"
]
}
]
},
"runAfter": {
"Parse_JSON": [
"Succeeded"
]
},
"type": "If"
},
"Get_entities_(V2)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azuretables']['connectionId']"
}
},
"method": "get",
"path": "/v2/storageAccounts/#{encodeURIComponent(encodeURIComponent('AccountNameFromSettings'))}/tables/#{encodeURIComponent('<TableName>')}/entities"
},
"runAfter": {},
"type": "ApiConnection"
},
"Parse_JSON": {
"inputs": {
"content": "#body('Get_entities_(V2)')?['value']",
"schema": {
"items": {
"properties": {
"FirstName": {
"type": "string"
},
"LastName": {
"type": "string"
},
"PartitionKey": {
"type": "string"
},
"RowKey": {
"type": "string"
},
"Timestamp": {
"type": "string"
},
"odata.etag": {
"type": "string"
}
},
"required": [
"odata.etag",
"PartitionKey",
"RowKey",
"Timestamp",
"FirstName",
"LastName"
],
"type": "object"
},
"type": "array"
}
},
"runAfter": {
"Get_entities_(V2)": [
"Succeeded"
]
},
"type": "ParseJson"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"manual": {
"inputs": {
"schema": {}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {
"$connections": {
"value": {
"azuretables": {
"connectionId": "/subscriptions/<SUB_ID>/resourceGroups/<RG>/providers/Microsoft.Web/connections/azuretables",
"connectionName": "azuretables",
"id": "/subscriptions/<SUB_ID>/providers/Microsoft.Web/locations/centralus/managedApis/azuretables"
}
}
}
}
}
Alternatively, you can use Recurrence trigger to trigger it in regular intervals with the same logic.
What I am trying to accomplish:
I am trying to do a HTTP GET request from Azure Logic Apps from https://endpoints.office.com/endpoints/Worldwide?ClientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7 where they provide public facing list of IP addresses for Office365.
I would like to only pull out the IPv4 list of addresses into a legible format and then store this into my Blob storage in Azure as a CSV file.
Then what I want is that the list of IPv4 addresses to be pulled into an IP-GROUP in Azure so that any changes of IP addresses from Microsoft would be dynamically updated via Logic Apps and stored into Blob Storage and then updated in the IP-Group.
The IP-Group is used in an Azure Firewall.
What I have Tried [logic app in code]:
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Create_blob_(V2)": {
"inputs": {
"body": "#triggerBody()",
"headers": {
"ReadFileMetadataFromServer": true
},
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "post",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('AccountNameFromSettings'))}/files",
"queries": {
"folderPath": "/project-a",
"name": "office365-test.csv",
"queryParametersSingleEncoded": true
}
},
"runAfter": {
"Create_job": [
"Succeeded"
]
},
"runtimeConfiguration": {
"contentTransfer": {
"transferMode": "Chunked"
}
},
"type": "ApiConnection"
},
"Create_job": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureautomation']['connectionId']"
}
},
"method": "put",
"path": "/subscriptions/#{encodeURIComponent('xxxxxxxxxxxxxxxxxxxxxxxxx')}/resourceGroups/#{encodeURIComponent('xxxxxxx')}/providers/Microsoft.Automation/automationAccounts/#{encodeURIComponent('test')}/jobs",
"queries": {
"runbookName": "test-hello",
"wait": false,
"x-ms-api-version": "2015-10-31"
}
},
"runAfter": {},
"type": "ApiConnection"
},
"Get_blob_content_using_path_(V2)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('AccountNameFromSettings'))}/GetFileContentByPath",
"queries": {
"inferContentType": true,
"path": "/project-a/office365-test.csv",
"queryParametersSingleEncoded": true
}
},
"runAfter": {
"Create_blob_(V2)": [
"Succeeded"
]
},
"type": "ApiConnection"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"HTTP": {
"evaluatedRecurrence": {
"frequency": "Day",
"interval": 1
},
"inputs": {
"method": "GET",
"uri": "https://endpoints.office.com/endpoints/Worldwide?ClientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7"
},
"recurrence": {
"frequency": "Day",
"interval": 1
},
"type": "Http"
}
}
},
"parameters": {
"$connections": {
"value": {
"azureautomation": {
"connectionId": "/subscriptions/xxxxxx/resourceGroups/xxx/providers/Microsoft.Web/connections/azureautomation",
"connectionName": "azureautomation",
"id": "/subscriptions/xxxxxx/providers/Microsoft.Web/locations/uksouth/managedApis/azureautomation"
},
"azureblob": {
"connectionId": "/subscriptions/xxxxxx/resourceGroups/xxx/providers/Microsoft.Web/connections/azureblob",
"connectionName": "azureblob",
"id": "/subscriptions/xxxxxx/providers/Microsoft.Web/locations/uksouth/managedApis/azureblob"
}
}
}
}
}
This pulls the whole lot of data from Microsoft Website and bundles it into blob storage in a messy format. I only need the IPv4 addresses in a clear format for CSV.
Then I would like that CSV to be used to update an existing IP-GROUP. Any suggestions?
I need to send the blobs uploaded to my Azure storage container as an attachments. Number of files getting uploaded to container will change so I need to use dynamic method for attachment.
I have verified this question related to it
I am using below logic:
Append to variable values
{
"Name": items('For_each')?['DisplayName']
"ContentBytes":body('Get_blob_content')
}
When I am trying to save the logic, getting below error:
Save logic app failed
Failed to save logic app testing. The template validation failed: 'The action(s) 'Get_blob_content' referenced by 'inputs' in action 'Append_to_array_variable' are not defined in the template.'.
How can I solve this ?
Based on the error message shared above, Instead of saving the entire workflow at once would suggest you to save the logic app at each stage or before the appendtoarray variable stage & post then append the values to attachment variable with previous stage outputs.
Based on the above requirement, we have created the below logic app in our local environment &tested it as well which is working fine.
In our workflow, We have Used For Each to loop the blobs from List Blobs action. Within For Each you can use Get blob content to get blob content, and then use Append to array variable to append attachments.
The expressions Name and ContentBytes are as follows:
"ContentBytes": "#base64(body('Get_blob_content_(V2)'))",
"Name": "#items('For_each')?['DisplayName']"
Here is the code view of the Logic app that we have created :
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"For_each": {
"actions": {
"Append_to_array_variable": {
"inputs": {
"name": "attachments",
"value": {
"ContentBytes": "#base64(body('Get_blob_content_(V2)'))",
"Name": "#items('For_each')?['DisplayName']"
}
},
"runAfter": {
"Get_blob_content_(V2)": [
"Succeeded"
]
},
"type": "AppendToArrayVariable"
},
"Get_blob_content_(V2)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('AccountNameFromSettings'))}/files/#{encodeURIComponent(encodeURIComponent(items('For_each')?['Path']))}/content",
"queries": {
"inferContentType": true
}
},
"runAfter": {},
"type": "ApiConnection"
}
},
"foreach": "#body('Lists_blobs_(V2)')?['value']",
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "Foreach"
},
"Initialize_variable": {
"inputs": {
"variables": [
{
"name": "attachments",
"type": "array"
}
]
},
"runAfter": {
"Lists_blobs_(V2)": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Lists_blobs_(V2)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('AccountNameFromSettings'))}/foldersV2/#{encodeURIComponent(encodeURIComponent('JTJmcmVwb3J0cw=='))}",
"queries": {
"nextPageMarker": "",
"useFlatListing": false
}
},
"metadata": {
"JTJmcmVwb3J0cw==": "/reports"
},
"runAfter": {},
"type": "ApiConnection"
},
"Send_an_email_(V2)": {
"inputs": {
"body": {
"Attachments": "#variables('attachments')",
"Body": "<p>tested logic app flow successfully</p>",
"Subject": "blob test",
"To": "<username>#microsoft.com"
},
"host": {
"connection": {
"name": "#parameters('$connections')['office365']['connectionId']"
}
},
"method": "post",
"path": "/v2/Mail"
},
"runAfter": {
"For_each": [
"Succeeded"
]
},
"type": "ApiConnection"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"When_a_blob_is_added_or_modified_(properties_only)_(V2)": {
"evaluatedRecurrence": {
"frequency": "Minute",
"interval": 1
},
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('AccountNameFromSettings'))}/triggers/batch/onupdatedfile",
"queries": {
"checkBothCreatedAndModifiedDateTime": false,
"folderId": "JTJmcmVwb3J0cw==",
"maxFileCount": 10
}
},
"metadata": {
"JTJmcmVwb3J0cw==": "/reports"
},
"recurrence": {
"frequency": "Minute",
"interval": 1
},
"splitOn": "#triggerBody()",
"type": "ApiConnection"
}
}
},
"parameters": {
"$connections": {
"value": {
"azureblob": {
"connectionId": "/subscriptions/<sub-ID>/resourceGroups/<resourceGroup>/providers/Microsoft.Web/connections/azureblob",
"connectionName": "azureblob",
"id": "/subscriptions/<sub-id>/providers/Microsoft.Web/locations/eastus/managedApis/azureblob"
},
"office365": {
"connectionId": "/subscriptions/<sub-id>/resourceGroups/<resroucegroup>/providers/Microsoft.Web/connections/office365",
"connectionName": "office365",
"id": "/subscriptions/<sub-id>/providers/Microsoft.Web/locations/eastus/managedApis/office365"
}
}
}
}
}
Here is the sample Output for reference:
We have Azure storage container with subfolders created dynamically, we want to monitor the creation of blob under this container/subfolders and trigger an email once per day with all the blobs added for the day as an attachment in the email.
What we tried is to create a Logic app with Event Grid Trigger (When a resource event occurs) like below.
we would like to know if there is way we can collect all the blobs added in a day under the container and get the contents of all those blobs and add it as an attachment and trigger an email at scheduled time once per day.
Any suggestion on
how to get all the blobs under a container, sub-folder and store the blobs metadata created as an array?
And then how to attach all the blobs created in a single email?
How to get the blob name after, "When a resource event occurs" trigger?
Based on the above requirements, we have created a logic app using timer to list & get the content of all the blob that were created on a particular day & will send an email with the content of the blob as an attachment. using the below work flow code you make the changes as per your business requirement.
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Attach": {
"inputs": {
"variables": [
{
"name": "Arraytoattach",
"type": "array"
}
]
},
"runAfter": {
"Lists_blobs_(V2)": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Blob_Name": {
"inputs": {
"variables": [
{
"name": "Count",
"type": "integer",
"value": "#length(variables('Arraytoattach'))"
}
]
},
"runAfter": {
"For_each": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"For_each": {
"actions": {
"Compose_2": {
"inputs": "#items('For_each')?['LastModified']",
"runAfter": {},
"type": "Compose"
},
"Compose_3": {
"inputs": "#formatDateTime(outputs('Compose_2'),'yyyy-MM-dd')",
"runAfter": {
"Compose_2": [
"Succeeded"
]
},
"type": "Compose"
},
"Condition": {
"actions": {
"Append_to_array_variable": {
"inputs": {
"name": "Arraytoattach",
"value": {
"ContentBytes": "#body('Get_blob_content_(V2)_2')?['$content']",
"Name": "#items('For_each')?['Name']"
}
},
"runAfter": {
"Get_blob_content_(V2)_2": [
"Succeeded"
]
},
"type": "AppendToArrayVariable"
},
"Get_blob_content_(V2)_2": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('stacklogictest'))}/files/#{encodeURIComponent(encodeURIComponent(items('For_each')?['Path']))}/content",
"queries": {
"inferContentType": true
}
},
"runAfter": {},
"type": "ApiConnection"
}
},
"expression": {
"and": [
{
"equals": [
"#outputs('Compose_3')",
"#formatDateTime(utcNow(),'yyyy-MM-dd')"
]
}
]
},
"runAfter": {
"Compose_3": [
"Succeeded"
]
},
"type": "If"
}
},
"foreach": "#body('Lists_blobs_(V2)')?['value']",
"runAfter": {
"Attach": [
"Succeeded"
]
},
"type": "Foreach"
},
"Lists_blobs_(V2)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('stacklogictest'))}/foldersV2/#{encodeURIComponent(encodeURIComponent('JTJmdGVzdDEyMw=='))}",
"queries": {
"nextPageMarker": "",
"useFlatListing": false
}
},
"metadata": {
"JTJmdGVzdDEyMw==": "/test123"
},
"runAfter": {},
"type": "ApiConnection"
},
"Send_an_email_(V2)": {
"inputs": {
"body": {
"Attachments": "#variables('Arraytoattach')",
"Body": "<p>Total Number of blob created today : #{variables('Count')}</p>",
"Subject": "Blob created Today",
"To": "<**ReciepientMailAddress**>"
},
"host": {
"connection": {
"name": "#parameters('$connections')['office365']['connectionId']"
}
},
"method": "post",
"path": "/v2/Mail"
},
"runAfter": {
"Blob_Name": [
"Succeeded"
]
},
"type": "ApiConnection"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"Recurrence": {
"recurrence": {
"frequency": "Day",
"interval": 1,
"startTime": "2021-07-15T04:00:00Z"
},
"type": "Recurrence"
}
}
},
"parameters": {
"$connections": {
"value": {
"azureblob": {
"connectionId": "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroups>/providers/Microsoft.Web/connections/azureblob",
"connectionName": "azureblob",
"id": "/subscriptions/<subscriptionId>/providers/Microsoft.Web/locations/southindia/managedApis/azureblob"
},
"office365": {
"connectionId": "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroups>/providers/Microsoft.Web/connections/office365",
"connectionName": "office365",
"id": "/subscriptions/<subscriptionId>/providers/Microsoft.Web/locations/southindia/managedApis/office365"
}
}
}
}
}
how to get all the blobs under a container, sub-folder and store the blobs metadata created as an array?
Ans: Using the Event Grid you can add all the blob under a particular container to a single array because event grid triggers the logic app when a new blob is added.
And then how to attach all the blobs created in a single email?
Ans: Due to outlook restrictions, we cannot sent or attach the data which excceds more than 25 MB.
3.How to get the blob name after, "When a resource event occurs" trigger?
Ans : As shown in the below image initialize a string variable and add it to the next of event grid event and add the below experssion to get the blob name from the event grid output
first(split(last(split(string(triggerBody()),'/blobs/')),'","event'))
The above logic app will fail if the content type of the blob is text you need make the changes accordingly based on requirement.
Here is the sample output of the above logic app
Created a logic app to send email with attachment of all the blobs inside a container that were added a day before the current day.
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Current_time": {
"inputs": {},
"kind": "CurrentTime",
"runAfter": {
"Lists_blobs_(V2)": [
"Succeeded"
]
},
"type": "Expression"
},
"For_each": {
"actions": {
"For_each_2": {
"actions": {
"Condition": {
"actions": {
"Append_to_array_variable": {
"inputs": {
"name": "attachements",
"value": "#outputs('Compose')"
},
"runAfter": {
"Compose": [
"Succeeded"
]
},
"type": "AppendToArrayVariable"
},
"Compose": {
"inputs": {
"ContentBytes": "#{base64(body('Get_Blob'))}",
"Name": "#{last(split(items('For_each_2')?['Path'],'/'))}"
},
"runAfter": {
"Get_Blob": [
"Succeeded"
]
},
"type": "Compose"
},
"Get_Blob": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('<StorageAccountName/connection>'))}/files/#{encodeURIComponent(encodeURIComponent(items('For_each_2')?['Path']))}/content",
"queries": {
"inferContentType": true
}
},
"runAfter": {},
"type": "ApiConnection"
}
},
"expression": {
"and": [
{
"greater": [
"#items('For_each_2')?['LastModified']",
"#addDays(body('Current_time'),-1)"
]
}
]
},
"runAfter": {},
"type": "If"
}
},
"foreach": "#body('Lists_blobs_(V2)_3')?['value']",
"runAfter": {
"Lists_blobs_(V2)_3": [
"Succeeded"
]
},
"type": "Foreach"
},
"Lists_blobs_(V2)_3": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('<storageaccount connection>'))}/foldersV2/#{encodeURIComponent(encodeURIComponent(items('For_each')?['Path']))}",
"queries": {
"nextPageMarker": "",
"useFlatListing": false
}
},
"runAfter": {},
"type": "ApiConnection"
}
},
"foreach": "#body('Lists_blobs_(V2)')?['value']",
"runAfter": {
"Current_time": [
"Succeeded"
]
},
"type": "Foreach"
},
"Initialize_variable": {
"inputs": {
"variables": [
{
"name": "attachements",
"type": "array"
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Lists_blobs_(V2)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('<storageaccount connection>'))}/foldersV2/#{encodeURIComponent(encodeURIComponent('JTJmY2FyYm9uYmxh='))}",
"queries": {
"nextPageMarker": "",
"useFlatListing": false
}
},
"metadata": {
"JTJmY2FyYm9uYmxh=": "/<containerName>"
},
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "ApiConnection"
},
"Send_an_email_(V2)_3": {
"inputs": {
"body": {
"Attachments": "#variables('attachements')",
"Body": "<p>body</p>",
"Subject": "Subject",
"To": "Email"
},
"host": {
"connection": {
"name": "#parameters('$connections')['office365']['connectionId']"
}
},
"method": "post",
"path": "/v2/Mail"
},
"runAfter": {
"For_each": [
"Succeeded",
"Failed",
"Skipped",
"TimedOut"
]
},
"type": "ApiConnection"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"Recurrence": {
"recurrence": {
"frequency": "Day",
"interval": 1,
"schedule": {
"hours": [
"9"
],
"minutes": [
0
]
},
"timeZone": "Standard Time"
},
"type": "Recurrence"
}
}
},
"parameters": {
"$connections": {
"value": {
"azureblob": {
"connectionId": "/subscriptions/<subscriptionId>/resourceGroups/<ResourceGroup>/providers/Microsoft.Web/connections/azureblob",
"connectionName": "azureblob",
"id": "/subscriptions/<subscriptionId>/providers/Microsoft.Web/locations/<location>/managedApis/azureblob"
},
"office365": {
"connectionId": "/subscriptions/<subscriptionId>/resourceGroups/<ResourceGroup>/providers/Microsoft.Web/connections/office365-1",
"connectionName": "office365",
"id": "/subscriptions/subscriptionId>/providers/Microsoft.Web/locations/<location>/managedApis/office365"
}
}
}
}
}
I am surprised to see this, but I witness that in some instance the string value aren't converting as expected to float; mostly returns zero.
The following image shows what happens. As you see I have 2 variables namely var_MarginStr of type string and var_MarginValues of type float in my Logic App. I am assigning var_MarginVal as follows:
var_MarginVal = float(string(variables('var_MarginStr')))
In my working where I trigger my logic app after a new blob is inserted into a blob storage account. The content(*.csv) of the blob is passed to an Azure Function which returns a JSON object. The JSON object is then being looped over each item and is sent to my DB via a Stored Proc.
I have checked my Azure Function which converts the content to JSON working perfectly and the response from such is:
{
"fileName": "20200307-PLC-JKB-Margin.csv",
"agentName": "PLC",
"noOfRecords": 5,
"data": [
{
"accountId": "JKB1234LC",
"marginValue": "0.00"
},
{
"accountId": "JKB4321LC",
"marginValue": "1200000.00"
},
{
"accountId": "JKB5678LC",
"marginValue": "6000000.00"
},
{
"accountId": "JKB8765LC",
"marginValue": "4000000.00"
},
{
"accountId": "JKB9123LC",
"marginValue": "0.00"
}
]
}
Here is my entire LogicApp:
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"CSVTOJSON": {
"inputs": {
"body": "#body('Get_blob_content')",
"function": {
"id": "/subscriptions/xxxx/resourceGroups/xxxx-PRD-PORTAL-01/providers/Microsoft.Web/sites/jksbmarginrequest/functions/CSVTOJSON"
},
"method": "POST",
"queries": {
"fileName": "#triggerBody()?['Name']"
}
},
"runAfter": {
"[Initialize]_For_Composed_AccountId": [
"Succeeded"
]
},
"type": "Function"
},
"Condition": {
"actions": {
"Apply_to_DB": {
"actions": {
"Execute_stored_procedure_(V2)": {
"inputs": {
"body": {
"pActualAccountId": "#{items('Apply_to_DB')?['accountId']}#{variables('var_ComposeAccountIdSuffix')}",
"pAgentId": "#variables('var_AgentName')",
"pEffectiveDate": "#{formatDateTime(utcNow(),'yyyy-MM-dd')}",
"pMarginVal": "#variables('var_MarginVal')"
},
"host": {
"connection": {
"name": "#parameters('$connections')['sql']['connectionId']"
}
},
"method": "post",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('default'))},#{encodeURIComponent(encodeURIComponent('default'))}/procedures/#{encodeURIComponent(encodeURIComponent('[dbo].[usp_MarginAddUpdate]'))}"
},
"runAfter": {
"[Set]_Margin_Value_Float": [
"Succeeded"
]
},
"type": "ApiConnection"
},
"[Set]_Margin_Value_Float": {
"inputs": {
"name": "var_MarginVal",
"value": "#float(string(variables('var_MarginStr')))"
},
"runAfter": {
"[Set]_Margin_Value_String": [
"Succeeded"
]
},
"type": "SetVariable"
},
"[Set]_Margin_Value_String": {
"inputs": {
"name": "var_MarginStr",
"value": "#items('Apply_to_DB')?['marginValue']"
},
"runAfter": {},
"type": "SetVariable"
}
},
"foreach": "#body('Parse_JSON')?['data']",
"runAfter": {
"For_each": [
"Succeeded"
]
},
"type": "Foreach"
},
"Create_HTML_table": {
"inputs": {
"format": "HTML",
"from": "#body('Parse_JSON')?['data']"
},
"runAfter": {
"Apply_to_DB": [
"Succeeded"
]
},
"type": "Table"
},
"Execute_a_SQL_query_(V2)": {
"inputs": {
"body": {
"actualParameters": {
"pAgentId": "#variables('var_AgentName')"
},
"formalParameters": {
"pAgentId": "VARCHAR(10)"
},
"query": "select * from [dbo].[Parser_MarginFileSettings]\nWhere AgentId =#pAgentId"
},
"host": {
"connection": {
"name": "#parameters('$connections')['sql']['connectionId']"
}
},
"method": "post",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('default'))},#{encodeURIComponent(encodeURIComponent('default'))}/query/sql"
},
"runAfter": {
"[Set]_Agent_Name": [
"Succeeded"
]
},
"type": "ApiConnection"
},
"For_each": {
"actions": {
"[Set]_Composed_Account_ID_with_Suffix": {
"inputs": {
"name": "var_ComposeAccountIdSuffix",
"value": "#items('For_each')?['Suffix_AccountId']"
},
"runAfter": {},
"type": "SetVariable"
}
},
"foreach": "#body('Execute_a_SQL_query_(V2)')?['resultsets']?['Table1']",
"runAfter": {
"Execute_a_SQL_query_(V2)": [
"Succeeded"
]
},
"type": "Foreach"
},
"Parse_JSON": {
"inputs": {
"content": "#body('CSVTOJSON')",
"schema": {
"properties": {
"agentName": {
"type": "string"
},
"data": {
"items": {
"properties": {
"accountId": {
"type": "string"
},
"marginValue": {
"type": "string"
}
},
"required": [
"accountId",
"marginValue"
],
"type": "object"
},
"type": "array"
},
"fileName": {
"type": "string"
},
"noOfRecords": {
"type": "integer"
}
},
"type": "object"
}
},
"runAfter": {},
"type": "ParseJson"
},
"[Set]_Agent_Name": {
"inputs": {
"name": "var_AgentName",
"value": "#body('Parse_JSON')?['agentName']"
},
"runAfter": {
"Parse_JSON": [
"Succeeded"
]
},
"type": "SetVariable"
}
},
"else": {
"actions": {
"Compose_Fail-over_Data": {
"inputs": {
"File_Name": "#triggerBody()?['Name']",
"Message": "#body('CSVTOJSON')",
"Status_Code": "#outputs('CSVTOJSON')['statusCode']"
},
"runAfter": {},
"type": "Compose"
},
"For_Error_Listing": {
"inputs": {
"format": "HTML",
"from": "#outputs('Compose_Fail-over_Data')"
},
"runAfter": {
"Compose_Fail-over_Data": [
"Succeeded"
]
},
"type": "Table"
},
"Send_an_email_(V2)": {
"inputs": {
"body": {
"Body": "<p><u><strong>An Error Occured While Updating Margin Request File<br>\n<br>\n</strong></u><u><strong>#{outputs('Compose_Fail-over_Data')}</strong></u><u><strong></strong></u><br>\n</p>",
"Subject": "Margin File Output",
"To": "itops#jkstock.keells.com"
},
"host": {
"connection": {
"name": "#parameters('$connections')['office365']['connectionId']"
}
},
"method": "post",
"path": "/v2/Mail"
},
"runAfter": {
"For_Error_Listing": [
"Succeeded"
]
},
"type": "ApiConnection"
}
}
},
"expression": {
"and": [
{
"equals": [
"#outputs('CSVTOJSON')['statusCode']",
200
]
}
]
},
"runAfter": {
"CSVTOJSON": [
"Succeeded"
]
},
"type": "If"
},
"Get_blob_content": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/datasets/default/files/#{encodeURIComponent(encodeURIComponent(triggerBody()?['Path']))}/content",
"queries": {
"inferContentType": true
}
},
"runAfter": {},
"runtimeConfiguration": {
"staticResult": {
"name": "Get_blob_content0",
"staticResultOptions": "Disabled"
}
},
"type": "ApiConnection"
},
"[Initialize]_Agent_Name": {
"inputs": {
"variables": [
{
"name": "var_AgentName",
"type": "string",
"value": "PLC"
}
]
},
"runAfter": {
"Get_blob_content": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"[Initialize]_For_Composed_AccountId": {
"inputs": {
"variables": [
{
"name": "var_ComposeAccountIdSuffix",
"type": "string"
}
]
},
"runAfter": {
"[Initialize]_For_Margin_Value_FLoat": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"[Initialize]_For_Margin_Value_FLoat": {
"inputs": {
"variables": [
{
"name": "var_MarginVal",
"type": "float",
"value": 0
}
]
},
"runAfter": {
"[Initialize]_Margin_Value_String": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"[Initialize]_Margin_Value_String": {
"inputs": {
"variables": [
{
"name": "var_MarginStr",
"type": "string"
}
]
},
"runAfter": {
"[Initialize]_Agent_Name": [
"Succeeded"
]
},
"type": "InitializeVariable"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"staticResults": {
"Get_blob_content0": {
"outputs": {
"headers": {},
"statusCode": "OK"
},
"status": "Succeeded"
}
},
"triggers": {
"When_a_blob_is_added_or_modified_(properties_only)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob']['connectionId']"
}
},
"method": "get",
"path": "/datasets/default/triggers/batch/onupdatedfile",
"queries": {
"folderId": "JTJmcGxj",
"maxFileCount": 1
}
},
"metadata": {
"JTJmcGxj": "/plc"
},
"recurrence": {
"frequency": "Second",
"interval": 3
},
"splitOn": "#triggerBody()",
"type": "ApiConnection"
}
}
},
"parameters": {
"$connections": {
"value": {
"azureblob": {
"connectionId": "/subscriptions/xxxx/resourceGroups/xxx-PRD-PORTAL-01/providers/Microsoft.Web/connections/azureblob-2",
"connectionName": "azureblob-2",
"id": "/subscriptions/xxxx/providers/Microsoft.Web/locations/southeastasia/managedApis/azureblob"
},
"office365": {
"connectionId": "/subscriptions/xxxx/resourceGroups/xxx-PRD-PORTAL-01/providers/Microsoft.Web/connections/office365",
"connectionName": "office365",
"id": "/subscriptions/xxxx/providers/Microsoft.Web/locations/southeastasia/managedApis/office365"
},
"sql": {
"connectionId": "/subscriptions/xxxx/resourceGroups/xxx-PRD-PORTAL-01/providers/Microsoft.Web/connections/sql-6",
"connectionName": "sql-6",
"id": "/subscriptions/xxxx/providers/Microsoft.Web/locations/southeastasia/managedApis/sql"
}
}
}
}
}
When a For Each runs by default it runs iterations concurrently. The variables are not guaranteed to use the value for the current iteration. If you change the For Each to run sequentially it will work with the variables. In the For Each settings turn on Concurrency Control and set the Degree of Parallelism to 1. The other option is to remove the use of variables in the loop if you want it to run in parallel.
The Microsoft documentation for loop on this page https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-control-flow-loops says
To get predictable results from operations on variables during each
loop iteration, run those loops sequentially. For example, when a
concurrently running loop ends, the increment, decrement, and append
to variable operations return predictable results. However, during
each iteration in the concurrently running loop, these operations
might return unpredictable results.