Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from KelvinTegelaar:master #2

Merged
merged 30 commits into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
87b601e
fix 404 links to the old docs site
kris6673 Oct 29, 2023
213fdee
Merge pull request #459 from kris6673/wiki-link-fix
KelvinTegelaar Oct 29, 2023
856752b
Fix OOO in Offboarding Wizard
Jr7468 Oct 30, 2023
decca17
BugFix: Get-CIPPMFAState outputting ints
AlexOSIT Oct 30, 2023
9b47590
Unbork Get-CIPPMFAState.ps1
AlexOSIT Oct 31, 2023
2cd3bec
little more sleep
KelvinTegelaar Nov 1, 2023
ac53cda
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP-API into…
KelvinTegelaar Nov 1, 2023
c406992
Merge pull request #460 from Jr7468/dev
KelvinTegelaar Nov 1, 2023
5095f79
Merge pull request #461 from officesolutions-it/dev
KelvinTegelaar Nov 1, 2023
64ee7bf
Add Get-CIPPPartnerAzSubscriptions.ps1
rvdwegen Nov 1, 2023
0b942ac
Fixed Typo :)
Jr7468 Nov 2, 2023
9a92a12
Merge pull request #463 from Jr7468/dev
KelvinTegelaar Nov 2, 2023
993c960
Merge pull request #462 from rvdwegen/patch-2
KelvinTegelaar Nov 2, 2023
fb98600
fix for blank tenants
KelvinTegelaar Nov 2, 2023
3f5cd04
Add or update the Azure App Service build and deployment workflow config
KelvinTegelaar Nov 2, 2023
6e52317
GDAP Invite Tweaks
JohnDuprey Nov 2, 2023
d1a733d
Merge pull request #464 from johnduprey/dev
KelvinTegelaar Nov 2, 2023
146f3ac
first version gdap check
KelvinTegelaar Nov 3, 2023
e6ef8c7
improved access checks
KelvinTegelaar Nov 3, 2023
e25eb59
adding links
KelvinTegelaar Nov 3, 2023
d5c7e98
added <12 group report
KelvinTegelaar Nov 3, 2023
a3df573
added count
KelvinTegelaar Nov 3, 2023
30eebcc
fixed bug
KelvinTegelaar Nov 3, 2023
2d55e5c
design changes
KelvinTegelaar Nov 3, 2023
7458433
minor text change
KelvinTegelaar Nov 3, 2023
4bbd618
Mailbox Restores
JohnDuprey Nov 3, 2023
1fcca38
Merge branch 'KelvinTegelaar:dev' into dev
JohnDuprey Nov 3, 2023
1e78706
upped to 4.5.5
KelvinTegelaar Nov 3, 2023
9902540
Merge pull request #465 from johnduprey/dev
KelvinTegelaar Nov 3, 2023
1c1f118
Merge pull request #466 from KelvinTegelaar/dev
KelvinTegelaar Nov 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/dev_cippb2p4g.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action
# More GitHub Actions for Azure: https://github.com/Azure/actions

name: Build and deploy Powershell project to Azure Function App - cippb2p4g

on:
push:
branches:
- dev
workflow_dispatch:

env:
AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root

jobs:
build-and-deploy:
runs-on: windows-latest
steps:
- name: 'Checkout GitHub Action'
uses: actions/checkout@v4

- name: 'Run Azure Functions Action'
uses: Azure/functions-action@v1
id: fa
with:
app-name: 'cippb2p4g'
slot-name: 'Production'
package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_C106B398356B4EFCB81F779ED5806A0D }}
254 changes: 5 additions & 249 deletions ExecAccessChecks/run.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,258 +10,14 @@ 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://cipp.app/docs/general/troubleshooting/#clear-token-cache'
}
) | 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://cipp.app/docs/general/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://cipp.app/docs/user/gettingstarted/postinstall/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
}
$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.' }
$Results = Test-CIPPAccessTenant -Tenantcsv $Request.body.TenantId
}
if ($Request.query.GDAP -eq 'true') {
$Results = Test-CIPPGDAPRelationships
}

$body = [pscustomobject]@{'Results' = $Results }
Expand Down
21 changes: 12 additions & 9 deletions ExecGDAPInvite/run.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,18 @@ $APIName = $TriggerMetadata.FunctionName
Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug'

$RoleMappings = $Request.body.gdapRoles
$Results = [System.Collections.ArrayList]@()
$Results = [System.Collections.Generic.List[string]]::new()
$InviteUrls = [System.Collections.Generic.List[string]]::new()

$Table = Get-CIPPTable -TableName 'GDAPInvites'
try {
$JSONBody = @{
'displayName' = "$((New-Guid).GUID)"
'partner' = @{
'tenantId' = "$env:tenantid"
}
'accessDetails' = @{
'displayName' = "$((New-Guid).GUID)"
'accessDetails' = @{
'unifiedRoles' = @($RoleMappings | Select-Object roleDefinitionId)
}
'duration' = 'P730D'
'autoExtendDuration' = 'P180D'
'duration' = 'P730D'
} | ConvertTo-Json -Depth 5 -Compress

$NewRelationship = New-GraphPostRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships' -type POST -body $JSONBody -verbose -tenantid $env:TenantID
Expand All @@ -40,6 +39,7 @@ try {

if ($NewRelationshipRequest.action -eq 'lockForApproval') {
$InviteUrl = "https://admin.microsoft.com/AdminPortal/Home#/partners/invitation/granularAdminRelationships/$($NewRelationship.id)"
$InviteUrls.Add($InviteUrl)

$InviteEntity = [PSCustomObject]@{
'PartitionKey' = 'invite'
Expand All @@ -58,9 +58,12 @@ try {
$Results.add('Error creating GDAP relationship')
}

Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created GDAP Invite - $InviteUrl" -Sev 'Debug'
Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created GDAP Invite - $InviteUrl" -Sev 'Info'

$body = @{Results = @($Results) }
$body = @{
Results = @($Results)
InviteUrls = @($InviteUrls)
}
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $body
Expand Down
6 changes: 3 additions & 3 deletions ExecGDAPInviteQueue/run.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Write-Host "PowerShell queue trigger function processed work item: $QueueItem"

$Table = Get-CIPPTable -TableName 'GDAPInvites'
$Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$QueueItem'"

$APINAME = 'GDAPInvites'
$RoleMappings = $Invite.RoleMappings | ConvertFrom-Json
Write-Host ($Invite | ConvertTo-Json -Compress)

Expand All @@ -27,9 +27,9 @@ foreach ($role in $RoleMappings) {
New-GraphPostRequest -NoAuthCheck $True -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$($QueueItem)/accessAssignments" -tenantid $env:TenantID -type POST -body $MappingBody -verbose
Start-Sleep -Milliseconds 100
} catch {
Write-LogMessage -API $APINAME -message "GDAP Group mapping failed - $($role.GroupId): $($_.Exception.Message)" -Sev 'Debug'
Write-LogMessage -API $APINAME -message "GDAP Group mapping failed - $($role.GroupId): $($_.Exception.Message)" -Sev Error
exit 1
}
Write-LogMessage -API $APINAME -message "Groups mapped for GDAP Relationship: $($GdapInvite.RowKey)"
Write-LogMessage -API $APINAME -message "Groups mapped for GDAP Relationship: $($GdapInvite.RowKey)" -Sev Info
}
Remove-AzDataTableEntity @Table -Entity $Invite
18 changes: 18 additions & 0 deletions ExecMailboxRestore/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1",
"entryPoint": "Receive-CippHttpTrigger",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": ["get", "post"]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
}
2 changes: 1 addition & 1 deletion ExecOffboardUser/run.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ try {
}

{ $_."OOO" -ne "" } {
Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -OOO $request.body.OOO -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser"
Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -InternalMessage $request.body.OOO -ExternalMessage $request.body.OOO -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser"
}
{ $_."forward" -ne "" } {
Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $request.body.forward -KeepCopy [bool]$request.body.keepCopy -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser"
Expand Down
Loading
Loading