From c4e873520542ae2d134684f9ec9707c30d17922a Mon Sep 17 00:00:00 2001
From: Erika Gressi <56914614+eriqua@users.noreply.github.com>
Date: Thu, 11 Apr 2024 06:27:47 +0100
Subject: [PATCH 1/9] fix: Platform scripts trigger exclusion missing in a few
 module validation workflows (#1643)

## Description

Platform scripts trigger exclusion missing in a few module validation
workflows

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
| N/A |

## Type of Change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [x] Update to CI Environment or utlities (Non-module effecting
changes)
- [ ] Azure Verified Module updates:
- [ ] Bugfix containing backwards compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [ ] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation

## Checklist

- [ ] I'm sure there are no other open Pull Requests for the same
update/change
- [ ] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [ ] My corresponding pipelines / checks run clean and green without
any errors or warnings

<!-- Please keep up to day with the contribution guide at
https://aka.ms/avm/contribute/bicep -->
---
 .github/workflows/avm.res.aad.domain-service.yml                 | 1 +
 .github/workflows/avm.res.container-instance.container-group.yml | 1 +
 .../workflows/avm.res.digital-twins.digital-twins-instance.yml   | 1 +
 .github/workflows/avm.res.network.service-endpoint-policy.yml    | 1 +
 .github/workflows/avm.res.recovery-services.vault.yml            | 1 +
 .github/workflows/avm.res.service-fabric.cluster.yml             | 1 +
 6 files changed, 6 insertions(+)

diff --git a/.github/workflows/avm.res.aad.domain-service.yml b/.github/workflows/avm.res.aad.domain-service.yml
index b5eb8d5e6a..b6c0a5883f 100644
--- a/.github/workflows/avm.res.aad.domain-service.yml
+++ b/.github/workflows/avm.res.aad.domain-service.yml
@@ -29,6 +29,7 @@ on:
       - ".github/workflows/avm.res.aad.domain-service.yml"
       - "avm/res/aad/domain-service/**"
       - "avm/utilities/pipelines/**"
+      - "!avm/utilities/pipelines/platform/**"
       - "!*/**/README.md"
 
 env:
diff --git a/.github/workflows/avm.res.container-instance.container-group.yml b/.github/workflows/avm.res.container-instance.container-group.yml
index 5f40c3cc22..9782de00fa 100644
--- a/.github/workflows/avm.res.container-instance.container-group.yml
+++ b/.github/workflows/avm.res.container-instance.container-group.yml
@@ -29,6 +29,7 @@ on:
       - ".github/workflows/avm.res.container-instance.container-group.yml"
       - "avm/res/container-instance/container-group/**"
       - "avm/utilities/pipelines/**"
+      - "!avm/utilities/pipelines/platform/**"
       - "!*/**/README.md"
 
 env:
diff --git a/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml b/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml
index 71b6b56d1a..fc9e6fb5da 100644
--- a/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml
+++ b/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml
@@ -29,6 +29,7 @@ on:
       - ".github/workflows/avm.res.digital-twins.digital-twins-instance.yml"
       - "avm/res/digital-twins/digital-twins-instance/**"
       - "avm/utilities/pipelines/**"
+      - "!avm/utilities/pipelines/platform/**"
       - "!*/**/README.md"
 
 env:
diff --git a/.github/workflows/avm.res.network.service-endpoint-policy.yml b/.github/workflows/avm.res.network.service-endpoint-policy.yml
index def975dfe0..80e26edeac 100644
--- a/.github/workflows/avm.res.network.service-endpoint-policy.yml
+++ b/.github/workflows/avm.res.network.service-endpoint-policy.yml
@@ -29,6 +29,7 @@ on:
       - ".github/workflows/avm.res.network.service-endpoint-policy.yml"
       - "avm/res/network/service-endpoint-policy/**"
       - "avm/utilities/pipelines/**"
+      - "!avm/utilities/pipelines/platform/**"
       - "!*/**/README.md"
 
 env:
diff --git a/.github/workflows/avm.res.recovery-services.vault.yml b/.github/workflows/avm.res.recovery-services.vault.yml
index bc630cebbc..9d5a1dc1ff 100644
--- a/.github/workflows/avm.res.recovery-services.vault.yml
+++ b/.github/workflows/avm.res.recovery-services.vault.yml
@@ -29,6 +29,7 @@ on:
       - ".github/workflows/avm.res.recovery-services.vault.yml"
       - "avm/res/recovery-services/vault/**"
       - "avm/utilities/pipelines/**"
+      - "!avm/utilities/pipelines/platform/**"
       - "!*/**/README.md"
 
 env:
diff --git a/.github/workflows/avm.res.service-fabric.cluster.yml b/.github/workflows/avm.res.service-fabric.cluster.yml
index 93c11bbf84..2e2c93206c 100644
--- a/.github/workflows/avm.res.service-fabric.cluster.yml
+++ b/.github/workflows/avm.res.service-fabric.cluster.yml
@@ -29,6 +29,7 @@ on:
       - ".github/workflows/avm.res.service-fabric.cluster.yml"
       - "avm/res/service-fabric/cluster/**"
       - "avm/utilities/pipelines/**"
+      - "!avm/utilities/pipelines/platform/**"
       - "!*/**/README.md"
 
 env:

From afeaf3eafef3d031590bcb3dd509ad57d171e8b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Wenjie=20Yu=EF=BC=88MSFT=EF=BC=89?=
 <81678720+zedy-wj@users.noreply.github.com>
Date: Thu, 11 Apr 2024 15:00:55 +0800
Subject: [PATCH 2/9] feat: Add output 'kubeletidentityClientId' and
 'kubeletidentityResourceId' in AKS Module -
 `avm/res/container-service/managed-cluster` (#1464)

Fixed issue #1128.

Updated content:

- Add output `kubeletidentityClientId` and `kubeletidentityResourceId`
in AKS Module.
- Update readme file in AKS Module.

@jongio for notification.

---------

Co-authored-by: zedy <zedy@wicresoft.com>
Co-authored-by: Alexander Sehr <ASehr@hotmail.de>
---
 .../container-service/managed-cluster/README.md  |  4 +++-
 .../container-service/managed-cluster/main.bicep |  8 +++++++-
 .../container-service/managed-cluster/main.json  | 16 +++++++++++++++-
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/avm/res/container-service/managed-cluster/README.md b/avm/res/container-service/managed-cluster/README.md
index ec4fc5f535..9c6755ddb5 100644
--- a/avm/res/container-service/managed-cluster/README.md
+++ b/avm/res/container-service/managed-cluster/README.md
@@ -3233,7 +3233,9 @@ Specifies whether the webApplicationRoutingEnabled add-on is enabled or not.
 | `ingressApplicationGatewayIdentityObjectId` | string | The Object ID of Application Gateway Ingress Controller (AGIC) identity. |
 | `keyvaultIdentityClientId` | string | The Client ID of the Key Vault Secrets Provider identity. |
 | `keyvaultIdentityObjectId` | string | The Object ID of the Key Vault Secrets Provider identity. |
-| `kubeletidentityObjectId` | string | The Object ID of the AKS identity. |
+| `kubeletIdentityClientId` | string | The Client ID of the AKS identity. |
+| `kubeletIdentityObjectId` | string | The Object ID of the AKS identity. |
+| `kubeletIdentityResourceId` | string | The Resource ID of the AKS identity. |
 | `location` | string | The location the resource was deployed into. |
 | `name` | string | The name of the managed cluster. |
 | `oidcIssuerUrl` | string | The OIDC token issuer URL. |
diff --git a/avm/res/container-service/managed-cluster/main.bicep b/avm/res/container-service/managed-cluster/main.bicep
index 492fb55b86..d8ffe6bc8f 100644
--- a/avm/res/container-service/managed-cluster/main.bicep
+++ b/avm/res/container-service/managed-cluster/main.bicep
@@ -892,8 +892,14 @@ output controlPlaneFQDN string = enablePrivateCluster
 @description('The principal ID of the system assigned identity.')
 output systemAssignedMIPrincipalId string = managedCluster.?identity.?principalId ?? ''
 
+@description('The Client ID of the AKS identity.')
+output kubeletIdentityClientId string = managedCluster.properties.?identityProfile.?kubeletidentity.?clientId ?? ''
+
 @description('The Object ID of the AKS identity.')
-output kubeletidentityObjectId string = managedCluster.properties.?identityProfile.?kubeletidentity.?objectId ?? ''
+output kubeletIdentityObjectId string = managedCluster.properties.?identityProfile.?kubeletidentity.?objectId ?? ''
+
+@description('The Resource ID of the AKS identity.')
+output kubeletIdentityResourceId string = managedCluster.properties.?identityProfile.?kubeletidentity.?resourceId ?? ''
 
 @description('The Object ID of the OMS agent identity.')
 output omsagentIdentityObjectId string = managedCluster.properties.?addonProfiles.?omsagent.?identity.?objectId ?? ''
diff --git a/avm/res/container-service/managed-cluster/main.json b/avm/res/container-service/managed-cluster/main.json
index e1f4ab5d28..b8fc5076be 100644
--- a/avm/res/container-service/managed-cluster/main.json
+++ b/avm/res/container-service/managed-cluster/main.json
@@ -2736,13 +2736,27 @@
       },
       "value": "[coalesce(tryGet(tryGet(reference('managedCluster', '2023-07-02-preview', 'full'), 'identity'), 'principalId'), '')]"
     },
-    "kubeletidentityObjectId": {
+    "kubeletIdentityClientId": {
+      "type": "string",
+      "metadata": {
+        "description": "The Client ID of the AKS identity."
+      },
+      "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'clientId'), '')]"
+    },
+    "kubeletIdentityObjectId": {
       "type": "string",
       "metadata": {
         "description": "The Object ID of the AKS identity."
       },
       "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'objectId'), '')]"
     },
+    "kubeletIdentityResourceId": {
+      "type": "string",
+      "metadata": {
+        "description": "The Resource ID of the AKS identity."
+      },
+      "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'resourceId'), '')]"
+    },
     "omsagentIdentityObjectId": {
       "type": "string",
       "metadata": {

From 80175c7cb472658bb0e3599afab4f331f603f11e Mon Sep 17 00:00:00 2001
From: Pierre Malarme <pmalarme@gmail.com>
Date: Thu, 11 Apr 2024 10:08:23 +0200
Subject: [PATCH 3/9] fix: Fix virtual machine warnings for max price of the
 billing profile and the type of the identity -
 `avm/res/compute/virtual-machine` (#1617)

## Description

This PR fixes 2 Bicep warning BCP036:
* Missing space between `SystemAssigned` and `UserAssigned` for the type
of the identity
* The value of `maxPrice` for the billing profile needs to be an integer
or a json decimal:
https://learn.microsoft.com/en-us/azure/templates/microsoft.compute/2022-11-01/virtualmachines?pivots=deployment-language-bicep#billingprofile.
By using `json()` function, I ensure that this value is converted to
`int` or json decimal.

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|          |

## Type of Change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utlities (Non-module effecting
changes)
- [x] Azure Verified Module updates:
- [ ] Bugfix containing backwards compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [x] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation

## Checklist

- [ ] I'm sure there are no other open Pull Requests for the same
update/change
- [ ] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [ ] My corresponding pipelines / checks run clean and green without
any errors or warnings

<!-- Please keep up to day with the contribution guide at
https://aka.ms/avm/contribute/bicep -->

---------

Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com>
---
 avm/res/compute/virtual-machine/main.bicep   | 4 ++--
 avm/res/compute/virtual-machine/version.json | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/avm/res/compute/virtual-machine/main.bicep b/avm/res/compute/virtual-machine/main.bicep
index a15b26418c..1fe7b22def 100644
--- a/avm/res/compute/virtual-machine/main.bicep
+++ b/avm/res/compute/virtual-machine/main.bicep
@@ -330,7 +330,7 @@ var formattedUserAssignedIdentities = reduce(
 var identity = !empty(managedIdentities)
   ? {
       type: (extensionAadJoinConfig.enabled ? true : (managedIdentities.?systemAssigned ?? false))
-        ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned')
+        ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned')
         : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null)
       userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null
     }
@@ -554,7 +554,7 @@ resource vm 'Microsoft.Compute/virtualMachines@2022-11-01' = {
     evictionPolicy: enableEvictionPolicy ? 'Deallocate' : null
     billingProfile: !empty(priority) && !empty(maxPriceForLowPriorityVm)
       ? {
-          maxPrice: maxPriceForLowPriorityVm
+          maxPrice: json(maxPriceForLowPriorityVm)
         }
       : null
     host: !empty(dedicatedHostId)
diff --git a/avm/res/compute/virtual-machine/version.json b/avm/res/compute/virtual-machine/version.json
index 729ac87673..76049e1c4a 100644
--- a/avm/res/compute/virtual-machine/version.json
+++ b/avm/res/compute/virtual-machine/version.json
@@ -1,6 +1,6 @@
 {
   "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#",
-  "version": "0.2",
+  "version": "0.3",
   "pathFilters": [
     "./main.json"
   ]

From b71115c2d46c3e01241a62e0d0ebb40632b546bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= <sebastian@graef.io>
Date: Thu, 11 Apr 2024 18:47:04 +1000
Subject: [PATCH 4/9] feat: module `avm/res/network/network-watcher` (#1478)

## Description

Closes https://github.com/Azure/Azure-Verified-Modules/issues/581

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|
[![avm.res.network.network-watcher](https://github.com/segraef/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml/badge.svg?branch=nw)](https://github.com/segraef/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml)
|

## Type of Change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utlities (Non-module effecting
changes)
- [x] Azure Verified Module updates:
- [ ] Bugfix containing backwards compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [ ] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [x] Update to documentation

## Checklist

- [x] I'm sure there are no other open Pull Requests for the same
update/change
- [x] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [x] My corresponding pipelines / checks run clean and green without
any errors or warnings

<!-- Please keep up to day with the contribution guide at
https://aka.ms/avm/contribute/bicep -->

---------

Co-authored-by: Alexander Sehr <ASehr@hotmail.de>
Co-authored-by: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com>
Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com>
---
 .github/CODEOWNERS                            |   2 +-
 .github/ISSUE_TEMPLATE/avm_module_issue.yml   |   2 +-
 .../avm.res.network.network-watcher.yml       |  87 +++
 avm/res/network/network-watcher/README.md     | 712 ++++++++++++++++++
 .../connection-monitor/README.md              | 117 +++
 .../connection-monitor/main.bicep             |  66 ++
 .../connection-monitor/main.json              | 126 ++++
 .../network-watcher/flow-log/README.md        | 158 ++++
 .../network-watcher/flow-log/main.bicep       |  97 +++
 .../network-watcher/flow-log/main.json        | 167 ++++
 avm/res/network/network-watcher/main.bicep    | 188 +++++
 avm/res/network/network-watcher/main.json     | 633 ++++++++++++++++
 .../tests/e2e/defaults/main.test.bicep        |  51 ++
 .../tests/e2e/max/dependencies.bicep          | 144 ++++
 .../tests/e2e/max/main.test.bicep             | 172 +++++
 .../tests/e2e/waf-aligned/dependencies.bicep  | 144 ++++
 .../tests/e2e/waf-aligned/main.test.bicep     | 156 ++++
 avm/res/network/network-watcher/version.json  |   7 +
 18 files changed, 3027 insertions(+), 2 deletions(-)
 create mode 100644 .github/workflows/avm.res.network.network-watcher.yml
 create mode 100644 avm/res/network/network-watcher/README.md
 create mode 100644 avm/res/network/network-watcher/connection-monitor/README.md
 create mode 100644 avm/res/network/network-watcher/connection-monitor/main.bicep
 create mode 100644 avm/res/network/network-watcher/connection-monitor/main.json
 create mode 100644 avm/res/network/network-watcher/flow-log/README.md
 create mode 100644 avm/res/network/network-watcher/flow-log/main.bicep
 create mode 100644 avm/res/network/network-watcher/flow-log/main.json
 create mode 100644 avm/res/network/network-watcher/main.bicep
 create mode 100644 avm/res/network/network-watcher/main.json
 create mode 100644 avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep
 create mode 100644 avm/res/network/network-watcher/tests/e2e/max/dependencies.bicep
 create mode 100644 avm/res/network/network-watcher/tests/e2e/max/main.test.bicep
 create mode 100644 avm/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep
 create mode 100644 avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep
 create mode 100644 avm/res/network/network-watcher/version.json

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index aeceb727dd..dd7d4654fc 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -98,7 +98,7 @@
 /avm/res/network/network-interface/ @Azure/avm-res-network-networkinterface-module-owners-bicep @Azure/avm-core-team-technical-bicep
 /avm/res/network/network-manager/ @Azure/avm-res-network-networkmanager-module-owners-bicep @Azure/avm-core-team-technical-bicep
 /avm/res/network/network-security-group/ @Azure/avm-res-network-networksecuritygroup-module-owners-bicep @Azure/avm-core-team-technical-bicep
-#/avm/res/network/network-watcher/ @Azure/avm-res-network-networkwatcher-module-owners-bicep @Azure/avm-core-team-technical-bicep
+/avm/res/network/network-watcher/ @Azure/avm-res-network-networkwatcher-module-owners-bicep @Azure/avm-core-team-technical-bicep
 /avm/res/network/private-dns-zone/ @Azure/avm-res-network-privatednszone-module-owners-bicep @Azure/avm-core-team-technical-bicep
 /avm/res/network/private-endpoint/ @Azure/avm-res-network-privateendpoint-module-owners-bicep @Azure/avm-core-team-technical-bicep
 /avm/res/network/private-link-service/ @Azure/avm-res-network-privatelinkservice-module-owners-bicep @Azure/avm-core-team-technical-bicep
diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml
index a1f30bffbc..9fea2a0a2e 100644
--- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml
+++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml
@@ -131,7 +131,7 @@ body:
         - "avm/res/network/network-interface"
         - "avm/res/network/network-manager"
         - "avm/res/network/network-security-group"
-        # - "avm/res/network/network-watcher"
+        - "avm/res/network/network-watcher"
         - "avm/res/network/private-dns-zone"
         - "avm/res/network/private-endpoint"
         - "avm/res/network/private-link-service"
diff --git a/.github/workflows/avm.res.network.network-watcher.yml b/.github/workflows/avm.res.network.network-watcher.yml
new file mode 100644
index 0000000000..823b4baf3e
--- /dev/null
+++ b/.github/workflows/avm.res.network.network-watcher.yml
@@ -0,0 +1,87 @@
+name: "avm.res.network.network-watcher"
+
+on:
+  schedule:
+    - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month)
+  workflow_dispatch:
+    inputs:
+      staticValidation:
+        type: boolean
+        description: "Execute static validation"
+        required: false
+        default: true
+      deploymentValidation:
+        type: boolean
+        description: "Execute deployment validation"
+        required: false
+        default: true
+      removeDeployment:
+        type: boolean
+        description: "Remove deployed module"
+        required: false
+        default: true
+
+  push:
+    branches:
+      - main
+    paths:
+      - ".github/actions/templates/avm-**"
+      - ".github/workflows/avm.template.module.yml"
+      - ".github/workflows/avm.res.network.network-watcher.yml"
+      - "avm/res/network/network-watcher/**"
+      - "avm/utilities/pipelines/**"
+      - "!avm/utilities/pipelines/platform/**"
+      - "!*/**/README.md"
+
+env:
+  modulePath: "avm/res/network/network-watcher"
+  workflowPath: ".github/workflows/avm.res.network.network-watcher.yml"
+
+concurrency:
+  group: ${{ github.workflow }}
+
+jobs:
+  ###########################
+  #   Initialize pipeline   #
+  ###########################
+  job_initialize_pipeline:
+    runs-on: ubuntu-latest
+    name: "Initialize pipeline"
+    steps:
+      - name: "Checkout"
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+      - name: "Set input parameters to output variables"
+        id: get-workflow-param
+        uses: ./.github/actions/templates/avm-getWorkflowInput
+        with:
+          workflowPath: "${{ env.workflowPath}}"
+      - name: "Get module test file paths"
+        id: get-module-test-file-paths
+        uses: ./.github/actions/templates/avm-getModuleTestFiles
+        with:
+          modulePath: "${{ env.modulePath }}"
+    outputs:
+      workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }}
+      moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }}
+      psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }}
+      modulePath: "${{ env.modulePath }}"
+
+  ##############################
+  #   Call reusable workflow   #
+  ##############################
+  call-workflow-passing-data:
+    name: "Run"
+    permissions:
+      id-token: write # For OIDC
+      contents: write # For release tags
+    needs:
+      - job_initialize_pipeline
+    uses: ./.github/workflows/avm.template.module.yml
+    with:
+      workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}"
+      moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}"
+      psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}"
+      modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}"
+    secrets: inherit
diff --git a/avm/res/network/network-watcher/README.md b/avm/res/network/network-watcher/README.md
new file mode 100644
index 0000000000..b415feec56
--- /dev/null
+++ b/avm/res/network/network-watcher/README.md
@@ -0,0 +1,712 @@
+# Network Watchers `[Microsoft.Network/networkWatchers]`
+
+This module deploys a Network Watcher.
+
+## Navigation
+
+- [Resource Types](#Resource-Types)
+- [Usage examples](#Usage-examples)
+- [Parameters](#Parameters)
+- [Outputs](#Outputs)
+- [Cross-referenced modules](#Cross-referenced-modules)
+- [Data Collection](#Data-Collection)
+
+## Resource Types
+
+| Resource Type | API Version |
+| :-- | :-- |
+| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) |
+| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) |
+| `Microsoft.Network/networkWatchers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers) |
+| `Microsoft.Network/networkWatchers/connectionMonitors` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers/connectionMonitors) |
+| `Microsoft.Network/networkWatchers/flowLogs` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers/flowLogs) |
+
+## Usage examples
+
+The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository.
+
+>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order.
+
+>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/network-watcher:<version>`.
+
+- [Using only defaults](#example-1-using-only-defaults)
+- [Using large parameter set](#example-2-using-large-parameter-set)
+- [WAF-aligned](#example-3-waf-aligned)
+
+### Example 1: _Using only defaults_
+
+This instance deploys the module with the minimum set of required parameters.
+
+
+<details>
+
+<summary>via Bicep module</summary>
+
+```bicep
+module networkWatcher 'br/public:avm/res/network/network-watcher:<version>' = {
+  name: 'networkWatcherDeployment'
+  params: {
+    location: '<location>'
+  }
+}
+```
+
+</details>
+<p>
+
+<details>
+
+<summary>via JSON Parameter file</summary>
+
+```json
+{
+  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+  "contentVersion": "1.0.0.0",
+  "parameters": {
+    "location": {
+      "value": "<location>"
+    }
+  }
+}
+```
+
+</details>
+<p>
+
+### Example 2: _Using large parameter set_
+
+This instance deploys the module with most of its features enabled.
+
+
+<details>
+
+<summary>via Bicep module</summary>
+
+```bicep
+module networkWatcher 'br/public:avm/res/network/network-watcher:<version>' = {
+  name: 'networkWatcherDeployment'
+  params: {
+    connectionMonitors: [
+      {
+        endpoints: [
+          {
+            name: '<name>'
+            resourceId: '<resourceId>'
+            type: 'AzureVM'
+          }
+          {
+            address: 'www.bing.com'
+            name: 'Bing'
+            type: 'ExternalAddress'
+          }
+        ]
+        name: 'nnwmax-cm-001'
+        testConfigurations: [
+          {
+            httpConfiguration: {
+              method: 'Get'
+              port: 80
+              preferHTTPS: false
+              requestHeaders: []
+              validStatusCodeRanges: [
+                '200'
+              ]
+            }
+            name: 'HTTP Bing Test'
+            protocol: 'Http'
+            successThreshold: {
+              checksFailedPercent: 5
+              roundTripTimeMs: 100
+            }
+            testFrequencySec: 30
+          }
+        ]
+        testGroups: [
+          {
+            destinations: [
+              'Bing'
+            ]
+            disable: false
+            name: 'test-http-Bing'
+            sources: [
+              'subnet-001(${resourceGroup.name})'
+            ]
+            testConfigurations: [
+              'HTTP Bing Test'
+            ]
+          }
+        ]
+        workspaceResourceId: '<workspaceResourceId>'
+      }
+    ]
+    flowLogs: [
+      {
+        enabled: false
+        storageId: '<storageId>'
+        targetResourceId: '<targetResourceId>'
+      }
+      {
+        formatVersion: 1
+        name: 'nnwmax-fl-001'
+        retentionInDays: 8
+        storageId: '<storageId>'
+        targetResourceId: '<targetResourceId>'
+        trafficAnalyticsInterval: 10
+        workspaceResourceId: '<workspaceResourceId>'
+      }
+    ]
+    location: '<location>'
+    name: '<name>'
+    roleAssignments: [
+      {
+        principalId: '<principalId>'
+        principalType: 'ServicePrincipal'
+        roleDefinitionIdOrName: 'Owner'
+      }
+      {
+        principalId: '<principalId>'
+        principalType: 'ServicePrincipal'
+        roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
+      }
+      {
+        principalId: '<principalId>'
+        principalType: 'ServicePrincipal'
+        roleDefinitionIdOrName: '<roleDefinitionIdOrName>'
+      }
+    ]
+    tags: {
+      Environment: 'Non-Prod'
+      'hidden-title': 'This is visible in the resource name'
+      Role: 'DeploymentValidation'
+    }
+  }
+}
+```
+
+</details>
+<p>
+
+<details>
+
+<summary>via JSON Parameter file</summary>
+
+```json
+{
+  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+  "contentVersion": "1.0.0.0",
+  "parameters": {
+    "connectionMonitors": {
+      "value": [
+        {
+          "endpoints": [
+            {
+              "name": "<name>",
+              "resourceId": "<resourceId>",
+              "type": "AzureVM"
+            },
+            {
+              "address": "www.bing.com",
+              "name": "Bing",
+              "type": "ExternalAddress"
+            }
+          ],
+          "name": "nnwmax-cm-001",
+          "testConfigurations": [
+            {
+              "httpConfiguration": {
+                "method": "Get",
+                "port": 80,
+                "preferHTTPS": false,
+                "requestHeaders": [],
+                "validStatusCodeRanges": [
+                  "200"
+                ]
+              },
+              "name": "HTTP Bing Test",
+              "protocol": "Http",
+              "successThreshold": {
+                "checksFailedPercent": 5,
+                "roundTripTimeMs": 100
+              },
+              "testFrequencySec": 30
+            }
+          ],
+          "testGroups": [
+            {
+              "destinations": [
+                "Bing"
+              ],
+              "disable": false,
+              "name": "test-http-Bing",
+              "sources": [
+                "subnet-001(${resourceGroup.name})"
+              ],
+              "testConfigurations": [
+                "HTTP Bing Test"
+              ]
+            }
+          ],
+          "workspaceResourceId": "<workspaceResourceId>"
+        }
+      ]
+    },
+    "flowLogs": {
+      "value": [
+        {
+          "enabled": false,
+          "storageId": "<storageId>",
+          "targetResourceId": "<targetResourceId>"
+        },
+        {
+          "formatVersion": 1,
+          "name": "nnwmax-fl-001",
+          "retentionInDays": 8,
+          "storageId": "<storageId>",
+          "targetResourceId": "<targetResourceId>",
+          "trafficAnalyticsInterval": 10,
+          "workspaceResourceId": "<workspaceResourceId>"
+        }
+      ]
+    },
+    "location": {
+      "value": "<location>"
+    },
+    "name": {
+      "value": "<name>"
+    },
+    "roleAssignments": {
+      "value": [
+        {
+          "principalId": "<principalId>",
+          "principalType": "ServicePrincipal",
+          "roleDefinitionIdOrName": "Owner"
+        },
+        {
+          "principalId": "<principalId>",
+          "principalType": "ServicePrincipal",
+          "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c"
+        },
+        {
+          "principalId": "<principalId>",
+          "principalType": "ServicePrincipal",
+          "roleDefinitionIdOrName": "<roleDefinitionIdOrName>"
+        }
+      ]
+    },
+    "tags": {
+      "value": {
+        "Environment": "Non-Prod",
+        "hidden-title": "This is visible in the resource name",
+        "Role": "DeploymentValidation"
+      }
+    }
+  }
+}
+```
+
+</details>
+<p>
+
+### Example 3: _WAF-aligned_
+
+This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.
+
+
+<details>
+
+<summary>via Bicep module</summary>
+
+```bicep
+module networkWatcher 'br/public:avm/res/network/network-watcher:<version>' = {
+  name: 'networkWatcherDeployment'
+  params: {
+    connectionMonitors: [
+      {
+        endpoints: [
+          {
+            name: '<name>'
+            resourceId: '<resourceId>'
+            type: 'AzureVM'
+          }
+          {
+            address: 'www.bing.com'
+            name: 'Bing'
+            type: 'ExternalAddress'
+          }
+        ]
+        name: 'nnwwaf-cm-001'
+        testConfigurations: [
+          {
+            httpConfiguration: {
+              method: 'Get'
+              port: 80
+              preferHTTPS: false
+              requestHeaders: []
+              validStatusCodeRanges: [
+                '200'
+              ]
+            }
+            name: 'HTTP Bing Test'
+            protocol: 'Http'
+            successThreshold: {
+              checksFailedPercent: 5
+              roundTripTimeMs: 100
+            }
+            testFrequencySec: 30
+          }
+        ]
+        testGroups: [
+          {
+            destinations: [
+              'Bing'
+            ]
+            disable: false
+            name: 'test-http-Bing'
+            sources: [
+              'subnet-001(${resourceGroup.name})'
+            ]
+            testConfigurations: [
+              'HTTP Bing Test'
+            ]
+          }
+        ]
+        workspaceResourceId: '<workspaceResourceId>'
+      }
+    ]
+    flowLogs: [
+      {
+        enabled: false
+        storageId: '<storageId>'
+        targetResourceId: '<targetResourceId>'
+      }
+      {
+        formatVersion: 1
+        name: 'nnwwaf-fl-001'
+        retentionInDays: 8
+        storageId: '<storageId>'
+        targetResourceId: '<targetResourceId>'
+        trafficAnalyticsInterval: 10
+        workspaceResourceId: '<workspaceResourceId>'
+      }
+    ]
+    location: '<location>'
+    name: '<name>'
+    tags: {
+      Environment: 'Non-Prod'
+      'hidden-title': 'This is visible in the resource name'
+      Role: 'DeploymentValidation'
+    }
+  }
+}
+```
+
+</details>
+<p>
+
+<details>
+
+<summary>via JSON Parameter file</summary>
+
+```json
+{
+  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+  "contentVersion": "1.0.0.0",
+  "parameters": {
+    "connectionMonitors": {
+      "value": [
+        {
+          "endpoints": [
+            {
+              "name": "<name>",
+              "resourceId": "<resourceId>",
+              "type": "AzureVM"
+            },
+            {
+              "address": "www.bing.com",
+              "name": "Bing",
+              "type": "ExternalAddress"
+            }
+          ],
+          "name": "nnwwaf-cm-001",
+          "testConfigurations": [
+            {
+              "httpConfiguration": {
+                "method": "Get",
+                "port": 80,
+                "preferHTTPS": false,
+                "requestHeaders": [],
+                "validStatusCodeRanges": [
+                  "200"
+                ]
+              },
+              "name": "HTTP Bing Test",
+              "protocol": "Http",
+              "successThreshold": {
+                "checksFailedPercent": 5,
+                "roundTripTimeMs": 100
+              },
+              "testFrequencySec": 30
+            }
+          ],
+          "testGroups": [
+            {
+              "destinations": [
+                "Bing"
+              ],
+              "disable": false,
+              "name": "test-http-Bing",
+              "sources": [
+                "subnet-001(${resourceGroup.name})"
+              ],
+              "testConfigurations": [
+                "HTTP Bing Test"
+              ]
+            }
+          ],
+          "workspaceResourceId": "<workspaceResourceId>"
+        }
+      ]
+    },
+    "flowLogs": {
+      "value": [
+        {
+          "enabled": false,
+          "storageId": "<storageId>",
+          "targetResourceId": "<targetResourceId>"
+        },
+        {
+          "formatVersion": 1,
+          "name": "nnwwaf-fl-001",
+          "retentionInDays": 8,
+          "storageId": "<storageId>",
+          "targetResourceId": "<targetResourceId>",
+          "trafficAnalyticsInterval": 10,
+          "workspaceResourceId": "<workspaceResourceId>"
+        }
+      ]
+    },
+    "location": {
+      "value": "<location>"
+    },
+    "name": {
+      "value": "<name>"
+    },
+    "tags": {
+      "value": {
+        "Environment": "Non-Prod",
+        "hidden-title": "This is visible in the resource name",
+        "Role": "DeploymentValidation"
+      }
+    }
+  }
+}
+```
+
+</details>
+<p>
+
+
+## Parameters
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`connectionMonitors`](#parameter-connectionmonitors) | array | Array that contains the Connection Monitors. |
+| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. |
+| [`flowLogs`](#parameter-flowlogs) | array | Array that contains the Flow Logs. |
+| [`location`](#parameter-location) | string | Location for all resources. |
+| [`lock`](#parameter-lock) | object | The lock settings of the service. |
+| [`name`](#parameter-name) | string | Name of the Network Watcher resource (hidden). |
+| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. |
+| [`tags`](#parameter-tags) | object | Tags of the resource. |
+
+### Parameter: `connectionMonitors`
+
+Array that contains the Connection Monitors.
+
+- Required: No
+- Type: array
+- Default: `[]`
+
+### Parameter: `enableTelemetry`
+
+Enable/Disable usage telemetry for module.
+
+- Required: No
+- Type: bool
+- Default: `True`
+
+### Parameter: `flowLogs`
+
+Array that contains the Flow Logs.
+
+- Required: No
+- Type: array
+- Default: `[]`
+
+### Parameter: `location`
+
+Location for all resources.
+
+- Required: No
+- Type: string
+- Default: `[resourceGroup().location]`
+
+### Parameter: `lock`
+
+The lock settings of the service.
+
+- Required: No
+- Type: object
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`kind`](#parameter-lockkind) | string | Specify the type of lock. |
+| [`name`](#parameter-lockname) | string | Specify the name of lock. |
+
+### Parameter: `lock.kind`
+
+Specify the type of lock.
+
+- Required: No
+- Type: string
+- Allowed:
+  ```Bicep
+  [
+    'CanNotDelete'
+    'None'
+    'ReadOnly'
+  ]
+  ```
+
+### Parameter: `lock.name`
+
+Specify the name of lock.
+
+- Required: No
+- Type: string
+
+### Parameter: `name`
+
+Name of the Network Watcher resource (hidden).
+
+- Required: No
+- Type: string
+- Default: `[format('NetworkWatcher_{0}', parameters('location'))]`
+
+### Parameter: `roleAssignments`
+
+Array of role assignments to create.
+
+- Required: No
+- Type: array
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. |
+| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". |
+| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. |
+| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. |
+| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. |
+| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. |
+
+### Parameter: `roleAssignments.principalId`
+
+The principal ID of the principal (user/group/identity) to assign the role to.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `roleAssignments.roleDefinitionIdOrName`
+
+The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `roleAssignments.condition`
+
+The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".
+
+- Required: No
+- Type: string
+
+### Parameter: `roleAssignments.conditionVersion`
+
+Version of the condition.
+
+- Required: No
+- Type: string
+- Allowed:
+  ```Bicep
+  [
+    '2.0'
+  ]
+  ```
+
+### Parameter: `roleAssignments.delegatedManagedIdentityResourceId`
+
+The Resource Id of the delegated managed identity resource.
+
+- Required: No
+- Type: string
+
+### Parameter: `roleAssignments.description`
+
+The description of the role assignment.
+
+- Required: No
+- Type: string
+
+### Parameter: `roleAssignments.principalType`
+
+The principal type of the assigned principal ID.
+
+- Required: No
+- Type: string
+- Allowed:
+  ```Bicep
+  [
+    'Device'
+    'ForeignGroup'
+    'Group'
+    'ServicePrincipal'
+    'User'
+  ]
+  ```
+
+### Parameter: `tags`
+
+Tags of the resource.
+
+- Required: No
+- Type: object
+
+
+## Outputs
+
+| Output | Type | Description |
+| :-- | :-- | :-- |
+| `location` | string | The location the resource was deployed into. |
+| `name` | string | The name of the deployed network watcher. |
+| `resourceGroupName` | string | The resource group the network watcher was deployed into. |
+| `resourceId` | string | The resource ID of the deployed network watcher. |
+
+## Cross-referenced modules
+
+_None_
+
+## Data Collection
+
+The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at <https://go.microsoft.com/fwlink/?LinkID=824704>. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
diff --git a/avm/res/network/network-watcher/connection-monitor/README.md b/avm/res/network/network-watcher/connection-monitor/README.md
new file mode 100644
index 0000000000..8ca9cfd750
--- /dev/null
+++ b/avm/res/network/network-watcher/connection-monitor/README.md
@@ -0,0 +1,117 @@
+# Network Watchers Connection Monitors `[Microsoft.Network/networkWatchers/connectionMonitors]`
+
+This module deploys a Network Watcher Connection Monitor.
+
+## Navigation
+
+- [Resource Types](#Resource-Types)
+- [Parameters](#Parameters)
+- [Outputs](#Outputs)
+- [Cross-referenced modules](#Cross-referenced-modules)
+- [Data Collection](#Data-Collection)
+
+## Resource Types
+
+| Resource Type | API Version |
+| :-- | :-- |
+| `Microsoft.Network/networkWatchers/connectionMonitors` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers/connectionMonitors) |
+
+## Parameters
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-name) | string | Name of the resource. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`endpoints`](#parameter-endpoints) | array | List of connection monitor endpoints. |
+| [`location`](#parameter-location) | string | Location for all resources. |
+| [`networkWatcherName`](#parameter-networkwatchername) | string | Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. |
+| [`tags`](#parameter-tags) | object | Tags of the resource. |
+| [`testConfigurations`](#parameter-testconfigurations) | array | List of connection monitor test configurations. |
+| [`testGroups`](#parameter-testgroups) | array | List of connection monitor test groups. |
+| [`workspaceResourceId`](#parameter-workspaceresourceid) | string | Specify the Log Analytics Workspace Resource ID. |
+
+### Parameter: `name`
+
+Name of the resource.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `endpoints`
+
+List of connection monitor endpoints.
+
+- Required: No
+- Type: array
+- Default: `[]`
+
+### Parameter: `location`
+
+Location for all resources.
+
+- Required: No
+- Type: string
+- Default: `[resourceGroup().location]`
+
+### Parameter: `networkWatcherName`
+
+Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG.
+
+- Required: No
+- Type: string
+- Default: `[format('NetworkWatcher_{0}', resourceGroup().location)]`
+
+### Parameter: `tags`
+
+Tags of the resource.
+
+- Required: No
+- Type: object
+
+### Parameter: `testConfigurations`
+
+List of connection monitor test configurations.
+
+- Required: No
+- Type: array
+- Default: `[]`
+
+### Parameter: `testGroups`
+
+List of connection monitor test groups.
+
+- Required: No
+- Type: array
+- Default: `[]`
+
+### Parameter: `workspaceResourceId`
+
+Specify the Log Analytics Workspace Resource ID.
+
+- Required: No
+- Type: string
+- Default: `''`
+
+
+## Outputs
+
+| Output | Type | Description |
+| :-- | :-- | :-- |
+| `location` | string | The location the resource was deployed into. |
+| `name` | string | The name of the deployed connection monitor. |
+| `resourceGroupName` | string | The resource group the connection monitor was deployed into. |
+| `resourceId` | string | The resource ID of the deployed connection monitor. |
+
+## Cross-referenced modules
+
+_None_
+
+## Data Collection
+
+The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at <https://go.microsoft.com/fwlink/?LinkID=824704>. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
diff --git a/avm/res/network/network-watcher/connection-monitor/main.bicep b/avm/res/network/network-watcher/connection-monitor/main.bicep
new file mode 100644
index 0000000000..0823dabe66
--- /dev/null
+++ b/avm/res/network/network-watcher/connection-monitor/main.bicep
@@ -0,0 +1,66 @@
+metadata name = 'Network Watchers Connection Monitors'
+metadata description = 'This module deploys a Network Watcher Connection Monitor.'
+metadata owner = 'Azure/module-maintainers'
+
+@description('Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG.')
+param networkWatcherName string = 'NetworkWatcher_${resourceGroup().location}'
+
+@description('Required. Name of the resource.')
+param name string
+
+@description('Optional. Tags of the resource.')
+param tags object?
+
+@description('Optional. Location for all resources.')
+param location string = resourceGroup().location
+
+@description('Optional. List of connection monitor endpoints.')
+param endpoints array = []
+
+@description('Optional. List of connection monitor test configurations.')
+param testConfigurations array = []
+
+@description('Optional. List of connection monitor test groups.')
+param testGroups array = []
+
+@description('Optional. Specify the Log Analytics Workspace Resource ID.')
+param workspaceResourceId string = ''
+
+
+resource networkWatcher 'Microsoft.Network/networkWatchers@2023-04-01' existing = {
+  name: networkWatcherName
+}
+
+resource connectionMonitor 'Microsoft.Network/networkWatchers/connectionMonitors@2023-04-01' = {
+  name: name
+  parent: networkWatcher
+  tags: tags
+  location: location
+  properties: {
+    endpoints: endpoints
+    testConfigurations: testConfigurations
+    testGroups: testGroups
+    outputs: !empty(workspaceResourceId)
+      ? [
+          {
+            type: 'Workspace'
+            workspaceSettings: {
+              workspaceResourceId: workspaceResourceId
+            }
+          }
+        ]
+      : null
+  }
+}
+
+@description('The name of the deployed connection monitor.')
+output name string = connectionMonitor.name
+
+@description('The resource ID of the deployed connection monitor.')
+output resourceId string = connectionMonitor.id
+
+@description('The resource group the connection monitor was deployed into.')
+output resourceGroupName string = resourceGroup().name
+
+@description('The location the resource was deployed into.')
+output location string = connectionMonitor.location
diff --git a/avm/res/network/network-watcher/connection-monitor/main.json b/avm/res/network/network-watcher/connection-monitor/main.json
new file mode 100644
index 0000000000..6c3fd5c843
--- /dev/null
+++ b/avm/res/network/network-watcher/connection-monitor/main.json
@@ -0,0 +1,126 @@
+{
+  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+  "languageVersion": "2.0",
+  "contentVersion": "1.0.0.0",
+  "metadata": {
+    "_generator": {
+      "name": "bicep",
+      "version": "0.26.54.24096",
+      "templateHash": "13403868700445795620"
+    },
+    "name": "Network Watchers Connection Monitors",
+    "description": "This module deploys a Network Watcher Connection Monitor.",
+    "owner": "Azure/module-maintainers"
+  },
+  "parameters": {
+    "networkWatcherName": {
+      "type": "string",
+      "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]",
+      "metadata": {
+        "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG."
+      }
+    },
+    "name": {
+      "type": "string",
+      "metadata": {
+        "description": "Required. Name of the resource."
+      }
+    },
+    "tags": {
+      "type": "object",
+      "nullable": true,
+      "metadata": {
+        "description": "Optional. Tags of the resource."
+      }
+    },
+    "location": {
+      "type": "string",
+      "defaultValue": "[resourceGroup().location]",
+      "metadata": {
+        "description": "Optional. Location for all resources."
+      }
+    },
+    "endpoints": {
+      "type": "array",
+      "defaultValue": [],
+      "metadata": {
+        "description": "Optional. List of connection monitor endpoints."
+      }
+    },
+    "testConfigurations": {
+      "type": "array",
+      "defaultValue": [],
+      "metadata": {
+        "description": "Optional. List of connection monitor test configurations."
+      }
+    },
+    "testGroups": {
+      "type": "array",
+      "defaultValue": [],
+      "metadata": {
+        "description": "Optional. List of connection monitor test groups."
+      }
+    },
+    "workspaceResourceId": {
+      "type": "string",
+      "defaultValue": "",
+      "metadata": {
+        "description": "Optional. Specify the Log Analytics Workspace Resource ID."
+      }
+    }
+  },
+  "resources": {
+    "networkWatcher": {
+      "existing": true,
+      "type": "Microsoft.Network/networkWatchers",
+      "apiVersion": "2023-04-01",
+      "name": "[parameters('networkWatcherName')]"
+    },
+    "connectionMonitor": {
+      "type": "Microsoft.Network/networkWatchers/connectionMonitors",
+      "apiVersion": "2023-04-01",
+      "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]",
+      "tags": "[parameters('tags')]",
+      "location": "[parameters('location')]",
+      "properties": {
+        "endpoints": "[parameters('endpoints')]",
+        "testConfigurations": "[parameters('testConfigurations')]",
+        "testGroups": "[parameters('testGroups')]",
+        "outputs": "[if(not(empty(parameters('workspaceResourceId'))), createArray(createObject('type', 'Workspace', 'workspaceSettings', createObject('workspaceResourceId', parameters('workspaceResourceId')))), null())]"
+      },
+      "dependsOn": [
+        "networkWatcher"
+      ]
+    }
+  },
+  "outputs": {
+    "name": {
+      "type": "string",
+      "metadata": {
+        "description": "The name of the deployed connection monitor."
+      },
+      "value": "[parameters('name')]"
+    },
+    "resourceId": {
+      "type": "string",
+      "metadata": {
+        "description": "The resource ID of the deployed connection monitor."
+      },
+      "value": "[resourceId('Microsoft.Network/networkWatchers/connectionMonitors', parameters('networkWatcherName'), parameters('name'))]"
+    },
+    "resourceGroupName": {
+      "type": "string",
+      "metadata": {
+        "description": "The resource group the connection monitor was deployed into."
+      },
+      "value": "[resourceGroup().name]"
+    },
+    "location": {
+      "type": "string",
+      "metadata": {
+        "description": "The location the resource was deployed into."
+      },
+      "value": "[reference('connectionMonitor', '2023-04-01', 'full').location]"
+    }
+  }
+}
\ No newline at end of file
diff --git a/avm/res/network/network-watcher/flow-log/README.md b/avm/res/network/network-watcher/flow-log/README.md
new file mode 100644
index 0000000000..93c1ac0144
--- /dev/null
+++ b/avm/res/network/network-watcher/flow-log/README.md
@@ -0,0 +1,158 @@
+# NSG Flow Logs `[Microsoft.Network/networkWatchers/flowLogs]`
+
+This module controls the Network Security Group Flow Logs and analytics settings.
+**Note: this module must be run on the Resource Group where Network Watcher is deployed**
+
+## Navigation
+
+- [Resource Types](#Resource-Types)
+- [Parameters](#Parameters)
+- [Outputs](#Outputs)
+- [Cross-referenced modules](#Cross-referenced-modules)
+- [Data Collection](#Data-Collection)
+
+## Resource Types
+
+| Resource Type | API Version |
+| :-- | :-- |
+| `Microsoft.Network/networkWatchers/flowLogs` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers/flowLogs) |
+
+## Parameters
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`storageId`](#parameter-storageid) | string | Resource ID of the diagnostic storage account. |
+| [`targetResourceId`](#parameter-targetresourceid) | string | Resource ID of the NSG that must be enabled for Flow Logs. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`enabled`](#parameter-enabled) | bool | If the flow log should be enabled. |
+| [`formatVersion`](#parameter-formatversion) | int | The flow log format version. |
+| [`location`](#parameter-location) | string | Location for all resources. |
+| [`name`](#parameter-name) | string | Name of the resource. |
+| [`networkWatcherName`](#parameter-networkwatchername) | string | Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. |
+| [`retentionInDays`](#parameter-retentionindays) | int | Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely. |
+| [`tags`](#parameter-tags) | object | Tags of the resource. |
+| [`trafficAnalyticsInterval`](#parameter-trafficanalyticsinterval) | int | The interval in minutes which would decide how frequently TA service should do flow analytics. |
+| [`workspaceResourceId`](#parameter-workspaceresourceid) | string | Specify the Log Analytics Workspace Resource ID. |
+
+### Parameter: `storageId`
+
+Resource ID of the diagnostic storage account.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `targetResourceId`
+
+Resource ID of the NSG that must be enabled for Flow Logs.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `enabled`
+
+If the flow log should be enabled.
+
+- Required: No
+- Type: bool
+- Default: `True`
+
+### Parameter: `formatVersion`
+
+The flow log format version.
+
+- Required: No
+- Type: int
+- Default: `2`
+- Allowed:
+  ```Bicep
+  [
+    1
+    2
+  ]
+  ```
+
+### Parameter: `location`
+
+Location for all resources.
+
+- Required: No
+- Type: string
+- Default: `[resourceGroup().location]`
+
+### Parameter: `name`
+
+Name of the resource.
+
+- Required: No
+- Type: string
+- Default: `[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]`
+
+### Parameter: `networkWatcherName`
+
+Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG.
+
+- Required: No
+- Type: string
+- Default: `[format('NetworkWatcher_{0}', resourceGroup().location)]`
+
+### Parameter: `retentionInDays`
+
+Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely.
+
+- Required: No
+- Type: int
+- Default: `365`
+
+### Parameter: `tags`
+
+Tags of the resource.
+
+- Required: No
+- Type: object
+
+### Parameter: `trafficAnalyticsInterval`
+
+The interval in minutes which would decide how frequently TA service should do flow analytics.
+
+- Required: No
+- Type: int
+- Default: `60`
+- Allowed:
+  ```Bicep
+  [
+    10
+    60
+  ]
+  ```
+
+### Parameter: `workspaceResourceId`
+
+Specify the Log Analytics Workspace Resource ID.
+
+- Required: No
+- Type: string
+- Default: `''`
+
+
+## Outputs
+
+| Output | Type | Description |
+| :-- | :-- | :-- |
+| `location` | string | The location the resource was deployed into. |
+| `name` | string | The name of the flow log. |
+| `resourceGroupName` | string | The resource group the flow log was deployed into. |
+| `resourceId` | string | The resource ID of the flow log. |
+
+## Cross-referenced modules
+
+_None_
+
+## Data Collection
+
+The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at <https://go.microsoft.com/fwlink/?LinkID=824704>. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
diff --git a/avm/res/network/network-watcher/flow-log/main.bicep b/avm/res/network/network-watcher/flow-log/main.bicep
new file mode 100644
index 0000000000..89a14ccc38
--- /dev/null
+++ b/avm/res/network/network-watcher/flow-log/main.bicep
@@ -0,0 +1,97 @@
+metadata name = 'NSG Flow Logs'
+metadata description = '''This module controls the Network Security Group Flow Logs and analytics settings.
+**Note: this module must be run on the Resource Group where Network Watcher is deployed**'''
+metadata owner = 'Azure/module-maintainers'
+
+@description('Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG.')
+param networkWatcherName string = 'NetworkWatcher_${resourceGroup().location}'
+
+@description('Optional. Name of the resource.')
+param name string = '${last(split(targetResourceId, '/'))}-${split(targetResourceId, '/')[4]}-flowlog'
+
+@description('Optional. Tags of the resource.')
+param tags object?
+
+@description('Optional. Location for all resources.')
+param location string = resourceGroup().location
+
+@description('Required. Resource ID of the NSG that must be enabled for Flow Logs.')
+param targetResourceId string
+
+@description('Required. Resource ID of the diagnostic storage account.')
+param storageId string
+
+@description('Optional. If the flow log should be enabled.')
+param enabled bool = true
+
+@description('Optional. The flow log format version.')
+@allowed([
+  1
+  2
+])
+param formatVersion int = 2
+
+@description('Optional. Specify the Log Analytics Workspace Resource ID.')
+param workspaceResourceId string = ''
+
+@description('Optional. The interval in minutes which would decide how frequently TA service should do flow analytics.')
+@allowed([
+  10
+  60
+])
+param trafficAnalyticsInterval int = 60
+
+@description('Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely.')
+@minValue(0)
+@maxValue(365)
+param retentionInDays int = 365
+
+var flowAnalyticsConfiguration = !empty(workspaceResourceId) && enabled == true
+  ? {
+      networkWatcherFlowAnalyticsConfiguration: {
+        enabled: true
+        workspaceResourceId: workspaceResourceId
+        trafficAnalyticsInterval: trafficAnalyticsInterval
+      }
+    }
+  : {
+      networkWatcherFlowAnalyticsConfiguration: {
+        enabled: false
+      }
+    }
+
+resource networkWatcher 'Microsoft.Network/networkWatchers@2023-04-01' existing = {
+  name: networkWatcherName
+}
+
+resource flowLog 'Microsoft.Network/networkWatchers/flowLogs@2023-04-01' = {
+  name: name
+  parent: networkWatcher
+  tags: tags
+  location: location
+  properties: {
+    targetResourceId: targetResourceId
+    storageId: storageId
+    enabled: enabled
+    retentionPolicy: {
+      days: retentionInDays
+      enabled: retentionInDays == 0 ? false : true
+    }
+    format: {
+      type: 'JSON'
+      version: formatVersion
+    }
+    flowAnalyticsConfiguration: flowAnalyticsConfiguration
+  }
+}
+@description('The name of the flow log.')
+output name string = flowLog.name
+
+@description('The resource ID of the flow log.')
+output resourceId string = flowLog.id
+
+@description('The resource group the flow log was deployed into.')
+output resourceGroupName string = resourceGroup().name
+
+@description('The location the resource was deployed into.')
+output location string = flowLog.location
diff --git a/avm/res/network/network-watcher/flow-log/main.json b/avm/res/network/network-watcher/flow-log/main.json
new file mode 100644
index 0000000000..1338480468
--- /dev/null
+++ b/avm/res/network/network-watcher/flow-log/main.json
@@ -0,0 +1,167 @@
+{
+  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+  "languageVersion": "2.0",
+  "contentVersion": "1.0.0.0",
+  "metadata": {
+    "_generator": {
+      "name": "bicep",
+      "version": "0.26.54.24096",
+      "templateHash": "7721211688474892554"
+    },
+    "name": "NSG Flow Logs",
+    "description": "This module controls the Network Security Group Flow Logs and analytics settings.\n**Note: this module must be run on the Resource Group where Network Watcher is deployed**",
+    "owner": "Azure/module-maintainers"
+  },
+  "parameters": {
+    "networkWatcherName": {
+      "type": "string",
+      "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]",
+      "metadata": {
+        "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG."
+      }
+    },
+    "name": {
+      "type": "string",
+      "defaultValue": "[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]",
+      "metadata": {
+        "description": "Optional. Name of the resource."
+      }
+    },
+    "tags": {
+      "type": "object",
+      "nullable": true,
+      "metadata": {
+        "description": "Optional. Tags of the resource."
+      }
+    },
+    "location": {
+      "type": "string",
+      "defaultValue": "[resourceGroup().location]",
+      "metadata": {
+        "description": "Optional. Location for all resources."
+      }
+    },
+    "targetResourceId": {
+      "type": "string",
+      "metadata": {
+        "description": "Required. Resource ID of the NSG that must be enabled for Flow Logs."
+      }
+    },
+    "storageId": {
+      "type": "string",
+      "metadata": {
+        "description": "Required. Resource ID of the diagnostic storage account."
+      }
+    },
+    "enabled": {
+      "type": "bool",
+      "defaultValue": true,
+      "metadata": {
+        "description": "Optional. If the flow log should be enabled."
+      }
+    },
+    "formatVersion": {
+      "type": "int",
+      "defaultValue": 2,
+      "allowedValues": [
+        1,
+        2
+      ],
+      "metadata": {
+        "description": "Optional. The flow log format version."
+      }
+    },
+    "workspaceResourceId": {
+      "type": "string",
+      "defaultValue": "",
+      "metadata": {
+        "description": "Optional. Specify the Log Analytics Workspace Resource ID."
+      }
+    },
+    "trafficAnalyticsInterval": {
+      "type": "int",
+      "defaultValue": 60,
+      "allowedValues": [
+        10,
+        60
+      ],
+      "metadata": {
+        "description": "Optional. The interval in minutes which would decide how frequently TA service should do flow analytics."
+      }
+    },
+    "retentionInDays": {
+      "type": "int",
+      "defaultValue": 365,
+      "minValue": 0,
+      "maxValue": 365,
+      "metadata": {
+        "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely."
+      }
+    }
+  },
+  "variables": {
+    "flowAnalyticsConfiguration": "[if(and(not(empty(parameters('workspaceResourceId'))), equals(parameters('enabled'), true())), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', true(), 'workspaceResourceId', parameters('workspaceResourceId'), 'trafficAnalyticsInterval', parameters('trafficAnalyticsInterval'))), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', false())))]"
+  },
+  "resources": {
+    "networkWatcher": {
+      "existing": true,
+      "type": "Microsoft.Network/networkWatchers",
+      "apiVersion": "2023-04-01",
+      "name": "[parameters('networkWatcherName')]"
+    },
+    "flowLog": {
+      "type": "Microsoft.Network/networkWatchers/flowLogs",
+      "apiVersion": "2023-04-01",
+      "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]",
+      "tags": "[parameters('tags')]",
+      "location": "[parameters('location')]",
+      "properties": {
+        "targetResourceId": "[parameters('targetResourceId')]",
+        "storageId": "[parameters('storageId')]",
+        "enabled": "[parameters('enabled')]",
+        "retentionPolicy": {
+          "days": "[parameters('retentionInDays')]",
+          "enabled": "[if(equals(parameters('retentionInDays'), 0), false(), true())]"
+        },
+        "format": {
+          "type": "JSON",
+          "version": "[parameters('formatVersion')]"
+        },
+        "flowAnalyticsConfiguration": "[variables('flowAnalyticsConfiguration')]"
+      },
+      "dependsOn": [
+        "networkWatcher"
+      ]
+    }
+  },
+  "outputs": {
+    "name": {
+      "type": "string",
+      "metadata": {
+        "description": "The name of the flow log."
+      },
+      "value": "[parameters('name')]"
+    },
+    "resourceId": {
+      "type": "string",
+      "metadata": {
+        "description": "The resource ID of the flow log."
+      },
+      "value": "[resourceId('Microsoft.Network/networkWatchers/flowLogs', parameters('networkWatcherName'), parameters('name'))]"
+    },
+    "resourceGroupName": {
+      "type": "string",
+      "metadata": {
+        "description": "The resource group the flow log was deployed into."
+      },
+      "value": "[resourceGroup().name]"
+    },
+    "location": {
+      "type": "string",
+      "metadata": {
+        "description": "The location the resource was deployed into."
+      },
+      "value": "[reference('flowLog', '2023-04-01', 'full').location]"
+    }
+  }
+}
\ No newline at end of file
diff --git a/avm/res/network/network-watcher/main.bicep b/avm/res/network/network-watcher/main.bicep
new file mode 100644
index 0000000000..71f388d98f
--- /dev/null
+++ b/avm/res/network/network-watcher/main.bicep
@@ -0,0 +1,188 @@
+metadata name = 'Network Watchers'
+metadata description = 'This module deploys a Network Watcher.'
+metadata owner = 'Azure/module-maintainers'
+
+@description('Optional. Name of the Network Watcher resource (hidden).')
+@minLength(1)
+param name string = 'NetworkWatcher_${location}'
+
+@description('Optional. Location for all resources.')
+param location string = resourceGroup().location
+
+@description('Optional. Array that contains the Connection Monitors.')
+param connectionMonitors array = []
+
+@description('Optional. Array that contains the Flow Logs.')
+param flowLogs array = []
+
+@description('Optional. The lock settings of the service.')
+param lock lockType
+
+@description('Optional. Array of role assignments to create.')
+param roleAssignments roleAssignmentType
+
+@description('Optional. Tags of the resource.')
+param tags object?
+
+@description('Optional. Enable/Disable usage telemetry for module.')
+param enableTelemetry bool = true
+
+var builtInRoleNames = {
+  Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
+  'Network Contributor': subscriptionResourceId(
+    'Microsoft.Authorization/roleDefinitions',
+    '4d97b98b-1d4f-4787-a291-c67834d212e7'
+  )
+  Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')
+  Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')
+  'Role Based Access Control Administrator (Preview)': subscriptionResourceId(
+    'Microsoft.Authorization/roleDefinitions',
+    'f58310d9-a9f6-439a-9e8d-f62e7b41a168'
+  )
+  'User Access Administrator': subscriptionResourceId(
+    'Microsoft.Authorization/roleDefinitions',
+    '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9'
+  )
+}
+
+resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' =
+  if (enableTelemetry) {
+    name: '46d3xbcp.res.network-networkwatcher.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}'
+    properties: {
+      mode: 'Incremental'
+      template: {
+        '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
+        contentVersion: '1.0.0.0'
+        resources: []
+        outputs: {
+          telemetry: {
+            type: 'String'
+            value: 'For more information, see https://aka.ms/avm/TelemetryInfo'
+          }
+        }
+      }
+    }
+  }
+
+resource networkWatcher 'Microsoft.Network/networkWatchers@2023-04-01' = {
+  name: name
+  location: location
+  tags: tags
+  properties: {}
+}
+
+resource networkWatcher_lock 'Microsoft.Authorization/locks@2020-05-01' =
+  if (!empty(lock ?? {}) && lock.?kind != 'None') {
+    name: lock.?name ?? 'lock-${name}'
+    properties: {
+      level: lock.?kind ?? ''
+      notes: lock.?kind == 'CanNotDelete'
+        ? 'Cannot delete resource or child resources.'
+        : 'Cannot delete or modify the resource or child resources.'
+    }
+    scope: networkWatcher
+  }
+
+resource networkWatcher_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [
+  for (roleAssignment, index) in (roleAssignments ?? []): {
+    name: guid(networkWatcher.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName)
+    properties: {
+      roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName)
+        ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName]
+        : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/')
+            ? roleAssignment.roleDefinitionIdOrName
+            : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)
+      principalId: roleAssignment.principalId
+      description: roleAssignment.?description
+      principalType: roleAssignment.?principalType
+      condition: roleAssignment.?condition
+      conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set
+      delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId
+    }
+    scope: networkWatcher
+  }
+]
+
+module networkWatcher_connectionMonitors 'connection-monitor/main.bicep' = [
+  for (connectionMonitor, index) in connectionMonitors: {
+    name: '${uniqueString(deployment().name, location)}-NW-ConnectionMonitor-${index}'
+    params: {
+      endpoints: contains(connectionMonitor, 'endpoints') ? connectionMonitor.endpoints : []
+      name: connectionMonitor.name
+      location: location
+      networkWatcherName: networkWatcher.name
+      testConfigurations: contains(connectionMonitor, 'testConfigurations') ? connectionMonitor.testConfigurations : []
+      testGroups: contains(connectionMonitor, 'testGroups') ? connectionMonitor.testGroups : []
+      workspaceResourceId: contains(connectionMonitor, 'workspaceResourceId')
+        ? connectionMonitor.workspaceResourceId
+        : ''
+    }
+  }
+]
+
+module networkWatcher_flowLogs 'flow-log/main.bicep' = [
+  for (flowLog, index) in flowLogs: {
+    name: '${uniqueString(deployment().name, location)}-NW-FlowLog-${index}'
+    params: {
+      enabled: contains(flowLog, 'enabled') ? flowLog.enabled : true
+      formatVersion: contains(flowLog, 'formatVersion') ? flowLog.formatVersion : 2
+      location: contains(flowLog, 'location') ? flowLog.location : location
+      name: contains(flowLog, 'name')
+        ? flowLog.name
+        : '${last(split(flowLog.targetResourceId, '/'))}-${split(flowLog.targetResourceId, '/')[4]}-flowlog'
+      networkWatcherName: networkWatcher.name
+      retentionInDays: contains(flowLog, 'retentionInDays') ? flowLog.retentionInDays : 365
+      storageId: flowLog.storageId
+      targetResourceId: flowLog.targetResourceId
+      trafficAnalyticsInterval: contains(flowLog, 'trafficAnalyticsInterval') ? flowLog.trafficAnalyticsInterval : 60
+      workspaceResourceId: contains(flowLog, 'workspaceResourceId') ? flowLog.workspaceResourceId : ''
+    }
+  }
+]
+
+@description('The name of the deployed network watcher.')
+output name string = networkWatcher.name
+
+@description('The resource ID of the deployed network watcher.')
+output resourceId string = networkWatcher.id
+
+@description('The resource group the network watcher was deployed into.')
+output resourceGroupName string = resourceGroup().name
+
+@description('The location the resource was deployed into.')
+output location string = networkWatcher.location
+
+// =============== //
+//   Definitions   //
+// =============== //
+
+type lockType = {
+  @description('Optional. Specify the name of lock.')
+  name: string?
+
+  @description('Optional. Specify the type of lock.')
+  kind: ('CanNotDelete' | 'ReadOnly' | 'None')?
+}?
+
+type roleAssignmentType = {
+  @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.')
+  roleDefinitionIdOrName: string
+
+  @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.')
+  principalId: string
+
+  @description('Optional. The principal type of the assigned principal ID.')
+  principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')?
+
+  @description('Optional. The description of the role assignment.')
+  description: string?
+
+  @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".')
+  condition: string?
+
+  @description('Optional. Version of the condition.')
+  conditionVersion: '2.0'?
+
+  @description('Optional. The Resource Id of the delegated managed identity resource.')
+  delegatedManagedIdentityResourceId: string?
+}[]?
diff --git a/avm/res/network/network-watcher/main.json b/avm/res/network/network-watcher/main.json
new file mode 100644
index 0000000000..1a74c3d9f4
--- /dev/null
+++ b/avm/res/network/network-watcher/main.json
@@ -0,0 +1,633 @@
+{
+  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+  "languageVersion": "2.0",
+  "contentVersion": "1.0.0.0",
+  "metadata": {
+    "_generator": {
+      "name": "bicep",
+      "version": "0.26.54.24096",
+      "templateHash": "4063023963915633324"
+    },
+    "name": "Network Watchers",
+    "description": "This module deploys a Network Watcher.",
+    "owner": "Azure/module-maintainers"
+  },
+  "definitions": {
+    "lockType": {
+      "type": "object",
+      "properties": {
+        "name": {
+          "type": "string",
+          "nullable": true,
+          "metadata": {
+            "description": "Optional. Specify the name of lock."
+          }
+        },
+        "kind": {
+          "type": "string",
+          "allowedValues": [
+            "CanNotDelete",
+            "None",
+            "ReadOnly"
+          ],
+          "nullable": true,
+          "metadata": {
+            "description": "Optional. Specify the type of lock."
+          }
+        }
+      },
+      "nullable": true
+    },
+    "roleAssignmentType": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "properties": {
+          "roleDefinitionIdOrName": {
+            "type": "string",
+            "metadata": {
+              "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'."
+            }
+          },
+          "principalId": {
+            "type": "string",
+            "metadata": {
+              "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to."
+            }
+          },
+          "principalType": {
+            "type": "string",
+            "allowedValues": [
+              "Device",
+              "ForeignGroup",
+              "Group",
+              "ServicePrincipal",
+              "User"
+            ],
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The principal type of the assigned principal ID."
+            }
+          },
+          "description": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The description of the role assignment."
+            }
+          },
+          "condition": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"."
+            }
+          },
+          "conditionVersion": {
+            "type": "string",
+            "allowedValues": [
+              "2.0"
+            ],
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. Version of the condition."
+            }
+          },
+          "delegatedManagedIdentityResourceId": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The Resource Id of the delegated managed identity resource."
+            }
+          }
+        }
+      },
+      "nullable": true
+    }
+  },
+  "parameters": {
+    "name": {
+      "type": "string",
+      "defaultValue": "[format('NetworkWatcher_{0}', parameters('location'))]",
+      "minLength": 1,
+      "metadata": {
+        "description": "Optional. Name of the Network Watcher resource (hidden)."
+      }
+    },
+    "location": {
+      "type": "string",
+      "defaultValue": "[resourceGroup().location]",
+      "metadata": {
+        "description": "Optional. Location for all resources."
+      }
+    },
+    "connectionMonitors": {
+      "type": "array",
+      "defaultValue": [],
+      "metadata": {
+        "description": "Optional. Array that contains the Connection Monitors."
+      }
+    },
+    "flowLogs": {
+      "type": "array",
+      "defaultValue": [],
+      "metadata": {
+        "description": "Optional. Array that contains the Flow Logs."
+      }
+    },
+    "lock": {
+      "$ref": "#/definitions/lockType",
+      "metadata": {
+        "description": "Optional. The lock settings of the service."
+      }
+    },
+    "roleAssignments": {
+      "$ref": "#/definitions/roleAssignmentType",
+      "metadata": {
+        "description": "Optional. Array of role assignments to create."
+      }
+    },
+    "tags": {
+      "type": "object",
+      "nullable": true,
+      "metadata": {
+        "description": "Optional. Tags of the resource."
+      }
+    },
+    "enableTelemetry": {
+      "type": "bool",
+      "defaultValue": true,
+      "metadata": {
+        "description": "Optional. Enable/Disable usage telemetry for module."
+      }
+    }
+  },
+  "variables": {
+    "builtInRoleNames": {
+      "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
+      "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]",
+      "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]",
+      "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
+      "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]",
+      "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]"
+    }
+  },
+  "resources": {
+    "avmTelemetry": {
+      "condition": "[parameters('enableTelemetry')]",
+      "type": "Microsoft.Resources/deployments",
+      "apiVersion": "2023-07-01",
+      "name": "[format('46d3xbcp.res.network-networkwatcher.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]",
+      "properties": {
+        "mode": "Incremental",
+        "template": {
+          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+          "contentVersion": "1.0.0.0",
+          "resources": [],
+          "outputs": {
+            "telemetry": {
+              "type": "String",
+              "value": "For more information, see https://aka.ms/avm/TelemetryInfo"
+            }
+          }
+        }
+      }
+    },
+    "networkWatcher": {
+      "type": "Microsoft.Network/networkWatchers",
+      "apiVersion": "2023-04-01",
+      "name": "[parameters('name')]",
+      "location": "[parameters('location')]",
+      "tags": "[parameters('tags')]",
+      "properties": {}
+    },
+    "networkWatcher_lock": {
+      "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]",
+      "type": "Microsoft.Authorization/locks",
+      "apiVersion": "2020-05-01",
+      "scope": "[format('Microsoft.Network/networkWatchers/{0}', parameters('name'))]",
+      "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]",
+      "properties": {
+        "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]",
+        "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]"
+      },
+      "dependsOn": [
+        "networkWatcher"
+      ]
+    },
+    "networkWatcher_roleAssignments": {
+      "copy": {
+        "name": "networkWatcher_roleAssignments",
+        "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]"
+      },
+      "type": "Microsoft.Authorization/roleAssignments",
+      "apiVersion": "2022-04-01",
+      "scope": "[format('Microsoft.Network/networkWatchers/{0}', parameters('name'))]",
+      "name": "[guid(resourceId('Microsoft.Network/networkWatchers', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]",
+      "properties": {
+        "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]",
+        "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]",
+        "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]",
+        "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]",
+        "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]",
+        "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]",
+        "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]"
+      },
+      "dependsOn": [
+        "networkWatcher"
+      ]
+    },
+    "networkWatcher_connectionMonitors": {
+      "copy": {
+        "name": "networkWatcher_connectionMonitors",
+        "count": "[length(parameters('connectionMonitors'))]"
+      },
+      "type": "Microsoft.Resources/deployments",
+      "apiVersion": "2022-09-01",
+      "name": "[format('{0}-NW-ConnectionMonitor-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]",
+      "properties": {
+        "expressionEvaluationOptions": {
+          "scope": "inner"
+        },
+        "mode": "Incremental",
+        "parameters": {
+          "endpoints": "[if(contains(parameters('connectionMonitors')[copyIndex()], 'endpoints'), createObject('value', parameters('connectionMonitors')[copyIndex()].endpoints), createObject('value', createArray()))]",
+          "name": {
+            "value": "[parameters('connectionMonitors')[copyIndex()].name]"
+          },
+          "location": {
+            "value": "[parameters('location')]"
+          },
+          "networkWatcherName": {
+            "value": "[parameters('name')]"
+          },
+          "testConfigurations": "[if(contains(parameters('connectionMonitors')[copyIndex()], 'testConfigurations'), createObject('value', parameters('connectionMonitors')[copyIndex()].testConfigurations), createObject('value', createArray()))]",
+          "testGroups": "[if(contains(parameters('connectionMonitors')[copyIndex()], 'testGroups'), createObject('value', parameters('connectionMonitors')[copyIndex()].testGroups), createObject('value', createArray()))]",
+          "workspaceResourceId": "[if(contains(parameters('connectionMonitors')[copyIndex()], 'workspaceResourceId'), createObject('value', parameters('connectionMonitors')[copyIndex()].workspaceResourceId), createObject('value', ''))]"
+        },
+        "template": {
+          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+          "languageVersion": "2.0",
+          "contentVersion": "1.0.0.0",
+          "metadata": {
+            "_generator": {
+              "name": "bicep",
+              "version": "0.26.54.24096",
+              "templateHash": "13403868700445795620"
+            },
+            "name": "Network Watchers Connection Monitors",
+            "description": "This module deploys a Network Watcher Connection Monitor.",
+            "owner": "Azure/module-maintainers"
+          },
+          "parameters": {
+            "networkWatcherName": {
+              "type": "string",
+              "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]",
+              "metadata": {
+                "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG."
+              }
+            },
+            "name": {
+              "type": "string",
+              "metadata": {
+                "description": "Required. Name of the resource."
+              }
+            },
+            "tags": {
+              "type": "object",
+              "nullable": true,
+              "metadata": {
+                "description": "Optional. Tags of the resource."
+              }
+            },
+            "location": {
+              "type": "string",
+              "defaultValue": "[resourceGroup().location]",
+              "metadata": {
+                "description": "Optional. Location for all resources."
+              }
+            },
+            "endpoints": {
+              "type": "array",
+              "defaultValue": [],
+              "metadata": {
+                "description": "Optional. List of connection monitor endpoints."
+              }
+            },
+            "testConfigurations": {
+              "type": "array",
+              "defaultValue": [],
+              "metadata": {
+                "description": "Optional. List of connection monitor test configurations."
+              }
+            },
+            "testGroups": {
+              "type": "array",
+              "defaultValue": [],
+              "metadata": {
+                "description": "Optional. List of connection monitor test groups."
+              }
+            },
+            "workspaceResourceId": {
+              "type": "string",
+              "defaultValue": "",
+              "metadata": {
+                "description": "Optional. Specify the Log Analytics Workspace Resource ID."
+              }
+            }
+          },
+          "resources": {
+            "networkWatcher": {
+              "existing": true,
+              "type": "Microsoft.Network/networkWatchers",
+              "apiVersion": "2023-04-01",
+              "name": "[parameters('networkWatcherName')]"
+            },
+            "connectionMonitor": {
+              "type": "Microsoft.Network/networkWatchers/connectionMonitors",
+              "apiVersion": "2023-04-01",
+              "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]",
+              "tags": "[parameters('tags')]",
+              "location": "[parameters('location')]",
+              "properties": {
+                "endpoints": "[parameters('endpoints')]",
+                "testConfigurations": "[parameters('testConfigurations')]",
+                "testGroups": "[parameters('testGroups')]",
+                "outputs": "[if(not(empty(parameters('workspaceResourceId'))), createArray(createObject('type', 'Workspace', 'workspaceSettings', createObject('workspaceResourceId', parameters('workspaceResourceId')))), null())]"
+              },
+              "dependsOn": [
+                "networkWatcher"
+              ]
+            }
+          },
+          "outputs": {
+            "name": {
+              "type": "string",
+              "metadata": {
+                "description": "The name of the deployed connection monitor."
+              },
+              "value": "[parameters('name')]"
+            },
+            "resourceId": {
+              "type": "string",
+              "metadata": {
+                "description": "The resource ID of the deployed connection monitor."
+              },
+              "value": "[resourceId('Microsoft.Network/networkWatchers/connectionMonitors', parameters('networkWatcherName'), parameters('name'))]"
+            },
+            "resourceGroupName": {
+              "type": "string",
+              "metadata": {
+                "description": "The resource group the connection monitor was deployed into."
+              },
+              "value": "[resourceGroup().name]"
+            },
+            "location": {
+              "type": "string",
+              "metadata": {
+                "description": "The location the resource was deployed into."
+              },
+              "value": "[reference('connectionMonitor', '2023-04-01', 'full').location]"
+            }
+          }
+        }
+      },
+      "dependsOn": [
+        "networkWatcher"
+      ]
+    },
+    "networkWatcher_flowLogs": {
+      "copy": {
+        "name": "networkWatcher_flowLogs",
+        "count": "[length(parameters('flowLogs'))]"
+      },
+      "type": "Microsoft.Resources/deployments",
+      "apiVersion": "2022-09-01",
+      "name": "[format('{0}-NW-FlowLog-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]",
+      "properties": {
+        "expressionEvaluationOptions": {
+          "scope": "inner"
+        },
+        "mode": "Incremental",
+        "parameters": {
+          "enabled": "[if(contains(parameters('flowLogs')[copyIndex()], 'enabled'), createObject('value', parameters('flowLogs')[copyIndex()].enabled), createObject('value', true()))]",
+          "formatVersion": "[if(contains(parameters('flowLogs')[copyIndex()], 'formatVersion'), createObject('value', parameters('flowLogs')[copyIndex()].formatVersion), createObject('value', 2))]",
+          "location": "[if(contains(parameters('flowLogs')[copyIndex()], 'location'), createObject('value', parameters('flowLogs')[copyIndex()].location), createObject('value', parameters('location')))]",
+          "name": "[if(contains(parameters('flowLogs')[copyIndex()], 'name'), createObject('value', parameters('flowLogs')[copyIndex()].name), createObject('value', format('{0}-{1}-flowlog', last(split(parameters('flowLogs')[copyIndex()].targetResourceId, '/')), split(parameters('flowLogs')[copyIndex()].targetResourceId, '/')[4])))]",
+          "networkWatcherName": {
+            "value": "[parameters('name')]"
+          },
+          "retentionInDays": "[if(contains(parameters('flowLogs')[copyIndex()], 'retentionInDays'), createObject('value', parameters('flowLogs')[copyIndex()].retentionInDays), createObject('value', 365))]",
+          "storageId": {
+            "value": "[parameters('flowLogs')[copyIndex()].storageId]"
+          },
+          "targetResourceId": {
+            "value": "[parameters('flowLogs')[copyIndex()].targetResourceId]"
+          },
+          "trafficAnalyticsInterval": "[if(contains(parameters('flowLogs')[copyIndex()], 'trafficAnalyticsInterval'), createObject('value', parameters('flowLogs')[copyIndex()].trafficAnalyticsInterval), createObject('value', 60))]",
+          "workspaceResourceId": "[if(contains(parameters('flowLogs')[copyIndex()], 'workspaceResourceId'), createObject('value', parameters('flowLogs')[copyIndex()].workspaceResourceId), createObject('value', ''))]"
+        },
+        "template": {
+          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+          "languageVersion": "2.0",
+          "contentVersion": "1.0.0.0",
+          "metadata": {
+            "_generator": {
+              "name": "bicep",
+              "version": "0.26.54.24096",
+              "templateHash": "7721211688474892554"
+            },
+            "name": "NSG Flow Logs",
+            "description": "This module controls the Network Security Group Flow Logs and analytics settings.\n**Note: this module must be run on the Resource Group where Network Watcher is deployed**",
+            "owner": "Azure/module-maintainers"
+          },
+          "parameters": {
+            "networkWatcherName": {
+              "type": "string",
+              "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]",
+              "metadata": {
+                "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG."
+              }
+            },
+            "name": {
+              "type": "string",
+              "defaultValue": "[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]",
+              "metadata": {
+                "description": "Optional. Name of the resource."
+              }
+            },
+            "tags": {
+              "type": "object",
+              "nullable": true,
+              "metadata": {
+                "description": "Optional. Tags of the resource."
+              }
+            },
+            "location": {
+              "type": "string",
+              "defaultValue": "[resourceGroup().location]",
+              "metadata": {
+                "description": "Optional. Location for all resources."
+              }
+            },
+            "targetResourceId": {
+              "type": "string",
+              "metadata": {
+                "description": "Required. Resource ID of the NSG that must be enabled for Flow Logs."
+              }
+            },
+            "storageId": {
+              "type": "string",
+              "metadata": {
+                "description": "Required. Resource ID of the diagnostic storage account."
+              }
+            },
+            "enabled": {
+              "type": "bool",
+              "defaultValue": true,
+              "metadata": {
+                "description": "Optional. If the flow log should be enabled."
+              }
+            },
+            "formatVersion": {
+              "type": "int",
+              "defaultValue": 2,
+              "allowedValues": [
+                1,
+                2
+              ],
+              "metadata": {
+                "description": "Optional. The flow log format version."
+              }
+            },
+            "workspaceResourceId": {
+              "type": "string",
+              "defaultValue": "",
+              "metadata": {
+                "description": "Optional. Specify the Log Analytics Workspace Resource ID."
+              }
+            },
+            "trafficAnalyticsInterval": {
+              "type": "int",
+              "defaultValue": 60,
+              "allowedValues": [
+                10,
+                60
+              ],
+              "metadata": {
+                "description": "Optional. The interval in minutes which would decide how frequently TA service should do flow analytics."
+              }
+            },
+            "retentionInDays": {
+              "type": "int",
+              "defaultValue": 365,
+              "minValue": 0,
+              "maxValue": 365,
+              "metadata": {
+                "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely."
+              }
+            }
+          },
+          "variables": {
+            "flowAnalyticsConfiguration": "[if(and(not(empty(parameters('workspaceResourceId'))), equals(parameters('enabled'), true())), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', true(), 'workspaceResourceId', parameters('workspaceResourceId'), 'trafficAnalyticsInterval', parameters('trafficAnalyticsInterval'))), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', false())))]"
+          },
+          "resources": {
+            "networkWatcher": {
+              "existing": true,
+              "type": "Microsoft.Network/networkWatchers",
+              "apiVersion": "2023-04-01",
+              "name": "[parameters('networkWatcherName')]"
+            },
+            "flowLog": {
+              "type": "Microsoft.Network/networkWatchers/flowLogs",
+              "apiVersion": "2023-04-01",
+              "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]",
+              "tags": "[parameters('tags')]",
+              "location": "[parameters('location')]",
+              "properties": {
+                "targetResourceId": "[parameters('targetResourceId')]",
+                "storageId": "[parameters('storageId')]",
+                "enabled": "[parameters('enabled')]",
+                "retentionPolicy": {
+                  "days": "[parameters('retentionInDays')]",
+                  "enabled": "[if(equals(parameters('retentionInDays'), 0), false(), true())]"
+                },
+                "format": {
+                  "type": "JSON",
+                  "version": "[parameters('formatVersion')]"
+                },
+                "flowAnalyticsConfiguration": "[variables('flowAnalyticsConfiguration')]"
+              },
+              "dependsOn": [
+                "networkWatcher"
+              ]
+            }
+          },
+          "outputs": {
+            "name": {
+              "type": "string",
+              "metadata": {
+                "description": "The name of the flow log."
+              },
+              "value": "[parameters('name')]"
+            },
+            "resourceId": {
+              "type": "string",
+              "metadata": {
+                "description": "The resource ID of the flow log."
+              },
+              "value": "[resourceId('Microsoft.Network/networkWatchers/flowLogs', parameters('networkWatcherName'), parameters('name'))]"
+            },
+            "resourceGroupName": {
+              "type": "string",
+              "metadata": {
+                "description": "The resource group the flow log was deployed into."
+              },
+              "value": "[resourceGroup().name]"
+            },
+            "location": {
+              "type": "string",
+              "metadata": {
+                "description": "The location the resource was deployed into."
+              },
+              "value": "[reference('flowLog', '2023-04-01', 'full').location]"
+            }
+          }
+        }
+      },
+      "dependsOn": [
+        "networkWatcher"
+      ]
+    }
+  },
+  "outputs": {
+    "name": {
+      "type": "string",
+      "metadata": {
+        "description": "The name of the deployed network watcher."
+      },
+      "value": "[parameters('name')]"
+    },
+    "resourceId": {
+      "type": "string",
+      "metadata": {
+        "description": "The resource ID of the deployed network watcher."
+      },
+      "value": "[resourceId('Microsoft.Network/networkWatchers', parameters('name'))]"
+    },
+    "resourceGroupName": {
+      "type": "string",
+      "metadata": {
+        "description": "The resource group the network watcher was deployed into."
+      },
+      "value": "[resourceGroup().name]"
+    },
+    "location": {
+      "type": "string",
+      "metadata": {
+        "description": "The location the resource was deployed into."
+      },
+      "value": "[reference('networkWatcher', '2023-04-01', 'full').location]"
+    }
+  }
+}
\ No newline at end of file
diff --git a/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep
new file mode 100644
index 0000000000..9fcca025ef
--- /dev/null
+++ b/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep
@@ -0,0 +1,51 @@
+targetScope = 'subscription'
+
+metadata name = 'Using only defaults'
+metadata description = 'This instance deploys the module with the minimum set of required parameters.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change.
+
+@description('Optional. The location to deploy resources to.')
+#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically
+param resourceLocation string = deployment().location
+
+@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG
+param tempLocation string = 'uksouth'
+
+@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.')
+param serviceShort string = 'nnwmin'
+
+#disable-next-line no-unused-params
+@description('Optional. A token to inject into the name of each resource.')
+param namePrefix string = '#_namePrefix_#'
+
+// ============ //
+// Dependencies //
+// ============ //
+
+// General resources
+// =================
+resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
+  name: resourceGroupName
+  location: tempLocation
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+  scope: resourceGroup
+  name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}'
+  params: {
+    // Note: This value is not required and only set to enable testing
+    location: tempLocation
+  }
+}]
diff --git a/avm/res/network/network-watcher/tests/e2e/max/dependencies.bicep b/avm/res/network/network-watcher/tests/e2e/max/dependencies.bicep
new file mode 100644
index 0000000000..c20f841f30
--- /dev/null
+++ b/avm/res/network/network-watcher/tests/e2e/max/dependencies.bicep
@@ -0,0 +1,144 @@
+@description('Optional. The location to deploy to.')
+param location string = resourceGroup().location
+
+@description('Required. The name of the Virtual Network to create.')
+param virtualNetworkName string
+
+@description('Required. The name of the Managed Identity to create.')
+param managedIdentityName string
+
+@description('Required. The name of the first Network Security Group to create.')
+param firstNetworkSecurityGroupName string
+
+@description('Required. The name of the second Network Security Group to create.')
+param secondNetworkSecurityGroupName string
+
+@description('Required. The name of the Virtual Machine to create.')
+param virtualMachineName string
+
+@description('Optional. The password to leverage for the VM login.')
+@secure()
+param password string = newGuid()
+
+var addressPrefix = '10.0.0.0/16'
+
+resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = {
+  name: virtualNetworkName
+  location: location
+  properties: {
+    addressSpace: {
+      addressPrefixes: [
+        addressPrefix
+      ]
+    }
+    subnets: [
+      {
+        name: 'defaultSubnet'
+        properties: {
+          addressPrefix: cidrSubnet(addressPrefix, 16, 0)
+        }
+      }
+    ]
+  }
+}
+
+resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
+  name: managedIdentityName
+  location: location
+}
+
+resource firstNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = {
+  name: firstNetworkSecurityGroupName
+  location: location
+}
+
+resource secondNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = {
+  name: secondNetworkSecurityGroupName
+  location: location
+}
+
+resource networkInterface 'Microsoft.Network/networkInterfaces@2023-04-01' = {
+  name: '${virtualMachineName}-nic'
+  location: location
+  properties: {
+    ipConfigurations: [
+      {
+        name: 'ipconfig01'
+        properties: {
+          subnet: {
+            id: virtualNetwork.properties.subnets[0].id
+          }
+        }
+      }
+    ]
+  }
+}
+
+resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-08-01' = {
+  name: virtualMachineName
+  location: location
+  properties: {
+    networkProfile: {
+      networkInterfaces: [
+        {
+          id: networkInterface.id
+          properties: {
+            deleteOption: 'Delete'
+            primary: true
+          }
+        }
+      ]
+    }
+    storageProfile: {
+      imageReference: {
+        publisher: 'Canonical'
+        offer: '0001-com-ubuntu-server-jammy'
+        sku: '22_04-lts-gen2'
+        version: 'latest'
+      }
+      osDisk: {
+        deleteOption: 'Delete'
+        createOption: 'FromImage'
+      }
+    }
+    hardwareProfile: {
+      vmSize: 'Standard_B1ms'
+    }
+    osProfile: {
+      adminUsername: '${virtualMachineName}cake'
+      adminPassword: password
+      computerName: virtualMachineName
+      linuxConfiguration: {
+        disablePasswordAuthentication: false
+      }
+    }
+  }
+}
+
+resource extension 'Microsoft.Compute/virtualMachines/extensions@2021-07-01' = {
+  name: 'NetworkWatcherAgent'
+  parent: virtualMachine
+  location: location
+  properties: {
+    publisher: 'Microsoft.Azure.NetworkWatcher'
+    type: 'NetworkWatcherAgentLinux'
+    typeHandlerVersion: '1.4'
+    autoUpgradeMinorVersion: true
+    enableAutomaticUpgrade: false
+    settings: {}
+    protectedSettings: {}
+    suppressFailures: false
+  }
+}
+
+@description('The principal ID of the created Managed Identity.')
+output managedIdentityPrincipalId string = managedIdentity.properties.principalId
+
+@description('The resource ID of the created Virtual Machine.')
+output virtualMachineResourceId string = virtualMachine.id
+
+@description('The resource ID of the first created Network Security Group.')
+output firstNetworkSecurityGroupResourceId string = firstNetworkSecurityGroup.id
+
+@description('The resource ID of the second created Network Security Group.')
+output secondNetworkSecurityGroupResourceId string = secondNetworkSecurityGroup.id
diff --git a/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep
new file mode 100644
index 0000000000..4386fe3d6e
--- /dev/null
+++ b/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep
@@ -0,0 +1,172 @@
+targetScope = 'subscription'
+
+metadata name = 'Using large parameter set'
+metadata description = 'This instance deploys the module with most of its features enabled.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change.
+
+@description('Optional. The location to deploy resources to.')
+#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically
+param resourceLocation string = deployment().location
+
+@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.')
+param serviceShort string = 'nnwmax'
+
+@description('Optional. A token to inject into the name of each resource.')
+param namePrefix string = '#_namePrefix_#'
+
+@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG
+param tempLocation string = 'uksouth'
+
+// ============ //
+// Dependencies //
+// ============ //
+
+// General resources
+// =================
+resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
+  name: resourceGroupName
+  location: tempLocation
+}
+
+resource resourceGroupDependencies 'Microsoft.Resources/resourceGroups@2021-04-01' = {
+  name: 'dep-${namePrefix}-network.networkwatcher-${serviceShort}-rg'
+  location: tempLocation
+}
+
+module nestedDependencies 'dependencies.bicep' = {
+  scope: resourceGroupDependencies
+  name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies'
+  params: {
+    managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}'
+    firstNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-1-${serviceShort}'
+    secondNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-2-${serviceShort}'
+    virtualMachineName: 'dep-${namePrefix}-vm-${serviceShort}'
+    virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}'
+    location: tempLocation
+  }
+}
+
+// Diagnostics
+// ===========
+module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = {
+  scope: resourceGroupDependencies
+  name: '${uniqueString(deployment().name, tempLocation)}-diagnosticDependencies'
+  params: {
+    storageAccountName: 'dep${namePrefix}diasa${serviceShort}01'
+    logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}'
+    eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}'
+    eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}'
+    location: tempLocation
+  }
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+  scope: resourceGroup
+  name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}'
+  params: {
+    name: 'NetworkWatcher_${tempLocation}'
+    location: tempLocation
+    connectionMonitors: [
+      {
+        name: '${namePrefix}-${serviceShort}-cm-001'
+        endpoints: [
+          {
+            name: '${namePrefix}-subnet-001(${resourceGroup.name})'
+            resourceId: nestedDependencies.outputs.virtualMachineResourceId
+            type: 'AzureVM'
+          }
+          {
+            address: 'www.bing.com'
+            name: 'Bing'
+            type: 'ExternalAddress'
+          }
+        ]
+        testConfigurations: [
+          {
+            httpConfiguration: {
+              method: 'Get'
+              port: 80
+              preferHTTPS: false
+              requestHeaders: []
+              validStatusCodeRanges: [
+                '200'
+              ]
+            }
+            name: 'HTTP Bing Test'
+            protocol: 'Http'
+            successThreshold: {
+              checksFailedPercent: 5
+              roundTripTimeMs: 100
+            }
+            testFrequencySec: 30
+          }
+        ]
+        testGroups: [
+          {
+            destinations: [
+              'Bing'
+            ]
+            disable: false
+            name: 'test-http-Bing'
+            sources: [
+              '${namePrefix}-subnet-001(${resourceGroup.name})'
+            ]
+            testConfigurations: [
+              'HTTP Bing Test'
+            ]
+          }
+        ]
+        workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId
+      }
+    ]
+    flowLogs: [
+      {
+        enabled: false
+        storageId: diagnosticDependencies.outputs.storageAccountResourceId
+        targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId
+      }
+      {
+        formatVersion: 1
+        name: '${namePrefix}-${serviceShort}-fl-001'
+        retentionInDays: 8
+        storageId: diagnosticDependencies.outputs.storageAccountResourceId
+        targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId
+        trafficAnalyticsInterval: 10
+        workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId
+      }
+    ]
+    roleAssignments: [
+      {
+        roleDefinitionIdOrName: 'Owner'
+        principalId: nestedDependencies.outputs.managedIdentityPrincipalId
+        principalType: 'ServicePrincipal'
+      }
+      {
+        roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
+        principalId: nestedDependencies.outputs.managedIdentityPrincipalId
+        principalType: 'ServicePrincipal'
+      }
+      {
+        roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')
+        principalId: nestedDependencies.outputs.managedIdentityPrincipalId
+        principalType: 'ServicePrincipal'
+      }
+    ]
+    tags: {
+      'hidden-title': 'This is visible in the resource name'
+      Environment: 'Non-Prod'
+      Role: 'DeploymentValidation'
+    }
+  }
+}]
diff --git a/avm/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep
new file mode 100644
index 0000000000..c20f841f30
--- /dev/null
+++ b/avm/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep
@@ -0,0 +1,144 @@
+@description('Optional. The location to deploy to.')
+param location string = resourceGroup().location
+
+@description('Required. The name of the Virtual Network to create.')
+param virtualNetworkName string
+
+@description('Required. The name of the Managed Identity to create.')
+param managedIdentityName string
+
+@description('Required. The name of the first Network Security Group to create.')
+param firstNetworkSecurityGroupName string
+
+@description('Required. The name of the second Network Security Group to create.')
+param secondNetworkSecurityGroupName string
+
+@description('Required. The name of the Virtual Machine to create.')
+param virtualMachineName string
+
+@description('Optional. The password to leverage for the VM login.')
+@secure()
+param password string = newGuid()
+
+var addressPrefix = '10.0.0.0/16'
+
+resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = {
+  name: virtualNetworkName
+  location: location
+  properties: {
+    addressSpace: {
+      addressPrefixes: [
+        addressPrefix
+      ]
+    }
+    subnets: [
+      {
+        name: 'defaultSubnet'
+        properties: {
+          addressPrefix: cidrSubnet(addressPrefix, 16, 0)
+        }
+      }
+    ]
+  }
+}
+
+resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
+  name: managedIdentityName
+  location: location
+}
+
+resource firstNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = {
+  name: firstNetworkSecurityGroupName
+  location: location
+}
+
+resource secondNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = {
+  name: secondNetworkSecurityGroupName
+  location: location
+}
+
+resource networkInterface 'Microsoft.Network/networkInterfaces@2023-04-01' = {
+  name: '${virtualMachineName}-nic'
+  location: location
+  properties: {
+    ipConfigurations: [
+      {
+        name: 'ipconfig01'
+        properties: {
+          subnet: {
+            id: virtualNetwork.properties.subnets[0].id
+          }
+        }
+      }
+    ]
+  }
+}
+
+resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-08-01' = {
+  name: virtualMachineName
+  location: location
+  properties: {
+    networkProfile: {
+      networkInterfaces: [
+        {
+          id: networkInterface.id
+          properties: {
+            deleteOption: 'Delete'
+            primary: true
+          }
+        }
+      ]
+    }
+    storageProfile: {
+      imageReference: {
+        publisher: 'Canonical'
+        offer: '0001-com-ubuntu-server-jammy'
+        sku: '22_04-lts-gen2'
+        version: 'latest'
+      }
+      osDisk: {
+        deleteOption: 'Delete'
+        createOption: 'FromImage'
+      }
+    }
+    hardwareProfile: {
+      vmSize: 'Standard_B1ms'
+    }
+    osProfile: {
+      adminUsername: '${virtualMachineName}cake'
+      adminPassword: password
+      computerName: virtualMachineName
+      linuxConfiguration: {
+        disablePasswordAuthentication: false
+      }
+    }
+  }
+}
+
+resource extension 'Microsoft.Compute/virtualMachines/extensions@2021-07-01' = {
+  name: 'NetworkWatcherAgent'
+  parent: virtualMachine
+  location: location
+  properties: {
+    publisher: 'Microsoft.Azure.NetworkWatcher'
+    type: 'NetworkWatcherAgentLinux'
+    typeHandlerVersion: '1.4'
+    autoUpgradeMinorVersion: true
+    enableAutomaticUpgrade: false
+    settings: {}
+    protectedSettings: {}
+    suppressFailures: false
+  }
+}
+
+@description('The principal ID of the created Managed Identity.')
+output managedIdentityPrincipalId string = managedIdentity.properties.principalId
+
+@description('The resource ID of the created Virtual Machine.')
+output virtualMachineResourceId string = virtualMachine.id
+
+@description('The resource ID of the first created Network Security Group.')
+output firstNetworkSecurityGroupResourceId string = firstNetworkSecurityGroup.id
+
+@description('The resource ID of the second created Network Security Group.')
+output secondNetworkSecurityGroupResourceId string = secondNetworkSecurityGroup.id
diff --git a/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep
new file mode 100644
index 0000000000..32fc738840
--- /dev/null
+++ b/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep
@@ -0,0 +1,156 @@
+targetScope = 'subscription'
+
+metadata name = 'WAF-aligned'
+metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change.
+
+@description('Optional. The location to deploy resources to.')
+#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically
+param resourceLocation string = deployment().location
+
+@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.')
+param serviceShort string = 'nnwwaf'
+
+@description('Optional. A token to inject into the name of each resource.')
+param namePrefix string = '#_namePrefix_#'
+
+@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG
+param tempLocation string = 'uksouth'
+
+// ============ //
+// Dependencies //
+// ============ //
+
+// General resources
+// =================
+resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
+  name: resourceGroupName
+  location: tempLocation
+}
+
+resource resourceGroupDependencies 'Microsoft.Resources/resourceGroups@2021-04-01' = {
+  name: 'dep-${namePrefix}-network.networkwatcher-${serviceShort}-rg'
+  location: tempLocation
+}
+
+module nestedDependencies 'dependencies.bicep' = {
+  scope: resourceGroupDependencies
+  name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies'
+  params: {
+    managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}'
+    firstNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-1-${serviceShort}'
+    secondNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-2-${serviceShort}'
+    virtualMachineName: 'dep-${namePrefix}-vm-${serviceShort}'
+    virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}'
+    location: tempLocation
+  }
+}
+
+// Diagnostics
+// ===========
+module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = {
+  scope: resourceGroupDependencies
+  name: '${uniqueString(deployment().name, tempLocation)}-diagnosticDependencies'
+  params: {
+    storageAccountName: 'dep${namePrefix}diasa${serviceShort}01'
+    logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}'
+    eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}'
+    eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}'
+    location: tempLocation
+  }
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+  scope: resourceGroup
+  name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}'
+  params: {
+    name: 'NetworkWatcher_${tempLocation}'
+    location: tempLocation
+    connectionMonitors: [
+      {
+        name: '${namePrefix}-${serviceShort}-cm-001'
+        endpoints: [
+          {
+            name: '${namePrefix}-subnet-001(${resourceGroup.name})'
+            resourceId: nestedDependencies.outputs.virtualMachineResourceId
+            type: 'AzureVM'
+          }
+          {
+            address: 'www.bing.com'
+            name: 'Bing'
+            type: 'ExternalAddress'
+          }
+        ]
+        testConfigurations: [
+          {
+            httpConfiguration: {
+              method: 'Get'
+              port: 80
+              preferHTTPS: false
+              requestHeaders: []
+              validStatusCodeRanges: [
+                '200'
+              ]
+            }
+            name: 'HTTP Bing Test'
+            protocol: 'Http'
+            successThreshold: {
+              checksFailedPercent: 5
+              roundTripTimeMs: 100
+            }
+            testFrequencySec: 30
+          }
+        ]
+        testGroups: [
+          {
+            destinations: [
+              'Bing'
+            ]
+            disable: false
+            name: 'test-http-Bing'
+            sources: [
+              '${namePrefix}-subnet-001(${resourceGroup.name})'
+            ]
+            testConfigurations: [
+              'HTTP Bing Test'
+            ]
+          }
+        ]
+        workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId
+      }
+    ]
+    flowLogs: [
+      {
+        enabled: false
+        storageId: diagnosticDependencies.outputs.storageAccountResourceId
+        targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId
+      }
+      {
+        formatVersion: 1
+        name: '${namePrefix}-${serviceShort}-fl-001'
+        retentionInDays: 8
+        storageId: diagnosticDependencies.outputs.storageAccountResourceId
+        targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId
+        trafficAnalyticsInterval: 10
+        workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId
+      }
+    ]
+    tags: {
+      'hidden-title': 'This is visible in the resource name'
+      Environment: 'Non-Prod'
+      Role: 'DeploymentValidation'
+    }
+  }
+}]
diff --git a/avm/res/network/network-watcher/version.json b/avm/res/network/network-watcher/version.json
new file mode 100644
index 0000000000..7fa401bdf7
--- /dev/null
+++ b/avm/res/network/network-watcher/version.json
@@ -0,0 +1,7 @@
+{
+    "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#",
+    "version": "0.1",
+    "pathFilters": [
+        "./main.json"
+    ]
+}

From 8021bb8f6df6d7b2863c71105a33d7c29ecf752d Mon Sep 17 00:00:00 2001
From: Alexander Sehr <ASehr@hotmail.de>
Date: Thu, 11 Apr 2024 11:43:04 +0200
Subject: [PATCH 5/9] fix: Added missing `privateLinkServiceConnectionName`
 parameter to Private Endpoint UDT (#1614)

## Description

To enable users to set an explicit `privateLinkServiceConnectionName` it
must be defined in the UDT where it was missing. Updated for all modules
that @krbar updated in his preceeding PR
https://github.com/Azure/bicep-registry-modules/pull/1472


![image](https://github.com/Azure/bicep-registry-modules/assets/5365358/ae4213c7-6f67-439d-9b5f-6e1bf1d5a612)

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |

[![avm.res.automation.automation-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml)

[![avm.res.batch.batch-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml)

[![avm.res.cache.redis](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml)

[![avm.res.cognitive-services.account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml)

[![avm.res.data-factory.factory](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml)

[![avm.res.digital-twins.digital-twins-instance](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml)

[![avm.res.document-db.database-account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml)

[![avm.res.event-grid.domain](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml)

[![avm.res.event-grid.namespace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml)

[![avm.res.event-grid.topic](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml)

[![avm.res.insights.private-link-scope](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml)

[![avm.res.key-vault.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml)

[![avm.res.purview.account](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml)

[![avm.res.recovery-services.vault](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml)

[![avm.res.relay.namespace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml)

[![avm.res.search.search-service](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml)

[![avm.res.service-bus.namespace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml)

[![avm.res.signal-r-service.signal-r](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml)

[![avm.res.signal-r-service.web-pub-sub](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml)

[![avm.res.sql.server](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml)

[![avm.res.synapse.private-link-hub](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml)

[![avm.res.synapse.workspace](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml/badge.svg?branch=users%2Falsehr%2FudtLinkName&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml)

## Type of Change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utlities (Non-module effecting
changes)
- [ ] Azure Verified Module updates:
- [x] Bugfix containing backwards compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [ ] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation

---------

Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com>
---
 .../automation/automation-account/README.md   |  8 ++++
 .../automation/automation-account/main.bicep  |  3 ++
 .../automation/automation-account/main.json   |  9 ++++-
 avm/res/batch/batch-account/README.md         |  8 ++++
 avm/res/batch/batch-account/main.bicep        |  3 ++
 avm/res/batch/batch-account/main.json         |  9 ++++-
 avm/res/cache/redis/README.md                 |  8 ++++
 avm/res/cache/redis/main.bicep                |  3 ++
 avm/res/cache/redis/main.json                 |  9 ++++-
 avm/res/cognitive-services/account/README.md  |  8 ++++
 avm/res/cognitive-services/account/main.bicep |  3 ++
 avm/res/cognitive-services/account/main.json  |  9 ++++-
 avm/res/data-factory/factory/README.md        |  8 ++++
 avm/res/data-factory/factory/main.bicep       |  3 ++
 avm/res/data-factory/factory/main.json        |  9 ++++-
 .../digital-twins-instance/README.md          |  8 ++++
 .../digital-twins-instance/main.bicep         |  3 ++
 .../digital-twins-instance/main.json          |  9 ++++-
 .../document-db/database-account/README.md    |  8 ++++
 .../document-db/database-account/main.bicep   |  3 ++
 .../document-db/database-account/main.json    |  9 ++++-
 avm/res/event-grid/domain/README.md           |  8 ++++
 avm/res/event-grid/domain/main.bicep          |  3 ++
 avm/res/event-grid/domain/main.json           |  9 ++++-
 avm/res/event-grid/namespace/README.md        |  8 ++++
 avm/res/event-grid/namespace/main.bicep       |  3 ++
 avm/res/event-grid/namespace/main.json        |  9 ++++-
 avm/res/event-grid/topic/README.md            |  8 ++++
 avm/res/event-grid/topic/main.bicep           |  3 ++
 avm/res/event-grid/topic/main.json            |  9 ++++-
 avm/res/insights/private-link-scope/README.md |  8 ++++
 .../insights/private-link-scope/main.bicep    |  3 ++
 avm/res/insights/private-link-scope/main.json |  9 ++++-
 avm/res/key-vault/vault/README.md             |  8 ++++
 avm/res/key-vault/vault/main.bicep            |  3 ++
 avm/res/key-vault/vault/main.json             |  9 ++++-
 avm/res/purview/account/README.md             | 40 +++++++++++++++++++
 avm/res/purview/account/main.bicep            |  3 ++
 avm/res/purview/account/main.json             |  9 ++++-
 avm/res/recovery-services/vault/README.md     |  8 ++++
 avm/res/recovery-services/vault/main.bicep    |  3 ++
 avm/res/recovery-services/vault/main.json     |  9 ++++-
 avm/res/relay/namespace/README.md             |  8 ++++
 avm/res/relay/namespace/main.bicep            |  3 ++
 avm/res/relay/namespace/main.json             |  9 ++++-
 avm/res/search/search-service/README.md       |  8 ++++
 avm/res/search/search-service/main.bicep      |  3 ++
 avm/res/search/search-service/main.json       |  9 ++++-
 avm/res/service-bus/namespace/README.md       | 12 ++++++
 avm/res/service-bus/namespace/main.bicep      |  3 ++
 avm/res/service-bus/namespace/main.json       |  9 ++++-
 .../namespace/tests/e2e/max/main.test.bicep   |  2 +
 avm/res/signal-r-service/signal-r/README.md   |  8 ++++
 avm/res/signal-r-service/signal-r/main.bicep  |  3 ++
 avm/res/signal-r-service/signal-r/main.json   |  9 ++++-
 .../signal-r-service/web-pub-sub/README.md    |  8 ++++
 .../signal-r-service/web-pub-sub/main.bicep   |  3 ++
 .../signal-r-service/web-pub-sub/main.json    |  9 ++++-
 avm/res/sql/server/README.md                  |  8 ++++
 avm/res/sql/server/main.bicep                 |  3 ++
 avm/res/sql/server/main.json                  |  9 ++++-
 avm/res/synapse/private-link-hub/README.md    |  8 ++++
 avm/res/synapse/private-link-hub/main.bicep   |  3 ++
 avm/res/synapse/private-link-hub/main.json    |  9 ++++-
 avm/res/synapse/workspace/README.md           |  8 ++++
 avm/res/synapse/workspace/main.bicep          |  3 ++
 avm/res/synapse/workspace/main.json           |  9 ++++-
 67 files changed, 456 insertions(+), 22 deletions(-)

diff --git a/avm/res/automation/automation-account/README.md b/avm/res/automation/automation-account/README.md
index 27d88eee16..26fd342e22 100644
--- a/avm/res/automation/automation-account/README.md
+++ b/avm/res/automation/automation-account/README.md
@@ -1463,6 +1463,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. |
@@ -1665,6 +1666,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/automation/automation-account/main.bicep b/avm/res/automation/automation-account/main.bicep
index 4d401435a5..3f579884c4 100644
--- a/avm/res/automation/automation-account/main.bicep
+++ b/avm/res/automation/automation-account/main.bicep
@@ -584,6 +584,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".')
   service: string
 
diff --git a/avm/res/automation/automation-account/main.json b/avm/res/automation/automation-account/main.json
index 758ecb9deb..ef54d7a09b 100644
--- a/avm/res/automation/automation-account/main.json
+++ b/avm/res/automation/automation-account/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "6251765763506796385"
+      "templateHash": "16001446000186457588"
     },
     "name": "Automation Accounts",
     "description": "This module deploys an Azure Automation Account.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "metadata": {
diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md
index 045ce70467..f2d6ddd938 100644
--- a/avm/res/batch/batch-account/README.md
+++ b/avm/res/batch/batch-account/README.md
@@ -1093,6 +1093,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. |
@@ -1295,6 +1296,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/batch/batch-account/main.bicep b/avm/res/batch/batch-account/main.bicep
index 84657dc22e..b74ebf3012 100644
--- a/avm/res/batch/batch-account/main.bicep
+++ b/avm/res/batch/batch-account/main.bicep
@@ -420,6 +420,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".')
   service: string
 
diff --git a/avm/res/batch/batch-account/main.json b/avm/res/batch/batch-account/main.json
index 1dcab47561..918b144932 100644
--- a/avm/res/batch/batch-account/main.json
+++ b/avm/res/batch/batch-account/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "6890367843750826610"
+      "templateHash": "11103817479788393007"
     },
     "name": "Batch Accounts",
     "description": "This module deploys a Batch Account.",
@@ -218,6 +218,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "metadata": {
diff --git a/avm/res/cache/redis/README.md b/avm/res/cache/redis/README.md
index 78ea24c202..a8e005dfd5 100644
--- a/avm/res/cache/redis/README.md
+++ b/avm/res/cache/redis/README.md
@@ -858,6 +858,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1054,6 +1055,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/cache/redis/main.bicep b/avm/res/cache/redis/main.bicep
index 92250dddf6..a7975ce724 100644
--- a/avm/res/cache/redis/main.bicep
+++ b/avm/res/cache/redis/main.bicep
@@ -354,6 +354,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/cache/redis/main.json b/avm/res/cache/redis/main.json
index d1d6787625..0dcf9d3c88 100644
--- a/avm/res/cache/redis/main.json
+++ b/avm/res/cache/redis/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "14239657026051186935"
+      "templateHash": "7874819819895628744"
     },
     "name": "Redis Cache",
     "description": "This module deploys a Redis Cache.",
@@ -80,6 +80,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md
index ad3aa7e878..587b599762 100644
--- a/avm/res/cognitive-services/account/README.md
+++ b/avm/res/cognitive-services/account/README.md
@@ -1241,6 +1241,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1437,6 +1438,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep
index fdac84cba9..d88001d7f3 100644
--- a/avm/res/cognitive-services/account/main.bicep
+++ b/avm/res/cognitive-services/account/main.bicep
@@ -549,6 +549,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json
index 35f3b05f87..db28c215b9 100644
--- a/avm/res/cognitive-services/account/main.json
+++ b/avm/res/cognitive-services/account/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "4464138557763734337"
+      "templateHash": "1728463055074429069"
     },
     "name": "Cognitive Services",
     "description": "This module deploys a Cognitive Service.",
@@ -218,6 +218,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/data-factory/factory/README.md b/avm/res/data-factory/factory/README.md
index bda24aa203..7dab0aa926 100644
--- a/avm/res/data-factory/factory/README.md
+++ b/avm/res/data-factory/factory/README.md
@@ -912,6 +912,7 @@ Configuration Details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1108,6 +1109,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/data-factory/factory/main.bicep b/avm/res/data-factory/factory/main.bicep
index c82317923d..b8214de937 100644
--- a/avm/res/data-factory/factory/main.bicep
+++ b/avm/res/data-factory/factory/main.bicep
@@ -408,6 +408,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/data-factory/factory/main.json b/avm/res/data-factory/factory/main.json
index aad72cb4c9..660811ad99 100644
--- a/avm/res/data-factory/factory/main.json
+++ b/avm/res/data-factory/factory/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "14187397977187427796"
+      "templateHash": "15112622274427305357"
     },
     "name": "Data Factories",
     "description": "This module deploys a Data Factory.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/digital-twins/digital-twins-instance/README.md b/avm/res/digital-twins/digital-twins-instance/README.md
index 1c7a729b3b..61d336db5c 100644
--- a/avm/res/digital-twins/digital-twins-instance/README.md
+++ b/avm/res/digital-twins/digital-twins-instance/README.md
@@ -780,6 +780,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Privte Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -976,6 +977,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Privte Endpoint into a different resource group than the main resource.
diff --git a/avm/res/digital-twins/digital-twins-instance/main.bicep b/avm/res/digital-twins/digital-twins-instance/main.bicep
index 7343b751e7..e1c317709d 100644
--- a/avm/res/digital-twins/digital-twins-instance/main.bicep
+++ b/avm/res/digital-twins/digital-twins-instance/main.bicep
@@ -362,6 +362,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/digital-twins/digital-twins-instance/main.json b/avm/res/digital-twins/digital-twins-instance/main.json
index 50fc49a6d8..be1138a612 100644
--- a/avm/res/digital-twins/digital-twins-instance/main.json
+++ b/avm/res/digital-twins/digital-twins-instance/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "592119492280088110"
+      "templateHash": "16174863317053860668"
     },
     "name": "Digital Twins Instances",
     "description": "This module deploys an Azure Digital Twins Instance.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/document-db/database-account/README.md b/avm/res/document-db/database-account/README.md
index 6ae99ad652..fa45217f9c 100644
--- a/avm/res/document-db/database-account/README.md
+++ b/avm/res/document-db/database-account/README.md
@@ -2772,6 +2772,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. |
@@ -2974,6 +2975,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/document-db/database-account/main.bicep b/avm/res/document-db/database-account/main.bicep
index 353f3a673f..5cbfbfe85d 100644
--- a/avm/res/document-db/database-account/main.bicep
+++ b/avm/res/document-db/database-account/main.bicep
@@ -599,6 +599,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".')
   service: string
 
diff --git a/avm/res/document-db/database-account/main.json b/avm/res/document-db/database-account/main.json
index bb1a275336..943fa8af42 100644
--- a/avm/res/document-db/database-account/main.json
+++ b/avm/res/document-db/database-account/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "4437379960992955499"
+      "templateHash": "9794166259717067711"
     },
     "name": "DocumentDB Database Accounts",
     "description": "This module deploys a DocumentDB Database Account.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "metadata": {
diff --git a/avm/res/event-grid/domain/README.md b/avm/res/event-grid/domain/README.md
index ae021496d2..11e5d6818e 100644
--- a/avm/res/event-grid/domain/README.md
+++ b/avm/res/event-grid/domain/README.md
@@ -745,6 +745,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -941,6 +942,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/event-grid/domain/main.bicep b/avm/res/event-grid/domain/main.bicep
index 9470ab66dd..0473c974c1 100644
--- a/avm/res/event-grid/domain/main.bicep
+++ b/avm/res/event-grid/domain/main.bicep
@@ -324,6 +324,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/event-grid/domain/main.json b/avm/res/event-grid/domain/main.json
index 00d1d38a99..f47aa20bf6 100644
--- a/avm/res/event-grid/domain/main.json
+++ b/avm/res/event-grid/domain/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "16218993533368650481"
+      "templateHash": "17171097905179773848"
     },
     "name": "Event Grid Domains",
     "description": "This module deploys an Event Grid Domain.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/event-grid/namespace/README.md b/avm/res/event-grid/namespace/README.md
index 856afe7f04..3be6075be5 100644
--- a/avm/res/event-grid/namespace/README.md
+++ b/avm/res/event-grid/namespace/README.md
@@ -1710,6 +1710,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1906,6 +1907,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/event-grid/namespace/main.bicep b/avm/res/event-grid/namespace/main.bicep
index 56edb55bdb..e76d65e7c2 100644
--- a/avm/res/event-grid/namespace/main.bicep
+++ b/avm/res/event-grid/namespace/main.bicep
@@ -491,6 +491,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/event-grid/namespace/main.json b/avm/res/event-grid/namespace/main.json
index f5d24919c4..45f6ea4550 100644
--- a/avm/res/event-grid/namespace/main.json
+++ b/avm/res/event-grid/namespace/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "16128168138494478881"
+      "templateHash": "18358017202196196766"
     },
     "name": "Event Grid Namespaces",
     "description": "This module deploys an Event Grid Namespace.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/event-grid/topic/README.md b/avm/res/event-grid/topic/README.md
index c611785a80..c589fdc2a3 100644
--- a/avm/res/event-grid/topic/README.md
+++ b/avm/res/event-grid/topic/README.md
@@ -839,6 +839,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1035,6 +1036,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/event-grid/topic/main.bicep b/avm/res/event-grid/topic/main.bicep
index 6f23833d93..b99f1f0bae 100644
--- a/avm/res/event-grid/topic/main.bicep
+++ b/avm/res/event-grid/topic/main.bicep
@@ -334,6 +334,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/event-grid/topic/main.json b/avm/res/event-grid/topic/main.json
index 5d7ac45336..8cf80a5253 100644
--- a/avm/res/event-grid/topic/main.json
+++ b/avm/res/event-grid/topic/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "3980392845295222742"
+      "templateHash": "16219476239317554941"
     },
     "name": "Event Grid Topics",
     "description": "This module deploys an Event Grid Topic.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/insights/private-link-scope/README.md b/avm/res/insights/private-link-scope/README.md
index ae2484afd1..33afa6a34b 100644
--- a/avm/res/insights/private-link-scope/README.md
+++ b/avm/res/insights/private-link-scope/README.md
@@ -941,6 +941,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1137,6 +1138,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/insights/private-link-scope/main.bicep b/avm/res/insights/private-link-scope/main.bicep
index 111bb87167..787d7aaafa 100644
--- a/avm/res/insights/private-link-scope/main.bicep
+++ b/avm/res/insights/private-link-scope/main.bicep
@@ -271,6 +271,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/insights/private-link-scope/main.json b/avm/res/insights/private-link-scope/main.json
index b0c5d75a20..8066330d58 100644
--- a/avm/res/insights/private-link-scope/main.json
+++ b/avm/res/insights/private-link-scope/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "3043663816660820718"
+      "templateHash": "15594611995771551731"
     },
     "name": "Azure Monitor Private Link Scopes",
     "description": "This module deploys an Azure Monitor Private Link Scope.",
@@ -123,6 +123,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md
index 54df61a844..f86a29fbc3 100644
--- a/avm/res/key-vault/vault/README.md
+++ b/avm/res/key-vault/vault/README.md
@@ -1320,6 +1320,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1516,6 +1517,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep
index 4fa14810d9..57ee7e3197 100644
--- a/avm/res/key-vault/vault/main.bicep
+++ b/avm/res/key-vault/vault/main.bicep
@@ -459,6 +459,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json
index 903efb61de..9a39a19b56 100644
--- a/avm/res/key-vault/vault/main.json
+++ b/avm/res/key-vault/vault/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "7617547098704473732"
+      "templateHash": "15417452365743513256"
     },
     "name": "Key Vaults",
     "description": "This module deploys a Key Vault.",
@@ -218,6 +218,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/purview/account/README.md b/avm/res/purview/account/README.md
index e8c88a8d1b..5f52f7ce62 100644
--- a/avm/res/purview/account/README.md
+++ b/avm/res/purview/account/README.md
@@ -667,6 +667,7 @@ Configuration details for Purview Account private endpoints. For security reason
 | [`name`](#parameter-accountprivateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-accountprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-accountprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-accountprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-accountprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-accountprivateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-accountprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -863,6 +864,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `accountPrivateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `accountPrivateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
@@ -1156,6 +1164,7 @@ Configuration details for Purview Managed Event Hub namespace private endpoints.
 | [`name`](#parameter-eventhubprivateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-eventhubprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-eventhubprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-eventhubprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-eventhubprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-eventhubprivateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-eventhubprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1352,6 +1361,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `eventHubPrivateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `eventHubPrivateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
@@ -1563,6 +1579,7 @@ Configuration details for Purview Portal private endpoints. For security reasons
 | [`name`](#parameter-portalprivateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-portalprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-portalprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-portalprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-portalprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-portalprivateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-portalprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1759,6 +1776,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `portalPrivateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `portalPrivateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
@@ -2003,6 +2027,7 @@ Configuration details for Purview Managed Storage Account blob private endpoints
 | [`name`](#parameter-storageblobprivateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-storageblobprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-storageblobprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-storageblobprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-storageblobprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-storageblobprivateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-storageblobprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -2199,6 +2224,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `storageBlobPrivateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `storageBlobPrivateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
@@ -2338,6 +2370,7 @@ Configuration details for Purview Managed Storage Account queue private endpoint
 | [`name`](#parameter-storagequeueprivateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-storagequeueprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-storagequeueprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-storagequeueprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-storagequeueprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-storagequeueprivateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-storagequeueprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -2534,6 +2567,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `storageQueuePrivateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `storageQueuePrivateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/purview/account/main.bicep b/avm/res/purview/account/main.bicep
index 42a4f887f9..b0beba41f6 100644
--- a/avm/res/purview/account/main.bicep
+++ b/avm/res/purview/account/main.bicep
@@ -558,6 +558,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   // Variant 1: A default service can be assumed (i.e., for services that only have one private endpoint type)
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
diff --git a/avm/res/purview/account/main.json b/avm/res/purview/account/main.json
index 79ece163df..b7c2504156 100644
--- a/avm/res/purview/account/main.json
+++ b/avm/res/purview/account/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "10478276284688945005"
+      "templateHash": "17174301778360799299"
     },
     "name": "Purview Accounts",
     "description": "This module deploys a Purview Account.",
@@ -258,6 +258,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/recovery-services/vault/README.md b/avm/res/recovery-services/vault/README.md
index 60cb4dddd3..445ea28d6f 100644
--- a/avm/res/recovery-services/vault/README.md
+++ b/avm/res/recovery-services/vault/README.md
@@ -2181,6 +2181,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -2377,6 +2378,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/recovery-services/vault/main.bicep b/avm/res/recovery-services/vault/main.bicep
index 293e839c67..8e50e68716 100644
--- a/avm/res/recovery-services/vault/main.bicep
+++ b/avm/res/recovery-services/vault/main.bicep
@@ -444,6 +444,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/recovery-services/vault/main.json b/avm/res/recovery-services/vault/main.json
index 42225dc535..577dc26077 100644
--- a/avm/res/recovery-services/vault/main.json
+++ b/avm/res/recovery-services/vault/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "7655373586022764690"
+      "templateHash": "2215975966866051299"
     },
     "name": "Recovery Services Vaults",
     "description": "This module deploys a Recovery Services Vault.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/relay/namespace/README.md b/avm/res/relay/namespace/README.md
index c9a6931fbf..00e11010ba 100644
--- a/avm/res/relay/namespace/README.md
+++ b/avm/res/relay/namespace/README.md
@@ -927,6 +927,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1123,6 +1124,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/relay/namespace/main.bicep b/avm/res/relay/namespace/main.bicep
index 18ca612874..1152aa1dfc 100644
--- a/avm/res/relay/namespace/main.bicep
+++ b/avm/res/relay/namespace/main.bicep
@@ -381,6 +381,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/relay/namespace/main.json b/avm/res/relay/namespace/main.json
index 20a1a87e84..bd8938cde5 100644
--- a/avm/res/relay/namespace/main.json
+++ b/avm/res/relay/namespace/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "18413649405351363659"
+      "templateHash": "17233437629149406382"
     },
     "name": "Relay Namespaces",
     "description": "This module deploys a Relay Namespace",
@@ -123,6 +123,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/search/search-service/README.md b/avm/res/search/search-service/README.md
index b2b9d3299b..fddc70b242 100644
--- a/avm/res/search/search-service/README.md
+++ b/avm/res/search/search-service/README.md
@@ -942,6 +942,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1138,6 +1139,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/search/search-service/main.bicep b/avm/res/search/search-service/main.bicep
index 755034072f..3beb423d54 100644
--- a/avm/res/search/search-service/main.bicep
+++ b/avm/res/search/search-service/main.bicep
@@ -379,6 +379,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/search/search-service/main.json b/avm/res/search/search-service/main.json
index 303cb2d214..df489a9cab 100644
--- a/avm/res/search/search-service/main.json
+++ b/avm/res/search/search-service/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "13049058701753751229"
+      "templateHash": "13069544635575133650"
     },
     "name": "Search Services",
     "description": "This module deploys a Search Service.",
@@ -136,6 +136,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/service-bus/namespace/README.md b/avm/res/service-bus/namespace/README.md
index 125cf687fa..4ef8712ce2 100644
--- a/avm/res/service-bus/namespace/README.md
+++ b/avm/res/service-bus/namespace/README.md
@@ -294,9 +294,11 @@ module namespace 'br/public:avm/res/service-bus/namespace:<version>' = {
             }
           }
         ]
+        name: 'myPrivateEndpoint'
         privateDnsZoneResourceIds: [
           '<privateDNSZoneResourceId>'
         ]
+        privateLinkServiceConnectionName: 'customLinkName'
         subnetResourceId: '<subnetResourceId>'
         tags: {
           Environment: 'Non-Prod'
@@ -526,9 +528,11 @@ module namespace 'br/public:avm/res/service-bus/namespace:<version>' = {
               }
             }
           ],
+          "name": "myPrivateEndpoint",
           "privateDnsZoneResourceIds": [
             "<privateDNSZoneResourceId>"
           ],
+          "privateLinkServiceConnectionName": "customLinkName",
           "subnetResourceId": "<subnetResourceId>",
           "tags": {
             "Environment": "Non-Prod",
@@ -1647,6 +1651,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1843,6 +1848,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/service-bus/namespace/main.bicep b/avm/res/service-bus/namespace/main.bicep
index 8f3a7c22ab..66b8bc38c8 100644
--- a/avm/res/service-bus/namespace/main.bicep
+++ b/avm/res/service-bus/namespace/main.bicep
@@ -499,6 +499,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/service-bus/namespace/main.json b/avm/res/service-bus/namespace/main.json
index e9e7ee32e7..86701b3773 100644
--- a/avm/res/service-bus/namespace/main.json
+++ b/avm/res/service-bus/namespace/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "12101686609428052773"
+      "templateHash": "9228932977984857525"
     },
     "name": "Service Bus Namespaces",
     "description": "This module deploys a Service Bus Namespace.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/service-bus/namespace/tests/e2e/max/main.test.bicep b/avm/res/service-bus/namespace/tests/e2e/max/main.test.bicep
index a1a500e934..b08e017836 100644
--- a/avm/res/service-bus/namespace/tests/e2e/max/main.test.bicep
+++ b/avm/res/service-bus/namespace/tests/e2e/max/main.test.bicep
@@ -213,6 +213,8 @@ module testDeployment '../../../main.bicep' = [
       ]
       privateEndpoints: [
         {
+          name: 'myPrivateEndpoint'
+          privateLinkServiceConnectionName: 'customLinkName'
           subnetResourceId: nestedDependencies.outputs.subnetResourceId
           privateDnsZoneResourceIds: [
             nestedDependencies.outputs.privateDNSZoneResourceId
diff --git a/avm/res/signal-r-service/signal-r/README.md b/avm/res/signal-r-service/signal-r/README.md
index 28819bb5be..9466ec00a2 100644
--- a/avm/res/signal-r-service/signal-r/README.md
+++ b/avm/res/signal-r-service/signal-r/README.md
@@ -695,6 +695,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -891,6 +892,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/signal-r-service/signal-r/main.bicep b/avm/res/signal-r-service/signal-r/main.bicep
index 66afadbde1..a1ddf132b0 100644
--- a/avm/res/signal-r-service/signal-r/main.bicep
+++ b/avm/res/signal-r-service/signal-r/main.bicep
@@ -368,6 +368,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/signal-r-service/signal-r/main.json b/avm/res/signal-r-service/signal-r/main.json
index fda5c481ab..6a3345bbfc 100644
--- a/avm/res/signal-r-service/signal-r/main.json
+++ b/avm/res/signal-r-service/signal-r/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "3713977800764774886"
+      "templateHash": "15213574724705700339"
     },
     "name": "SignalR Service SignalR",
     "description": "This module deploys a SignalR Service SignalR.",
@@ -123,6 +123,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/signal-r-service/web-pub-sub/README.md b/avm/res/signal-r-service/web-pub-sub/README.md
index 303f1a02c5..bd364eb46f 100644
--- a/avm/res/signal-r-service/web-pub-sub/README.md
+++ b/avm/res/signal-r-service/web-pub-sub/README.md
@@ -664,6 +664,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -860,6 +861,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/signal-r-service/web-pub-sub/main.bicep b/avm/res/signal-r-service/web-pub-sub/main.bicep
index 7df5cef044..6f0d42ceb5 100644
--- a/avm/res/signal-r-service/web-pub-sub/main.bicep
+++ b/avm/res/signal-r-service/web-pub-sub/main.bicep
@@ -340,6 +340,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/signal-r-service/web-pub-sub/main.json b/avm/res/signal-r-service/web-pub-sub/main.json
index b0cd717eea..bb5da794c7 100644
--- a/avm/res/signal-r-service/web-pub-sub/main.json
+++ b/avm/res/signal-r-service/web-pub-sub/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "5123587026582880440"
+      "templateHash": "17706812200280440535"
     },
     "name": "SignalR Web PubSub Services",
     "description": "This module deploys a SignalR Web PubSub Service.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md
index ed1f6f52c9..31d607a435 100644
--- a/avm/res/sql/server/README.md
+++ b/avm/res/sql/server/README.md
@@ -1251,6 +1251,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -1447,6 +1448,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/sql/server/main.bicep b/avm/res/sql/server/main.bicep
index 1b95eb7fb0..b068331ee2 100644
--- a/avm/res/sql/server/main.bicep
+++ b/avm/res/sql/server/main.bicep
@@ -529,6 +529,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/sql/server/main.json b/avm/res/sql/server/main.json
index ef545418bd..5611ff656f 100644
--- a/avm/res/sql/server/main.json
+++ b/avm/res/sql/server/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "16217985022425971907"
+      "templateHash": "7285009334035421293"
     },
     "name": "Azure SQL Servers",
     "description": "This module deploys an Azure SQL Server.",
@@ -146,6 +146,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/synapse/private-link-hub/README.md b/avm/res/synapse/private-link-hub/README.md
index 676a1ea168..0fe999a92c 100644
--- a/avm/res/synapse/private-link-hub/README.md
+++ b/avm/res/synapse/private-link-hub/README.md
@@ -420,6 +420,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". |
@@ -616,6 +617,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/synapse/private-link-hub/main.bicep b/avm/res/synapse/private-link-hub/main.bicep
index c704bb0d20..f7294f8188 100644
--- a/avm/res/synapse/private-link-hub/main.bicep
+++ b/avm/res/synapse/private-link-hub/main.bicep
@@ -204,6 +204,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".')
   service: string?
 
diff --git a/avm/res/synapse/private-link-hub/main.json b/avm/res/synapse/private-link-hub/main.json
index edf4acca71..fd84d2835d 100644
--- a/avm/res/synapse/private-link-hub/main.json
+++ b/avm/res/synapse/private-link-hub/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "13337660618824697392"
+      "templateHash": "10734135538553335635"
     },
     "name": "Azure Synapse Analytics",
     "description": "This module deploys an Azure Synapse Analytics (Private Link Hub).",
@@ -123,6 +123,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "nullable": true,
diff --git a/avm/res/synapse/workspace/README.md b/avm/res/synapse/workspace/README.md
index e3b70632bd..62fbe376dd 100644
--- a/avm/res/synapse/workspace/README.md
+++ b/avm/res/synapse/workspace/README.md
@@ -1144,6 +1144,7 @@ Configuration details for private endpoints. For security reasons, it is recomme
 | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. |
 | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. |
 | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. |
+| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. |
 | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. |
 | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. |
 | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. |
@@ -1346,6 +1347,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g
 - Required: No
 - Type: array
 
+### Parameter: `privateEndpoints.privateLinkServiceConnectionName`
+
+The name of the private link connection to create.
+
+- Required: No
+- Type: string
+
 ### Parameter: `privateEndpoints.resourceGroupName`
 
 Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.
diff --git a/avm/res/synapse/workspace/main.bicep b/avm/res/synapse/workspace/main.bicep
index cd2ebc4b68..1e9c17624b 100644
--- a/avm/res/synapse/workspace/main.bicep
+++ b/avm/res/synapse/workspace/main.bicep
@@ -451,6 +451,9 @@ type privateEndpointType = {
   @description('Optional. The location to deploy the private endpoint to.')
   location: string?
 
+  @description('Optional. The name of the private link connection to create.')
+  privateLinkServiceConnectionName: string?
+
   @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".')
   service: string
 
diff --git a/avm/res/synapse/workspace/main.json b/avm/res/synapse/workspace/main.json
index 4ae63838c2..89049892d8 100644
--- a/avm/res/synapse/workspace/main.json
+++ b/avm/res/synapse/workspace/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "229457556089965339"
+      "templateHash": "456170449467900103"
     },
     "name": "Synapse Workspaces",
     "description": "This module deploys a Synapse Workspace.",
@@ -138,6 +138,13 @@
               "description": "Optional. The location to deploy the private endpoint to."
             }
           },
+          "privateLinkServiceConnectionName": {
+            "type": "string",
+            "nullable": true,
+            "metadata": {
+              "description": "Optional. The name of the private link connection to create."
+            }
+          },
           "service": {
             "type": "string",
             "metadata": {

From 1428397a83320e214b79395f615d9b859ff46d00 Mon Sep 17 00:00:00 2001
From: Rainer Halanek <61878316+rahalan@users.noreply.github.com>
Date: Thu, 11 Apr 2024 12:48:22 +0200
Subject: [PATCH 6/9] fix: update VM json, so static test doesn't fail (#1668)

Update of VM main.json file
---
 avm/res/compute/virtual-machine/main.json | 68 +++++++++++------------
 1 file changed, 34 insertions(+), 34 deletions(-)

diff --git a/avm/res/compute/virtual-machine/main.json b/avm/res/compute/virtual-machine/main.json
index 65a9cdeb1e..5d9c60bd68 100644
--- a/avm/res/compute/virtual-machine/main.json
+++ b/avm/res/compute/virtual-machine/main.json
@@ -5,8 +5,8 @@
   "metadata": {
     "_generator": {
       "name": "bicep",
-      "version": "0.25.53.49325",
-      "templateHash": "11337690191653715343"
+      "version": "0.26.54.24096",
+      "templateHash": "5410471245439722622"
     },
     "name": "Virtual Machines",
     "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.",
@@ -684,7 +684,7 @@
       "signedProtocol": "https"
     },
     "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]",
-    "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]",
+    "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]",
     "builtInRoleNames": {
       "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
       "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]",
@@ -815,7 +815,7 @@
         "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]",
         "priority": "[parameters('priority')]",
         "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]",
-        "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', parameters('maxPriceForLowPriorityVm')), null())]",
+        "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]",
         "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]",
         "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]"
       },
@@ -949,8 +949,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "4698911337326052062"
+              "version": "0.26.54.24096",
+              "templateHash": "13415879962041783892"
             }
           },
           "definitions": {
@@ -2419,8 +2419,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -2625,8 +2625,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -2827,8 +2827,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -3041,8 +3041,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -3239,8 +3239,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -3436,8 +3436,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -3637,8 +3637,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -3846,8 +3846,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -4047,8 +4047,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -4246,8 +4246,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -4436,8 +4436,8 @@
           "enableAutomaticUpgrade": "[if(contains(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionHostPoolRegistration').enableAutomaticUpgrade), createObject('value', false()))]",
           "settings": {
             "value": {
-              "modulesUrl": "[parameters('extensionHostPoolRegistration').hostPoolModulesUrl]",
-              "configurationFunction": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'configurationFunction'), 'Configuration.ps1\\AddSessionHost')]",
+              "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]",
+              "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]",
               "properties": {
                 "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]",
                 "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]",
@@ -4456,8 +4456,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -4656,8 +4656,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "5949079428725139834"
+              "version": "0.26.54.24096",
+              "templateHash": "16251967456691023698"
             },
             "name": "Virtual Machine Extensions",
             "description": "This module deploys a Virtual Machine Extension.",
@@ -4855,8 +4855,8 @@
           "metadata": {
             "_generator": {
               "name": "bicep",
-              "version": "0.25.53.49325",
-              "templateHash": "15677187951825533891"
+              "version": "0.26.54.24096",
+              "templateHash": "5385249890312845255"
             },
             "name": "Recovery Service Vaults Protection Container Protected Item",
             "description": "This module deploys a Recovery Services Vault Protection Container Protected Item.",

From 5c3e9228b4cf4522623b5be746d8c63b27f3edfd Mon Sep 17 00:00:00 2001
From: John <J.G.Lokerse@gmail.com>
Date: Thu, 11 Apr 2024 18:09:35 +0200
Subject: [PATCH 7/9] feat: Added UDTs for Azure Firewall Application, network
 and NAT rules - `avm/res/network/azure-firewall` (#1440)

## Description

This pull request adds UDTs for Azure Firewall application, network, and
NAT rules. Also, added an extra network rule for service tags in the
`max` test.

@hundredacres @AlexanderSehr We must be aware that the change itself is
not breaking, but when existing rules are not written as the UDT expects
it will break a deployment. See the image below (left is how it is now
and right is what's new with the UDT). How do we handle this version
wise?

<img width="751" alt="image"
src="https://github.com/Azure/bicep-registry-modules/assets/3514513/89933a2f-e0ef-4bc4-8567-0f6097662fd7">

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|
[![avm.res.network.azure-firewall](https://github.com/johnlokerse/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=johnlokerse%2Fadd-udt-azfw)](https://github.com/johnlokerse/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml)
|

## Type of Change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utlities (Non-module effecting
changes)
- [ ] Azure Verified Module updates:
- [ ] Bugfix containing backwards compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [ ] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [x] Update to documentation

## Checklist

- [x] I'm sure there are no other open Pull Requests for the same
update/change
- [x] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [x] My corresponding pipelines / checks run clean and green without
any errors or warnings

<!-- Please keep up to day with the contribution guide at
https://aka.ms/avm/contribute/bicep -->
---
 avm/res/network/azure-firewall/README.md      | 615 ++++++++++++++++--
 avm/res/network/azure-firewall/main.bicep     | 225 +++++--
 avm/res/network/azure-firewall/main.json      | 453 ++++++++++++-
 .../tests/e2e/max/main.test.bicep             |  36 +-
 .../tests/e2e/waf-aligned/dependencies.bicep  |   3 +
 .../tests/e2e/waf-aligned/main.test.bicep     |  20 +-
 avm/res/network/azure-firewall/version.json   |   2 +-
 7 files changed, 1238 insertions(+), 116 deletions(-)

diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md
index 8629811336..da0018a179 100644
--- a/avm/res/network/azure-firewall/README.md
+++ b/avm/res/network/azure-firewall/README.md
@@ -444,7 +444,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
         name: 'allow-app-rules'
         properties: {
           action: {
-            type: 'allow'
+            type: 'Allow'
           }
           priority: 100
           rules: [
@@ -456,12 +456,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
               name: 'allow-ase-tags'
               protocols: [
                 {
-                  port: '80'
-                  protocolType: 'HTTP'
+                  port: 80
+                  protocolType: 'Http'
                 }
                 {
-                  port: '443'
-                  protocolType: 'HTTPS'
+                  port: 443
+                  protocolType: 'Https'
                 }
               ]
               sourceAddresses: [
@@ -472,12 +472,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
               name: 'allow-ase-management'
               protocols: [
                 {
-                  port: '80'
-                  protocolType: 'HTTP'
+                  port: 80
+                  protocolType: 'Http'
                 }
                 {
-                  port: '443'
-                  protocolType: 'HTTPS'
+                  port: 443
+                  protocolType: 'Https'
                 }
               ]
               sourceAddresses: [
@@ -515,7 +515,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
         name: 'allow-network-rules'
         properties: {
           action: {
-            type: 'allow'
+            type: 'Allow'
           }
           priority: 100
           rules: [
@@ -535,6 +535,22 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
                 '*'
               ]
             }
+            {
+              description: 'allow azure devops'
+              destinationAddresses: [
+                'AzureDevOps'
+              ]
+              destinationPorts: [
+                '443'
+              ]
+              name: 'allow-azure-devops'
+              protocols: [
+                'Any'
+              ]
+              sourceAddresses: [
+                '*'
+              ]
+            }
           ]
         }
       }
@@ -595,7 +611,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
           "name": "allow-app-rules",
           "properties": {
             "action": {
-              "type": "allow"
+              "type": "Allow"
             },
             "priority": 100,
             "rules": [
@@ -607,12 +623,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
                 "name": "allow-ase-tags",
                 "protocols": [
                   {
-                    "port": "80",
-                    "protocolType": "HTTP"
+                    "port": 80,
+                    "protocolType": "Http"
                   },
                   {
-                    "port": "443",
-                    "protocolType": "HTTPS"
+                    "port": 443,
+                    "protocolType": "Https"
                   }
                 ],
                 "sourceAddresses": [
@@ -623,12 +639,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
                 "name": "allow-ase-management",
                 "protocols": [
                   {
-                    "port": "80",
-                    "protocolType": "HTTP"
+                    "port": 80,
+                    "protocolType": "Http"
                   },
                   {
-                    "port": "443",
-                    "protocolType": "HTTPS"
+                    "port": 443,
+                    "protocolType": "Https"
                   }
                 ],
                 "sourceAddresses": [
@@ -674,7 +690,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
           "name": "allow-network-rules",
           "properties": {
             "action": {
-              "type": "allow"
+              "type": "Allow"
             },
             "priority": 100,
             "rules": [
@@ -693,6 +709,22 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
                 "sourceAddresses": [
                   "*"
                 ]
+              },
+              {
+                "description": "allow azure devops",
+                "destinationAddresses": [
+                  "AzureDevOps"
+                ],
+                "destinationPorts": [
+                  "443"
+                ],
+                "name": "allow-azure-devops",
+                "protocols": [
+                  "Any"
+                ],
+                "sourceAddresses": [
+                  "*"
+                ]
               }
             ]
           }
@@ -766,7 +798,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
         name: 'allow-app-rules'
         properties: {
           action: {
-            type: 'allow'
+            type: 'Allow'
           }
           priority: 100
           rules: [
@@ -778,12 +810,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
               name: 'allow-ase-tags'
               protocols: [
                 {
-                  port: '80'
-                  protocolType: 'HTTP'
+                  port: 80
+                  protocolType: 'Http'
                 }
                 {
-                  port: '443'
-                  protocolType: 'HTTPS'
+                  port: 443
+                  protocolType: 'Https'
                 }
               ]
               sourceAddresses: [
@@ -794,12 +826,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
               name: 'allow-ase-management'
               protocols: [
                 {
-                  port: '80'
-                  protocolType: 'HTTP'
+                  port: 80
+                  protocolType: 'Http'
                 }
                 {
-                  port: '443'
-                  protocolType: 'HTTPS'
+                  port: 443
+                  protocolType: 'Https'
                 }
               ]
               sourceAddresses: [
@@ -833,7 +865,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
         name: 'allow-network-rules'
         properties: {
           action: {
-            type: 'allow'
+            type: 'Allow'
           }
           priority: 100
           rules: [
@@ -896,7 +928,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
           "name": "allow-app-rules",
           "properties": {
             "action": {
-              "type": "allow"
+              "type": "Allow"
             },
             "priority": 100,
             "rules": [
@@ -908,12 +940,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
                 "name": "allow-ase-tags",
                 "protocols": [
                   {
-                    "port": "80",
-                    "protocolType": "HTTP"
+                    "port": 80,
+                    "protocolType": "Http"
                   },
                   {
-                    "port": "443",
-                    "protocolType": "HTTPS"
+                    "port": 443,
+                    "protocolType": "Https"
                   }
                 ],
                 "sourceAddresses": [
@@ -924,12 +956,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
                 "name": "allow-ase-management",
                 "protocols": [
                   {
-                    "port": "80",
-                    "protocolType": "HTTP"
+                    "port": 80,
+                    "protocolType": "Http"
                   },
                   {
-                    "port": "443",
-                    "protocolType": "HTTPS"
+                    "port": 443,
+                    "protocolType": "Https"
                   }
                 ],
                 "sourceAddresses": [
@@ -969,7 +1001,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:<version>' = {
           "name": "allow-network-rules",
           "properties": {
             "action": {
-              "type": "allow"
+              "type": "Allow"
             },
             "priority": 100,
             "rules": [
@@ -1106,7 +1138,176 @@ Collection of application rule collections used by Azure Firewall.
 
 - Required: No
 - Type: array
-- Default: `[]`
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-applicationrulecollectionsname) | string | Name of the application rule collection. |
+| [`properties`](#parameter-applicationrulecollectionsproperties) | object | Properties of the azure firewall application rule collection. |
+
+### Parameter: `applicationRuleCollections.name`
+
+Name of the application rule collection.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `applicationRuleCollections.properties`
+
+Properties of the azure firewall application rule collection.
+
+- Required: Yes
+- Type: object
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`action`](#parameter-applicationrulecollectionspropertiesaction) | object | The action type of a rule collection. |
+| [`priority`](#parameter-applicationrulecollectionspropertiespriority) | int | Priority of the application rule collection. |
+| [`rules`](#parameter-applicationrulecollectionspropertiesrules) | array | Collection of rules used by a application rule collection. |
+
+### Parameter: `applicationRuleCollections.properties.action`
+
+The action type of a rule collection.
+
+- Required: Yes
+- Type: object
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`type`](#parameter-applicationrulecollectionspropertiesactiontype) | string | The type of action. |
+
+### Parameter: `applicationRuleCollections.properties.action.type`
+
+The type of action.
+
+- Required: Yes
+- Type: string
+- Allowed:
+  ```Bicep
+  [
+    'Allow'
+    'Deny'
+  ]
+  ```
+
+### Parameter: `applicationRuleCollections.properties.priority`
+
+Priority of the application rule collection.
+
+- Required: Yes
+- Type: int
+
+### Parameter: `applicationRuleCollections.properties.rules`
+
+Collection of rules used by a application rule collection.
+
+- Required: Yes
+- Type: array
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-applicationrulecollectionspropertiesrulesname) | string | Name of the application rule. |
+| [`protocols`](#parameter-applicationrulecollectionspropertiesrulesprotocols) | array | Array of ApplicationRuleProtocols. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`description`](#parameter-applicationrulecollectionspropertiesrulesdescription) | string | Description of the rule. |
+| [`fqdnTags`](#parameter-applicationrulecollectionspropertiesrulesfqdntags) | array | List of FQDN Tags for this rule. |
+| [`sourceAddresses`](#parameter-applicationrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. |
+| [`sourceIpGroups`](#parameter-applicationrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. |
+| [`targetFqdns`](#parameter-applicationrulecollectionspropertiesrulestargetfqdns) | array | List of FQDNs for this rule. |
+
+### Parameter: `applicationRuleCollections.properties.rules.name`
+
+Name of the application rule.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `applicationRuleCollections.properties.rules.protocols`
+
+Array of ApplicationRuleProtocols.
+
+- Required: Yes
+- Type: array
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`protocolType`](#parameter-applicationrulecollectionspropertiesrulesprotocolsprotocoltype) | string | Protocol type. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`port`](#parameter-applicationrulecollectionspropertiesrulesprotocolsport) | int | Port number for the protocol. |
+
+### Parameter: `applicationRuleCollections.properties.rules.protocols.protocolType`
+
+Protocol type.
+
+- Required: Yes
+- Type: string
+- Allowed:
+  ```Bicep
+  [
+    'Http'
+    'Https'
+    'Mssql'
+  ]
+  ```
+
+### Parameter: `applicationRuleCollections.properties.rules.protocols.port`
+
+Port number for the protocol.
+
+- Required: No
+- Type: int
+
+### Parameter: `applicationRuleCollections.properties.rules.description`
+
+Description of the rule.
+
+- Required: No
+- Type: string
+
+### Parameter: `applicationRuleCollections.properties.rules.fqdnTags`
+
+List of FQDN Tags for this rule.
+
+- Required: No
+- Type: array
+
+### Parameter: `applicationRuleCollections.properties.rules.sourceAddresses`
+
+List of source IP addresses for this rule.
+
+- Required: No
+- Type: array
+
+### Parameter: `applicationRuleCollections.properties.rules.sourceIpGroups`
+
+List of source IpGroups for this rule.
+
+- Required: No
+- Type: array
+
+### Parameter: `applicationRuleCollections.properties.rules.targetFqdns`
+
+List of FQDNs for this rule.
+
+- Required: No
+- Type: array
 
 ### Parameter: `azureSkuTier`
 
@@ -1352,7 +1553,175 @@ Collection of NAT rule collections used by Azure Firewall.
 
 - Required: No
 - Type: array
-- Default: `[]`
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-natrulecollectionsname) | string | Name of the NAT rule collection. |
+| [`properties`](#parameter-natrulecollectionsproperties) | object | Properties of the azure firewall NAT rule collection. |
+
+### Parameter: `natRuleCollections.name`
+
+Name of the NAT rule collection.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `natRuleCollections.properties`
+
+Properties of the azure firewall NAT rule collection.
+
+- Required: Yes
+- Type: object
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`action`](#parameter-natrulecollectionspropertiesaction) | object | The action type of a NAT rule collection. |
+| [`priority`](#parameter-natrulecollectionspropertiespriority) | int | Priority of the NAT rule collection. |
+| [`rules`](#parameter-natrulecollectionspropertiesrules) | array | Collection of rules used by a NAT rule collection. |
+
+### Parameter: `natRuleCollections.properties.action`
+
+The action type of a NAT rule collection.
+
+- Required: Yes
+- Type: object
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`type`](#parameter-natrulecollectionspropertiesactiontype) | string | The type of action. |
+
+### Parameter: `natRuleCollections.properties.action.type`
+
+The type of action.
+
+- Required: Yes
+- Type: string
+- Allowed:
+  ```Bicep
+  [
+    'Dnat'
+    'Snat'
+  ]
+  ```
+
+### Parameter: `natRuleCollections.properties.priority`
+
+Priority of the NAT rule collection.
+
+- Required: Yes
+- Type: int
+
+### Parameter: `natRuleCollections.properties.rules`
+
+Collection of rules used by a NAT rule collection.
+
+- Required: Yes
+- Type: array
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-natrulecollectionspropertiesrulesname) | string | Name of the NAT rule. |
+| [`protocols`](#parameter-natrulecollectionspropertiesrulesprotocols) | array | Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`description`](#parameter-natrulecollectionspropertiesrulesdescription) | string | Description of the rule. |
+| [`destinationAddresses`](#parameter-natrulecollectionspropertiesrulesdestinationaddresses) | array | List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags. |
+| [`destinationPorts`](#parameter-natrulecollectionspropertiesrulesdestinationports) | array | List of destination ports. |
+| [`sourceAddresses`](#parameter-natrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. |
+| [`sourceIpGroups`](#parameter-natrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. |
+| [`translatedAddress`](#parameter-natrulecollectionspropertiesrulestranslatedaddress) | string | The translated address for this NAT rule. |
+| [`translatedFqdn`](#parameter-natrulecollectionspropertiesrulestranslatedfqdn) | string | The translated FQDN for this NAT rule. |
+| [`translatedPort`](#parameter-natrulecollectionspropertiesrulestranslatedport) | string | The translated port for this NAT rule. |
+
+### Parameter: `natRuleCollections.properties.rules.name`
+
+Name of the NAT rule.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `natRuleCollections.properties.rules.protocols`
+
+Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule.
+
+- Required: Yes
+- Type: array
+- Allowed:
+  ```Bicep
+  [
+    'Any'
+    'ICMP'
+    'TCP'
+    'UDP'
+  ]
+  ```
+
+### Parameter: `natRuleCollections.properties.rules.description`
+
+Description of the rule.
+
+- Required: No
+- Type: string
+
+### Parameter: `natRuleCollections.properties.rules.destinationAddresses`
+
+List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags.
+
+- Required: No
+- Type: array
+
+### Parameter: `natRuleCollections.properties.rules.destinationPorts`
+
+List of destination ports.
+
+- Required: No
+- Type: array
+
+### Parameter: `natRuleCollections.properties.rules.sourceAddresses`
+
+List of source IP addresses for this rule.
+
+- Required: No
+- Type: array
+
+### Parameter: `natRuleCollections.properties.rules.sourceIpGroups`
+
+List of source IpGroups for this rule.
+
+- Required: No
+- Type: array
+
+### Parameter: `natRuleCollections.properties.rules.translatedAddress`
+
+The translated address for this NAT rule.
+
+- Required: No
+- Type: string
+
+### Parameter: `natRuleCollections.properties.rules.translatedFqdn`
+
+The translated FQDN for this NAT rule.
+
+- Required: No
+- Type: string
+
+### Parameter: `natRuleCollections.properties.rules.translatedPort`
+
+The translated port for this NAT rule.
+
+- Required: No
+- Type: string
 
 ### Parameter: `networkRuleCollections`
 
@@ -1360,7 +1729,167 @@ Collection of network rule collections used by Azure Firewall.
 
 - Required: No
 - Type: array
-- Default: `[]`
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-networkrulecollectionsname) | string | Name of the network rule collection. |
+| [`properties`](#parameter-networkrulecollectionsproperties) | object | Properties of the azure firewall network rule collection. |
+
+### Parameter: `networkRuleCollections.name`
+
+Name of the network rule collection.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `networkRuleCollections.properties`
+
+Properties of the azure firewall network rule collection.
+
+- Required: Yes
+- Type: object
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`action`](#parameter-networkrulecollectionspropertiesaction) | object | The action type of a rule collection. |
+| [`priority`](#parameter-networkrulecollectionspropertiespriority) | int | Priority of the network rule collection. |
+| [`rules`](#parameter-networkrulecollectionspropertiesrules) | array | Collection of rules used by a network rule collection. |
+
+### Parameter: `networkRuleCollections.properties.action`
+
+The action type of a rule collection.
+
+- Required: Yes
+- Type: object
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`type`](#parameter-networkrulecollectionspropertiesactiontype) | string | The type of action. |
+
+### Parameter: `networkRuleCollections.properties.action.type`
+
+The type of action.
+
+- Required: Yes
+- Type: string
+- Allowed:
+  ```Bicep
+  [
+    'Allow'
+    'Deny'
+  ]
+  ```
+
+### Parameter: `networkRuleCollections.properties.priority`
+
+Priority of the network rule collection.
+
+- Required: Yes
+- Type: int
+
+### Parameter: `networkRuleCollections.properties.rules`
+
+Collection of rules used by a network rule collection.
+
+- Required: Yes
+- Type: array
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-networkrulecollectionspropertiesrulesname) | string | Name of the network rule. |
+| [`protocols`](#parameter-networkrulecollectionspropertiesrulesprotocols) | array | Array of AzureFirewallNetworkRuleProtocols. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`description`](#parameter-networkrulecollectionspropertiesrulesdescription) | string | Description of the rule. |
+| [`destinationAddresses`](#parameter-networkrulecollectionspropertiesrulesdestinationaddresses) | array | List of destination IP addresses. |
+| [`destinationFqdns`](#parameter-networkrulecollectionspropertiesrulesdestinationfqdns) | array | List of destination FQDNs. |
+| [`destinationIpGroups`](#parameter-networkrulecollectionspropertiesrulesdestinationipgroups) | array | List of destination IP groups for this rule. |
+| [`destinationPorts`](#parameter-networkrulecollectionspropertiesrulesdestinationports) | array | List of destination ports. |
+| [`sourceAddresses`](#parameter-networkrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. |
+| [`sourceIpGroups`](#parameter-networkrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. |
+
+### Parameter: `networkRuleCollections.properties.rules.name`
+
+Name of the network rule.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `networkRuleCollections.properties.rules.protocols`
+
+Array of AzureFirewallNetworkRuleProtocols.
+
+- Required: Yes
+- Type: array
+- Allowed:
+  ```Bicep
+  [
+    'Any'
+    'ICMP'
+    'TCP'
+    'UDP'
+  ]
+  ```
+
+### Parameter: `networkRuleCollections.properties.rules.description`
+
+Description of the rule.
+
+- Required: No
+- Type: string
+
+### Parameter: `networkRuleCollections.properties.rules.destinationAddresses`
+
+List of destination IP addresses.
+
+- Required: No
+- Type: array
+
+### Parameter: `networkRuleCollections.properties.rules.destinationFqdns`
+
+List of destination FQDNs.
+
+- Required: No
+- Type: array
+
+### Parameter: `networkRuleCollections.properties.rules.destinationIpGroups`
+
+List of destination IP groups for this rule.
+
+- Required: No
+- Type: array
+
+### Parameter: `networkRuleCollections.properties.rules.destinationPorts`
+
+List of destination ports.
+
+- Required: No
+- Type: array
+
+### Parameter: `networkRuleCollections.properties.rules.sourceAddresses`
+
+List of source IP addresses for this rule.
+
+- Required: No
+- Type: array
+
+### Parameter: `networkRuleCollections.properties.rules.sourceIpGroups`
+
+List of source IpGroups for this rule.
+
+- Required: No
+- Type: array
 
 ### Parameter: `publicIPAddressObject`
 
diff --git a/avm/res/network/azure-firewall/main.bicep b/avm/res/network/azure-firewall/main.bicep
index 08f4af0cc2..3176534913 100644
--- a/avm/res/network/azure-firewall/main.bicep
+++ b/avm/res/network/azure-firewall/main.bicep
@@ -34,13 +34,13 @@ param managementIPResourceID string = ''
 param managementIPAddressObject object = {}
 
 @description('Optional. Collection of application rule collections used by Azure Firewall.')
-param applicationRuleCollections array = []
+param applicationRuleCollections applicationRuleCollectionType
 
 @description('Optional. Collection of network rule collections used by Azure Firewall.')
-param networkRuleCollections array = []
+param networkRuleCollections networkRuleCollectionType
 
 @description('Optional. Collection of NAT rule collections used by Azure Firewall.')
-param natRuleCollections array = []
+param natRuleCollections natRuleCollectionType
 
 @description('Optional. Resource ID of the Firewall Policy that should be attached.')
 param firewallPolicyId string = ''
@@ -261,41 +261,33 @@ resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-04-01' = {
   location: location
   zones: length(zones) == 0 ? null : zones
   tags: tags
-  properties: azureSkuName == 'AZFW_VNet'
-    ? {
-        threatIntelMode: threatIntelMode
-        firewallPolicy: !empty(firewallPolicyId)
-          ? {
-              id: firewallPolicyId
-            }
-          : null
-        ipConfigurations: ipConfigurations
-        managementIpConfiguration: requiresManagementIp ? managementIPConfiguration : null
-        sku: {
-          name: azureSkuName
-          tier: azureSkuTier
-        }
-        applicationRuleCollections: applicationRuleCollections
-        natRuleCollections: natRuleCollections
-        networkRuleCollections: networkRuleCollections
-      }
-    : {
-        firewallPolicy: !empty(firewallPolicyId)
-          ? {
-              id: firewallPolicyId
-            }
-          : null
-        sku: {
-          name: azureSkuName
-          tier: azureSkuTier
-        }
-        hubIPAddresses: !empty(hubIPAddresses) ? hubIPAddresses : null
-        virtualHub: !empty(virtualHubId)
-          ? {
-              id: virtualHubId
-            }
-          : null
-      }
+  properties: azureSkuName == 'AZFW_VNet' ? {
+    threatIntelMode: threatIntelMode
+    firewallPolicy: !empty(firewallPolicyId) ? {
+      id: firewallPolicyId
+    } : null
+    ipConfigurations: ipConfigurations
+    managementIpConfiguration: requiresManagementIp ? managementIPConfiguration : null
+    sku: {
+      name: azureSkuName
+      tier: azureSkuTier
+    }
+    applicationRuleCollections: applicationRuleCollections ?? []
+    natRuleCollections: natRuleCollections ?? []
+    networkRuleCollections: networkRuleCollections ?? []
+  } : {
+    firewallPolicy: !empty(firewallPolicyId) ? {
+      id: firewallPolicyId
+    } : null
+    sku: {
+      name: azureSkuName
+      tier: azureSkuTier
+    }
+    hubIPAddresses: !empty(hubIPAddresses) ? hubIPAddresses : null
+    virtualHub: !empty(virtualHubId) ? {
+      id: virtualHubId
+    } : null
+  }
 }
 
 resource azureFirewall_lock 'Microsoft.Authorization/locks@2020-05-01' =
@@ -379,13 +371,13 @@ output ipConfAzureFirewallSubnet object = contains(azureFirewall.properties, 'ip
   : {}
 
 @description('List of Application Rule Collections.')
-output applicationRuleCollections array = applicationRuleCollections
+output applicationRuleCollections array = applicationRuleCollections ?? []
 
 @description('List of Network Rule Collections.')
-output networkRuleCollections array = networkRuleCollections
+output networkRuleCollections array = networkRuleCollections ?? []
 
 @description('Collection of NAT rule collections used by Azure Firewall.')
-output natRuleCollections array = natRuleCollections
+output natRuleCollections array = natRuleCollections ?? []
 
 @description('The location the resource was deployed into.')
 output location string = azureFirewall.location
@@ -468,3 +460,154 @@ type diagnosticSettingType = {
   @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.')
   marketplacePartnerResourceId: string?
 }[]?
+
+type natRuleCollectionType = {
+  @description('Required. Name of the NAT rule collection.')
+  name: string
+
+  @description('Required. Properties of the azure firewall NAT rule collection.')
+  properties: {
+    @description('Required. The action type of a NAT rule collection.')
+    action: {
+      @description('Required. The type of action.')
+      type: 'Dnat' | 'Snat'
+    }
+
+    @description('Required. Priority of the NAT rule collection.')
+    @minValue(100)
+    @maxValue(65000)
+    priority: int
+
+    @description('Required. Collection of rules used by a NAT rule collection.')
+    rules: {
+      @description('Required. Name of the NAT rule.')
+      name: string
+
+      @description('Optional. Description of the rule.')
+      description: string?
+
+      @description('Required. Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule.')
+      protocols: ('TCP' | 'UDP' | 'Any' | 'ICMP')[]
+
+      @description('Optional. List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags.')
+      destinationAddresses: string[]?
+
+      @description('Optional. List of destination ports.')
+      destinationPorts: string[]?
+
+      @description('Optional. List of source IP addresses for this rule.')
+      sourceAddresses: string[]?
+
+      @description('Optional. List of source IpGroups for this rule.')
+      sourceIpGroups: string[]?
+
+      @description('Optional. The translated address for this NAT rule.')
+      translatedAddress: string?
+
+      @description('Optional. The translated FQDN for this NAT rule.')
+      translatedFqdn: string?
+
+      @description('Optional. The translated port for this NAT rule.')
+      translatedPort: string?
+    }[]
+  }
+}[]?
+
+type applicationRuleCollectionType = {
+  @description('Required. Name of the application rule collection.')
+  name: string
+
+  @description('Required. Properties of the azure firewall application rule collection.')
+  properties: {
+    @description('Required. The action type of a rule collection.')
+    action: {
+      @description('Required. The type of action.')
+      type: 'Allow' | 'Deny'
+    }
+
+    @description('Required. Priority of the application rule collection.')
+    @minValue(100)
+    @maxValue(65000)
+    priority: int
+
+    @description('Required. Collection of rules used by a application rule collection.')
+    rules: {
+      @description('Required. Name of the application rule.')
+      name: string
+
+      @description('Optional. Description of the rule.')
+      description: string?
+
+      @description('Required. Array of ApplicationRuleProtocols.')
+      protocols: {
+        @description('Optional. Port number for the protocol.')
+        @maxValue(64000)
+        port: int?
+
+        @description('Required. Protocol type.')
+        protocolType: 'Http' | 'Https' | 'Mssql'
+      }[]
+
+      @description('Optional. List of FQDN Tags for this rule.')
+      fqdnTags: string[]?
+
+      @description('Optional. List of FQDNs for this rule.')
+      targetFqdns: string[]?
+
+      @description('Optional. List of source IP addresses for this rule.')
+      sourceAddresses: string[]?
+
+      @description('Optional. List of source IpGroups for this rule.')
+      sourceIpGroups: string[]?
+    }[]
+  }
+}[]?
+
+type networkRuleCollectionType = {
+  @description('Required. Name of the network rule collection.')
+  name: string
+
+  @description('Required. Properties of the azure firewall network rule collection.')
+  properties: {
+    @description('Required. The action type of a rule collection.')
+    action: {
+      @description('Required. The type of action.')
+      type: 'Allow' | 'Deny'
+    }
+
+    @description('Required. Priority of the network rule collection.')
+    @minValue(100)
+    @maxValue(65000)
+    priority: int
+
+    @description('Required. Collection of rules used by a network rule collection.')
+    rules: {
+      @description('Required. Name of the network rule.')
+      name: string
+
+      @description('Optional. Description of the rule.')
+      description: string?
+
+      @description('Required. Array of AzureFirewallNetworkRuleProtocols.')
+      protocols: ('TCP' | 'UDP' | 'Any' | 'ICMP')[]
+
+      @description('Optional. List of destination IP addresses.')
+      destinationAddresses: string[]?
+
+      @description('Optional. List of destination FQDNs.')
+      destinationFqdns: string[]?
+
+      @description('Optional. List of destination IP groups for this rule.')
+      destinationIpGroups: string[]?
+
+      @description('Optional. List of destination ports.')
+      destinationPorts: string[]?
+
+      @description('Optional. List of source IP addresses for this rule.')
+      sourceAddresses: string[]?
+
+      @description('Optional. List of source IpGroups for this rule.')
+      sourceIpGroups: string[]?
+    }[]
+  }
+}[]?
diff --git a/avm/res/network/azure-firewall/main.json b/avm/res/network/azure-firewall/main.json
index b38f878a9d..877e4dbea2 100644
--- a/avm/res/network/azure-firewall/main.json
+++ b/avm/res/network/azure-firewall/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.26.54.24096",
-      "templateHash": "1527004517287633679"
+      "templateHash": "3831870271484638637"
     },
     "name": "Azure Firewalls",
     "description": "This module deploys an Azure Firewall.",
@@ -223,6 +223,440 @@
         }
       },
       "nullable": true
+    },
+    "natRuleCollectionType": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string",
+            "metadata": {
+              "description": "Required. Name of the NAT rule collection."
+            }
+          },
+          "properties": {
+            "type": "object",
+            "properties": {
+              "action": {
+                "type": "object",
+                "properties": {
+                  "type": {
+                    "type": "string",
+                    "allowedValues": [
+                      "Dnat",
+                      "Snat"
+                    ],
+                    "metadata": {
+                      "description": "Required. The type of action."
+                    }
+                  }
+                },
+                "metadata": {
+                  "description": "Required. The action type of a NAT rule collection."
+                }
+              },
+              "priority": {
+                "type": "int",
+                "minValue": 100,
+                "maxValue": 65000,
+                "metadata": {
+                  "description": "Required. Priority of the NAT rule collection."
+                }
+              },
+              "rules": {
+                "type": "array",
+                "items": {
+                  "type": "object",
+                  "properties": {
+                    "name": {
+                      "type": "string",
+                      "metadata": {
+                        "description": "Required. Name of the NAT rule."
+                      }
+                    },
+                    "description": {
+                      "type": "string",
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. Description of the rule."
+                      }
+                    },
+                    "protocols": {
+                      "type": "array",
+                      "allowedValues": [
+                        "Any",
+                        "ICMP",
+                        "TCP",
+                        "UDP"
+                      ],
+                      "metadata": {
+                        "description": "Required. Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule."
+                      }
+                    },
+                    "destinationAddresses": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags."
+                      }
+                    },
+                    "destinationPorts": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of destination ports."
+                      }
+                    },
+                    "sourceAddresses": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of source IP addresses for this rule."
+                      }
+                    },
+                    "sourceIpGroups": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of source IpGroups for this rule."
+                      }
+                    },
+                    "translatedAddress": {
+                      "type": "string",
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. The translated address for this NAT rule."
+                      }
+                    },
+                    "translatedFqdn": {
+                      "type": "string",
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. The translated FQDN for this NAT rule."
+                      }
+                    },
+                    "translatedPort": {
+                      "type": "string",
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. The translated port for this NAT rule."
+                      }
+                    }
+                  }
+                },
+                "metadata": {
+                  "description": "Required. Collection of rules used by a NAT rule collection."
+                }
+              }
+            },
+            "metadata": {
+              "description": "Required. Properties of the azure firewall NAT rule collection."
+            }
+          }
+        }
+      },
+      "nullable": true
+    },
+    "applicationRuleCollectionType": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string",
+            "metadata": {
+              "description": "Required. Name of the application rule collection."
+            }
+          },
+          "properties": {
+            "type": "object",
+            "properties": {
+              "action": {
+                "type": "object",
+                "properties": {
+                  "type": {
+                    "type": "string",
+                    "allowedValues": [
+                      "Allow",
+                      "Deny"
+                    ],
+                    "metadata": {
+                      "description": "Required. The type of action."
+                    }
+                  }
+                },
+                "metadata": {
+                  "description": "Required. The action type of a rule collection."
+                }
+              },
+              "priority": {
+                "type": "int",
+                "minValue": 100,
+                "maxValue": 65000,
+                "metadata": {
+                  "description": "Required. Priority of the application rule collection."
+                }
+              },
+              "rules": {
+                "type": "array",
+                "items": {
+                  "type": "object",
+                  "properties": {
+                    "name": {
+                      "type": "string",
+                      "metadata": {
+                        "description": "Required. Name of the application rule."
+                      }
+                    },
+                    "description": {
+                      "type": "string",
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. Description of the rule."
+                      }
+                    },
+                    "protocols": {
+                      "type": "array",
+                      "items": {
+                        "type": "object",
+                        "properties": {
+                          "port": {
+                            "type": "int",
+                            "nullable": true,
+                            "maxValue": 64000,
+                            "metadata": {
+                              "description": "Optional. Port number for the protocol."
+                            }
+                          },
+                          "protocolType": {
+                            "type": "string",
+                            "allowedValues": [
+                              "Http",
+                              "Https",
+                              "Mssql"
+                            ],
+                            "metadata": {
+                              "description": "Required. Protocol type."
+                            }
+                          }
+                        }
+                      },
+                      "metadata": {
+                        "description": "Required. Array of ApplicationRuleProtocols."
+                      }
+                    },
+                    "fqdnTags": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of FQDN Tags for this rule."
+                      }
+                    },
+                    "targetFqdns": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of FQDNs for this rule."
+                      }
+                    },
+                    "sourceAddresses": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of source IP addresses for this rule."
+                      }
+                    },
+                    "sourceIpGroups": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of source IpGroups for this rule."
+                      }
+                    }
+                  }
+                },
+                "metadata": {
+                  "description": "Required. Collection of rules used by a application rule collection."
+                }
+              }
+            },
+            "metadata": {
+              "description": "Required. Properties of the azure firewall application rule collection."
+            }
+          }
+        }
+      },
+      "nullable": true
+    },
+    "networkRuleCollectionType": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string",
+            "metadata": {
+              "description": "Required. Name of the network rule collection."
+            }
+          },
+          "properties": {
+            "type": "object",
+            "properties": {
+              "action": {
+                "type": "object",
+                "properties": {
+                  "type": {
+                    "type": "string",
+                    "allowedValues": [
+                      "Allow",
+                      "Deny"
+                    ],
+                    "metadata": {
+                      "description": "Required. The type of action."
+                    }
+                  }
+                },
+                "metadata": {
+                  "description": "Required. The action type of a rule collection."
+                }
+              },
+              "priority": {
+                "type": "int",
+                "minValue": 100,
+                "maxValue": 65000,
+                "metadata": {
+                  "description": "Required. Priority of the network rule collection."
+                }
+              },
+              "rules": {
+                "type": "array",
+                "items": {
+                  "type": "object",
+                  "properties": {
+                    "name": {
+                      "type": "string",
+                      "metadata": {
+                        "description": "Required. Name of the network rule."
+                      }
+                    },
+                    "description": {
+                      "type": "string",
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. Description of the rule."
+                      }
+                    },
+                    "protocols": {
+                      "type": "array",
+                      "allowedValues": [
+                        "Any",
+                        "ICMP",
+                        "TCP",
+                        "UDP"
+                      ],
+                      "metadata": {
+                        "description": "Required. Array of AzureFirewallNetworkRuleProtocols."
+                      }
+                    },
+                    "destinationAddresses": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of destination IP addresses."
+                      }
+                    },
+                    "destinationFqdns": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of destination FQDNs."
+                      }
+                    },
+                    "destinationIpGroups": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of destination IP groups for this rule."
+                      }
+                    },
+                    "destinationPorts": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of destination ports."
+                      }
+                    },
+                    "sourceAddresses": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of source IP addresses for this rule."
+                      }
+                    },
+                    "sourceIpGroups": {
+                      "type": "array",
+                      "items": {
+                        "type": "string"
+                      },
+                      "nullable": true,
+                      "metadata": {
+                        "description": "Optional. List of source IpGroups for this rule."
+                      }
+                    }
+                  }
+                },
+                "metadata": {
+                  "description": "Required. Collection of rules used by a network rule collection."
+                }
+              }
+            },
+            "metadata": {
+              "description": "Required. Properties of the azure firewall network rule collection."
+            }
+          }
+        }
+      },
+      "nullable": true
     }
   },
   "parameters": {
@@ -289,22 +723,19 @@
       }
     },
     "applicationRuleCollections": {
-      "type": "array",
-      "defaultValue": [],
+      "$ref": "#/definitions/applicationRuleCollectionType",
       "metadata": {
         "description": "Optional. Collection of application rule collections used by Azure Firewall."
       }
     },
     "networkRuleCollections": {
-      "type": "array",
-      "defaultValue": [],
+      "$ref": "#/definitions/networkRuleCollectionType",
       "metadata": {
         "description": "Optional. Collection of network rule collections used by Azure Firewall."
       }
     },
     "natRuleCollections": {
-      "type": "array",
-      "defaultValue": [],
+      "$ref": "#/definitions/natRuleCollectionType",
       "metadata": {
         "description": "Optional. Collection of NAT rule collections used by Azure Firewall."
       }
@@ -445,7 +876,7 @@
       "location": "[parameters('location')]",
       "zones": "[if(equals(length(parameters('zones')), 0), null(), parameters('zones'))]",
       "tags": "[parameters('tags')]",
-      "properties": "[if(equals(variables('azureSkuName'), 'AZFW_VNet'), createObject('threatIntelMode', parameters('threatIntelMode'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'ipConfigurations', concat(createArray(createObject('name', if(not(empty(parameters('publicIPResourceID'))), last(split(parameters('publicIPResourceID'), '/')), reference('publicIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('publicIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('publicIPResourceID'))), parameters('publicIPResourceID'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))), variables('additionalPublicIpConfigurationsVar')), 'managementIpConfiguration', if(variables('requiresManagementIp'), createObject('name', if(not(empty(parameters('managementIPResourceID'))), last(split(parameters('managementIPResourceID'), '/')), reference('managementIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallManagementSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('managementIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('managementIPResourceID'))), parameters('managementIPResourceID'), reference('managementIPAddress').outputs.resourceId.value))), createObject()))), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'applicationRuleCollections', parameters('applicationRuleCollections'), 'natRuleCollections', parameters('natRuleCollections'), 'networkRuleCollections', parameters('networkRuleCollections')), createObject('firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'hubIPAddresses', if(not(empty(parameters('hubIPAddresses'))), parameters('hubIPAddresses'), null()), 'virtualHub', if(not(empty(parameters('virtualHubId'))), createObject('id', parameters('virtualHubId')), null())))]",
+      "properties": "[if(equals(variables('azureSkuName'), 'AZFW_VNet'), createObject('threatIntelMode', parameters('threatIntelMode'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'ipConfigurations', concat(createArray(createObject('name', if(not(empty(parameters('publicIPResourceID'))), last(split(parameters('publicIPResourceID'), '/')), reference('publicIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('publicIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('publicIPResourceID'))), parameters('publicIPResourceID'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))), variables('additionalPublicIpConfigurationsVar')), 'managementIpConfiguration', if(variables('requiresManagementIp'), createObject('name', if(not(empty(parameters('managementIPResourceID'))), last(split(parameters('managementIPResourceID'), '/')), reference('managementIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallManagementSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('managementIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('managementIPResourceID'))), parameters('managementIPResourceID'), reference('managementIPAddress').outputs.resourceId.value))), createObject()))), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'applicationRuleCollections', coalesce(parameters('applicationRuleCollections'), createArray()), 'natRuleCollections', coalesce(parameters('natRuleCollections'), createArray()), 'networkRuleCollections', coalesce(parameters('networkRuleCollections'), createArray())), createObject('firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'hubIPAddresses', if(not(empty(parameters('hubIPAddresses'))), parameters('hubIPAddresses'), null()), 'virtualHub', if(not(empty(parameters('virtualHubId'))), createObject('id', parameters('virtualHubId')), null())))]",
       "dependsOn": [
         "managementIPAddress",
         "publicIPAddress"
@@ -1757,21 +2188,21 @@
       "metadata": {
         "description": "List of Application Rule Collections."
       },
-      "value": "[parameters('applicationRuleCollections')]"
+      "value": "[coalesce(parameters('applicationRuleCollections'), createArray())]"
     },
     "networkRuleCollections": {
       "type": "array",
       "metadata": {
         "description": "List of Network Rule Collections."
       },
-      "value": "[parameters('networkRuleCollections')]"
+      "value": "[coalesce(parameters('networkRuleCollections'), createArray())]"
     },
     "natRuleCollections": {
       "type": "array",
       "metadata": {
         "description": "Collection of NAT rule collections used by Azure Firewall."
       },
-      "value": "[parameters('natRuleCollections')]"
+      "value": "[coalesce(parameters('natRuleCollections'), createArray())]"
     },
     "location": {
       "type": "string",
diff --git a/avm/res/network/azure-firewall/tests/e2e/max/main.test.bicep b/avm/res/network/azure-firewall/tests/e2e/max/main.test.bicep
index 7a69b2eebf..07ce848092 100644
--- a/avm/res/network/azure-firewall/tests/e2e/max/main.test.bicep
+++ b/avm/res/network/azure-firewall/tests/e2e/max/main.test.bicep
@@ -74,7 +74,7 @@ module testDeployment '../../../main.bicep' = [
           name: 'allow-app-rules'
           properties: {
             action: {
-              type: 'allow'
+              type: 'Allow'
             }
             priority: 100
             rules: [
@@ -86,12 +86,12 @@ module testDeployment '../../../main.bicep' = [
                 name: 'allow-ase-tags'
                 protocols: [
                   {
-                    port: '80'
-                    protocolType: 'HTTP'
+                    port: 80
+                    protocolType: 'Http'
                   }
                   {
-                    port: '443'
-                    protocolType: 'HTTPS'
+                    port: 443
+                    protocolType: 'Https'
                   }
                 ]
                 sourceAddresses: [
@@ -102,12 +102,12 @@ module testDeployment '../../../main.bicep' = [
                 name: 'allow-ase-management'
                 protocols: [
                   {
-                    port: '80'
-                    protocolType: 'HTTP'
+                    port: 80
+                    protocolType: 'Http'
                   }
                   {
-                    port: '443'
-                    protocolType: 'HTTPS'
+                    port: 443
+                    protocolType: 'Https'
                   }
                 ]
                 sourceAddresses: [
@@ -145,7 +145,7 @@ module testDeployment '../../../main.bicep' = [
           name: 'allow-network-rules'
           properties: {
             action: {
-              type: 'allow'
+              type: 'Allow'
             }
             priority: 100
             rules: [
@@ -165,6 +165,22 @@ module testDeployment '../../../main.bicep' = [
                   '*'
                 ]
               }
+              {
+                name: 'allow-azure-devops'
+                protocols: [
+                  'Any'
+                ]
+                description: 'allow azure devops'
+                sourceAddresses: [
+                  '*'
+                ]
+                destinationAddresses: [
+                  'AzureDevOps'
+                ]
+                destinationPorts: [
+                  '443'
+                ]
+              }
             ]
           }
         }
diff --git a/avm/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep
index de9bfec4ea..4e6ccd3d21 100644
--- a/avm/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep
+++ b/avm/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep
@@ -60,5 +60,8 @@ output virtualNetworkResourceId string = virtualNetwork.id
 @description('The resource ID of the created Public IP.')
 output publicIPResourceId string = publicIP.id
 
+@description('The public IP Address of the created Public IP.')
+output publicIPAddress string = publicIP.properties.ipAddress
+
 @description('The principal ID of the created Managed Identity.')
 output managedIdentityPrincipalId string = managedIdentity.properties.principalId
diff --git a/avm/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep
index ca84384701..33bd48b938 100644
--- a/avm/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep
+++ b/avm/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep
@@ -74,7 +74,7 @@ module testDeployment '../../../main.bicep' = [
           name: 'allow-app-rules'
           properties: {
             action: {
-              type: 'allow'
+              type: 'Allow'
             }
             priority: 100
             rules: [
@@ -86,12 +86,12 @@ module testDeployment '../../../main.bicep' = [
                 name: 'allow-ase-tags'
                 protocols: [
                   {
-                    port: '80'
-                    protocolType: 'HTTP'
+                    port: 80
+                    protocolType: 'Http'
                   }
                   {
-                    port: '443'
-                    protocolType: 'HTTPS'
+                    port: 443
+                    protocolType: 'Https'
                   }
                 ]
                 sourceAddresses: [
@@ -102,12 +102,12 @@ module testDeployment '../../../main.bicep' = [
                 name: 'allow-ase-management'
                 protocols: [
                   {
-                    port: '80'
-                    protocolType: 'HTTP'
+                    port: 80
+                    protocolType: 'Http'
                   }
                   {
-                    port: '443'
-                    protocolType: 'HTTPS'
+                    port: 443
+                    protocolType: 'Https'
                   }
                 ]
                 sourceAddresses: [
@@ -141,7 +141,7 @@ module testDeployment '../../../main.bicep' = [
           name: 'allow-network-rules'
           properties: {
             action: {
-              type: 'allow'
+              type: 'Allow'
             }
             priority: 100
             rules: [
diff --git a/avm/res/network/azure-firewall/version.json b/avm/res/network/azure-firewall/version.json
index 83083db694..1c035df49f 100644
--- a/avm/res/network/azure-firewall/version.json
+++ b/avm/res/network/azure-firewall/version.json
@@ -1,6 +1,6 @@
 {
     "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#",
-    "version": "0.1",
+    "version": "0.2",
     "pathFilters": [
         "./main.json"
     ]

From 54eb21648f9f220c4ef6ef5094e3c2307724e240 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20H=C3=A9zser?= <rene@hezser.de>
Date: Fri, 12 Apr 2024 10:49:53 +0200
Subject: [PATCH 8/9] fix: aad-ds tests (#1669)

## Description

Fixes the tests for the Domain Services Module

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|
[![avm.res.aad.domain-service](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml/badge.svg?branch=aad-ds-test-fix)](https://github.com/ReneHezser/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml)
|

## Type of Change

- [ ] Update to CI Environment or utlities (Non-module effecting
changes)
- [x] Azure Verified Module updates:
- [x] Bugfix containing backwards compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [x] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [ ] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation

## Checklist

- [x] I'm sure there are no other open Pull Requests for the same
update/change
- [x] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [x] My corresponding pipelines / checks run clean and green without
any errors or warnings

Co-authored-by: ChrisSidebotham-MSFT <48600046+ChrisSidebotham@users.noreply.github.com>
---
 avm/res/aad/domain-service/README.md                          | 4 ++--
 avm/res/aad/domain-service/main.json                          | 4 ++--
 .../aad/domain-service/tests/e2e/waf-aligned/main.test.bicep  | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/avm/res/aad/domain-service/README.md b/avm/res/aad/domain-service/README.md
index 640ab0847b..87f33b1d5f 100644
--- a/avm/res/aad/domain-service/README.md
+++ b/avm/res/aad/domain-service/README.md
@@ -56,7 +56,7 @@ module domainService 'br/public:avm/res/aad/domain-service:<version>' = {
         eventHubName: '<eventHubName>'
         logCategoriesAndGroups: [
           {
-            category: 'AllLogs'
+            categoryGroup: 'allLogs'
           }
         ]
         metricCategories: [
@@ -124,7 +124,7 @@ module domainService 'br/public:avm/res/aad/domain-service:<version>' = {
           "eventHubName": "<eventHubName>",
           "logCategoriesAndGroups": [
             {
-              "category": "AllLogs"
+              "categoryGroup": "allLogs"
             }
           ],
           "metricCategories": [
diff --git a/avm/res/aad/domain-service/main.json b/avm/res/aad/domain-service/main.json
index 84a4f00d14..c210fd41ff 100644
--- a/avm/res/aad/domain-service/main.json
+++ b/avm/res/aad/domain-service/main.json
@@ -5,8 +5,8 @@
   "metadata": {
     "_generator": {
       "name": "bicep",
-      "version": "0.25.53.49325",
-      "templateHash": "7386947428934165964"
+      "version": "0.26.54.24096",
+      "templateHash": "10683253750371964167"
     },
     "name": "Azure Active Directory Domain Services",
     "description": "This module deploys an Azure Active Directory Domain Services (AADDS).",
diff --git a/avm/res/aad/domain-service/tests/e2e/waf-aligned/main.test.bicep b/avm/res/aad/domain-service/tests/e2e/waf-aligned/main.test.bicep
index e4af67fbc9..90db155b23 100644
--- a/avm/res/aad/domain-service/tests/e2e/waf-aligned/main.test.bicep
+++ b/avm/res/aad/domain-service/tests/e2e/waf-aligned/main.test.bicep
@@ -87,7 +87,7 @@ module testDeployment '../../../main.bicep' = {
         ]
         logCategoriesAndGroups: [
           {
-            category: 'AllLogs'
+            categoryGroup: 'allLogs'
           }
         ]
         storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId
@@ -155,7 +155,7 @@ module testDeploymentIdem '../../../main.bicep' = {
         ]
         logCategoriesAndGroups: [
           {
-            category: 'AllLogs'
+            categoryGroup: 'allLogs'
           }
         ]
         storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId

From bed50a4f961da33726e81efbc35b3a032ef65b4c Mon Sep 17 00:00:00 2001
From: Rainer Halanek <61878316+rahalan@users.noreply.github.com>
Date: Fri, 12 Apr 2024 13:49:10 +0200
Subject: [PATCH 9/9] feat: Add additional logic if workflow fails and issue is
 created (#1403)

More fine grained logic, regarding commenting and assigning new failing
workflow issues
---
 .../avm.platform.manage-workflow-issue.yml    | 13 +++-
 ...form.set-avm-github-issue-owner-config.yml | 16 +++--
 .../Set-AvmGithubIssueForWorkflow.ps1         | 54 ++++++++++++++++-
 .../helper/Add-GithubIssueToProject.ps1       | 57 ++++++++++++++++++
 .../platform/helper/Get-AvmCsvData.ps1        | 59 +++++++++++++++++++
 5 files changed, 188 insertions(+), 11 deletions(-)
 create mode 100644 avm/utilities/pipelines/platform/helper/Add-GithubIssueToProject.ps1
 create mode 100644 avm/utilities/pipelines/platform/helper/Get-AvmCsvData.ps1

diff --git a/.github/workflows/avm.platform.manage-workflow-issue.yml b/.github/workflows/avm.platform.manage-workflow-issue.yml
index 8d37f57d3d..9c80793d18 100644
--- a/.github/workflows/avm.platform.manage-workflow-issue.yml
+++ b/.github/workflows/avm.platform.manage-workflow-issue.yml
@@ -3,6 +3,7 @@ name: "avm.platform.manage-workflow-issue"
 on:
   schedule:
     - cron: "30 5 * * *" # Every day at 5:30 am
+  workflow_dispatch:
 
 jobs:
   manage-issues:
@@ -14,16 +15,22 @@ jobs:
         uses: actions/checkout@v4
         with:
           fetch-depth: 0
-      - env:
-          GH_TOKEN: ${{ github.token }}
-        name: Manage issues
+      - uses: tibdex/github-app-token@v2
+        id: generate-token
+        with:
+          app_id: ${{ secrets.APP_ID }}
+          private_key: ${{ secrets.APP_PRIVATE_KEY }}
+      - name: Manage issues
         shell: pwsh
+        env:
+          GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
         run: |
           # Load used functions
           . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'Set-AvmGithubIssueForWorkflow.ps1')
 
           $functionInput = @{
             Repo              = "${{ github.repository_owner }}/${{ github.event.repository.name }}"
+            RepoRoot          = $env:GITHUB_WORKSPACE
             LimitNumberOfRuns = 500
             LimitInDays       = 2
             IgnoreWorkflows   = @()
diff --git a/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml b/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml
index 775d83c94d..48cc265747 100644
--- a/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml
+++ b/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml
@@ -16,16 +16,22 @@ jobs:
         uses: actions/checkout@v4
         with:
           fetch-depth: 0
-      - env:
-          GH_TOKEN: ${{ github.token }}
-        name: "Run scripts"
+      - uses: tibdex/github-app-token@v2
+        id: generate-token
+        with:
+          app_id: ${{ secrets.TEAM_LINTER_APP_ID }}
+          private_key: ${{ secrets.TEAM_LINTER_PRIVATE_KEY }}
+      - name: "Run scripts"
         shell: pwsh
+        env:
+          GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
         run: |
           # Load used functions
-          . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines'  'platform' 'Set-AvmGitHubIssueOwnerConfig.ps1')
+          . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'Set-AvmGitHubIssueOwnerConfig.ps1')
 
           $functionInput = @{
-            Repo = "${{ github.repository_owner }}/${{ github.event.repository.name }}"
+            Repo     = "${{ github.repository_owner }}/${{ github.event.repository.name }}"
+            RepoRoot = $env:GITHUB_WORKSPACE
             IssueUrl = "${{ github.event.issue.url }}"
           }
 
diff --git a/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 b/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1
index 7a30bfa96d..a2c1a5f98d 100644
--- a/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1
+++ b/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1
@@ -6,7 +6,10 @@ Check for failing pipelines and create issues for those, that are failing.
 If a pipeline fails, a new issue will be created, with a link to the failed pipeline. If the issue is already existing, a comment will be added, if a new run failed (with the link for the new failed run). If a pipeline run succeeds and an issue is open for the failed run, it will be closed (and a link to the successful run is added to the issue).
 
 .PARAMETER Repo
-Mandatory. The name of the respository to scan. Needs to have the structure "<owner>/<repositioryName>"
+Mandatory. The name of the respository to scan. Needs to have the structure "<owner>/<repositioryName>", like 'Azure/bicep-registry-modules/'
+
+.PARAMETER RepoRoot
+Optional. Path to the root of the repository.
 
 .PARAMETER LimitNumberOfRuns
 Optional. Number of recent runs to scan for failed runs. Default is 100.
@@ -23,7 +26,7 @@ Set-AvmGithubIssueForWorkflow -Repo 'owner/repo01' -LimitNumberOfRuns 100 -Limit
 Check the last 100 workflow runs in the repository 'owner/repo01' that happened in the last 2 days. If the workflow name is 'Pipeline 01', then ignore the workflow run.
 
 .NOTES
-The function requires GitHub CLI to be installed.
+Will be triggered by the workflow avm.platform.manage-workflow-issue.yml
 #>
 function Set-AvmGithubIssueForWorkflow {
   [CmdletBinding(SupportsShouldProcess)]
@@ -31,6 +34,9 @@ function Set-AvmGithubIssueForWorkflow {
     [Parameter(Mandatory = $true)]
     [string] $Repo,
 
+    [Parameter(Mandatory = $false)]
+    [string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.parent.FullName,
+
     [Parameter(Mandatory = $false)]
     [int] $LimitNumberOfRuns = 100,
 
@@ -41,6 +47,10 @@ function Set-AvmGithubIssueForWorkflow {
     [String[]] $IgnoreWorkflows = @()
   )
 
+  # Loading helper functions
+  . (Join-Path $RepoRoot 'avm' 'utilities' 'pipelines' 'platform' 'helper' 'Get-AvmCsvData.ps1')
+  . (Join-Path $RepoRoot 'avm' 'utilities' 'pipelines' 'platform' 'helper' 'Add-GithubIssueToProject.ps1')
+
   $issues = gh issue list --state open --limit 500 --label 'Type: AVM :a: :v: :m:,Type: Bug :bug:' --json 'title,url,body,comments,labels' --repo $Repo | ConvertFrom-Json -Depth 100
   $runs = gh run list --json 'url,workflowName,headBranch,startedAt' --limit $LimitNumberOfRuns --repo $Repo | ConvertFrom-Json -Depth 100
   $workflowRuns = @{}
@@ -81,7 +91,45 @@ function Set-AvmGithubIssueForWorkflow {
 
       if ($issues.title -notcontains $issueName) {
         if ($PSCmdlet.ShouldProcess("Issue [$issueName]", 'Create')) {
-          gh issue create --title "$issueName" --body "$failedrun" --label 'Type: AVM :a: :v: :m:,Type: Bug :bug:' --repo $Repo
+          $issueUrl = gh issue create --title "$issueName" --body "$failedrun" --label 'Type: AVM :a: :v: :m:,Type: Bug :bug:' --repo $Repo
+          $ProjectNumber = 538 # AVM - Issue Triage
+          $comment = @"
+> [!IMPORTANT]
+> @Azure/avm-core-team-technical-bicep, the workflow for the ``$moduleName`` module has failed. Please investigate the failed workflow run.
+"@
+
+          if ($workflowRun.workflowName -match 'avm.(?:res|ptn)') {
+            $moduleName = $workflowRun.workflowName.Replace('.', '/')
+            $moduleIndex = $moduleName.StartsWith('avm/res') ? 'Bicep-Resource' : 'Bicep-Pattern'
+            # get CSV data
+            $module = Get-AvmCsvData -ModuleIndex $moduleIndex | Where-Object ModuleName -EQ $moduleName
+
+            if (($module.ModuleStatus -ne 'Module Orphaned :eyes:') -and (-not ([string]::IsNullOrEmpty($module.PrimaryModuleOwnerGHHandle)))) {
+              $ProjectNumber = 566 # AVM - Module Issues
+              $comment = @"
+> [!IMPORTANT]
+> @$($module.ModuleOwnersGHTeam), the workflow for the ``$moduleName`` module has failed. Please investigate the failed workflow run. If you are not able to do so, please inform the AVM core team to take over.
+"@
+              # assign owner
+              $assign = gh issue edit $issue.url --add-assignee $module.PrimaryModuleOwnerGHHandle --repo $Repo
+
+              if ([String]::IsNullOrEmpty($assign)) {
+                if ($PSCmdlet.ShouldProcess("missing user comment to issue [$($issue.title)]", 'Add')) {
+                  $comment = @"
+> [!WARNING]
+> This issue couldn't be assigend due to an internal error. @$($module.PrimaryModuleOwnerGHHandle), please make sure this issue is assigned to you and please provide an initial response as soon as possible, in accordance with the [AVM Support statement](https://aka.ms/AVM/Support).
+"@
+
+                  gh issue comment $issue.url --body $reply --repo $Repo
+                }
+              }
+            }
+          }
+
+          # add issue to project
+          Add-GithubIssueToProject -Repo $Repo -ProjectNumber $ProjectNumber -IssueUrl $issueUrl
+          # add comment
+          gh issue comment $issueUrl --body $comment --repo $Repo
         }
 
         $issuesCreated++
diff --git a/avm/utilities/pipelines/platform/helper/Add-GithubIssueToProject.ps1 b/avm/utilities/pipelines/platform/helper/Add-GithubIssueToProject.ps1
new file mode 100644
index 0000000000..cd9d0222e4
--- /dev/null
+++ b/avm/utilities/pipelines/platform/helper/Add-GithubIssueToProject.ps1
@@ -0,0 +1,57 @@
+<#
+.SYNOPSIS
+Adds an existing GitHub issue to an existing GitHub project (the new type, not the classic ones)
+
+.DESCRIPTION
+Adds an existing GitHub issue to an existing GitHub project (the new type, not the classic ones)
+
+.PARAMETER Repo
+Mandatory. The name of the respository to scan. Needs to have the structure "<owner>/<repositioryName>", like 'Azure/bicep-registry-modules/'
+
+.PARAMETER ProjectNumber
+Mandatory. The GitHub project number (see last part of project URL, for example 538 for https://github.com/orgs/Azure/projects/538)
+
+.PARAMETER IssueUrl
+Mandatory. The URL of the GitHub issue, like 'https://github.com/Azure/bicep-registry-modules/issues/757'
+
+.EXAMPLE
+Add-GithubIssueToProject -Repo 'Azure/bicep-registry-modules' -ProjectNumber 538 -IssueUrl 'https://github.com/Azure/bicep-registry-modules/issues/757'
+
+.NOTES
+Needs to run under a context with the permissions to read/write organization projects
+#>
+function Add-GithubIssueToProject {
+  param (
+    [Parameter(Mandatory = $true)]
+    [string] $Repo,
+
+    [Parameter(Mandatory = $true)]
+    [int] $ProjectNumber,
+
+    [Parameter(Mandatory = $true)]
+    [string] $IssueUrl
+  )
+
+  $Organization = $Repo.Split('/')[0]
+
+  $Project = gh api graphql -f query='
+  query($organization: String! $number: Int!){
+    organization(login: $organization){
+      projectV2(number: $number) {
+        id
+      }
+    }
+  }' -f organization=$Organization -F number=$ProjectNumber | ConvertFrom-Json -Depth 10
+
+  $ProjectId = $Project.data.organization.projectV2.id
+  $IssueId = (gh issue view $IssueUrl --repo $Repo --json 'id' | ConvertFrom-Json -Depth 100).id
+
+  gh api graphql -f query='
+  mutation($project:ID!, $issue:ID!) {
+    addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) {
+      item {
+        id
+      }
+    }
+  }' -f project=$ProjectId -f issue=$IssueId
+}
diff --git a/avm/utilities/pipelines/platform/helper/Get-AvmCsvData.ps1 b/avm/utilities/pipelines/platform/helper/Get-AvmCsvData.ps1
new file mode 100644
index 0000000000..821f476bb7
--- /dev/null
+++ b/avm/utilities/pipelines/platform/helper/Get-AvmCsvData.ps1
@@ -0,0 +1,59 @@
+<#
+.SYNOPSIS
+Parses AVM module CSV file
+
+.DESCRIPTION
+Depending on the parameter, the correct CSV file will be parsed and returned a an object
+
+.PARAMETER ModuleIndex
+Mandatory. Type of CSV file, that should be parsed ('Bicep-Resource', 'Bicep-Pattern')
+
+.EXAMPLE
+Get-AvmCsvData -ModuleIndex 'Bicep-Resource'
+
+Parse the AVM Bicep modules
+#>
+Function Get-AvmCsvData {
+  [CmdletBinding()]
+  param (
+    [Parameter(Mandatory)]
+    [ValidateSet('Bicep-Resource', 'Bicep-Pattern')]
+    [string] $ModuleIndex
+  )
+
+  # CSV file URLs
+  $BicepResourceUrl = 'https://aka.ms/avm/index/bicep/res/csv'
+  $BicepPatternUrl = 'https://aka.ms/avm/index/bicep/ptn/csv'
+
+  # Retrieve the CSV file
+  switch ($ModuleIndex) {
+    'Bicep-Resource' {
+      try {
+        $unfilteredCSV = Invoke-WebRequest -Uri $BicepResourceUrl
+      } catch {
+        throw 'Unable to retrieve CSV file - Check network connection.'
+      }
+    }
+    'Bicep-Pattern' {
+      try {
+        $unfilteredCSV = Invoke-WebRequest -Uri $BicepPatternUrl
+      } catch {
+        throw 'Unable to retrieve CSV file - Check network connection.'
+      }
+    }
+  }
+
+  # Convert the CSV content to a PowerShell object
+  $formattedBicepFullCsv = ConvertFrom-Csv $unfilteredCSV.Content
+
+  # Loop through each item in the filtered data
+  foreach ($item in $formattedBicepFullCsv) {
+    # Remove '@Azure/' from the ModuleOwnersGHTeam property
+    $item.ModuleOwnersGHTeam = $item.ModuleOwnersGHTeam -replace '@Azure\/', ''
+    # Remove '@Azure/' from the ModuleContributorsGHTeam property
+    $item.ModuleContributorsGHTeam = $item.ModuleContributorsGHTeam -replace '@Azure\/', ''
+  }
+
+  # Return the modified data
+  return $formattedBicepFullCsv
+}