public/Get-MtRegistrableDomain.ps1
|
function Get-MtRegistrableDomain { <# .SYNOPSIS Get the registrable domain for a given domain name. .DESCRIPTION This function retrieves the registrable domain for a given domain name based on the public suffix list. Uses a cached version of the public suffix list for performance reasons. Public suffix list is sourced from https://publicsuffix.org/ and stored in the Maester powershell assets repository. .PARAMETER DomainName The domain name for which to retrieve the registrable domain. .EXAMPLE Get-MtRegistrableDomain -DomainName "sub.example.co.uk" Returns "example.co.uk". .EXAMPLE Get-MtRegistrableDomain -DomainName "example.co.uk" Returns "example.co.uk". .EXAMPLE Get-MtRegistrableDomain -DomainName "sub.example.com" Returns "example.com". .EXAMPLE Get-MtRegistrableDomain -DomainName "example.com" Returns "example.com". .LINK https://maester.dev/docs/commands/Get-MtRegistrableDomain #> [OutputType([string])] [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$DomainName ) $normalizedDomainName = $DomainName.Trim('.').ToLowerInvariant() $labels = $normalizedDomainName.Split('.') # If the domain has less than 2 labels, return it as is (e.g., localhost or similar) if ($labels.Count -lt 2) { return $normalizedDomainName } # Load public suffix list if not already loaded for performance if ($null -eq $script:MtPublicSuffixRules) { Write-Verbose 'Loading public suffix list for registrable domain extraction' $pslPath = Join-Path -Path $PSScriptRoot -ChildPath '../assets/public_domain_suffix_list.dat' $exactRules = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) $wildcardRules = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) $exceptionRules = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($rule in (Get-Content -Path $pslPath -Encoding UTF8)) { $trimmedRule = $rule.Trim().ToLowerInvariant() if (($trimmedRule -eq '') -or $trimmedRule.StartsWith('//')) { continue } if ($trimmedRule.StartsWith('!')) { $null = $exceptionRules.Add($trimmedRule.Substring(1)) } elseif ($trimmedRule.StartsWith('*.')) { $null = $wildcardRules.Add($trimmedRule.Substring(2)) } else { $null = $exactRules.Add($trimmedRule) } } $script:MtPublicSuffixRules = @{ Exact = $exactRules Wildcard = $wildcardRules Exception = $exceptionRules } } # Apply the public suffix list longest-match algorithm, including wildcard and exception rules. $publicSuffixLabelCount = 1 for ($i = 0; $i -lt $labels.Count; $i++) { $candidate = $labels[$i..($labels.Count - 1)] -join '.' $candidateLabelCount = $labels.Count - $i if ($script:MtPublicSuffixRules.Exception.Contains($candidate)) { $publicSuffixLabelCount = $candidateLabelCount - 1 break } if ($script:MtPublicSuffixRules.Exact.Contains($candidate) -and ($candidateLabelCount -gt $publicSuffixLabelCount)) { $publicSuffixLabelCount = $candidateLabelCount } if (($i -gt 0) -and $script:MtPublicSuffixRules.Wildcard.Contains($candidate) -and (($candidateLabelCount + 1) -gt $publicSuffixLabelCount)) { $publicSuffixLabelCount = $candidateLabelCount + 1 } } if ($labels.Count -le $publicSuffixLabelCount) { return $normalizedDomainName } $registrableLabelCount = $publicSuffixLabelCount + 1 return ($labels[($labels.Count - $registrableLabelCount)..($labels.Count - 1)] -join '.') } |