Get All Members of a Local Group Using PowerShell (2023)

I wrote a function a while back that is used to query a local group on a remote or local system (or systems) and based on the –Depth parameter, will perform a recursive query for all members of that group to include local and domain groups and users. I felt that it was something worth sharing out just in case someone has a need for it. It also isn’t the same script that I wrote back in January here: https://learn-powershell.net/2013/01/22/find-and-report-members-of-a-local-group/

To avoid an issue with circular groups (probably not the technical name for it), I use a hash table to manage the local/domain groups to ensure that they are not queried again later on. By circular groups, I am talking about groups that are members of a parent group that may have the parent group listed as a member later on down the group membership. A more understandable example is here:

Get All Members of a Local Group Using PowerShell (1)

Because Administrators exist in Group3 and Administrators has Group3 as a member, this madness will never stop or will stop when it hits some limit on depth. Regardless, this would be a very annoying thing to have happen.

 [cmdletbinding()] Param ( [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [Alias('CN','__Server','Computer','IPAddress')] [string[]]$Computername = $env:COMPUTERNAME, [parameter()] [string]$Group = "Administrators", [parameter()] [int]$Depth = ([int]::MaxValue) )
(Video) Using PowerShell - List the Members of a Group

Nothing really new here. I am setting up my parameters for Computername, a Group name (which defaults to’Administrators and the Depth limit. You will notice that I am using [int]::MaxValue which is 2147483647 which is my ”unlimited” recursion. If someone has a nested group that far down, then my hats off to you!

#region Extra ConfigurationsWrite-Verbose ("Depth: {0}" -f $Depth)#endregion Extra Configurations#region Helper FunctionsFunction Get-NetBIOSDomain { Try { $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() $Root = $Domain.GetDirectoryEntry() $Base = ($Root.distinguishedName) # Use the NameTranslate object. $Script:Translate = New-Object -comObject "NameTranslate" $Script:objNT = $Translate.GetType() # Initialize NameTranslate by locating the Global Catalog. $objNT.InvokeMember("Init", "InvokeMethod", $Null, $Translate, (3, $Null)) # Retrieve NetBIOS name of the current domain. $objNT.InvokeMember("Set", "InvokeMethod", $Null, $Translate, (1, "$Base")) $objNT.InvokeMember("Get", "InvokeMethod", $Null, $Translate, 3) } Catch {Write-Warning ("{0}" -f $_.Exception.Message)} }

This piece of code starts out with some verbose output (if using –Verbose) that will show the parameters being used as well as what the current depth that will be allowed for the nested groups.

The Get-NetBIOSDomain function is used only to help get the distinguishedName of a domain group in the Get-DomainGroupMember function (shown later in this article).

Function Get-LocalGroupMember { [cmdletbinding()] Param ( [parameter()] [System.DirectoryServices.DirectoryEntry]$LocalGroup ) $Counter++ # Invoke the Members method and convert to an array of member objects. $Members= @($LocalGroup.psbase.Invoke("Members")) ForEach ($Member In $Members) { Try { $Name = $Member.GetType().InvokeMember("Name", 'GetProperty', $Null, $Member, $Null) $Path = $Member.GetType().InvokeMember("ADsPath", 'GetProperty', $Null, $Member, $Null) # Check if this member is a group. $isGroup = ($Member.GetType().InvokeMember("Class", 'GetProperty', $Null, $Member, $Null) -eq "group") If (($Path -like "*/$Computer/*")) { $Type = 'Local' } Else {$Type = 'Domain'} New-Object PSObject -Property @{ Computername = $Computer Name = $Name Type = $Type ParentGroup = $LocalGroup.Name[0] isGroup = $isGroup Depth = $Counter } If ($isGroup) { Write-Verbose ("{0} is a group" -f $Name) # Check if this group is local or domain. Write-Verbose ("Checking if Counter: {0} is less than Depth: {1}" -f $Counter, $Depth) If ($Counter -lt $Depth) { If ($Type -eq 'Local') { If ($Groups[$Name] -notcontains 'Local') { Write-Verbose ("{0}: Getting local group members" -f $Name) $Groups[$Name] += ,'Local' # Enumerate members of local group. Get-LocalGroupMember $Member } } Else { If ($Groups[$Name] -notcontains 'Domain') { Write-Verbose ("{0}: Getting domain group members" -f $Name) $Groups[$Name] += ,'Domain' # Enumerate members of domain group. Get-DomainGroupMember $Member $Name $True } } } } } Catch { Write-Warning ("{0}" -f $_.Exception.Message) } }}
(Video) 12. Get members of all Active Directory Groups with PowerShell

Get-LocalGroupMember is my first helper function when it comes to getting members of a group. In this case, I am gathering the members of a local group. A number of possibilities exist here such as whether the member is actually a User, or if it is another group that is either local on the system or a domain group. Based on the group type, it will either call itself again for the local group or call the Get-DomainGroupMember function which will be explained next. You can tell from my $Groups variable that it is the hash table used to make sure that the group hasn’t already queried as well as the counter which helps to determine the depth level of the current group and its members.

Function Get-DomainGroupMember { [cmdletbinding()] Param ( [parameter()] $DomainGroup, [parameter()] [string]$NTName, [parameter()] [string]$blnNT ) $Counter++ If ($blnNT -eq $True) { # Convert NetBIOS domain name of group to Distinguished Name. $objNT.InvokeMember("Set", "InvokeMethod", $Null, $Translate, (3, ("{0}{1}" -f $NetBIOSDomain.Trim(),$NTName))) $DN = $objNT.InvokeMember("Get", "InvokeMethod", $Null, $Translate, 1) $ADGroup = [ADSI]"LDAP://$DN" } Else { $DN = $DomainGroup.distinguishedName $ADGroup = $DomainGroup } ForEach ($MemberDN In $ADGroup.Member) { $MemberGroup = [ADSI]("LDAP://{0}" -f ($MemberDN -replace '/','\/')) New-Object PSObject -Property @{ Computername = $Computer Name = $MemberGroup.name[0] Type = 'Domain' ParentGroup = $NTName isGroup = ($MemberGroup.Class -eq "group") Depth = $Counter } # Check if this member is a group. If ($MemberGroup.Class -eq "group") { Write-Verbose ("{0} is a group" -f $MemberGroup.name[0]) Write-Verbose ("Checking if Counter: {0} is less than Depth: {1}" -f $Counter, $Depth) If ($Counter -lt $Depth) { If ($Groups[$MemberGroup.name[0]] -notcontains 'Domain') { Write-Verbose ("{0}: Getting domain group members" -f $MemberGroup.name[0]) $Groups[$MemberGroup.name[0]] += ,'Domain' # Enumerate members of domain group. Get-DomainGroupMember $MemberGroup $MemberGroup.Name[0] $False } } } }}

The Get-DomainGroupMember is my second helper function used to get group members. As the name implies, this will gather the group memberships that have been queried. the NetBIOSDomain name is also used here to find out the actual distinguishedName of the group so I can be used with the [ADSI] accelerator to make the query for group members. As with my Get-LocalGroupMember function, this makes use of the same hash table and counter to handle circular groups and recursion depth.

 Process { #region Get Local Group Members ForEach ($Computer in $Computername) { $Script:Groups = @{} $Script:Counter=0 # Bind to the group object with the WinNT provider. $ADSIGroup = [ADSI]"WinNT://$Computer/$Group,group" Write-Verbose ("Checking {0} membership for {1}" -f $Group,$Computer) $Groups[$Group] += ,'Local' Get-LocalGroupMember -LocalGroup $ADSIGroup } #endregion Get Local Group Members }

Here is where everything happens for the queries. Everything that exists in the Process block is here for a reason so I am not needlessly making the same variable creation for each computer passed through the pipeline. Each computer will have a fresh counter and new hash table to handle recursion depth and circular groups, respectfully. Because the first group queried is the one that we defined in the Group parameter, it is already known to be a local group and Get-LocalGroupMember is called first.

(Video) Use PowerShell : Get all Groups in domain

I also have some runspace stuff in the code as well, but being how I have already talked about this in other articles, I figured it wasn’t worth mentioning again. If you really want to see the code behind the runspaces, check out those articles here.

Ok, enough talk about the code! It is time to see Get-LocalGroupMembership in action.

Get-LocalGroupMembership | Format-Table –AutoSize

Get All Members of a Local Group Using PowerShell (2)

You will notice that the groups are only nested 2 levels deep. Also important to notice is that I have some circular groups here with Sysops Admins under Enterprise Admins. Sysops Admins which is also listed under Administrators in which Sysops Admins has… Enterprise Admins listed as a member and thus the circle of member begins! Or at least it would have begun had the code not caught it.

(Video) Manage Computer Local Groups With PowerShell

I do not have other remote systems to use –Computername but trust me in that it does work against remote systems.

Get-LocalGroupMembership -Depth 1 | Format-Table –AutoSize

Get All Members of a Local Group Using PowerShell (3)

This is an example of setting the Depth parameter to only go 1 level deep.

That is all for this function. Feel free to download it from the Script Repository (link below) and let me know what you think!

(Video) Get members of multiple Security Groups using PowerShell

Download

Technet Script Repository

FAQs

How do I get local group members in PowerShell? ›

To get the local Administrators group members using PowerShell, you need to use the GetLocalGroupMember command. This command is available in PowerShell version 5.1 onwards and the module for it is Microsoft.

How do I get a list of user group members in PowerShell? ›

Use Get-ADGroupMember cmdlet to List Members of an Active Directory Group. The PowerShell Get-ADGroupMember cmdlet is used to list the members of an Active Directory group. You can just type the cmdlet in a PowerShell window and you'll be prompted to enter the name of the group you want to use.

How do I list members of a local admin group? ›

Type net localgroup groupname, where groupname is the name of the group you want to list. For example, if the group name is Administrators, you would type net localgroup Administrators. Then press Enter. Observe the list of users in the local group.

What does the command @() mean in PowerShell? ›

In PowerShell V2, @ is also the Splat operator. PS> # First use it to create a hashtable of parameters: PS> $params = @{path = "c:\temp"; Recurse= $true} PS> # Then use it to SPLAT the parameters - which is to say to expand a hash table PS> # into a set of command line parameters.

Videos

1. Using PowerShell - Get all Members of a Group (With Name,Description,Office,Phone)
(microsoft lab)
2. How to Create Powershell Script for Getting Group Members
(Joy Banerjee)
3. 40. How to get the local Administrators of one or many computers remotely with PowerShell.
(CyberAutomate)
4. Using PowerShell - Get members of the group with over 5000 users
(microsoft lab)
5. Using PowerShell - Get only users from member a group
(microsoft lab)
6. How to get Users & Group Membership from AD with PowerShell
(Ravi Kiran TECHLOGS)
Top Articles
Latest Posts
Article information

Author: Twana Towne Ret

Last Updated: 03/26/2023

Views: 6720

Rating: 4.3 / 5 (64 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Twana Towne Ret

Birthday: 1994-03-19

Address: Apt. 990 97439 Corwin Motorway, Port Eliseoburgh, NM 99144-2618

Phone: +5958753152963

Job: National Specialist

Hobby: Kayaking, Photography, Skydiving, Embroidery, Leather crafting, Orienteering, Cooking

Introduction: My name is Twana Towne Ret, I am a famous, talented, joyous, perfect, powerful, inquisitive, lovely person who loves writing and wants to share my knowledge and understanding with you.