From 3d95b6f171365fedbc8f0593d7144bb5f56880db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 12 Dec 2023 23:21:52 +0100 Subject: [PATCH 1/6] Update enabled shared mailbox report --- .../Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 index 4f5bffce19f1..683f05eed5a1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 @@ -20,10 +20,10 @@ Function Invoke-ListSharedMailboxAccountEnabled { # Get Shared Mailbox Stuff try { $SharedMailboxList = (New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($TenantFilter)/Mailbox?`$filter=RecipientTypeDetails eq 'SharedMailbox'" -Tenantid $TenantFilter -scope ExchangeOnline) - $AllUsersAccountState = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?select=id,userPrincipalName,accountEnabled,displayName,givenName,surname' -tenantid $Tenantfilter + $AllUsersAccountState = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?select=id,userPrincipalName,accountEnabled,displayName,givenName,surname,onPremisesSyncEnabled' -tenantid $Tenantfilter $EnabledUsersWithSharedMailbox = foreach ($SharedMailbox in $SharedMailboxList) { # Match the User - $User = $AllUsersAccountState | Where-Object { $_.userPrincipalName -eq $SharedMailbox.userPrincipalName } | Select-Object -Property id, userPrincipalName, accountEnabled, displayName, givenName, surname -First 1 + $User = $AllUsersAccountState | Where-Object { $_.userPrincipalName -eq $SharedMailbox.userPrincipalName } | Select-Object -Property id, userPrincipalName, accountEnabled, displayName, givenName, surname, onPremisesSyncEnabled -First 1 if ($User.accountEnabled) { $User | Select-Object ` @{Name = 'UserPrincipalName'; Expression = { $User.UserPrincipalName } }, ` @@ -31,7 +31,8 @@ Function Invoke-ListSharedMailboxAccountEnabled { @{Name = 'givenName'; Expression = { $User.givenName } }, @{Name = 'surname'; Expression = { $User.surname } }, @{Name = 'accountEnabled'; Expression = { $User.accountEnabled } }, - @{Name = 'id'; Expression = { $User.id } } + @{Name = 'id'; Expression = { $User.id } }, + @{Name = 'onPremisesSyncEnabled'; Expression = { $User.onPremisesSyncEnabled } } } } From 1e5fd44a0de29331a9e335b8e24aca26d29bb0b5 Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Wed, 13 Dec 2023 00:04:32 +0100 Subject: [PATCH 2/6] Update Revoke-CIPPSessions.ps1 --- Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 b/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 index bc1234fd05e6..a43996e3fe68 100644 --- a/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 +++ b/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 @@ -15,7 +15,7 @@ function Revoke-CIPPSessions { } catch { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Revoked sessions for $($username)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to revoke sessions for $($username): $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter return "Revoke Session Failed: $($_.Exception.Message)" } } From e0ce82b8196e8e63423c7763f707632343830ff0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 13 Dec 2023 08:09:30 -0500 Subject: [PATCH 3/6] Tenant onboarding Add http entrypoint for initiating onboarding Add queue entrypoint for processing onboarding Allow for invites to be processed as a function or queue --- ExecGDAPInviteQueue/run.ps1 | 28 +----- .../Entrypoints/Invoke-ExecOnboardTenant.ps1 | 87 +++++++++++++++++++ .../Entrypoints/Invoke-ListGDAPInvite.ps1 | 7 +- .../Public/Set-CIPPGDAPInviteGroups.ps1 | 46 ++++++++-- 4 files changed, 128 insertions(+), 40 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOnboardTenant.ps1 diff --git a/ExecGDAPInviteQueue/run.ps1 b/ExecGDAPInviteQueue/run.ps1 index 87fd14236b3c..1b95a443bab0 100644 --- a/ExecGDAPInviteQueue/run.ps1 +++ b/ExecGDAPInviteQueue/run.ps1 @@ -4,30 +4,4 @@ param( $QueueItem, $TriggerMetadata) # Write out the queue message and metadata to the information log. Write-Host "PowerShell queue trigger function processed work item: $($QueueItem.customer.displayName)" -$Table = Get-CIPPTable -TableName 'GDAPInvites' -$Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($QueueItem.id)'" -$APINAME = 'GDAPInvites' -$RoleMappings = $Invite.RoleMappings | ConvertFrom-Json - -foreach ($role in $RoleMappings) { - try { - $Mappingbody = ConvertTo-Json -Depth 10 -InputObject @{ - 'accessContainer' = @{ - 'accessContainerId' = "$($Role.GroupId)" - 'accessContainerType' = 'securityGroup' - } - 'accessDetails' = @{ - 'unifiedRoles' = @(@{ - 'roleDefinitionId' = "$($Role.roleDefinitionId)" - }) - } - } - New-GraphPostRequest -NoAuthCheck $True -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$($QueueItem.id)/accessAssignments" -tenantid $env:TenantID -type POST -body $MappingBody -verbose - Start-Sleep -Milliseconds 100 - } catch { - Write-LogMessage -API $APINAME -message "GDAP Group mapping failed for $($QueueItem.customer.displayName) - Group: $($role.GroupId) - Exception: $($_.Exception.Message)" -Sev Error - exit 1 - } -} -Write-LogMessage -API $APINAME -message "Groups mapped for GDAP Relationship: $($QueueItem.customer.displayName) - $($QueueItem.displayName)" -Sev Info -Remove-AzDataTableEntity @Table -Entity $Invite +Set-CIPPGDAPInviteGroups -Relationship $QueueItem \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOnboardTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOnboardTenant.ps1 new file mode 100644 index 000000000000..c67be5c4de8f --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOnboardTenant.ps1 @@ -0,0 +1,87 @@ +using namespace System.Net + +function Invoke-ExecOnboardTenant { + param($Request, $TriggerMetadata) + + $APIName = 'ExecOnboardTenant' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + $Id = $Request.Body.Id + if ($Id) { + try { + $OnboardTable = Get-CIPPTable -TableName 'TenantOnboarding' + $TenantOnboarding = Get-CIPPAzDataTableEntity @OnboardTable -Filter "RowKey eq '$Id'" + + if (!$TenantOnboarding -or [bool]$Request.Query.Retry) { + $OnboardingSteps = [PSCustomObject]@{ + 'Step1' = @{ + 'Status' = 'pending' + 'Title' = 'Step 1: GDAP Invite' + 'Message' = 'Waiting for onboarding job to start' + } + 'Step2' = @{ + 'Status' = 'pending' + 'Title' = 'Step 2: GDAP Role Test' + 'Message' = 'Waiting for Step 1' + } + 'Step3' = @{ + 'Status' = 'pending' + 'Title' = 'Step 3: GDAP Group Mapping' + 'Message' = 'Waiting for Step 2' + } + 'Step4' = @{ + 'Status' = 'pending' + 'Title' = 'Step 4: CPV Refresh' + 'Message' = 'Waiting for Step 3' + } + 'Step5' = @{ + 'Status' = 'pending' + 'Title' = 'Step 5: Graph API Test' + 'Message' = 'Waiting for Step 4' + } + } + $TenantOnboarding = [PSCustomObject]@{ + PartitionKey = 'Onboarding' + RowKey = [string]$Id + CustomerId = '' + Status = 'queued' + OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) + Relationship = '' + Logs = '' + Exception = '' + } + Add-CIPPAzDataTableEntity @OnboardTable -Entity $TenantOnboarding -Force -ErrorAction Stop + + Push-OutputBinding -Name QueueItem -Value ([pscustomobject]@{ + FunctionName = 'ExecOnboardTenantQueue' + id = $Id + Roles = $Request.Body.gdapRoles + }) + } + + $Steps = $TenantOnboarding.OnboardingSteps | ConvertFrom-Json + $OnboardingSteps = foreach ($Step in $Steps.PSObject.Properties.Name) { $Steps.$Step } + $Relationship = try { $TenantOnboarding.Relationship | ConvertFrom-Json -ErrorAction Stop } catch { @{} } + $Logs = try { $TenantOnboarding.Logs | ConvertFrom-Json -ErrorAction Stop } catch { @{} } + $TenantOnboarding.OnboardingSteps = $OnboardingSteps + $TenantOnboarding.Relationship = $Relationship + $TenantOnboarding.Logs = $Logs + $Results = $TenantOnboarding + + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMsg = Get-NormalizedError -message $($_.Exception.Message) + $Results = "Function Error: $($_.InvocationInfo.ScriptLineNumber) - $ErrorMsg" + $StatusCode = [HttpStatusCode]::BadRequest + } + } else { + $StatusCode = [HttpStatusCode]::NotFound + $Results = 'Relationship not found' + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Results + }) + +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPInvite.ps1 index 3ae888f60ec8..afc2bacfc630 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPInvite.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPInvite.ps1 @@ -15,18 +15,15 @@ Function Invoke-ListGDAPInvite { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - Write-Host ($Request | ConvertTo-Json) + $Table = Get-CIPPTable -TableName 'GDAPInvites' if (![string]::IsNullOrEmpty($Request.Query.RelationshipId)) { - $Table = Get-CIPPTable -TableName 'GDAPInvites' $Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Query.RelationshipId)'" - Write-Host $Invite } else { - $Invite = @{} + $Invite = Get-CIPPAzDataTableEntity @Table } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Invite }) - } diff --git a/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 b/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 index a868f5573d16..407eccddc796 100644 --- a/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 @@ -1,15 +1,45 @@ function Set-CIPPGDAPInviteGroups { - Param() + Param($Relationship) $Table = Get-CIPPTable -TableName 'GDAPInvites' - $InviteList = Get-CIPPAzDataTableEntity @Table - if (($InviteList | Measure-Object).Count -gt 0) { - $Activations = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships?`$filter=status eq 'active'" + if ($Relationship) { + $Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Relationship.id)'" + $APINAME = 'GDAPInvites' + $RoleMappings = $Invite.RoleMappings | ConvertFrom-Json - foreach ($Activation in $Activations) { - if ($InviteList.RowKey -contains $Activation.id) { - Write-Host "Mapping groups for GDAP relationship: $($Activation.customer.displayName) - $($Activation.id)" - Push-OutputBinding -Name gdapinvitequeue -Value $Activation + foreach ($role in $RoleMappings) { + try { + $Mappingbody = ConvertTo-Json -Depth 10 -InputObject @{ + 'accessContainer' = @{ + 'accessContainerId' = "$($Role.GroupId)" + 'accessContainerType' = 'securityGroup' + } + 'accessDetails' = @{ + 'unifiedRoles' = @(@{ + 'roleDefinitionId' = "$($Role.roleDefinitionId)" + }) + } + } + New-GraphPostRequest -NoAuthCheck $True -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$($Relationship.id)/accessAssignments" -tenantid $env:TenantID -type POST -body $MappingBody -verbose + Start-Sleep -Milliseconds 100 + } catch { + Write-LogMessage -API $APINAME -message "GDAP Group mapping failed for $($Relationship.customer.displayName) - Group: $($role.GroupId) - Exception: $($_.Exception.Message)" -Sev Error + return $false + } + } + Write-LogMessage -API $APINAME -message "Groups mapped for GDAP Relationship: $($Relationship.customer.displayName) - $($Relationship.customer.displayName)" -Sev Info + Remove-AzDataTableEntity @Table -Entity $Invite + return $true + } else { + $InviteList = Get-CIPPAzDataTableEntity @Table + if (($InviteList | Measure-Object).Count -gt 0) { + $Activations = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships?`$filter=status eq 'active'" + + foreach ($Activation in $Activations) { + if ($InviteList.RowKey -contains $Activation.id) { + Write-Host "Mapping groups for GDAP relationship: $($Activation.customer.displayName) - $($Activation.id)" + Push-OutputBinding -Name gdapinvitequeue -Value $Activation + } } } } From 9efb6296db0627cfdd966487fa10e3ea76a33cdb Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Wed, 13 Dec 2023 18:40:32 +0100 Subject: [PATCH 4/6] Decrease confusion by making the completed message the same --- Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSAMSetup.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSAMSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSAMSetup.ps1 index 1319ced9aa86..a224182bf1c9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSAMSetup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSAMSetup.ps1 @@ -180,7 +180,7 @@ Function Invoke-ExecSAMSetup { Remove-AzDataTableEntity @Table -Entity $Rows $step = 5 - $Results = @{'message' = 'Installation completed.'; step = $step + $Results = @{'message' = 'setup completed.'; step = $step } } } From bcd0a96d9fca735b70e108bc5c32208869bdbfcd Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 13 Dec 2023 18:48:16 +0100 Subject: [PATCH 5/6] Fix rare case of report/remediat confusion --- Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 index d6a1ff13fe58..353551cdaadf 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 @@ -16,7 +16,7 @@ function Invoke-CIPPStandardsRun { $Tenants = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json #Migrate from old standards to new standards. - $Tenants | Where-Object -Property 'v2.1' -NE $true | ForEach-Object { + $Tenants | Where-Object -Property 'v2.1' -NE $null | ForEach-Object { $OldStd = $_ $OldStd.standards.psobject.properties.name | ForEach-Object { if ($_ -eq 'MailContacts') { @@ -28,7 +28,7 @@ function Invoke-CIPPStandardsRun { remediate = $true } } else { - if ($OldStd.Standards.$_ -eq $true) { + if ($OldStd.Standards.$_ -eq $true -and $_ -ne 'v2.1') { $OldStd.Standards.$_ = @{ remediate = $true } } else { $OldStd.Standards.$_ | Add-Member -NotePropertyName 'remediate' -NotePropertyValue $true -Force From a802a91b56b3d461c8957a7861111b7a825e85dd Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 13 Dec 2023 18:48:38 +0100 Subject: [PATCH 6/6] hotfix --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index 40b4ea0598c8..490375502c2a 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -4.8.3 \ No newline at end of file +4.8.4 \ No newline at end of file