Simplifying Microsoft Logic App Exports: A Powerful Tool for DevOps Teams

πŸš€ Export Logic Apps with Ease: One Script to Rule All Environments! πŸš€

Published on 10 March 2025

Introduction

For organisations working with Microsoft Azure, Logic Apps have become an essential component for workflow automation. Whether you're orchestrating business processes, automating Sentinel security responses, or integrating disparate systems, Logic Apps provide the glue that binds these processes together. However, when it comes to managing these workflows across environmentsβ€”from development to testing and productionβ€”things can get complicated quickly.

I have created a new open-source PowerShell tool that addresses this challenge: theLogic App ARM Template Export Script. This utility enables DevOps teams, cloud architects, and IT professionals to easily export Logic Apps as Azure Resource Manager (ARM) templates, streamlining the deployment process and ensuring consistency across environments.

The Challenge of Logic App Management

Before diving into the solution, let's examine the common challenges faced when managing Logic Apps:

  • Manual export processes: Using the Azure Portal to individually export Logic Apps is time-consuming
  • Connection handling: Managing API connections across environments often requires tedious reconfiguration
  • Gallery-compatible templates: Creating templates suitable for Microsoft Sentinel's Content Hub Gallery requires specific formatting
  • Multi-environment consistency: Ensuring identical workflows across development, testing, and production environments

The Logic App ARM Template Export Script

This PowerShell-based solution provides an elegant approach to exporting Logic Apps as ARM templates. Crafted with cross-platform compatibility in mind, the script runs on PowerShell 7 across Windows, macOS, and Linux, making it accessible to all Azure administrators regardless of their operating system preference.

Key Features

The script offers several powerful features:

  1. Interactive selection: Easily navigate through tenants, subscriptions, resource groups, and Logic Apps via an intuitive console interface
  2. Gallery template generation: Optional configuration to generate templates suitable for the Microsoft Sentinel Content Hub Gallery
  3. API connection handling: Automatic detection and configuration of API connections within the templates
  4. Managed identity support: Seamless handling of connections that use managed service identities
  5. Customisable export location: Flexibility to choose where your exported templates are saved
  6. Comprehensive logging: Detailed activity tracking to facilitate troubleshooting

How It Works

The script follows a logical, user-friendly workflow:

  1. Environment setup: Verifies and installs required PowerShell modules (Az.Accounts and Microsoft.PowerShell.ConsoleGuiTools)
  2. User choices: Prompts for gallery template generation and Az module updates
  3. Azure navigation: Guides you through selecting the tenant, subscription, and resource group
  4. Logic App selection: Presents available Logic Apps for multi-selection
  5. Template generation: Builds ARM templates with proper parameter handling and connection references
  6. Export: Saves the ARM templates to your specified location

Implementation Deep Dive

The script is remarkably thorough in handling the nuances of Logic App exports. Let's examine some of its key components:

Interactive Module Verification

The script begins with robust module verification, intelligently checking for required modules and guiding the user through installation if they're missing:

Function Ensure-Module {
    param (
        [string]$ModuleName,
        [string]$InstallMessage,
        [string]$InstallCommand
    )
    Write-Log -Message "Checking if module '$ModuleName' is installed..." -Severity "Information"

    if (-not (Get-Module -ListAvailable -Name $ModuleName)) {
        Write-Log -Message "Module '$ModuleName' is not installed. Prompting user for installation." -Severity "Warning"

        $InstallQuestion = "The $ModuleName module is required. Do you want to install it now?"
        $InstallChoices = New-Object System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription]
        $InstallChoices.Add((New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes', "Install the $ModuleName module"))
        $InstallChoices.Add((New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList '&No', "Do not install and exit"))

        $InstallDecision = $Host.UI.PromptForChoice(
            "Install $ModuleName",
            $InstallQuestion,
            $InstallChoices,
            1
        )

        if ($InstallDecision -eq 0) {
            try {
                Invoke-Expression $InstallCommand
                Import-Module $ModuleName -ErrorAction Stop
                Write-Log -Message "Module '$ModuleName' installed and imported successfully." -Severity "Information"
            } catch {
                Write-Log -Message "Failed to install module '$ModuleName': $($_.Exception.Message)" -Severity "Error"
                Write-Log -Message "Exiting script due to missing required module." -Severity "Error"
                exit 1
            }
        } else {
            Write-Log -Message "User chose not to install module '$ModuleName'. Exiting..." -Severity "Error"
            exit 1
        }
    }
}

This attention to detail ensures a smooth user experience even when prerequisites aren't met initially.

Comprehensive Logging System

The script implements a sophisticated logging system that tracks operations at multiple severity levels:

Function Write-Log {
    param(
        [Parameter(Mandatory=$true)][string]$Message,
        [ValidateSet("Information", "Warning", "Error", "Debug")][string]$Severity = 'Information'
    )

    # Get the script root directory
    $ScriptRoot = $PSScriptRoot
    if (-not $ScriptRoot) {
        $ScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Definition
        if (-not $ScriptRoot) {
            $ScriptRoot = (Get-Location).Path
        }
    }

    # Define the log file path
    $LogFile = Join-Path -Path $ScriptRoot -ChildPath "ScriptLog.txt"

    # Build the log entry with timestamp and severity
    $TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $LogEntry = "[$TimeStamp] [$Severity] $Message"

    # Write to the console with appropriate color
    switch ($Severity) {
        "Warning"     { Write-Host $LogEntry -ForegroundColor Yellow }
        "Error"       { Write-Host $LogEntry -ForegroundColor Red }
        "Debug"       { Write-Host $LogEntry -ForegroundColor Cyan }
    }

    # Append to the log file
    try {
        Add-Content -Path $LogFile -Value $LogEntry
    } catch {
        Write-Host "Failed to write log to file: $($_.Exception.Message)" -ForegroundColor Red
    }
}

This dual logging approachβ€”to both console and fileβ€”ensures administrators have a clear record of actions for troubleshooting and audit purposes.

Flexible Export Location Selection

Rather than forcing a fixed export location, the script offers a user-friendly way to select the destination folder:

Function Initialize-ExportFolder {
    param (
        [string]$DefaultExportFolder
    )

    $ChangeLocationQuestion = "Would you like to change the default export location?"
    $ChangeLocationChoices = New-Object System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription]
    $ChangeLocationChoices.Add((New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes', 'Change the export folder location'))
    $ChangeLocationChoices.Add((New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList '&No', 'Use the default export folder location'))

    $ChangeLocationDecision = $Host.UI.PromptForChoice(
        "Change Export Location",
        $ChangeLocationQuestion,
        $ChangeLocationChoices,
        1
    )

    if ($ChangeLocationDecision -eq 0) {
        # Present directories in a grid view for selection
        $directories = Get-ChildItem -Directory -Path $HOME | Select-Object Name,FullName
        $selectedDirectory = $directories | Out-ConsoleGridView -Title "Select Export Folder (Press ENTER when done)" -OutputMode Single
        
        if ($selectedDirectory) {
            $ExportFolder = $selectedDirectory.FullName
        } else {
            $ExportFolder = $DefaultExportFolder
        }
    } else {
        $ExportFolder = $DefaultExportFolder
    }

    # Ensure folder exists
    if (-not (Test-Path -Path $ExportFolder)) {
        New-Item -Path $ExportFolder -ItemType Directory -Force | Out-Null
    }

    return $ExportFolder
}

This visual directory selection approach leverages the Out-ConsoleGridView cmdlet for a more intuitive experience than traditional command-line parameter passing.

API Connection Handling

One of the most impressive aspects is how the script manages API connections. It meticulously extracts and reconfigures connection information to work in any target environment:

Function HandlePlaybookApiConnectionReference($apiConnectionReference, $playbookResource) {
    # Get connection name
    $connectionName = $apiConnectionReference.Name
    $connectionName = $connectionName.Split('_')[0].ToString().Trim()
    $connectionName = (Get-Culture).TextInfo.ToTitleCase($connectionName)

    # Create variable for the connection
    if ($connectionName -ieq "azuresentinel") {
        $connectionVariableName = "MicrosoftSentinelConnectionName" 
        $templateVariables.Add($connectionVariableName, "[concat('MicrosoftSentinel-', parameters('PlaybookName'))]")           
    } else {
        $connectionVariableName = "$($connectionName)ConnectionName"
        $templateVariables.Add($connectionVariableName, "[concat('$connectionName-', parameters('PlaybookName'))]")
    }

    # Determine connector type and authentication method
    $connectorType = if ($apiConnectionReference.Value.id.ToLowerInvariant().Contains("/managedapis/")) { "managedApis" } else { "customApis" } 
    $connectionAuthenticationType = if ($apiConnectionReference.Value.connectionProperties.authentication.type -eq "ManagedServiceIdentity") { "Alternative" } else { $null }    

    # Special handling for Sentinel connections when generating gallery templates
    if ($GenerateForGallery -and $connectionName -eq "azuresentinel" -and !$connectionAuthenticationType) {
        $connectionAuthenticationType = "Alternative"
        if (!$apiConnectionReference.Value.ConnectionProperties) {
            Add-Member -InputObject $apiConnectionReference.Value -Name "ConnectionProperties" -Value @{} -MemberType NoteProperty
        }
        $apiConnectionReference.Value.connectionProperties = @{
            "authentication"= @{
                "type"= "ManagedServiceIdentity"
            }
        }
    }

    # Try to retrieve existing connection details from ARM
    try {
        $existingConnectionProperties = SendArmGetCall -relativeUrl "$($apiConnectionReference.Value.connectionId)?api-version=2016-06-01"
    }
    catch {
        $existingConnectionProperties = $null
    }

    # Create the connection resource for the ARM template
    $apiConnectionResource = [ordered] @{
        "type"= "Microsoft.Web/connections"
        "apiVersion"= "2016-06-01"
        "name"= "[variables('$connectionVariableName')]"
        "location"= "[resourceGroup().location]"
        "kind"= "V1"
        "properties"= [ordered] @{
            "displayName"= "[variables('$connectionVariableName')]"
            "customParameterValues"= [ordered] @{}
            "parameterValueType"= $connectionAuthenticationType
            "api"= [ordered] @{
                "id"= "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/$connectorType/$connectionName')]"
            }
        }
    }

    # Add the connection resource and update the playbook to reference it
    $apiConnectionResources.Add($apiConnectionResource) | Out-Null
    $playbookResource.dependsOn += "[resourceId('Microsoft.Web/connections', variables('$connectionVariableName'))]"
}

This function handles both standard API connections and Microsoft Sentinel-specific connections, with special consideration for Managed Service Identity authentication.

Intelligent ARM Template Construction

The script constructs ARM templates with meticulous attention to detail, removing deployment-specific properties and adapting resources for redeployment:

Function GetPlaybookResource() {
    Try {    
        $playbookArmIdToUse = BuildPlaybookArmId
        $playbookResource = SendArmGetCall -relativeUrl "$($playbookArmIdToUse)?api-version=2017-07-01"

        # Add a parameter for the playbook name
        $PlaybookARMParameters.Add("PlaybookName", [ordered] @{
            "defaultValue"= $playbookResource.Name
            "type"= "string"
        })

        # Gallery-specific handling
        if ($GenerateForGallery) {
            # Add required tags for Content Hub Gallery
            if (!("tags" -in $playbookResource.PSobject.Properties.Name)) {
                Add-Member -InputObject $playbookResource -Name "tags" -Value @() -MemberType NoteProperty -Force
            }

            if (!$playbookResource.tags) {
                $playbookResource.tags = [ordered] @{
                    "hidden-SentinelTemplateName"= $playbookResource.name
                    "hidden-SentinelTemplateVersion"= "1.0"
                }
            }
            
            # Ensure SystemAssigned identity for gallery templates
            if ($playbookResource.identity.type -ne "SystemAssigned") {
                if (!$playbookResource.identity) {
                    Add-Member -InputObject $playbookResource -Name "identity" -Value @{
                        "type"= "SystemAssigned"
                    } -MemberType NoteProperty -Force
                }
                else {
                    $playbookResource.identity = @{
                        "type"= "SystemAssigned"
                    }
                }
            }
        }

        # Remove deployment-specific properties
        $playbookResource.PSObject.Properties.remove("id")
        $playbookResource.location = "[resourceGroup().location]"
        $playbookResource.name = "[parameters('PlaybookName')]"
        Add-Member -InputObject $playbookResource -Name "apiVersion" -Value "2017-07-01" -MemberType NoteProperty
        Add-Member -InputObject $playbookResource -Name "dependsOn" -Value @() -MemberType NoteProperty

        # Remove runtime properties
        $playbookResource.properties.PSObject.Properties.remove("createdTime")
        $playbookResource.properties.PSObject.Properties.remove("changedTime")
        $playbookResource.properties.PSObject.Properties.remove("version")
        $playbookResource.properties.PSObject.Properties.remove("accessEndpoint")
        $playbookResource.properties.PSObject.Properties.remove("endpointsConfiguration")

        return $playbookResource
    }
    Catch {
        Write-Log -Message "Error occurred in GetPlaybookResource :$($_)" -Severity Error
    }
}

Professional JSON Formatting

The script includes a sophisticated JSON formatting function that ensures the exported templates are professionally structured and human-readable:

Function FixJsonIndentation ($jsonOutput) {
    Try {
        $currentIndent = 0
        $tabSize = 4
        $lines = $jsonOutput.Split([Environment]::NewLine)
        $newString = ""
        foreach ($line in $lines) {
            if ($line.Trim() -eq "") {
                continue
            }

            # If line ends with ] or }, reduce indent first
            if ($line -match "[\]\}],?\s*$") {
                $currentIndent -= 1
            }

            # Add current line with the right indent
            if ($newString -eq "") {
                $newString = $line
            } else {
                $spaces = ""
                $matchFirstChar = [regex]::Match($line, '[^\s]+')
                $totalSpaces = $currentIndent * $tabSize
                if ($totalSpaces -gt 0) {
                    $spaces = " " * $totalSpaces
                }
                $newString += [Environment]::NewLine + $spaces + $line.Substring($matchFirstChar.Index)
            }

            # If line ends with { or [, increase indent
            if ($line -match "[\[{]\s*$") {
                $currentIndent += 1
            }
        }
        return $newString
    }
    catch {
        Write-Log -Message "Error occurred in FixJsonIndentation :$($_)" -Severity Error
    }
}

This attention to detail ensures that the exported templates are not just functional but also easy to read and maintainβ€”a crucial factor for teams that need to review or modify the templates before deployment.

Real-World Applications

This tool excels in several real-world scenarios:

Scenario 1: DevOps Automation

Teams embracing Infrastructure as Code (IaC) can integrate this script into their CI/CD pipelines to automate the export of Logic Apps from development environments. The script's ability to handle tenant and subscription selection makes it particularly valuable for organisations with complex Azure environments.

# Example of how the script navigates Azure environments
if (-not $TenantId) {
    $tenants = Get-AzTenant
    if ($tenants.Count -gt 1) {
        $selectedTenant = $tenants | Out-ConsoleGridView -Title "Select Tenant" -OutputMode Single
        if (-not $selectedTenant) {
            Write-Log -Message "No tenant selected. Exiting..." -Severity "Error"
            exit
        }
        $TenantId = $selectedTenant.TenantId
    } else {
        # Only one tenant found, use it automatically
        $TenantId = $tenants[0].TenantId
    }
}

The exported templates can be version-controlled and deployed to testing and production environments, ensuring consistency across the deployment lifecycle.

Scenario 2: Microsoft Sentinel Content Creators

Security teams developing custom Sentinel playbooks can use this script to prepare their Logic Apps for submission to the Content Hub Gallery. The script automatically handles the specific requirements for gallery templates:

# Logic for gallery-specific template formatting
if ($GenerateForGallery) {
    $armTemplate.Insert(2, "metadata", [ordered] @{
        "title"= ""
        "description"= ""
        "prerequisites"= ""
        "postDeployment" = @()
        "prerequisitesDeployTemplateFile"= ""
        "lastUpdateTime"= ""
        "entities"= @()
        "tags"= @()
        "support"= [ordered] @{
            "tier"= "community"
            "armtemplate" = "Generated"
        }
        "author"= @{
            "name"= ""
        }
    })
}

This gallery-specific formatting ensures that submissions meet all the requirements for sharing with the wider security community, saving considerable time in the submission process.

Scenario 3: Environment Migration

When organisations need to migrate Logic Apps between Azure environmentsβ€”perhaps during a tenant migration or regional expansionβ€”this script simplifies the process by generating templates that are environment-agnostic. The script intelligently parameterizes environment-specific values:

# Converting resource-specific references to parameters
$playbookResource.location = "[resourceGroup().location]"
$playbookResource.name = "[parameters('PlaybookName')]"

# Handling API connections with subscription-agnostic references
$apiConnectionReference.Value = [ordered] @{
    "connectionId"= "[resourceId('Microsoft.Web/connections', variables('$connectionVariableName'))]"
    "connectionName" = "[variables('$connectionVariableName')]"
    "id" = "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/$connectorType/$connectionName')]"
}

This parameterization ensures that the templates can be deployed to any Azure environment without manual modifications.

Getting Started

To start using this powerful tool:

  1. Prerequisites:
    • PowerShell 7.0 or later installed on your system
    • Basic familiarity with Azure and PowerShell
  2. Setup:
    • Clone or download the script from the repository
    • Run the script in a PowerShell 7+ terminal with the optional -TenantId parameter or let it guide you through tenant selection
    • Follow the interactive prompts to select your export options
  3. First Run Experience:

The script offers a guided experience during its first execution:

************************************************************
*          Logic App ARM Template Export Script            *
************************************************************
This script will help you select and export Logic Apps as ARM templates.
By default, the output will be saved to:
C:\Scripts\LogicAppExport
You can choose to change this location if desired.
Running on PowerShell 7+, multi-platform compatible.
************************************************************

Change Export Location
Would you like to change the default export location?
[Y] Yes  [N] No  [?] Help (default is "N"):

Install Microsoft.PowerShell.ConsoleGuiTools
The Microsoft.PowerShell.ConsoleGuiTools module is required. Do you want to install it now?
[Y] Yes  [N] No  [?] Help (default is "N"):

Gallery Template Generation
Generate ARM Template for Gallery?
[Y] Yes  [N] No  [?] Help (default is "N"):

Update Az Modules
Do you want to update required Az Modules to the latest version?
[Y] Yes  [N] No  [?] Help (default is "N"):

From there, the script will guide you through:

  • Tenant selection (if not provided as a parameter)
  • Subscription selection using an interactive grid view
  • Resource group selection
  • Logic App selection (with multi-select capability)
  • Template generation with real-time progress updates

Here's an example of the multi-select grid for Logic Apps:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Select Logic Apps to Export as ARM Templates (Press ENTER when done)    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ResourceGroupName β”‚ Name               β”‚ Location β”‚ Kind     β”‚ State    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Sentinel-Playbook β”‚ Alert-TeamChannel  β”‚ westeu   β”‚ Playbook β”‚ Enabled  β”‚
β”‚ Sentinel-Playbook β”‚ Create-Incident    β”‚ westeu   β”‚ Playbook β”‚ Enabled  β”‚
β”‚ Sentinel-Playbook β”‚ Email-SOC-Team     β”‚ westeu   β”‚ Playbook β”‚ Enabled  β”‚
β”‚ Sentinel-Playbook β”‚ EntraID-Monitor    β”‚ westeu   β”‚ Playbook β”‚ Enabled  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The script will then export the selected Logic Apps as ARM templates to your chosen location, with detailed logging of each action performed.

Security and Best Practices

When using this tool, consider these security best practices:

  • Use the script on a secure workstation with appropriate Azure access
  • Review exported templates before deployment to ensure sensitive information isn't inadvertently included
  • Consider applying additional encryption or secure storage for exported templates
  • When defining permanent export locations, ensure appropriate access controls are in place

Technical Highlights

Cross-Platform Compatibility

One of the standout features of this script is its true cross-platform compatibility. Built for PowerShell 7+, it works flawlessly across Windows, macOS, and Linux environments:

#requires -Version 7.0
#requires -Module Az.Accounts

<#
.SYNOPSIS
    Logic App ARM Template Export Script

.DESCRIPTION
    This script helps you select and export Logic Apps (including Sentinel Playbooks)
    as ARM templates. It guides you through selecting a tenant, subscription, resource group,
    and one or more Logic Apps. It can optionally generate templates suitable for gallery deployment
    and can update the required Az modules.

    It also allows you to change the default export location for the generated templates,
    and ensures you have both the Az.Accounts module and Microsoft.PowerShell.ConsoleGuiTools module
    installed, prompting you to install them if not found.

    This script is designed to run on PowerShell 7 or later, and is compatible with 
    Windows, macOS, and Linux environments.
#>

This cross-platform support is particularly valuable for diverse DevOps teams where engineers might be using different operating systems.

Error Handling

The script is designed with robust error handling throughout, ensuring graceful operation even when encountering issues:

try {
    $armTemplateJson | Out-File -FilePath $armFileName -Encoding UTF8
    Write-Log "Exported ARM Template for '$name' to '$armFileName'" -Severity Information
} catch {
    Write-Log "Failed to export ARM Template for '$name': $($_.Exception.Message)" -Severity Error
}

This comprehensive error handling ensures that even if one Logic App export fails, the script can continue with others, providing a more resilient export experience.

Conclusion

The Logic App ARM Template Export Script represents a significant advancement in Azure Logic App management. By automating the export process with meticulous attention to detail, it solves numerous challenges:

  1. It eliminates manual work through its guided, interactive approach to Logic App selection and export
  2. It ensures proper API connection handling by intelligently extracting and parameterizing connection information
  3. It supports special use cases like Microsoft Sentinel Content Hub Gallery submissions with specialized template formatting
  4. It maintains full fidelity of Logic App definitions while making them environment-agnostic for redeployment
  5. It works across platforms with full support for Windows, macOS, and Linux environments

For DevOps teams, cloud architects, and security professionals working with Logic Apps and Sentinel playbooks, this tool should become an essential part of your toolkit. It transforms what was once a tedious, error-prone process into a streamlined, consistent experienceβ€”saving time, reducing errors, and enabling more robust deployment practices.

The script's sophisticated approach to user interactionβ€”leveraging console grid views rather than traditional command-line parametersβ€”makes it accessible to both PowerShell experts and those with more limited scripting experience.

Give it a try today, and transform how you manage Logic Apps across your Azure environments!


Have you implemented automation for Logic App deployment in your environment? Share your experiences in the comments below!

Acknowledgements: Special thanks to Sreedhar Ande for the original Playbook-ARM-Template-Generator script that inspired this.