Rethinking an old Logic App deployment package – part II

Previously in Note to self…

I’ve been discussing how my first Logic App deployment package was not exactly what I’ve envisaged. So when I had a chance to revamp it, I jumped into the opportunity. You can read about that here.

Logic App Template Generator

I’ve decided to use Jeff Hollan’s Logic App Template Generator – a PowerShell utility that Jeff created sometime ago and have made available on GitHub. Jeff’s PowerShell module have a two cmdlets:Get-LogicAppTemplate: this cmdlet generates the template of a logic app passed as parameter.

  • Get-ParameterTemplate: this cmdlet generates the parameters of an ARM template passed as parameter.

Installing the Template Generator

Installing the component is as easy as forking the code and building. But be aware that it requires a couple of components:

Once the component is installed, you need to import the module for your PowerShell session:

Import-Module <path to local repository>\LogicAppTemplateCreator\LogicAppTemplate\bin\Debug\LogicAppTemplate.dll

After importing, the cmdlets are ready to be used. Notice that as much of the other commands that interact with Azure, you need to be logged into Azure first. You can do that by simply executing the following command:

Login-AzureRMAccount

A Resource Group Logic App Template Generator

With the component installed and working fine, it was now time to create a script that execute the following steps:

  1. Load a list of logic apps from a resource group
  2. For each logic app
    • Create a new folder to host the logic app templates
    • Create the Logic App Template and save in the new folder created
    • Create the Parameter file and save in the new folder created

Loading a list of logic apps from a resource group

This can be achieved with a couple of PowerShell cmdlets:

Get-AzureRmSubscription -SubscriptionName $subscriptionname | Select-AzureRmSubscription
Find-AzureRmResource -ResourceGroupNameContains $resourcegroup -ResourceType Microsoft.Logic/workflows

In the script above, the first line find a subscription  $subscription in your list of subscriptions and select that subscription. From that point on, cmdlets will reference that subscription. The second line find all resources in a resource group $resourcegroup whose type is Microsoft.Logic/workflows.

Extracting templates for each command

With the list of logic apps retrieved, we can now loop through the result set and create

ForEach-Object{ 
        $logicappfolder = [IO.Path]::GetFullPath((Join-Path $destination $_.Name))
	md $logicappfolder -Force | Out-Null
	
        $destinationfile = $(Join-path $logicappfolder ($_.Name + ".json"))
	$destinationparmfile = $(Join-path $logicappfolder ($_.Name + ".param.json"))

	armclient token $_.SubscriptionId | Get-LogicAppTemplate -LogicApp $_.Name -ResourceGroup $_.ResourceGroupName -SubscriptionId $_.SubscriptionId -TenantName $tenantname -Verbose | Out-File $destinationfile -Force

	Get-ParameterTemplate -TemplateFile $destinationfile | Out-File $destinationparmfile -Force}

The code above runs pipped on the result of the previous code snippet. Within that snippet we execute the following operations:

  1. Define and create a new logic app folder.
  2. Define the names of both logic app template and parameter files.
  3. Extract the template of a logic app, saving the result to the folder
  4. Extrat the parameter file, saving the result to the folder.

The lines highlighted are at the core of the snippet, using the cmdlets implemented by the Logic App Template Generator. ARM Client is used to aqcuire an authentication token which is used by Get-LogicAppTemplate to access the resource group.

Putting everything together

The final script looks like this:

param([string] $subscriptionname, [string] $tenantname, [string] $resourcegroup, [string] $destination)

# Import the Logic Apps Template Module #
$module = resolve-path ".\..\bin\Debug\LogicAppTemplate.dll"
Import-Module $module

# Create required folders #
md -Force $destination | Out-Null

# Select the correct subscription #
Get-AzureRmSubscription -SubscriptionName $subscriptionname | Select-AzureRmSubscription | Out-Null

Write-Host

# Gets a list of logic app
Find-AzureRmResource -ResourceGroupNameContains $resourcegroup -ResourceType Microsoft.Logic/workflows | ForEach-Object{ 

	Write-Host $("Creating {0} Logic App Template" -f $_.Name)

	# Define the destination folder #
	$logicappfolder = [IO.Path]::GetFullPath((Join-Path $destination $_.Name))
	md $logicappfolder -Force | Out-Null
	
	# Define the destination file names #
	$destinationfile = $(Join-path $logicappfolder ($_.Name + ".json"))
	$destinationparmfile = $(Join-path $logicappfolder ($_.Name + ".param.json"))
	
	# Create Logic App Template #
	armclient token $_.SubscriptionId |	Get-LogicAppTemplate -LogicApp $_.Name -ResourceGroup $_.ResourceGroupName -SubscriptionId $_.SubscriptionId -TenantName $tenantname -Verbose | Out-File $destinationfile -Force
	
	# Generate the Parameter File #
	Get-ParameterTemplate -TemplateFile $destinationfile | Out-File $destinationparmfile -Force}

Write-Host

Using the script

In order to use the script (which is now added to Jeff’s repository under cmdlets) you just need to follow the steps below:

  1. Open PowerShell console
  2. Navigate to <path to local repository>\LogicAppTemplateCreator\LogicAppTemplate\Cmdlets\
  3. Execute the following command:
./Get-RGLogicAppsTemplate.ps1 "<mysubscription" "<mytenant>" "<myresourcegroup>" "<mypath>"

Where:

  • mysubscription is the name of the subscription containing the resource group (e.g. Contoso Development)
  • mytenant is the name of the tenant that the subscription is associated to (e.g. contoso.onmicrosoft.com)
  • myresourcegroup is the name of the resource group containing the logic apps to export (e.g. Sample Application RG)
  • mypath is the name of the folder where the subfolders and logic apps will be created. If the folder doesn’t exists it will be created.

A sample call would look like this:

./Get-RGLogicAppsTemplate.ps1 "Contoso Development" "contoso.onmicrosoft.com" "Sample Application" "c:\sampleapplication"

Next Steps

With this exercise I was able to create parse a resource group and generate logic apps templates for each one of them. So I am now one step closer of my final goal of having a full set project with individual templates that can be deployed either by themselves or as a package.

To do this, I need to dynamically create a nested template. And that is the topic of my next post.


Posted

in

,

by

Comments

16 responses to “Rethinking an old Logic App deployment package – part II”

  1. sujith reddy komma Avatar
    sujith reddy komma

    Hi Wagner,
    Thanks for the Detailed Explanation.its very nice and resourceful.

    when i was executing the Get-RGLogicAppsTemplate.ps1, i was getting a small problem at this Statement
    Get-AzureRmSubscription -SubscriptionName $subscriptionname | Select-AzureRmSubscription

    i had multiple Subscriptions so I have to Change the Subscription from my Default. So i have provided the Subscription name and tried it, but it didn’t change.(Ideally it should have)

    I couldn’t find the root cause,so just tried to Change the Powershell Script to use SubscriptionID instead of subscriptionName as Parameter and replace the above statement like below
    Set-AzureRmContext -SubscriptionId $subscriptionID

    Then i was able to get all the Logic Apps Extracted into my Folder.

    Is there anything wrong i did which was not able to execute the first Statement?

    1. wsilveiranz Avatar
      wsilveiranz

      H Sujith,

      Good to know it was helpful. The only thing I can think of is the version of AzureRM. I had a couple of issues (not with this script, but another one using Service Bus) and I think it was because of that. I will make sure that I get a copy of the latest version of AzureRM and try again. Let you know once I find more info.

      Cheers, Wagner.

      1. Wagner Silveira Avatar
        Wagner Silveira

        Just circling back on this one. I was using this one this week, and I am having trouble with that as well – in my case I am getting an error that I can’t get the token – possibly because of the same issue. I have the impression that something changed in AzureRM (or the underlying security configuration). I am testing your workaround and see how I can include that in the script.I was also talking to Mattias and he was having problems with ARMClient, so it might be that is also causing some problem. Once I have an updated script I will push again and send you a note.

        Thanks for that!

        1. sujith reddy komma Avatar
          sujith reddy komma

          Thanks Wagner for your time. I have used the Script like below

          param([string] $subscriptionID, [string] $tenantname, [string] $resourcegroup, [string] $destination)

          # Import the Logic Apps Template Module #
          $module = resolve-path “.\..\bin\Debug\LogicAppTemplate.dll”
          Import-Module $module

          # Create required folders #
          md -Force $destination | Out-Null

          # Select the correct subscription #
          Set-AzureRmContext -SubscriptionId $subscriptionID

          #Write-Host $resourcegroup

          # Gets a list of logic app
          Find-AzureRmResource -ResourceGroupNameContains $resourcegroup -ResourceType Microsoft.Logic/workflows | ForEach-Object{

          Write-Host $(“Creating {0} Logic App Template” -f $_.Name)

          # Define the destination folder #
          $logicappfolder = [IO.Path]::GetFullPath((Join-Path $destination $_.Name))
          md $logicappfolder -Force | Out-Null

          # Define the destination file names #
          $destinationfile = $(Join-path $logicappfolder ($_.Name + “.json”))
          $destinationparmfile = $(Join-path $logicappfolder ($_.Name + “.parameters.json”))

          # Create Logic App Template #
          armclient token $_.SubscriptionId | Get-LogicAppTemplate -LogicApp $_.Name -ResourceGroup $_.ResourceGroupName -SubscriptionId $_.SubscriptionId -TenantName $tenantname -Verbose | Out-File $destinationfile -Force

          # Generate the Parameter File #
          Get-ParameterTemplate -TemplateFile $destinationfile | Out-File $destinationparmfile -Force}

          Write-Host
          # Initialize Azure Deploy nested Templates variable #
          $azuredeploytemplate = “”

          Write-Host “Creating AzureDeploy ARM Template”

          # Gets a list of resources to add to the nested template #
          Get-ChildItem $destination -Directory | ForEach-object {

          # Adds the resource to the nested templates #
          $azuredeploytemplate = Get-NestedResourceTemplate -ResourceName $_.Name -Template $azuredeploytemplate}

          #Save nested template to destination #
          $azuredeploytemplate | Out-File $(Join-path $destination “azuredeploy.json”) -Force

          Write-Host

          Write-Host “Creating AzureDeploy ARM Parameter Template”

          #Generate an empty Azure Deploy Parameter

          Get-EmptyParameterTemplate | Out-File $(Join-path $destination “azuredeploy.parameters.json”) -Force

          Write-Host

          I changed the SubscriptionName to have the SubscriptionID in the above Script.

          I also faced a Problem with ARM Client and was facing an Error when creating logic app Template.

          So i have to do one more prerequisite before running the script i have to login with ArmClient with the below command.

          ARMClient.exe login

          Then i have run the script and i was able to get all the Logic App Templates.

          May be it can help you in your investigation.

  2. wsilveiranz Avatar
    wsilveiranz

    Thanks for sharing Sujith!

    Yep, that one definitely works – I end up using that as a workaround too. I am still trying to find a way to pass the subscription name as a parameter. Once I have some time on my hands again I will come back to that.

    I will keep you posted.

  3. Maithili Kotla Avatar
    Maithili Kotla

    Thanks for this article, very helpful.
    I have an issue when running the script “Get-RGLogicAppsTemplate.ps1”. I get the error “The file cannot be loaded. The file is not digitally signed. You cannot run this script on the current system.
    CategoryInfo: SecurityError : PSSecurityException, UnauthorizedAccess.

    1. wsilveiranz Avatar
      wsilveiranz

      Hi Maithili,

      Sorry for the late reply – I think the error is because of the execution policy. I needs to be set to unrestricted (as it is a private script)

  4. Kannan Avatar

    Hi, I’m unable to run the cmdlet Get-ParameterTemplate. It’s not recognised as a valid cmdlet command. I looked at the source code and the cmdlet is available.

  5. Maithili Kotla Avatar
    Maithili Kotla

    Please ignore my previous post. I had not setup ArmClient, after that I am able to go past that error. The issue now is that the logic app json file is empty. the rest of the structure downloaded is alright though.

    1. wsilveiranz Avatar
      wsilveiranz

      Hi Maithili,

      I think Sujith had a similar issue, due to an old version of ArmClient – try to remove the following block and run again. I will try to do some more tests and update the code as required.

      armclient token $_.SubscriptionId |

  6. Kannan Avatar

    Hi wsilveiranz,
    How this template is different from the one generated using VS 2017 which allows us to download logic app with parmeters populated?

    1. sujith reddy komma Avatar
      sujith reddy komma

      Hi Kannan,
      When you Develop or Create a Template from VS 2017,There will be only One Logic App in it and we have ARM Template as Part of it.

      Script Which is Developed by Wagner in the above can help us to download all the Logic Apps Present in One Resource Group at once and then we can use or modify it.

  7. Sathish Avatar
    Sathish

    Hi,

    I tried using this Script, but I face below error, please help me!
    Executing the script in elevated PS window.

    Creating HelloWorld Logic App Template
    Get-LogicAppTemplate : Aggregation Exception thrown, One or more errors occurred., first Exception message is: Could not find a part of the path ‘C:\Users\profile\Token copied to clipboard
    successfully\providers-Microsoft.Logic-workflows-HelloWorld.json’., for more information read the output file.
    + … tionId | Get-LogicAppTemplate -LogicApp $_.Name -ResourceGroup $_. …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Get-LogicAppTemplate], Exception
    + FullyQualifiedErrorId : System.Exception,LogicAppTemplate.GeneratorCmdlet

    Get-ParameterTemplate : Error reading JObject from JsonReader. Path ”, line 0, position 0.
    + Get-ParameterTemplate -TemplateFile $destinationfile | Out-File $ …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Get-ParameterTemplate], JsonReaderException
    + FullyQualifiedErrorId : Newtonsoft.Json.JsonReaderException,LogicAppTemplate.ParamGenerator

    1. wsilveiranz Avatar
      wsilveiranz

      Hi Satish, can you give me more information on how you are trying to run the script? Can you show the example command line that you are trying to execute?

      1. Sathish Avatar
        Sathish

        Hi Thanks for the quick reply,

        Below is the script…

        #param([string] $subscriptionname, [string] $tenantname, [string] $resourcegroup, [string] $destination)

        $subscriptionname=’xyz’
        $tenantname=’xxxxx.onmicrosoft.com’
        $resourcegroup=’SathishRG’
        $destination=’C:\Users\satis\Desktop\myoutput’
        $SubscriptionId=’1232b0xxx-xxxx-4b6b-xxxx-fd45c234b804′

        # Import the Logic Apps Template Module #
        $module =’C:\Users\satis\Documents\LogicAppTemplateCreator-master\LogicAppTemplate\bin\Debug\LogicAppTemplate.dll’
        Import-Module $module

        # Create required folders #
        md -Force $destination | Out-Null

        # Select the correct subscription #
        Get-AzureRmSubscription -SubscriptionName $subscriptionname | Select-AzureRmSubscription | Out-Null

        Write-Host

        # Gets a list of logic app
        Find-AzureRmResource -ResourceGroupNameContains $resourcegroup -ResourceType Microsoft.Logic/workflows | ForEach-Object{

        Write-Host $(“Creating {0} Logic App Template” -f $_.Name)

        # Define the destination folder #
        $logicappfolder = [IO.Path]::GetFullPath((Join-Path $destination $_.Name))
        md $logicappfolder -Force | Out-Null

        # Define the destination file names #
        $destinationfile = $(Join-path $logicappfolder ($_.Name + “.json”))
        $destinationparmfile = $(Join-path $logicappfolder ($_.Name + “.param.json”))

        # Create Logic App Template #
        armclient token $_.SubscriptionId | Get-LogicAppTemplate -LogicApp $_.Name -ResourceGroup $_.ResourceGroupName -SubscriptionId $_.SubscriptionId -TenantName $tenantname -Verbose | Out-File $destinationfile -Force

        # Generate the Parameter File #
        Get-ParameterTemplate -TemplateFile $destinationfile | Out-File $destinationparmfile -Force}

        Write-Host

        1. Wagner Silveira Avatar

          Hi Sathish,

          I’ve got a couple of reports that the ARMClient was causing issues with this script. Try to remove the following command from the script and see if it works.

          armclient token $_.SubscriptionId |

          Let us know if that helps. If so I will make sure I have the script updated without that.

Leave a Reply

Your email address will not be published. Required fields are marked *