0

Thanks a lot for your time in advance of reading this (it is going to be a long question).

I'm a newbie with a little knowledge of Powershell. I have a situation in which I'm creating an installation wrapper script.

This script will be executed on many user machines, and they may/may not have Active directory access.

But the script should be in such a way that, if the Machine object is part of a specific OU in active directory, then it should choose the configuration file accordingly.

Will the OU information be stored somewhere in the WMI? What is ADSI searcher, will it need any special access or pre-requisites to work properly?

I have googled and got the below script using ADSI and it seems to be working on my virtual machine, but not on a few other virtual machines (for reasons unknown to me).

$ComputerName = $env:ComputerName

$ADSISearcher = New-Object System.DirectoryServices.DirectorySearcher

$ADSISearcher.Filter = '(&(name=' + $ComputerName + ')(objectClass=computer))'

$ADSISearcher.SearchScope = 'Subtree'

$Computer = $ADSISearcher.FindAll()

$OU = $($Computer.Properties.Item('distinguishedName'))

I've tried running the script on various other user machines (mixed AD access levels), and $OU = $($Computer.Properties.Item('distinguishedName')) is giving error.

You cannot call a method on a null-valued expression. At line:1 char:42 + $OU = $($Computer.Properties.Item < <<< ('distinguishedName')) + CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull

But $computer is not a null value. It has the result below (I have modified the LDAP info..)

 Path                                                        Properties
----                                                        ----------
LDAP://CN=,OU=< ........>,OU=V< ...>,OU=N... {primarygroupid, iscriticalsystemobject, msds-supportede...

Now the question is: Am I in the right direction, will ADSI searcher query this information from locally cached information?

If yes, can you help me fix this issue? If I'm all wrong, please correct me. I've been sitting with this for days now and help would be much appreciated.

Palle Due
  • 5,929
  • 4
  • 17
  • 32
karockiad
  • 11
  • 1
  • 5
  • *"if the Machine object is part of a specific OU in active directory then, choose the configuration file accordingly"* - I think a Group Policy would be a better fit. You can set a group policy on each OU that runs a different logon script. – Gabriel Luci Nov 15 '19 at 13:53
  • yes.. but the configuration file is passed to a installer which is pretty huge. so my clients are lil reluctant to it. – karockiad Nov 15 '19 at 13:59
  • That error is saying that `$Computer.Properties.Item` is `null`. It's not `null` for me when I try it. But you can access the same attribute with `$Computer.Properties["distinguishedName"]`... maybe that works? – Gabriel Luci Nov 15 '19 at 14:01
  • Maybe better use `$ADSISearcher.FindOne()` or loop through the results returned by `$ADSISearcher.FindAll()` – Theo Nov 15 '19 at 14:26

3 Answers3

0

Is there a chance the machines you are testing on are not joined to the domain?

Regardless, while I do recommend you choose a different solution other than the path you are going down, does this code work any better for you? Also note that you mentioned that the DCs may or may not be reachable. If that's the case this query will fail from the local machine (and retrieving the group policy from sysvol would too).

$LDAPDN = ([adsisearcher]"(&(name=$env:computername)(objectClass=computer))").findall().path

If ($LDAPDN) {
    $OU = $LDAPDN.Replace("LDAP://CN=$env:computername,","")
}

Else {
    Write-Warning "Unable to find $env:computername in AD or the adsi search failed"
}
  • Thanks alot for your valuable time and code. and i did try your code, got the warning message you presented. But I'm sure the machine is in Vcenter and there would not be connection issue. But as you suggested, i'm starting to think for other possible solutions. Thanks again for your help here on this. – karockiad Nov 15 '19 at 16:05
0

I was able to reproduce this if you run it with a user account that is not on the same domain as the computer. It tries to search the domain of the user and then doesn't find the computer. So you need to specifically tell it to connect to the domain of the computer, which you can find using:

$ComputerDomain = (Get-WmiObject Win32_ComputerSystem).Domain

There are also some short forms you can use, like [adsi] and [adsisearcher] to make the code more succinct.

The DirectorySearcher (aka [adsisearcher]) used here is .NET's DirectorySearcher, which is part of the .NET Framework and will be installed by default in Windows. So you don't need to worry about it not being available. But the computer does need to be connected to the network for this to work.

$ComputerName = $env:ComputerName
$ComputerDomain = (Get-WmiObject Win32_ComputerSystem).Domain

$ADSISearcher = [adsisearcher]"(&(name=$ComputerName)(objectClass=computer))"
$ADSISearcher.PropertiesToLoad.Add("distinguishedName")
$ADSISearcher.SearchRoot = [adsi]"LDAP://$ComputerDomain"

$Computer = $ADSISearcher.FindOne()

$DN = $Computer.Properties["distinguishedName"][0]
$OU = $DN.Substring($DN.IndexOf("OU="))

Note that the SearchRoot is set to the domain of the computer.

The SearchScope is Subtree by default, so you don't need to set that.

It's a good idea to use PropertiesToLoad to tell it which attributes you want it to return. Otherwise, it will return every attribute with a value. It probably won't make much of a difference here, but it can in other cases.

I also used FindOne(), which returns a single value, instead of FindAll(), which returns an array. Really, there should only be one result anyway, which is why you can treat the array as if it wasn't.

Note that the distinguishedName attribute is the full path to the object, not just the OU. So if you want the OU, you need to extract that portion of the distinguishedName, which is what I did here. (all attributes are presented as arrays, which is why you need [0] there)

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • Thanks alot for helping me understand. I did try your script on one of the failed machines and unfortunate that i failed for the same reason – karockiad Nov 15 '19 at 16:01
  • $DN = $Computer.Properties["distinguishedName"][0] Cannot index into a null array. At line:1 char:49 + $DN = $Computer.Properties["distinguishedName"][ <<<< 0] + CategoryInfo : InvalidOperation: (0:Int32) [], RuntimeException + FullyQualifiedErrorId : NullArray – karockiad Nov 15 '19 at 16:07
  • Yes this is the error. Find one is successfull. and even $computer has search values.PS C:\Users\adoss> $computer Path Properties ---- ---------- LDAP:///CN=,OU=... {distinguishedname, adspath} – karockiad Nov 15 '19 at 17:08
0

Thanks alot for helping me today! I definitely learned lot of info. I did take a U turn and i was looking through another route(definitely a very slow Query compared to ADSI). But is working on cross domain Scenarios. Ref:How do I use WMI to get the current OU of a computer and list all other computers in that OU?

$ComputerName = $env:ComputerName;
$Computer = Get-WmiObject -Namespace 'root\directory\ldap' -Query "Select DS_distinguishedName from DS_computer where DS_cn = '$ComputerName'";
$OU = $Computer.DS_distinguishedName.Substring($Computer.DS_distinguishedName.IndexOf('OU='));

And it did the magic and i got the desired out from all my test VM's

karockiad
  • 11
  • 1
  • 5