Public/Network/Get-VergeDNSZone.ps1

function Get-VergeDNSZone {
    <#
    .SYNOPSIS
        Retrieves DNS zones from a VergeOS virtual network.

    .DESCRIPTION
        Get-VergeDNSZone queries DNS zones configured on a network's DNS views.
        Use -IncludeRecords to also retrieve the DNS records within each zone.

    .PARAMETER Network
        The name or key of the network to query DNS zones from.

    .PARAMETER NetworkObject
        A network object from Get-VergeNetwork. Accepts pipeline input.

    .PARAMETER Domain
        Filter by domain name. Supports wildcards (* and ?).

    .PARAMETER Key
        Get a specific zone by its unique key.

    .PARAMETER IncludeRecords
        Include DNS records in the output.

    .PARAMETER Server
        The VergeOS connection to use. Defaults to the current default connection.

    .EXAMPLE
        Get-VergeDNSZone -Network "Internal"

        Lists all DNS zones on the Internal network.

    .EXAMPLE
        Get-VergeDNSZone -Network "Internal" -Domain "*.local"

        Gets all zones ending with .local.

    .EXAMPLE
        Get-VergeDNSZone -Network "Internal" -IncludeRecords

        Gets all zones with their DNS records.

    .OUTPUTS
        Verge.DNSZone

    .NOTES
        DNS zones are organized under DNS views. Each network can have multiple views.
    #>

    [CmdletBinding(DefaultParameterSetName = 'ByNetworkName')]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByNetworkName')]
        [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByKey')]
        [string]$Network,

        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'ByNetworkObject')]
        [PSTypeName('Verge.Network')]
        [PSCustomObject]$NetworkObject,

        [Parameter()]
        [SupportsWildcards()]
        [string]$Domain,

        [Parameter(Mandatory, ParameterSetName = 'ByKey')]
        [int]$Key,

        [Parameter()]
        [switch]$IncludeRecords,

        [Parameter()]
        [object]$Server
    )

    begin {
        # Resolve connection
        if (-not $Server) {
            $Server = $script:DefaultConnection
        }
        if (-not $Server) {
            throw [System.InvalidOperationException]::new(
                'Not connected to VergeOS. Use Connect-VergeOS to establish a connection.'
            )
        }

        # Type mapping
        $typeMap = @{
            'master'      = 'Primary'
            'slave'       = 'Secondary'
            'redirect'    = 'Redirect'
            'forward'     = 'Forward'
            'static-stub' = 'Static Stub'
            'stub'        = 'Stub'
        }
    }

    process {
        # Resolve network
        $targetNetwork = $null
        if ($PSCmdlet.ParameterSetName -eq 'ByNetworkObject') {
            $targetNetwork = $NetworkObject
        }
        else {
            if ($Network -match '^\d+$') {
                $targetNetwork = Get-VergeNetwork -Key ([int]$Network) -Server $Server
            }
            else {
                $targetNetwork = Get-VergeNetwork -Name $Network -Server $Server
            }
        }

        if (-not $targetNetwork) {
            Write-Error -Message "Network '$Network' not found" -ErrorId 'NetworkNotFound'
            return
        }

        Write-Verbose "Querying DNS zones for network '$($targetNetwork.Name)'"

        # First get DNS views for this network
        $viewQuery = @{
            filter = "vnet eq $($targetNetwork.Key)"
            fields = '$key,name'
        }

        try {
            $viewResponse = Invoke-VergeAPI -Method GET -Endpoint 'vnet_dns_views' -Query $viewQuery -Connection $Server

            # Handle view response
            $views = if ($null -eq $viewResponse) {
                @()
            }
            elseif ($viewResponse -is [array]) {
                $viewResponse
            }
            elseif ($viewResponse.'$key') {
                @($viewResponse)
            }
            else {
                @()
            }

            if ($views.Count -eq 0) {
                Write-Verbose "No DNS views found on network '$($targetNetwork.Name)'"
                return
            }

            # Get zones for each view
            foreach ($view in $views) {
                $viewKey = $view.'$key'
                $viewName = $view.name

                # Build filter for zones
                $filterParts = @("view eq $viewKey")

                if ($PSBoundParameters.ContainsKey('Key')) {
                    $filterParts += "`$key eq $Key"
                }

                if ($Domain -and -not [WildcardPattern]::ContainsWildcardCharacters($Domain)) {
                    $filterParts += "domain eq '$Domain'"
                }

                $filter = $filterParts -join ' and '

                $zoneQuery = @{
                    filter = $filter
                    fields = '$key,view,domain,type,nameserver,email,default_ttl,serial_number'
                    sort   = 'domain'
                }

                $zoneResponse = Invoke-VergeAPI -Method GET -Endpoint 'vnet_dns_zones' -Query $zoneQuery -Connection $Server

                # Handle zone response
                $zones = if ($null -eq $zoneResponse) {
                    @()
                }
                elseif ($zoneResponse -is [array]) {
                    $zoneResponse
                }
                elseif ($zoneResponse.'$key') {
                    @($zoneResponse)
                }
                else {
                    @()
                }

                # Apply wildcard filtering if needed
                if ($Domain -and [WildcardPattern]::ContainsWildcardCharacters($Domain)) {
                    $zones = $zones | Where-Object { $_.domain -like $Domain }
                }

                foreach ($zone in $zones) {
                    # Get records if requested
                    $records = @()
                    if ($IncludeRecords) {
                        $recordQuery = @{
                            filter = "zone eq $($zone.'$key')"
                            fields = '$key,host,type,value,ttl,mx_preference'
                            sort   = 'orderid'
                        }

                        $recordResponse = Invoke-VergeAPI -Method GET -Endpoint 'vnet_dns_zone_records' -Query $recordQuery -Connection $Server

                        $records = if ($null -eq $recordResponse) {
                            @()
                        }
                        elseif ($recordResponse -is [array]) {
                            $recordResponse
                        }
                        elseif ($recordResponse.'$key') {
                            @($recordResponse)
                        }
                        else {
                            @()
                        }
                    }

                    # Create typed output object
                    $output = [PSCustomObject]@{
                        PSTypeName   = 'Verge.DNSZone'
                        Key          = $zone.'$key'
                        NetworkKey   = $targetNetwork.Key
                        NetworkName  = $targetNetwork.Name
                        ViewKey      = $viewKey
                        ViewName     = $viewName
                        Domain       = $zone.domain
                        Type         = if ($typeMap[$zone.type]) { $typeMap[$zone.type] } else { $zone.type }
                        NameServer   = $zone.nameserver
                        Email        = $zone.email
                        DefaultTTL   = $zone.default_ttl
                        SerialNumber = $zone.serial_number
                    }

                    if ($IncludeRecords) {
                        $recordObjects = foreach ($rec in $records) {
                            [PSCustomObject]@{
                                Key          = $rec.'$key'
                                Host         = $rec.host
                                Type         = $rec.type
                                Value        = $rec.value
                                TTL          = $rec.ttl
                                MXPreference = $rec.mx_preference
                            }
                        }
                        $output | Add-Member -MemberType NoteProperty -Name 'Records' -Value $recordObjects
                    }

                    Write-Output $output
                }
            }
        }
        catch {
            Write-Error -Message "Failed to query DNS zones: $($_.Exception.Message)" -ErrorId 'DNSZoneQueryFailed'
        }
    }
}