tests/Test-Assessment.24552.ps1

<#
.SYNOPSIS
    Test macOS Firewall Policy is created and assigned
#>




function Test-Assessment-24552 {
    [ZtTest(
        Category = 'Device',
        ImplementationCost = 'Low',
        MinimumLicense = ('Intune'),
        Pillar = 'Devices',
        RiskLevel = 'Medium',
        SfiPillar = 'Protect engineering systems',
        TenantType = ('Workforce'),
        TestId = 24552,
        Title = 'macOS Firewall policies protect against unauthorized network access',
        UserImpact = 'High'
    )]
    [CmdletBinding()]
    param(
        $Database
    )

    #region Helper Functions
    function Test-PolicyAssignment {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory = $false)]
            [array]$Policies
        )

        # Return false if $Policies is null or empty
        if (-not $Policies) {
            return $false
        }

        # Check if at least one policy has assignments
        $assignedPolicies = $Policies | Where-Object {
            $_.PSObject.Properties.Match("assignments") -and $_.assignments -and $_.assignments.Count -gt 0
        }

        return $assignedPolicies.Count -gt 0
    }

    #endregion Helper Functions

    #region Data Collection
    Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose

    if ( -not (Get-ZtLicense Intune) ) {
        Add-ZtTestResultDetail -SkippedBecause NotLicensedIntune
        return
    }

    $activity = "Checking macOS Firewall Policy is Created and Assigned"
    Write-ZtProgress -Activity $activity -Status "Getting policy"

    # Query: Retrieve all macOS policies with mdm and appleRemoteManagement technologies.
    # Settings and assignments are returned as JSON for PowerShell-side filtering,
    # avoiding DuckDB list_transform lambda issues when data is null or absent.
    $sql = @"
    SELECT id, name, to_json(settings) as settings, to_json(assignments) as assignments
    FROM ConfigurationPolicy
    WHERE platforms LIKE '%macOS%'
      AND technologies LIKE '%mdm%'
      AND technologies LIKE '%appleRemoteManagement%'
"@

    $macOSAllPolicies = Invoke-DatabaseQuery -Database $Database -Sql $sql -AsCustomObject

    # Parse JSON fields
    foreach ($policy in $macOSAllPolicies) {
        if ($policy.settings -is [string]) {
            $policy.settings = $policy.settings | ConvertFrom-Json
        }
        if ($policy.assignments -is [string]) {
            $policy.assignments = $policy.assignments | ConvertFrom-Json
        }
    }

    # Filter to only policies that contain the macOS firewall setting definition
    $macOSFirewallPolicies = @($macOSAllPolicies | Where-Object {
        $_.settings.settingInstance.settingDefinitionId -contains 'com.apple.security.firewall_com.apple.security.firewall'
    })

    # Filter policies to include only those related to firewall settings
    foreach ($macOSPolicy in $macOSFirewallPolicies) {
        $validSettingIds = @('com.apple.security.firewall_enablefirewall_true')

        # Get all choice values from the firewall setting's children (PowerShell-side, avoids DuckDB lambda issues)
        $firewallSetting = $macOSPolicy.settings | Where-Object { $_.settingInstance.settingDefinitionId -eq 'com.apple.security.firewall_com.apple.security.firewall' } | Select-Object -First 1
        $policySettingIds = if ($firewallSetting -and $firewallSetting.settingInstance.groupSettingCollectionValue) {
            @($firewallSetting.settingInstance.groupSettingCollectionValue[0].children.choiceSettingValue.value)
        } else {
            @()
        }

        # Check if any of the policy's setting IDs match our valid setting IDs
        $hasValidSetting = $false
        foreach ($settingId in $policySettingIds) {
            if ($validSettingIds -contains $settingId) {
                $hasValidSetting = $true
                [PSFramework.Object.ObjectHost]::AddNoteProperty($macOSPolicy, 'FirewallSettings', $true)
                break
            }
        }

        if (-not $hasValidSetting) {
             [PSFramework.Object.ObjectHost]::AddNoteProperty($macOSPolicy, 'FirewallSettings', $false)
        }
    }
    #endregion Data Collection

    #region Assessment Logic
    $passed = $false
    $testResultMarkdown = ""

    # Test macOS firewall policy assignments — only policies with firewall actually enabled count
    $passed = Test-PolicyAssignment -Policies ($macOSFirewallPolicies | Where-Object { $_.FirewallSettings -eq $true })

    if ($passed) {
        $testResultMarkdown = "A macOS firewall policy is configured and assigned in Intune.`n`n%TestResult%"
    }
    else {
        $testResultMarkdown = "No assigned macOS firewall policy was found in Intune.`n`n%TestResult%"
    }
    #endregion Assessment Logic

    #region Report Generation
    # Build the detailed sections of the markdown

    # Define variables to insert into the format string
    $reportTitle = "macOS Firewall Policies"
    $tableRows = ""

    if ($macOSFirewallPolicies.Count -gt 0) {
        # Create a here-string with format placeholders {0}, {1}, etc.
        $formatTemplate = @'
 
## {0}
 
| Policy name | Status | Assignment target | Firewall status |
| :---------- | :----- | :---------------- | :-------------- |
{1}
 
'@


        foreach ($policy in $macOSFirewallPolicies) {

            $policyName = Get-SafeMarkdown -Text $policy.name
            $portalLink = 'https://intune.microsoft.com/#view/Microsoft_Intune_DeviceSettings/DevicesMenu/~/configuration'

            if ($policy.assignments -and $policy.assignments.Count -gt 0) {
                $status = '✅ Assigned'
                $assignmentTarget = Get-PolicyAssignmentTarget -Assignments $policy.assignments
            }
            else {
                $status = '❌ Not assigned'
                $assignmentTarget = 'None'
            }

            if ($policy.FirewallSettings) {
                $firewallSettings = '✅ Enabled'
            }
            else {
                $firewallSettings = '❌ Disabled'
            }

            $tableRows += "| [$policyName]($portalLink) | $status | $assignmentTarget | $firewallSettings |`n"
        }

        # Format the template by replacing placeholders with values
        $mdInfo = $formatTemplate -f $reportTitle, $tableRows
    }
    else {
        $mdInfo = ''
    }

    # Replace the placeholder with the detailed information
    $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $mdInfo
    #endregion Report Generation

    $params = @{
        TestId = '24552'
        Title  = 'macOS - Firewall policy is created and assigned'
        Status = $passed
        Result = $testResultMarkdown
    }

    Add-ZtTestResultDetail @params
}