diff --git a/HelperFunctions.psm1 b/HelperFunctions.psm1 index 111e943..875bd6e 100644 --- a/HelperFunctions.psm1 +++ b/HelperFunctions.psm1 @@ -22,18 +22,24 @@ function Get-GraphRequestRecursive { [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1)] - [String] $Url + [String] $Url, + + # Graph headers + [Parameter(Mandatory = $false, + Position = 2)] + [Hashtable] $AdditionalHeaders = @{} ) - + Write-Debug "Fetching url $Url" - $Result = Invoke-RestMethod $Url -Headers @{Authorization = "Bearer $AccessToken" } -Verbose:$false + $Headers = @{Authorization = "Bearer $AccessToken" } + $AdditionalHeaders + $Result = Invoke-RestMethod $Url -Headers $Headers -Verbose:$false if ($Result.value) { $Result.value } # Calls itself when there is a nextlink, in order to get next page if ($Result.'@odata.nextLink') { - Get-GraphRequestRecursive -Url $Result.'@odata.nextLink' -AccessToken $AccessToken + Get-GraphRequestRecursive -Url $Result.'@odata.nextLink' -AccessToken $AccessToken -AdditionalHeaders $AdditionalHeaders } } diff --git a/README.md b/README.md index b82c241..e512158 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,8 @@ The following can be useful if you have multple Azure ADs or limitations in scop | AADGroupScopingConfig | 2 | Additional info required to determine groups (filter etc.) | id eq '' | | GroupDeprovisioningMethod | Yes | Determines what to do when source AAD group is deleted | Delete / ConvertToDistributionGroup / PrintWarning / DoNothing | | ADGroupNamePattern | No | Format string for AD group name, {0} = displayName from AAD, {1} = objectId from AAD, {2} = mailNickname from AAD | {0} ({1}) | -| Environment | No | Azure Environment (default to AzurePublic) | AzureCloud / AzureUSGovernment | +| Environment | No | Azure Environment (default to AzurePublic) | AzureCloud / AzureUSGovernment | +| TransitiveMembers | No | Retrieves a flat list of members from all child groups of the AAD group | true | 1. If AuthenticationMethod is ClientCredentials 2. If AADGroupScopingMethod is GroupMemberOfGroup or AADGroupScopingConfig @@ -193,4 +194,4 @@ PAM bastion forest support using the AD optional feature for PAM and msDS-Shadow ``` $of = get-ADOptionalFeature -filter "name -eq 'privileged access management feature'" Enable-ADOptionalFeature $of -scope ForestOrConfigurationSet -target ((Get-ADForest).RootDomain) -``` \ No newline at end of file +``` diff --git a/Run.ps1 b/Run.ps1 index 5939524..c461a37 100644 --- a/Run.ps1 +++ b/Run.ps1 @@ -95,8 +95,12 @@ $ErrorActionPreference = "Continue" # No need to fail hard anymore. This reduces Write-Verbose "Processing all memberships" Foreach($ScopedGroup in $ScopedGroups) { Write-Verbose " - Processing group '$($ScopedGroup.displayName)' ($($ScopedGroup.id))" - $Members = Get-GraphRequestRecursive -Url "$($graphEndpoints.GraphUrl)/v1.0/groups/$($ScopedGroup.id)/members?`$select=id,userType,displayName,userPrincipalName,onPremisesDistinguishedName,onPremisesImmutableId" -AccessToken $AccessToken - + if ($Config.TransitiveMembers -eq 'true') { + $Members = Get-GraphRequestRecursive -Url "$($graphEndpoints.GraphUrl)/v1.0/groups/$($ScopedGroup.id)/transitiveMembers/microsoft.graph.user?`$count=true&`$select=id,userType,displayName,userPrincipalName,onPremisesDistinguishedName,onPremisesImmutableId" -AccessToken $AccessToken -AdditionalHeaders @{ConsistencyLevel = 'eventual' } + } else { + $Members = Get-GraphRequestRecursive -Url "$($graphEndpoints.GraphUrl)/v1.0/groups/$($ScopedGroup.id)/members?`$select=id,userType,displayName,userPrincipalName,onPremisesDistinguishedName,onPremisesImmutableId" -AccessToken $AccessToken + } + # Get all onPremisesDistinguishedName values from AAD, which should be our correct list $ExpectedADMembers = $Members | Where-Object onPremisesDistinguishedName |