Learn What IT Pros Need to Know About Windows 11 - August 24th at 1 PM ET! Learn What IT Pros Need to Know About Windows 11 - August 24th at 1 PM ET!
Active Directory|PowerShell

Finding Groups with the Active Directory Searcher and PowerShell

We will continue looking at ways to use the Active Directory Searcher with PowerShell. If you are just joining in, you might want to start at the beginning with this article. If you have been following along, you know that this is a powerful way to work with Active Directory. It works without requiring the Active Directory module that is a part of Remote Server Administration Tools (RSAT). Let’s start with a fresh searcher object on a domain member that is configured with a filter to find group objects.

 

 

$searcher = New-Object system.DirectoryServices.DirectorySearcher
$searcher.filter = "(objectclass=group)"

We will leave the search root alone, which will default to the domain root. Let’s see what type of object we can find.

Sponsored Content

Read the Best Personal and Business Tech without Ads

Staying updated on what is happening in the technology sector is important to your career and your personal life but ads can make reading news, distracting. With Thurrott Premium, you can enjoy the best coverage in tech without the annoying ads.

 

Getting an AD group object (Image Credit: Jeff Hicks)

Getting an AD Group Object (Image Credit: Jeff Hicks)

 

Even though this is a group, it is still an Active Directory search result. This means that I can use techniques from my previous articles like specifying the properties to retrieve and Convert-ADSearchResult function.

$props = "distinguishedname","name","member","description",
"whencreated","whenchanged","grouptype"
$searcher.PropertiesToLoad.Clear()
foreach ($item in $props) {
    $searcher.PropertiesToLoad.Add($item) | out-null
}

 

Now, I can get all the groups in my domain.

A sample group (Image Credit: Jeff Hicks)
A Sample Group (Image Credit: Jeff Hicks)

 

I can look at $groups by itself. I can also pipe it to Out-Gridview or Export-Csv. Really, I can do just about anything I want with it.

There is one bit of information that is not readily apparent in the output. It is difficult to tell what is a security or distribution group and whether it is global or universal. This information is available but it is hidden in the GroupType property.  When you search for a group, you should get a result with a GroupType property that matches one of these values:

Value Scope Category
2 Global Distribution
8 Universal Distribution
-2147483640 Universal Security
-2147483643 DomainLocal Security
-2147483644 DomainLocal Security
-2147483646 Global Security

 

The -2147483643 value is for built-in groups and -2147483644 is for default groups found in the User container. Of course, you can filter for any of the group types.

$searcher.filter = "(&(objectclass=group)(grouptype=-2147483644))"
$searcher | Convert-ADSearchResult | Out-Gridview

Filtered groups by type (Image Credit: Jeff Hicks)
Filtered Groups by Type (Image Credit: Jeff Hicks)

 

What would make this even easier? Let’s look at a function to get group objects.

#requires -version 5.0

#dot source my conversion function
. .\Convert-ADSearchResult.ps1

Function Get-MyADGroupObject {
[cmdletbinding()]
Param(
[Parameter(Position = 0)]
[ValidateNotNullorEmpty()]
[string]$Name="*",
[ValidatePattern("^LDAP://")]
[string]$SearchRoot
)

$searcher = New-Object system.DirectoryServices.DirectorySearcher

$searcher.PropertiesToLoad.Clear()
$props = "distinguishedname","name","member","description",
"whencreated","whenchanged","grouptype"
foreach ($item in $props) {
    $searcher.PropertiesToLoad.Add($item) | out-null
}

$searcher.filter = "(&(objectclass=group)(name=$name))"

if ($SearchRoot) {
    $searcher.SearchRoot = $SearchRoot
}

$groups = $searcher.findAll() | Convert-ADSearchResult

if ($groups) {

foreach ($group in $groups) {
    switch ($group.GroupType -as [string]) {
      "2" { 
        $group | Add-Member -MemberType Noteproperty -Name GroupScope -Value "Global"
        $group | Add-Member -MemberType Noteproperty -Name GroupCategory -Value "Distribution"
       }
     
      "8" {
        $group | Add-Member -MemberType Noteproperty -Name GroupScope -Value "Universal"
        $group | Add-Member -MemberType Noteproperty -Name GroupCategory -Value "Distribution"
      }
     
     "-2147483640" { 
        $group | Add-Member -MemberType Noteproperty -Name GroupScope -Value "Universal"
        $group | Add-Member -MemberType Noteproperty -Name GroupCategory -Value "Security"
      }

      "-2147483643" {
        $group | Add-Member -MemberType Noteproperty -Name GroupScope -Value "DomainLocal"
        $group | Add-Member -MemberType Noteproperty -Name GroupCategory -Value "Security"
      }
      "-2147483644" {
        $group | Add-Member -MemberType Noteproperty -Name GroupScope -Value "DomainLocal"
        $group | Add-Member -MemberType Noteproperty -Name GroupCategory -Value "Security"
      }
      "-2147483646" {
        $group | Add-Member -MemberType Noteproperty -Name GroupScope -Value "Global"
        $group | Add-Member -MemberType Noteproperty -Name GroupCategory -Value "Security"
      }
      Default {
        $group | Add-Member -MemberType Noteproperty -Name GroupScope -Value "Unknown"
        $group | Add-Member -MemberType Noteproperty -Name GroupCategory -Value "Unknown"
      }
  } #Switch

  $Group | Add-Member -MemberType ScriptProperty -Name MemberCount -Value {$this.member.count}

} #foreach

$groups

}
else {
    Write-Warning "Could not find group $Name under $($searcher.SearchRoot.Path)"
}

} #end function

 

This relies on my conversion function to properly format the results. The function properly decodes the GroupType property and adds 2 new properties, GroupScope and GroupCategory. It also adds a property that shows the total member count. Now, I have an easy way to find a group.

 

Testing the AD group function (Image Credit: Jeff Hicks)
Testing the Active Directory Group Function (Image Credit: Jeff Hicks)

 

I can also limit the search to a particular organizational unit. Just like with any other PowerShell command, I can use the output.

Get-MyADGroupObject -SearchRoot "LDAP://OU=employees,DC=globomantics,dc=local" | 
sort MemberCount -Descending | 
Select -first 10 -Property distinguishedname,name,description,WhenCreated,whenchanged,membercount |
Out-GridView -Title "Top Groups"

Getting AD groups by member count (Image Credit: Jeff Hicks)
Getting Active Directory Groups by Member Count (Image Credit: Jeff Hicks)

 

You could easily extend the function to add other filtering options, such as group category, scope, or test for empty groups. I hope you will grab a copy and try it out in your test environment. Next time, we will look at how to use the Active Directory Searcher with thousands of results. Feel free to leave a comment about what you think of this little series.

Related Topics:

BECOME A PETRI MEMBER:

Don't have a login but want to join the conversation? Sign up for a Petri Account

Register
Comments (0)

Leave a Reply

Register for Advanced Microsoft 365 Day!

GET-IT: Advanced Microsoft 365 1-Day Virtual Conference - Live August 24th!

Join us on Tuesday, August 24th and hear from Microsoft MVPs and industry experts about how to take advantage of Microsoft 365 at a technical level and dive deep into the features and functionality that will make your environment more secure and compliant.

RSVP Now

Sponsored By