2

How can I get the Fully Qualified Domain Name (FQDN) for a user on a different, trusted domain?

Normally, I would ask said user to take any one of the approaches outlined here (e.g. whoami /fqdn or echo %userDNSdomain%), but if this approach isn't available for whatever reason (e.g. the account is a proxy account that I am unable to log in with interactively, the company I'm working for was acquired and the new owners aren't as forthcoming, etc.), is there a way I can get this different user account's FQDN?

Alternatively, taking the approach of "emulating" the FQDN being returned by my user credentials is also prone to error. Take for example the output of running whoami /fqdn as my user:

C:\Users\john.eisbrener>whoami /fqdn
CN=John M. Eisbrener,OU=Standard Users,OU=Resources,DC=CONTOSO,DC=COM

I could conceptually adjust the CONTOSO Domain Component to the other, trusted domain, with the expectation that it follows the same structure, but that would be short sighted as not all domains follow the same naming convention. I've seen too many trusted domains using .org or including additional domain prefix or suffixes within their LDAP root path.

The main driver to all of this is that I need to pass the proper Domain Components to the following PowerShell queries which I rely on when trying to find what user groups and user names may need to be added to certain security groups, file paths, etc.

## List Groups for a Username
$domainName = 'CONTOSO'
$domainSuffix = 'COM'
$username = 'john.eisbrener'
(New-Object System.DirectoryServices.DirectorySearcher((New-Object System.DirectoryServices.DirectoryEntry("LDAP://dc=$($domainName),dc=$($domainSuffix)")), "(&(objectCategory=User)(samAccountName=$($username)))")).FindOne().GetDirectoryEntry().memberOf | % { (New-Object System.DirectoryServices.DirectoryEntry("LDAP://"+$_)) } | Sort-Object sAMAccountName | SELECT @{name="Group Name";expression={$_.Name}},@{name="Group sAMAccountName";expression={$_.sAMAccountName}}


## List Members in a Group
$domainName = 'CORP'
$domainSuffix = 'ORG'
$groupname = 'RemoteUsers'
(New-Object System.DirectoryServices.DirectoryEntry((New-Object System.DirectoryServices.DirectorySearcher((New-Object System.DirectoryServices.DirectoryEntry("LDAP://dc=$($domainname),dc=$($domainSuffix)")), "(&(objectCategory=Group)(name=$($groupname)))")).FindOne().GetDirectoryEntry().Path)).member | % { (New-Object System.DirectoryServices.DirectoryEntry("LDAP://"+$_)) } | Sort-Object sAMAccountName | SELECT @{name="User Name";expression={$_.Name}},@{name="User sAMAccountName";expression={$_.sAMAccountName}}

Why can't I install any other components or modules? The computer I'm using is pretty vanilla and doesn't have any extra PowerShell modules or mmc snapins (e.f. dsa.msc) available because my user account doesn't have sufficient privileges to install software.

My current approach to get the FQDN of this other user's domain is to setup a Windows Scheduled Task running as said user, saving the output of the aforementioned whoami /fqdn or echo %userDNSdomain% commands to a text file, but this seems a bit kludgy and I was hoping for a simple one-liner that I could run from the command prompt or a PowerShell prompt. Any suggestions would be appreciated.

Final note, my apologies if my terminology is incorrect or leading to confusion. I'm open to any edits to this from someone that understands what I'm asking.

John Eisbrener
  • 642
  • 8
  • 17
  • 1
    ADSI and the Active Directory module from RSAT are not the same. ADSI will be the method you would likely want to use. – BenH Jun 13 '17 at 16:12
  • @BenH I'm unable to use either of these tools in this scenario as my account does not have sufficient permissions to install software onto the machine I have access to. – John Eisbrener Jun 13 '17 at 16:15
  • then you need to use what's natively available in the shell via the [adsisearcher] type accelerator or the System.DirectoryServices.DirectorySearcher class. – thepip3r Jun 13 '17 at 16:17
  • and what exactly is the FQDN of the user? Do you mean distinguishedname? – thepip3r Jun 13 '17 at 16:20
  • 1
    ADSI is not installed. It's part of .Net. @thepip3r `whoami /fqdn` does return the Distinguished Name. – BenH Jun 13 '17 at 16:25
  • 1
    for the current user, and AD doens't call it a "FQDN", it's a distinguishedname. it might happen to be fully qualified since it includes the authority to which it belongs: e.g. dc=contoso,dc=com but just trying to make sure it's the DN he's looking for. – thepip3r Jun 13 '17 at 16:27
  • @BenH I've updated the question, hopefully providing more clarity on my circumstances. – John Eisbrener Jun 13 '17 at 16:35
  • @thepip3r Hopefully the edits I made to the question make it a bit clearer. Sorry about the mixing up the terminology! – John Eisbrener Jun 13 '17 at 16:45
  • Can you count on the user account having a profile on computer? Or the domain being in the same forest? – BenH Jun 13 '17 at 17:04
  • @BenH I wouldn't count on there being a profile on a computer for the user as it may be setup in a similar fashion to a service account (e.g. _Logon as a Service/Logon as a Batch File_). The domain should be in the same forest though, but I'm interested if it's possible when this isn't the case. – John Eisbrener Jun 13 '17 at 17:13
  • Wait so all you're concerned about is the FQDN of the acquiring company's domain? Is there a trust that's set up? – thepip3r Jun 13 '17 at 18:28
  • If so, this should have the information you need: [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().GetAllTrustRelationships() – thepip3r Jun 13 '17 at 18:34
  • @thepip3r Looks like I've got one forest that isn't trusted because it's not showing up as a result of this call: `[System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().GetAllTrustRelationships()`. This is pretty close to what I'm looking for though! – John Eisbrener Jun 13 '17 at 18:57
  • Looks like `[System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().RootDomain.GetAllTrustRelationships()` gets me the outstanding domain I was missing from the set returned by the prior command. – John Eisbrener Jun 13 '17 at 19:15

2 Answers2

3

This should just use .Net classes, so it should work just fine for you.

Function Get-TrustedDomainUser{
Param([String]$Alias)
    $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
    $AllTrusts=$Forest.GetAllTrustRelationships()
    $Filter = "(&(sAMAccountName=$Alias)(objectClass=user))"
    $Searcher = [adsisearcher]$Filter
    ForEach($Domain in $AllTrusts.TargetName){
        Write-Host "Trying to find user in $Domain"
        $LDAP = 'DC=' + ($Domain.split('.') -join ',DC=')
        $Searcher.SearchRoot = "LDAP://$LDAP"
        $ErrorActionPreference = 'Stop'
        try{
            $DomUser = $Searcher.FindAll()

        }Catch{
            Write-Host "User not found in $Domain"
        }
        If(!([string]::IsNullOrEmpty($DomUser.Path))){Break}
    }
    $DomUser
}

Get-TrustedDomainUser -Alias 'SomeUser'

That will get all trusted domains, and then try and find the user in each domain until it finds the user, at which point it returns the user. If you don't like the on screen spam just comment out the Write-Host lines.

TheMadTechnician
  • 34,906
  • 3
  • 42
  • 56
  • If I adjust `$AllTrusts=$Forest.GetAllTrustRelationships()` to `$rootTrusts = $Forest.RootDomain.GetAllTrustRelationships() $targetTrusts = $Forest.GetAllTrustRelationships() $AllTrusts = $rootTrusts + $targetTrusts`, this includes all domains *EXCEPT* the source domain. Any quick or _better_ way to include these additional domains? – John Eisbrener Jun 13 '17 at 19:51
1
$s = [adsisearcher]'(&(objectcategory=user)(samaccountname=somename))'
$s.SearchRoot = [adsi]'LDAP://DomainFqdnOfTargetUserDomain'
$r = $s.FindOne()

$r.properties
  • Use the adsisearcher type accelerator constructor to specify the ldap search we want to run
  • Use properties on the underlying DirectorySearcher object to specify we don't want use the default user's domain but the domain we specify (must be an ADSI reference).
  • distinguishedname is a default AD attribute returned. If it wasn't or you needed to add one that wasn't default, you can use: $s.PropertiesToLoad.Add('propertyname')
  • Execute the .FindOne() method to return a singular item. If you are doing a generic search, e.g. (samaccountname=tom*), you can switch this to .FindAll().
  • Emit the results to the screen so you can see the object properties that are returned.
  • Understand that for some crazy reason, these calls return every property as an array (even if it's defined as single-value in the AD schema) so in most cases, while referencing the property will work in single-item arrays, it would be more proper to reference it by index as well: e.g. $r.properties.samaccountname[0]
thepip3r
  • 2,855
  • 6
  • 32
  • 38
  • I'm trying to figure out `'LDAP://DomainFqdnOfTargetUserDomain'` in this scenario. Sorry if my question is leading to more confusion than anything else... – John Eisbrener Jun 13 '17 at 16:37
  • 1
    what is the FQDN of the target user's domain? if your AD domain is sears.com and the target domain is roebuck.com, then when you run the script from your computer, you need to replace 'DomainFqdnOfTargetUserDomain' with roebuck.com. Reason being, this property has a default property and it defaults to the USER CONTEXT of the principal running the script (ie your user account's domain). In order to search another domain, you must use the SearchRoot property to have it target another domain. – thepip3r Jun 13 '17 at 16:45
  • The scenario here is that no one knows the FQDN of the target user's domain, so that's exactly what I'm trying to figure out. – John Eisbrener Jun 13 '17 at 16:48