Automate the Busywork: How Nonprofits Can Use Power Automate to Extract and Process Form Data
July 1, 2025Azure Document Intelligence – How to Extract Data from PDFs and Scanned Files
July 1, 2025A few weeks ago, I presented the Bicep-Deploy GitHub Action that could test and deploy Bicep templates and validate, deploy, and delete deploymentStacks. The first part was about Bicep templates, the second is for deploymentStack.
With DeploymentStack you can perform these operations with bicep-deploy
- Validate, to lint the code.
- Create, to create a stack at the Management Group, Subscription, or Resource Group level.
- Delete, to delete a stack.
To illustrate this post, I will use a simple resource group-level template, creating a network infrastructure (a VNET with its subnets, and a Network Security Group.
param location string = resourceGroup().location
param vnetName string = 'mainVnet'
var vnetTags object = {
environment: 'production'
owner: 'admin'
}
var nsgRules = [
{
name: 'default-nsg'
rules: [
{
name: 'rule-deny-all'
properties: {
description: 'description'
protocol: 'Tcp'
sourcePortRange: '*'
destinationPortRange: '*'
sourceAddressPrefix: '*'
destinationAddressPrefix: '*'
access: 'Deny'
priority: 3000
direction: 'Inbound'
}
}
{
name: 'rule-allow-rdp'
properties: {
description: 'description'
protocol: 'Tcp'
sourcePortRange: '*'
destinationPortRange: '3389'
sourceAddressPrefix: '*'
destinationAddressPrefix: '*'
access: 'Allow'
priority: 150
direction: 'Inbound'
}
}
{
name: 'rule-allow-ssh'
properties: {
description: 'description'
protocol: 'Tcp'
sourcePortRange: '*'
destinationPortRange: '22'
sourceAddressPrefix: '*'
destinationAddressPrefix: '*'
access: 'Allow'
priority: 110
direction: 'Inbound'
}
}
]
}
]
resource NetworkSecurityGroups 'Microsoft.Network/networkSecurityGroups@2024-07-01' = [for rule in nsgRules: {
name: rule.name
location: resourceGroup().location
properties: {
securityRules: rule.rules
}
}]
resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-07-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
subnets: [
{
name: 'Subnet-1'
properties: {
addressPrefix: '10.0.0.0/24'
}
}
{
name: 'Subnet-2'
properties: {
addressPrefix: '10.0.1.0/24'
}
}
]
}
}
resource crutialSubnet 'Microsoft.Network/virtualNetworks/subnets@2024-07-01' = {
name: 'crucial'
parent: virtualNetwork
properties: {
addressPrefix: '10.0.2.0/24'
}
}
But first, let’s build the workflow. I will reuse the workflow from the first part for the connection.
name: Bicep-deploy stack demo
on:
push:
branches:
- main
permissions:
id-token: write
contents: read
jobs:
Bicep-deploy-demo:
name: Bicep-Deploy Stack
runs-on: ubuntu-latest
environment: DevTo-Demo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: login to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
enable-AzPSSession: true
Validating a deployment stack is similar to validating a Bicep code.
Before trying to validate a deploymentStack we need to make sure that the identity running the pipeline has the privilege to manage deploymentStack, including the deny settings; Azure Deployment Stack Contributor. Without this role, you will not be able to validate the stack.
- name: Validate deploymentStack Code in GitHub
uses: azure/bicep-deploy@v2
with:
type: deploymentStack
operation: validate
name: Validate-code
scope: resourceGroup
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
resource-group-name: bicep-deploy
template-file: ./Stack/vnet.bicep
action-on-unmanage-resources: delete
deny-settings-mode: denyWriteAndDelete
You will need to give the deploymentStack type, the operation, the scope (here at the resource group level), and what will happen to unmanaged resources (delete or detach) and deny settings (none, denyDelete or denyWriteAndDelete).
You can customize the validation by adding a bicepconfig.json file in the same directory. You can trigger an error if the validation finds unused variables or parameters. See
There is no whatif operation for deploymentStack to test what will be deployed, there are only two other operations create and delete.
The “Create” operation creates the deployment stack in the scope defined by the scope parameter (Management Group, Subscription, or resource group).
Here’s an example
- name: Validate deploymentStack Code in GitHub
uses: azure/bicep-deploy@v2
with:
type: deploymentStack
operation: create
name: create-stack
scope: resourceGroup
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
resource-group-name: bicep-deploy
template-file: ./Stack/vnet.bicep
action-on-unmanage-resources: delete
deny-settings-mode: denyWriteAndDelete
The same code we use to validate is used to deploy the Stack. In this example, the unmanaged resources are deleted, and users are not allowed to update or delete resources deployed by the stack. You can also use the deny-settings-excluded-actions to exclude action from the deny settings and deny-settings-excluded-principals to exclude a list of users/applications from the deny settings. Check this post for more details
Running the pipeline will create the deploymentStack create-stack.
The last operation that we can do with the bicep-deploy action. The delete operation is similar to the create operation. It takes the same parameters; you need to provide the name of the deployment, the scope, the template you used to deploy the stack (and parameters if any), the action-on-unmanage-resources and deny-settings-mode parameters (if you omit then you will have an error).
- name: Validate deploymentStack Code in GitHub
uses: azure/bicep-deploy@v2
with:
type: deploymentStack
operation: delete
name: create-stack
scope: resourceGroup
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
resource-group-name: bicep-deploy
template-file: ./Stack/vnet.bicep
action-on-unmanage-resources: delete
deny-settings-mode: denyWriteAndDelete
This will delete the deploymentStack object on the resource group and remove all resources associated with this stack.