DSCResources/DhcpServer/DhcpServer.schema.psm1

# see https://github.com/dsccommunity/xDhcpServer
configuration DhcpServer
{
    param
    (
        [Parameter()]
        [hashtable[]]
        $Scopes,

        [Parameter()]
        [object[]]
        $ExclusionRanges,

        [Parameter()]
        [hashtable[]]
        $OptionValues,

        [Parameter()]
        [hashtable[]]
        $Reservations,

        [Parameter()]
        [hashtable]
        $Authorization,

        [Parameter()]
        [bool]
        $EnableSecurityGroups
    )

    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Import-DscResource -ModuleName xDhcpServer

    WindowsFeature DHCPServer
    {
        Name   = 'DHCP'
        Ensure = 'Present'
    }

    if ($EnableSecurityGroups -eq $true)
    {
        Script DHCPSecGroups
        {
            SetScript  = {
                netsh dhcp add securitygroups
                Restart-Service dhcpserver
            }
            TestScript = {
                $checkDhcpSecGrpA = Get-ADGroup -filter "Name -eq 'DHCP Administrators'"
                $checkDhcpSecGrpU = Get-ADGroup -filter "Name -eq 'DHCP Users'"

                if ( $null -eq $checkDhcpSecGrpA -or $null -eq $checkDhcpSecGrpU )
                {
                    Write-Verbose -Message 'Missing ADGroup DHCP Security groups.'
                    return $false
                }

                Write-Verbose -Message 'ADGroup DHCP Security groups are existing.'
                return $true
            }
            GetScript  = { return `
                @{
                    result = 'N/A'
                }
            }
            DependsOn  = '[WindowsFeature]DHCPServer'
        }
    }

    if ($null -ne $Scopes)
    {
        foreach ($scope in $Scopes.GetEnumerator())
        {
            # Remove Case Sensitivity of ordered Dictionary or Hashtables
            $scope = @{} + $scope

            if ( [String]::IsNullOrWhitespace($scope.Ensure) )
            {
                $scope.Ensure = 'Present'
            }

            if ( [String]::IsNullOrWhitespace($scope.AddressFamily) )
            {
                $scope.AddressFamily = 'IPv4'
            }

            $scope.DependsOn = '[WindowsFeature]DHCPServer'

            $nameProtection = $scope.DnsNameProtection

            $scope.Remove( 'DnsNameProtection' )

            $executionName = "dhcpscope_$($scope.ScopeID -replace '[-.\s]','_')"
            (Get-DscSplattedResource -ResourceName xDhcpServerScope -ExecutionName $executionName -Properties $scope -NoInvoke).Invoke($scope)

            # generate DNS settings only if scope is present and one of the DNS settings are explicitly specified
            if ($scope.Ensure -eq 'Present' -and $null -ne $nameProtection)
            {
                [string]$scopeId = $scope.ScopeID
                [boolean]$dnsNameProtection = $nameProtection

                Script "$($executionName)_DnsSetting"
                {
                    SetScript  = {
                        Write-Verbose "DHCP Scope: $using:scopeId -> set DNS NameProtection to $using:dnsNameProtection"
                        Set-DhcpServerv4DnsSetting -ScopeId $using:scopeId -NameProtection $using:dnsNameProtection
                    }
                    TestScript = {
                        Write-Verbose "DHCP Scope: $using:scopeId -> test DNS NameProtection: $using:dnsNameProtection"
                        $dnsSetting = Get-DhcpServerv4DnsSetting -ScopeId $using:scopeId
                        Write-Verbose "DNS setting: $(($dnsSetting | Select-Object -Property '*' -ExcludeProperty 'Cim*') -join ', ' | Out-String)"

                        if ( $null -ne $dnsSetting -and $dnsSetting.NameProtection -eq $using:dnsNameProtection )
                        {
                            return $True
                        }

                        return $False
                    }
                    GetScript  = { return `
                        @{
                            result = 'N/A'
                        }
                    }
                    DependsOn  = "[xDhcpServerScope]$executionName"
                }
            }
        }
    }

    if ( $null -ne $ExclusionRanges )
    {
        [int] $i = 0

        foreach ($exclusionRange in $ExclusionRanges.GetEnumerator())
        {
            $exclusionRange.DependsOn = '[WindowsFeature]DHCPServer'

            $i++
            (Get-DscSplattedResource -ResourceName DhcpServerExclusionRange -ExecutionName "dhcpExclusionRange$i" -Properties $exclusionRange -NoInvoke).Invoke($exclusionRange)
        }
    }

    if ($null -ne $Reservations)
    {
        foreach ($reservation in $Reservations.GetEnumerator())
        {
            # Remove Case Sensitivity of ordered Dictionary or Hashtables
            $reservation = @{} + $reservation

            if ([String]::IsNullOrWhitespace($reservation.Ensure))
            {
                $reservation.Ensure = 'Present'
            }

            if ([String]::IsNullOrWhitespace($reservation.AddressFamily))
            {
                $reservation.AddressFamily = 'IPv4'
            }

            # remove all separators from MAC Address
            $reservation.ClientMACAddress = $reservation.ClientMACAddress -replace '[-:\s]', ''

            $reservation.DependsOn = '[WindowsFeature]DHCPServer'

            $executionName = "dhcpReservation_$($reservation.ScopeID -replace '[().:\s]', '_')__$($reservation.IPAddress -replace '[().:\s]', '_')"

            (Get-DscSplattedResource -ResourceName xDhcpServerReservation -ExecutionName $executionName -Properties $reservation -NoInvoke).Invoke($reservation)
        }
    }

    if ( $null -ne $OptionValues )
    {
        foreach ($optionValue in $OptionValues.GetEnumerator())
        {
            # Remove Case Sensitivity of ordered Dictionary or Hashtables
            $optionValue = @{} + $optionValue

            $optionValue.DependsOn = '[WindowsFeature]DHCPServer'

            # set VendorClass/UserClass to default if missing or empty
            if ([String]::IsNullOrWhitespace($optionValue.VendorClass))
            {
                $optionValue.VendorClass = ''
            }

            if ([String]::IsNullOrWhitespace($optionValue.UserClass))
            {
                $optionValue.UserClass = ''
            }

            (Get-DscSplattedResource -ResourceName DhcpServerOptionValue -ExecutionName "dhcpServerOptionValue$($optionValue.OptionId)" -Properties $optionValue -NoInvoke).Invoke($optionValue)
        }
    }

    if ($null -ne $Authorization)
    {
        # Remove Case Sensitivity of ordered Dictionary or Hashtables
        $Authorization = @{} + $Authorization

        if ([String]::IsNullOrWhitespace($Authorization.Ensure))
        {
            $Authorization.Ensure = 'Present'
        }

        $Authorization.IsSingleInstance = 'Yes'

        (Get-DscSplattedResource -ResourceName xDhcpServerAuthorization -ExecutionName 'dhcpSrvAuth' -Properties $Authorization -NoInvoke).Invoke($Authorization)
    }
}