List Active Directory group hierarchy - powershell

I'm looking to build a script which would show Active Directory group hierarchy.
Unfortunately simple Get-ADGroupMember $group -Recursive lists only members, not groups.
Example:
Group1 is main group - it has 3 subgroups named GroupA,B,C. So GroupA,B,C is MemberOf Group1.
GroupA has no subgroups
GroupB has 2 subgroups named subGroup1,2
GroupC has 1 subgroup named subGroup3
subGroup1,2,3 has no subgroups
Ideally would be great to have output something like this:
Level1 Level2 Level3 Level4
Group1 GroupA
GroupB subGroup1
subGroup2
GroupC subGroup3
Of course I have Googled it for, I found two Web-Sites:
http://powershell.com/cs/forums/p/9588/15894.aspx
http://www.experts-exchange.com/Programming/Languages/Scripting/Powershell/Q_27346526.html
It's little over my scope to understand them, in first link there is simple script.
function Get-GroupHierarchy ($searchGroup)
{
import-module activedirectory
$groupMember = get-adgroupmember $searchGroup | sort-object objectClass -descending
foreach ($member in $groupMember)
{Write-Host $member.objectclass,":", $member.name;
if ($member.ObjectClass -eq "group")
{Get-GroupHierarchy $member.name}}
}
I put $searchGroup = "Administrators" before the script, but script doesn't show any results. It has 3 sub-groups if I do Get-ADGroupMember. Probably I don't know how to work with functions.
How to make those scripts to work or make something similar?

To directly answer your question of how to make that script work, you call the function as such:
Get-GroupHierarchy "Administrators"
But if you read further in the forum post somebody does note an issue with the function... circular references. Given this:
Group1 -GroupA -GroupX
-GroupB -GroupY
-Group1
The function would never finish. It would get the members of Group1, then GroupA, then GroupX. After GroupX it wouldn't have any more nested groups so it would move down to GroupB, and then GroupY, and would then Group1, where it would start on GroupA again. It would cycle over, and over. I've never tried it, so I don't know if it can be done with AD groups, but if you can nest groups within groups that are nested within themselves then this will give you problems.

Related

Count AD group members with certain properties

I need a PowerShell script to count the members of an AD group that have the extensionAttribute4 property equal to o365_facstaff.
I’ve been using the following script to count all members of the group but I specifically need just the ones with the property:
$ADInfo = Get-AdGroup -Identity ‘<group name>’ -Properties Members
$ADInfo.Members.Count
We can get this information from AD with a single -Filter query on Get-ADUser:
# We'll need the group DN instead of the group name
# Here's an example
$groupDn = 'CN=test_group,CN=Users,DC=bender,DC=net'
# Get all ADUsers member of the target group with the specific
$groupMembers = Get-ADUser -Filter "(memberOf -RecursiveMatch '$groupDn') -and (extensionAttribute4 -eq 'o365_facstaff')"
# Check the Count property like you would with any array
$groupMembers.Count
Alternatively, as also mentioned in the comments, you can get the group members off of the ADGroup and further filter, though this results in additional unnecessary local processing. This can become problematic with very large groups, especially if your ADDS infrastructure runs closer to the minimum system requirements:
# Using $ADInfo from your code sample
$membersWithfacstaff = $ADInfo.Members | Where-Object {
( Get-ADUser $_ -Properties extensionAttribute4 ).extensionAttribute4 -eq 'o365_facstaff'
}
# Use the Count property
$facstaff.Count
As also mentioned in the comments, Measure-Command will give you the count too but is a bit redundant here, considering you'd have to reference the Count property anyways if you want to use it programmatically.
See this answer of mine for more information on effectively using the -Filter parameter on the RSAT AD cmdlets.

Add An AD Attribute To All Users In an AD Group

We have a few groups that we are playing with. We'll call it Group1 Group2 Group3. We then have a custom AD Attribute called "team". We need to take all the users of Group1 and change their AD Attribute to "Group1" etc etc. I've looked at a few ways to do this but am drawing up a blank. Any suggestion is greatly appreciated.
There are a few functions to work with here, and this will require that you have the AD module installed for PowerShell.
First, you'll need to get all of the members of the group, and you likely want to do it recursively. So that's:
Get-ADGroupMember -Identity "Group A" -Recursive
Running that on its own should give you all the members. But now you want to do something with what you got back from that function, so you want to loop over them
Get-ADGroupMember | ForEach-Object {
# You'll do something with each member here.
}
And what you want to do it set the AD attribute, which you can do with Set-ADUser. While most attributes can be set easily as they're all properties of the function, yours appears to be custom so you need to use -replace. That looks like this:
Get-ADGroupMember | ForEach-Object {
Set-ADUser -Identity $_ -Replace #{"Team"="Group A"} -WhatIf
}
The -WhatIf on the end makes the function tell you what it would do, but it doesn't actually do it. I've left it there so you don't accidentally run the code without testing it out first. When you want this to actually do something, remove that text.
You should try this on a small group with one or two people to make sure it works the way you want, and then when you're ready, hit the larger group

Need to validate user input (domain user,group) and fetch detail

When I supply a string and need to extract the domain user object (name, surname, manager name) I get the desired detail through following code.
$groupdetail : gc d:\domainobject.txt
$output = Get-ADUser $GroupDetail
$output | Select Name, GivenName,SurName, #{label="Manager";expression={(Get-ADUser $_.Manager -Properties DisplayName).Displayname}}
Next thing is validate of the input if it is a domain group then extract the group member names then get the user object information again as above. The problem is I am unable to validate if the string is a group.
$groupname = Get-content D:\domainobject.txt
foreach ($group in $groupname){
$groupname = get-adgroup $group
$groupmember = Get-ADGroupMember $groupname | Format-Table Name, SamAccountName -AutoSize
foreach ($groupdetail in $groupmember){
$groupdoutput = get-aduser $groupdetail
$groupoutput | Select-Object Name, GivenName,SurName, #{label="Manager";expression={(Get-ADUser $_.Manager -Properties DisplayName).Displayname}}
}
Write-Host $groupoutput
}
Both condition should run in one code so if the input string is a domain user get the information and exit. Incase string is a domain group it will loop in get the group member name then extract the domain user information. One way I thought is to run this condition $groupname.objectclass -eq "group" or $groupname.objectclass -eq "name" so that I need to convert the input string to PowerShell object.
I tried a few things but that did not work. Please suggest what are the possible way I can achieve this.
You could always use a try-catch block
try{$group = get-adgroup $groupname}
catch{$user = get-aduser $groupname}
if($group)
{write-host "It's a group!"}
else
{Write-host "It's a user!"}
That will tell you if it's a group or a user. Just replace the write-host with your logic.
Usually when doing this sort of thing, I want one of two things:
In the first case, if I want the groups that a user is a member of directly regardless of nesting, then I specify:
Get-AdUser -Identity 'Alice' -Properties MemberOf
This will return the MemberOf property with the user, which is a string array that in each element includes the distinguished name of a group the user is a direct member of. Depending on exactly what you're doing, it may make sense to fetch all groups from AD at once to get the group details en masse, and then do a lookup for each MemberOf.
In the second case, I only care about effective group membership of user accounts. I will want Get-AdGroupMember to resolve the nested groups into the resulting set of users. In other words, if I run Get-AdGroupMember -Identity 'Foo', and the members are user Alice and group Bar, and user Bob is a member of group Bar, then I want the cmdlet to return Alice and Bob. I don't care that Bar is the reason that Bob is in Foo. To do that, I run:
Get-AdGroupMember -Identity 'Foo' -Recurse

How to extract a list of users with rights to create domain users in the Active Directory?

I was tasked with creating Powershell scripts that we will use to review the Active Directory of our clients. I like to add that my knowledge of Powershell is very basic, but I've found A LOT online (including many Stack Overflow topics!) to help me with this task. My script is pretty much in place, but there is one functionality that I would like to add to my script. I do not know if (and how) this even possible. I've looked at many sites to help me with this issue, but I did not find any solutions. So I decided to ask it to the community itself. Here is a description of my issue.
What I want is to have a list of users that have the rights to create Domain Users and have the rights to install Updates / Hot-Fixes on Domain Controllers. In order to be able to create a Domain User, the user must have a membership (or equivalent) to Domain Administrators (Found here https://technet.microsoft.com/en-us/library/dd894463(v=ws.10).aspx. It's easy to get the Domain Administrators and Enterprise Administrators (the latter having also the ability to create Domain Users obviously). I have a script that retrieves all the Domain Users and the groups that they have membership to, so that is covered.
What I want to achieve is to get Domain Users that are not a member of the Domain Administrators (or equivalent) groups that have rights to create Domain Users (or within certain OU's like explained in this topic https://serverfault.com/questions/83686/how-to-create-a-limited-domain-admin-that-does-not-have-access-to-domain-contr).
There is not an attribute that defines what I am looking for. I had some ideas of using de 'admincount' property like this: Get-ADUser -Server $ADServer -Filter {admincount -gt 0}. This returns to me all the ADUsers that are within the Default Protected Groups within the Active Directory. But what I want is to be able to get Users that are not contained in these groups.
Is there a way to get this information?
Sorry I began fully coding this but without seeing your script and not having a full test AD env in front of me at the moment, I will give you the psudo-code as it seems like you've done enough that you can probably take this code and run with it and pretty easily have a fully working script since most the primary commands/filters needed I have included below:
Get a list of all OUs
$OUs = #(Get-ADDomain | Select-Object -ExpandProperty DistinguishedName)
$OUs += Get-ADOrganizationalUnit -Filter * | Select-Object -ExpandProperty DistinguishedName
$OUs += Get-ADObject -SearchBase (Get-ADDomain).DistinguishedName -SearchScope OneLevel -LDAPFilter '(objectClass=container)' | Select-Object -ExpandProperty DistinguishedName
Get a filtered list of all non-admin users using:
Get-ADUser -Server $ADServer -Filter { admincount -eq 0 }
Loop through each of the OUs and retrieve their permissions
foreach ($OU in $OUs)
(Get-Acl $OU).access | where { accesscontroltype -eq 'Allow' })
Inner loop your filtered non-admin user array with each access permission needed to perform the pseudo-admin duties using:
foreach ($objUser in $(Get-ADUser -Server $ADServer -Filter { admincount -eq 0 }))
(Get-Acl $OU).access | where { identityreference -eq <TRIMMED INNER LOOP USER OBJECT NAME FROM $objUser> }
If matched, add to new array, otherwise do nothing
Dump array to report

Active Directory Querying with PowerShell

I am building a report on our active directory groups and am having a hard time when it comes to different forests.
We have groups from forestA with users inside from forestB. I was able to pull those groups using Quest AD:
$GroupUsers = Get-QADGroupMember $GroupName -Type 'user' -Indirect
The only problem is that even though the users inside are from forest B, they come up showing they are from forestA. They do exist in both forests, don't know if that's a problem.
Any clue on why this happens?
Thanks in advance.
There is -Server parameter of Get-ADGroupMember cmdlet where you may specify domain controller from another domain/forest. Something like:
Get-ADGroupMember -Identity $GroupName -Server DC.AnotherDomain.com
you can query forest for domains or all global catalogs: get-adforest (properties GlobalCatalogs,Domains) - I often did something like this:
I pulled the list of all SIDs in the group then checked which one belongs to my domain/forest, the rest was searched in external forest.