From d61cceec4d89b8e798e4155ce441831a7df3a219 Mon Sep 17 00:00:00 2001 From: Ashwini Karke Date: Mon, 29 Dec 2025 15:06:33 +0530 Subject: [PATCH 01/10] added test files for 25537 --- src/powershell/tests/Test-Assessment.25537.md | 7 + .../tests/Test-Assessment.25537.ps1 | 130 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 src/powershell/tests/Test-Assessment.25537.md create mode 100644 src/powershell/tests/Test-Assessment.25537.ps1 diff --git a/src/powershell/tests/Test-Assessment.25537.md b/src/powershell/tests/Test-Assessment.25537.md new file mode 100644 index 000000000..8c0f748d8 --- /dev/null +++ b/src/powershell/tests/Test-Assessment.25537.md @@ -0,0 +1,7 @@ +Azure Firewall Threat intelligence-based filtering alerts and denies traffic from/to known malicious IP addresses, FQDNs, and URLs. The IP addresses, domains, and URLs are sourced from the Microsoft Threat Intelligence feed, which includes multiple sources including the Microsoft Cyber Security team. When threat intelligence-based filtering is enabled, Azure Firewall evaluates traffic against the threat intelligence rules before applying NAT, network, or application rules. This check verifies that Threat Intelligence feature is enabled in “Alert and Deny” mode in the Azure Firewall policy configuration. The check will fail if Threat Intelligence is either “Disabled” or if it is not configured in “Alert and Deny” mode, in the firewall policy attached to the firewall. + +**Remediation action** + +- [Please check this article for guidance on how to enable Threat Intelligence in “Alert and Deny” mode in the Azure Firewall Policy.](https://learn.microsoft.com/en-us/azure/firewall-manager/threat-intelligence-settings) + +%TestResult% diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 new file mode 100644 index 000000000..593cea082 --- /dev/null +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -0,0 +1,130 @@ +<# +.SYNOPSIS + Validates Threat intelligence is Enabled in Deny Mode on Azure Firewall. +.DESCRIPTION + This test validates that Azure Firewall Policies have Threat Intelligence enabled in Deny mode. + Checks all firewall policies in the subscription and reports their threat intelligence status. +.NOTES + Test ID: 25537 + Category: Internet Access Control + Required API: Azure Firewall Policies +#> + +function Test-Assessment-25537 { + [ZtTest( + Category = 'Internet Access Control', + ImplementationCost = 'Low', + MinimumLicense = ('Azure_Firewall_Standard','Azure_Firewall_Premium'), + Pillar = 'Network', + RiskLevel = 'High', + SfiPillar = 'Protect networks', + TenantType = ('Workforce'), + TestId = 25537, + Title = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall', + UserImpact = 'Low' + )] + [CmdletBinding()] + param() + + Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose + + #region Authentication Check + try { + $accessToken = Get-AzAccessToken -AsSecureString -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + catch { + Write-PSFMessage $_.Exception.Message -Tag Test -Level Error + } + + if (!$accessToken) { + Write-PSFMessage "Azure authentication token not found." -Level Warning + Add-ZtTestResultDetail -SkippedBecause NotConnectedAzure + return + } + #endregion Authentication Check + + #region Data Collection + Write-ZtProgress ` + -Activity 'Azure Firewall Threat Intelligence' ` + -Status 'Enumerating Firewall Policies' + + try { + $policies = Get-AzResource -ResourceType "Microsoft.Network/firewallPolicies" -ErrorAction Stop + } + catch { + Write-PSFMessage $_.Exception.Message -Tag Test -Level Error + Add-ZtTestResultDetail -SkippedBecause NoAzureAccess + return + } + #endregion Data Collection + + #region Assessment Logic + $passed = $false + $testResultMarkdown = "" + $results = @() + + if (-not $policies) { + $testResultMarkdown = "No Azure Firewall Policies were found in this subscription." + Add-ZtTestResultDetail ` + -TestId '25537' ` + -Title 'Threat intelligence is Enabled in Deny Mode on Azure Firewall' ` + -Status $false ` + -Result $testResultMarkdown + return + } + + $results = @() + + foreach ($policyResource in $policies) { + $policy = Get-AzFirewallPolicy ` + -Name $policyResource.Name ` + -ResourceGroupName $policyResource.ResourceGroupName ` + -ErrorAction SilentlyContinue + + $mode = $policy.ThreatIntelMode + + $result = switch ($mode) { + 'Deny' { '✅ Enabled (Alert and Deny)' } + 'Alert' { '❌ Alert only' } + 'Off' { '❌ Disabled' } + default { '❌ Not configured' } + } + + $results += [PSCustomObject]@{ + PolicyName = $policy.Name + ResourceGroup = $policy.ResourceGroupName + ThreatIntelMode = $mode + Result = $result + } + } + #endregion Data Collection + + #region Assessment Logic Evaluation + $failedPolicies = $results | Where-Object { $_.ThreatIntelMode -ne 'Deny' } + $passed = ($failedPolicies.Count -eq 0) + + if ($passed) { + $testResultMarkdown = "Threat Intelligence is enabled in **Alert and Deny** mode for all Azure Firewall Policies.`n`n%TestResult%" + } else { + $testResultMarkdown = "One or more Azure Firewall Policies do **not** have Threat Intelligence enabled in **Alert and Deny** mode.`n`n%TestResult%" + } + #endregion Assessment Logic Evaluation + + #region Report Generation + $mdInfo = "## Azure Firewall Threat Intelligence Status`n`n" + $mdInfo += "Policy Name | Resource Group | Threat Intel Mode | Result |`n" + $mdInfo += "| :--- | :--- | :--- | :---: |`n" + + foreach ($item in $results | Sort-Object PolicyName) { + $mdInfo += "| $($item.PolicyName) | $($item.ResourceGroup) | $($item.ThreatIntelMode) | $($item.Result) |`n" + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $mdInfo + + # --- Final result (NO AppliesTo) --- + Add-ZtTestResultDetail ` + -TestId '25537' ` + -Title 'Azure Firewall Threat Intelligence is enabled in Alert and Deny mode' ` + -Status $passed ` + -Result $testResultMarkdown +} From 7332dd652c246e1e3775a3127dcb37f2fddc6006 Mon Sep 17 00:00:00 2001 From: Ashwini Karke Date: Wed, 31 Dec 2025 15:54:18 +0530 Subject: [PATCH 02/10] updated code --- .../tests/Test-Assessment.25537.ps1 | 176 +++++++++--------- 1 file changed, 93 insertions(+), 83 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 index 593cea082..3882025a0 100644 --- a/src/powershell/tests/Test-Assessment.25537.ps1 +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -6,15 +6,15 @@ Checks all firewall policies in the subscription and reports their threat intelligence status. .NOTES Test ID: 25537 - Category: Internet Access Control + Category: Azure Network Security Required API: Azure Firewall Policies #> function Test-Assessment-25537 { [ZtTest( - Category = 'Internet Access Control', + Category = 'Azure Network Security', ImplementationCost = 'Low', - MinimumLicense = ('Azure_Firewall_Standard','Azure_Firewall_Premium'), + MinimumLicense = ('Azure_Firewall_Standard', 'Azure_Firewall_Premium'), Pillar = 'Network', RiskLevel = 'High', SfiPillar = 'Protect networks', @@ -28,103 +28,113 @@ function Test-Assessment-25537 { Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose - #region Authentication Check - try { - $accessToken = Get-AzAccessToken -AsSecureString -ErrorAction SilentlyContinue -WarningAction SilentlyContinue - } - catch { - Write-PSFMessage $_.Exception.Message -Tag Test -Level Error - } - - if (!$accessToken) { - Write-PSFMessage "Azure authentication token not found." -Level Warning - Add-ZtTestResultDetail -SkippedBecause NotConnectedAzure - return - } - #endregion Authentication Check - #region Data Collection Write-ZtProgress ` -Activity 'Azure Firewall Threat Intelligence' ` -Status 'Enumerating Firewall Policies' - try { - $policies = Get-AzResource -ResourceType "Microsoft.Network/firewallPolicies" -ErrorAction Stop - } - catch { - Write-PSFMessage $_.Exception.Message -Tag Test -Level Error - Add-ZtTestResultDetail -SkippedBecause NoAzureAccess - return - } - #endregion Data Collection - - #region Assessment Logic - $passed = $false - $testResultMarkdown = "" + $subscriptions = Get-AzSubscription $results = @() + foreach ($sub in $subscriptions) { + Set-AzContext -SubscriptionId $sub.Id | Out-Null + # Get all firewall policies in the subscription + $policies = Get-AzResource -ResourceType 'Microsoft.Network/firewallPolicies' -ErrorAction Stop - if (-not $policies) { - $testResultMarkdown = "No Azure Firewall Policies were found in this subscription." - Add-ZtTestResultDetail ` - -TestId '25537' ` - -Title 'Threat intelligence is Enabled in Deny Mode on Azure Firewall' ` - -Status $false ` - -Result $testResultMarkdown - return + if (-not $policies) { + continue + } + + #endregion Data Collection + #region Assessment Logic + + foreach ($policyResource in $policies) { + $policy = Get-AzFirewallPolicy ` + -Name $policyResource.Name ` + -ResourceGroupName $policyResource.ResourceGroupName ` + -ErrorAction SilentlyContinue + + if (-not $policy) { + continue + } + + $subContext = Get-AzContext + $status = if ($policy.ThreatIntelMode -eq 'Deny') { + 'Pass' + } + else { + 'Fail' + } + + $results += [PSCustomObject]@{ + CheckName = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall' + PolicyName = $policy.Name + ResourceGroup = $policy.ResourceGroupName + SubscriptionName = $subContext.Subscription.Name + SubscriptionId = $subContext.Subscription.Id + ThreatIntelMode = $policy.ThreatIntelMode + Status = $status + } + } } + #endregion Assessment Logic - $results = @() + #region Assessment Logic Evaluation + if (-not $results) { + Write-PSFMessage 'No Azure Firewall policies found. Skipping test.' -Tag Firewall -Level Verbose + return + } + else { + $allModes = $results.ThreatIntelMode + $uniqueModes = $allModes | Select-Object -Unique - foreach ($policyResource in $policies) { - $policy = Get-AzFirewallPolicy ` - -Name $policyResource.Name ` - -ResourceGroupName $policyResource.ResourceGroupName ` - -ErrorAction SilentlyContinue + if ($uniqueModes.Count -eq 1 -and $uniqueModes -eq 'Deny') { - $mode = $policy.ThreatIntelMode + $passed = $true + $testResultMarkdown = 'Threat Intel is enabled in **Alert and Deny** mode.' - $result = switch ($mode) { - 'Deny' { '✅ Enabled (Alert and Deny)' } - 'Alert' { '❌ Alert only' } - 'Off' { '❌ Disabled' } - default { '❌ Not configured' } } - - $results += [PSCustomObject]@{ - PolicyName = $policy.Name - ResourceGroup = $policy.ResourceGroupName - ThreatIntelMode = $mode - Result = $result + else { + + $passed = $false + + if ($uniqueModes.Count -eq 1) { + + switch ($uniqueModes) { + 'Alert' { + $testResultMarkdown = 'Threat Intel is enabled in **Alert** mode.' + } + 'Off' { + $testResultMarkdown = 'Threat Intel is **disabled**.' + } + default { + $testResultMarkdown = 'Threat Intel is not enabled in **Alert and Deny** mode for all Firewall policies.' + } + } + } + else { + $testResultMarkdown = 'Threat Intel is not enabled in **Alert and Deny** mode for all Firewall policies.' + } } - } - #endregion Data Collection - - #region Assessment Logic Evaluation - $failedPolicies = $results | Where-Object { $_.ThreatIntelMode -ne 'Deny' } - $passed = ($failedPolicies.Count -eq 0) - if ($passed) { - $testResultMarkdown = "Threat Intelligence is enabled in **Alert and Deny** mode for all Azure Firewall Policies.`n`n%TestResult%" - } else { - $testResultMarkdown = "One or more Azure Firewall Policies do **not** have Threat Intelligence enabled in **Alert and Deny** mode.`n`n%TestResult%" - } - #endregion Assessment Logic Evaluation + # --- Markdown Table --- + $mdInfo = "`n`n## Firewall Policies`n`n" + $mdInfo += "| Check name | Policy name | Subscription name | Subscription id | Threat Intel Mode |`n" + $mdInfo += "| :--- | :--- | :--- | :--- | :---: |`n" - #region Report Generation - $mdInfo = "## Azure Firewall Threat Intelligence Status`n`n" - $mdInfo += "Policy Name | Resource Group | Threat Intel Mode | Result |`n" - $mdInfo += "| :--- | :--- | :--- | :---: |`n" + foreach ($item in $results | Sort-Object PolicyName) { + $mdInfo += "| $($item.CheckName) | $($item.PolicyName) | $($item.SubscriptionName) | $($item.SubscriptionId) | $($item.ThreatIntelMode) |`n" + } - foreach ($item in $results | Sort-Object PolicyName) { - $mdInfo += "| $($item.PolicyName) | $($item.ResourceGroup) | $($item.ThreatIntelMode) | $($item.Result) |`n" - } + $testResultMarkdown += $mdInfo - $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $mdInfo + #endregion Assessment Logic Evaluation - # --- Final result (NO AppliesTo) --- - Add-ZtTestResultDetail ` - -TestId '25537' ` - -Title 'Azure Firewall Threat Intelligence is enabled in Alert and Deny mode' ` - -Status $passed ` - -Result $testResultMarkdown + #region Report Generation + Add-ZtTestResultDetail ` + -TestId '25537' ` + -Title 'Azure Firewall Threat Intelligence is enabled in Alert and Deny mode' ` + -Status $passed ` + -Result $testResultMarkdown + #endregion Report Generation + } } From 551a8aec03c80f04c08b3c72602e5bb686ed7a33 Mon Sep 17 00:00:00 2001 From: Ashwini Karke Date: Wed, 31 Dec 2025 15:59:40 +0530 Subject: [PATCH 03/10] updated code --- src/powershell/tests/Test-Assessment.25537.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.md b/src/powershell/tests/Test-Assessment.25537.md index 8c0f748d8..3e260acf2 100644 --- a/src/powershell/tests/Test-Assessment.25537.md +++ b/src/powershell/tests/Test-Assessment.25537.md @@ -1,7 +1,11 @@ -Azure Firewall Threat intelligence-based filtering alerts and denies traffic from/to known malicious IP addresses, FQDNs, and URLs. The IP addresses, domains, and URLs are sourced from the Microsoft Threat Intelligence feed, which includes multiple sources including the Microsoft Cyber Security team. When threat intelligence-based filtering is enabled, Azure Firewall evaluates traffic against the threat intelligence rules before applying NAT, network, or application rules. This check verifies that Threat Intelligence feature is enabled in “Alert and Deny” mode in the Azure Firewall policy configuration. The check will fail if Threat Intelligence is either “Disabled” or if it is not configured in “Alert and Deny” mode, in the firewall policy attached to the firewall. +Azure Firewall Threat intelligence-based filtering alerts and denies traffic from/to known malicious IP addresses, FQDNs, and URLs. The IP addresses, domains, and URLs are sourced from the Microsoft Threat Intelligence feed, which includes multiple sources including the Microsoft Cyber Security team. When threat intelligence-based filtering is enabled, Azure Firewall evaluates traffic against the threat intelligence rules before applying NAT, network, or application rules. + +This check verifies that Threat Intelligence feature is enabled in “Alert and Deny” mode in the Azure Firewall policy configuration. The check will fail if Threat Intelligence is either “Disabled” or if it is not configured in “Alert and Deny” mode, in the firewall policy attached to the firewall. **Remediation action** -- [Please check this article for guidance on how to enable Threat Intelligence in “Alert and Deny” mode in the Azure Firewall Policy.](https://learn.microsoft.com/en-us/azure/firewall-manager/threat-intelligence-settings) +Please check this article for guidance on how to enable Threat Intelligence in “Alert and Deny” mode in the Azure Firewall Policy: +- [Azure Firewall threat intelligence configuration | Microsoft Learn](https://learn.microsoft.com/en-us/azure/firewall-manager/threat-intelligence-settings) + %TestResult% From 6363e607102e33460a942a29960c6d6e26d2acad Mon Sep 17 00:00:00 2001 From: Kshitiz Sharma Date: Mon, 19 Jan 2026 14:17:45 +0530 Subject: [PATCH 04/10] feature-25537 --- src/powershell/tests/Test-Assessment.25537.ps1 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 index 3882025a0..460b2cb22 100644 --- a/src/powershell/tests/Test-Assessment.25537.ps1 +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -118,11 +118,15 @@ function Test-Assessment-25537 { # --- Markdown Table --- $mdInfo = "`n`n## Firewall Policies`n`n" - $mdInfo += "| Check name | Policy name | Subscription name | Subscription id | Threat Intel Mode |`n" - $mdInfo += "| :--- | :--- | :--- | :--- | :---: |`n" + $mdInfo += "| Policy name | Subscription name | Threat Intel Mode |`n" + $mdInfo += "| :--- | :--- | :---: |`n" foreach ($item in $results | Sort-Object PolicyName) { - $mdInfo += "| $($item.CheckName) | $($item.PolicyName) | $($item.SubscriptionName) | $($item.SubscriptionId) | $($item.ThreatIntelMode) |`n" + $policyLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)/resourceGroups/$($item.ResourceGroup)/providers/Microsoft.Network/firewallPolicies/$($item.PolicyName)" + $subLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)" + $policyMd = "[$(Get-SafeMarkdown -Text $item.PolicyName)]($policyLink)" + $subMd = "[$(Get-SafeMarkdown -Text $item.SubscriptionName)]($subLink)" + $mdInfo += "| $policyMd | $subMd | $($item.ThreatIntelMode) |`n" } $testResultMarkdown += $mdInfo From 57ad827877779e96d5ad88923e628620586a7ef9 Mon Sep 17 00:00:00 2001 From: Kshitiz Sharma Date: Mon, 19 Jan 2026 23:27:19 +0530 Subject: [PATCH 05/10] Code Fix --- .../tests/Test-Assessment.25537.ps1 | 108 ++++++------------ 1 file changed, 38 insertions(+), 70 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 index 460b2cb22..8a27fdb43 100644 --- a/src/powershell/tests/Test-Assessment.25537.ps1 +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -33,112 +33,80 @@ function Test-Assessment-25537 { -Activity 'Azure Firewall Threat Intelligence' ` -Status 'Enumerating Firewall Policies' + # Query 1: List all subscriptions $subscriptions = Get-AzSubscription $results = @() + foreach ($sub in $subscriptions) { Set-AzContext -SubscriptionId $sub.Id | Out-Null - # Get all firewall policies in the subscription - $policies = Get-AzResource -ResourceType 'Microsoft.Network/firewallPolicies' -ErrorAction Stop - if (-not $policies) { + # Query 1: List Azure Firewall Policies + try { + $policies = Get-AzResource -ResourceType 'Microsoft.Network/firewallPolicies' -ErrorAction Stop + } + catch { + Write-PSFMessage "Unable to enumerate firewall policies in subscription $($sub.Name): $($_.Exception.Message)" -Tag Firewall -Level Warning continue } - #endregion Data Collection - #region Assessment Logic + if (-not $policies) { continue } + # Query 2: Get details for each firewall policy and check threatIntelMode foreach ($policyResource in $policies) { $policy = Get-AzFirewallPolicy ` -Name $policyResource.Name ` -ResourceGroupName $policyResource.ResourceGroupName ` -ErrorAction SilentlyContinue - if (-not $policy) { - continue - } + if (-not $policy) { continue } $subContext = Get-AzContext - $status = if ($policy.ThreatIntelMode -eq 'Deny') { - 'Pass' - } - else { - 'Fail' - } + $isCompliant = $policy.ThreatIntelMode -eq 'Deny' $results += [PSCustomObject]@{ - CheckName = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall' PolicyName = $policy.Name ResourceGroup = $policy.ResourceGroupName SubscriptionName = $subContext.Subscription.Name SubscriptionId = $subContext.Subscription.Id ThreatIntelMode = $policy.ThreatIntelMode - Status = $status + IsCompliant = $isCompliant } } } - #endregion Assessment Logic + #endregion Data Collection - #region Assessment Logic Evaluation + #region Assessment Logic if (-not $results) { - Write-PSFMessage 'No Azure Firewall policies found. Skipping test.' -Tag Firewall -Level Verbose + Add-ZtTestResultDetail -SkippedBecause NoResults return } - else { - $allModes = $results.ThreatIntelMode - $uniqueModes = $allModes | Select-Object -Unique - if ($uniqueModes.Count -eq 1 -and $uniqueModes -eq 'Deny') { + $passed = ($results | Where-Object { -not $_.IsCompliant }).Count -eq 0 - $passed = $true - $testResultMarkdown = 'Threat Intel is enabled in **Alert and Deny** mode.' + $testResultMarkdown = if ($passed) { + 'Threat intelligence mode is set to Deny for all Azure Firewall policies.`n`n%TestResult%' + } else { + 'Threat intelligence mode is not set to Deny for all Azure Firewall policies.`n`n%TestResult%' + } + #endregion Assessment Logic - } - else { - - $passed = $false - - if ($uniqueModes.Count -eq 1) { - - switch ($uniqueModes) { - 'Alert' { - $testResultMarkdown = 'Threat Intel is enabled in **Alert** mode.' - } - 'Off' { - $testResultMarkdown = 'Threat Intel is **disabled**.' - } - default { - $testResultMarkdown = 'Threat Intel is not enabled in **Alert and Deny** mode for all Firewall policies.' - } - } - } - else { - $testResultMarkdown = 'Threat Intel is not enabled in **Alert and Deny** mode for all Firewall policies.' - } - } + #region Report Generation + $mdInfo = "## Firewall policies`n`n" + $mdInfo += "| Policy name | Subscription name | Threat Intel mode | Result |`n" + $mdInfo += "| :--- | :--- | :--- | :--- |`n" - # --- Markdown Table --- - $mdInfo = "`n`n## Firewall Policies`n`n" - $mdInfo += "| Policy name | Subscription name | Threat Intel Mode |`n" - $mdInfo += "| :--- | :--- | :---: |`n" - - foreach ($item in $results | Sort-Object PolicyName) { - $policyLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)/resourceGroups/$($item.ResourceGroup)/providers/Microsoft.Network/firewallPolicies/$($item.PolicyName)" - $subLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)" - $policyMd = "[$(Get-SafeMarkdown -Text $item.PolicyName)]($policyLink)" - $subMd = "[$(Get-SafeMarkdown -Text $item.SubscriptionName)]($subLink)" - $mdInfo += "| $policyMd | $subMd | $($item.ThreatIntelMode) |`n" - } + foreach ($item in $results | Sort-Object PolicyName) { + $policyLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)/resourceGroups/$($item.ResourceGroup)/providers/Microsoft.Network/firewallPolicies/$($item.PolicyName)" + $subLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)" + $policyMd = "[$(Get-SafeMarkdown -Text $item.PolicyName)]($policyLink)" + $subMd = "[$(Get-SafeMarkdown -Text $item.SubscriptionName)]($subLink)" + $icon = if ($item.IsCompliant) { '✅' } else { '❌' } - $testResultMarkdown += $mdInfo + $mdInfo += "| $policyMd | $subMd | $($item.ThreatIntelMode) | $icon |`n" + } - #endregion Assessment Logic Evaluation + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo + #endregion Report Generation - #region Report Generation - Add-ZtTestResultDetail ` - -TestId '25537' ` - -Title 'Azure Firewall Threat Intelligence is enabled in Alert and Deny mode' ` - -Status $passed ` - -Result $testResultMarkdown - #endregion Report Generation - } + Add-ZtTestResultDetail -TestId '25537' -Status $passed -Result $testResultMarkdown } From e6b92cd6e42a666f873be2fd3b8263445491a38f Mon Sep 17 00:00:00 2001 From: Kshitij Sharma Date: Tue, 20 Jan 2026 11:10:30 +0530 Subject: [PATCH 06/10] Update src/powershell/tests/Test-Assessment.25537.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/powershell/tests/Test-Assessment.25537.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 index 8a27fdb43..d582e1c27 100644 --- a/src/powershell/tests/Test-Assessment.25537.ps1 +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -84,9 +84,9 @@ function Test-Assessment-25537 { $passed = ($results | Where-Object { -not $_.IsCompliant }).Count -eq 0 $testResultMarkdown = if ($passed) { - 'Threat intelligence mode is set to Deny for all Azure Firewall policies.`n`n%TestResult%' + "Threat intelligence mode is set to Deny for all Azure Firewall policies.`n`n%TestResult%" } else { - 'Threat intelligence mode is not set to Deny for all Azure Firewall policies.`n`n%TestResult%' + "Threat intelligence mode is not set to Deny for all Azure Firewall policies.`n`n%TestResult%" } #endregion Assessment Logic From b3c8651d4f3d6dd327409ea821d074f53363ef57 Mon Sep 17 00:00:00 2001 From: Kshitiz Sharma Date: Tue, 20 Jan 2026 20:49:43 +0530 Subject: [PATCH 07/10] Code fix as per alex feedback --- .../tests/Test-Assessment.25537.ps1 | 231 ++++++++++-------- 1 file changed, 128 insertions(+), 103 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 index 8a27fdb43..15188cb14 100644 --- a/src/powershell/tests/Test-Assessment.25537.ps1 +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -1,112 +1,137 @@ -<# -.SYNOPSIS - Validates Threat intelligence is Enabled in Deny Mode on Azure Firewall. -.DESCRIPTION - This test validates that Azure Firewall Policies have Threat Intelligence enabled in Deny mode. - Checks all firewall policies in the subscription and reports their threat intelligence status. -.NOTES - Test ID: 25537 - Category: Azure Network Security - Required API: Azure Firewall Policies -#> - -function Test-Assessment-25537 { - [ZtTest( - Category = 'Azure Network Security', - ImplementationCost = 'Low', - MinimumLicense = ('Azure_Firewall_Standard', 'Azure_Firewall_Premium'), - Pillar = 'Network', - RiskLevel = 'High', - SfiPillar = 'Protect networks', - TenantType = ('Workforce'), - TestId = 25537, - Title = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall', - UserImpact = 'Low' - )] - [CmdletBinding()] - param() - - Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose - - #region Data Collection - Write-ZtProgress ` - -Activity 'Azure Firewall Threat Intelligence' ` - -Status 'Enumerating Firewall Policies' - - # Query 1: List all subscriptions - $subscriptions = Get-AzSubscription - $results = @() - - foreach ($sub in $subscriptions) { - Set-AzContext -SubscriptionId $sub.Id | Out-Null - - # Query 1: List Azure Firewall Policies + + <# + .SYNOPSIS + Validates Threat intelligence is Enabled in Deny Mode on Azure Firewall. + .DESCRIPTION + This test validates that Azure Firewall Policies have Threat Intelligence enabled in Deny mode. + Checks all firewall policies in the subscription and reports their threat intelligence status. + .NOTES + Test ID: 25537 + Category: Azure Network Security + Required API: Azure Firewall Policies + #> + + function Test-Assessment-25537 { + [ZtTest( + Category = 'Azure Network Security', + ImplementationCost = 'Low', + MinimumLicense = ('Azure_Firewall_Standard', 'Azure_Firewall_Premium'), + Pillar = 'Network', + RiskLevel = 'High', + SfiPillar = 'Protect networks', + TenantType = ('Workforce'), + TestId = 25537, + Title = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall', + UserImpact = 'Low' + )] + [CmdletBinding()] + param() + + Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose + + #region Data Collection + $activity = 'Azure Firewall Threat Intelligence' + Write-ZtProgress ` + -Activity $activity ` + -Status 'Enumerating Firewall Policies' + + # Query 1: List all subscriptions + $resourceManagerUrl = (Get-AzContext).Environment.ResourceManagerUrl.TrimEnd('/') + $subscriptionsUri = "$resourceManagerUrl/subscriptions?api-version=2020-01-01" + try { - $policies = Get-AzResource -ResourceType 'Microsoft.Network/firewallPolicies' -ErrorAction Stop + $subscriptionsResponse = Invoke-AzRestMethod -Method GET -Uri $subscriptionsUri -ErrorAction Stop } catch { - Write-PSFMessage "Unable to enumerate firewall policies in subscription $($sub.Name): $($_.Exception.Message)" -Tag Firewall -Level Warning - continue - } - - if (-not $policies) { continue } - - # Query 2: Get details for each firewall policy and check threatIntelMode - foreach ($policyResource in $policies) { - $policy = Get-AzFirewallPolicy ` - -Name $policyResource.Name ` - -ResourceGroupName $policyResource.ResourceGroupName ` - -ErrorAction SilentlyContinue - - if (-not $policy) { continue } - - $subContext = Get-AzContext - $isCompliant = $policy.ThreatIntelMode -eq 'Deny' - - $results += [PSCustomObject]@{ - PolicyName = $policy.Name - ResourceGroup = $policy.ResourceGroupName - SubscriptionName = $subContext.Subscription.Name - SubscriptionId = $subContext.Subscription.Id - ThreatIntelMode = $policy.ThreatIntelMode - IsCompliant = $isCompliant + if ($_.Exception.Response.StatusCode -eq 403 -or $_.Exception.Message -like '*403*' -or $_.Exception.Message -like '*Forbidden*') { + Add-ZtTestResultDetail -SkippedBecause NoAzureAccess + return } - } - } - #endregion Data Collection - - #region Assessment Logic - if (-not $results) { - Add-ZtTestResultDetail -SkippedBecause NoResults - return - } - $passed = ($results | Where-Object { -not $_.IsCompliant }).Count -eq 0 - - $testResultMarkdown = if ($passed) { - 'Threat intelligence mode is set to Deny for all Azure Firewall policies.`n`n%TestResult%' - } else { - 'Threat intelligence mode is not set to Deny for all Azure Firewall policies.`n`n%TestResult%' - } - #endregion Assessment Logic - - #region Report Generation - $mdInfo = "## Firewall policies`n`n" - $mdInfo += "| Policy name | Subscription name | Threat Intel mode | Result |`n" - $mdInfo += "| :--- | :--- | :--- | :--- |`n" + throw + } - foreach ($item in $results | Sort-Object PolicyName) { - $policyLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)/resourceGroups/$($item.ResourceGroup)/providers/Microsoft.Network/firewallPolicies/$($item.PolicyName)" - $subLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)" - $policyMd = "[$(Get-SafeMarkdown -Text $item.PolicyName)]($policyLink)" - $subMd = "[$(Get-SafeMarkdown -Text $item.SubscriptionName)]($subLink)" - $icon = if ($item.IsCompliant) { '✅' } else { '❌' } + $subscriptions = ($subscriptionsResponse.Content | ConvertFrom-Json).value - $mdInfo += "| $policyMd | $subMd | $($item.ThreatIntelMode) | $icon |`n" + if (-not $subscriptions) { + Add-ZtTestResultDetail -SkippedBecause NoResults + return + } + $results = @() + + foreach ($sub in $subscriptions) { + + Set-AzContext -SubscriptionId $sub.subscriptionId | Out-Null + + # Query 1: List Azure Firewall Policies + try { + $policiesUri = "$resourceManagerUrl/subscriptions/$($sub.subscriptionId)/providers/Microsoft.Network/firewallPolicies?api-version=2023-04-01" + Write-ZtProgress -Activity $activity -Status "Enumerating policies in subscription $($sub.displayName)" + + $policyResponse = (Invoke-AzRestMethod -Method GET -Uri $policiesUri -ErrorAction Stop ).Content | ConvertFrom-Json + $policies = $policyResponse.value + + } + catch { + Write-PSFMessage "Unable to enumerate firewall policies in subscription $($sub.Name): $($_.Exception.Message)" -Tag Firewall -Level Warning + continue + } + + if (-not $policies) { continue } + + # Query 2: Get details for each firewall policy and check threatIntelMode + foreach ($policyResource in $policies) { + + $threatIntelMode = $policyResource.Properties.threatIntelMode + + $subContext = Get-AzContext + + $results += [PSCustomObject]@{ + PolicyName = $policyResource.Name + SubscriptionName = $subContext.Subscription.Name + SubscriptionId = $subContext.Subscription.Id + ThreatIntelMode = $threatIntelMode + PolicyID = $policyResource.Id + Passed = $threatIntelMode -eq 'Deny' + } + } + } + #endregion Data Collection + + #region Assessment Logic + + + $passed = ($results | Where-Object { -not $_.Passed }).Count -eq 0 + + $testResultMarkdown = if ($passed) { + "Threat intelligence mode is set to Deny for all Azure Firewall policies.`n`n %TestResult%" + } else { + "Threat intelligence mode is not set to Deny for all Azure Firewall policies.`n`n %TestResult%" + } + #endregion Assessment Logic + + #region Report Generation + $mdInfo = "## Firewall policies`n`n" + $mdInfo += "| Policy name | Subscription name | Threat Intel mode | Result |`n" + $mdInfo += "| :--- | :--- | :--- | :--- |`n" + + foreach ($item in $results | Sort-Object PolicyName) { + $policyLink = "https://portal.azure.com/#resource$($item.PolicyID)" + $subLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)" + $policyMd = "[$(Get-SafeMarkdown -Text $item.PolicyName)]($policyLink)" + $subMd = "[$(Get-SafeMarkdown -Text $item.SubscriptionName)]($subLink)" + $icon = if ($item.Passed) { '✅' } else { '❌' } + $mdInfo += "| $policyMd | $subMd | $($item.ThreatIntelMode) | $icon |`n" + } + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo + #endregion Report Generation + $params = @{ + TestId = '25537' + Title = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall' + Status = $passed + Result = $testResultMarkdown } - $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo - #endregion Report Generation - - Add-ZtTestResultDetail -TestId '25537' -Status $passed -Result $testResultMarkdown -} + Add-ZtTestResultDetail @params + } From d6251a3bec8d6a47dfd6b9ff382d46becd5f5d6a Mon Sep 17 00:00:00 2001 From: Kshitiz sharma Date: Wed, 28 Jan 2026 18:16:15 +0530 Subject: [PATCH 08/10] Code update as per spec --- src/powershell/tests/Test-Assessment.25537.ps1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 index 0d08d2f93..f56c75486 100644 --- a/src/powershell/tests/Test-Assessment.25537.ps1 +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -47,8 +47,6 @@ Add-ZtTestResultDetail -SkippedBecause NoAzureAccess return } - - throw } $subscriptions = ($subscriptionsResponse.Content | ConvertFrom-Json).value @@ -58,7 +56,7 @@ return } $results = @() - + $resourceManagerUrl = (Get-AzContext).Environment.ResourceManagerUrl.TrimEnd('/') foreach ($sub in $subscriptions) { Set-AzContext -SubscriptionId $sub.subscriptionId | Out-Null @@ -102,11 +100,14 @@ $passed = ($results | Where-Object { -not $_.Passed }).Count -eq 0 + $allAlert = ($results | Where-Object { $_.ThreatIntelMode -ne 'Alert' }).Count -eq 0 $testResultMarkdown = if ($passed) { - "Threat intelligence mode is set to Deny for all Azure Firewall policies.`n`n%TestResult%" + "Threat Intel is enabled in **Alert and Deny** mode .`n`n%TestResult%" + } elseif ($allAlert) { + "Threat Intel is enabled in **Alert** mode .`n`n%TestResult%" } else { - "Threat intelligence mode is not set to Deny for all Azure Firewall policies.`n`n%TestResult%" + "Threat Intel is not enabled in **Alert and Deny** mode for all Firewall policies.`n`n%TestResult%" } #endregion Assessment Logic From 16d9ba2498ae7df009792861f94ad488e0d41496 Mon Sep 17 00:00:00 2001 From: Kshitiz sharma Date: Wed, 28 Jan 2026 22:47:41 +0530 Subject: [PATCH 09/10] Feature-25533 - Co-pilot fix --- src/powershell/tests/Test-Assessment.25537.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 index f56c75486..a1e60b51f 100644 --- a/src/powershell/tests/Test-Assessment.25537.ps1 +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -56,7 +56,6 @@ return } $results = @() - $resourceManagerUrl = (Get-AzContext).Environment.ResourceManagerUrl.TrimEnd('/') foreach ($sub in $subscriptions) { Set-AzContext -SubscriptionId $sub.subscriptionId | Out-Null @@ -71,7 +70,7 @@ } catch { - Write-PSFMessage "Unable to enumerate firewall policies in subscription $($sub.Name): $($_.Exception.Message)" -Tag Firewall -Level Warning + Write-PSFMessage "Unable to enumerate firewall policies in subscription $($sub.displayName): $($_.Exception.Message)" -Tag Firewall -Level Warning continue } From d3be959cbaa69e2056e855d6a814c997e15527a7 Mon Sep 17 00:00:00 2001 From: Kshitiz sharma Date: Thu, 5 Feb 2026 09:44:40 +0530 Subject: [PATCH 10/10] Reviewer comment resolved --- .../tests/Test-Assessment.25537.ps1 | 210 ++++++++++-------- 1 file changed, 118 insertions(+), 92 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.25537.ps1 b/src/powershell/tests/Test-Assessment.25537.ps1 index a1e60b51f..5c313158a 100644 --- a/src/powershell/tests/Test-Assessment.25537.ps1 +++ b/src/powershell/tests/Test-Assessment.25537.ps1 @@ -1,5 +1,5 @@ - <# +<# .SYNOPSIS Validates Threat intelligence is Enabled in Deny Mode on Azure Firewall. .DESCRIPTION @@ -11,127 +11,153 @@ Required API: Azure Firewall Policies #> - function Test-Assessment-25537 { - [ZtTest( - Category = 'Azure Network Security', - ImplementationCost = 'Low', - MinimumLicense = ('Azure_Firewall_Standard', 'Azure_Firewall_Premium'), - Pillar = 'Network', - RiskLevel = 'High', - SfiPillar = 'Protect networks', - TenantType = ('Workforce'), - TestId = 25537, - Title = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall', - UserImpact = 'Low' - )] - [CmdletBinding()] - param() - - Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose - - #region Data Collection +function Test-Assessment-25537 { + [ZtTest( + Category = 'Azure Network Security', + ImplementationCost = 'Low', + MinimumLicense = ('Azure_Firewall_Standard', 'Azure_Firewall_Premium'), + Pillar = 'Network', + RiskLevel = 'High', + SfiPillar = 'Protect networks', + TenantType = ('Workforce'), + TestId = 25537, + Title = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall', + UserImpact = 'Low' + )] + [CmdletBinding()] + param() + + Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose + + #region Data Collection $activity = 'Azure Firewall Threat Intelligence' - Write-ZtProgress ` - -Activity $activity ` - -Status 'Enumerating Firewall Policies' - - # Query 1: List all subscriptions - $resourceManagerUrl = (Get-AzContext).Environment.ResourceManagerUrl.TrimEnd('/') - $subscriptionsUri = "$resourceManagerUrl/subscriptions?api-version=2020-01-01" + Write-ZtProgress -Activity $activity -Status 'Enumerating Firewall Policies' + + # Query 1: List all subscriptions + $context = Get-AzContext + if (($context).Environment.name -ne 'AzureCloud') { + Write-PSFMessage "This test is only applicable to the Global environment." -Tag Test -Level VeryVerbose + Add-ZtTestResultDetail -SkippedBecause NotSupported + return + } - try { - $subscriptionsResponse = Invoke-AzRestMethod -Method GET -Uri $subscriptionsUri -ErrorAction Stop - } - catch { - if ($_.Exception.Response.StatusCode -eq 403 -or $_.Exception.Message -like '*403*' -or $_.Exception.Message -like '*Forbidden*') { - Add-ZtTestResultDetail -SkippedBecause NoAzureAccess - return - } - } + try { + $accessToken = Get-AzAccessToken -AsSecureString -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + catch { + Write-PSFMessage $_.Exception.Message -Tag Test -Level Error + } - $subscriptions = ($subscriptionsResponse.Content | ConvertFrom-Json).value + if (-not $accessToken) { + Write-PSFMessage "Azure authentication token not found." -Tag Test -Level Warning + Add-ZtTestResultDetail -SkippedBecause 'NotConnectedAzure' + return + } + $resourceManagerUrl = ($context).Environment.ResourceManagerUrl.TrimEnd('/') + $subscriptionsUri = "$resourceManagerUrl/subscriptions?api-version=2025-03-01" - if (-not $subscriptions) { - Add-ZtTestResultDetail -SkippedBecause NoResults + try { + $subscriptionsResponse = Invoke-AzRestMethod -Method GET -Uri $subscriptionsUri -ErrorAction Stop + } + catch { + if ($_.Exception.Response.StatusCode -eq 403 -or $_.Exception.Message -like '*403*' -or $_.Exception.Message -like '*Forbidden*') { + Add-ZtTestResultDetail -SkippedBecause NoAzureAccess return } - $results = @() - foreach ($sub in $subscriptions) { + } - Set-AzContext -SubscriptionId $sub.subscriptionId | Out-Null + $subscriptions = ($subscriptionsResponse.Content | ConvertFrom-Json).value - # Query 1: List Azure Firewall Policies - try { - $policiesUri = "$resourceManagerUrl/subscriptions/$($sub.subscriptionId)/providers/Microsoft.Network/firewallPolicies?api-version=2023-04-01" - Write-ZtProgress -Activity $activity -Status "Enumerating policies in subscription $($sub.displayName)" + if (-not $subscriptions) { + Add-ZtTestResultDetail -SkippedBecause NoAzureAccess + return + } + $results = @() + foreach ($sub in $subscriptions) { - $policyResponse = (Invoke-AzRestMethod -Method GET -Uri $policiesUri -ErrorAction Stop ).Content | ConvertFrom-Json - $policies = $policyResponse.value + Set-AzContext -SubscriptionId $sub.subscriptionId | Out-Null - } - catch { - Write-PSFMessage "Unable to enumerate firewall policies in subscription $($sub.displayName): $($_.Exception.Message)" -Tag Firewall -Level Warning - continue - } + # Query 2 : List Azure Firewall Policies + try { + $policiesUri = "$resourceManagerUrl/subscriptions/$($sub.subscriptionId)/providers/Microsoft.Network/firewallPolicies?api-version=2025-03-01" + Write-ZtProgress -Activity $activity -Status "Enumerating policies in subscription $($sub.displayName)" - if (-not $policies) { continue } + $policyResponse = (Invoke-AzRestMethod -Method GET -Uri $policiesUri -ErrorAction Stop ).Content | ConvertFrom-Json + $policies = $policyResponse.value - # Query 2: Get details for each firewall policy and check threatIntelMode - foreach ($policyResource in $policies) { + } + catch { + Write-PSFMessage "Unable to enumerate firewall policies in subscription $($sub.displayName): $($_.Exception.Message)" -Tag Firewall -Level Warning + continue + } + + if (-not $policies) { + continue + } + + # Query 2: Get details for each firewall policy and check threatIntelMode + foreach ($policyResource in $policies) { $threatIntelMode = $policyResource.Properties.threatIntelMode - $subContext = Get-AzContext + $subContext = Get-AzContext - $results += [PSCustomObject]@{ - PolicyName = $policyResource.Name - SubscriptionName = $subContext.Subscription.Name - SubscriptionId = $subContext.Subscription.Id - ThreatIntelMode = $threatIntelMode - PolicyID = $policyResource.Id - Passed = $threatIntelMode -eq 'Deny' - } - } - } - #endregion Data Collection + $results += [PSCustomObject]@{ + PolicyName = $policyResource.Name + SubscriptionName = $subContext.Subscription.Name + SubscriptionId = $subContext.Subscription.Id + ThreatIntelMode = $threatIntelMode + PolicyID = $policyResource.Id + Passed = $threatIntelMode -eq 'Deny' + } + } + } + #endregion Data Collection - #region Assessment Logic + #region Assessment Logic - $passed = ($results | Where-Object { -not $_.Passed }).Count -eq 0 - $allAlert = ($results | Where-Object { $_.ThreatIntelMode -ne 'Alert' }).Count -eq 0 + $passed = ($results | Where-Object { -not $_.Passed }).Count -eq 0 + $allAlert = ($results | Where-Object { $_.ThreatIntelMode -ne 'Alert' }).Count -eq 0 $testResultMarkdown = if ($passed) { "Threat Intel is enabled in **Alert and Deny** mode .`n`n%TestResult%" - } elseif ($allAlert) { + } + elseif ($allAlert) { "Threat Intel is enabled in **Alert** mode .`n`n%TestResult%" - } else { + } + else { "Threat Intel is not enabled in **Alert and Deny** mode for all Firewall policies.`n`n%TestResult%" } #endregion Assessment Logic - #region Report Generation - $mdInfo = "## Firewall policies`n`n" - $mdInfo += "| Policy name | Subscription name | Threat Intel mode | Result |`n" - $mdInfo += "| :--- | :--- | :--- | :--- |`n" - - foreach ($item in $results | Sort-Object PolicyName) { - $policyLink = "https://portal.azure.com/#resource$($item.PolicyID)" - $subLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)" - $policyMd = "[$(Get-SafeMarkdown -Text $item.PolicyName)]($policyLink)" - $subMd = "[$(Get-SafeMarkdown -Text $item.SubscriptionName)]($subLink)" - $icon = if ($item.Passed) { '✅' } else { '❌' } - $mdInfo += "| $policyMd | $subMd | $($item.ThreatIntelMode) | $icon |`n" - } - - $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo - #endregion Report Generation - $params = @{ + #region Report Generation + $mdInfo = "## Firewall policies`n`n" + $mdInfo += "| Policy name | Subscription name | Threat Intel mode | Result |`n" + $mdInfo += "| :--- | :--- | :--- | :--- |`n" + + foreach ($item in $results | Sort-Object PolicyName) { + $policyLink = "https://portal.azure.com/#resource$($item.PolicyID)" + $subLink = "https://portal.azure.com/#resource/subscriptions/$($item.SubscriptionId)" + $policyMd = "[$(Get-SafeMarkdown -Text $item.PolicyName)]($policyLink)" + $subMd = "[$(Get-SafeMarkdown -Text $item.SubscriptionName)]($subLink)" + $icon = if ($item.Passed) { + '✅' + } + else { + '❌' + } + $mdInfo += "| $policyMd | $subMd | $($item.ThreatIntelMode) | $icon |`n" + } + + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo + #endregion Report Generation + $params = @{ TestId = '25537' Title = 'Threat intelligence is Enabled in Deny Mode on Azure Firewall' Status = $passed Result = $testResultMarkdown } - Add-ZtTestResultDetail @params - } + Add-ZtTestResultDetail @params +}