Get-GroupWithChildren.ps1
<# .SYNOPSIS This function pulls the groups information and then starts recursively passing through all membership. .DESCRIPTION This function pulls the groups information and then starts recursively passing through all membership. .PARAMETER GROUPID This is the ID of the parent group. .PARAMETER PROCESSEDGROUPIDS This is a hash collection of all groups processed - this is what prevents circular references from reprocessing. .PARAMETER OBJECTTYPE Utilized to determine the type of query that is made. .OUTPUTS None .EXAMPLE Get-GroupWithChildren -groupID GROUPID -processedGroupIDs PROCESSEDGROUPIDs -objectType OBJECTTYPE #> Function Get-GroupWithChildren() { Param ( [Parameter(Mandatory = $true,ParameterSetName = 'MSGraph')] [Parameter(Mandatory = $true,ParameterSetName = 'ExchangeOnline')] [Parameter(Mandatory = $true,ParameterSetName = 'LDAP')] [string]$objectID, [Parameter(Mandatory = $true,ParameterSetName = 'MSGraph')] [Parameter(Mandatory = $true,ParameterSetName = 'ExchangeOnline')] [Parameter(Mandatory = $true,ParameterSetName = 'LDAP')] $processedGroupIDs, [Parameter(Mandatory = $true,ParameterSetName = 'MSGraph')] [Parameter(Mandatory = $true,ParameterSetName = 'ExchangeOnline')] [Parameter(Mandatory = $true,ParameterSetName = 'LDAP')] [string]$objectType, [Parameter(Mandatory = $true,ParameterSetName = 'MSGraph')] [boolean]$queryMethodGraph=$false, [Parameter(Mandatory = $true,ParameterSetName = 'ExchangeOnline')] [boolean]$queryMethodExchangeOnline=$false, [Parameter(Mandatory = $true,ParameterSetName = 'LDAP')] [boolean]$queryMethodLDAP=$false, [Parameter(Mandatory = $true,ParameterSetName = 'LDAP')] $globalCatalogServer, [Parameter(Mandatory = $true,ParameterSetName = 'LDAP')] $activeDirectoryCredential, [Parameter(Mandatory = $true,ParameterSetName = 'LDAP')] [boolean]$firstLDAPQuery, [Parameter(Mandatory =$FALSE)] [boolean]$expandGroupMembership=$TRUE, [Parameter(Mandatory =$FALSE)] [boolean]$expandDynamicGroupMembership=$TRUE, [Parameter(Mandatory = $false,ParameterSetName = 'LDAP')] [Parameter(Mandatory = $true,ParameterSetName = 'ExchangeOnline')] [Parameter(Mandatory = $true,ParameterSetName = 'MSGraph')] [boolean]$reverseHierarchy=$FALSE, [Parameter(Mandatory = $false,ParameterSetName = 'LDAP')] [string]$parentObjectID="N/A" ) out-logfile -string "***********************************************************" out-logfile -string "Entering Get-GroupWithChildren" out-logfile -string "***********************************************************" $functionObject = $NULL $childNodes = @() $children=@() $functionParamterSetName = $PsCmdlet.ParameterSetName $functionGraphName = "MSGraph" $functionExchangeOnlineName = "ExchangeOnline" $functionLDAPName = "LDAP" $functionGraphGroup = "#microsoft.graph.group" $functiongraphUser = "#microsoft.graph.user" $functionGraphContact = "#microsoft.graph.orgContact" $functionExchangeGroup = "Group" $functionExchangeMailUniversalSecurityGroup = "MailUniversalSecurityGroup" $functionExchangeMailUniversalDistributionGroup = "MailUniversalDistributionGroup" $functionExchangeUserMailbox = "UserMailbox" $functionExchangeMailUser = "Mailuser" $functionExchangeGuestMailUser = "GuestMailUser" $functionExchangeMailContact = "MailContact" $functionExchangeGroupMailbox = "GroupMailbox" $functionExchangeDynamicGroup = "DynamicDistributionGroup" $functionExchangeSharedMailbox = "SharedMailbox" $functionExchangeRoomMailbox = "RoomMailbox" $functionExchangeEquipmentMailbox = "EquipmentMailbox" $functionExchangeUser = "User" $isExchangeGroupType = $false $functionLDAPGroup = "Group" $functionLDAPUser = "User" $functionLDAPContact = "Contact" $functionLDAPDynamicGroup = "msExchDynamicDistributionList" $exchangeMembersAttribute = "Members" out-logfile -string ("Parameter Set Name: "+$functionParamterSetName) out-logfile -string ("Processing group ID: "+$objectID) out-logfile -string ("Processing object type: "+$objectType) out-logfile -string ("QueryMethodGraph: "+$queryMethodGraph) out-logfile -string ("QueryMethodExchangeOnline: "+$queryMethodExchangeOnline) out-logfile -string ("QueryMethodLDAP: "+$queryMethodLDAP) out-logfile -string "Determine the path utilized based on paramter set name." #=============================================================================== #Exchange Functions #=============================================================================== function reset-exchangeOnlinePowershell { if ($exchangeOnlineCertificateThumbPrint -eq "") { #User specified non-certifate authentication credentials. try { New-ExchangeOnlinePowershellSession -exchangeOnlineCredentials $exchangeOnlineCredential -exchangeOnlineEnvironmentName $exchangeOnlineEnvironmentName -debugLogPath $logFolderPath } catch { out-logfile -string "Unable to create the exchange online connection using credentials." out-logfile -string $_ -isError:$TRUE } } elseif ($exchangeOnlineCertificateThumbPrint -ne "") { #User specified thumbprint authentication. try { new-ExchangeOnlinePowershellSession -exchangeOnlineCertificateThumbPrint $exchangeOnlineCertificateThumbPrint -exchangeOnlineAppId $exchangeOnlineAppID -exchangeOnlineOrganizationName $exchangeOnlineOrganizationName -exchangeOnlineEnvironmentName $exchangeOnlineEnvironmentName -debugLogPath $logFolderPath } catch { out-logfile -string "Unable to create the exchange online connection using certificate." out-logfile -string $_ -isError:$TRUE } } } function get-ExchangeGroup { Param ( [Parameter(Mandatory = $true)] $objectID, [Parameter(Mandatory = $false)] $queryType, [Parameter(Mandatory = $false)] $secondTry = $FALSE ) $retryCounter = 0 $retryRequired = $TRUE do { if ($queryType -eq $functionExchangeMailUniversalSecurityGroup) { try { $returnObject = get-o365DistributionGroup -identity $objectID -ErrorAction Stop $global:mailUniversalSecurityGroupCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($returnCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Mail Enabled Security Group." out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeMailUniversalDistributionGroup) { try { $returnObject = get-o365DistributionGroup -identity $objectID -ErrorAction Stop $global:mailUniversalDistributionGroupCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Mail Enabled Distribution Group." out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeGroupMailbox) { try { $returnObject = get-o365UnifiedGroup -identity $objectID -ErrorAction Stop if ($returnObject.IsMembershipDynamic -eq $TRUE) { $global:groupMailboxDynamicCounter+=$returnObject.exchangeObjectID } else { $global:groupMailboxCounter+=$returnObject.exchangeObjectID } $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Unified Group." out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeDynamicGroup) { try { $returnObject = get-o365DynamicDistributionGroup -Identity $objectID -errorAction Stop $global:dynamicGroupCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ out-logfile -string "Unable to obtain Exchange Online Dynamic Distribution Group." if ($secondTry -eq $FALSE) { if ($retryCounter -gt 4) { out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } else { out-logfile -string $_ } } } elseif ($queryType -eq $functionExchangeGroup) { try { $returnObject = get-o365group -identity $objectID -ErrorAction Stop $global:groupCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { out-logfile -string "It is possible the root group is a dynamic group - this is not returned by get-group." out-logfile -string "Try obtaining dynamic group." try { $returnObject = get-ExchangeGroup -objectID $objectID -queryType $functionExchangeDynamicGroup -ErrorAction Stop -secondTry $TRUE $retryRequired = $FALSE } catch { out-logfile -string "Group is neither a root dynamic group or returned by get-group." out-logfile -string "Unable to obtain Exchange Group object." out-logfile -string "This error may be expected. If a security group was previously mail enabled.." out-logfile -string "And then mail disalbed it remains in Exchange Online and could be a member..." out-logfile -string "But is not returned by get-Group." out-logfile -string "Testing to ensure root group is not a dynamic group." out-logfile -string $_ -isError:$true } } } } until ( $retryRequired -eq $false ) return $returnObject } function get-ExchangeUser { Param ( [Parameter(Mandatory = $true)] $objectID, [Parameter(Mandatory = $true)] $queryType ) $retryCounter = 0 $retryRequired = $TRUE do { if ($queryType -eq $functionExchangeUser) { try { $returnObject = get-o365user -identity $objectID -ErrorAction Stop $global:userCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online User Object" out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeSharedMailbox) { try { $returnObject = get-o365Mailbox -identity $objectID -ErrorAction Stop $global:sharedMailboxCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Mailbox Object" out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeEquipmentMailbox) { try { $returnObject = get-o365Mailbox -identity $objectID -ErrorAction Stop $global:equipmentMailboxCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Mailbox Object" out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeRoomMailbox) { try { $returnObject = get-o365Mailbox -identity $objectID -ErrorAction Stop $global:roomMailboxCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Mailbox Object" out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeUserMailbox) { try { $returnObject = get-o365Mailbox -identity $objectID -ErrorAction Stop $global:userMailboxCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Mailbox Object" out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeMailUser) { try { $returnObject = get-o365MailUser -identity $objectID -ErrorAction Stop $global:mailUserCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Mail User Object" out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeGuestMailUser) { try { $returnObject = get-o365MailUser -identity $objectID -ErrorAction Stop $global:guestMailUserCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Guest Mail Object" out-logfile -string $_ -isError:$TRUE } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } elseif ($queryType -eq $functionExchangeMailContact) { try { $returnObject = get-o365contact -Identity $objectID -errorAction Stop $global:mailContactCounter+=$returnObject.exchangeObjectID $retryRequired = $FALSE } catch { $retryCounter++ if ($retryCounter -gt 4) { out-logfile -string "Unable to obtain Exchange Online Mail Contact Object" out-logfile -string $_ -isError:$TR } else { start-sleepProgress -sleepString "Error obtaining Exchange Online object - resetting connection." -sleepSeconds 60 disable-allPowerShellSessions reset-exchangeOnlinePowershell } } } } until ( $retryRequired -eq $FALSE ) return $returnObject } function get-GraphGroupMemberOf { Param ( [Parameter(Mandatory = $true)] $objectID ) $returnObjects = Get-MGGroupMemberOf -groupID $objectID -all -errorAction STOP return $returnObjects } function get-ExchangeGroupMemberOf { Param ( [Parameter(Mandatory = $true)] $distinguishedName ) $returnObjects = @() out-logfile -string "Entering get-ExchangeGroupMemberOF" $functionCommand = "Get-o365DistributionGroup -Filter { $exchangeMembersAttribute -eq `"$distinguishedName`" } -errorAction 'STOP'" out-logfile -string $functionCommand $scriptBlock=[scriptBlock]::create($functionCommand) try { $returnObjects += invoke-command -scriptBlock $scriptBlock } catch { out-logfile $_ out-logfile -string "Unable to obtain distribution group membership." -isError:$TRUE } return $returnObjects } #=============================================================================== #Graph Code #=============================================================================== if ($functionParamterSetName -eq $functionGraphName) { out-logfile -string "Entering graph processing..." switch ($objectType) { $functionGraphGroup { out-logfile -string $functionGraphGroup try { $functionObject = get-MGGroup -GroupId $objectID -ErrorAction Stop if ($functionObject.groupTypes -contains "DynamicMembership") { $global:msGraphObjects+=$functionObjects $global:msGraphGroupDynamicCount+=$functionObject.id } else { $global:msGraphObjects+=$functionObject $global:msGraphGroupCount+=$functionObject.id } } catch { out-logfile -string $_ out-logfile -string "Error obtaining group." -isError:$TRUE } } $functiongraphUser { out-logfile -string $functiongraphUser try { $functionObject = get-MGUser -userID $objectID -ErrorAction Stop $global:msGraphObjects+=$functionObject $global:msGraphUserCount+=$functionObject.id } catch { out-logfile -string $_ out-logfile -string "Error obtaining user." -isError:$TRUE } } $functionGraphContact { out-logfile -string $functionGraphContact try { $functionObject = get-MGContact -OrgContactId $objectID -errorAction Stop $global:msGraphObjects+=$functionObject $global:msGraphContactCount+=$functionObject.id } catch { out-logfile -string $_ out-logfile -string "Error obtaining contact." -isError:$TRUE } } Default { out-logfile -string "Default" out-logfile -string "Invalid object type discovered - contact support." -isError:$TRUE } } out-logfile -string $functionObject if (!$processedGroupIds.Contains($functionObject.Id)) { out-logfile -string "Group has not already been processed." $NULL = $processedGroupIds.add($functionObject.id) if ($objectType -eq $functionGraphGroup) { out-logfile -string "Object is a group - determining children." if ($expandGroupMembership -eq $TRUE) { if ($reverseHierarchy -eq $FALSE) { out-logfile -string "Full group membership expansion is enabled." try { $children = Get-MgGroupMember -GroupId $functionObject.Id -all -errorAction STOP } catch { out-logfile -string $_ out-logfile -string "Error obtaining group membership." -isError:$TRUE } } else { out-logfile -string "Full group membership expansion is enabled - reverse" try { $children = get-GraphGroupMemberOf -objectID $functionObject.id } catch { out-logfile -string $_ out-logfile -string "Error obtaining parent group membership." -isError:$TRUE } } } else { if ($reverseHierarchy -eq $FALSE) { out-logfile -string "Full group membership expansion disabled." try { $children = Get-MgGroupMember -GroupId $functionObject.Id -all -errorAction STOP | where {$_.AdditionalProperties.'@odata.type' -eq $functionGraphGroup} } catch { out-logfile -string $_ out-logfile -string "Error obtaining group membership." -isError:$TRUE } } else { out-logfile -string "Full group membership expansion disabled - reverse." try { $children = get-GraphGroupMemberOf -objectID $functionObject.id } catch { out-logfile -string $_ out-logfile -string "Error obtaining parent group membership." -isError:$TRUE } } } } else { out-logfile -string "Object is not a group - no children." $children=@() } foreach ($child in $children) { out-logfile -string "Processing child..." out-logfile -string $child.id $global:childGroupIDs = New-Object System.Collections.Generic.HashSet[string] $processedGroupIds $childNode = Get-GroupWithChildren -objectID $child.id -processedGroupIds $childGroupIDs -objectType $child.additionalProperties["@odata.type"] -queryMethodGraph:$true -expandGroupMembership $expandGroupMembership -reverseHierarchy $reverseHierarchy $childNodes += $childNode } } else { out-logfile -string "Group has already been processed." $functionObject.DisplayName = $functionObject.DisplayName + " (Circular Membership)" } $node = New-TreeNode -object $functionObject -children $childNodes } #=============================================================================== #Exchange Online Code #=============================================================================== elseif ($functionParamterSetName -eq $functionExchangeOnlineName) { out-logfile -string "Entering exchange online processing..." switch ($objectType) { $functionExchangeGroupMailbox { out-logfile -string $functionExchangeGroupMailbox $functionObject = get-ExchangeGroup -objectID $objectID -queryType $functionExchangeGroupMailbox $isExchangeGroupType=$TRUE $global:exchangeObjects += $functionObject } $functionExchangeRoomMailbox { out-logfile -string $functionExchangeRoomMailbox $functionObject = get-ExchangeUser -objectID $objectID -queryType $functionExchangeRoomMailbox $global:exchangeObjects += $functionObject } $functionExchangeSharedMailbox { out-logfile -string $functionExchangeSharedMailbox $functionObject = get-ExchangeUser -objectID $objectID -queryType $functionExchangeSharedMailbox $global:exchangeObjects += $functionObject } $functionExchangeEquipmentMailbox { out-logfile -string $functionExchangeEquipmentMailbox $functionObject = get-ExchangeUser -objectID $objectID -queryType $functionExchangeEquipmentMailbox $global:exchangeObjects += $functionObject } $functionExchangeUser { out-logfile -string $functionExchangeUser $functionObject = get-ExchangeUser -objectID $objectID -queryType $functionExchangeUser $global:exchangeObjects += $functionObject } $functionExchangeGroup { out-logfile -string $functionExchangeGroup $functionObject = get-ExchangeGroup -objectID $objectID -queryType $functionExchangeGroup $isExchangeGroupType=$TRUE $global:exchangeObjects += $functionObject } $functionExchangeMailUniversalSecurityGroup { out-logfile -string $functionExchangeMailUniversalSecurityGroup $functionObject = get-ExchangeGroup -objectID $objectID -queryType $functionExchangeMailUniversalSecurityGroup $isExchangeGroupType=$TRUE $global:exchangeObjects += $functionObject } $functionExchangeMailUniversalDistributionGroup { out-logfile -string $functionExchangeMailUniversalDistributionGroup $functionObject = get-ExchangeGroup -objectID $objectID -queryType $functionExchangeMailUniversalDistributionGroup $isExchangeGroupType=$TRUE $global:exchangeObjects += $functionObject } $functionExchangeUserMailbox { out-logfile -string $functionExchangeUserMailbox $functionObject = get-ExchangeUser -objectID $objectID -queryType $functionExchangeUserMailbox $global:exchangeObjects += $functionObject } $functionExchangeMailUser { out-logfile -string $functionExchangeMailUser $functionObject = get-ExchangeUser -objectID $objectID -queryType $functionExchangeMailUser $global:exchangeObjects += $functionObject } $functionExchangeGuestMailUser { out-logfile -string $functionExchangeGuestMailUser $functionObject = get-ExchangeUser -objectID $objectID -queryType $functionExchangeGuestMailUser $global:exchangeObjects += $functionObject } $functionExchangeMailContact { out-logfile -string $functionExchangeMailContact $functionObject = get-ExchangeUser -objectID $objectID -queryType $functionExchangeMailContact $global:exchangeObjects += $functionObject } $functionExchangeDynamicGroup { out-logfile -string $functionExchangeDynamicGroup $functionObject = get-ExchangeGroup -objectID $objectID -queryType $functionExchangeDynamicGroup $isExchangeGroupType=$TRUE $global:exchangeObjects += $functionObject } Default { out-logfile -string "Default" out-logfile -string "Invalid object type discovered - contact support." -isError:$TRUE } } out-logfile -string $functionObject out-logfile -string "Beginning object processing..." if (!$processedGroupIds.Contains($functionObject.ExchangeObjectID)) { out-logfile -string "Group has not already been processed." $NULL = $processedGroupIds.add($functionObject.ExchangeObjectID) out-logfile -string "Determine if object is an Exchange Group type and if so enumerate membership." out-logfile -string ("Exchange Group Type: "+$isExchangeGroupType) if ($isExchangeGroupType -eq $TRUE) { if ($functionObject.recipientTypeDetails -eq $functionExchangeDynamicGroup) { out-logfile -string "Group is a dynamic group - children determined by recipient filter." if ($reverseHierarchy -eq $false) { if ($expandDynamicGroupMembership -eq $TRUE) { out-logfile -string "Dynamic group membership expansion enabled." try { $children = get-o365Recipient -RecipientPreviewFilter $functionObject.RecipientFilter -resultsize unlimited -errorAction STOP } catch { out-logfile $_ out-logfile -string "Unable to obtain dynamic DL members by recipient filter preview." -isError:$TRUE } } else { out-logfile -string "Dynamic group membership expansion is disabled." $childern=@() } } else { out-logfile -string "Full group membership expansion is enabled - reverse." $children = get-ExchangeGroupMemberOf -distinguishedName $functionObject.distinguishedName } } elseif ($functionObject.recipientTypeDetails -ne $functionExchangeGroupMailbox) { out-logfile -string "Group is not a unified group or dynamic group - get standard membership." if ($expandGroupMembership -eq $TRUE) { if ($reverseHierarchy -eq $FALSE) { out-logfile -string "Full group membership expansion is enabled." try { $children = Get-o365distributionGroupMember -Identity $functionObject.ExchangeObjectID -resultSize unlimited -errorAction STOP } catch { out-logfile $_ out-logfile -string "Unable to obtain distribution group membership." -isError:$TRUE } } else { out-logfile -string "Full group membership expansion is enabled - reverse." $children = get-ExchangeGroupMemberOf -distinguishedName $functionObject.distinguishedName } } else { out-logfile -string "Full group membership expansion is disabled." if ($reverseHierarchy -eq $FALSE) { try { $children = Get-o365distributionGroupMember -Identity $functionObject.ExchangeObjectID -resultSize unlimited -errorAction STOP | where {($_.recipientTypeDetails -eq $functionExchangeMailUniversalSecurityGroup) -or ($_.recipientTypeDetails -eq $functionExchangeMailUniversalDistributionGroup) -or ($_.recipientTypeDetails -eq $functionExchangeGroupMailbox) -or ($_.recipientTypeDetails -eq $functionExchangeDynamicGroup)} } catch { out-logfile $_ out-logfile -string "Unable to obtain distribution group membership." -isError:$TRUE } } else { out-logfile -string "Full group membership expansion is enabled - reverse." $children = get-ExchangeGroupMemberOf -distinguishedName $functionObject.distinguishedName } } } else { out-logfile -string "Group is a unified group - perform link member query." if ($reverseHierarchy -eq $FALSE) { if ($expandGroupMembership -eq $TRUE) { out-logfile -string "Full group membership expansion is enabled." try { $children = get-o365UnifiedGroupLinks -identity $functionObject.ExchangeObjectID -linkType Member -resultSize unlimited -errorAction STOP } catch { out-logfile $_ out-logfile -string "Unable to obtain unified group membership." -isError:$TRUE } } else { out-logfile -string "Full group membership expansion is disabled." $children=@() } } else { out-logfile -string "Full group membership expansion is enabled - reverse." $children = get-ExchangeGroupMemberOf -distinguishedName $functionObject.distinguishedName } } } else { $children=@() } foreach ($child in $children) { out-logfile -string "Processing child..." out-logfile -string $child.ExchangeObjectID $childGroupIDs = New-Object System.Collections.Generic.HashSet[string] $processedGroupIds $childNode = Get-GroupWithChildren -objectID $child.ExchangeObjectID -processedGroupIds $childGroupIDs -objectType $child.RecipientTypeDetails -queryMethodExchangeOnline:$TRUE -expandGroupMembership $expandGroupMembership -expandDynamicGroupMembership $expandDynamicGroupMembership -reverseHierarchy $reverseHierarchy $childNodes += $childNode } } else { out-logfile -string "Group has already been processed." if ($functionObject.displayName -eq "") { $functionObject.displayName = $functionObject.name } elseif ($functionObject.displayName -eq $NULL) { $functionObject.displayName = $functionObject.name } $functionObject.DisplayName = $functionObject.DisplayName + " (Circular Membership)" } if ($functionObject.displayName -eq "") { $functionObject.displayName = $functionObject.name } elseif ($functionObject.displayName -eq $NULL) { $functionObject.displayName = $functionObject.name } $node = New-TreeNode -object $functionObject -children $childNodes } #=============================================================================== #LDAP Code #=============================================================================== elseif ($functionParamterSetName -eq $functionLDAPName) { out-logfile -string "Entering LDAP processing..." out-logfile -string "Obtaining group getting adobject." try{ $functionObject = get-adObject -identity $objectID -properties * -server $globalCatalogServer -Credential $activeDirectoryCredential -ErrorAction STOP $global:ldapObjects += $functionObject } catch { out-logfile -string $_ out-logfile -string "Unable to obtain the ad object by ID." -isError:$TRUE } if (($functionObject.objectClass -ne $functionLDAPDynamicGroup) -and ($functionObject.objectClass -ne $functionLDAPGroup) -and ($firstLDAPQuery -eq $TRUE)) { out-logfile -string $functionObject.objectClass out-logfile -string "Object specified is not a group or dynamic group." -isError:$TRUE } $childNodes = @() out-logfile -string $functionObject out-logfile -string "Beginning object processing..." if ($functionObject.objectClass -eq $functionLDAPDynamicGroup) { $global:dynamicGroupCounter+=$functionObject.objectGUID } elseif ($functionObject.objectClass -eq $functionLDAPContact) { $global:contactCounter+=$functionObject.objectGUID } elseif ($functionObject.objectClass -eq $functionLDAPUser) { $global:userCounter+=$functionObject.objectGUID } elseif ($functionObject.objectClass -eq $functionLDAPGroup) { out-logfile -string $functionObject.objectGUID $global:groupCounter+=$functionObject.objectGUID if ($functionObject.mail -ne $NULL) { $outputObject = New-Object PSObject -Property @{ ParentObjectGUID = $parentObjectID ObjectGUID = $functionObject.objectGUID CN = $functionObject.cn Mail = $functionObject.Mail NestingLevel = $global:childCounter.tostring() } $global:groupTracking+=$outputObject } else { $outputObject = New-Object PSObject -Property @{ ParentObjectGUID = $parentObjectID ObjectGUID = $functionObject.objectGUID CN = $functionObject.cn Mail = "CAUTION: Group in hierarchy with no mail address." NestingLevel = $global:childCounter.tostring() } $global:groupTracking+=$outputObject } } if ($reverseHierarchy -eq $FALSE) { $global:childCounter++ out-logfile -string ("Recursion Counter: "+$global:childCounter.tostring()) } else { $global:childCounter-- out-logfile -string ("Recursion Counter: "+$global:childCounter.tostring()) } if (!$processedGroupIds.Contains($functionObject.distinguishedName)) { out-logfile -string "Object has not been previously processed..." $NULL = $processedGroupIds.add($functionObject.distinguishedName) if ($functionObject.objectClass -eq $functionLDAPDynamicGroup) { out-logfile -string "Object class is dynamic group - members determined via query." if ($expandDynamicGroupMembership -eq $TRUE) { out-logfile -string "Dynamic group membership expansion enabled." if ($reverseHierarchy -eq $FALSE) { try { $children = Get-ADObject -LDAPFilter $functionObject.msExchDynamicDLFilter -SearchBase $functionObject.msExchDynamicDLBaseDN -Properties * -server $globalCatalogServer -Credential $activeDirectoryCredential -ErrorAction STOP } catch { out-logfile $_ out-logfile -string "Unable to obtain dynamic group membership via LDAP call." } out-logfile -string "Filter children to only contain users, groups, or contacts since LDAP query inclues all object classes." out-logfile -string $children.Count.tostring() $children = $children | where {($_.objectClass -eq $functionLDAPuser) -or ($_.objectClass -eq $functionLDAPGroup) -or ($_.objectClass -eq $functionLDAPContact) -or ($_.objectClass -eq $functionLDAPDynamicGroup)} out-logfile -string $children.Count.tostring() } else { out-logfile -string "Expand full group membership enabled." out-logfile -string "Reverse hierarchy in use." $children = $functionObject.memberof } } else { out-logfile -string "Dynamic group membership expansion disabled." $children = @() } } elseif ($functionObject.objectClass -eq $functionLDAPGroup ) { out-logfile -string "Object class id group - members determiend by member attribute on group." if ($expandGroupMembership -eq $TRUE) { if ($reverseHierarchy -eq $FALSE) { out-logfile -string "Expand full group membership enabled." out-logfile -string "Reverse hierarchy not in use." $children = $functionObject.member } else { out-logfile -string "Expand full group membership enabled." out-logfile -string "Reverse hierarchy in use." $children = $functionObject.memberof } } else { if ($reverseHierarchy -eq $FALSE) { out-logfile -string "Expand full group membership disabled." out-logfile -string "Reverse hierarchy not in use." out-logfile -string "Construct LDAP Filter" $groupLdapFilter = "(&(objectCategory=Group)(memberof="+$functionObject.distinguishedName+"))" out-logfile -string $groupLDAPFilter try { $children = get-adGroup -ldapFilter $groupLDAPFilter -server $globalCatalogServer -Credential $activeDirectoryCredential -ErrorAction STOP } catch { out-logfile -string $_ out-logfile "Unable to obtain group membership filtered by groups only." -isError:$TRUE } } else { out-logfile -string "Expand full group membership disabled." out-logfile -string "Reverse hierarchy in use." out-logfile -string "Construct LDAP Filter" $groupLdapFilter = "(&(objectCategory=Group)(member="+$functionObject.distinguishedName+"))" out-logfile -string $groupLDAPFilter try { $children = get-adGroup -ldapFilter $groupLDAPFilter -server $globalCatalogServer -Credential $activeDirectoryCredential -ErrorAction STOP } catch { out-logfile -string $_ out-logfile "Unable to obtain group membership filtered by groups only." -isError:$TRUE } } } } else { out-logfile -string "Object is not a dynamic group or group." $children=@() } foreach ($child in $children) { if ($reverseHierarchy -eq $FALSE) { write-host "ChildID" write-host $child $childGroupIDs = New-Object System.Collections.Generic.HashSet[string] $processedGroupIds $childNode = Get-GroupWithChildren -objectID $child -processedGroupIds $childGroupIDs -objectType "None" -globalCatalogServer $globalCatalogServer -activeDirectoryCredential $activeDirectoryCredential -queryMethodLDAP:$true -expandGroupMembership $expandGroupMembership -expandDynamicGroupMembership $expandDynamicGroupMembership -firstLDAPQuery $false -parentObjectID $functionObject.objectGUID $childNodes += $childNode } else { write-host "ChildID" write-host $child $childGroupIDs = New-Object System.Collections.Generic.HashSet[string] $processedGroupIds $childNode = Get-GroupWithChildren -objectID $child -processedGroupIds $childGroupIDs -objectType "None" -globalCatalogServer $globalCatalogServer -activeDirectoryCredential $activeDirectoryCredential -queryMethodLDAP:$true -expandGroupMembership $expandGroupMembership -expandDynamicGroupMembership $expandDynamicGroupMembership -firstLDAPQuery $false -reverseHierarchy:$TRUE -parentObjectID $functionObject.objectGUID $childNodes += $childNode } } } else { out-logfile -string "Group has already been processed." if ($functionObject.displayName -eq "") { $functionObject.displayName = $functionObject.name } elseif ($functionObject.displayname -eq $NULL) { $functionObject.displayName = $functionObject.name } $functionObject.DisplayName = $functionObject.DisplayName + " (Circular Membership)" } if ($functionObject.displayName -eq "") { $functionObject.displayName = $functionObject.name } elseif ($functionObject.displayname -eq $NULL) { $functionObject.displayName = $functionObject.name } $node = New-TreeNode -object $functionObject -children $childNodes } if ($reverseHierarchy -eq $FALSE) { $global:childCounter-- } else { $global:childCounter++ } out-logfile -string $global:childCounter.tostring() out-logfile -string "***********************************************************" out-logfile -string "Exiting Get-GroupWithChildren" out-logfile -string "***********************************************************" return $node } |