• Finding Domain Trusts in an Active Directory Forest using Microsoft PowerShell

    April 21, 2014

    Active Directory, 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.

    #http://gallery.technet.microsoft.com/scriptcenter/Enumerate-Domain-Trusts-25ecb802#content
    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
    
    				#http://msdn.microsoft.com/en-us/library/cc220955.aspx
    				#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 }
    				} 
    
    				#http://msdn.microsoft.com/en-us/library/cc223779.aspx
    				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 }
    				} 
    				 
    				#http://msdn.microsoft.com/en-us/library/cc223768.aspx
    				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

    , , ,

    About Carl Webster

    Webster is a Sr. Solutions Architect for Choice Solutions, LLC and specializes in Citrix, Active Directory and Technical Documentation. Webster has been working with Citrix products for many years starting with Multi-User OS/2 in 1990.

    View all posts by Carl Webster

    to “Finding Domain Trusts in an Active Directory Forest using Microsoft PowerShell”

    1. zhiaga Says:

      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

      Reply

      • Carl Webster Says:

        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

        Reply

        • Adriano Ciampoli Says:

          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

          Reply

          • Carl Webster Says:

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

            Webster

            Reply

        • Adriano Ciampoli Says:

          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.

          Reply

          • Carl Webster Says:

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

            Webster

            Reply

    2. manoj Says:

      $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

      Reply

      • Carl Webster Says:

        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

        Reply

    3. Rejone Says:

      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

      Reply

      • Jeremy Saunders Says:

        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

        Reply

    4. Jeremy Saunders Says:

      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

      Reply

    Leave a Reply