My company uses Microsoft Intune. We've got 4 groups in an on-premise AD that controls the conditional access. We'll just call them AllowGroup1, AllowGroup2, BlockGroup1, and BlockGroup2. What I want know find is all users that are not in all of the groups. The result I'm wanting to find is any User object that is not in the mentioned groups. That way I can provide proof that our entire system is compliant. See below for the Powershell code I've borrowed from this post List AD Users who do not belong to one of several groups
I'm running these tests on my home domain controller. The problem I'm having is that the script isn't looking in the entire domain for users. Specifically, there is an OU in my personal DC that is called Home (I created the OU) and there are 2 user objects in a child OU called Users that this script isn't pulling from. I am running this script with a user that is in the Enterprise Admins group so I know it has sufficient privilege's. It's supposed to search AD via PowerShell for users not in multiple groups and place those users in a group called NotInGroup
To further elaborate, some users will be in AllowGroup1 and in BlockGroup2. Some users will be in BlockGroup1 and BlockGroup2. I want to find all users that are not in any of the groups listed above.
Import-Module ActiveDirectory
$groupname = "NotInGroup"
$members = Get-ADGroupMember -Identity $groupname
foreach($member in $members)
{
Remove-ADGroupMember -Identity $groupname -Member $member.samaccountname
}
$users = Get-ADUser -Filter
{
((memberof -notlike "CN=AllowGroup1,OU=Intune,OU=Groups,DC=domain,DC=local")
-AND (memberof -notlike "CN=AllowGroup2,OU=Intune,OU=Groups,DC=domain,DC=local")
-AND (memberof -notlike "CN=BlockGroup1,OU=Intune,OU=Groups,DC=domain,DC=local")
-AND (memberof -notlike "CN=BlockGroup2,OU=Intune,OU=Groups,DC=domain,DC=local"))
}
-SearchBase "dc=domain,dc=local" -SearchScope Subtree
foreach($user in $users)
{
Add-ADGroupMember -Identity $groupname -Members $user.samaccountname -ErrorAction SilentlyContinue
}
I don't think a complex filter like that would work and I would opt for using a regex.
Perhaps something like
# get users not in groups 'AllowGroup1', 'AllowGroup2', 'BlockGroup1', 'BlockGroup2'
$regex = 'CN=(AllowGroup[12]|BlockGroup[12])'
$users = Get-ADUser -Filter * -Properties MemberOf | Where-Object { ($_.MemberOf -join ';') -notmatch $regex }
Or you could try using the LDAPFilter parameter:
$filter = '(!(|(memberof=CN=AllowGroup1,OU=Intune,OU=Groups,DC=domain,DC=local)
(memberof=CN=AllowGroup2,OU=Intune,OU=Groups,DC=domain,DC=local)
(memberof=CN=BlockGroup1,OU=Intune,OU=Groups,DC=domain,DC=local)
(memberof=CN=BlockGroup2,OU=Intune,OU=Groups,DC=domain,DC=local)))'
$users = Get-ADUser -LDAPFilter $filter
Both parameters Filter and LDAPFilter are expecting a string, not a scriptblock
Related
I want to delete individual ID's from Administrator group
I have below code to get the members and delete them
Get-LocalGroupMember -Name 'Administrators'
$AdminGroup = [ADSI]"WinNT://$ComputerName/Administrators,group"
$User = [ADSI]"WinNT://$DomainName/$UserName,user"
$AdminGroup.Remove($User.Path)
Write-Host "Successfull:" $ComputerName
the problem I am facing is how to identify the single/individual IDs in the group.
below is one sample output from one of the server I fetched the members where there is no individual IDs present
Name SID PrincipalSource ObjectClass
---- --- --------------- -----------
AUTO1AP\csgadm# S-1-5-21-126948685-454775200-1760099607-500 Local User
ZA\ S-1-5-21-3095416536-3097367016-2845470932 ActiveDirectory Other
ZA\A-Auto$ S-1-5-21-3095416536-3097367016-2845470932-1423106 ActiveDirectory User
ZA\A-Server Administrators S-1-5-21-3095416536-3097367016-2845470932-128673 ActiveDirectory Group
ZA\A92361 S-1-5-21-3095416536-3097367016-2845470932-1423726 ActiveDirectory User
ZA\A-SAN-AUTO S-1-5-21-3095416536-3097367016-2845470932-1475616 ActiveDirectory User
ZA\Domain Admins S-1-5-21-3095416536-3097367016-2845470932-512 ActiveDirectory Group
I have the above data now and I want to delete the Individual account from this which is ZA\A92361 ( here I know this is the individual account but in actual case I need to find out and delete)
Please let me know on this
Although it is still not clear to me what you mean by identify the users you want to remove, I believe the Get-LocalGroupMember cmdlet returns everything you need to identify them.
$ADusersToRemove = 'jdoe', 'cblossom' # example some SamAccountNames of users to remove from the group
# from these users to remove, get an array of their Security IDs
$ADsidsToRemove = $ADusersToRemove | ForEach-Object { (Get-ADUser -Identity $_ -ErrorAction SilentlyContinue).SID }
# get a list of members of the local group, AD users only
$allADMembers = Get-LocalGroupMember -Name 'Administrators' | Where-Object { $_.ObjectClass -eq 'user' -and $_.PrincipalSource -eq 'ActiveDirectory' }
# remove the wanted AD users from the group
$ADmembersToRemove = #($allADMembers | Where-Object { $ADsidsToRemove -contains $_.SID })
if ($ADmembersToRemove.Count) {
Remove-LocalGroupMember -Name 'Administrators' -Member $membersToRemove.SID
}
If you also want to remove LOCAL users (not AD), you can do something similar
# get an array of LocalPrincipal objects
$LocalUsersToRemove = #(Get-LocalUser -Name 'someguy', 'anotheruser' )
if ($LocalUsersToRemove.Count) {
Remove-LocalGroupMember -Name 'Administrators' -Member $LocalUsersToRemove
}
If as you say you want to exclude service accounts, then this question really is how to distinguish between a service account and a normal user account.
I have no idea how you have organized your AD, but therfe are several options of course:
you can have all service accounts start their samaccountname with a special prefix, like svc_ or something.
Then you can alter the filter to become
Where-Object { $ADsidsToRemove -contains $_.SID -and (($_.Name -split '\\') -notlike 'svc_*')}
you can have a special OU where all service accounts are stored like OU=ServiceAccounts,DC=Company,DC=com
Then you can use filter
Where-Object { $ADsidsToRemove -contains $_.SID -and ((Get-ADUser -Identity $_.SID).DistinguishedName -notlike '*OU=ServiceAccounts,DC=Company,DC=com')}
you can have the Description property of the service accounts all contain the words Service account
Then you can use filter
Where-Object { $ADsidsToRemove -contains $_.SID -and ((Get-ADUser -Identity $_.SID -Properties Description).Description -notlike '*Service account*')}
maybe you have used an Extension attribute on service accounts to test like ExtensionAttribute1=svc
Then you can use filter
Where-Object { $ADsidsToRemove -contains $_.SID -and ((Get-ADUser -Identity $_.SID -Properties ExtensionAttribute1).ExtensionAttribute1 -notlike 'svc')}
The possibilities are almost endless as you can see..
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
}
I'll start off by saying that I am not a scripting expert at all. But I was tasked with creating a script to remove all group memberships of all users in a specified OU (called DISABLE) a few months ago.
Long story short, the script works great most of the time, but on random occasions it won't remove 1 (random) group for a user , or 2, or sometimes more, and I can't figure out what the reasoning is. The script used is:
#Remove User Group Memberships
$ou = Get-ADUser -SearchBase "OU=DISABLE,OU=CE,DC=ourdomain,DC=org" -Filter *
foreach ($user in $ou) {
$UserDN = $user.DistinguishedName
$user.PrimaryGroupID = 513
set-aduser -instance $user
Get-ADGroup -LDAPFilter "(member=$UserDN)" | foreach-object {
if ($_.name -ne "Domain Users") {remove-adgroupmember -identity $_.name -
member $UserDN -Confirm:$False} }
}
Any help that can be provided would be greatly appreciated, thank you!
Instead of searching for users, and then searching for all groups that user is a member of, just include that in your first search. This has the benefit of fewer AD searches, and less chance that an AD search misses the user.
#Remove User Group Memberships
$ou = Get-ADUser -SearchBase "OU=DISABLE,OU=CE,DC=ourdomain,DC=org" -Filter * -Property MemberOf
foreach ($user in $ou) {
$UserDN = $user.DistinguishedName
$user.PrimaryGroupID = 513
set-aduser -instance $user
$user.MemberOf |
Where{$_ -notmatch "Domain.?Users"} |
ForEach {remove-adgroupmember -identity $_ -member $UserDN -Confirm:$False}
}
Try that and see if you get better mileage out of it. Also, consider that perhaps some of these are protected groups, and the account that you run the script under doesn't have rights to affect those groups. Check these users that aren't being removed from groups and see if they have their AdminCount property set to 1.
We are looking to create a Powershell script that will automatically sort our user base by Country Code into two AD groups, one for English speakers, and one for French speakers. We are having challenges in getting this to work.
Each account should only be on one list, based on their country. The original source list of members for our list is Staff All, and we are looking into having two groups, one called Staff All EN, and the other called Staff All FR. It should also be able to exclude those in a Disabled OU for accounts that are no longer valid. (see below)
This is what we have so far:
$frenchCC = Get-Content .\CCFrench.txt
$staffAll = "CN=Staff-ALL,OU=Internal,OU=DistributionLists,OU=SFCG,DC=sfcg,DC=org"
$staffAllEn = "CN=Staff ALL EN,OU=Internal,OU=DistributionLists,OU=SFCG,DC=sfcg,DC=org"
$staffAllFr = "CN=Staff ALL FR,OU=Internal,OU=DistributionLists,OU=SFCG,DC=sfcg,DC=org"
$Target = Get-ADGroupMember -Identity $staffAll
We have tried several different approaches. The idea is to populate the French list from the AD based on the country code list. Populate the Staff-EN by copying the Staff-ALL list and then removing everyone in the French list.
And somewhere in the process, Remove everyone who is in HR-Disabled.
foreach ($Person in $Target) {
Add-ADGroupMember -Identity $staffAllEn -Members $Person.distinguishedname -confirm:$false
}
foreach ($Country in $frenchCC) {
Add-ADGroupMember -Identity $staffAllFr -Members (Get-ADUser -Filter '"$country"' -eq '") -confirm:$false
}
foreach ($Country in $frenchCC) {
Remove-ADGroupMember "Staff-ALL-EN" -Members (Get-ADUser -Filter $Country) -confirm:$false
}
$searchOU = Specify the OU where your groups are here (OU=Groups,DC=domain,DC=local)
Get-ADGroupMember Staff-ALL-EN -Properties Disabled | Remove-ADGroupMember Staff-ALL-EN
Get-ADGroupMember Staff-ALL-FR -Properties Disabled | Remove-ADGroupMember Staff-ALL-FR
In the source file for the country code, we have put the country codes in single quotes, double quotes and no quotes. with no difference.
This has really caught us in a pickle. Any suggestions would be appreciated.
I was able to work on the following for Brad, but I am not being able to make it run for each line in the text files (ex: multiple country codes). Anyone know what to change?
$frenchCC = Get-Content .\Countries.txt
$OUs = Get-Content .\OUs.txt
$userListFR = Get-ADUser -Filter {country -eq $frenchCC} -SearchBase $OUs -SearchScope OneLevel
$userListEN = Get-ADUser -Filter {country -ne $frenchCC} -SearchBase $OUs -SearchScope OneLevel
foreach($user in $userListFR) {add-adgroupmember "Staff-ALL-FR" -Members $user}
foreach($user in $userListEN) {add-adgroupmember "Staff-ALL-EN" -Members $user}
First up, I am not a script writer, so I apologise if this sounds like a real newbie question.
I am trying to write a Powershell query to list all user accounts within a certain OU sub-tree who do not belong to at least one of 4 groups.
As far as I can tell you cannot query this directly on the AD User object, so you need to iterate through the groups to get the membership, but I'm not clear on how to go about this across multiple groups.
I have put together a script that can find all users, add them to a temporary group and then remove them if they belong to one of the four other groups, but this looks like a horrible way to approach it, so I am hoping someone has a better solution.
Here's what I currently have (don't laugh) :-(
Import-Module ActiveDirectory
$groupname = "TempGroup"
$excludegroup1 = "Group1"
$excludegroup2 = "Group2"
$excludegroup2 = "Group4"
$excludegroup2 = "Group4"
$users = Get-ADUser -Filter * -SearchBase "ou=xxx,dc=xxx,dc=xxx" -SearchScope Subtree
foreach($user in $users)
{
Add-ADGroupMember -Identity $groupname -Member $user.samaccountname -ErrorAction SilentlyContinue
}
$members = Get-ADGroupMember -Identity $groupname
$excludemembers = Get-ADGroupMember -Identity $excludegroup1
foreach($member in $excludemembers)
{
Remove-ADGroupMember -Identity $groupname -Member $member.samaccountname
}
$members = Get-ADGroupMember -Identity $groupname
$excludemembers = Get-ADGroupMember -Identity $excludegroup2
foreach($member in $excludemembers)
{
Remove-ADGroupMember -Identity $groupname -Member $member.samaccountname
}
$members = Get-ADGroupMember -Identity $groupname
$excludemembers = Get-ADGroupMember -Identity $excludegroup3
foreach($member in $excludemembers)
{
Remove-ADGroupMember -Identity $groupname -Member $member.samaccountname
}
$members = Get-ADGroupMember -Identity $groupname
$excludemembers = Get-ADGroupMember -Identity $excludegroup4
foreach($member in $excludemembers)
{
Remove-ADGroupMember -Identity $groupname -Member $member.samaccountname
}
All help gratefully accepted.
All users, computers, groups and contacts (and possibly other objects) in Active Directory have a property called memberof. This property contains the distinguished names of all groups from the whole forest that this entity is a member of, as the attribute's name implies.
Given this information, you can now construct an ldap search query to find all entities that are not members of at least one of those groups:
(!(|(memberof=CN=Group1,dc=domain,dc=com)(memberof=CN=Group3,dc=domain,dc=com)(memberof=CN=Group3,dc=domain,dc=com)))
Other conditions may be included as necessary.
If you need to obtain the distinguished names of those groups first, you can either hard-code them in your filter or do a normal Powershell search for the groups and then read their distinguished names.
You can use the ldap query via the command's -LDAPFilter parameter.
In case anyone is interested, this is the code I have now. It uses a group, which it flushes each run, because then I can simply double-click a user to get into their object and add them to the group they're missing from.
Import-Module ActiveDirectory
$groupname = "NotInGroups"
$members = Get-ADGroupMember -Identity $groupname
foreach($member in $members)
{
Remove-ADGroupMember -Identity $groupname -Member $member.samaccountname
}
$users = Get-ADUser -Filter {((memberof -notlike "CN=Group1,DC=domain,DC=local") -AND (memberof -notlike "CN=Group2,DC=domain,DC=local") -AND (memberof -notlike "CN=Group3,DC=domain,DC=local") -AND (memberof -notlike "CN=Group4,DC=domain,DC=local"))} -SearchBase "ou=users,dc=domin,dc=local" -SearchScope Subtree
foreach($user in $users)
{
Add-ADGroupMember -Identity $groupname -Member $user.samaccountname -ErrorAction SilentlyContinue
}