Skip to content

Instantly share code, notes, and snippets.

@malacupa
Last active December 13, 2024 21:50
Show Gist options
  • Save malacupa/0b7694f93dbaf5bf1b9d23ec55b0b648 to your computer and use it in GitHub Desktop.
Save malacupa/0b7694f93dbaf5bf1b9d23ec55b0b648 to your computer and use it in GitHub Desktop.
Enumerate dynamic update settings for Active Directory Integrated DNS (ADIDNS) zones
# see https://malacupa.com/2024/12/13/unsecure-dynamic-updates for a bit more info on dynamic update settings
function Parse-DnsProperty {
param (
[Parameter(Mandatory=$true)]
$dnsPropertyValues
)
# see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/445c7843-e4a1-4222-8c0f-630c230a4c80 for description
$parsedValues = @()
$dnsPropertyValues | %{
$value = $_
if ($value -is [byte[]]) {
$parsedValue = @{}
# Extract DataLength (4 bytes)
$dataLengthBytes = $value[0..3]
#[Array]::Reverse($dataLengthBytes)
$parsedValue.DataLength = [BitConverter]::ToUInt32($dataLengthBytes, 0)
# Extract NameLength (4 bytes) - Not Used
$nameLengthBytes = $value[4..7]
#[Array]::Reverse($nameLengthBytes)
$parsedValue.NameLength = [BitConverter]::ToUInt32($nameLengthBytes, 0)
# Extract Flag (4 bytes) - Reserved for future use
$flagBytes = $value[8..11]
#[Array]::Reverse($flagBytes)
$parsedValue.Flag = [BitConverter]::ToUInt32($flagBytes, 0)
# Extract Version (4 bytes)
$versionBytes = $value[12..15]
#[Array]::Reverse($versionBytes)
$parsedValue.Version = [BitConverter]::ToUInt32($versionBytes, 0)
# Extract Id (4 bytes)
$idBytes = $value[16..19]
#[Array]::Reverse($idBytes)
$parsedValue.Id = [BitConverter]::ToUInt32($idBytes, 0)
# Extract Data (variable length)
$dataBytes = $value[20..(19 + $parsedValue.DataLength)]
$parsedValue.Data = $dataBytes
# Extract Name (1 byte) - Not Used
$parsedValue.Name = $value[20 + $parsedValue.DataLength]
$parsedValues += $parsedValue
}
}
return $parsedValues
}
function Get-DynamicUpdateSupport {
param(
$zone
)
$values = Parse-DnsProperty $zone.properties.dnsproperty | ?{ $_.id -eq 2 }
if ($values.length -eq 1) {
switch ($values.Data) {
# see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dnsp/e8651544-0fbb-4038-8232-375ff2d8a55e for details
0 { return 'ZONE_UPDATE_OFF' }
1 { return 'ZONE_UPDATE_UNSECURE'}
2 { return 'ZONE_UPDATE_SECURE' }
Default { return 'Invalid value' }
}
}
throw "dnsProperty structure is missing DSPROPERTY_ZONE_ALLOW_UPDATE property ID"
}
function Get-DynamicUpdateSupportInForest {
<#
.SYNOPSIS
Retrieves the dynamic update support status for all DNS zones in the forest.
.DESCRIPTION
The Get-DynamicUpdateSupportInForest function retrieves the dynamic update support status for all DNS zones in the forest. It queries each domain in the forest and checks the dynamic update status for each DNS zone.
.PARAMETER None
This function does not take any parameters.
.EXAMPLE
PS C:\> Get-DynamicUpdateSupportInForest -Verbose
This command retrieves the dynamic update support status for all DNS zones in the forest, shows status during processing and displays the results.
#>
[CmdletBinding()]
param()
$res = [System.Collections.ArrayList]@()
$ds =[ADSISearcher]'(objectClass=dnsZone)'
$ds.PropertiesToLoad.Add('dNSProperty') | Out-Null
$ds.PropertiesToLoad.Add('Name') | Out-Null
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().Forest.Domains.Name | %{
Write-Verbose "Processing $_ domain"
$domain = $_
$domainDn = ('DC=' + ($_.split('.') -join ',DC='))
$ds.searchroot = "LDAP://DC=DomainDnsZones,$domainDn"
$ds.FindAll() |%{
$zone = $_
$zoneName = $zone.properties.name
$dynamicUpdateSupport = (Get-DynamicUpdateSupport $zone)
Write-Verbose "Processing $_ domain's zone $zoneName"
$res.Add([PSCustomObject]@{
Domain = $domain
Zone = $zoneName
DynamicUpdate = $dynamicUpdateSupport
}) | Out-Null
Write-Verbose "Doing $_ domain, zone $zoneName, dynamic update status = $dynamicUpdateSupport"
}
}
return $res
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment