Skip to content

Instantly share code, notes, and snippets.

@Bill-Stewart
Created December 2, 2019 19:44
Show Gist options
  • Save Bill-Stewart/ac1e981088f8dbf0f1358ab511e94173 to your computer and use it in GitHub Desktop.
Save Bill-Stewart/ac1e981088f8dbf0f1358ab511e94173 to your computer and use it in GitHub Desktop.
Get-ADGroupMembership.ps1
# Get-ADGroupMembership.ps1
# Written by Bill Stewart
#requires -version 2
# Version history:
# 1.0 (2019-12-02)
# * Initial version. Only searches the current domain.
<#
.SYNOPSIS
Gets the distinguished names of the Active Directory groups that have a specified object as a member.
.DESCRIPTION
Gets the distinguished names of the Active Directory groups that have a specified object, represented by the -Identity parameter, as a member.
.PARAMETER Identity
Specifies an Active Directory object. You can specify either the distinguishedName or the sAMAccountName of the object.
.PARAMETER Recursive
Specifies to include the object's nested group memberships.
.NOTES
If you use the ActiveDirectory PowerShell module and want Microsoft.ActiveDirectory.Management.ADGroup objects as output, pipe this command's output to the Get-ADGroup cmdlet.
.EXAMPLE
Get the distinguished names of the groups that the kendyer account is a member of:
PS C:\> Get-ADGroupMembership kendyer
.EXAMPLE
Get the distinguished names of the groups that the kendyer account is a member of, including nested groups:
PS C:\> Get-ADGroupMembership kendyer -Recursive
.EXAMPLE
Get the ADGroup objects representing the groups that the kendyer account is a member of (requires the Active Directory module):
PS C:\> Get-ADGroupMembership kendyer | Get-ADGroup
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,ValueFromPipeline = $true)]
[String[]] $Identity,
[Switch] $Recursive
)
begin {
$CommandName = $MyInvocation.MyCommand.Name
# Set up Pathname COM object
$ADS_ESCAPEDMODE_ON = 2
$ADS_SETTYPE_DN = 4
$ADS_FORMAT_X500_DN = 7
$Pathname = New-Object -ComObject "Pathname"
if ( -not $Pathname ) {
return
}
[Void] $Pathname.GetType().InvokeMember("EscapedMode","SetProperty",$null,$Pathname,$ADS_ESCAPEDMODE_ON)
# Outputs correctly escaped distinguished name using Pathname object
function Get-EscapedName {
param(
[String] $distinguishedName
)
[Void] $Pathname.GetType().InvokeMember("Set","InvokeMethod",$null,$Pathname,@($distinguishedName,$ADS_SETTYPE_DN))
$Pathname.GetType().InvokeMember("Retrieve","InvokeMethod",$null,$Pathname,$ADS_FORMAT_X500_DN)
}
# Outputs the memberOf attribute of an object using paged search (in case
# an object is a member of a large number of groups)
function Get-MemberOfAttribute {
param(
[String] $distinguishedName,
[Ref] $memberOf,
[Switch] $recursive
)
$searcher = [ADSISearcher] "(objectClass=*)"
$searcher.SearchRoot = [ADSI] "LDAP://$(Get-EscapedName $distinguishedName)"
$lastQuery = $false
$rangeStep = 1500
$rangeLow = 0
$rangeHigh = $rangeLow + ($rangeStep - 1)
do {
if ( -not $lastQuery ) {
$property = "memberOf;range={0}-{1}" -f $rangeLow,$rangeHigh
}
else {
$property = "memberOf;range={0}-*" -f $rangeLow
}
$searcher.PropertiesToLoad.Clear()
[Void] $searcher.PropertiesToLoad.Add($property)
$searchResults = $searcher.FindOne()
if ( $searchResults.Properties.Contains($property) ) {
foreach ( $searchResult in $searchResults.Properties[$property] ) {
if ( $memberOf.Value.Count -gt 100 ) {
Write-Progress `
-Activity $CommandName `
-Status "Getting membership of '$distinguishedName'" `
-CurrentOperation $searchResult
}
if ( $recursive ) {
if ( -not $memberOf.Value.Contains($searchResult) ) {
Get-MemberOfAttribute $searchResult $memberOf -recursive
}
}
if ( -not $memberOf.Value.Contains($searchResult) ) {
$memberOf.Value.Add($searchResult)
}
}
$done = $lastQuery
}
else {
if ( -not $lastQuery ) {
$lastQuery = $true
}
else {
$done = $true
}
}
if ( -not $lastQuery ) {
$rangeLow = $rangeHigh + 1
$rangeHigh = $rangeLow + ($rangeStep - 1)
}
}
until ( $done )
Write-Progress `
-Activity $CommandName `
-Status "Getting membership of '$distinguishedName'" `
-Completed:$true
}
function Get-ADGroupMembership {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[String] $identity,
[Switch] $recursive
)
$ldapString = $identity -replace '\\','\5c' -replace '\(','\28' -replace '\)','\29' -replace '\*','\2a' -replace '\/','\2f'
$searcher = [ADSISearcher] "(|(distinguishedName=$ldapString)(sAMAccountName=$ldapString))"
try {
$searchResults = $searcher.FindAll()
if ( $searchResults.Count -gt 0 ) {
foreach ( $searchResult in $searchResults ) {
$memberOf = New-Object Collections.Generic.List[String]
Get-MemberOfAttribute $searchResult.Properties["distinguishedname"][0] ([Ref] $memberOf) -recursive:$recursive
$memberOf
}
}
else {
Write-Error "Cannot find an object with identity '$identity'." -Category ObjectNotFound
}
}
catch {
Write-Error -ErrorRecord $_
}
finally {
$searchResults.Dispose()
}
}
}
process {
foreach ( $IdentityItem in $Identity ) {
Get-ADGroupMembership $IdentityItem -recursive:$Recursive
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment