List groups and number of users in AD using Powershell - powershell

I am trying to pull a list of groups from AD that start with "pegp" and a count of how many users are in each group and performing this action in PowerShell. This script will give me a list of the all the groups, but I also need how many users are in each group:
$groups = Get-ADGroup -Filter "Name -like 'pegp*'"
$Output = forEach($group in $groups) {
Get-ADGroup -Identity $group | Select-Object name
}
$Output | Export-Csv C:\temp\file_test2.csv
I then tried this code, but it's not giving me a count of the users in each group and is actually inserting an additional row after each group name in the CSV:
$groups = Get-ADGroup -Filter "Name -like 'pegp*'"
$Output = forEach($group in $groups) {
Get-ADGroup -Identity $group | Select-Object name
(Get-ADGroupMember -Identity $group).count
}
$Output | Export-Csv C:\temp\file_test4.csv
Since I'm still new to PowerShell and programming in general, I thought I'd reach out to the well of knowledge to help me figure out where I'm going wrong. Thanks!

Your current code produces an alternating stream of 1 object with a Name property, and 1 integer, which is why Export-Csv is not producing the results you want - it's expecting uniform input.
What you'll want to do is produce 1 object with 2 properties - for that you could use the Select-Object cmdlet with a calculated property for the member count:
$groupsWithMemberCount = Get-ADGroup -Filter "Name -like 'pegp*'" |Select Name,#{Name='MemberCount';Expression={#(Get-ADGroupMember -Identity $_).Count }}
# no need to call Get-ADGroup again, we already have all the information we need
$groupsWithMemberCount |Export-Csv C:\temp\file_test4.csv -NoTypeInformation
Beware that this counts the total number of members (principals AND nested groups).
If you want only users, filter the ouput from Get-ADGroupMember based on their objectClass:
$groupsWithMemberCount = Get-ADGroup -Filter "Name -like 'pegp*'" |Select Name,#{Name='MemberCount';Expression={#(Get-ADGroupMember -Identity $_ |Where-Object objectClass -eq 'user').Count}}

Related

The size limit for this request was exceeded [duplicate]

I am trying to pull groups in from a text file and one of my groups is too large, 80,000 people.
How do I get this to work l, it outputs how I want it.
$groups = Get-Content c:\temp\ADGroups.txt
foreach($group in $groups) {
#(Get-ADGroup $group -Properties Member| Select-Object -ExpandProperty Member).Count
Get-ADGroupMember -Identity $group |
Get-ADObject -Properties Name, DisplayName |
Select-Object -Property #{n="Username";e={$_.Name}}, DisplayName,
#{n="AD Group";e={$group}} |
Export-Csv C:\Users\Desktop\GroupsInfo.CSV -NoTypeInformation -Append
}
The number of objects that Get-ADGroupMember can return is restricted by a limit in the ADWS (Active Directory Web Services):
MaxGroupOrMemberEntries
5000
Specifies the maximum number of group members (recursive or non-recursive), group memberships, and authorization groups that can be retrieved by the Active Directory module Get-ADGroupMember, Get-ADPrincipalGroupMembership, and Get-ADAccountAuthorizationGroup cmdlets. Set this parameter to a higher value if you anticipate these cmdlets to return more than 5000 results in your environment.
According to this thread you should be able to work around it by querying group objects and expanding their member property (if you can't increase the limit on the service):
Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
Get-ADUser -Property Name, DisplayName
Beware, though, that this is likely to be slow, because you'll be sending thousands of requests. It might be better to build a hashtable of all users:
$users = #{}
Get-ADUser -Filter '*' -Property Name, DisplayName | ForEach-Object {
$users[$_.DistinguishedName] = $_
}
so that you can look them up by their distinguished name:
Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
ForEach-Object { $users[$_] }
I was hitting the 5000 limit with Get-ADGroupMember.
You can use Get-ADUser with the -LDAPFilter parameter to get group members. It's quick and supports >5000 entries.
$groups = #(
"group1"
"group2"
"group3"
)
Foreach ($group in $groups) {
Get-ADUser -LDAPFilter "(&(objectCategory=user)(memberof=CN=$group,OU=Groups,OU=rest,DC=of,DC=distinguished,DC=name))" | Export-Csv "C:\$group.csv"
}
It looks like you can build up complex filters with this method. I needed to quickly return enabled members from some extremely large groups. The filter I used for this was:
"(&(objectCategory=user)(!useraccountcontrol:1.2.840.113556.1.4.803:=2)(memberof=CN=$group,OU=Groups,OU=rest,DC=of,DC=distinguished,DC=name))"
I hear this is a limitation of the AD Webservices that actually service the requests from powershell cmdlets. The maximum size is 5000. But you can try the dsget command, although you will need to get a little creative.
$GroupDN = (Get-ADGroup -Identity $Group).DistinguishedName will give you the DN of the group.
Use the DSget like this.
$members = DSget group $GroupDN -members This will give you the list of DNs of all members.
Feed that to a Get-ADUser cmdlet in a pipe or foreach loop and you are good to go.
You would need to use the -resultpagesize parameter. The highest value you can specify is 2147483647.
So:
Get-ADGroupMember -Identity $group -resultpagesize 2147483647 |
Select-Object -Property #{n="Username";e={$_.Name}}, DisplayName,
#{n="AD Group";e={$group}} |
Export-Csv C:\Users\Desktop\GroupsInfo.CSV -NoTypeInformation -Append
This is how I did mine. I needed to extract more than 25k machines from a security group.
$Groups = gc C:\Temp\Groups.txt
$results = foreach ($Group in $Groups) {
Get-ADGroup $Group -Properties Member | Select-Object -ExpandProperty Member | Get-ADObject -Properties Name
}
$results | Export-csv "C:\Temp\Groups.csv" -NoTypeInformation
This will give you all of the members of a group quickly (mine had 85k members)
$groupMembers = Get-ADGroup -Identity $group -Server $domainGroupIsIn -Properties Member | Select-Object -ExpandProperty Member ;
or if you need to filter some
$whereMatch = $recipient.DistinguishedName.Remove(0, $index); # limits to a domain or container
$groupMembers = Get-ADGroup -Identity $group -Server $domainGroupIsIn -Properties Member | Select-Object -ExpandProperty Member | Where {$_ -match $whereMatch};
Just increase the limit from ADUC --> View --> Filter Option - Maximum number of options displayed per folder.
That's it. Try again running your command. It takes me 4 days to figure out this and finally it's working.

get-adgroupmember inconsistently returns group members

I've been writing powershell since powershell 2, and I've run into something odd I've never seen before.
$groups = get-adgroup -filter {name -like 'SomeGroup*'} | select name | sort name
foreach ($group in $groups){
$groupsid = $group.name
write-host $groupsid
Get-ADGroupMember $groupsid | select name | sort name
write-host "`n`n"
}
The get-adgroupmember in the foreach loop is only enumerating members in certain groups and not in others.
If "$groupsid" = "DeveloperGroup" and I use
get-adgroupmember DeveloperGroup | select name | sort name in the shell,
then I get back what I expected to see: a list of group members. But for several groups that are enumerated by the first line, I get nothing back when the exact same cmdlet is executed within the foreach loop. I know some of the cmdlets are still a little buggy, just no idea why this is being intermittent in what the loop decides to fetch.
I have edited few lines of your cmdlet and it is working fine for me. Please use the below formatted PowerShell command to get your desire output.
$groups = get-adgroup -filter {name -like 'Group*'} | sort name
$results = foreach ($group in $groups) {
Get-ADGroupMember $group | select samaccountname, name, #{n='GroupName';e={$group}}, #{n='Description';e={(Get-ADGroup $group -Properties description).description}} | sort name
}
$results
$results | Export-csv C:\GroupMemberShip.txt -NoTypeInformation
#Doug Maurer comment is helpful and may be part of the issue.
Another problem: avoid using the name of the group.
Either use the group object directly as input of the Get-ADGroupMember cmdlet like below, or use the DistinguishedName property of the group.
foreach ($group in $groups){
Get-ADGroupMember $group | select name | sort name
write-host "`n`n"
}

Powershell to count members of a large AD group that exceeds 5000 members [duplicate]

I am trying to pull groups in from a text file and one of my groups is too large, 80,000 people.
How do I get this to work l, it outputs how I want it.
$groups = Get-Content c:\temp\ADGroups.txt
foreach($group in $groups) {
#(Get-ADGroup $group -Properties Member| Select-Object -ExpandProperty Member).Count
Get-ADGroupMember -Identity $group |
Get-ADObject -Properties Name, DisplayName |
Select-Object -Property #{n="Username";e={$_.Name}}, DisplayName,
#{n="AD Group";e={$group}} |
Export-Csv C:\Users\Desktop\GroupsInfo.CSV -NoTypeInformation -Append
}
The number of objects that Get-ADGroupMember can return is restricted by a limit in the ADWS (Active Directory Web Services):
MaxGroupOrMemberEntries
5000
Specifies the maximum number of group members (recursive or non-recursive), group memberships, and authorization groups that can be retrieved by the Active Directory module Get-ADGroupMember, Get-ADPrincipalGroupMembership, and Get-ADAccountAuthorizationGroup cmdlets. Set this parameter to a higher value if you anticipate these cmdlets to return more than 5000 results in your environment.
According to this thread you should be able to work around it by querying group objects and expanding their member property (if you can't increase the limit on the service):
Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
Get-ADUser -Property Name, DisplayName
Beware, though, that this is likely to be slow, because you'll be sending thousands of requests. It might be better to build a hashtable of all users:
$users = #{}
Get-ADUser -Filter '*' -Property Name, DisplayName | ForEach-Object {
$users[$_.DistinguishedName] = $_
}
so that you can look them up by their distinguished name:
Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
ForEach-Object { $users[$_] }
I was hitting the 5000 limit with Get-ADGroupMember.
You can use Get-ADUser with the -LDAPFilter parameter to get group members. It's quick and supports >5000 entries.
$groups = #(
"group1"
"group2"
"group3"
)
Foreach ($group in $groups) {
Get-ADUser -LDAPFilter "(&(objectCategory=user)(memberof=CN=$group,OU=Groups,OU=rest,DC=of,DC=distinguished,DC=name))" | Export-Csv "C:\$group.csv"
}
It looks like you can build up complex filters with this method. I needed to quickly return enabled members from some extremely large groups. The filter I used for this was:
"(&(objectCategory=user)(!useraccountcontrol:1.2.840.113556.1.4.803:=2)(memberof=CN=$group,OU=Groups,OU=rest,DC=of,DC=distinguished,DC=name))"
I hear this is a limitation of the AD Webservices that actually service the requests from powershell cmdlets. The maximum size is 5000. But you can try the dsget command, although you will need to get a little creative.
$GroupDN = (Get-ADGroup -Identity $Group).DistinguishedName will give you the DN of the group.
Use the DSget like this.
$members = DSget group $GroupDN -members This will give you the list of DNs of all members.
Feed that to a Get-ADUser cmdlet in a pipe or foreach loop and you are good to go.
You would need to use the -resultpagesize parameter. The highest value you can specify is 2147483647.
So:
Get-ADGroupMember -Identity $group -resultpagesize 2147483647 |
Select-Object -Property #{n="Username";e={$_.Name}}, DisplayName,
#{n="AD Group";e={$group}} |
Export-Csv C:\Users\Desktop\GroupsInfo.CSV -NoTypeInformation -Append
This is how I did mine. I needed to extract more than 25k machines from a security group.
$Groups = gc C:\Temp\Groups.txt
$results = foreach ($Group in $Groups) {
Get-ADGroup $Group -Properties Member | Select-Object -ExpandProperty Member | Get-ADObject -Properties Name
}
$results | Export-csv "C:\Temp\Groups.csv" -NoTypeInformation
This will give you all of the members of a group quickly (mine had 85k members)
$groupMembers = Get-ADGroup -Identity $group -Server $domainGroupIsIn -Properties Member | Select-Object -ExpandProperty Member ;
or if you need to filter some
$whereMatch = $recipient.DistinguishedName.Remove(0, $index); # limits to a domain or container
$groupMembers = Get-ADGroup -Identity $group -Server $domainGroupIsIn -Properties Member | Select-Object -ExpandProperty Member | Where {$_ -match $whereMatch};
Just increase the limit from ADUC --> View --> Filter Option - Maximum number of options displayed per folder.
That's it. Try again running your command. It takes me 4 days to figure out this and finally it's working.

Get-ADGroupMember : The size limit for this request was exceeded

I am trying to pull groups in from a text file and one of my groups is too large, 80,000 people.
How do I get this to work l, it outputs how I want it.
$groups = Get-Content c:\temp\ADGroups.txt
foreach($group in $groups) {
#(Get-ADGroup $group -Properties Member| Select-Object -ExpandProperty Member).Count
Get-ADGroupMember -Identity $group |
Get-ADObject -Properties Name, DisplayName |
Select-Object -Property #{n="Username";e={$_.Name}}, DisplayName,
#{n="AD Group";e={$group}} |
Export-Csv C:\Users\Desktop\GroupsInfo.CSV -NoTypeInformation -Append
}
The number of objects that Get-ADGroupMember can return is restricted by a limit in the ADWS (Active Directory Web Services):
MaxGroupOrMemberEntries
5000
Specifies the maximum number of group members (recursive or non-recursive), group memberships, and authorization groups that can be retrieved by the Active Directory module Get-ADGroupMember, Get-ADPrincipalGroupMembership, and Get-ADAccountAuthorizationGroup cmdlets. Set this parameter to a higher value if you anticipate these cmdlets to return more than 5000 results in your environment.
According to this thread you should be able to work around it by querying group objects and expanding their member property (if you can't increase the limit on the service):
Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
Get-ADUser -Property Name, DisplayName
Beware, though, that this is likely to be slow, because you'll be sending thousands of requests. It might be better to build a hashtable of all users:
$users = #{}
Get-ADUser -Filter '*' -Property Name, DisplayName | ForEach-Object {
$users[$_.DistinguishedName] = $_
}
so that you can look them up by their distinguished name:
Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
ForEach-Object { $users[$_] }
I was hitting the 5000 limit with Get-ADGroupMember.
You can use Get-ADUser with the -LDAPFilter parameter to get group members. It's quick and supports >5000 entries.
$groups = #(
"group1"
"group2"
"group3"
)
Foreach ($group in $groups) {
Get-ADUser -LDAPFilter "(&(objectCategory=user)(memberof=CN=$group,OU=Groups,OU=rest,DC=of,DC=distinguished,DC=name))" | Export-Csv "C:\$group.csv"
}
It looks like you can build up complex filters with this method. I needed to quickly return enabled members from some extremely large groups. The filter I used for this was:
"(&(objectCategory=user)(!useraccountcontrol:1.2.840.113556.1.4.803:=2)(memberof=CN=$group,OU=Groups,OU=rest,DC=of,DC=distinguished,DC=name))"
I hear this is a limitation of the AD Webservices that actually service the requests from powershell cmdlets. The maximum size is 5000. But you can try the dsget command, although you will need to get a little creative.
$GroupDN = (Get-ADGroup -Identity $Group).DistinguishedName will give you the DN of the group.
Use the DSget like this.
$members = DSget group $GroupDN -members This will give you the list of DNs of all members.
Feed that to a Get-ADUser cmdlet in a pipe or foreach loop and you are good to go.
You would need to use the -resultpagesize parameter. The highest value you can specify is 2147483647.
So:
Get-ADGroupMember -Identity $group -resultpagesize 2147483647 |
Select-Object -Property #{n="Username";e={$_.Name}}, DisplayName,
#{n="AD Group";e={$group}} |
Export-Csv C:\Users\Desktop\GroupsInfo.CSV -NoTypeInformation -Append
This is how I did mine. I needed to extract more than 25k machines from a security group.
$Groups = gc C:\Temp\Groups.txt
$results = foreach ($Group in $Groups) {
Get-ADGroup $Group -Properties Member | Select-Object -ExpandProperty Member | Get-ADObject -Properties Name
}
$results | Export-csv "C:\Temp\Groups.csv" -NoTypeInformation
This will give you all of the members of a group quickly (mine had 85k members)
$groupMembers = Get-ADGroup -Identity $group -Server $domainGroupIsIn -Properties Member | Select-Object -ExpandProperty Member ;
or if you need to filter some
$whereMatch = $recipient.DistinguishedName.Remove(0, $index); # limits to a domain or container
$groupMembers = Get-ADGroup -Identity $group -Server $domainGroupIsIn -Properties Member | Select-Object -ExpandProperty Member | Where {$_ -match $whereMatch};
Just increase the limit from ADUC --> View --> Filter Option - Maximum number of options displayed per folder.
That's it. Try again running your command. It takes me 4 days to figure out this and finally it's working.

Target all users in two OU's and remove Distribution Lists

hoping to get a little help here – I looked around the site but didn’t see anything quite like this (please direct me if there IS and I missed it).
I need to incorporate a new step in our user offboarding process, which would remove them from any AD Distribution Lists. I would like to set this up as a scheduled task to run once a night against two OU’s where the inactivated user accounts can be found.
I’d like to run this by pointing it at the USERS instead of the OU where the Distro Lists live, because I suspect that we’ll ultimately get the request to remove these users from OTHER types of group as well.
This snippet will remove AD Distro Lists from a single user, but leave all other types of AD groups alone:
# GroupCategory 0 = Distro List
# GroupCategory 1 = Security Group
# GroupScope 0 = DomainLocal
# GroupScope 1 = Global
# GroupScope 2 = Universal
$user = "userlogon"
Get-ADPrincipalGroupMembership -Identity $user|
Where {$_.GroupCategory -eq 0} |
ForEach {Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_ -Confirm:$false}
THIS snippet will look at an OU and return some info (just my example for using a variable with -searchbase):
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$OU | ForEach {Get-ADGroup -Filter * -Properties ManagedBy -SearchBase $_ } |
Select Name, ManagedBy |
Sort -Property Name
Out-GridView
BUT – Does it hold together that in order to complete my objective, I would do something like this?! I'm a bit out of my depth here, any advice for a re-write is appreciated:
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$user = "*"
$OUs | ForEach {
Get-ADPrincipalGroupMembership -Identity $user|
Where {$_.GroupCategory -eq 0} |
ForEach {Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_ -Confirm:$false}
}
There’s always a couple of ways to do stuff in PoSh, so I’m sure there’s a less-complicated way to do the same thing. If anyone has a different approach please feel free to suggest an alternative.
Thanks for taking a look!
So it sounds like you need three loops.
First, you will need to loop over the OU list to get the Users. We'll store the user objects in $Users
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -SearchBase $OU
}
Next loop over the users to get the groups that you want to remove. Then loop over the groups to remove each one.
ForEach ($User in $Users) {
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq 0} |
ForEach-Object {
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_
}
}
I think I'd take this a little differently, by getting the group membership of all users, then grouping by AD group, and processing each group that way. Seems like it would be a lot fewer calls to AD. So I'd start out getting all of the users, just like BenH, except I would include their MemberOf property. Then I'd build a list of potential groups and filter down to just the Distribution Lists. I'd make a Hashtable of those as the keys, and make the value an array of each user that is in that group. Then loop through that removing the value of each from the associated key.
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -SearchBase $OU -Properties MemberOf
}
$UsersByGroup = #{}
ForEach($Group in ($Users.MemberOf | Select -Unique | Get-ADGroup | Where{ $_.GroupCategory -eq 0 })) {
$UsersByGroup.Add($Group.DistinguishedName,($Users | Where{ $Group.DistinguishedName -in $_.MemberOf}))
}
$UsersByGroup.Keys | ForEach{
Remove-ADGroupMember -Identity $_ -Members $UsersByGroup[$_] -Confirm:$false
}