notcontains not working for User objects pulled from AD Groups

前端 未结 1 1325
长情又很酷
长情又很酷 2020-12-11 12:31

When using notcontains to check for an object in array it is saying True when it should be false. This is the code that I have.

$SPSecUsers = Get-ADGroupMemb         


        
相关标签:
1条回答
  • 2020-12-11 13:25

    tl;dr

    Don't store the AD user objects themselves in your arrays, use their .SamAccountName property value instead (generally, pick a property that uniquely identifies the objects):

    # ...
    $SPSecUKUsers += $SPSecUser.SamAccountName
    # ...
    if ($SPSecUKUsers -notcontains $UKUser.SamAccountName) { # ...
    

    See the next section, if you want to know why storing the objects themselves doesn't work.

    Alternatively - for faster lookups - use a hashtable:

    $SPSecUKUsers = @{} # initialize hashtabe
    # ...
    # Create an entry for the object at hand, using its .SamAccountName
    # as the entry *key*; you can store the object itself as the entry *value*.
    # If all you need are lookups by SAM account name, however, you can just
    # use a fixed value such as $true.
    $SPSecUKUsers[$SPSecUser.SamAccountName] = $SPSecUser
    # ...
    if ($SPSecUKUsers.ContainsKey($UKUser.SamAccountName)) { # ...
    

    About PowerShell's containment (collection-membership) operators:

    As Olaf and Lee_Daily imply in the comments, PowerShell's containment operators (-contains / notcontains and -in / -notin) check the comparison operand for reference equality (identity) with the elements of the input array, if those elements are instance of .NET reference types, with the exception of [string] instances, which are treated like value types, which are tested with
    value equality (equivalence) - see Equality Comparisons.

    You can think of the set operators as an implicit loop over the input array's elements, testing each against the comparison operand with the -eq operator (or, if you use the case-sensitive variant such as -ccontains, with -ceq), using reference equality or value equality, depending on the element type.

    Important: Due to PowerShell's flexible automatic type-conversion rules, which operand is the LHS in an -eq operation matters. Using -in or -contains means that the LHS of the implied -eq operation is the array element being tested against, as the following examples show:

     # `, 10` creates a single-element array
     '0xa' -in , 10       # equivalent of: 10 -eq '0xa' => $true
     , 10 -contains '0xa' # ditto
    
     # 
     10 -in , '0xa'        # equivalent of: '0xa' -eq 10 => $false
     , '0xa' -contains 10  # ditto
    

    In the first 2 operations, the LHS being a number ([int]) forces the string RHS ([string]) to a number ([int]) too, and the hex "number string" '0xa' converts to an [int] with decimal value 10 too.

    In the latter 2, the LHS being a string ([string]) forces the number 10 to become a string too, and '10' obviously doesn't match '0xa'.

    Value equality (equivalence) means that two objects have the same content, even though, with distinct value-type objects, that content is by definition stored in different memory locations.

    Numeric types such as [int] and [double] are value types, for instance. As a rough rule of thumb, objects that have properties are often reference types. You can check a given type's .IsValueType property; e.g., [int].IsValueType returns $true.

    Reference equality (identity) means that two values are only considered equal if they point to the very same object in memory, i.e., the same instance of a reference type.

    Otherwise, they're considered not equal, even if they represent what is conceptually the same entity, which is what happened in your case: two separate calls to Get-ADUser return distinct objects, even if you (in part) ask for the same users in both cases (Get-ADUser returns instance of type Microsoft.ActiveDirectory.Management.ADUser, which is a reference type).

    Examples:

    # Create a custom object...
    $customObject = [pscustomobject] @{ one = 1; two = 2 }
    # which is an instance of a reference type.
    $customObject.GetType().IsValueType # -> $false
    
    # Create an array comprising a value-type instance (1)
    # and a reference-type instance (the custom object).
    $arr = 1, $customObject 
    
    # Look for the value-type instance.
    $objectToLookFor = 1
    
    $arr -contains $objectToLookFor # value equality -> $true
    
    # Create another custom object, with the same properties as above.
    $objectToLookFor = [pscustomobject] @{ one = 1; two = 2 }
    
    # This lookup *fails*, because $objectToLookFor, despite having the same
    # properties as the custom object stored in the array, is a *different object* 
    $arr -contains $objectToLookFor # reference equality -> $false(!)
    
    # If we look for the very same object stored in the array, the lookup
    # succeeds.
    $arr -contains $customObject # -> $true
    
    0 讨论(0)
提交回复
热议问题