PS loop not finding string in array?

This topic contains 5 replies, has 4 voices, and was last updated by Profile photo of Mike F Robbins Mike F Robbins 2 years, 2 months ago.

  • Author
    Posts
  • #19428
    Profile photo of Ben Knorr
    Ben Knorr
    Participant

    Hey all, I'm looking at writing some scripts to clean up distribution lists in our Exchange environment.

    My script:

    # Groups in AD that we're working on-
    $Affiliations=@()
    $Affiliations=@("Staff","Faculty")
    $exceptionsPath="c:\temp\FacStfexceptions.csv"
    $exceptionsList=import-csv $exceptionsPath
    $allStaffFacultyAdjuncts=foreach ($group in $Affiliations) { Get-ADGroupMember $group }
    
    foreach ($user in $allStaffFacultyAdjuncts)
    {
        $userN=$user.Name
        $userDN=$user.distinguishedName
        $dsgot=dsget user $userDN -memberof
        
        if ($exceptionsList.Name -contains "$userN")
        {
            write-host Bypassing $userN
        }    
        
        elseif ($dsgot -contains "Staff")
        {
            write-host $userN is in the Staff group.
        }
    }

    Some relevant data as returned from pieces of the script:

    $userDN=$user.distinguishedName
    $dsgot=dsget user $userDN -memberof

    $userDN : CN=ben,ou=staff,ou=accounts,dc=domain,dc=int
    $dsgot : "CN=TestUsers,OU=Groups,OU=accounts,DC=domain,DC=int"
    "CN=Staff,OU=Groups,OU=accounts,DC=domain,DC=int"
    "CN=Domain Users,CN=Users,DC=domain,DC=int"

    My exceptions list works fine. The problem is where my script is trying to determine which groups a user is a member of. The script appears to successfully get the user's DN, and uses dsget to pull the group information (returned DN LDAP values with quotes). My loop in PS where it checks $dsgot if it contains "Staff" doesn't ever catch anything. My value of $dsgot is an array if I'm not mistaken since most users are in more than one group- how do I parse an array in such a way so that my loop can "see" a value somewhere within it to trigger it?

  • #19434
    Profile photo of Stig Sörnsen
    Stig Sörnsen
    Participant

    Try use the -match comparison operator instead, like this:

    elseif ($dsgot -match "Staff")
    {
    }
    

    Should work with your example 🙂

    For more info please see: http://technet.microsoft.com/en-us/library/hh847759.aspx

    Best regards
    Stig

  • #19440
    Profile photo of Daniel Krebs
    Daniel Krebs
    Participant

    Hi Ben,

    The external "dsget" tool will not return an array but plain text with line breaks. That is why your -contains condition does not work.

    One of the many PowerShell best practices is to use cmdlets if available instead of command line tools like "dsget" because the cmdlets return rich objects instead of plain text. In your case you're already using the Get-ADGroupMember cmdlet from the ActiveDirectory Module. This module also contains a cmdlet called Get-ADUser which is perfect for getting an array of distinguished names of groups.

    Example of using Get-ADUser to get the group membership:

    $GroupDNs = Get-ADUser -Identity $user.distinguishedName -Property MemberOf
    $GroupDNs
    

    Even better instead of doing the work twice like in your script would be to use the objects returned by your Get-ADGroupMember call that already contain the necessary information to match against your exception list.

    Here is an example function which I've created based on your script. It returns custom object to the pipeline which hold the group and user objects to process further.

    Function Get-InvalidGroupMembers
    {
        Param
        (
            [Parameter(Mandatory = $true)]
            [ValidateNotNullOrEmpty()]
            [String[]]$GroupName,
    
            [Parameter(Mandatory = $true)]
            [ValidateNotNullOrEmpty()]
            [Object[]]$ExceptionList
        )
    
        # Get members of each group and output a custom object to the pipeline with group and user details
        $GroupName | ForEach-Object -Process {
            foreach ($GroupMember in Get-ADGroupMember -Identity $_)
            {
                if (($GroupMember.objectClass -eq 'user') -and
                    ($ExceptionList.Name -notcontains $GroupMember.Name))
                {
                    Write-Output -InputObject [pscustomobject]@{ Group = $Group; User = $GroupMember }
                }
            }
        }
    }
    
    $ExceptionList = Import-Csv -Path 'C:\Temp\FacStfexceptions.csv'
    $Results = Get-InvalidGroupMembers -GroupName @('Staff','Faculty') -ExceptionList $ExceptionList
    $Results
    

    I hope above helps.

    Best,
    Daniel

  • #19441
    Profile photo of Mike F Robbins
    Mike F Robbins
    Participant

    The issue is that $dsgot is an array of distinguished names and you need to see if it contains the distinguished name for the staff group including the quote marks because of the way dsget returns the results:

    elseif ($dsgot -contains '"CN=Staff,OU=Groups,OU=accounts,DC=domain,DC=int"')
    

    Using the -match operator, at least the way the previous poster is using it will return false positives if the user is in a group that contains the word "Staff" anywhere in the distinguished names such as a group named test in an OU named Staff.

    Also note that the way the script is written, if a user is a member of both the Staff and Faulty group and not contained in the CSV, they will be in the results twice.

  • #19443
    Profile photo of Mike F Robbins
    Mike F Robbins
    Participant

    You could also accomplish your task with a couple of lines of PowerShell and eliminate a lot of the complexity:

    $exceptionsList = Import-Csv -Path 'C:\temp\FacStfexceptions.csv'
    'Staff','Faculty' | Get-ADGroupMember | Get-ADUser | Where {$exceptionsList.name -notcontains $_.Name} | Select-Object -Property Name -Unique
    

    I'm not sure what version of PowerShell you're using so I've written this to be compatible with version 2.0 or higher.

  • #19444
    Profile photo of Mike F Robbins
    Mike F Robbins
    Participant

    Actually, you could even eliminate the Get-ADUser portion since Get-ADGroupMember returns their name:

    $exceptionsList = Import-Csv -Path 'C:\temp\FacStfexceptions.csv'
    'Staff','Faculty' | Get-ADGroupMember | Where {$exceptionsList.name -notcontains $_.Name} | Select-Object -Property Name -Unique
    

You must be logged in to reply to this topic.