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 and 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' }
        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
        }
    }

    try {
        # USERDNSDOMAIN first: it is set on any domain-joined session and costs nothing, where
        # Get-ADDomain is a directory call.
        $dnsDomain = $env:USERDNSDOMAIN
        if ([string]::IsNullOrEmpty($dnsDomain)) {
            $currentDomain = Get-ADDomain -Current LocalComputer -ErrorAction SilentlyContinue
            if ($currentDomain) {
                $dnsDomain = $currentDomain.DNSRoot
            }
        }

        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 ','

        Write-Verbose "Detected domain: $dnsDomain (DN: $domainDN)"

        return @{
            DNSName  = $dnsDomain
            DomainDN = $domainDN
        }
    }
    catch {
        throw "Failed to detect domain: $($_.Exception.Message). Please ensure this is run on a domain-joined machine with the ActiveDirectory module available."
    }
}