From e6ef8c734a8f74f3197fdc1d0a549e4b0ee24e47 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 3 Nov 2023 15:53:25 +0100 Subject: [PATCH 1/7] improved access checks --- ExecAccessChecks/run.ps1 | 188 +----------------- .../Public/PermissionsTranslator.json | 9 + .../Public/Test-CIPPAccessPermissions.ps1 | 131 ++++++++++++ .../CIPPCore/Public/Test-CIPPAccessTenant.ps1 | 118 +++++++++++ .../Public/Test-CIPPGDAPRelationships.ps1 | 7 +- 5 files changed, 267 insertions(+), 186 deletions(-) create mode 100644 Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 create mode 100644 Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 diff --git a/ExecAccessChecks/run.ps1 b/ExecAccessChecks/run.ps1 index d9dd4990af89..0cc71645208e 100644 --- a/ExecAccessChecks/run.ps1 +++ b/ExecAccessChecks/run.ps1 @@ -10,196 +10,16 @@ Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -m # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' if ($Request.query.Permissions -eq 'true') { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Started permissions check' -Sev 'Debug' - $Messages = [System.Collections.Generic.List[string]]::new() - $MissingPermissions = [System.Collections.Generic.List[string]]::new() - $Links = [System.Collections.Generic.List[object]]::new() - $AccessTokenDetails = [PSCustomObject]@{ - AppId = '' - AppName = '' - Audience = '' - AuthMethods = '' - IPAddress = '' - Name = '' - Scope = '' - TenantId = '' - UserPrincipalName = '' - } - $Success = $true - try { - Set-Location (Get-Item $PSScriptRoot).Parent.FullName - $ExpectedPermissions = Get-Content '.\Cache_SAMSetup\SAMManifest.json' | ConvertFrom-Json - - $GraphToken = Get-GraphToken -returnRefresh $true - if ($GraphToken) { - $GraphPermissions = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/myorganization/applications?`$filter=appId eq '$env:ApplicationID'" -NoAuthCheck $true - } - if ($env:MSI_SECRET) { - try { - Disable-AzContextAutosave -Scope Process | Out-Null - $AzSession = Connect-AzAccount -Identity - - $KV = $ENV:WEBSITE_DEPLOYMENT_ID - $KeyVaultRefresh = Get-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -AsPlainText - if ($ENV:RefreshToken -ne $KeyVaultRefresh) { - $Success = $false - $Messages.Add('Your refresh token does not match key vault, clear your cache or wait 30 minutes.') | Out-Null - $Links.Add([PSCustomObject]@{ - Text = 'Clear Token Cache' - Href = 'https://docs.cipp.app/setup/installation/cleartokencache' - } - ) | Out-Null - } - else { - $Messages.Add('Your refresh token matches key vault.') | Out-Null - } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Key vault exception: $($_) " -Sev 'Error' - } - } - - try { - $AccessTokenDetails = Read-JwtAccessDetails -Token $GraphToken.access_token -erroraction SilentlyContinue - } - catch { - $AccessTokenDetails = [PSCustomObject]@{ - Name = '' - AuthMethods = @() - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Token exception: $($_) " -Sev 'Error' - $Success = $false - } - - if ($AccessTokenDetails.Name -eq '') { - $Messages.Add('Your refresh token is invalid, check for line breaks or missing characters.') | Out-Null - $Success = $false - } - else { - if ($AccessTokenDetails.AuthMethods -contains 'mfa') { - $Messages.Add('Your access token contains the MFA claim.') | Out-Null - } - else { - $Messages.Add('Your access token does not contain the MFA claim, Refresh your SAM tokens.') | Out-Null - $Success = $false - $Links.Add([PSCustomObject]@{ - Text = 'MFA Troubleshooting' - Href = 'https://docs.cipp.app/troubleshooting/troubleshooting#multi-factor-authentication-troubleshooting' - } - ) | Out-Null - } - } - - $MissingPermissions = $ExpectedPermissions.requiredResourceAccess.ResourceAccess.id | Where-Object { $_ -notin $GraphPermissions.requiredResourceAccess.ResourceAccess.id } - if ($MissingPermissions) { - $Translator = Get-Content '.\Cache_SAMSetup\PermissionsTranslator.json' | ConvertFrom-Json - $TranslatedPermissions = $Translator | Where-Object id -In $MissingPermissions | ForEach-Object { "$($_.value) - $($_.Origin)" } - $MissingPermissions = @($TranslatedPermissions) - $Success = $false - $Links.Add([PSCustomObject]@{ - Text = 'Permissions' - Href = 'https://docs.cipp.app/setup/installation/permissions' - } - ) | Out-Null - } - else { - $Messages.Add('Your Secure Application Model has all required permissions') | Out-Null - } - $CIPPGroupCount = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/`$count?`$filter=startsWith(displayName,'M365 GDAP')" -NoAuthCheck $true -ComplexFilter - $SAMUserMemberships = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/me/memberOf?$select=id,displayName,isAssignableToRole' -NoAuthCheck $true - $ExpectedGroups = @( - 'AdminAgents', - 'M365 GDAP Application Administrator', - 'M365 GDAP User Administrator', - 'M365 GDAP Intune Administrator', - 'M365 GDAP Exchange Administrator', - 'M365 GDAP Security Administrator', - 'M365 GDAP Cloud App Security Administrator', - 'M365 GDAP Cloud Device Administrator', - 'M365 GDAP Teams Administrator', - 'M365 GDAP Sharepoint Administrator', - 'M365 GDAP Authentication Policy Administrator', - 'M365 GDAP Privileged Role Administrator', - 'M365 GDAP Privileged Authentication Administrator' - ) - $RoleAssignableGroups = $SAMUserMemberships | Where-Object { $_.isAssignableToRole } - $NestedGroups = foreach ($Group in $RoleAssignableGroups) { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($Group.id)/memberOf?`$select=id,displayName" -NoAuthCheck $true - } - - $MissingGroups = [System.Collections.Generic.List[string]]::new() - foreach ($Group in $ExpectedGroups) { - $GroupFound = $false - foreach ($Membership in ($SAMUserMemberships + $NestedGroups)) { - if ($Membership.displayName -match $Group -and (($CIPPGroupCount -gt 0 -and $Group -match 'M365 GDAP') -or $Group -notmatch 'M365 GDAP')) { - $GroupFound = $true - } - } - if (-not $GroupFound) { - $MissingGroups.Add($Group) - } - } - if (($MissingGroups | Measure-Object).Count -eq 0) { - $Messages.Add('The SAM user has all the required groups') - } - else { - $Success = $false - } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Permissions check failed: $($_) " -Sev 'Error' - $Messages.Add("We could not connect to the API to retrieve the permissions. There might be a problem with the secure application model configuration. The returned error is: $(Get-NormalizedError -message $_)") | Out-Null - $Success = $false - } - - $Results = [PSCustomObject]@{ - AccessTokenDetails = $AccessTokenDetails - Messages = @($Messages) - MissingPermissions = @($MissingPermissions) - MissingGroups = @($MissingGroups) - Memberships = @($SAMUserMemberships) - CIPPGroupCount = $CIPPGroupCount - Links = @($Links) - Success = $Success - } + $Results = Test-CIPPAccessPermissions -tenantfilter $ENV:tenantid -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' } if ($Request.query.Tenants -eq 'true') { - $ExpectedRoles = @( - @{ Name = 'Application Administrator'; Id = '9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3' }, - @{ Name = 'User Administrator'; Id = 'fe930be7-5e62-47db-91af-98c3a49a38b1' }, - @{ Name = 'Intune Administrator'; Id = '3a2c62db-5318-420d-8d74-23affee5d9d5' }, - @{ Name = 'Exchange Administrator'; Id = '29232cdf-9323-42fd-ade2-1d097af3e4de' }, - @{ Name = 'Security Administrator'; Id = '194ae4cb-b126-40b2-bd5b-6091b380977d' }, - @{ Name = 'Cloud App Security Administrator'; Id = '892c5842-a9a6-463a-8041-72aa08ca3cf6' }, - @{ Name = 'Cloud Device Administrator'; Id = '7698a772-787b-4ac8-901f-60d6b08affd2' }, - @{ Name = 'Teams Administrator'; Id = '69091246-20e8-4a56-aa4d-066075b2a7a8' }, - @{ Name = 'Sharepoint Administrator'; Id = 'f28a1f50-f6e7-4571-818b-6a12f2af6b6c' }, - @{ Name = 'Authentication Policy Administrator'; Id = '0526716b-113d-4c15-b2c8-68e3c22b9f80' }, - @{ Name = 'Privileged Role Administrator'; Id = 'e8611ab8-c189-46e8-94e1-60213ab1f814' }, - @{ Name = 'Privileged Authentication Administrator'; Id = '7be44c8a-adaf-4e2a-84d6-ab2649e08a13' } - ) - $Tenants = ($Request.body.tenantid).split(',') - if (!$Tenants) { $results = 'Could not load the tenants list from cache. Please run permissions check first, or visit the tenants page.' } - $TenantList = Get-Tenants - $TenantIds = foreach ($Tenant in $Tenants) { - ($TenantList | Where-Object { $_.defaultDomainName -eq $Tenant }).customerId - } - try { - $MyRoles = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/myRoles?`$filter=tenantId in ('$($TenantIds -join "','")')" - } - catch { - $MyRoles = $null - } - $results = foreach ($tenant in $Tenants) { - Test-CIPPTenantAccess -TenantFilter $Tenant -Myroles $Myroles -ExpectedRoles $ExpectedRoles - } - if (!$Tenants) { $results = 'Could not load the tenants list from cache. Please run permissions check first, or visit the tenants page.' } + $Results = Test-CIPPAccessTenant -Tenantcsv $Request.body.TenantId } - if ($Request.query.GDAP -eq 'true') { - $Results = Test-CIPPGDAPConnection + $Results = Test-CIPPGDAPRelationships } + $body = [pscustomobject]@{'Results' = $Results } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/PermissionsTranslator.json b/Modules/CIPPCore/Public/PermissionsTranslator.json index a38d0786d5f1..a0ba05d3dc02 100644 --- a/Modules/CIPPCore/Public/PermissionsTranslator.json +++ b/Modules/CIPPCore/Public/PermissionsTranslator.json @@ -5312,5 +5312,14 @@ "userConsentDescription": "Access Microsoft Teams and Skype for Business data as the signed in user", "userConsentDisplayName": "Access Microsoft Teams and Skype for Business data based on the user's role membership", "value": "user_impersonation" + }, + { + "description": "Read and write all on-premises directory synchronization information", + "displayName": "Read and write all on-premises directory synchronization information", + "id": "c2d95988-7604-4ba1-aaed-38a5f82a51c7", + "Origin": "Delegated", + "userConsentDescription": "Access Microsoft Teams and Skype for Business data as the signed in user", + "userConsentDisplayName": "Access Microsoft Teams and Skype for Business data based on the user's role membership", + "value": "OnPremDirectorySynchronization.ReadWrite.All" } ] diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 new file mode 100644 index 000000000000..971753f68d40 --- /dev/null +++ b/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 @@ -0,0 +1,131 @@ +function Test-CIPPAccessPermissions { + [CmdletBinding()] + param ( + $TenantFilter, + $APIName = "Access Check", + $ExecutingUser + ) + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Started permissions check' -Sev 'Debug' + $Messages = [System.Collections.Generic.List[string]]::new() + $MissingPermissions = [System.Collections.Generic.List[string]]::new() + $Links = [System.Collections.Generic.List[object]]::new() + $AccessTokenDetails = [PSCustomObject]@{ + AppId = '' + AppName = '' + Audience = '' + AuthMethods = '' + IPAddress = '' + Name = '' + Scope = '' + TenantId = '' + UserPrincipalName = '' + } + Write-Host "Setting success to true by default." + $Success = $true + try { + Set-Location (Get-Item $PSScriptRoot).FullName + $ExpectedPermissions = Get-Content '.\SAMManifest.json' | ConvertFrom-Json + + $GraphToken = Get-GraphToken -returnRefresh $true + if ($GraphToken) { + $GraphPermissions = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/myorganization/applications?`$filter=appId eq '$env:ApplicationID'" -NoAuthCheck $true + } + if ($env:MSI_SECRET) { + try { + Disable-AzContextAutosave -Scope Process | Out-Null + $AzSession = Connect-AzAccount -Identity + + $KV = $ENV:WEBSITE_DEPLOYMENT_ID + $KeyVaultRefresh = Get-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -AsPlainText + if ($ENV:RefreshToken -ne $KeyVaultRefresh) { + Write-Host "Setting success to false due to nonmaching token." + + $Success = $false + $Messages.Add('Your refresh token does not match key vault, clear your cache or wait 30 minutes.') | Out-Null + $Links.Add([PSCustomObject]@{ + Text = 'Clear Token Cache' + Href = 'https://docs.cipp.app/setup/installation/cleartokencache' + } + ) | Out-Null + } + else { + $Messages.Add('Your refresh token matches key vault.') | Out-Null + } + } + catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Key vault exception: $($_) " -Sev 'Error' + } + } + + try { + $AccessTokenDetails = Read-JwtAccessDetails -Token $GraphToken.access_token -erroraction SilentlyContinue + } + catch { + $AccessTokenDetails = [PSCustomObject]@{ + Name = '' + AuthMethods = @() + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Token exception: $($_) " -Sev 'Error' + $Success = $false + Write-Host "Setting success to false due to not able to decode token." + + } + + if ($AccessTokenDetails.Name -eq '') { + $Messages.Add('Your refresh token is invalid, check for line breaks or missing characters.') | Out-Null + Write-Host "Setting success to false invalid token." + + $Success = $false + } + else { + if ($AccessTokenDetails.AuthMethods -contains 'mfa') { + $Messages.Add('Your access token contains the MFA claim.') | Out-Null + } + else { + $Messages.Add('Your access token does not contain the MFA claim, Refresh your SAM tokens.') | Out-Null + Write-Host "Setting success to False due to invalid list of claims." + + $Success = $false + $Links.Add([PSCustomObject]@{ + Text = 'MFA Troubleshooting' + Href = 'https://docs.cipp.app/troubleshooting/troubleshooting#multi-factor-authentication-troubleshooting' + } + ) | Out-Null + } + } + + $MissingPermissions = $ExpectedPermissions.requiredResourceAccess.ResourceAccess.id | Where-Object { $_ -notin $GraphPermissions.requiredResourceAccess.ResourceAccess.id } + if ($MissingPermissions) { + Write-Host "Setting success to False due to permissions issues: $($MissingPermissions | ConvertTo-Json)" + + $Translator = Get-Content '.\PermissionsTranslator.json' | ConvertFrom-Json + $TranslatedPermissions = $Translator | Where-Object id -In $MissingPermissions | ForEach-Object { "$($_.value) - $($_.Origin)" } + $MissingPermissions = @($TranslatedPermissions) + $Success = $false + $Links.Add([PSCustomObject]@{ + Text = 'Permissions' + Href = 'https://docs.cipp.app/setup/installation/permissions' + } + ) | Out-Null + } + else { + $Messages.Add('Your Secure Application Model has all required permissions') | Out-Null + } + + } + catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Permissions check failed: $($_) " -Sev 'Error' + $Messages.Add("We could not connect to the API to retrieve the permissions. There might be a problem with the secure application model configuration. The returned error is: $(Get-NormalizedError -message $_)") | Out-Null + Write-Host "Setting success to False due to not being able to connect." + + $Success = $false + } + + return [PSCustomObject]@{ + AccessTokenDetails = $AccessTokenDetails + Messages = @($Messages) + MissingPermissions = @($MissingPermissions) + Links = @($Links) + Success = $Success + } +} diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 new file mode 100644 index 000000000000..677b642e24c0 --- /dev/null +++ b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 @@ -0,0 +1,118 @@ +function Test-CIPPAccessTenant { + [CmdletBinding()] + param ( + $TenantCSV, + $APIName = "Access Check", + $ExecutingUser + ) + $ExpectedRoles = @( + @{ Name = 'Application Administrator'; Id = '9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3' }, + @{ Name = 'User Administrator'; Id = 'fe930be7-5e62-47db-91af-98c3a49a38b1' }, + @{ Name = 'Intune Administrator'; Id = '3a2c62db-5318-420d-8d74-23affee5d9d5' }, + @{ Name = 'Exchange Administrator'; Id = '29232cdf-9323-42fd-ade2-1d097af3e4de' }, + @{ Name = 'Security Administrator'; Id = '194ae4cb-b126-40b2-bd5b-6091b380977d' }, + @{ Name = 'Cloud App Security Administrator'; Id = '892c5842-a9a6-463a-8041-72aa08ca3cf6' }, + @{ Name = 'Cloud Device Administrator'; Id = '7698a772-787b-4ac8-901f-60d6b08affd2' }, + @{ Name = 'Teams Administrator'; Id = '69091246-20e8-4a56-aa4d-066075b2a7a8' }, + @{ Name = 'Sharepoint Administrator'; Id = 'f28a1f50-f6e7-4571-818b-6a12f2af6b6c' }, + @{ Name = 'Authentication Policy Administrator'; Id = '0526716b-113d-4c15-b2c8-68e3c22b9f80' }, + @{ Name = 'Privileged Role Administrator'; Id = 'e8611ab8-c189-46e8-94e1-60213ab1f814' }, + @{ Name = 'Privileged Authentication Administrator'; Id = '7be44c8a-adaf-4e2a-84d6-ab2649e08a13' } + ) + $Tenants = ($TenantCSV).split(',') + if (!$Tenants) { $results = 'Could not load the tenants list from cache. Please run permissions check first, or visit the tenants page.' } + $TenantList = Get-Tenants + $TenantIds = foreach ($Tenant in $Tenants) { + ($TenantList | Where-Object { $_.defaultDomainName -eq $Tenant }).customerId + } + $MyRoles = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/myRoles?`$filter=tenantId in ('$($TenantIds -join "','")')" + $results = foreach ($tenant in $Tenants) { + $AddedText = '' + try { + $TenantId = ($TenantList | Where-Object { $_.defaultDomainName -eq $tenant }).customerId + $Assignments = ($MyRoles | Where-Object { $_.tenantId -eq $TenantId }).assignments + $SAMUserRoles = ($Assignments | Where-Object { $_.assignmentType -eq 'granularDelegatedAdminPrivileges' }).roles + + $BulkRequests = $ExpectedRoles | ForEach-Object { @( + @{ + id = "roleManagement_$($_.id)" + method = 'GET' + url = "roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '$($_.id)'&`$expand=principal" + } + ) + } + $GDAPRolesGraph = New-GraphBulkRequest -tenantid $tenant -Requests $BulkRequests + $GDAPRoles = [System.Collections.Generic.List[object]]::new() + $MissingRoles = [System.Collections.Generic.List[object]]::new() + foreach ($RoleId in $ExpectedRoles) { + $GraphRole = $GDAPRolesGraph.body.value | Where-Object -Property roleDefinitionId -EQ $RoleId.Id + $Role = $GraphRole.principal | Where-Object -Property organizationId -EQ $ENV:tenantid + $SAMRole = $SAMUserRoles | Where-Object -Property templateId -EQ $RoleId.Id + if (!$Role) { + $MissingRoles.Add( + [PSCustomObject]@{ + Name = $RoleId.Name + Type = 'Tenant' + } + ) + $AddedText = 'but missing GDAP roles' + } + else { + $GDAPRoles.Add([PSCustomObject]$RoleId) + } + if (!$SAMRole) { + $MissingRoles.Add( + [PSCustomObject]@{ + Name = $RoleId.Name + Type = 'SAM User' + } + ) + $AddedText = 'but missing GDAP roles' + } + } + if (!($MissingRoles | Measure-Object).Count -gt 0) { + $MissingRoles = $true + } + @{ + TenantName = "$($Tenant)" + Status = "Successfully connected $($AddedText)" + GDAPRoles = $GDAPRoles + MissingRoles = $MissingRoles + SAMUserRoles = $SAMUserRoles + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message 'Tenant access check executed successfully' -Sev 'Info' + + } + catch { + @{ + TenantName = "$($tenant)" + Status = "Failed to connect: $(Get-NormalizedError -message $_.Exception.Message)" + GDAP = '' + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Tenant access check failed: $(Get-NormalizedError -message $_) " -Sev 'Error' + + } + + try { + $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig' -ErrorAction Stop + @{ + TenantName = "$($Tenant)" + Status = 'Successfully connected to Exchange' + } + + } + catch { + $ReportedError = ($_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue) + $Message = if ($ReportedError.error.details.message) { $ReportedError.error.details.message } else { $ReportedError.error.innererror.internalException.message } + if ($null -eq $Message) { $Message = $($_.Exception.Message) } + @{ + TenantName = "$($Tenant)" + Status = "Failed to connect to Exchange: $(Get-NormalizedError -message $Message)" + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Tenant access check for Exchange failed: $(Get-NormalizedError -message $Message) " -Sev 'Error' + } + } + if (!$Tenants) { $results = 'Could not load the tenants list from cache. Please run permissions check first, or visit the tenants page.' } + + return $results +} diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index ac202ac4a517..253cf0fd79a2 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -1,4 +1,4 @@ -function Test-CIPPTenantAccess { +function Test-CIPPGDAPRelationships { [CmdletBinding()] param ( $TenantFilter, @@ -77,6 +77,9 @@ function Test-CIPPTenantAccess { } return [PSCustomObject]@{ - GDAPIssues = @($GDAPissues) + GDAPIssues = @($GDAPissues) + MissingGroups = @($MissingGroups) + Memberships = @($SAMUserMemberships) + CIPPGroupCount = $CIPPGroupCount } } From e25eb591e66f3624488f94332c4bfbafb6e6555a Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 3 Nov 2023 17:53:11 +0100 Subject: [PATCH 2/7] adding links --- Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index 253cf0fd79a2..55b1e2d8df1e 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -19,6 +19,7 @@ function Test-CIPPGDAPRelationships { Issue = "This tenant only has a MLT(Microsoft Led Transition) relationship. This is a read-only relationship. You must migrate this tenant to GDAP." Tenant = $Tenant.Group.customer.displayName Relationship = $Tenant.Group.displayName + Link = "https://docs.cipp.app/setup/gdap/index" }) | Out-Null } foreach ($Group in $Tenant.Group) { @@ -28,6 +29,8 @@ function Test-CIPPGDAPRelationships { Issue = "The relationship for $($Tenant.Group.customer.displayName) has global administrator access. This relationship is not available for auto-extend." Tenant = $Tenant.Group.customer.displayName Relationship = $group.displayName + Link = "https://docs.cipp.app/setup/gdap/troubleshooting#autoextend" + }) | Out-Null } } @@ -67,6 +70,8 @@ function Test-CIPPGDAPRelationships { Issue = "$($Group) cannot be found in your tenant. If you have migrated outside of CIPP this is to be expected. Please perform an access check to make sure you have the correct set of permissions." Tenant = "*Partner Tenant" Relationship = "None" + Link = "https://docs.cipp.app/setup/gdap/troubleshooting#groups" + }) | Out-Null } } From d5c7e98e8ede7ecafb7d77dd13ef425c753d0a2e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 3 Nov 2023 18:17:20 +0100 Subject: [PATCH 3/7] added <12 group report --- .../CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index 55b1e2d8df1e..6d4e3af7dac1 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -36,6 +36,7 @@ function Test-CIPPGDAPRelationships { } } + $me = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/me?$select=UserPrincipalName' -NoAuthCheck $true).UserPrincipalName $CIPPGroupCount = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/`$count?`$filter=startsWith(displayName,'M365 GDAP')" -NoAuthCheck $true -ComplexFilter $SAMUserMemberships = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/me/memberOf?$select=id,displayName,isAssignableToRole' -NoAuthCheck $true $ExpectedGroups = @( @@ -67,7 +68,17 @@ function Test-CIPPGDAPRelationships { if (-not $GroupFound) { $GDAPissues.add([PSCustomObject]@{ Type = "Warning" - Issue = "$($Group) cannot be found in your tenant. If you have migrated outside of CIPP this is to be expected. Please perform an access check to make sure you have the correct set of permissions." + Issue = "$($Group) is not assigned to the SAM user $me. If you have migrated outside of CIPP this is to be expected. Please perform an access check to make sure you have the correct set of permissions." + Tenant = "*Partner Tenant" + Relationship = "None" + Link = "https://docs.cipp.app/setup/gdap/troubleshooting#groups" + + }) | Out-Null + } + if ($CIPPGroupCount -lt 12) { + $GDAPissues.add([PSCustomObject]@{ + Type = "Warning" + Issue = "We could not find all 12 recommended CIPP groups. If you have migrated outside of CIPP this is to be expected. Please perform an access check to make sure you have the correct set of permissions." Tenant = "*Partner Tenant" Relationship = "None" Link = "https://docs.cipp.app/setup/gdap/troubleshooting#groups" From a3df5735d0d49253e7a8c1cb4d291ab3aefb2b45 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 3 Nov 2023 18:18:06 +0100 Subject: [PATCH 4/7] added count --- Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index 6d4e3af7dac1..d1e2da39827e 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -78,7 +78,7 @@ function Test-CIPPGDAPRelationships { if ($CIPPGroupCount -lt 12) { $GDAPissues.add([PSCustomObject]@{ Type = "Warning" - Issue = "We could not find all 12 recommended CIPP groups. If you have migrated outside of CIPP this is to be expected. Please perform an access check to make sure you have the correct set of permissions." + Issue = "We only found $($CIPPGroupCount) of the 12 required groups. If you have migrated outside of CIPP this is to be expected. Please perform an access check to make sure you have the correct set of permissions." Tenant = "*Partner Tenant" Relationship = "None" Link = "https://docs.cipp.app/setup/gdap/troubleshooting#groups" From 30eebcc562ee2c6d86bdbfedf2964247ab7526b4 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 3 Nov 2023 18:33:37 +0100 Subject: [PATCH 5/7] fixed bug --- Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index d1e2da39827e..3501b7dae8ab 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -23,7 +23,7 @@ function Test-CIPPGDAPRelationships { }) | Out-Null } foreach ($Group in $Tenant.Group) { - if ("62e90394-69f5-4237-9190-012177145e10" -in $Group.accessDetails) { + if ("62e90394-69f5-4237-9190-012177145e10" -in $Group.accessDetails.unifiedRoles.roleDefinitionId) { $GDAPissues.add([PSCustomObject]@{ Type = "Warning" Issue = "The relationship for $($Tenant.Group.customer.displayName) has global administrator access. This relationship is not available for auto-extend." From 2d55e5cd6fe02405748ccf81c299f86c8ab9a452 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 3 Nov 2023 18:39:57 +0100 Subject: [PATCH 6/7] design changes --- Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index 3501b7dae8ab..65ae1519c540 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -26,9 +26,9 @@ function Test-CIPPGDAPRelationships { if ("62e90394-69f5-4237-9190-012177145e10" -in $Group.accessDetails.unifiedRoles.roleDefinitionId) { $GDAPissues.add([PSCustomObject]@{ Type = "Warning" - Issue = "The relationship for $($Tenant.Group.customer.displayName) has global administrator access. This relationship is not available for auto-extend." - Tenant = $Tenant.Group.customer.displayName - Relationship = $group.displayName + Issue = "The relationship has global administrator access. This relationship is not available for Auto-Extend." + Tenant = $Tenant.Group.customer.displayName | Out-String + Relationship = $group.displayName | Out-String Link = "https://docs.cipp.app/setup/gdap/troubleshooting#autoextend" }) | Out-Null From 7458433c7d56d0e299fcb433422bd23025927cad Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 3 Nov 2023 18:44:49 +0100 Subject: [PATCH 7/7] minor text change --- Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index 65ae1519c540..cf2bacb49e68 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -26,7 +26,7 @@ function Test-CIPPGDAPRelationships { if ("62e90394-69f5-4237-9190-012177145e10" -in $Group.accessDetails.unifiedRoles.roleDefinitionId) { $GDAPissues.add([PSCustomObject]@{ Type = "Warning" - Issue = "The relationship has global administrator access. This relationship is not available for Auto-Extend." + Issue = "The relationship has global administrator access. Auto-Extend is not available." Tenant = $Tenant.Group.customer.displayName | Out-String Relationship = $group.displayName | Out-String Link = "https://docs.cipp.app/setup/gdap/troubleshooting#autoextend"