The issue is not with the properties or filtering but with the position of the Select
statement, and how it changes the following statements in the pipeline.
The first statement:
Get-Content "MembersMS.txt" | ForEach-Object {Get-ADUser -Identity $_ -Properties name, uht-IdentityManagement-AccountType} | Where-Object {($_['uht-IdentityManagement-AccountType'] -ne "N")}
Can be broken up into 2 statements:
$AllUsers = $Get-Content "MembersMS.txt" | ForEach-Object {Get-ADUser -Identity $_ -Properties name, uht-IdentityManagement-AccountType}
$AllUsers | Where-Object {($_['uht-IdentityManagement-AccountType'] -ne "N")}
Similarly, the second statement:
Get-Content "MembersMS.txt" | ForEach-Object {Get-ADUser -Identity $_ -Properties * | select name, uht-IdentityManagement-AccountType} | Where-Object {($_['uht-IdentityManagement-AccountType'] -ne "N")}
Can be broken up into 2 statements:
$AllUsers2 = Get-Content "MembersMS.txt" | ForEach-Object {Get-ADUser -Identity $_ -Properties * | select name, uht-IdentityManagement-AccountType}
$AllUsers2 | Where-Object {($_['uht-IdentityManagement-AccountType'] -ne "N")}
Both statements generate arrays:
PS C:\> $AllUsers.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS C:\> $AllUsers2.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
But the objects inside the array are different.
PS C:\> $AllUsers[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False ADUser Microsoft.ActiveDirectory.Management.ADAccount
PS C:\> $AllUsers2[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False ADUser System.Object
The first is an array of Type ADAccount
and the second is an array of Sytem.Object
accounts. This is ok if you are iterating over (and filtering over) the items inside the array. But this is different when you are iterating/filtering over properties inside the array.
The way you use Where-Object
tries to invoke the GetEnumerator()
Method, which the Type ADAccount
conveniently has, but System.Object
does not.
PS C:\> $AllUsers | Get-Member
TypeName: Microsoft.ActiveDirectory.Management.ADUser
Name MemberType Definition
---- ---------- ----------
GetEnumerator Method System.Collections.IDictionaryEnumerator GetEnumerator()
Name Property System.String Name {get;}
...
PS C:\> $AllUsers2 | Get-Member
TypeName: Selected.Microsoft.ActiveDirectory.Management.ADUser
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Name NoteProperty string name=HAL9256
Therefore it can't enumerate over the properties and properly perform the Where-Object
filtering.
The better method is to do the "formatting" of Select
at the end of the pipeline:
Get-Content "MembersMS.txt" | ForEach-Object {Get-ADUser -Identity $_ -Properties name, uht-IdentityManagement-AccountType} | Where-Object {($_['uht-IdentityManagement-AccountType'] -ne "N")} } | Select name, uht-IdentityManagement-AccountType