Search code examples
powershellexceptioninvoke-command

Exception calling "FindOne" with "0" argument(s): "The specified directory service attribute or value does not exist


I am attempting to validate the OU of a remote computer in an Invoke session. The code works outside of the script block, but tanks when run within the script block on the remote machine... o_O

This works:

$rootDse = New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")
$Domain = $rootDse.DefaultNamingContext 
$root = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$Domain") 
$ComputerName = $env:COMPUTERNAME 
$searcher = New-Object System.DirectoryServices.DirectorySearcher($root) 
$searcher.Filter = "(&(objectClass=computer)(name=$ComputerName))" 
[System.DirectoryServices.SearchResult]$result = $searcher.FindOne() 
$dn = $result.Properties["distinguishedName"] 
$ouResult = $dn.Substring($ComputerName.Length + 4) 

$ouResult 

And this does not (returns error in title)

#$VMname = Read-Host -Prompt "What server do you want to validate? "
$VMname = "ObsfucatedHostNameHere"
#$Domain = Read-Host -Prompt "What domain is it in (Please specify complete domain)? "
$Domain = "ObsfucatedDomainNameHere.com"

Invoke-Command -ComputerName "$VMname.$Domain" -Credential $Cred -ScriptBlock { param($VMname)

$rootDse = New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")
$Domain = $rootDse.DefaultNamingContext 
$root = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$Domain") 
$ComputerName = $env:COMPUTERNAME 
$searcher = New-Object System.DirectoryServices.DirectorySearcher($root) 
$searcher.Filter = "(&(objectClass=computer)(name=$ComputerName))" 
[System.DirectoryServices.SearchResult]$result = $searcher.FindOne() 
$dn = $result.Properties["distinguishedName"] 
$ouResult = $dn.Substring($ComputerName.Length + 4) 

$ouResult 
}

Solution

  • After getting a chance to double check this, this is a case of the double hop problem. When you use Invoke-Command you aren't able to connect to yet another server using the credentials in the Invoke-Command. But there are some workarounds to this. The best being Resourced-Base constrained Delegation, which Ashley McGlone has several articles on along with the other workarounds, but where that doesn't work you can just bundle up the credentials that you want to use and pass them inside the scriptblock.

    Here an example of this applied to your code:

    #$VMname = Read-Host -Prompt "What server do you want to validate? "
    $VMname = "ObsfucatedHostNameHere"
    #$Domain = Read-Host -Prompt "What domain is it in (Please specify complete domain)? "
    $Domain = "ObsfucatedDomainNameHere.com"
    
    $Cred = (Get-Credential)
    $Username = $Cred.UserName
    $Password = $Cred.GetNetworkCredential().Password
    
    Invoke-Command -ComputerName "$VMname.$Domain" -Credential $Cred -ScriptBlock { 
        $rootDse = New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE",$using:Username,$using:Password)
        $Domain = $rootDse.DefaultNamingContext 
        $root = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$Domain",$using:Username,$using:Password) 
        $ComputerName = $env:COMPUTERNAME 
        $searcher = New-Object System.DirectoryServices.DirectorySearcher($root) 
        $searcher.Filter = "(&(objectClass=computer)(name=$ComputerName))" 
        [System.DirectoryServices.SearchResult]$result = $searcher.FindOne() 
        $dn = $result.Properties["distinguishedName"] 
        $dn.Substring($ComputerName.Length + 4) 
    }
    

    I maybe a couple other clean up changes too. You weren't using VMname after you paramed it so I dropped out param($VMname). (Note that if you are using PowerShell 2, you'll need to use the param rather than scoping with $using. And I also dropped out $ouResult as you could just output without the extra step of defining a extra variable.