Finding Domain Trusts in an Active Directory Forest using Microsoft PowerShell

For my Active Directory (AD) documentation script, I needed to enumerate all Trusts for a Domain. I found a script on TechNet but it had issues. I fixed the issues but I cannot post it as a solution on TechNet because my script is longer than 2000 characters.

I found the original script here.

My issues with the original script are:

  • No error checking
  •  Did not handle singletons
  •  Did not use its $DomainDNS variable in the Get-ADObject call to specify which domain to restrict the trusts
  •  The $TrustAttributesNumber variable used decimal values instead of hexadecimal values (i.e. 20 instead of 32)
  •  The $TrustAttributesNumber variable did not have a value for Inter-Forest trusts (hex 64)
  •  The Switch statements did not use Default but used an If statement after the Switch statement to set the Default value

Here is my version of the script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
Import-module ActiveDirectory
$Domains = (Get-ADForest).Domains
 
If($? -and $Domains -ne $Null)
{
    ForEach($Domain in $Domains)
    {
        Write-output "Get list of AD Domain Trusts in $Domain `r";
        $ADDomainTrusts = Get-ADObject -Filter {ObjectClass -eq "trustedDomain"} -Server $Domain -Properties * -EA 0
 
        If($? -and $ADDomainTrusts -ne $Null)
        {
            If($ADDomainTrusts -is [array])
            {
                [int]$ADDomainTrustsCount = $ADDomainTrusts.Count
            }
            Else
            {
                [int]$ADDomainTrustsCount = 1
            }
             
            Write-Output "Discovered $ADDomainTrustsCount trusts in $Domain"
             
            ForEach($Trust in $ADDomainTrusts)
            {
                $TrustName = $Trust.Name
                $TrustDescription = $Trust.Description
                $TrustCreated = $Trust.Created
                $TrustModified = $Trust.Modified
                $TrustDirectionNumber = $Trust.TrustDirection
                $TrustTypeNumber = $Trust.TrustType
                $TrustAttributesNumber = $Trust.TrustAttributes
 
                #no values are defined at the above link
                Switch ($TrustTypeNumber)
                {
                    1 { $TrustType = "Downlevel (Windows NT domain external)"}
                    2 { $TrustType = "Uplevel (Active Directory domain - parent-child, root domain, shortcut, external, or forest)"}
                    3 { $TrustType = "MIT (non-Windows) Kerberos version 5 realm"}
                    4 { $TrustType = "DCE (Theoretical trust type - DCE refers to Open Group's Distributed Computing Environment specification)"}
                    Default { $TrustType = $TrustTypeNumber }
                }
 
                Switch ($TrustAttributesNumber)
                {
                    1 { $TrustAttributes = "Non-Transitive"}
                    2 { $TrustAttributes = "Uplevel clients only (Windows 2000 or newer"}
                    4 { $TrustAttributes = "Quarantined Domain (External)"}
                    8 { $TrustAttributes = "Forest Trust"}
                    16 { $TrustAttributes = "Cross-Organizational Trust (Selective Authentication)"}
                    32 { $TrustAttributes = "Intra-Forest Trust (trust within the forest)"}
                    64 { $TrustAttributes = "Inter-Forest Trust (trust with another forest)"}
                    Default { $TrustAttributes = $TrustAttributesNumber }
                }
                  
                Switch ($TrustDirectionNumber)
                {
                    0 { $TrustDirection = "Disabled (The trust relationship exists but has been disabled)"}
                    1 { $TrustDirection = "Inbound (TrustING domain)"}
                    2 { $TrustDirection = "Outbound (TrustED domain)"}
                    3 { $TrustDirection = "Bidirectional (two-way trust)"}
                    Default { $TrustDirection = $TrustDirectionNumber }
                }
                        
                Write-output "`tTrust Name: $TrustName `r "
                Write-output "`tTrust Description: $TrustDescription `r "
                Write-output "`tTrust Created: $TrustCreated `r "
                Write-output "`tTrust Modified: $TrustModified  `r "
                Write-output "`tTrust Direction: $TrustDirection `r "
                Write-output "`tTrust Type: $TrustType `r "
                Write-output "`tTrust Attributes: $TrustAttributes `r "
                Write-output " `r "
            }
        }
        ElseIf(!$?)
        {
            #error retrieving domain trusts
            Write-output "Error retrieving domain trusts for $Domain"
        }
        Else
        {
            #no domain trust data
            Write-output "No domain trust data for $Domain"
        }
    }
}
ElseIf(!$?)
{
    #error retrieving domains
    Write-output "Error retrieving domains"
}
Else
{
    #no domain data
    Write-output "No domain data"
}

The original script only processed the domain in which the user was running the script. I changed it to process all domains in the forest.

I am using Write-Output as that is what the original script uses. I will update this code to work in my script using my normal output routines.

Thanks

Webster

15 Comments

  1. Bhaskar Raman

    A very naive question.

    1. Need permission to plagarize the script.
    2. How do I run the script?

    • Carl Webster

      1. Permission granted.
      2. Copy and paste the script into ISE or a PowerShell prompt.

      Thanks

      Webster

  2. Glenn

    I like this script, is there a way to write this to a file or html report?

    • Carl Webster

      This is included in my AD documentation script starting at line 10620.

      Webster

  3. zhiaga

    I got this error, help me please

    Get-ADObject : Error parsing query: ‘ObjectClass -eq “trustedDomain”;’ Error Message: ‘Operator Not supported: ‘ at
    position: ’32’.
    At C:\scripts\Get-ADTrusts-v2.ps1:42 char:27
    + $ADDomainTrusts = Get-ADObject -Filter {ObjectClass -eq “trustedDomain”; …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ParserError: (:) [Get-ADObject], ADFilterParsingException
    + FullyQualifiedErrorId : Error parsing query: ‘ObjectClass -eq “trustedDomain”;’ Error Message: ‘Operator Not sup
    ported: ‘ at position: ’32’.,Microsoft.ActiveDirectory.Management.Commands.GetADObject

    • Carl Webster

      This is usually a copy and paste issue. Make sure all the “-“s in your script are real “-“s. Copy what you see as a “-” and then do a replace with the “-” from your keyboard. That always fixes the issue for me.

      Thanks

      Webster

      • Adriano Ciampoli

        I get the same error

        Get-ADObject : Error parsing query: ‘ObjectClass -eq “trustedDomain”;’ Error Message: ‘Operator Not supported: ‘ at position: ’32’.
        At line:6 char:27
        + … ainTrusts = Get-ADObject -Filter {ObjectClass -eq “trustedDomain”;} – …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : ParserError: (:) [Get-ADObject], ADFilterParsingException
        + FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADFilterParsingException,Microsoft.ActiveDirectory.Management.Commands.GetADObject

        • Carl Webster

          Standard copy & paste error. Replace what looks like a – with what is on the same key as the underscore character.

          Webster

      • Adriano Ciampoli

        Actually there is a ; in the line below
        $ADDomainTrusts = Get-ADObject -Filter {ObjectClass -eq “trustedDomain”;} -Server $Domain -Properties * -EA 0

        I removed it and it works.

        • Carl Webster

          Actually looking back at other comments, several people have noted that. I thought I had removed it from the article.

          Webster

  4. manoj

    $ADDomainTrusts = Get-ADObject -Filter {ObjectClass -eq “trustedDomain”;} -Server $Domain -Properties * -EA 0

    should be

    $ADDomainTrusts = Get-ADObject -Filter ‘ObjectClass -eq “trustedDomain”‘ -Server $Domain -Properties * -EA 0

    • Carl Webster

      From my PowerShell mentor Michael B. Smith:

      The truth is, it doesn’t matter. The way you wrote it minimizes quoting requirements and it is the way all of the examples for the parameter are written. You do have an unneeded semicolon though. 

      This is just the way PowerShell works. All of the below produce equivalent results:

      { this is a test }
      “ this is a test “
      ‘ this is a test ‘

      Using a quoted string is slightly more efficient the first time it’s executed, but based on the way PowerShell caches the AST it doesn’t make any difference on subsequent executions.

      Note: AST = Abstract Syntax Trees

      Thanks

      Webster

  5. Rejone

    Hi Jeremy;

    Great info. We have an issue with a child domain. We recently deployed Citrix VDI and all of our virtual machines are not able to ping our child domain controllers. Have you seen this issue before? Any help would be appreciated.

    Rejone

    • Hi Rejone,

      Not sure if your question was for Webster or myself.

      I would expect this to be a host (Windows) firewall issue, but we would need more information from you before concluding that this is the issue:
      – Are the VMs also in the child domain?
      – Can the VMs communicate with the child domain controllers on other ports, such as LDAP, browse to the SYSVOL, etc?

      As this question is unrelated to Webster’s script it’s probably a question that would be better posed on a forum so that others can join in the discussion to assist you.

      Cheers,
      Jeremy

  6. Nice work Webster. I found the same issue with that script, but haven’t had the time to re-write it.

    You may also want to report whether or not the trust supports AES encryption by examining the value of the msDS-SupportedEncryptionTypes attribute. If enabled the value is typically 24 (8 = AES 128 bit key length, 16 = AES 256 bit key length)

    If it’s a forest trust, you’ll want to to get the Name Suffix Routing from the msDS-TrustForestTrustInfo attribute, which you can only do by examining the output of the “netdom trust” command.
    http://blogs.msdn.com/b/spatdsg/archive/2008/08/21/kerberos-domain-routing.aspx
    http://xitnotes.wordpress.com/2012/03/29/kerberos-in-an-active-directory-forest-trust-vs-external-trust/

    Cheers,
    Jeremy

Comments are closed