html-emailpower-automate

Create HTML table from array of Objects in Power Automate


I have a variable ObjectArrayItems that is an array of objects in Power Automate that looks like this:

[
  {
    "Name": "Date",
    "Value": "2024-10-11"
  },
  {
    "Name": "Time",
    "Value": "10-24-48"
  },
  {
    "Name": "Desc",
    "Value": "SSL VPN login fail"
  },
  {
    "Name": "IPAddress",
    "Value": "74.119.194.131"
  },
  {
    "Name": "User",
    "Value": "msi"
  },
  {
    "Name": "Group",
    "Value": "VPN-USERS-Epicor"
  },
  {
    "Name": "Msg",
    "Value": "SSL user failed to logged in"
  },
  {
    "Name": "",
    "Value": ""
  },
  {
    "Name": "Date",
    "Value": "2024-10-11"
  },
  {
    "Name": "Time",
    "Value": "10-24-40"
  },
  {
    "Name": "Desc",
    "Value": "SSL VPN login fail"
  },
  {
    "Name": "IPAddress",
    "Value": "91.132.133.118"
  },
  {
    "Name": "User",
    "Value": "msi"
  },
  {
    "Name": "Group",
    "Value": "VPN-USERS-Epicor"
  },
  {
    "Name": "Msg",
    "Value": "SSL user failed to logged in"
  }
]

I am trying to get it into an email as an HTML table that will look like this:

Date Time Desc IPAddress User Group Msg
10/11/2024 10-24-48 SSL VPN login fail 74.119.194.131 msi VPN-USERS-Epicor SSL user failed to logged in
10/11/2024 10-24-40 SSL VPN login fail 91.132.133.118 msi VPN-USERS-Epicor SSL user failed to logged in

What I've ended up getting is something that looks like this instead:

Name Value
Date 2024-10-11
Time 09-24-24
Desc SSL VPN login fail
IPAddress 194.4.48.122
User mikrotik
Group VPN-USERS-Epicor
Msg SSL user failed to logged in
Date 2024-10-11
Time 09-23-54
Desc SSL VPN login fail
IPAddress 109.120.137.38
User fortinet
Group VPN-USERS-Epicor
Msg SSL user failed to logged in

Or like this:

Date Time Desc IP Address User Group Message

With no values in the table.


Here is what I've tried:

Create HTML table with the from being my variable from above "from": "@variables('ObjectArrayItems')"

That gave me the long table with Name and Value as the headers.

Then I tried this:

Create HTML table, same From as above, but then I selected the columns with something like this:

{
    "header": "Date",
    "value": "@variables('ObjectArrayItems')?['Date']"
},
{
    "header": "Time",
    "value": "@variables('ObjectArrayItems')?['Time']"
},
{
    "header": "Desc",
    "value": "@variables('ObjectArrayItems')?['Desc']"
},
{
    "header": "IP Address",
    "value": "@variables('ObjectArrayItems')?['IPAddress']"
},
{
    "header": "User",
    "value": "@variables('ObjectArrayItems')?['User']"
},
{
    "header": "Group",
    "value": "@variables('ObjectArrayItems')?['Group']"
},
{
    "header": "Message",
    "value": "@variables('ObjectArrayItems')?['Msg']"
}

This gives me an error saying

The execution of template action 'Create_HTML_table_1' failed. The column values could not be evaluated: 'The template language expression 'variables('ObjectArrayItems')?['Date']' cannot be evaluated because property 'Date' cannot be selected. Array elements can only be selected using an integer index. Please see https://aka.ms/logicexpressions for usage details.'.

I'm certain there is a simple way to do this, but I've not been able to figure it out. Any help will be greatly appreciated!


Solution

  • Your problem is, each array item is a property and value, you need all of the properties and values grouped into a single object and created as items within another array.

    To achieve that, you need to do the following ...

    Part 1

    Part 1

    Initialize Original Data

    This is the data you provided in your question entered into a variable of type Array ...

    [
      {
        "Name": "Date",
        "Value": "2024-10-11"
      },
      {
        "Name": "Time",
        "Value": "10-24-48"
      },
      {
        "Name": "Desc",
        "Value": "SSL VPN login fail"
      },
      {
        "Name": "IPAddress",
        "Value": "74.119.194.131"
      },
      {
        "Name": "User",
        "Value": "msi"
      },
      {
        "Name": "Group",
        "Value": "VPN-USERS-Epicor"
      },
      {
        "Name": "Msg",
        "Value": "SSL user failed to logged in"
      },
      {
        "Name": "",
        "Value": ""
      },
      {
        "Name": "Date",
        "Value": "2024-10-11"
      },
      {
        "Name": "Time",
        "Value": "10-24-40"
      },
      {
        "Name": "Desc",
        "Value": "SSL VPN login fail"
      },
      {
        "Name": "IPAddress",
        "Value": "91.132.133.118"
      },
      {
        "Name": "User",
        "Value": "msi"
      },
      {
        "Name": "Group",
        "Value": "VPN-USERS-Epicor"
      },
      {
        "Name": "Msg",
        "Value": "SSL user failed to logged in"
      }
    ]
    

    Filter Out Blank Properties

    I noticed you had a break in the data where there was a blank property. To remove that, I used a Filter array operation with the following expression ...

    Filter

    That expression at the item level is ...

    length(coalesce(item()?['Name'], ''))
    

    Initialize Object Array

    Initialize a variable of type Array. This will store the transformed array that will be used to create the HTML table.

    Initialize Object

    Initialize a variable of type Object. For every new item we create with all properties, this will be that object.

    Part 2

    Part 2

    From here, we're going to loop through your data and create each object that contains each property per larger item.

    The Apply to each is working off the result from the filtered data ...

    body('Filter_Out_Blank_Properties')
    

    If Property EQ Date

    Date is your first property so in the condition, we need to check for that each time and act on it accordingly.

    Condition

    First we need to make sure that the Object variable isn't equal to NULL. On the first iteration, it will be because it hasn't been built yet.

    The second AND condition is ...

    toUpper(item()['Name'])
    

    ... this checks to see if the current property is equal to Date. If it is and the first condition is satisfied then we're starting a new object, so, append the existing object to the Object Array variable. That's what the next step does.

    Append To Object Array

    It appends the Object variable to the resulting array. The expression is ...

    variables('Object')
    

    Reset Object

    This is a Set variable operation and resets the Object variable back to nothing, not null, just a blank object. Set the value to ...

    {}
    

    Compose Add Property To Object

    Outside of the condition, we now want to use a Compose operation to add the current property with its associated value to the Object variable. To do that, this is the expression ...

    addProperty(coalesce(variables('Object'), json('{}')), item()['Name'], item()['Value'])
    

    Set Object

    We now want to set the Object variable to be the output of the previous step. The reason why we need the previous step and we don't just use addProperty() in a single step to set the variable is because it won't let you, you'll get an error. This is the expression ...

    outputs('Compose_Add_Property_To_Object')
    

    Part 3

    Part 3

    This is where we'll create the HTML table.

    Append To Object Array (Last)

    This step seems a bit weird but it's doing the same thing as the previously named Append To Object Array step. It's the exact same thing. We need it because when we processed the last property and added it to the object, we never loop around again like we do in the Apply to each operation section, so we need to add that very last object to the final array. Without this, we'll miss one of the items.

    So now overall, the Object Array variable will look like this ...

    [
      {
        "Date": "2024-10-11",
        "Time": "10-24-48",
        "Desc": "SSL VPN login fail",
        "IPAddress": "74.119.194.131",
        "User": "msi",
        "Group": "VPN-USERS-Epicor",
        "Msg": "SSL user failed to logged in"
      },
      {
        "Date": "2024-10-11",
        "Time": "10-24-40",
        "Desc": "SSL VPN login fail",
        "IPAddress": "91.132.133.118",
        "User": "msi",
        "Group": "VPN-USERS-Epicor",
        "Msg": "SSL user failed to logged in"
      }
    ]
    

    ... THIS IS WHAT YOU NEED!!!

    Create HTML Table

    With that data, now you can create your HTML table.

    Create HTML Table

    This is the result ...

    <table><thead><tr><th>Date</th><th>Time</th><th>Desc</th><th>IPAddress</th><th>User</th><th>Group</th><th>Msg</th></tr></thead><tbody><tr><td>2024-10-11</td><td>10-24-48</td><td>SSL VPN login fail</td><td>74.119.194.131</td><td>msi</td><td>VPN-USERS-Epicor</td><td>SSL user failed to logged in</td></tr><tr><td>2024-10-11</td><td>10-24-40</td><td>SSL VPN login fail</td><td>91.132.133.118</td><td>msi</td><td>VPN-USERS-Epicor</td><td>SSL user failed to logged in</td></tr></tbody></table>