Providers/AD/Private/Get-ADTestDomain.ps1
|
function Get-ADTestDomain { <# .SYNOPSIS Returns the domain the provider is working against, and its distinguished name .DESCRIPTION Every AD provider function needs the domain DN to build an OU path, so this is asked for constantly and must give the same answer every time within a session. The connection recorded by Connect-ADEnvironment is therefore authoritative when there is one. Re-detecting per call would let a session that started against one domain quietly continue against another - a machine can be re-joined, and USERDNSDOMAIN can be set by hand - and every function that builds a path from it would follow without complaint. Detection only runs when nothing is connected, which keeps the helper usable on its own. .OUTPUTS System.Collections.Hashtable with DNSName, DomainDN and ForestDN. ForestDN is the forest root's distinguished name, which differs from DomainDN in a child domain; when nothing is connected it is derived from the detected domain's forest, or falls back to DomainDN. .EXAMPLE PS> Get-ADTestDomain DESCRIPTION: Returns the connected domain, detecting one if nothing is connected OUTPUT: @{ DNSName = 'ad.contoso.com'; DomainDN = 'DC=ad,DC=contoso,DC=com'; ForestDN = 'DC=ad,DC=contoso,DC=com' } USE CASE: Called by every function that builds a distinguished name .NOTES Author: Jeffrey Stuhr Blog: https://www.techbyjeff.net LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/ #> [CmdletBinding()] [OutputType([hashtable])] param() if ($script:ADConnection) { return @{ DNSName = $script:ADConnection.DNSName DomainDN = $script:ADConnection.DomainDN ForestDN = $script:ADConnection.ForestDN } } try { # USERDNSDOMAIN first: it is set on any domain-joined session and costs nothing, where # Get-ADDomain is a directory call. $dnsDomain = $env:USERDNSDOMAIN $forestName = $null if ([string]::IsNullOrEmpty($dnsDomain)) { $currentDomain = Get-ADDomain -Current LocalComputer -ErrorAction SilentlyContinue if ($currentDomain) { $dnsDomain = $currentDomain.DNSRoot $forestName = $currentDomain.Forest } } if (-not $dnsDomain) { throw 'Could not detect domain' } # Every label becomes a DC component. The previous version enumerated the one, two and # three label cases and fell through to the first label alone for anything deeper, so a # four-label domain silently produced a DN one level below the root - and every OU path # built from it would have been wrong without erroring. $domainDN = ($dnsDomain.Split('.') | ForEach-Object { "DC=$_" }) -join ',' # USERDNSDOMAIN says nothing about the forest, so the forest root is known only when # the directory was asked. Without it the domain's own DN is the best available answer, # which is exact in a single-domain forest. $forestDN = if ($forestName) { ($forestName.Split('.') | ForEach-Object { "DC=$_" }) -join ',' } else { $domainDN } Write-Verbose "Detected domain: $dnsDomain (DN: $domainDN, forest: $forestDN)" return @{ DNSName = $dnsDomain DomainDN = $domainDN ForestDN = $forestDN } } catch { throw "Failed to detect domain: $($_.Exception.Message). Please ensure this is run on a domain-joined machine with the ActiveDirectory module available." } } |