Different Results with Powershel v2 and v3

Hope someone can help me determine why there is a difference in my data between v2 and v3 of Powershell. I do my development on my laptop which has version 3 installed, but the script is executed on a server which has version 2 installed.

#create directory searcher object and set it's porperties
  $searcher = New-Object DirectoryServices.DirectorySearcher
  # (!userAccountControl:1.2.840.113556.1.4.803:=2) - Filters out disabled accounts
  $searcher.Filter = '(&(objectCategory=person)(objectClass=user)(!samaccountname=ITS-*)(!userAccountControl:1.2.840.113556.1.4.803:=2))'
  $searcher.PageSize = 5
  $searcher.SearchRoot = "LDAP://OU=District Offices,DC=myDomain,DC=com"
  
  #load only the following properties
  $params = @("samaccountname","sn","givenname","mail","physicaldeliveryofficename","department","title","manager","distinguishedname")
  
  foreach($param in $params)
  {
    $searcher.PropertiesToLoad.Add($param) | Out-Null
  }

try
  {
    $found = $searcher.FindAll()
	$found | ForEach-Object {
	  if (($_.Properties["distinguishedname"] -notlike "*,OU=Generic User Accounts*") -and ($_.Properties["title"] -notlike "*Consultant*") `
	    -and ($_.Properties["title"] -notlike "*Commissioner*") -and ($_.Properties["title"] -notlike "*Security Guard*") `
		-and ($_.Properties["title"] -notlike "*OSC*") -and ($_.Properties["title"] -notlike "*DCC*Temp*") -and ($_.Properties["samaccountname"] -ne "tbjohn") `
		-and (($_.Properties["mail"] -ne "")))
	  {
	    $filtered += $_
	  }
	}
  }

Running this script on my machine produces the data that the user is looking for. When I run it on the server, there are users in the data file that should not be. In the filter statement if I change

-and (($_.Properties["mail"] -ne "")))

#TO BE

-and (($_.Properties["mail"] -ne $null)))
Then those users are removed, but then other users are included and I haven't figured out why yet. Why would there be a difference, with the above script? I would think that should work in any version but obviously that is not true.
January 26th, 2015 5:34pm

Try usinga simple and straighforward method. 

$searcher=[adsisearcher]'(&(objectCategory=person)(objectClass=user)(mail=*)(!samaccountname=ITS-*)(!userAccountControl:1.2.840.113556.1.4.803:=2))'
$searcher.PageSize=500
$searcher.SearchRoot='LDAP://OU=District Offices,DC=myDomain,DC=com'
$props=@("samaccountname","sn","givenname","mail","physicaldeliveryofficename","department","title","manager","distinguishedname")
$searcher.FindAll() | 
    Where-Object{
	    $_.Properties['distinguishedname'][0] -notmatch ',OU=Generic User Accounts'
        -and $_.Properties["title"][0] -notmatch 'Consultant|Commissioner|Security Guard|OSC|DCC.*Temp'
        -and $_.Properties["samaccountname"][0] -ne 'tbjohn'
    }

Notice that this uses much less code and is easier to read.  Put the mail filter in the search filter. (mail=*) - says only include objects with a mail address that is not blank or null.   This executes ont eh AD server and not on the client so Powerhellll versiosn will not behave differently.

Free Windows Admin Tool Kit Click here and download it now
January 26th, 2015 6:03pm

Thanks jrv, I like the consolidation of the code, does make it easier to read, and adding the mail to the searcher object. That did solve my issue for the mail part of things, although I had to modify your code, because I kept receiving cannot index into a null array, when I tried it your way. I changed it to be

$found = $searcher.FindAll()

    $found | ForEach-Object {
	  if ($_.Properties["distinguishedname"] -notmatch ",OU=Generic User Accounts" `
	  -and $_.Properties["title"] -notmatch "Consultant|Commissioner|Security Guard|OCS|DCC.*Temp" `
	  -and $_.Properties["samaccountname"] -ne "tbjohn")
	  {
	    $filtered += $_
	  }
	}
That is working except for one issue when running it on Powershell version 3, the data looks good. When I run it on version 2.0, I have three users in the data file that should not be there. The reason they are coming up is because they should have Consultant in their title field, but they don't which is why I know they are not being filtered, but why would they be filtered in version 3.0?

January 26th, 2015 6:33pm

You cannot match something that doesn't exist.  You say that the DON'T have "consultant" in the title. I\f that is true then they will show up unless thaey are excluded for one of the other reasons.

The result makes not difference onV2 or V3.  The query is simple. 

Free Windows Admin Tool Kit Click here and download it now
January 26th, 2015 6:51pm

You cannot match something that doesn't exist.  You say that the DON'T have "consultant" in the title. I\f that is true then they will show up unless thaey are excluded for one of the other reasons.

The result makes not difference onV2 or V3.  The query is simple. 

January 26th, 2015 7:01pm

Don't use PowerGui.  Just use plain Powersshell.

Just use my copy of the code and nothing else.

Check all of these criteria on the missing accounts.

Your IF code is wrong which is why I rewrote it.

$searcher.PageSize=500
$searcher.SearchRoot='LDAP://OU=District Offices,DC=myDomain,DC=com'
$props=@("samaccountname","sn","givenname","mail","physicaldeliveryofficename","department","title","manager","distinguishedname")
$searcher.FindAll() | 
    Where-Object{
	    $_.Properties['distinguishedname'][0] -notmatch 'Generic User Accounts'
        -and $_.Properties["title"][0] -notmatch 'Consultant|Commissioner|Security Guard|OSC|DCC.*Temp'
        -and $_.Properties["samaccountname"][0] -ne 'tbjohn'
    }

Reove one filter component at a time until you see the missing accounts. I gurantee you that that is sthe reason.  YOu IF logic does not work the way you think it does.

Free Windows Admin Tool Kit Click here and download it now
January 26th, 2015 7:08pm

OK thank you for your help. I ran the above code in a console window saving the results to a variable, search that variable and the user is there, did the same thing in PowerGUI and the user is there, so it was something with my if statement.
January 26th, 2015 7:22pm

I always simpllify commplex logix as much as possible.  Once it is very readable then it is easier to see logic issues and it is easier to cut and papste to test incrementally.

Look carefull at you if and you will see more than one subtle issue.

Free Windows Admin Tool Kit Click here and download it now
January 26th, 2015 8:10pm

jrv, with your modifications, things look to be going great, but again I am having an issue between version 3 and version 2 of powershell

I have the following code in a file

$searcher = New-Object DirectoryServices.DirectorySearcher
$searcher.Filter = '(&(objectCategory=person)(objectClass=user)(mail=*)(!samaccountname=ITS-*)(!userAccountControl:1.2.840.113556.1.4.803:=2))'
$searcher.PageSize = 5
$searcher.SearchRoot = "LDAP://OU=District Offices,DC=MyDomain,DC=com"
  
#load only the following properties
$params = @("samaccountname","sn","givenname","mail","physicaldeliveryofficename","department","title","manager","distinguishedname")

foreach($param in $params)
{
  $searcher.PropertiesToLoad.Add($param) | Out-Null
}
  
# Filtered results to exclude certain OU's
$filtered = @()

try
{
  $filtered += $searcher.FindAll() | Where {
    $_.Properties["distinguishedname"][0] -notmatch ",OU=Generic User Accounts" `
    -and $_.Properties["title"][0] -notmatch "Consultant|Commissioner|Security Guard|OCS|DCC.*Temp" `
    -and $_.Properties["samaccountname"][0] -ne "tbjohn"
  }

  $filtered.Count
}
catch
{
  Write-Host "Error occured $_"
  exit
}

I then did two different tests. In a command window I run the following

C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe -Version 3.0 -ExecutionPolicy RemoteSigned -File F:\PS_Scripts\ADTest.ps1

The results here return the count of 2485, yet if I force it to use version two with the following command

C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe -Version 2.0 -ExecutionPolicy RemoteSigned -File F:\PS_Scripts\ADTest.ps1

The results returned is an error stating "Cannot index into a null array", is there a difference in the DirectorySearcher object in version 2.0 compared to versio

January 28th, 2015 4:59pm

I believe I have corrected the issue, it seems to have been your Where-Object code, as you have

$searcher.FindAll() | Where {
    $_.Properties["distinguishedname"][0] -notmatch ",OU=Generic User Accounts" `
    -and $_.Properties["title"][0] -notmatch "Consultant|Commissioner|Security Guard|OCS|DCC.*Temp" `
    -and $_.Properties["samaccountname"][0] -ne "tbjohn"

After $searcher.FindAll() executes, it in fact creates a collection. You should just have to pipe the results over to Where-Object, and it loops through the collection one object at a time, but reading the code says to me that you are passing an array over to Where-Object and you just want to look at the first item "[0]"

If I remove the "[0]" from the code after the Where-Object, everything seems to be running as it should now.

Free Windows Admin Tool Kit Click here and download it now
January 28th, 2015 6:03pm

I believe I have corrected the issue, it seems to have been your Where-Object code, as you have

$searcher.FindAll() | Where {
    $_.Properties["distinguishedname"][0] -notmatch ",OU=Generic User Accounts" `
    -and $_.Properties["title"][0] -notmatch "Consultant|Commissioner|Security Guard|OCS|DCC.*Temp" `
    -and $_.Properties["samaccountname"][0] -ne "tbjohn"

After $searcher.FindAll() executes, it in fact creates a collection. You should just have to pipe the results over to Where-Object, and it loops through the collection one object at a time, but reading the code says to me that you are passing an array over to Where-Object and you just want to look at the first item "[0]"

If I remove the "[0]" from the code after the Where-Object, everything seems to be running as it shoul

January 28th, 2015 6:34pm

$searcher.FindAll() is returning a collection, and if I loop through that collection, an object has a Path and a Properties, which Path is the LDAP path of the object and properties is a collection of the properties returned, if I do a GetType() on the properties it is of type ResultPropertyCollection which is a dictionary based collection.

So by doing $_.Properties["samaccountname"] I am directly accessing that particular property within the properties collection, so I do not need to do $_.Properties["samaccountname"][0], but for some reason $_.Properties["samaccountname"][0] works without any issues in version 3.0, but will produce an error in versi

Free Windows Admin Tool Kit Click here and download it now
January 28th, 2015 6:42pm

The PSTeam already told us: if you have an old script, run it in old PowerShell.

I'd like to add to this: ... and develop this script in the old PowerShell, because language features vary.

Test this in PowerShell 3 or above:

$a=123

$a # prints 123

$a.count # prints 1

$a[0] # prints 123

$a[-1] # prints 123

-

Test this in PowerShell 2:

$a=123

$a # prints 123

$a.count # prints nothing - it is null

$a[0] # prints error msg

$a[-1] # prints error msg

Moreover, what is v3? What is v2? If v3 is already nothing, imagine v2...

Open you PowerShell application and run this:

        help about_win*

Do you see any reference to v3 or v2?

Try to find any on technet.com...

Ok - I will byte.

Is there some reason to expect anything different or are you just wasting my time?

Your move.

January 29th, 2015 12:12am

Hope someone can help me determine why there is a difference in my data between v2 and v3 of Powershell. I do my development on my laptop which has version 3 installed, but the script is executed on a server which has version 2 installed.

#create directory searcher object and set it's porperties
  $searcher = New-Object DirectoryServices.DirectorySearcher
  # (!userAccountControl:1.2.840.113556.1.4.803:=2) - Filters out disabled accounts
  $searcher.Filter = '(&(objectCategory=person)(objectClass=user)(!samaccountname=ITS-*)(!userAccountControl:1.2.840.113556.1.4.803:=2))'
  $searcher.PageSize = 5
  $searcher.SearchRoot = "LDAP://OU=District Offices,DC=myDomain,DC=com"
  
  #load only the following properties
  $params = @("samaccountname","sn","givenname","mail","physicaldeliveryofficename","department","title","manager","distinguishedname")
  
  foreach($param in $params)
  {
    $searcher.PropertiesToLoad.Add($param) | Out-Null
  }

try
  {
    $found = $searcher.FindAll()
	$found | ForEach-Object {
	  if (($_.Properties["distinguishedname"] -notlike "*,OU=Generic User Accounts*") -and ($_.Properties["title"] -notlike "*Consultant*") `
	    -and ($_.Properties["title"] -notlike "*Commissioner*") -and ($_.Properties["title"] -notlike "*Security Guard*") `
		-and ($_.Properties["title"] -notlike "*OSC*") -and ($_.Properties["title"] -notlike "*DCC*Temp*") -and ($_.Properties["samaccountname"] -ne "tbjohn") `
		-and (($_.Properties["mail"] -ne "")))
	  {
	    $filtered += $_
	  }
	}
  }

Running this script on my machine produces the data that the user is looking for. When I run it on the server, there are users in the data file that should not be. In the filter statement if I change

-and (($_.Properties["mail"] -ne "")))

#TO BE

-and (($_.Properties["mail"] -ne $null)))
Then those users are removed, but then other users are included and I haven't figured out why yet. Why would there be a difference, with the above script? I would think that should work in any version but obviously that is not true.
Free Windows Admin Tool Kit Click here and download it now
May 8th, 2015 8:13pm

The PSTeam already told us: if you have an old script, run it in old PowerShell.

I'd like to add to this: ... and develop this script in the old PowerShell, because language features vary.

Test this in PowerShell 3 or above:

$a=123

$a # prints 123

$a.count # prints 1

$a[0] # prints 123

$a[-1] # prints 123

-

Test this in PowerShell 2:

$a=123

$a # prints 123

$a.count # prints nothing - it is null

$a[0] # prints error msg

$a[-1] # prints error msg

Moreover, what is v3? What is v2? If v3 is already nothing, imagine v2...

Open you PowerShell application and run this:

        help about_win*

Do you see any reference to v3 or v2?

Try to find any on technet.com...

Ok - I will byte.

Is there some reason to expect anything different or are you just wasting my time?

Your move.

May 8th, 2015 8:19pm

All of the attributes you're retrieving are single valued attributes, so they will not be presented in a collection.

So why are you trying to retrieve an element from it as if it was a collection?

Have you tried doing something like to see that type of object you're dealing with?

$_.Properties["title"].GetType()

As pointed out PowerShell v3 is a lot more permissive in that sense and will understand [0] even if the object is not a collection that you can iterate through, but PowerShell v2 does not understand that.

Free Windows Admin Tool Kit Click here and download it now
May 9th, 2015 3:32am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics