Author Posts

December 20, 2017 at 12:35 am

Hi,
I have this code:

$searcher = New-Object System.DirectoryServices.DirectorySearcher
$searcher.Filter = "(samaccountname=$env:username)"
$searcher.pageSize = 1000
$Userobj = $searcher.FindOne()
# Search for the computer account
$searcher.Filter = "(name=$env:COMPUTERNAME)"
$ComputerObj = $searcher.FindOne()
$computerdivcode = $ComputerObj.properties.dstdivisioncode[0]
# Searchf for the Site OU
$sitecode = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite().Name
$searcher.Filter = "(name=$sitecode)"
$OUObj = $searcher.FindOne()
$Sitename = $OUobj.properties.dstsitename[0]

# Now get the objects

$global:user = [ADSI]$Userobj.path
$global:computer = [ADSI]$ComputerObj.Path
$logondate = (get-date).tostring('yyyy/MM/dd')
$logontime = (get-date).tostring('HH:mm:ss')

# Dont do Server objects for site and division codes
if ($global:computer.OperatingSystem[0] -notlike '*server*') {
    # If its not a server then set the site if different
    # Set the division from the user account if different
    if ($sitecode -ne $global:computer.dstsitecode[0]) {
        $global:computer.Put('dstSiteName',$Sitename)
        $global:computer.Put('dstSiteCode',$sitecode)
        $global:computer.setinfo()
    }
    if ($computerdivcode -ne $global:user.dstdivisioncode[0]) {
        $global:computer.Put('dstDivisionName',$global:user.dstDivisionName[0])
        $global:computer.Put('dstDivisionCode',$global:user.dstDivisionCode[0])
        $global:computer.setinfo()
    }
}

Note the following output:

PS C:\ScriptOut> $computerdivcode -ne $global:user.dstdivisioncode[0]
False

PS C:\ScriptOut> $computerdivcode
IMT

PS C:\ScriptOut> $global:user.dstdivisioncode[0]
IMT

PS C:\ScriptOut> $computerdivcode = $ComputerObj.properties.dstdivisioncode

PS C:\ScriptOut> $computerdivcode -ne $global:user.dstdivisioncode[0]

PS C:\ScriptOut> $computerdivcode -eq $global:user.dstdivisioncode[0]
IMT

PS C:\ScriptOut> $computerdivcode
IMT

PS C:\ScriptOut> $global:user.dstdivisioncode[0]
IMT

What is the difference between '$ComputerObj.properties.dstdivisioncode' and '$ComputerObj.properties.dstdivisioncode[0]'?
If I do an -is [array] on both it says false for both. However, as you can see with the comparison results, one works and one doesnt.
Thanks
David Z

December 20, 2017 at 4:45 am

Firstly, using $global without a really good reason is something which should be approached with caution.

See this write up by the creator of PowerShell.
'blogs.msdn.microsoft.com/powershell/2007/04/14/controlling-the-scope-of-variables'

Additionally, see:
'sapien.com/blog/2013/03/06/first-rule-of-powershell-scoping-rules'

As for you query... simply this...

$ComputerObj.properties.dstdivisioncode = Give me everything that can be returned from the list/array, etc.

$ComputerObj.properties.dstdivisioncode[0] = Give me only the first thing of everything that can be returned from the list/array, etc..

Other simple example:

$AllSystemProcesses = Get-Process
$AllSystemProcesses

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
——- —— —– —– —— — — ———–
600 33 35196 44556 9.27 5728 1 ApplicationFrameHost
149 9 1564 6684 0.03 5052 0 armsvc
345 23 18164 26392 4,755.41 5172 0 audiodg
...

$AllSystemProcesses[0]

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
——- —— —– —– —— — — ———–
600 33 35196 44556 9.27 5728 1 ApplicationFrameHost

$AllSystemProcesses.Count
210

$AllSystemProcesses[0].Count
1

December 20, 2017 at 5:48 am

Thanks – How come -is [array] is false on both?
and how come not even a true or false for the second $computerdivcode -ne $global:user.dstdivisioncode[0]?
Cheers
DZ

December 20, 2017 at 6:46 am

Remember collection arrays are not a sting, so string compare is not really a thing. Unless you convert the array to a string, using say a -join approach, or a loop, though -contains or -match are also options.

Also, you really have to know you are returning an array. If you step through your code, one line at a time and auto output the response, you'll see what is really there.

Just use a parenthetical at each line instead of any Write-* cmdlet to send all to the screen and run only one line at a time.

($searcher = New-Object System.DirectoryServices.DirectorySearcher)

It's just my way of avoiding the Write-Host noise, well, I call it my poor man's debug session.

Also, the attribute you are going after here, 'dstdivisioncode / dstsitename' are not somehithn in my AD environment or ever seen an any AD environment I've ever worked on / supported. So, I have no idea what could be in those. I am going to assume this was an AD attribute extension deployed by you or your organization.

December 20, 2017 at 10:42 am

Just out of curiosity why use System.DirectoryServices.DirectorySearcher, [ADSI] etc instead of the AD cmdlets. if I remember correctly the AD cmdlets were introduced in Server 2008. All Windows Server versions prior to 2008 are out of support and really shouldn't be used

December 20, 2017 at 10:47 am

Richard – This is part of a script that everyone in the organisation runs. Im hardly going to install RSAT on every computer!

December 20, 2017 at 10:50 am

I know arrays are not a string but I keep saying – both results for -is [array] are false. And both results for | gm say they are strings and the output shows they are the same value.
Maybe tell me a command I can run that shows something about them that is understandably different?

December 21, 2017 at 3:07 am

Everything I do says they are the same but the comparison says they arent. What else could be different?
The last comparison is really baffing

btw – the AD attributes are just normal single valued custom attributes we have created

PS C:\ScriptOut> $computerdivcodez = $ComputerObj.properties.dstdivisioncode[0]

PS C:\ScriptOut> $computerdivcodea = $ComputerObj.properties.dstdivisioncode

PS C:\ScriptOut> $computerdivcodez
IMT

PS C:\ScriptOut> $computerdivcodea
IMT

PS C:\ScriptOut> $computerdivcodez -is [array]
False

PS C:\ScriptOut> $computerdivcodea -is [array]
False

PS C:\ScriptOut> $computerdivcodez -ne $global:user.dstdivisioncode[0]
False

PS C:\ScriptOut> $computerdivcodea -ne $global:user.dstdivisioncode[0]

PS C:\ScriptOut> $computerdivcodez | gm


   TypeName: System.String

PS C:\ScriptOut> $computerdivcodea | gm


   TypeName: System.String

PS C:\ScriptOut> $computerdivcodea.count
1

PS C:\ScriptOut> $computerdivcodez.count
1
PS C:\ScriptOut> $computerdivcodez -eq $computerdivcodea
True


December 21, 2017 at 6:11 am

To just use the AD cmdlets, you don't have to install RSAT on other servers.

You can use Implicit Remoting from any machines to any domain controller and proxy the AD cmdlets to any machine for the session as needed. Once the session is closed the cmdlets are no longer available on that machine.

Use PowerShell Active Directory Cmdlets Without Installing Any Software
'blogs.technet.microsoft.com/heyscriptingguy/2011/10/04/use-powershell-active-directory-cmdlets-without-installing-any-software'

The above shows how this is done using Explicit remoting, but you can use New-PSSession to accomplish the same thing, that's the whole Implicit thing. AS detailed in a post on this site here:
'powershell.org/forums/topic/use-get-adobject-without-installing-rsat'

December 21, 2017 at 6:15 am

You don't shoe -is Array in your original post.

Again, the property you are drawing attention to is not something I've ever seen / used in any AD deployment, so I do not know what is in those properties.

You really need to post what (the values – sanitized of course) are in those properties.

December 21, 2017 at 6:24 am

I get your frustration. We've all been that at one point or the other. I know, I've been there more than I could count, but I have always find a workaround. Well, at least I have to date.

As for... 'btw – the AD attributes are just normal single valued custom attributes we have created'

I worked under that assumption, but, yet, without seeing the data that is in the variables / properties, I cannot say what is really happening. As a rule Windows is not a case sensitive thing, except for where it is.

For Example:

"PowerShell Magazine".CompareTo("PowerShell magazine")
1

"PowerShell Magazine".CompareTo("PowerShell Magazine")
0

[string]::Compare("PowerShell Magazine", "PowerShell magazine", $True)
0

[string]::Compare("PowerShell Magazine", "PowerShell magazine", $false)
1

December 21, 2017 at 9:13 pm

I know some bits are case sensitive but the I cannot find anything that is different.
In the sample code above both $computerdivcodea and $computerdivcodez are all uppercase, 3 character length strings with the value of 'IMT'. Yet somehow they are behaving differently when doing the comparison '$computerdivcodea -ne $global:user.dstdivisioncode[0]'.
There must be a reason. I just cant find it.

December 21, 2017 at 10:55 pm

Yes I know you can use invoke-command to execute AD cmdlets. I have actually set up constrained endpoints to do just that for some of my utilities. This particular script happens to be part of a logon script and I figured just using good old dotnet would be quicker.