Author Posts

July 9, 2016 at 12:03 am

I'm trying to pull a report that:

only lists Security Groups that have other Security Groups as members and/or are memberOf other security groups.

I have this code so far:

Get-ADGroup -Filter {GroupCategory -eq 'security'} -SearchBase 'DC=child,DC=root,DC=com' -Credential $creds -Properties * | select member,memberOf

I want to then pull the DN, SamAccountName for those results but haven't gotten close to narrowing down the initial results.

thanks

July 11, 2016 at 1:44 pm

not fully tested, but you might try something like this

$notsecuritygroup = New-Object System.Collections.ArrayList

Write-Host 'getting all security groups...'
$groups = Get-ADGroup -Filter "groupcategory -eq 'security'" -properties member | select name, member

# all groups progress
$index = 0
$total = $groups.Count
$starttime = $lasttime = Get-Date

# all members progress
$index2 = 0
$total2 = $groups.member.Count
$starttime2 = $lasttime2 = Get-Date

$results = foreach ($group in $groups) {
    # all groups progress
    $index++
    $currtime = (Get-Date) - $starttime
    $avg = $currtime.TotalSeconds / $index
    $last = ((Get-Date) - $lasttime).TotalSeconds
    $left = $total - $index
    $WrPrgParam = @{
        Activity = (
            "ALL GROUPS $(Get-Date -f s)",
            "Total: $($currtime -replace '\..*')",
            "Avg: $('{0:N2}' -f $avg)",
            "Last: $('{0:N2}' -f $last)",
            "ETA: $('{0:N2}' -f ($avg * $left / 60))",
            "min ($([string](Get-Date).AddSeconds($avg*$left) -replace '^.* '))"
        ) -join ' '
        Status = "$index of $total ($left left) [$('{0:N2}' -f ($index / $total * 100))%]"
        CurrentOperation = "GROUP: $($group.name)"
        PercentComplete = $index / $total * 100
    }
    Write-Progress @WrPrgParam
    $lasttime = Get-Date
    
    # all members progress
    $index3 = 0
    $total3 = $group.member.Count
    $starttime3 = $lasttime3 = Get-Date
    foreach ($member in $group.member) {
        $index2++
        $currtime2 = (Get-Date) - $starttime2
        $avg2 = $currtime2.TotalSeconds / $index2
        $last2 = ((Get-Date) - $lasttime2).TotalSeconds
        $left2 = $total2 - $index2
        $WrPrgParam2 = @{
            Activity = (
                "ALL MEMBERS $(Get-Date -f s)",
                "Total: $($currtime2 -replace '\..*')",
                "Avg: $('{0:N2}' -f $avg2)",
                "Last: $('{0:N2}' -f $last2)",
                "ETA: $('{0:N2}' -f ($avg2 * $left2 / 60))",
                "min ($([string](Get-Date).AddSeconds($avg2*$left2) -replace '^.* '))"
            ) -join ' '
            Status = "$index2 of $total2 ($left2 left) [$('{0:N2}' -f ($index2 / $total2 * 100))%]"
            CurrentOperation = "MEMBER: $member"
            PercentComplete = $index2 / $total2 * 100
            id = 2
        }
        Write-Progress @WrPrgParam2
        $lasttime2 = Get-Date

        # current members progress
        $index3++
        $currtime3 = (Get-Date) - $starttime3
        $avg3 = $currtime3.TotalSeconds / $index3
        $last3 = ((Get-Date) - $lasttime3).TotalSeconds
        $left3 = $total3 - $index3
        $WrPrgParam3 = @{
            Activity = (
                "CURRENT GROUP MEMBERS $(Get-Date -f s)",
                "Total: $($currtime3 -replace '\..*')",
                "Avg: $('{0:N2}' -f $avg3)",
                "Last: $('{0:N2}' -f $last3)",
                "ETA: $('{0:N2}' -f ($avg3 * $left3 / 60))",
                "min ($([string](Get-Date).AddSeconds($avg3*$left3) -replace '^.* '))"
            ) -join ' '
            Status = "$index3 of $total3 ($left3 left) [$('{0:N2}' -f ($index3 / $total3 * 100))%]"
            CurrentOperation = "MEMBER: $member"
            PercentComplete = $index3 / $total3 * 100
            id = 3
        }
        Write-Progress @WrPrgParam3
        $lasttime3 = Get-Date

        $group | select name, @{n='member';e={
            $_.member | ? {
                $_ -notin $notsecuritygroup -and
                $(try {
                    (get-adobject $_ -prop groupcategory).groupcategory -eq 'security'
                } catch {
                    $null = $notsecuritygroup.Add($_)
                })
            }
        }} | ? member
    }
}

$results

July 11, 2016 at 3:03 pm

Get-ADGroup -Filter {GroupCategory -eq 'security'} -Properties memberof,members |
Where-Object {

        $members = $_.members |
        Get-ADObject |
        Where-Object {
            $_.ObjectClass -eq 'group'
        } | 
        Get-ADGroup |
        Where-Object {
            $_.GroupCategory -eq 'security'
        }

        $memberof = $_.memberof |
        Get-ADObject |
        Where-Object {
            $_.ObjectClass -eq 'group'
        } | 
        Get-ADGroup |
        Where-Object {
            $_.GroupCategory -eq 'security'
        }

        $members -or $memberof

} |
Select-Object -Property DistinguishedName,SamAccountName

This isn't very efficient, as it results in a lot of calls to AD, but I think it'll get the list you want.

July 11, 2016 at 8:18 pm

Here is an example to query AD once and then work with the returned data

$groups = Get-ADGroup -Filter {GroupCategory -eq 'security'} -Properties member,memberof

$groups.member | ForEach-Object {
    If ($groups.distinguishedname -contains $_) {
        $current=$_
        $groups | Where-Object {$_.member -contains $current} | Select-Object distinguishedname, samaccountname, @{Label='Type';Expression={"HasMember"}}, @{Label='RelativeGroup';Expression={$current}}
    }
} | Select-Object * -Unique

$groups.memberof | ForEach-Object {
    If ($groups.distinguishedname -contains $_) {
        $current=$_
        $groups | Where-Object {$_.memberof -contains $current} | Select-Object distinguishedname, samaccountname, @{Label='Type';Expression={"IsMemberOf"}}, @{Label='RelativeGroup';Expression={$current}}
    }
} | Select-Object * -Unique

Results:

distinguishedname                                                     samaccountname                         Type       RelativeGroup                                                  
-----------------                                                     --------------                         ----       -------------                                                  
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Read-only Domain Controllers,CN=Users,DC=domain,DC=local          
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Group Policy Creator Owners,CN=Users,DC=domain,DC=local           
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Domain Admins,CN=Users,DC=domain,DC=local                         
CN=Administrators,CN=Builtin,DC=domain,DC=local                       Administrators                         HasMember  CN=Domain Admins,CN=Users,DC=domain,DC=local                         
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Cert Publishers,CN=Users,DC=domain,DC=local                       
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Enterprise Admins,CN=Users,DC=domain,DC=local                     
CN=Administrators,CN=Builtin,DC=domain,DC=local                       Administrators                         HasMember  CN=Enterprise Admins,CN=Users,DC=domain,DC=local                     
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Schema Admins,CN=Users,DC=domain,DC=local                         
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Domain Controllers,CN=Users,DC=domain,DC=local                    
CN=Users,CN=Builtin,DC=domain,DC=local                                Users                                  HasMember  CN=Domain Users,CN=Users,DC=domain,DC=local                          
CN=Guests,CN=Builtin,DC=domain,DC=local                               Guests                                 HasMember  CN=Domain Guests,CN=Users,DC=domain,DC=local                         
CN=Domain Controllers,CN=Users,DC=domain,DC=local                     Domain Controllers                     IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Domain Admins,CN=Users,DC=domain,DC=local                          Domain Admins                          IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Group Policy Creator Owners,CN=Users,DC=domain,DC=local            Group Policy Creator Owners            IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Read-only Domain Controllers,CN=Users,DC=domain,DC=local           Read-only Domain Controllers           IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Cert Publishers,CN=Users,DC=domain,DC=local                        Cert Publishers                        IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Schema Admins,CN=Users,DC=domain,DC=local                          Schema Admins                          IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Enterprise Admins,CN=Users,DC=domain,DC=local                      Enterprise Admins                      IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Domain Admins,CN=Users,DC=domain,DC=local                          Domain Admins                          IsMemberOf CN=Administrators,CN=Builtin,DC=domain,DC=local                      
CN=Enterprise Admins,CN=Users,DC=domain,DC=local                      Enterprise Admins                      IsMemberOf CN=Administrators,CN=Builtin,DC=domain,DC=local                      
CN=Domain Users,CN=Users,DC=domain,DC=local                           Domain Users                           IsMemberOf CN=Users,CN=Builtin,DC=domain,DC=local                               
CN=Domain Guests,CN=Users,DC=domain,DC=local                          Domain Guests                          IsMemberOf CN=Guests,CN=Builtin,DC=domain,DC=local                              

Of course you can limit it to just the distinguishedname and samaccountname if you like, but the above gives you more info at a glance.

$groups = Get-ADGroup -Filter {GroupCategory -eq 'security'} -Properties member,memberof

$groups.member | ForEach-Object {
    If ($groups.distinguishedname -contains $_) {
        $current=$_
        $groups | Where-Object {$_.member -contains $current} | Select-Object distinguishedname, samaccountname, @{Label='Type';Expression={"HasMember"}}, @{Label='RelativeGroup';Expression={$current}}
    }
} | Select-Object distinguishedname, samaccountname -Unique

$groups.memberof | ForEach-Object {
    If ($groups.distinguishedname -contains $_) {
        $current=$_
        $groups | Where-Object {$_.memberof -contains $current} | Select-Object distinguishedname, samaccountname, @{Label='Type';Expression={"IsMemberOf"}}, @{Label='RelativeGroup';Expression={$current}}
    }
} | Select-Object distinguishedname, samaccountname -Unique

Results:
distinguishedname                                                     samaccountname                        
-----------------                                                     --------------                        
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group
CN=Administrators,CN=Builtin,DC=domain,DC=local                       Administrators                        
CN=Users,CN=Builtin,DC=domain,DC=local                                Users                                 
CN=Guests,CN=Builtin,DC=domain,DC=local                               Guests                                
CN=Domain Controllers,CN=Users,DC=domain,DC=local                     Domain Controllers                    
CN=Domain Admins,CN=Users,DC=domain,DC=local                          Domain Admins                         
CN=Group Policy Creator Owners,CN=Users,DC=domain,DC=local            Group Policy Creator Owners           
CN=Read-only Domain Controllers,CN=Users,DC=domain,DC=local           Read-only Domain Controllers          
CN=Cert Publishers,CN=Users,DC=domain,DC=local                        Cert Publishers                       
CN=Schema Admins,CN=Users,DC=domain,DC=local                          Schema Admins                         
CN=Enterprise Admins,CN=Users,DC=domain,DC=local                      Enterprise Admins                     
CN=Domain Users,CN=Users,DC=domain,DC=local                           Domain Users                          
CN=Domain Guests,CN=Users,DC=domain,DC=local                          Domain Guests                         

July 11, 2016 at 8:19 pm

Here is an example to query AD once and then work with the returned data

$groups = Get-ADGroup -Filter {GroupCategory -eq 'security'} -Properties member,memberof

$groups.member | ForEach-Object {
    If ($groups.distinguishedname -contains $_) {
        $current=$_
        $groups | Where-Object {$_.member -contains $current} | Select-Object distinguishedname, samaccountname, @{Label='Type';Expression={"HasMember"}}, @{Label='RelativeGroup';Expression={$current}}
    }
} | Select-Object * -Unique

$groups.memberof | ForEach-Object {
    If ($groups.distinguishedname -contains $_) {
        $current=$_
        $groups | Where-Object {$_.memberof -contains $current} | Select-Object distinguishedname, samaccountname, @{Label='Type';Expression={"IsMemberOf"}}, @{Label='RelativeGroup';Expression={$current}}
    }
} | Select-Object * -Unique

Results:

distinguishedname                                                     samaccountname                         Type       RelativeGroup                                                  
-----------------                                                     --------------                         ----       -------------                                                  
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Read-only Domain Controllers,CN=Users,DC=domain,DC=local          
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Group Policy Creator Owners,CN=Users,DC=domain,DC=local           
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Domain Admins,CN=Users,DC=domain,DC=local                         
CN=Administrators,CN=Builtin,DC=domain,DC=local                       Administrators                         HasMember  CN=Domain Admins,CN=Users,DC=domain,DC=local                         
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Cert Publishers,CN=Users,DC=domain,DC=local                       
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Enterprise Admins,CN=Users,DC=domain,DC=local                     
CN=Administrators,CN=Builtin,DC=domain,DC=local                       Administrators                         HasMember  CN=Enterprise Admins,CN=Users,DC=domain,DC=local                     
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Schema Admins,CN=Users,DC=domain,DC=local                         
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group HasMember  CN=Domain Controllers,CN=Users,DC=domain,DC=local                    
CN=Users,CN=Builtin,DC=domain,DC=local                                Users                                  HasMember  CN=Domain Users,CN=Users,DC=domain,DC=local                          
CN=Guests,CN=Builtin,DC=domain,DC=local                               Guests                                 HasMember  CN=Domain Guests,CN=Users,DC=domain,DC=local                         
CN=Domain Controllers,CN=Users,DC=domain,DC=local                     Domain Controllers                     IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Domain Admins,CN=Users,DC=domain,DC=local                          Domain Admins                          IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Group Policy Creator Owners,CN=Users,DC=domain,DC=local            Group Policy Creator Owners            IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Read-only Domain Controllers,CN=Users,DC=domain,DC=local           Read-only Domain Controllers           IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Cert Publishers,CN=Users,DC=domain,DC=local                        Cert Publishers                        IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Schema Admins,CN=Users,DC=domain,DC=local                          Schema Admins                          IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Enterprise Admins,CN=Users,DC=domain,DC=local                      Enterprise Admins                      IsMemberOf CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local
CN=Domain Admins,CN=Users,DC=domain,DC=local                          Domain Admins                          IsMemberOf CN=Administrators,CN=Builtin,DC=domain,DC=local                      
CN=Enterprise Admins,CN=Users,DC=domain,DC=local                      Enterprise Admins                      IsMemberOf CN=Administrators,CN=Builtin,DC=domain,DC=local                      
CN=Domain Users,CN=Users,DC=domain,DC=local                           Domain Users                           IsMemberOf CN=Users,CN=Builtin,DC=domain,DC=local                               
CN=Domain Guests,CN=Users,DC=domain,DC=local                          Domain Guests                          IsMemberOf CN=Guests,CN=Builtin,DC=domain,DC=local                              

Of course you can limit it to just the distinguishedname and samaccountname if you like, but the above gives you more info at a glance.

$groups = Get-ADGroup -Filter {GroupCategory -eq 'security'} -Properties member,memberof

$groups.member | ForEach-Object {
    If ($groups.distinguishedname -contains $_) {
        $current=$_
        $groups | Where-Object {$_.member -contains $current} | Select-Object distinguishedname, samaccountname, @{Label='Type';Expression={"HasMember"}}, @{Label='RelativeGroup';Expression={$current}}
    }
} | Select-Object distinguishedname, samaccountname -Unique

$groups.memberof | ForEach-Object {
    If ($groups.distinguishedname -contains $_) {
        $current=$_
        $groups | Where-Object {$_.memberof -contains $current} | Select-Object distinguishedname, samaccountname, @{Label='Type';Expression={"IsMemberOf"}}, @{Label='RelativeGroup';Expression={$current}}
    }
} | Select-Object distinguishedname, samaccountname -Unique

Results:

distinguishedname                                                     samaccountname                        
-----------------                                                     --------------                        
CN=Denied RODC Password Replication Group,CN=Users,DC=domain,DC=local Denied RODC Password Replication Group
CN=Administrators,CN=Builtin,DC=domain,DC=local                       Administrators                        
CN=Users,CN=Builtin,DC=domain,DC=local                                Users                                 
CN=Guests,CN=Builtin,DC=domain,DC=local                               Guests                                
CN=Domain Controllers,CN=Users,DC=domain,DC=local                     Domain Controllers                    
CN=Domain Admins,CN=Users,DC=domain,DC=local                          Domain Admins                         
CN=Group Policy Creator Owners,CN=Users,DC=domain,DC=local            Group Policy Creator Owners           
CN=Read-only Domain Controllers,CN=Users,DC=domain,DC=local           Read-only Domain Controllers          
CN=Cert Publishers,CN=Users,DC=domain,DC=local                        Cert Publishers                       
CN=Schema Admins,CN=Users,DC=domain,DC=local                          Schema Admins                         
CN=Enterprise Admins,CN=Users,DC=domain,DC=local                      Enterprise Admins                     
CN=Domain Users,CN=Users,DC=domain,DC=local                           Domain Users                          
CN=Domain Guests,CN=Users,DC=domain,DC=local                          Domain Guests                         

July 18, 2016 at 11:07 pm

~

  • This reply was modified 2 years, 1 month ago by  Jeff Taylor.

July 18, 2016 at 11:09 pm

Thanks Craig, I'm afraid this one took way too long to get results. We have about 62k User objects in our forest

July 19, 2016 at 2:24 pm

in my original example i got all the members of the groups and went through that list, but i think a shorter way is to just get all the security groups and see if they are a member of another security group.

it ran exponentially faster than my last attempt, but you'll have to let me know if it gives problems for your environment

EDIT: taking Curtis' information in mind (don't query AD multiple times), i have updated the script

Write-Host 'getting all security groups...'
$groups = Get-ADGroup -Filter "groupcategory -eq 'security'" -Properties memberof | select name, distinguishedname, memberof | ? memberof

$securitygroups = $groups.distinguishedname

# all groups progress
$index = 0
$total = $groups.Count
$starttime = $lasttime = Get-Date

$results = foreach ($group in $groups) {
    # all groups progress
    $index++
    $currtime = (Get-Date) - $starttime
    $avg = $currtime.TotalSeconds / $index
    $last = ((Get-Date) - $lasttime).TotalSeconds
    $left = $total - $index
    $WrPrgParam = @{
        Activity = (
            "ALL GROUPS $(Get-Date -f s)",
            "Total: $($currtime -replace '\..*')",
            "Avg: $('{0:N2}' -f $avg)",
            "Last: $('{0:N2}' -f $last)",
            "ETA: $('{0:N2}' -f ($avg * $left / 60))",
            "min ($([string](Get-Date).AddSeconds($avg*$left) -replace '^.* '))"
        ) -join ' '
        Status = "$index of $total ($left left) [$('{0:N2}' -f ($index / $total * 100))%]"
        CurrentOperation = "GROUP: $($group.name)"
        PercentComplete = $index / $total * 100
    }
    Write-Progress @WrPrgParam
    $lasttime = Get-Date
    
    $group | select name, @{n='memberof';e={$_.memberof | ? {$_ -in $securitygroups}}} | ? memberof
}

$results

July 19, 2016 at 2:38 pm

Anything that queries AD multiple times in a loop is going to be slower than querying once and working with the returned data. The example I posted shows how to do this and uses much less code to do it.