From 68a6fc3182811744a23c5e522eed4daa1d6a67bb Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Thu, 1 May 2025 00:19:58 +0200 Subject: [PATCH 001/149] Remove un-used/overprivileged Mail.Send b633e1c5-b582-4048-a93e-9f11b44c7e96 --- Cache_SAMSetup/SAMManifest.json | 1 - 1 file changed, 1 deletion(-) diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index f94959dc3ac6..71b6a3fdcbbc 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -106,7 +106,6 @@ { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, - { "id": "b633e1c5-b582-4048-a93e-9f11b44c7e96", "type": "Role" }, { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, From 6ce3831d250d15e9e590a5d1855721002758608e Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Thu, 1 May 2025 00:20:25 +0200 Subject: [PATCH 002/149] Remove un-used/overprivileged Mail.Send --- Modules/CIPPCore/Public/SAMManifest.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/SAMManifest.json b/Modules/CIPPCore/Public/SAMManifest.json index 5ffaae201e77..ff59fb4f7e32 100644 --- a/Modules/CIPPCore/Public/SAMManifest.json +++ b/Modules/CIPPCore/Public/SAMManifest.json @@ -135,10 +135,6 @@ "id": "19da66cb-0fb0-4390-b071-ebc76a349482", "type": "Role" }, - { - "id": "b633e1c5-b582-4048-a93e-9f11b44c7e96", - "type": "Role" - }, { "id": "6931bccd-447a-43d1-b442-00a195474933", "type": "Role" @@ -635,4 +631,4 @@ ] } ] -} \ No newline at end of file +} From 5454d3213f3531bc8431776c316ed2aa233f0f2d Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Thu, 1 May 2025 18:42:37 +0800 Subject: [PATCH 003/149] addition of new options --- .../Resources/Invoke-EditRoomMailbox.ps1 | 43 ++++++++++++++++++- .../Resources/Invoke-ListRooms.ps1 | 29 ++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-EditRoomMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-EditRoomMailbox.ps1 index fda1275a1956..6e206791b411 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-EditRoomMailbox.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-EditRoomMailbox.ps1 @@ -53,13 +53,54 @@ Function Invoke-EditRoomMailbox { } } + + # Then update the calendar properties + $UpdateCalendarParams = @{ + Identity = $MailboxObject.roomId + } + + $CalendarProperties = @( + 'AllowConflicts', 'AllowRecurringMeetings', 'BookingWindowInDays', + 'MaximumDurationInMinutes', 'ProcessExternalMeetingMessages', 'EnforceCapacity', + 'ForwardRequestsToDelegates', 'ScheduleOnlyDuringWorkHours ', 'AutomateProcessing' + ) + + foreach ($prop in $CalendarProperties) { + if (![string]::IsNullOrWhiteSpace($MailboxObject.$prop)) { + $UpdateCalendarParams[$prop] = $MailboxObject.$prop + } + } + + # Then update the calendar configuration + $UpdateCalendarConfigParams = @{ + Identity = $MailboxObject.roomId + } + + $CalendarConfiguration = @( + 'WorkDays', 'WorkHoursStartTime', 'WorkHoursEndTime', 'WorkingHoursTimeZone' + ) + + foreach ($prop in $CalendarConfiguration) { + if (![string]::IsNullOrWhiteSpace($MailboxObject.$prop)) { + $UpdateCalendarConfigParams[$prop] = $MailboxObject.$prop + } + } + try { # Update mailbox properties $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-Mailbox' -cmdParams $UpdateMailboxParams # Update place properties $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-Place' -cmdParams $UpdatePlaceParams - $Results.Add("Successfully updated room: $($MailboxObject.DisplayName)") + $Results.Add("Successfully updated room: $($MailboxObject.DisplayName) (Place Properties)") + + # Update calendar properties + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-CalendarProcessing' -cmdParams $UpdateCalendarParams + $Results.Add("Successfully updated room: $($MailboxObject.DisplayName) (Calendar Properties)") + + # Update calendar configuration properties + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MailboxCalendarConfiguration' -cmdParams $UpdateCalendarConfigParams + $Results.Add("Successfully updated room: $($MailboxObject.DisplayName) (Calendar Configuration)") Write-LogMessage -headers $Request.Headers -API $APIName -tenant $Tenant -message "Updated room $($MailboxObject.DisplayName)" -Sev 'Info' $StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRooms.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRooms.ps1 index 4507af02a40e..ad7625bd61c6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRooms.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRooms.ps1 @@ -32,7 +32,17 @@ Function Invoke-ListRooms { Identity = $RoomId } | Select-Object -ExcludeProperty *@odata.type* - if ($RoomMailbox -and $PlaceDetails) { + # Get calendar properties + $CalendarProperties = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-CalendarProcessing' -cmdParams @{ + Identity = $RoomId + } | Select-Object -ExcludeProperty *@odata.type* + + # Get calendar properties + $CalendarConfigurationProperties = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MailboxCalendarConfiguration' -cmdParams @{ + Identity = $RoomId + } | Select-Object -ExcludeProperty *@odata.type* + + if ($RoomMailbox -and $PlaceDetails -and $CalendarProperties -and $CalendarConfigurationProperties) { $GraphRequest = @( [PSCustomObject]@{ # Core Mailbox Properties @@ -70,6 +80,23 @@ Function Invoke-ListRooms { phone = if ([string]::IsNullOrWhiteSpace($PlaceDetails.Phone)) { $null } else { $PlaceDetails.Phone } tags = $PlaceDetails.Tags spaceType = $PlaceDetails.SpaceType + + # Calendar Properties + AllowConflicts = $CalendarProperties.AllowConflicts + AllowRecurringMeetings = $CalendarProperties.AllowRecurringMeetings + BookingWindowInDays = $CalendarProperties.BookingWindowInDays + MaximumDurationInMinutes = $CalendarProperties.MaximumDurationInMinutes + ProcessExternalMeetingMessages= $CalendarProperties.ProcessExternalMeetingMessages + EnforceCapacity = $CalendarProperties.EnforceCapacity + ForwardRequestsToDelegates = $CalendarProperties.ForwardRequestsToDelegates + ScheduleOnlyDuringWorkHours = $CalendarProperties.ScheduleOnlyDuringWorkHours + AutomateProcessing = $CalendarProperties.AutomateProcessing + + # Calendar Configuration Properties + WorkDays = if ([string]::IsNullOrWhiteSpace($CalendarConfigurationProperties.WorkDays)) { $null } else { $CalendarConfigurationProperties.WorkDays } + WorkHoursStartTime = if ([string]::IsNullOrWhiteSpace($CalendarConfigurationProperties.WorkHoursStartTime)) { $null } else { $CalendarConfigurationProperties.WorkHoursStartTime } + WorkHoursEndTime = if ([string]::IsNullOrWhiteSpace($CalendarConfigurationProperties.WorkHoursEndTime)) { $null } else { $CalendarConfigurationProperties.WorkHoursEndTime } + WorkingHoursTimeZone = $CalendarConfigurationProperties.WorkingHoursTimeZone } ) } From c98fbbee702c9e25fe6738f8a170c4e9c4a17864 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 1 May 2025 09:00:35 -0400 Subject: [PATCH 004/149] durable cleanup fix part 2 --- .../Entrypoints/Timer Functions/Start-DurableCleanup.ps1 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-DurableCleanup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-DurableCleanup.ps1 index aaca4e5c6baa..661bf5182d89 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-DurableCleanup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-DurableCleanup.ps1 @@ -26,16 +26,13 @@ function Start-DurableCleanup { $CleanupCount = 0 $QueueCount = 0 - $ClearQueues = $false $FunctionsWithLongRunningOrchestrators = [System.Collections.Generic.List[object]]::new() foreach ($Table in $InstancesTables) { - $RunningOrchestratorCount = 0 $Table = Get-CippTable -TableName $Table $FunctionName = $Table.TableName -replace 'Instances', '' $Orchestrators = Get-CIPPAzDataTableEntity @Table -Filter "RuntimeStatus eq 'Running'" | Select-Object * -ExcludeProperty Input $Queues = Get-AzStorageQueue -Context $StorageContext -Name ('{0}*' -f $FunctionName) | Select-Object -Property Name, ApproximateMessageCount, QueueClient - $RunningOrchestratorCount = $Orchestrators.Count $LongRunningOrchestrators = $Orchestrators | Where-Object { $_.CreatedTime.DateTime -lt $TargetTime } if ($LongRunningOrchestrators.Count -gt 0) { $FunctionsWithLongRunningOrchestrators.Add(@{'FunctionName' = $FunctionName }) @@ -45,7 +42,6 @@ function Start-DurableCleanup { $TimeSpan = New-TimeSpan -Start $CreatedTime -End (Get-Date).ToUniversalTime() $RunningDuration = [math]::Round($TimeSpan.TotalMinutes, 2) Write-Information "Orchestrator: $($Orchestrator.PartitionKey), created: $CreatedTime, running for: $RunningDuration minutes" - $ClearQueues = $true if ($PSCmdlet.ShouldProcess($_.PartitionKey, 'Terminate Orchestrator')) { $Orchestrator = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Orchestrator.PartitionKey)'" $Orchestrator.RuntimeStatus = 'Failed' @@ -58,7 +54,7 @@ function Start-DurableCleanup { $CleanupCount++ } } - if ($ClearQueues -or ($RunningOrchestratorCount -eq 0 -and $Queues.ApproximateMessageCount -gt 0)) { + if ($LongRunningOrchestrators.Count -gt 0 -and $Queues.ApproximateMessageCount -gt 0) { $RunningQueues = $Queues | Where-Object { $_.ApproximateMessageCount -gt 0 } foreach ($Queue in $RunningQueues) { Write-Information "- Removing queue: $($Queue.Name), message count: $($Queue.ApproximateMessageCount)" From 4e9540c590e47419faf199802529926e0dc9c09f Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 1 May 2025 16:01:33 +0200 Subject: [PATCH 005/149] chore: CRLF to LF --- Cache_SAMSetup/PermissionsTranslator.json | 10700 ++++++++++---------- Cache_SAMSetup/SAMManifest.json | 386 +- 2 files changed, 5543 insertions(+), 5543 deletions(-) diff --git a/Cache_SAMSetup/PermissionsTranslator.json b/Cache_SAMSetup/PermissionsTranslator.json index ecc57bd2649d..204fe8532c4f 100644 --- a/Cache_SAMSetup/PermissionsTranslator.json +++ b/Cache_SAMSetup/PermissionsTranslator.json @@ -1,5350 +1,5350 @@ -[ - { - "description": "Allows Exchange Management as app", - "displayName": "Manage Exchange As Application ", - "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", - "origin": "Application (Office 365 Exchange Online)", - "value": "Exchange.ManageAsApp" - }, - { - "description": "Allows the app to read a basic set of profile properties of other users in your organization without a signed-in user. Includes display name, first and last name, email address, open extensions, and photo.", - "displayName": "Read all users' basic profiles", - "id": "97235f07-e226-4f63-ace3-39588e11d3a1", - "origin": "Application", - "value": "User.ReadBasic.All" - }, - { - "description": "Allows the app to read all\u00a0class assignments without grades for all users without a signed-in user.", - "displayName": "Read all class assignments without grades", - "id": "6e0a958b-b7fc-4348-b7c4-a6ab9fd3dd0e", - "origin": "Application", - "value": "EduAssignments.ReadBasic.All" - }, - { - "description": "Allows the app to create, read, update and delete all\u00a0class assignments without grades for all users without a signed-in user.", - "displayName": "Create, read, update and delete all\u00a0class assignments without grades", - "id": "f431cc63-a2de-48c4-8054-a34bc093af84", - "origin": "Application", - "value": "EduAssignments.ReadWriteBasic.All" - }, - { - "description": "Allows the app to read all\u00a0class assignments with grades for all users without a signed-in user.", - "displayName": "Read all class assignments with grades", - "id": "4c37e1b6-35a1-43bf-926a-6f30f2cdf585", - "origin": "Application", - "value": "EduAssignments.Read.All" - }, - { - "description": "Allows the app to create, read, update and delete all\u00a0class assignments with grades for all users without a signed-in user.", - "displayName": "Create, read, update and delete all\u00a0class assignments with grades", - "id": "0d22204b-6cad-4dd0-8362-3e3f2ae699d9", - "origin": "Application", - "value": "EduAssignments.ReadWrite.All" - }, - { - "description": "Allows\u00a0the\u00a0app\u00a0to\u00a0read\u00a0subject\u00a0rights requests\u00a0without a\u00a0signed-in\u00a0user.", - "displayName": "Read\u00a0all subject\u00a0rights requests", - "id": "ee1460f0-368b-4153-870a-4e1ca7e72c42", - "origin": "Application", - "value": "SubjectRightsRequest.Read.All" - }, - { - "description": "Allows\u00a0the\u00a0app\u00a0to\u00a0read\u00a0and\u00a0write subject\u00a0rights requests\u00a0without a signed in user.", - "displayName": "Read\u00a0and\u00a0write\u00a0all subject\u00a0rights requests", - "id": "8387eaa4-1a3c-41f5-b261-f888138e6041", - "origin": "Application", - "value": "SubjectRightsRequest.ReadWrite.All" - }, - { - "description": "Allows the app to read attack simulation and training data for an organization without a signed-in user.", - "displayName": "Read attack simulation data of an organization", - "id": "93283d0a-6322-4fa8-966b-8c121624760d", - "origin": "Application", - "value": "AttackSimulation.Read.All" - }, - { - "description": "Allows custom authentication extensions associated with the app to receive HTTP requests triggered by an authentication event. The request can include information about a user, client and resource service principals, and other information about the authentication.", - "displayName": "Receive custom authentication extension HTTP requests", - "id": "214e810f-fda8-4fd7-a475-29461495eb00", - "origin": "Application", - "value": "CustomAuthenticationExtension.Receive.Payload" - }, - { - "description": "Allows the app to read and write your organization's directory access review default policy without a signed-in user.", - "displayName": "Read and write your organization's directory access review default policy", - "id": "77c863fd-06c0-47ce-a7eb-49773e89d319", - "origin": "Application", - "value": "Policy.ReadWrite.AccessReview" - }, - { - "description": "Allows the app to create groups, read all group properties and memberships, update group properties and memberships, and delete groups. Also allows the app to read and write conversations. All of these operations can be performed by the app without a signed-in user.", - "displayName": "Read and write all groups", - "id": "62a82d76-70ea-41e2-9197-370581804d09", - "origin": "Application", - "value": "Group.ReadWrite.All" - }, - { - "description": "Allows the app to read group properties and memberships, and read\u00a0conversations for all groups, without a signed-in user.", - "displayName": "Read all groups", - "id": "5b567255-7703-4780-807c-7be8301ae99b", - "origin": "Application", - "value": "Group.Read.All" - }, - { - "description": "Allows the app to read your organization's threat submissions and threat submission policies without a signed-in user. Also allows the app to create new threat submissions without a signed-in user.", - "displayName": "Read and write all of the organization's threat submissions", - "id": "d72bdbf4-a59b-405c-8b04-5995895819ac", - "origin": "Application", - "value": "ThreatSubmission.ReadWrite.All" - }, - { - "description": "Allows an app to read Bookings appointments, businesses, customers, services, and staff without a signed-in user. ", - "displayName": "Read all Bookings related resources.", - "id": "6e98f277-b046-4193-a4f2-6bf6a78cd491", - "origin": "Application", - "value": "Bookings.Read.All" - }, - { - "description": "Allows an app to read and write Bookings appointments and customers, and additionally allows reading businesses, services, and staff without a signed-in user. ", - "displayName": "Read and write all Bookings related resources.", - "id": "9769393e-5a9f-4302-9e3d-7e018ecb64a7", - "origin": "Application", - "value": "BookingsAppointment.ReadWrite.All" - }, - { - "description": "Allows the application to read any data from Records Management, such as configuration, labels, and policies without the signed in user.", - "displayName": "Read Records Management configuration,\u00a0labels and policies", - "id": "ac3a2b8e-03a3-4da9-9ce0-cbe28bf1accd", - "origin": "Application", - "value": "RecordsManagement.Read.All" - }, - { - "description": "Allow the application to create, update and delete any data from Records Management, such as configuration, labels, and policies without the signed in user.", - "displayName": "Read and write Records Management configuration, labels and policies", - "id": "eb158f57-df43-4751-8b21-b8932adb3d34", - "origin": "Application", - "value": "RecordsManagement.ReadWrite.All" - }, - { - "description": "Allows the app to read details of delegated admin relationships with customers like access details (that includes roles) and the duration as well as specific role assignments to security groups without a signed-in user.", - "displayName": "Read Delegated Admin relationships with customers", - "id": "f6e9e124-4586-492f-adc0-c6f96e4823fd", - "origin": "Application", - "value": "DelegatedAdminRelationship.Read.All" - }, - { - "description": "Allows the app to manage (create-update-terminate) Delegated Admin relationships with customers and role assignments to security groups for active Delegated Admin relationships without a signed-in user.", - "displayName": "Manage Delegated Admin relationships with customers", - "id": "cc13eba4-8cd8-44c6-b4d4-f93237adce58", - "origin": "Application", - "value": "DelegatedAdminRelationship.ReadWrite.All" - }, - { - "description": "Allows the app to read and manage the Cloud PC role-based access control (RBAC) settings, without a signed-in user. This includes reading and managing Cloud PC role definitions and memberships.", - "displayName": "Read and write all Cloud PC RBAC settings", - "id": "274d0592-d1b6-44bd-af1d-26d259bcb43a", - "origin": "Application", - "value": "RoleManagement.ReadWrite.CloudPC" - }, - { - "description": "Allows the app to read the Cloud PC role-based access control (RBAC) settings, without a signed-in user.", - "displayName": "Read Cloud PC RBAC settings", - "id": "031a549a-bb80-49b6-8032-2068448c6a3c", - "origin": "Application", - "value": "RoleManagement.Read.CloudPC" - }, - { - "description": "Allows the app to read custom security attribute assignments for all principals in the tenant without a signed in user.", - "displayName": "Read custom security attribute assignments", - "id": "3b37c5a4-1226-493d-bec3-5d6c6b866f3f", - "origin": "Application", - "value": "CustomSecAttributeAssignment.Read.All" - }, - { - "description": "Allows the app to read custom security attribute definitions for the tenant without a signed in user.", - "displayName": "Read custom security attribute definitions", - "id": "b185aa14-d8d2-42c1-a685-0f5596613624", - "origin": "Application", - "value": "CustomSecAttributeDefinition.Read.All" - }, - { - "description": "Allows the app to read all external connections without a signed-in user.", - "displayName": "Read all external connections", - "id": "1914711b-a1cb-4793-b019-c2ce0ed21b8c", - "origin": "Application", - "value": "ExternalConnection.Read.All" - }, - { - "description": "Allows the app to read and write all external connections without a signed-in user.", - "displayName": "Read and write all external connections", - "id": "34c37bc0-2b40-4d5e-85e1-2365cd256d79", - "origin": "Application", - "value": "ExternalConnection.ReadWrite.All" - }, - { - "description": "Allows the app to read all external items without a signed-in user.", - "displayName": "Read all external items", - "id": "7a7cffad-37d2-4f48-afa4-c6ab129adcc2", - "origin": "Application", - "value": "ExternalItem.Read.All" - }, - { - "description": "Allows the app to read and write your organization's cross tenant access policies without a signed-in user.", - "displayName": "Read and write your organization's cross tenant access policies", - "id": "338163d7-f101-4c92-94ba-ca46fe52447c", - "origin": "Application", - "value": "Policy.ReadWrite.CrossTenantAccess" - }, - { - "description": "Allows the app to read and write custom security attribute definitions for the tenant without a signed in user.", - "displayName": "Read and write custom security attribute definitions", - "id": "12338004-21f4-4896-bf5e-b75dfaf1016d", - "origin": "Application", - "value": "CustomSecAttributeDefinition.ReadWrite.All" - }, - { - "description": "Allows the app to read and write custom security attribute assignments for all principals in the tenant without a signed in user.", - "displayName": "Read and write custom security attribute assignments", - "id": "de89b5e4-5b8f-48eb-8925-29c2b33bd8bd", - "origin": "Application", - "value": "CustomSecAttributeAssignment.ReadWrite.All" - }, - { - "description": "Allows the app to read and write to all security incidents, without a signed-in user.", - "displayName": "Read and write to all security incidents", - "id": "34bf0e97-1971-4929-b999-9e2442d941d7", - "origin": "Application", - "value": "SecurityIncident.ReadWrite.All" - }, - { - "description": "Allows the app to read all security incidents, without a signed-in user.", - "displayName": "Read all security incidents", - "id": "45cc0394-e837-488b-a098-1918f48d186c", - "origin": "Application", - "value": "SecurityIncident.Read.All" - }, - { - "description": "Allows the app to read and write to all security alerts, without a signed-in user.", - "displayName": "Read and write to all security alerts", - "id": "ed4fca05-be46-441f-9803-1873825f8fdb", - "origin": "Application", - "value": "SecurityAlert.ReadWrite.All" - }, - { - "description": "Allows the app to read all security alerts, without a signed-in user.", - "displayName": "Read all security alerts", - "id": "472e4a4d-bb4a-4026-98d1-0b0d74cb74a5", - "origin": "Application", - "value": "SecurityAlert.Read.All" - }, - { - "description": "Allows the app to read and write eDiscovery objects such as cases, custodians, review sets and other related objects without a signed-in user.", - "displayName": "Read and write all eDiscovery objects", - "id": "b2620db1-3bf7-4c5b-9cb9-576d29eac736", - "origin": "Application", - "value": "eDiscovery.ReadWrite.All" - }, - { - "description": "Allows the app to read eDiscovery objects such as cases, custodians, review sets and other related objects without a signed-in user.", - "displayName": "Read all eDiscovery objects", - "id": "50180013-6191-4d1e-a373-e590ff4e66af", - "origin": "Application", - "value": "eDiscovery.Read.All" - }, - { - "description": "Allows the app to run hunting queries, without a signed-in user.", - "displayName": "Run hunting queries", - "id": "dd98c7f5-2d42-42d3-a0e4-633161547251", - "origin": "Application", - "value": "ThreatHunting.Read.All" - }, - { - "description": "Allow the app to read the management data for Teams devices, without a signed-in user.", - "displayName": "Read Teams devices", - "id": "0591bafd-7c1c-4c30-a2a5-2b9aacb1dfe8", - "origin": "Application", - "value": "TeamworkDevice.Read.All" - }, - { - "description": "Allow the app to read and write the management data for Teams devices, without a signed-in user.", - "displayName": "Read and write Teams devices", - "id": "79c02f5b-bd4f-4713-bc2c-a8a4a66e127b", - "origin": "Application", - "value": "TeamworkDevice.ReadWrite.All" - }, - { - "description": "Allows the app to read and update identity risky service principal for your organization, without a signed-in user.", - "displayName": "Read and write all identity risky service principal information", - "id": "cb8d6980-6bcb-4507-afec-ed6de3a2d798", - "origin": "Application", - "value": "IdentityRiskyServicePrincipal.ReadWrite.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs for any user, without a signed-in user.", - "displayName": "Allow the Teams app to manage only its own tabs for all users", - "id": "3c42dec6-49e8-4a0a-b469-36cff0d9da93", - "origin": "Application", - "value": "TeamsTab.ReadWriteSelfForUser.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs in any team, without a signed-in user.", - "displayName": "Allow the Teams app to manage only its own tabs for all teams", - "id": "91c32b81-0ef0-453f-a5c7-4ce2e562f449", - "origin": "Application", - "value": "TeamsTab.ReadWriteSelfForTeam.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs for any chat, without a signed-in user.", - "displayName": "Allow the Teams app to manage only its own tabs for all chats", - "id": "9f62e4a2-a2d6-4350-b28b-d244728c4f86", - "origin": "Application", - "value": "TeamsTab.ReadWriteSelfForChat.All" - }, - { - "description": "Allows the app to read all risky service principal information for your organization, without a signed-in user.", - "displayName": "Read all identity risky service principal information", - "id": "607c7344-0eed-41e5-823a-9695ebe1b7b0", - "origin": "Application", - "value": "IdentityRiskyServicePrincipal.Read.All" - }, - { - "description": "Allows the app to read and write search configurations, without a signed-in user.", - "displayName": "Read and write your organization's search configuration", - "id": "0e778b85-fefa-466d-9eec-750569d92122", - "origin": "Application", - "value": "SearchConfiguration.ReadWrite.All" - }, - { - "description": "Allows the app to read search configurations, without a signed-in user.", - "displayName": "Read your organization's search configuration", - "id": "ada977a5-b8b1-493b-9a91-66c206d76ecf", - "origin": "Application", - "value": "SearchConfiguration.Read.All" - }, - { - "description": "Allows the app to read online meeting artifacts in your organization, without a signed-in user.", - "displayName": "Read online meeting artifacts", - "id": "df01ed3b-eb61-4eca-9965-6b3d789751b2", - "origin": "Application", - "value": "OnlineMeetingArtifact.Read.All" - }, - { - "description": "Allows the app to create, read, update, and delete apps in the app catalogs without a signed-in user.", - "displayName": "Read and write to all app catalogs", - "id": "dc149144-f292-421e-b185-5953f2e98d7f", - "origin": "Application", - "value": "AppCatalog.ReadWrite.All" - }, - { - "description": "Allows the app to read apps in the app catalogs without a signed-in user.", - "displayName": "Read all app catalogs", - "id": "e12dae10-5a57-4817-b79d-dfbec5348930", - "origin": "Application", - "value": "AppCatalog.Read.All" - }, - { - "description": "Allows the app to manage workforce integrations to synchronize data from Microsoft Teams Shifts, without a signed-in user.", - "displayName": "Read and write workforce integrations", - "id": "202bf709-e8e6-478e-bcfd-5d63c50b68e3", - "origin": "Application", - "value": "WorkforceIntegration.ReadWrite.All" - }, - { - "description": "Allows the app to read all presence information and write activity and availability of all users in the directory without a signed-in user. Presence information includes activity, availability, status note, calendar out-of-office message, time zone and location.", - "displayName": "Read and write presence information for all users", - "id": "83cded22-8297-4ff6-a7fa-e97e9545a259", - "origin": "Application", - "value": "Presence.ReadWrite.All" - }, - { - "description": "Allows the app to read and write tags in Teams without a signed-in user.", - "displayName": "Read and write tags in Teams", - "id": "a3371ca5-911d-46d6-901c-42c8c7a937d8", - "origin": "Application", - "value": "TeamworkTag.ReadWrite.All" - }, - { - "description": "Allows the app to read\u00a0tags in Teams\u00a0without a signed-in user.", - "displayName": "Read tags in Teams", - "id": "b74fd6c4-4bde-488e-9695-eeb100e4907f", - "origin": "Application", - "value": "TeamworkTag.Read.All" - }, - { - "description": "Allows the app to read and write all Windows update deployment settings for the organization without a signed-in user.", - "displayName": "Read and write all Windows update deployment settings", - "id": "7dd1be58-6e76-4401-bf8d-31d1e8180d5b", - "origin": "Application", - "value": "WindowsUpdates.ReadWrite.All" - }, - { - "description": "Allows the app to read and write external connections without a signed-in user. The app can only read and write external connections that it is authorized to, or it can create new external connections. ", - "displayName": "Read and write external connections", - "id": "f431331c-49a6-499f-be1c-62af19c34a9d", - "origin": "Application", - "value": "ExternalConnection.ReadWrite.OwnedBy" - }, - { - "description": "Allows the app to read and write external items without a signed-in user. The app can only read external items of the connection that it is authorized to.", - "displayName": "Read and write external items", - "id": "8116ae0f-55c2-452d-9944-d18420f5b2c8", - "origin": "Application", - "value": "ExternalItem.ReadWrite.OwnedBy" - }, - { - "description": "Allow the application to access a subset of site collections without a signed in user.\u00a0\u00a0The specific site collections and the permissions granted will be configured in SharePoint Online.", - "displayName": "Access selected site collections", - "id": "883ea226-0bf2-4a8f-9f9d-92c9162a727d", - "origin": "Application", - "value": "Sites.Selected" - }, - { - "description": "Allows the app to read documents and list items in all site collections without a signed in user.", - "displayName": "Read items in all site collections ", - "id": "332a536c-c7ef-4017-ab91-336970924f0d", - "origin": "Application", - "value": "Sites.Read.All" - }, - { - "description": "Allows the app to create, read, update, and delete documents and list items in all site collections without a signed in user.", - "displayName": "Read and write items in all site collections", - "id": "9492366f-7969-46a4-8d15-ed1a20078fff", - "origin": "Application", - "value": "Sites.ReadWrite.All" - }, - { - "description": "Allows the app to read and write the properties of Cloud PCs, without a signed-in user.", - "displayName": "Read and write Cloud PCs", - "id": "3b4349e1-8cf5-45a3-95b7-69d1751d3e6a", - "origin": "Application", - "value": "CloudPC.ReadWrite.All" - }, - { - "description": "Allows the app to read the properties of Cloud PCs, without a signed-in user.", - "displayName": "Read Cloud PCs", - "id": "a9e09520-8ed4-4cde-838e-4fdea192c227", - "origin": "Application", - "value": "CloudPC.Read.All" - }, - { - "description": "Allows the app to update service principal endpoints", - "displayName": "Read and update service principal endpoints", - "id": "89c8469c-83ad-45f7-8ff2-6e3d4285709e", - "origin": "Application", - "value": "ServicePrincipalEndpoint.ReadWrite.All" - }, - { - "description": "Allows the app to read service principal endpoints", - "displayName": "Read service principal endpoints", - "id": "5256681e-b7f6-40c0-8447-2d9db68797a0", - "origin": "Application", - "value": "ServicePrincipalEndpoint.Read.All" - }, - { - "description": "Allows the app to create new notifications in users' teamwork activity feeds without a signed in user. These notifications may not be discoverable or be held or governed by compliance policies.", - "displayName": "Send a teamwork activity to any user", - "id": "a267235f-af13-44dc-8385-c1dc93023186", - "origin": "Application", - "value": "TeamsActivity.Send" - }, - { - "description": "Allows the app to read terms of use acceptance statuses, without a signed in user.", - "displayName": "Read all terms of use acceptance statuses", - "id": "d8e4ec18-f6c0-4620-8122-c8b1f2bf400e", - "origin": "Application", - "value": "AgreementAcceptance.Read.All" - }, - { - "description": "Allows the app to read and write terms of use agreements, without a signed in user.", - "displayName": "Read and write all terms of use agreements", - "id": "c9090d00-6101-42f0-a729-c41074260d47", - "origin": "Application", - "value": "Agreement.ReadWrite.All" - }, - { - "description": "Allows the app to read terms of use agreements, without a signed in user.", - "displayName": "Read all terms of use agreements", - "id": "2f3e6f8c-093b-4c57-a58b-ba5ce494a169", - "origin": "Application", - "value": "Agreement.Read.All" - }, - { - "description": "Allows the app to read app consent requests and approvals, and deny or approve those requests without a signed-in user.", - "displayName": "Read and write all consent requests", - "id": "9f1b81a7-0223-4428-bfa4-0bcb5535f27d", - "origin": "Application", - "value": "ConsentRequest.ReadWrite.All" - }, - { - "description": "Allows the app to read and write your organization's consent requests policy without a signed-in user.", - "displayName": "Read and write your organization's consent request policy", - "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", - "origin": "Application", - "value": "Policy.ReadWrite.ConsentRequest" - }, - { - "description": "Allows the app to read consent requests and approvals without a signed-in user.", - "displayName": "Read all consent requests", - "id": "1260ad83-98fb-4785-abbb-d6cc1806fd41", - "origin": "Application", - "value": "ConsentRequest.Read.All" - }, - { - "description": "Allows the app to read basic mail properties in all mailboxes without a signed-in user. Includes all properties except body, previewBody, attachments and any extended properties.", - "displayName": "Read basic mail in all mailboxes", - "id": "693c5e45-0940-467d-9b8a-1022fb9d42ef", - "origin": "Application", - "value": "Mail.ReadBasic.All" - }, - { - "description": "Allows the app to read basic mail properties in all mailboxes without a signed-in user. Includes all properties except body, previewBody, attachments and any extended properties.", - "displayName": "Read basic mail in all mailboxes", - "id": "6be147d2-ea4f-4b5a-a3fa-3eab6f3c140a", - "origin": "Application", - "value": "Mail.ReadBasic" - }, - { - "description": "Allows the app to read and write feature rollout policies without a signed-in user. Includes abilities to assign and remove users and groups to rollout of a specific feature.", - "displayName": "Read and write feature rollout policies", - "id": "2044e4f1-e56c-435b-925c-44cd8f6ba89a", - "origin": "Application", - "value": "Policy.ReadWrite.FeatureRollout" - }, - { - "description": "Allows the app to read and manage the role-based access control (RBAC) settings for your company's directory, without a signed-in user. This includes instantiating directory roles and managing directory role membership, and reading directory role templates, directory roles and memberships.", - "displayName": "Read and write all directory RBAC settings", - "id": "9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8", - "origin": "Application", - "value": "RoleManagement.ReadWrite.Directory" - }, - { - "description": "Allows the app to read the role-based access control (RBAC) settings for your company's directory, without a signed-in user. This includes reading directory role templates, directory roles and memberships.", - "displayName": "Read all directory RBAC settings", - "id": "483bed4a-2ad3-4361-a73b-c83ccdbdc53c", - "origin": "Application", - "value": "RoleManagement.Read.Directory" - }, - { - "description": "Allows the app to read and write the organization and related resources, without a signed-in user.\u00a0Related resources include things like subscribed skus and tenant branding information.", - "displayName": "Read and write organization information", - "id": "292d869f-3427-49a8-9dab-8c70152b74e9", - "origin": "Application", - "value": "Organization.ReadWrite.All" - }, - { - "description": "Allows the app to read the organization and related resources, without a signed-in user.\u00a0Related resources include things like subscribed skus and tenant branding information.", - "displayName": "Read organization information", - "id": "498476ce-e0fe-48b0-b801-37ba7e2685c6", - "origin": "Application", - "value": "Organization.Read.All" - }, - { - "description": "Allows the app to read company places (conference rooms and room lists) for calendar events and other applications, without a signed-in user.", - "displayName": "Read all company places", - "id": "913b9306-0ce1-42b8-9137-6a7df690a760", - "origin": "Application", - "value": "Place.Read.All" - }, - { - "description": "Allows the app to read the memberships of hidden groups and administrative units without a signed-in user.", - "displayName": "Read all hidden memberships", - "id": "658aa5d8-239f-45c4-aa12-864f4fc7e490", - "origin": "Application", - "value": "Member.Read.Hidden" - }, - { - "description": "Allow the app to read or write items in all external datasets that the app is authorized to access", - "displayName": "Read and write items in external datasets", - "id": "38c3d6ee-69ee-422f-b954-e17819665354", - "origin": "Application", - "value": "ExternalItem.ReadWrite.All" - }, - { - "description": "Allows the app to read, update, delete and perform actions on access reviews, reviewers, decisions and settings in the organization for group and app memberships, without a signed-in user.", - "displayName": "Manage access reviews for group and app memberships", - "id": "18228521-a591-40f1-b215-5fad4488c117", - "origin": "Application", - "value": "AccessReview.ReadWrite.Membership" - }, - { - "description": "Allows the app to read properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups, without a signed-in user.", - "displayName": "Read Microsoft Intune device configuration and policies", - "id": "dc377aa6-52d8-4e23-b271-2a7ae04cedf3", - "origin": "Application", - "value": "DeviceManagementConfiguration.Read.All" - }, - { - "description": "Allows the app to read the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune, without a signed-in user.", - "displayName": "Read Microsoft Intune apps", - "id": "7a6ee1e7-141e-4cec-ae74-d9db155731ff", - "origin": "Application", - "value": "DeviceManagementApps.Read.All" - }, - { - "description": "Allows the app to read the properties of devices managed by Microsoft Intune, without a signed-in user.", - "displayName": "Read Microsoft Intune devices", - "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", - "origin": "Application", - "value": "DeviceManagementManagedDevices.Read.All" - }, - { - "description": "Allows the app to read the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings, without a signed-in user.", - "displayName": "Read Microsoft Intune RBAC settings", - "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", - "origin": "Application", - "value": "DeviceManagementRBAC.Read.All" - }, - { - "description": "Allows the app to read Microsoft Intune service properties including device enrollment and third party service connection configuration, without a signed-in user.", - "displayName": "Read Microsoft Intune configuration", - "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", - "origin": "Application", - "value": "DeviceManagementServiceConfig.Read.All" - }, - { - "description": "Allows the app to create, view, update and delete on-premises published resources, on-premises agents and agent groups, as part of a hybrid identity configuration, without a signed in user.", - "displayName": "Manage on-premises published resources", - "id": "0b57845e-aa49-4e6f-8109-ce654fffa618", - "origin": "Application", - "value": "OnPremisesPublishingProfiles.ReadWrite.All" - }, - { - "description": "Allows the app to read and write trust framework key set properties without a signed-in user.", - "displayName": "Read and write trust framework key sets", - "id": "4a771c9a-1cf2-4609-b88e-3d3e02d539cd", - "origin": "Application", - "value": "TrustFrameworkKeySet.ReadWrite.All" - }, - { - "description": "Allows the app to read trust framework key set properties without a signed-in user.", - "displayName": "Read trust framework key sets", - "id": "fff194f1-7dce-4428-8301-1badb5518201", - "origin": "Application", - "value": "TrustFrameworkKeySet.Read.All" - }, - { - "description": "Allows the app to read and write your organization's trust framework policies without a signed in user.", - "displayName": "Read and write your organization's trust framework policies", - "id": "79a677f7-b79d-40d0-a36a-3e6f8688dd7a", - "origin": "Application", - "value": "Policy.ReadWrite.TrustFramework" - }, - { - "description": "Allows the app to read all your organization's policies without a signed in user.", - "displayName": "Read your organization's policies", - "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", - "origin": "Application", - "value": "Policy.Read.All" - }, - { - "description": "Allows the app to read and write your organization\u2019s identity (authentication) providers\u2019 properties without a signed in user.", - "displayName": "Read and write identity providers", - "id": "90db2b9a-d928-4d33-a4dd-8442ae3d41e4", - "origin": "Application", - "value": "IdentityProvider.ReadWrite.All" - }, - { - "description": "Allows the app to read your organization\u2019s identity (authentication) providers\u2019 properties without a signed in user.", - "displayName": "Read identity providers", - "id": "e321f0bb-e7f7-481e-bb28-e3b0b32d4bd0", - "origin": "Application", - "value": "IdentityProvider.Read.All" - }, - { - "description": "Allows the app to create, read, update, and delete administrative units and manage administrative unit membership without a signed-in user.", - "displayName": "Read and write all administrative units", - "id": "5eb59dd3-1da2-4329-8733-9dabdc435916", - "origin": "Application", - "value": "AdministrativeUnit.ReadWrite.All" - }, - { - "description": "Allows the app to read administrative units and administrative unit membership without a signed-in user.", - "displayName": "Read all administrative units", - "id": "134fd756-38ce-4afd-ba33-e9623dbe66c2", - "origin": "Application", - "value": "AdministrativeUnit.Read.All" - }, - { - "description": "Allows an app to read published sensitivity labels and label policy settings for the entire organization or a specific user, without a signed in user.", - "displayName": "Read all published labels and label policies for an organization.", - "id": "19da66cb-0fb0-4390-b071-ebc76a349482", - "origin": "Application", - "value": "InformationProtectionPolicy.Read.All" - }, - { - "description": "Allows the app to read all the OneNote notebooks in your organization, without a signed-in user.", - "displayName": "Read all OneNote notebooks", - "id": "3aeca27b-ee3a-4c2b-8ded-80376e2134a4", - "origin": "Application", - "value": "Notes.Read.All" - }, - { - "description": "Allows the app to invite guest users to the organization, without a signed-in user.", - "displayName": "Invite guest users to the organization", - "id": "09850681-111b-4a89-9bed-3f2cae46d706", - "origin": "Application", - "value": "User.Invite.All" - }, - { - "description": "Allows the app to read, create, update and delete all files in all site collections without a signed in user. ", - "displayName": "Read and write files in all site collections", - "id": "75359482-378d-4052-8f01-80520e7db3cd", - "origin": "Application", - "value": "Files.ReadWrite.All" - }, - { - "description": "Allows the app to create threat indicators, and fully manage those threat indicators (read, update and delete), without a signed-in user. \u00a0It cannot update any threat indicators it does not own.", - "displayName": "Manage threat indicators this app creates or owns", - "id": "21792b6c-c986-4ffc-85de-df9da54b52fa", - "origin": "Application", - "value": "ThreatIndicators.ReadWrite.OwnedBy" - }, - { - "description": "Allows the app to read or update security actions, without a signed-in user.", - "displayName": "Read and update your organization's security actions", - "id": "f2bf083f-0179-402a-bedb-b2784de8a49b", - "origin": "Application", - "value": "SecurityActions.ReadWrite.All" - }, - { - "description": "Allows the app to read security actions, without a signed-in user.", - "displayName": "Read your organization's security actions", - "id": "5e0edab9-c148-49d0-b423-ac253e121825", - "origin": "Application", - "value": "SecurityActions.Read.All" - }, - { - "description": "Allows the app to read your organization\u2019s security events without a signed-in user. Also allows the app to update editable properties in security events.", - "displayName": "Read and update your organization\u2019s security events", - "id": "d903a879-88e0-4c09-b0c9-82f6a1333f84", - "origin": "Application", - "value": "SecurityEvents.ReadWrite.All" - }, - { - "description": "Allows the app to read your organization\u2019s security events without a signed-in user.", - "displayName": "Read your organization\u2019s security events", - "id": "bf394140-e372-4bf9-a898-299cfc7564e5", - "origin": "Application", - "value": "SecurityEvents.Read.All" - }, - { - "description": "Allows an app to read and write all chat messages in Microsoft Teams, without a signed-in user.", - "displayName": "Read and write all chat messages", - "id": "294ce7c9-31ba-490a-ad7d-97a7d075e4ed", - "origin": "Application", - "value": "Chat.ReadWrite.All" - }, - { - "description": "Allows the app to read and update identity risk detection information for your organization without a signed-in user. Update operations include confirming risk event detections.\u00a0", - "displayName": "Read and write all risk detection information", - "id": "db06fb33-1953-4b7b-a2ac-f1e2c854f7ae", - "origin": "Application", - "value": "IdentityRiskEvent.ReadWrite.All" - }, - { - "description": "Allows the app to read and update identity risky user information for your organization without a signed-in user. \u00a0Update operations include dismissing risky users.", - "displayName": "Read and write all risky user information", - "id": "656f6061-f9fe-4807-9708-6a2e0934df76", - "origin": "Application", - "value": "IdentityRiskyUser.ReadWrite.All" - }, - { - "description": "Allows the app to read all files in all site collections without a signed in user.", - "displayName": "Read files in all site collections", - "id": "01d4889c-1287-42c6-ac1f-5d1e02578ef6", - "origin": "Application", - "value": "Files.Read.All" - }, - { - "description": "Allows the app to read the identity risk event information for your organization without a signed in user.", - "displayName": "Read all identity risk event information", - "id": "6e472fd1-ad78-48da-a0f0-97ab2c6b769e", - "origin": "Application", - "value": "IdentityRiskEvent.Read.All" - }, - { - "description": "Allows the app to read a limited subset of properties from both the structure of schools and classes in the organization's roster and education-specific information about all users. Includes name, status, role, email address and photo.", - "displayName": "Read a limited subset of the organization's roster", - "id": "0d412a8c-a06c-439f-b3ec-8abcf54d2f96", - "origin": "Application", - "value": "EduRoster.ReadBasic.All" - }, - { - "description": "Allows the app to read the structure of schools and classes in the organization's roster and education-specific information about all users to be read.", - "displayName": "Read the organization's roster", - "id": "e0ac9e1b-cb65-4fc5-87c5-1a8bc181f648", - "origin": "Application", - "value": "EduRoster.Read.All" - }, - { - "description": "Allows the app to read and write the structure of schools and classes in the organization's roster and education-specific information about all users to be read and written.", - "displayName": "Read and write the organization's roster", - "id": "d1808e82-ce13-47af-ae0d-f9b254e6d58a", - "origin": "Application", - "value": "EduRoster.ReadWrite.All" - }, - { - "description": "Read the state and settings of all Microsoft education apps.", - "displayName": "Read Education app settings", - "id": "7c9db06a-ec2d-4e7b-a592-5a1e30992566", - "origin": "Application", - "value": "EduAdministration.Read.All" - }, - { - "description": "Manage the state and settings of all Microsoft education apps.", - "displayName": "Manage education app settings", - "id": "9bc431c3-b8bc-4a8d-a219-40f10f92eff6", - "origin": "Application", - "value": "EduAdministration.ReadWrite.All" - }, - { - "description": "Allows the app to read the identity risky user information for your organization without a signed in user.", - "displayName": "Read all identity risky user information", - "id": "dc5007c0-2d7d-4c42-879c-2dab87571379", - "origin": "Application", - "value": "IdentityRiskyUser.Read.All" - }, - { - "description": "Allows the app to read and update user profiles without a signed in user.", - "displayName": "Read and write all users' full profiles", - "id": "741f803b-c850-494e-b5df-cde7c675a1ca", - "origin": "Application", - "value": "User.ReadWrite.All" - }, - { - "description": "Allows the app to read user profiles without a signed in user.", - "displayName": "Read all users' full profiles", - "id": "df021288-bdef-4463-88db-98f22de89214", - "origin": "Application", - "value": "User.Read.All" - }, - { - "description": "Allows the app to read and query your audit log activities, without a signed-in user.", - "displayName": "Read all audit log data", - "id": "b0afded3-3588-46d8-8b3d-9842eff778da", - "origin": "Application", - "value": "AuditLog.Read.All" - }, - { - "description": "Allows the app to create other applications, and fully manage those applications (read, update, update application secrets and delete), without a signed-in user. \u00a0It cannot update any apps that it is not an owner of.", - "displayName": "Manage apps that this app creates or owns", - "id": "18a4783c-866b-4cc7-a460-3d5e5662c884", - "origin": "Application", - "value": "Application.ReadWrite.OwnedBy" - }, - { - "description": "Allows the app to export data (e.g. customer content or system-generated logs), associated with any user in your company, when the app is used by a privileged user (e.g. a Company Administrator).", - "displayName": "Export user's data", - "id": "405a51b5-8d8d-430b-9842-8be4b0e9f324", - "origin": "Application", - "value": "User.Export.All" - }, - { - "description": "Allows the app to read, update, delete and perform actions on programs and program controls in the organization, without a signed-in user.", - "displayName": "Manage all programs", - "id": "60a901ed-09f7-4aa5-a16e-7dd3d6f9de36", - "origin": "Application", - "value": "ProgramControl.ReadWrite.All" - }, - { - "description": "Allows the app to read programs and program controls in the organization, without a signed-in user.", - "displayName": "Read all programs", - "id": "eedb7fdd-7539-4345-a38b-4839e4a84cbd", - "origin": "Application", - "value": "ProgramControl.Read.All" - }, - { - "description": "Allows the app to read, update, delete and perform actions on access reviews, reviewers, decisions and settings in the organization, without a signed-in user.", - "displayName": "Manage all access reviews", - "id": "ef5f7d5c-338f-44b0-86c3-351f46c8bb5f", - "origin": "Application", - "value": "AccessReview.ReadWrite.All" - }, - { - "description": "Allows the app to read access reviews, reviewers, decisions and settings in the organization, without a signed-in user.", - "displayName": "Read all access reviews", - "id": "d07a8cc0-3d51-4b77-b3b0-32704d1f69fa", - "origin": "Application", - "value": "AccessReview.Read.All" - }, - { - "description": "Allows an app to read all service usage reports without a signed-in user. Services that provide usage reports include Office 365 and Azure Active Directory.", - "displayName": "Read all usage reports", - "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", - "origin": "Application", - "value": "Reports.Read.All" - }, - { - "description": "Allows the app to read any user's scored list of relevant people, without a signed-in user. The list can include local contacts, contacts from social networking, your organization's directory, and people from recent communications (such as email and Skype).", - "displayName": "Read all users' relevant people lists", - "id": "b528084d-ad10-4598-8b93-929746b4d7d6", - "origin": "Application", - "value": "People.Read.All" - }, - { - "description": "Allows the app to update Microsoft Teams 1-to-1 or group chat messages by patching a set of Data Loss Prevention (DLP) policy violation properties to handle the output of DLP processing.", - "displayName": "Flag chat messages for violating policy", - "id": "7e847308-e030-4183-9899-5235d7270f58", - "origin": "Application", - "value": "Chat.UpdatePolicyViolation.All" - }, - { - "description": "Allows the app to read all 1-to-1 or group chat messages in Microsoft Teams.", - "displayName": "Read all chat messages", - "id": "6b7d71aa-70aa-4810-a8d9-5d9fb2830017", - "origin": "Application", - "value": "Chat.Read.All" - }, - { - "description": "Allows the app to read all channel messages in Microsoft Teams", - "displayName": "Read all channel messages", - "id": "7b2449af-6ccd-4f4d-9f78-e550c193f0d1", - "origin": "Application", - "value": "ChannelMessage.Read.All" - }, - { - "description": "Allows the app to update Microsoft Teams channel messages by patching a set of Data Loss Prevention (DLP) policy violation properties to handle the output of DLP processing.", - "displayName": "Flag channel messages for violating policy", - "id": "4d02b0cc-d90b-441f-8d82-4fb55c34d6bb", - "origin": "Application", - "value": "ChannelMessage.UpdatePolicyViolation.All" - }, - { - "description": "Allows the app to create, read, update and delete applications and service principals without a signed-in user. Does not allow management of consent grants.", - "displayName": "Read and write all applications", - "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", - "origin": "Application", - "value": "Application.ReadWrite.All" - }, - { - "description": "Allows the app to create, read, update, and delete user's mailbox settings without a signed-in user. Does not include permission to send mail.", - "displayName": "Read and write all user mailbox settings", - "id": "6931bccd-447a-43d1-b442-00a195474933", - "origin": "Application", - "value": "MailboxSettings.ReadWrite" - }, - { - "description": "Allows the app to read and write all domain properties without a signed in user. \u00a0Also allows the app to add, \u00a0verify and remove domains.", - "displayName": "Read and write domains", - "id": "7e05723c-0bb0-42da-be95-ae9f08a6e53c", - "origin": "Application", - "value": "Domain.ReadWrite.All" - }, - { - "description": "Allows the app to read user's mailbox settings without a signed-in user. Does not include permission to send mail.", - "displayName": "Read all user mailbox settings", - "id": "40f97065-369a-49f4-947c-6a255697ae91", - "origin": "Application", - "value": "MailboxSettings.Read" - }, - { - "description": "Allows the app to read mail in all mailboxes without a signed-in user.", - "displayName": "Read mail in all mailboxes", - "id": "810c84a8-4a9e-49e6-bf7d-12d183f40d01", - "origin": "Application", - "value": "Mail.Read" - }, - { - "description": "Allows the app to create, read, update, and delete mail in all mailboxes without a signed-in user. Does not include permission to send mail.", - "displayName": "Read and write mail in all mailboxes", - "id": "e2a3a72e-5f79-4c64-b1b1-878b674786c9", - "origin": "Application", - "value": "Mail.ReadWrite" - }, - { - "description": "Allows the app to send mail as any user without a signed-in user.", - "displayName": "Send mail as any user", - "id": "b633e1c5-b582-4048-a93e-9f11b44c7e96", - "origin": "Application", - "value": "Mail.Send" - }, - { - "description": "Allows the app to read all contacts in all mailboxes without a signed-in user.", - "displayName": "Read contacts in all mailboxes", - "id": "089fe4d0-434a-44c5-8827-41ba8a0b17f5", - "origin": "Application", - "value": "Contacts.Read" - }, - { - "description": "Allows the app to create, read, update, and delete all contacts in all mailboxes without a signed-in user.", - "displayName": "Read and write contacts in all mailboxes", - "id": "6918b873-d17a-4dc1-b314-35f528134491", - "origin": "Application", - "value": "Contacts.ReadWrite" - }, - { - "description": "Allows the app to read data in your organization's directory, such as users, groups and apps, without a signed-in user.", - "displayName": "Read directory data", - "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", - "origin": "Application", - "value": "Directory.Read.All" - }, - { - "description": "Allows the app to read and write data in your organization's directory, such as users, and groups, without a signed-in user. Does not allow user or group deletion.", - "displayName": "Read and write directory data", - "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", - "origin": "Application", - "value": "Directory.ReadWrite.All" - }, - { - "description": "Allows the app to read and write all device properties without a signed in user. Does not allow device creation, device deletion or update of device alternative security identifiers.", - "displayName": "Read and write devices", - "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", - "origin": "Application", - "value": "Device.ReadWrite.All" - }, - { - "description": "Allows the app to read events of all calendars without a signed-in user.", - "displayName": "Read calendars in all mailboxes", - "id": "798ee544-9d2d-430c-a058-570e29e34338", - "origin": "Application", - "value": "Calendars.Read" - }, - { - "description": "Allows the app to create, read, update, and delete events of all calendars without a signed-in user.", - "displayName": "Read and write calendars in all mailboxes", - "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", - "origin": "Application (Office 365 Exchange Online)", - "value": "Calendars.ReadWrite.All" - }, - { - "description": "Allows the app to create, read, update, and delete user's mailbox settings without a signed-in user. Does not include permission to send mail.", - "displayName": "Read and write all user mailbox settings", - "id": "f9156939-25cd-4ba8-abfe-7fabcf003749", - "origin": "Application (Office 365 Exchange Online)", - "value": "Mailbox.Settings.ReadWrite" - }, - { - "description": "Allows the app to read your organization's user flows, without a signed-in user.", - "displayName": "Read all identity user flows", - "id": "1b0c317f-dd31-4305-9932-259a8b6e8099", - "origin": "Application", - "value": "IdentityUserFlow.Read.All" - }, - { - "description": "Allows the app to read or write your organization's user flows, without a signed-in user.", - "displayName": "Read and write all identity user flows", - "id": "65319a09-a2be-469d-8782-f6b07debf789", - "origin": "Application", - "value": "IdentityUserFlow.ReadWrite.All" - }, - { - "description": "Allows the app to read and create online meetings as an application in your organization.", - "displayName": "Read and create online meetings", - "id": "b8bb2037-6e08-44ac-a4ea-4674e010e2a4", - "origin": "Application", - "value": "OnlineMeetings.ReadWrite.All" - }, - { - "description": "Allows the app to read online meeting details in your organization, without a signed-in user.", - "displayName": "Read online meeting details", - "id": "c1684f21-1984-47fa-9d61-2dc8c296bb70", - "origin": "Application", - "value": "OnlineMeetings.Read.All" - }, - { - "description": "Allows the app to get direct access to media streams in a call, without a signed-in user.", - "displayName": "Access media streams in a call as an app", - "id": "a7a681dc-756e-4909-b988-f160edc6655f", - "origin": "Application", - "value": "Calls.AccessMedia.All" - }, - { - "description": "Allows the app to anonymously join group calls and scheduled meetings in your organization, without a signed-in user. \u00a0The app will be joined as a guest to meetings in your organization.", - "displayName": "Join group calls and meetings as a guest", - "id": "fd7ccf6b-3d28-418b-9701-cd10f5cd2fd4", - "origin": "Application", - "value": "Calls.JoinGroupCallAsGuest.All" - }, - { - "description": "Allows the app to join group calls and scheduled meetings in your organization, without a signed-in user. \u00a0The app will be joined with the privileges of a directory user to meetings in your organization.", - "displayName": "Join group calls and meetings as an app", - "id": "f6b49018-60ab-4f81-83bd-22caeabfed2d", - "origin": "Application", - "value": "Calls.JoinGroupCall.All" - }, - { - "description": "Allows the app to place outbound calls to multiple users and add participants to meetings in your organization, without a signed-in user.", - "displayName": "Initiate outgoing group calls from the app", - "id": "4c277553-8a09-487b-8023-29ee378d8324", - "origin": "Application", - "value": "Calls.InitiateGroupCall.All" - }, - { - "description": "Allows the app to place outbound calls to a single user and transfer calls to users in your organization\u2019s directory, without a signed-in user.", - "displayName": "Initiate outgoing 1 to 1 calls from the app", - "id": "284383ee-7f6e-4e40-a2a8-e85dcb029101", - "origin": "Application", - "value": "Calls.Initiate.All" - }, - { - "description": "Allows the app to read all organizational contacts without a signed-in user. These contacts are managed by the organization and are different from a user's personal contacts.", - "displayName": "Read organizational contacts", - "id": "e1a88a34-94c4-4418-be12-c87b00e26bea", - "origin": "Application", - "value": "OrgContact.Read.All" - }, - { - "description": "Allows the app to read and write the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune, without a signed-in user.", - "displayName": "Read and write Microsoft Intune apps", - "id": "78145de6-330d-4800-a6ce-494ff2d33d07", - "origin": "Application", - "value": "DeviceManagementApps.ReadWrite.All" - }, - { - "description": "Allows the app to read and write properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups, without a signed-in user.", - "displayName": "Read and write Microsoft Intune device configuration and policies", - "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", - "origin": "Application", - "value": "DeviceManagementConfiguration.ReadWrite.All" - }, - { - "description": "Allows the app to perform remote high impact actions such as wiping the device or resetting the passcode on devices managed by Microsoft Intune, without a signed-in user.", - "displayName": "Perform user-impacting remote actions on Microsoft Intune devices", - "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", - "origin": "Application", - "value": "DeviceManagementManagedDevices.PrivilegedOperations.All" - }, - { - "description": "Allows the app to read and write the properties of devices managed by Microsoft Intune, without a signed-in user. Does not allow high impact operations such as remote wipe and password reset on the device\u2019s owner", - "displayName": "Read and write Microsoft Intune devices", - "id": "243333ab-4d21-40cb-a475-36241daa0842", - "origin": "Application", - "value": "DeviceManagementManagedDevices.ReadWrite.All" - }, - { - "description": "Allows the app to read and write the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings, without a signed-in user.", - "displayName": "Read and write Microsoft Intune RBAC settings", - "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", - "origin": "Application", - "value": "DeviceManagementRBAC.ReadWrite.All" - }, - { - "description": "Allows the app to read and write Microsoft Intune service properties including device enrollment and third party service connection configuration, without a signed-in user.", - "displayName": "Read and write Microsoft Intune configuration", - "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", - "origin": "Application", - "value": "DeviceManagementServiceConfig.ReadWrite.All" - }, - { - "description": "Allows the app to manage permission grants for application permissions to any API (including Microsoft Graph) and application assignments for any app, without a signed-in user.", - "displayName": "Manage app permission grants and app role assignments", - "id": "06b708a9-e830-4db3-a914-8e69da51d44f", - "origin": "Application", - "value": "AppRoleAssignment.ReadWrite.All" - }, - { - "description": "Allows the app to manage permission grants for delegated permissions exposed by any API (including Microsoft Graph), without a signed-in user.", - "displayName": "Manage all delegated permission grants", - "id": "8e8e4742-1d95-4f68-9d56-6ee75648c72a", - "origin": "Application", - "value": "DelegatedPermissionGrant.ReadWrite.All" - }, - { - "description": "Allows the app to read all users' teamwork activity feed, without a signed-in user.", - "displayName": "Read all users' teamwork activity feed", - "id": "70dec828-f620-4914-aa83-a29117306807", - "origin": "Application", - "value": "TeamsActivity.Read.All" - }, - { - "description": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD built-in and custom administrative roles in your organization, without a signed-in user.", - "displayName": "Read privileged access to Azure AD roles", - "id": "4cdc2547-9148-4295-8d11-be0db1391d6b", - "origin": "Application", - "value": "PrivilegedAccess.Read.AzureAD" - }, - { - "description": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups in your organization, without a signed-in user.", - "displayName": "Read privileged access to Azure AD groups", - "id": "01e37dc9-c035-40bd-b438-b2879c4870a6", - "origin": "Application", - "value": "PrivilegedAccess.Read.AzureADGroup" - }, - { - "description": "Allows the app to read time-based assignment and just-in-time elevation of user privileges to audit Azure resources in your organization, without a signed-in user.", - "displayName": "Read privileged access to Azure resources", - "id": "5df6fe86-1be0-44eb-b916-7bd443a71236", - "origin": "Application", - "value": "PrivilegedAccess.Read.AzureResources" - }, - { - "description": "Allows the app to request and manage time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD built-in and custom administrative roles in your organization, without a signed-in user.", - "displayName": "Read and write privileged access to Azure AD roles", - "id": "854d9ab1-6657-4ec8-be45-823027bcd009", - "origin": "Application", - "value": "PrivilegedAccess.ReadWrite.AzureAD" - }, - { - "description": "Allows the app to request and manage time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups in your organization, without a signed-in user.", - "displayName": "Read and write privileged access to Azure AD groups", - "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", - "origin": "Application", - "value": "PrivilegedAccess.ReadWrite.AzureADGroup" - }, - { - "description": "Allows the app to request and manage time-based assignment and just-in-time elevation of Azure resources (like your subscriptions, resource groups, storage, compute) in your organization, without a signed-in user.", - "displayName": "Read and write privileged access to Azure resources", - "id": "6f9d5abc-2db6-400b-a267-7de22a40fb87", - "origin": "Application", - "value": "PrivilegedAccess.ReadWrite.AzureResources" - }, - { - "description": "Allows the app to read all the indicators for your organization, without a signed-in user.", - "displayName": "Read all threat indicators", - "id": "197ee4e9-b993-4066-898f-d6aecc55125b", - "origin": "Application", - "value": "ThreatIndicators.Read.All" - }, - { - "description": "Allows the app to send, read, update and delete user\u2019s notifications, without a signed-in user.", - "displayName": "Deliver and manage all user's notifications", - "id": "4e774092-a092-48d1-90bd-baad67c7eb47", - "origin": "Application", - "value": "UserNotification.ReadWrite.CreatedByApp" - }, - { - "description": "Allows the app to read all applications and service principals without a signed-in user.", - "displayName": "Read all applications", - "id": "9a5d68dd-52b0-4cc2-bd40-abcf44ac3a30", - "origin": "Application", - "value": "Application.Read.All" - }, - { - "description": "Allows the app to read memberships and basic group properties for all groups without a signed-in user.", - "displayName": "Read all group memberships", - "id": "98830695-27a2-44f7-8c18-0c3ebc9698f6", - "origin": "Application", - "value": "GroupMember.Read.All" - }, - { - "description": "Allows the app to list groups, read basic properties, read and update the membership of the groups this app has access to without a signed-in user. Group properties and owners cannot be updated and groups cannot be deleted.", - "displayName": "Read and write all group memberships", - "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", - "origin": "Application", - "value": "GroupMember.ReadWrite.All" - }, - { - "description": "Allows the app to create groups without a signed-in user.", - "displayName": "Create groups", - "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", - "origin": "Application", - "value": "Group.Create" - }, - { - "description": "Allows an app to read your organization's threat assessment requests, without a signed-in user.", - "displayName": "Read threat assessment requests", - "id": "f8f035bb-2cce-47fb-8bf5-7baf3ecbee48", - "origin": "Application", - "value": "ThreatAssessment.Read.All" - }, - { - "description": "Allows the app to read all schedules, schedule groups, shifts and associated entities in the Teams or Shifts application without a signed-in user.", - "displayName": "Read all schedule items", - "id": "7b2ebf90-d836-437f-b90d-7b62722c4456", - "origin": "Application", - "value": "Schedule.Read.All" - }, - { - "description": "Allows the app to manage all schedules, schedule groups, shifts and associated entities in the Teams or Shifts application without a signed-in user.", - "displayName": "Read and write all schedule items", - "id": "b7760610-0545-4e8a-9ec3-cce9e63db01c", - "origin": "Application", - "value": "Schedule.ReadWrite.All" - }, - { - "description": "Allows the app to read call records for all calls and online meetings without a signed-in user.", - "displayName": "Read all call records", - "id": "45bbb07e-7321-4fd7-a8f6-3ff27e6a81c8", - "origin": "Application", - "value": "CallRecords.Read.All" - }, - { - "description": "Allows the app to read and write your organization's conditional access policies, without a signed-in user.", - "displayName": "Read and write your organization's conditional access policies", - "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", - "origin": "Application", - "value": "Policy.ReadWrite.ConditionalAccess" - }, - { - "description": "Allows the application to read and write authentication methods of all users in your organization, without a signed-in user. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods", - "displayName": "Read and write all users' authentication methods ", - "id": "50483e42-d915-4231-9639-7fdb7fd190e5", - "origin": "Application", - "value": "UserAuthenticationMethod.ReadWrite.All" - }, - { - "description": " Allows the app to read authentication methods of all users in your organization, without a signed-in user. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", - "displayName": " Read all users' authentication methods", - "id": "38d9df27-64da-44fd-b7c5-a6fbac20248f", - "origin": "Application", - "value": "UserAuthenticationMethod.Read.All" - }, - { - "description": "Allows the app to create tabs in any team in Microsoft Teams, without a signed-in user. This does not grant the ability to read, modify or delete tabs after they are created, or give access to the content inside the tabs.", - "displayName": "Create tabs in Microsoft Teams.", - "id": "49981c42-fd7b-4530-be03-e77b21aed25e", - "origin": "Application", - "value": "TeamsTab.Create" - }, - { - "description": "Read the names and settings of tabs inside any team in Microsoft Teams, without a signed-in user. This does not give access to the content inside the tabs. ", - "displayName": "Read tabs in Microsoft Teams.", - "id": "46890524-499a-4bb2-ad64-1476b4f3e1cf", - "origin": "Application", - "value": "TeamsTab.Read.All" - }, - { - "description": "Read and write tabs in any team in Microsoft Teams, without a signed-in user. This does not give access to the content inside the tabs.", - "displayName": "Read and write tabs in Microsoft Teams.", - "id": "a96d855f-016b-47d7-b51c-1218a98d791c", - "origin": "Application", - "value": "TeamsTab.ReadWrite.All" - }, - { - "description": "Allows the app to read all domain properties without a signed-in user.", - "displayName": "Read domains", - "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", - "origin": "Application", - "value": "Domain.Read.All" - }, - { - "description": "Allows the app to read and write your organization's application configuration policies, without a signed-in user. This includes policies such as activityBasedTimeoutPolicy, claimsMappingPolicy, homeRealmDiscoveryPolicy, tokenIssuancePolicy and tokenLifetimePolicy.", - "displayName": "Read and write your organization's application configuration policies", - "id": "be74164b-cff1-491c-8741-e671cb536e13", - "origin": "Application", - "value": "Policy.ReadWrite.ApplicationConfiguration" - }, - { - "description": "Allows the app to read your organization's devices' configuration information without a signed-in user.", - "displayName": "Read all devices", - "id": "7438b122-aefc-4978-80ed-43db9fcc7715", - "origin": "Application", - "value": "Device.Read.All" - }, - { - "description": "Allows the app to read, update and delete identities that are associated with a user's account, without a signed in user. This controls the identities users can sign-in with.", - "displayName": "Manage all users' identities", - "id": "c529cfca-c91b-489c-af2b-d92990b66ce6", - "origin": "Application", - "value": "User.ManageIdentities.All" - }, - { - "description": "Allows the app to read all users' shift schedule preferences without a signed-in user.", - "displayName": "Read all user shift preferences", - "id": "de023814-96df-4f53-9376-1e2891ef5a18", - "origin": "Application", - "value": "UserShiftPreferences.Read.All" - }, - { - "description": "Allows the app to manage all users' shift schedule preferences without a signed-in user.", - "displayName": "Read and write all user shift preferences", - "id": "d1eec298-80f3-49b0-9efb-d90e224798ac", - "origin": "Application", - "value": "UserShiftPreferences.ReadWrite.All" - }, - { - "description": "Allows the app to read all the OneNote notebooks in your organization, without a signed-in user.", - "displayName": "Read and write all OneNote notebooks", - "id": "0c458cef-11f3-48c2-a568-c66751c238c0", - "origin": "Application", - "value": "Notes.ReadWrite.All" - }, - { - "description": "Allows the app to have full control of all site collections without a signed in user.", - "displayName": "Have full control of all site collections", - "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", - "origin": "Application", - "value": "Sites.FullControl.All" - }, - { - "description": "Allows the app to create or delete document libraries and lists in all site collections without a signed in user.", - "displayName": "Create, edit, and delete items and lists in all site collections", - "id": "0c0bf378-bf22-4481-8f81-9e89a9b4960a", - "origin": "Application", - "value": "Sites.Manage.All" - }, - { - "description": "Allows the app to read access packages and related entitlement management resources without a signed-in user.", - "displayName": "Read all entitlement management resources", - "id": "c74fd47d-ed3c-45c3-9a9e-b8676de685d2", - "origin": "Application", - "value": "EntitlementManagement.Read.All" - }, - { - "description": "Allows the app to read and write access packages and related entitlement management resources without a signed-in user.", - "displayName": "Read and write all entitlement management resources", - "id": "9acd699f-1e81-4958-b001-93b1d2506e19", - "origin": "Application", - "value": "EntitlementManagement.ReadWrite.All" - }, - { - "description": "Create channels in any team, without a signed-in user.", - "displayName": "Create channels", - "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", - "origin": "Application", - "value": "Channel.Create" - }, - { - "description": "Delete channels in any team, without a signed-in user.", - "displayName": "Delete channels", - "id": "6a118a39-1227-45d4-af0c-ea7b40d210bc", - "origin": "Application", - "value": "Channel.Delete.All" - }, - { - "description": "Read all channel names, channel descriptions, and channel settings, without a signed-in user.", - "displayName": "Read the names, descriptions, and settings of all channels", - "id": "c97b873f-f59f-49aa-8a0e-52b32d762124", - "origin": "Application", - "value": "ChannelSettings.Read.All" - }, - { - "description": "Read and write the names, descriptions, and settings of all channels, without a signed-in user.", - "displayName": "Read and write the names, descriptions, and settings of all channels", - "id": "243cded2-bd16-4fd6-a953-ff8177894c3d", - "origin": "Application", - "value": "ChannelSettings.ReadWrite.All" - }, - { - "description": "Get a list of all teams, without a signed-in user.", - "displayName": "Get a list of all teams", - "id": "2280dda6-0bfd-44ee-a2f4-cb867cfc4c1e", - "origin": "Application", - "value": "Team.ReadBasic.All" - }, - { - "description": "Read all channel names and channel descriptions, without a signed-in user.", - "displayName": "Read the names and descriptions of all channels", - "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", - "origin": "Application", - "value": "Channel.ReadBasic.All" - }, - { - "description": "Read and change all teams' settings, without a signed-in user.", - "displayName": "Read and change all teams' settings", - "id": "bdd80a03-d9bc-451d-b7c4-ce7c63fe3c8f", - "origin": "Application", - "value": "TeamSettings.ReadWrite.All" - }, - { - "description": "Read all team's settings, without a signed-in user.", - "displayName": "Read all teams' settings", - "id": "242607bd-1d2c-432c-82eb-bdb27baa23ab", - "origin": "Application", - "value": "TeamSettings.Read.All" - }, - { - "description": "Read the members of all teams, without a signed-in user.", - "displayName": "Read the members of all teams", - "id": "660b7406-55f1-41ca-a0ed-0b035e182f3e", - "origin": "Application", - "value": "TeamMember.Read.All" - }, - { - "description": "Add and remove members from all teams, without a signed-in user. Also allows changing a team member's role, for example from owner to non-owner.", - "displayName": "Add and remove members from all teams", - "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", - "origin": "Application", - "value": "TeamMember.ReadWrite.All" - }, - { - "description": "Read the members of all channels, without a signed-in user.", - "displayName": "Read the members of all channels", - "id": "3b55498e-47ec-484f-8136-9013221c06a9", - "origin": "Application", - "value": "ChannelMember.Read.All" - }, - { - "description": "Add and remove members from all channels, without a signed-in user. Also allows changing a member's role, for example from owner to non-owner.", - "displayName": "Add and remove members from all channels", - "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", - "origin": "Application", - "value": "ChannelMember.ReadWrite.All" - }, - { - "description": "Allows the app to read and write all authentication flow policies for the tenant, without a signed-in user.", - "displayName": "Read and write authentication flow policies", - "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", - "origin": "Application", - "value": "Policy.ReadWrite.AuthenticationFlows" - }, - { - "description": "Allows the app to read and write all authentication method policies for the tenant, without a signed-in user.\u00a0", - "displayName": "Read and write all authentication method policies\u00a0", - "id": "29c18626-4985-4dcd-85c0-193eef327366", - "origin": "Application", - "value": "Policy.ReadWrite.AuthenticationMethod" - }, - { - "description": "Allows the app to read and write your organization's authorization policy without a signed in user. For example, authorization policies can control some of the permissions that the out-of-the-box user role has by default.", - "displayName": "Read and write your organization's authorization policy", - "id": "fb221be6-99f2-473f-bd32-01c6a0e9ca3b", - "origin": "Application", - "value": "Policy.ReadWrite.Authorization" - }, - { - "description": "Read names and members of all one-to-one and group chats in Microsoft Teams, without a signed-in user.", - "displayName": "Read names and members of all chat threads", - "id": "b2e060da-3baf-4687-9611-f4ebc0f0cbde", - "origin": "Application", - "value": "Chat.ReadBasic.All" - }, - { - "description": "Allows the app to read policies related to consent and permission grants for applications, without a signed-in user.", - "displayName": "Read consent and permission grant policies", - "id": "9e640839-a198-48fb-8b9a-013fd6f6cbcd", - "origin": "Application", - "value": "Policy.Read.PermissionGrant" - }, - { - "description": "Allows the app to manage policies related to consent and permission grants for applications, without a signed-in user.", - "displayName": "Manage consent and permission grant policies", - "id": "a402ca1c-2696-4531-972d-6e5ee4aa11ea", - "origin": "Application", - "value": "Policy.ReadWrite.PermissionGrant" - }, - { - "description": "Allows the application to read printers without a signed-in user.\u00a0", - "displayName": "Read printers", - "id": "9709bb33-4549-49d4-8ed9-a8f65e45bb0f", - "origin": "Application", - "value": "Printer.Read.All" - }, - { - "description": "Allows the application to read and update printers without a signed-in user. Does not allow creating (registering) or deleting (unregistering) printers.", - "displayName": "Read and update printers", - "id": "f5b3f73d-6247-44df-a74c-866173fddab0", - "origin": "Application", - "value": "Printer.ReadWrite.All" - }, - { - "description": "Allows the application to perform advanced operations like redirecting a print job to another printer without a signed-in user. Also allows the application to read and update the metadata of print jobs.", - "displayName": "Perform advanced operations on print jobs", - "id": "58a52f47-9e36-4b17-9ebe-ce4ef7f3e6c8", - "origin": "Application", - "value": "PrintJob.Manage.All" - }, - { - "description": "Allows the application to read the metadata and document content of print jobs without a signed-in user.\u00a0", - "displayName": "Read print jobs", - "id": "ac6f956c-edea-44e4-bd06-64b1b4b9aec9", - "origin": "Application", - "value": "PrintJob.Read.All" - }, - { - "description": "Allows the application to read the metadata of print jobs without a signed-in user.\u00a0Does not allow access to print job document content.", - "displayName": "Read basic information for print jobs", - "id": "fbf67eee-e074-4ef7-b965-ab5ce1c1f689", - "origin": "Application", - "value": "PrintJob.ReadBasic.All" - }, - { - "description": "Allows the application to read and update the metadata and document content of print jobs without a signed-in user.", - "displayName": "Read and write print jobs", - "id": "5114b07b-2898-4de7-a541-53b0004e2e13", - "origin": "Application", - "value": "PrintJob.ReadWrite.All" - }, - { - "description": "Allows the application to read and update the metadata of print jobs without a signed-in user.\u00a0Does not allow access to print job document content.", - "displayName": "Read and write basic information for print jobs", - "id": "57878358-37f4-4d3a-8c20-4816e0d457b1", - "origin": "Application", - "value": "PrintJob.ReadWriteBasic.All" - }, - { - "description": "Allows the application to read and update print task definitions without a signed-in user.\u00a0", - "displayName": "Read, write and update print task definitions", - "id": "456b71a7-0ee0-4588-9842-c123fcc8f664", - "origin": "Application", - "value": "PrintTaskDefinition.ReadWrite.All" - }, - { - "description": "Allows the app to create chat and channel messages, without a signed in user. The app specifies which user appears as the sender, and can backdate the message to appear as if it was sent long ago. The messages can be sent to any chat or channel in the organization.", - "displayName": "Create chat and channel messages with anyone's identity and with any timestamp", - "id": "dfb0dd15-61de-45b2-be36-d6a69fba3c79", - "origin": "Application", - "value": "Teamwork.Migrate.All" - }, - { - "description": "Allows the app to read the Teams apps that are installed in any chat, without a signed-in user. Does not give the ability to read application-specific settings.", - "displayName": "Read installed Teams apps for all chats", - "id": "cc7e7635-2586-41d6-adaa-a8d3bcad5ee5", - "origin": "Application", - "value": "TeamsAppInstallation.ReadForChat.All" - }, - { - "description": "Allows the app to read the Teams apps that are installed in any team, without a signed-in user. Does not give the ability to read application-specific settings.", - "displayName": "Read installed Teams apps for all teams", - "id": "1f615aea-6bf9-4b05-84bd-46388e138537", - "origin": "Application", - "value": "TeamsAppInstallation.ReadForTeam.All" - }, - { - "description": "Allows the app to read the Teams apps that are installed for any user, without a signed-in user. Does not give the ability to read application-specific settings.", - "displayName": "Read installed Teams apps for all users", - "id": "9ce09611-f4f7-4abd-a629-a05450422a97", - "origin": "Application", - "value": "TeamsAppInstallation.ReadForUser.All" - }, - { - "description": "Allows the app to read, install, upgrade, and uninstall Teams apps in any chat, without a signed-in user. Does not give the ability to read application-specific settings.", - "displayName": "Manage Teams apps for all chats", - "id": "9e19bae1-2623-4c4f-ab6e-2664615ff9a0", - "origin": "Application", - "value": "TeamsAppInstallation.ReadWriteForChat.All" - }, - { - "description": "Allows the app to read, install, upgrade, and uninstall Teams apps in any team, without a signed-in user. Does not give the ability to read application-specific settings.", - "displayName": "Manage Teams apps for all teams", - "id": "5dad17ba-f6cc-4954-a5a2-a0dcc95154f0", - "origin": "Application", - "value": "TeamsAppInstallation.ReadWriteForTeam.All" - }, - { - "description": "Allows the app to read, install, upgrade, and uninstall Teams apps for any user, without a signed-in user. Does not give the ability to read application-specific settings.", - "displayName": "Manage Teams apps for all users", - "id": "74ef0291-ca83-4d02-8c7e-d2391e6a444f", - "origin": "Application", - "value": "TeamsAppInstallation.ReadWriteForUser.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall itself for any chat, without a signed-in user.", - "displayName": "Allow the Teams app to manage itself for all chats", - "id": "73a45059-f39c-4baf-9182-4954ac0e55cf", - "origin": "Application", - "value": "TeamsAppInstallation.ReadWriteSelfForChat.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall itself in any team, without a signed-in user.", - "displayName": "Allow the Teams app to manage itself for all teams", - "id": "9f67436c-5415-4e7f-8ac1-3014a7132630", - "origin": "Application", - "value": "TeamsAppInstallation.ReadWriteSelfForTeam.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall itself to any user, without a signed-in user.", - "displayName": "Allow the app to manage itself for all users", - "id": "908de74d-f8b2-4d6b-a9ed-2a17b3b78179", - "origin": "Application", - "value": "TeamsAppInstallation.ReadWriteSelfForUser.All" - }, - { - "description": "Allows the app to create teams without a signed-in user.\u00a0", - "displayName": "Create teams", - "id": "23fc2474-f741-46ce-8465-674744c5c361", - "origin": "Application", - "value": "Team.Create" - }, - { - "description": "Add and remove members from all teams, without a signed-in user. Does not allow adding or removing a member with the owner role. Additionally, does not allow the app to elevate an existing member to the owner role.", - "displayName": "Add and remove members with non-owner role for all teams", - "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", - "origin": "Application", - "value": "TeamMember.ReadWriteNonOwnerRole.All" - }, - { - "description": "Allows the app to read all term store data, without a signed-in user. This includes all sets, groups and terms in the term store.", - "displayName": "Read all term store data", - "id": "ea047cc2-df29-4f3e-83a3-205de61501ca", - "origin": "Application", - "value": "TermStore.Read.All" - }, - { - "description": "Allows the app to read, edit or write all term store data, without a signed-in user. This includes all sets, groups and terms in the term store.", - "displayName": "Read and write all term store data", - "id": "f12eb8d6-28e3-46e6-b2c0-b7e4dc69fc95", - "origin": "Application", - "value": "TermStore.ReadWrite.All" - }, - { - "description": "Allows the app to read your tenant's service health information, without a signed-in user. Health information may include service issues or service health overviews.", - "displayName": "Read service health", - "id": "79c261e0-fe76-4144-aad5-bdc68fbe4037", - "origin": "Application", - "value": "ServiceHealth.Read.All" - }, - { - "description": "Allows the app to read your tenant's service announcement messages, without a signed-in user. Messages may include information about new or changed features.", - "displayName": "Read service messages", - "id": "1b620472-6534-4fe6-9df2-4680e8aa28ec", - "origin": "Application", - "value": "ServiceMessage.Read.All" - }, - { - "description": "Allows the app to read all the short notes without a signed-in user.", - "displayName": "Read all users' short notes", - "id": "0c7d31ec-31ca-4f58-b6ec-9950b6b0de69", - "origin": "Application", - "value": "ShortNotes.Read.All" - }, - { - "description": "Allows the app to read, create, edit, and delete all the short notes without a signed-in user.", - "displayName": "Read, create, edit, and delete all users' short notes", - "id": "842c284c-763d-4a97-838d-79787d129bab", - "origin": "Application", - "value": "ShortNotes.ReadWrite.All" - }, - { - "description": "Allows the app to read your organization's conditional access policies, without a signed-in user.", - "displayName": "Read your organization's conditional access policies", - "id": "37730810-e9ba-4e46-b07e-8ca78d182097", - "origin": "Application", - "value": "Policy.Read.ConditionalAccess" - }, - { - "description": "Allows the app to read role-based access control (RBAC) settings for all RBAC providers without a signed-in user. This includes reading role definitions and role assignments.", - "displayName": "Read role management data for all RBAC providers", - "id": "c7fbd983-d9aa-4fa7-84b8-17382c103bc4", - "origin": "Application", - "value": "RoleManagement.Read.All" - }, - { - "description": "Allows the app to read all PSTN and direct routing call log data without a signed-in user.", - "displayName": "Read PSTN and direct routing call log data", - "id": "a2611786-80b3-417e-adaa-707d4261a5f0", - "origin": "Application", - "value": "CallRecord-PstnCalls.Read.All" - }, - { - "description": "Allows the app to read all one-to-one and group chats messages in Microsoft Teams, without a signed-in user.", - "displayName": "Read all chat messages", - "id": "b9bb2381-47a4-46cd-aafb-00cb12f68504", - "origin": "Application", - "value": "ChatMessage.Read.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs for any chat, without a signed-in user.", - "displayName": "Allow the Teams app to manage all tabs for all chats", - "id": "fd9ce730-a250-40dc-bd44-8dc8d20f39ea", - "origin": "Application", - "value": "TeamsTab.ReadWriteForChat.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs in any team, without a signed-in user.", - "displayName": "Allow the Teams app to manage all tabs for all teams", - "id": "6163d4f4-fbf8-43da-a7b4-060fe85ed148", - "origin": "Application", - "value": "TeamsTab.ReadWriteForTeam.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs for any user, without a signed-in user.", - "displayName": "Allow the app to manage all tabs for all users", - "id": "425b4b59-d5af-45c8-832f-bb0b7402348a", - "origin": "Application", - "value": "TeamsTab.ReadWriteForUser.All" - }, - { - "description": "Allows the app to read the API connectors used in user authentication flows, without a signed-in user.", - "displayName": "Read API connectors for authentication flows", - "id": "b86848a7-d5b1-41eb-a9b4-54a4e6306e97", - "origin": "Application", - "value": "APIConnectors.Read.All" - }, - { - "description": "Allows the app to read, create and manage the API connectors used in user authentication flows, without a signed-in user.", - "displayName": "Read and write API connectors for authentication flows", - "id": "1dfe531a-24a6-4f1b-80f4-7a0dc5a0a171", - "origin": "Application", - "value": "APIConnectors.ReadWrite.All" - }, - { - "description": "Read the members of all chats, without a signed-in user.", - "displayName": "Read the members of all chats", - "id": "a3410be2-8e48-4f32-8454-c29a7465209d", - "origin": "Application", - "value": "ChatMember.Read.All" - }, - { - "description": "Add and remove members from all chats, without a signed-in user.", - "displayName": "Add and remove members from all chats", - "id": "57257249-34ce-4810-a8a2-a03adf0c5693", - "origin": "Application", - "value": "ChatMember.ReadWrite.All" - }, - { - "description": "Allows the app to create chats without a signed-in user.\u00a0", - "displayName": "Create chats", - "id": "d9c48af6-9ad9-47ad-82c3-63757137b9af", - "origin": "Application", - "value": "Chat.Create" - }, - { - "description": "Allows the application to read tenant-wide print settings without a signed-in user.", - "displayName": "Read tenant-wide print settings", - "id": "b5991872-94cf-4652-9765-29535087c6d8", - "origin": "Application", - "value": "PrintSettings.Read.All" - }, - { - "description": "Allows an app to read and write all browser site lists configured for your organization, without a signed-in user.", - "displayName": "Read and write all browser site lists for your organization", - "id": "8349ca94-3061-44d5-9bfb-33774ea5e4f9", - "origin": "Application", - "value": "BrowserSiteLists.ReadWrite.All" - }, - { - "description": "Allows the application to read and change the tenant-level settings of SharePoint and OneDrive, without a signed-in user.", - "displayName": "Read and change SharePoint and OneDrive tenant settings", - "id": "19b94e34-907c-4f43-bde9-38b1909ed408", - "origin": "Application", - "value": "SharePointTenantSettings.ReadWrite.All" - }, - { - "description": "Allows the app to read your organization's authentication event listeners without a signed-in user.", - "displayName": "Read all authentication event listeners", - "id": "b7f6385c-6ce6-4639-a480-e23c42ed9784", - "origin": "Application", - "value": "EventListener.Read.All" - }, - { - "description": "Allows the app to read or write your organization's authentication event listeners without a signed-in user.", - "displayName": "Read and write all authentication event listeners", - "id": "0edf5e9e-4ce8-468a-8432-d08631d18c43", - "origin": "Application", - "value": "EventListener.ReadWrite.All" - }, - { - "description": "Allows the app to read your organization's custom authentication extensions without a signed-in user.", - "displayName": "Read all custom authentication extensions", - "id": "88bb2658-5d9e-454f-aacd-a3933e079526", - "origin": "Application", - "value": "CustomAuthenticationExtension.Read.All" - }, - { - "description": "Allows the app to read all users\u2019 tasks and task lists in your organization, without a signed-in user.", - "displayName": "Read all users\u2019 tasks and tasklist", - "id": "f10e1f91-74ed-437f-a6fd-d6ae88e26c1f", - "origin": "Application", - "value": "Tasks.Read.All" - }, - { - "description": "Allows the app to create, update, list, read and delete all workflows, tasks and related lifecycle workflows resources without a signed-in user.", - "displayName": "Read and write all lifecycle workflows resources", - "id": "5c505cf4-8424-4b8e-aa14-ee06e3bb23e3", - "origin": "Application", - "value": "LifecycleWorkflows.ReadWrite.All" - }, - { - "description": "Allows an app to read all bookmarks without a signed-in user.", - "displayName": "Read all bookmarks", - "id": "be95e614-8ef3-49eb-8464-1c9503433b86", - "origin": "Application", - "value": "Bookmark.Read.All" - }, - { - "description": "Allows the application to obtain basic tenant information about another target tenant within the Azure AD ecosystem without a signed-in user.", - "displayName": "Read cross-tenant basic information", - "id": "cac88765-0581-4025-9725-5ebc13f729ee", - "origin": "Application", - "value": "CrossTenantInformation.ReadBasic.All" - }, - { - "description": "Allows the application to list and query any shared user profile information associated with the current tenant without a signed-in user.\u00a0 It also permits the application to export and remove external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant without a signed-in user.", - "displayName": "Read all shared cross-tenant user profiles and export or delete their data", - "id": "306785c5-c09b-4ba0-a4ee-023f3da165cb", - "origin": "Application", - "value": "CrossTenantUserProfileSharing.ReadWrite.All" - }, - { - "description": "Allows the app to read all learning content in the organization's directory, without a signed-in user.", - "displayName": "Read all learning content", - "id": "8740813e-d8aa-4204-860e-2a0f8f84dbc8", - "origin": "Application", - "value": "LearningContent.Read.All" - }, - { - "description": "Allows the app to read and update the authentication context information in your organization without a signed-in user.", - "displayName": "Read and write all authentication context information", - "id": "a88eef72-fed0-4bf7-a2a9-f19df33f8b83", - "origin": "Application", - "value": "AuthenticationContext.ReadWrite.All" - }, - { - "description": "Allows the app to read all admin report settings, such as whether to display concealed information in reports, without a signed-in user.", - "displayName": "Read all admin report settings", - "id": "ee353f83-55ef-4b78-82da-555bfa2b4b95", - "origin": "Application", - "value": "ReportSettings.Read.All" - }, - { - "description": "Allows the app to read the members of all chats where the associated Teams application is installed, without a signed-in user.", - "displayName": "Read the members of all chats where the associated Teams application is installed.", - "id": "93e7c9e4-54c5-4a41-b796-f2a5adaacda7", - "origin": "Application", - "value": "ChatMember.Read.WhereInstalled" - }, - { - "description": "Allows the app to add and remove members from all chats where the associated Teams application is installed, without a signed-in user.", - "displayName": "Add and remove members from all chats where the associated Teams application is installed.", - "id": "e32c2cd9-0124-4e44-88fc-772cd98afbdb", - "origin": "Application", - "value": "ChatMember.ReadWrite.WhereInstalled" - }, - { - "description": "Allows the app to read your organization's threat submissions and to view threat submission policies without a signed-in user.", - "displayName": "Read all of the organization's threat submissions", - "id": "86632667-cd15-4845-ad89-48a88e8412e1", - "origin": "Application", - "value": "ThreatSubmission.Read.All" - }, - { - "description": "Allows an app to sign digests for data without a signed-in user.", - "displayName": "Sign digests for data", - "id": "cbe6c7e4-09aa-4b8d-b3c3-2dbb59af4b54", - "origin": "Application", - "value": "InformationProtectionContent.Sign.All" - }, - { - "description": "Allows the app to read your organization's threat submission policies without a signed-in user. Also allows the app to create new threat submission polices without a signed-in user.", - "displayName": "Read and write all of the organization's threat submission policies", - "id": "926a6798-b100-4a20-a22f-a4918f13951d", - "origin": "Application", - "value": "ThreatSubmissionPolicy.ReadWrite.All" - }, - { - "description": "Allows the app to read all one-to-one or group chat messages in Microsoft Teams for chats where the associated Teams application is installed, without a signed-in user.", - "displayName": "Read all chat messages for chats where the associated Teams application is installed.", - "id": "1c1b4c8e-3cc7-4c58-8470-9b92c9d5848b", - "origin": "Application", - "value": "Chat.Read.WhereInstalled" - }, - { - "description": "Allows the app to read and write all chat messages in Microsoft Teams for chats where the associated Teams application is installed, without a signed-in user.", - "displayName": "Read and write all chat messages for chats where the associated Teams application is installed.", - "id": "ad73ce80-f3cd-40ce-b325-df12c33df713", - "origin": "Application", - "value": "Chat.ReadWrite.WhereInstalled" - }, - { - "description": "Allows the app to read and update all Azure AD recommendations, without a signed-in user. ", - "displayName": "Read and update all Azure AD recommendations", - "id": "0e9eea12-4f01-45f6-9b8d-3ea4c8144158", - "origin": "Application", - "value": "DirectoryRecommendations.ReadWrite.All" - }, - { - "description": "Allows the app to read all recordings of all online meetings, without a signed-in user.", - "displayName": "Read all recordings of online meetings.", - "id": "a4a08342-c95d-476b-b943-97e100569c8d", - "origin": "Application", - "value": "OnlineMeetingRecording.Read.All" - }, - { - "description": "Allows an app to manage license assignments for users and groups, without a signed-in user.", - "displayName": "Manage all license assignments", - "id": "5facf0c1-8979-4e95-abcf-ff3d079771c0", - "origin": "Application", - "value": "LicenseAssignment.ReadWrite.All" - }, - { - "description": "Allows the app to read and write the Teams app settings without a signed-in user.", - "displayName": "Read and write Teams app settings", - "id": "ab5b445e-8f10-45f4-9c79-dd3f8062cc4e", - "origin": "Application", - "value": "TeamworkAppSettings.ReadWrite.All" - }, - { - "description": "Allows the app to read and write the lifecycle information like employeeLeaveDateTime of users in your organization, without a signed-in user.", - "displayName": "Read and write all users' lifecycle information", - "id": "925f1248-0f97-47b9-8ec8-538c54e01325", - "origin": "Application", - "value": "User-LifeCycleInfo.ReadWrite.All" - }, - { - "description": "Allows the app to read all Azure AD recommendations, without a signed-in user. ", - "displayName": "Read all Azure AD recommendations", - "id": "ae73097b-cb2a-4447-b064-5d80f6093921", - "origin": "Application", - "value": "DirectoryRecommendations.Read.All" - }, - { - "description": "Allows the application to list and query any shared user profile information associated with the current tenant without a signed-in user.\u00a0 It also permits the application to export external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant without a signed-in user.", - "displayName": "Read all shared cross-tenant user profiles and export their data", - "id": "8b919d44-6192-4f3d-8a3b-f86f8069ae3c", - "origin": "Application", - "value": "CrossTenantUserProfileSharing.Read.All" - }, - { - "description": "Allows the app to manage restricted resources based on the other permissions granted to the app, without a signed-in user.", - "displayName": "Manage restricted resources in the directory", - "id": "f20584af-9290-4153-9280-ff8bb2c0ea7f", - "origin": "Application", - "value": "Directory.Write.Restricted" - }, - { - "description": "Allows the app to read all transcripts of all online meetings, without a signed-in user.", - "displayName": "Read all transcripts of online meetings.", - "id": "a4a80d8d-d283-4bd8-8504-555ec3870630", - "origin": "Application", - "value": "OnlineMeetingTranscript.Read.All" - }, - { - "description": "Allows\u00a0the\u00a0app\u00a0to\u00a0manage all learning\u00a0content\u00a0in\u00a0the\u00a0organization's\u00a0directory, without a signed-in user.", - "displayName": "Manage all\u00a0learning\u00a0content", - "id": "444d6fcb-b738-41e5-b103-ac4f2a2628a3", - "origin": "Application", - "value": "LearningContent.ReadWrite.All" - }, - { - "description": "Allows the application to read the tenant-level settings of SharePoint and OneDrive, without a signed-in user.", - "displayName": "Read SharePoint and OneDrive tenant settings", - "id": "83d4163d-a2d8-4d3b-9695-4ae3ca98f888", - "origin": "Application", - "value": "SharePointTenantSettings.Read.All" - }, - { - "description": "Allows the app to read or write your organization's custom authentication extensions without a signed-in user.", - "displayName": "Read and write all custom authentication extensions", - "id": "c2667967-7050-4e7e-b059-4cbbb3811d03", - "origin": "Application", - "value": "CustomAuthenticationExtension.ReadWrite.All" - }, - { - "description": "Allows the app to read names and members of all one-to-one and group chats in Microsoft Teams where the associated Teams application is installed, without a signed-in user.", - "displayName": "Read names and members of all chat threads where the associated Teams application is installed.", - "id": "818ba5bd-5b3e-4fe0-bbe6-aa4686669073", - "origin": "Application", - "value": "Chat.ReadBasic.WhereInstalled" - }, - { - "description": "Allows the app to list and read all workflows, tasks and related lifecycle workflows resources without a signed-in user.", - "displayName": "Read all lifecycle workflows resources", - "id": "7c67316a-232a-4b84-be22-cea2c0906404", - "origin": "Application", - "value": "LifecycleWorkflows.Read.All" - }, - { - "description": "Allows the app to create protected content without a signed-in user. ", - "displayName": "Create protected content", - "id": "287bd98c-e865-4e8c-bade-1a85523195b9", - "origin": "Application", - "value": "InformationProtectionContent.Write.All" - }, - { - "description": "Allows the app to create, read, update and delete all users\u2019 tasks and task lists in your organization, without a signed-in user", - "displayName": "Read and write all users\u2019 tasks and tasklists", - "id": "44e666d1-d276-445b-a5fc-8815eeb81d55", - "origin": "Application", - "value": "Tasks.ReadWrite.All" - }, - { - "description": "Allows the app to read the Teams app settings without a signed-in user.", - "displayName": "Read Teams app settings", - "id": "475ebe88-f071-4bd7-af2b-642952bd4986", - "origin": "Application", - "value": "TeamworkAppSettings.Read.All" - }, - { - "description": "Allows the app to read the authentication context information in your organization without a signed-in user.", - "displayName": "Read all authentication context information", - "id": "381f742f-e1f8-4309-b4ab-e3d91ae4c5c1", - "origin": "Application", - "value": "AuthenticationContext.Read.All" - }, - { - "description": "Allows the app to read and update all admin report settings, such as whether to display concealed information in reports, without a signed-in user.", - "displayName": "Read and write all admin report settings", - "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", - "origin": "Application", - "value": "ReportSettings.ReadWrite.All" - }, - { - "description": "Allows an app to read all browser site lists configured for your organization, without a signed-in user.", - "displayName": "Read all browser site lists for your organization", - "id": "c5ee1f21-fc7f-4937-9af0-c91648ff9597", - "origin": "Application", - "value": "BrowserSiteLists.Read.All" - }, - { - "description": "Allows the app to read the lifecycle information like employeeLeaveDateTime of users in your organization, without a signed-in user.", - "displayName": "Read all users' lifecycle information", - "id": "8556a004-db57-4d7a-8b82-97a13428e96f", - "origin": "Application", - "value": "User-LifeCycleInfo.Read.All" - }, - { - "description": "Allows an app to read all acronyms without a signed-in user.", - "displayName": "Read all acronyms", - "id": "8c0aed2c-0c61-433d-b63c-6370ddc73248", - "origin": "Application", - "value": "Acronym.Read.All" - }, - { - "description": "Allows the app to see your users' basic profile (e.g., name, picture, user name, email address)", - "displayName": "View users' basic profile", - "id": "14dad69e-099b-42c9-810b-d002981feec1", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to see your basic profile (e.g., name, picture, user name, email address)", - "userConsentDisplayName": "View your basic profile", - "value": "profile" - }, - { - "description": "Allows the app to read attack simulation and training data for an organization for the signed-in user.", - "displayName": "Read attack simulation data of an organization", - "id": "104a7a4b-ca76-4677-b7e7-2f4bc482f381", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read attack simulation and training data for an organization on your behalf.", - "userConsentDisplayName": "Read attack simulation data of an organization", - "value": "AttackSimulation.Read.All" - }, - { - "description": "Allows the app to read and write your organization's directory access review default policy on behalf of the signed-in user.", - "displayName": "Read and write your organization's directory access review default policy", - "id": "4f5bc9c8-ea54-4772-973a-9ca119cb0409", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's directory access review default policy on your behalf.", - "userConsentDisplayName": "Read and write your organization's directory access review default policy", - "value": "Policy.ReadWrite.AccessReview" - }, - { - "description": "Allows the app to read your organization's threat submissions and threat submission policies on behalf of the signed-in user. Also allows the app to create new threat submissions on behalf of the signed-in user.", - "displayName": "Read and write all threat submissions", - "id": "8458e264-4eb9-4922-abe9-768d58f13c7f", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization's threat submissions and threat submission policies on your behalf. Also allows the app to create new threat submissions on your behalf.", - "userConsentDisplayName": "Read and write all threat submissions", - "value": "ThreatSubmission.ReadWrite.All" - }, - { - "description": "Allows the application to read any data from Records Management, such as configuration, labels, and policies on behalf of the signed-in user.", - "displayName": "Read Records Management configuration,\u00a0labels, and policies", - "id": "07f995eb-fc67-4522-ad66-2b8ca8ea3efd", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read any data from Records Management, such as configuration, labels and policies on your behalf.", - "userConsentDisplayName": "Read Records Management configuration,\u00a0labels, and policies", - "value": "RecordsManagement.Read.All" - }, - { - "description": "Allow the application to create, update and delete any data from Records Management, such as configuration, labels, and policies on behalf of the signed-in user.", - "displayName": "Read and write Records Management configuration, labels, and policies", - "id": "f2833d75-a4e6-40ab-86d4-6dfe73c97605", - "Origin": "Delegated", - "userConsentDescription": "Allow the application to create, update and delete any data from Records Management, such as configuration, labels, and policies on your behalf.", - "userConsentDisplayName": "Read and write Records Management configuration, labels, and policies", - "value": "RecordsManagement.ReadWrite.All" - }, - { - "description": "Allows the app to read details of delegated admin relationships with customers like access details (that includes roles) and the duration as well as specific role assignments to security groups on behalf of the signed-in user.", - "displayName": "Read Delegated Admin relationships with customers", - "id": "0c0064ea-477b-4130-82a5-4c2cc4ff68aa", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read details of Delegated Admin relationships with customers like access details (that includes roles) and the duration as well as specific role assignments to security groups on your behalf.", - "userConsentDisplayName": "Read Delegated Admin relationships with customers", - "value": "DelegatedAdminRelationship.Read.All" - }, - { - "description": "Allows the app to manage (create-update-terminate) Delegated Admin relationships with customers as well as role assignments to security groups for active Delegated Admin relationships on behalf of the signed-in user.", - "displayName": "Manage Delegated Admin relationships with customers", - "id": "885f682f-a990-4bad-a642-36736a74b0c7", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage (create-update-terminate) Delegated Admin relationships with customers and role assignments to security groups for active Delegated Admin relationships on your behalf.", - "userConsentDisplayName": "Manage Delegated Admin relationships with customers", - "value": "DelegatedAdminRelationship.ReadWrite.All" - }, - { - "description": "Allows the app to read and write all managed tenant information on behalf of the signed-in user.", - "displayName": "Read and write all managed tenant information", - "id": "b31fa710-c9b3-4d9e-8f5e-8036eecddab9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write all managed tenant information on your behalf.", - "userConsentDisplayName": "Read and write all managed tenant information", - "value": "ManagedTenants.ReadWrite.All" - }, - { - "description": "Allows the app to read all managed tenant information on behalf of the signed-in user.", - "displayName": "Read all managed tenant information", - "id": "dc34164e-6c4a-41a0-be89-3ae2fbad7cd3", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all managed tenant information on your behalf.", - "userConsentDisplayName": "Read all managed tenant information", - "value": "ManagedTenants.Read.All" - }, - { - "description": "Allows the app to read and manage the Cloud PC role-based access control (RBAC) settings, on behalf of the signed-in user. This includes reading and managing Cloud PC role definitions and role assignments.", - "displayName": "Read and write Cloud PC RBAC settings", - "id": "501d06f8-07b8-4f18-b5c6-c191a4af7a82", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and manage the Cloud PC role-based access control (RBAC) settings, on your behalf. This includes reading and managing Cloud PC role definitions and memberships.", - "userConsentDisplayName": "Read and write Cloud PC RBAC settings", - "value": "RoleManagement.ReadWrite.CloudPC" - }, - { - "description": "Allows the app to read the Cloud PC role-based access control (RBAC) settings, on behalf of the signed-in user.\u00a0 This includes reading Cloud PC role definitions and role assignments.", - "displayName": "Read Cloud PC RBAC settings", - "id": "9619b88a-8a25-48a7-9571-d23be0337a79", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the Cloud PC role-based access control (RBAC) settings, on your behalf.\u00a0 This includes reading Cloud PC role definitions and role assignments.", - "userConsentDisplayName": "Read Cloud PC RBAC settings", - "value": "RoleManagement.Read.CloudPC" - }, - { - "description": "Allows the app to read and write settings of external connections on behalf of a signed-in user. The signed-in user must be an administrator. The app can only read and write settings of connections that it is authorized to.", - "displayName": "Read and write external connections", - "id": "4082ad95-c812-4f02-be92-780c4c4f1830", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write external connections on your behalf. The signed-in user must be an administrator. The app can only read and write external connections that it is authorized to, or it can create new external connections. ", - "userConsentDisplayName": "Read and write external connections", - "value": "ExternalConnection.ReadWrite.OwnedBy" - }, - { - "description": "Allows the app to read all external connections on behalf of a signed-in user. The signed-in user must be an administrator.", - "displayName": "Read all external connections", - "id": "a38267a5-26b6-4d76-9493-935b7599116b", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all external connections on your behalf. The signed-in user must be an administrator.", - "userConsentDisplayName": "Read all external connections", - "value": "ExternalConnection.Read.All" - }, - { - "description": "Allows the app to read and write all external connections on behalf of a signed-in user. The signed-in user must be an administrator.", - "displayName": "Read and write all external connections", - "id": "bbbbd9b3-3566-4931-ac37-2b2180d9e334", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write all external connections on your behalf. The signed-in user must be an administrator.", - "userConsentDisplayName": "Read and write all external connections", - "value": "ExternalConnection.ReadWrite.All" - }, - { - "description": "Allows the app to read and write external items on behalf of a signed-in user. The signed-in user must be an administrator. The app can only read external items of the connection that it is authorized to.", - "displayName": "Read and write external items", - "id": "4367b9d7-cee7-4995-853c-a0bdfe95c1f9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write external items on your behalf. The signed-in user must be an administrator. The app can only read external items of the connection that it is authorized to.", - "userConsentDisplayName": "Read and write external items", - "value": "ExternalItem.ReadWrite.OwnedBy" - }, - { - "description": "Allows the app to read and write all external items on behalf of a signed-in user. The signed-in user must be an administrator.", - "displayName": "Read and write all external items", - "id": "b02c54f8-eb48-4c50-a9f0-a149e5a2012f", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write all external items on your behalf. The signed-in user must be an administrator.", - "userConsentDisplayName": "Read and write all external items", - "value": "ExternalItem.ReadWrite.All" - }, - { - "description": "Allows the app to read custom security attribute assignments for all principals in the tenant on behalf of a signed in user.", - "displayName": "Read custom security attribute assignments", - "id": "b46ffa80-fe3d-4822-9a1a-c200932d54d0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read custom security attribute assignments for all principals in the tenant on your behalf.", - "userConsentDisplayName": "Read custom security attribute assignments", - "value": "CustomSecAttributeAssignment.Read.All" - }, - { - "description": "Allows the app to read custom security attribute definitions for the tenant on behalf of a signed in user.", - "displayName": "Read custom security attribute definitions", - "id": "ce026878-a0ff-4745-a728-d4fedd086c07", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read custom security attribute definitions for the tenant on your behalf.", - "userConsentDisplayName": "Read custom security attribute definitions", - "value": "CustomSecAttributeDefinition.Read.All" - }, - { - "description": "Allows the app to read and write your organization's cross tenant access policies on behalf of the signed-in user.", - "displayName": "Read and write your organization's cross tenant access policies", - "id": "014b43d0-6ed4-4fc6-84dc-4b6f7bae7d85", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's cross tenant access policies on your behalf.", - "userConsentDisplayName": "Read and write your organization's cross tenant access policies", - "value": "Policy.ReadWrite.CrossTenantAccess" - }, - { - "description": "Allows the app to read and write tags in Teams, on behalf of the signed-in user.", - "displayName": "Read and write tags in Teams", - "id": "539dabd7-b5b6-4117-b164-d60cd15a8671", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write tags in Teams, on your behalf.", - "userConsentDisplayName": "Read and write tags in Teams", - "value": "TeamworkTag.ReadWrite" - }, - { - "description": "Allows the app to read tags in Teams, on behalf of the signed-in user.", - "displayName": "Read tags in Teams", - "id": "57587d0b-8399-45be-b207-8050cec54575", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read tags in Teams, on your behalf.", - "userConsentDisplayName": "Read tags in Teams", - "value": "TeamworkTag.Read" - }, - { - "description": "Allows the app to read and write security incidents, on behalf of the signed-in user.", - "displayName": "Read and write to incidents", - "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write to all security incidents that you have access to.", - "userConsentDisplayName": "Read and write to security incidents", - "value": "SecurityIncident.ReadWrite.All" - }, - { - "description": "Allows the app to read security incidents, on behalf of the signed-in user.", - "displayName": "Read incidents", - "id": "b9abcc4f-94fc-4457-9141-d20ce80ec952", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all security incidents that you have access to.", - "userConsentDisplayName": "Read security incidents", - "value": "SecurityIncident.Read.All" - }, - { - "description": "Allows the app to read and write to all security alerts, on behalf of the signed-in user.", - "displayName": "Read and write to all security alerts", - "id": "471f2a7f-2a42-4d45-a2bf-594d0838070d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write all alerts that you have access to.", - "userConsentDisplayName": "Read and write all alerts", - "value": "SecurityAlert.ReadWrite.All" - }, - { - "description": "Allows the app to read all security alerts, on behalf of the signed-in user.", - "displayName": "Read all security alerts", - "id": "bc257fb8-46b4-4b15-8713-01e91bfbe4ea", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all security alerts that you have access to.", - "userConsentDisplayName": "Read all alerts", - "value": "SecurityAlert.Read.All" - }, - { - "description": "Allows the app to update service announcement messages' user status on behalf of the signed-in user. The message status can be marked as read, archive, or favorite.", - "displayName": "Update user status on service announcement messages", - "id": "636e1b0b-1cc2-4b1c-9aa9-4eeed9b9761b", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to update service announcement messages' status on your behalf. Your status for messages can be marked as read, archive, or favorite.", - "userConsentDisplayName": "Update your user status on service announcement messages", - "value": "ServiceMessageViewpoint.Write" - }, - { - "description": "Allows the app to run hunting queries, on behalf of the signed-in user.", - "displayName": "Run hunting queries", - "id": "b152eca8-ea73-4a48-8c98-1a6742673d99", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to run hunting queries that you can execute.", - "userConsentDisplayName": "Run hunting queries", - "value": "ThreatHunting.Read.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall itself to teams the signed-in user can access.", - "displayName": "Allow the app to manage itself in teams", - "id": "0f4595f7-64b1-4e13-81bc-11a249df07a9", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall itself to teams you can access.", - "userConsentDisplayName": "Allow the Teams app to manage itself in teams", - "value": "TeamsAppInstallation.ReadWriteSelfForTeam" - }, - { - "description": "Allow the app to read the management data for Teams devices on behalf of the signed-in user.", - "displayName": "Read Teams devices", - "id": "b659488b-9d28-4208-b2be-1c6652b3c970", - "Origin": "Delegated", - "userConsentDescription": "Allow the app to read the management data for Teams devices on your behalf.", - "userConsentDisplayName": "Read Teams devices", - "value": "TeamworkDevice.Read.All" - }, - { - "description": "Allow the app to read and write the management data for Teams devices on behalf of the signed-in user.", - "displayName": "Read and write Teams devices", - "id": "ddd97ecb-5c31-43db-a235-0ee20e635c40", - "Origin": "Delegated", - "userConsentDescription": "Allow the app to read and write the management data for Teams devices on your behalf.", - "userConsentDisplayName": "Read and write Teams devices", - "value": "TeamworkDevice.ReadWrite.All" - }, - { - "description": "Allows the app to read all identity risky service principal information for your organization, on behalf of the signed-in user.", - "displayName": "Read all identity risky service principal information", - "id": "ea5c4ab0-5a73-4f35-8272-5d5337884e5d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all identity risky service principal information for your organization, on your behalf.", - "userConsentDisplayName": "Read all identity risky service principal information", - "value": "IdentityRiskyServicePrincipal.Read.All" - }, - { - "description": "Allows the app to read and update identity risky service principal information for all service principals in your organization, on behalf of the signed-in user. Update operations include dismissing risky service principals.", - "displayName": "Read and write all identity risky service principal information", - "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and update identity risky service principal information for all service principals in your organization, on your behalf. Update operations include dismissing risky service principals.", - "userConsentDisplayName": "Read and write all identity risky service principal information", - "value": "IdentityRiskyServicePrincipal.ReadWrite.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs to teams the signed-in user can access.", - "displayName": "Allow the Teams app to manage only its own tabs in teams", - "id": "f266662f-120a-4314-b26a-99b08617c7ef", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs to teams you can access.", - "userConsentDisplayName": "Allow the Teams app to manage only its own tabs in teams", - "value": "TeamsTab.ReadWriteSelfForTeam" - }, - { - "description": "Allows the app to read the presence information and write activity and availability on behalf of the signed-in user. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", - "displayName": "Read and write a user's presence information", - "id": "8d3c54a7-cf58-4773-bf81-c0cd6ad522bb", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the presence information and write activity and availability on your behalf. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", - "userConsentDisplayName": "Read and write your presence information", - "value": "Presence.ReadWrite" - }, - { - "description": "Allows the app to read subject rights requests on behalf of the signed-in user", - "displayName": "Read subject rights requests", - "id": "9c3af74c-fd0f-4db4-b17a-71939e2a9d77", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read subject rights requests on your behalf.", - "userConsentDisplayName": "Read data subject requests", - "value": "SubjectRightsRequest.Read.All" - }, - { - "description": "Allows the app to read and write subject rights requests on behalf of the signed-in user", - "displayName": "Read and write subject rights requests", - "id": "2b8fcc74-bce1-4ae3-a0e8-60c53739299d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write subject rights requests on your behalf.", - "userConsentDisplayName": "Read and write data subject requests", - "value": "SubjectRightsRequest.ReadWrite.All" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs for the signed-in user.", - "displayName": "Allow the Teams app to manage only its own tabs for a user", - "id": "395dfec1-a0b9-465f-a783-8250a430cb8c", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs for you.", - "userConsentDisplayName": "Allow the Teams app to manage only its own tabs for you", - "value": "TeamsTab.ReadWriteSelfForUser" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs in chats the signed-in user can access.", - "displayName": "Allow the Teams app to manage only its own tabs in chats", - "id": "0c219d04-3abf-47f7-912d-5cca239e90e6", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs in chats you can access.", - "userConsentDisplayName": "Allow the Teams app to manage only its own tabs in chats", - "value": "TeamsTab.ReadWriteSelfForChat" - }, - { - "description": "Allows the app to read and write search configuration, on behalf of the signed-in user.", - "displayName": "Read and write your organization's search configuration", - "id": "b1a7d408-cab0-47d2-a2a5-a74a3733600d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write search configuration, on your behalf.", - "userConsentDisplayName": "Read and write your organization's search configuration", - "value": "SearchConfiguration.ReadWrite.All" - }, - { - "description": "Allows the app to read search configuration, on behalf of the signed-in user.", - "displayName": "Read your organization's search configuration", - "id": "7d307522-aa38-4cd0-bd60-90c6f0ac50bd", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read search configuration, on your behalf.", - "userConsentDisplayName": "Read your organization's search configuration", - "value": "SearchConfiguration.Read.All" - }, - { - "description": "Allows the app to read online meeting artifacts on behalf of the signed-in user.", - "displayName": "Read user's online meeting artifacts", - "id": "110e5abb-a10c-4b59-8b55-9b4daa4ef743", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read online meeting artifacts on your behalf.", - "userConsentDisplayName": "Read user's online meeting artifacts", - "value": "OnlineMeetingArtifact.Read.All" - }, - { - "description": "Allows the app to read and manage the active role-based access control (RBAC) assignments for your company's directory, on behalf of the signed-in user. This includes managing active directory role membership, and reading directory role templates, directory roles and active memberships.", - "displayName": "Read, update, and delete all active role assignments for your company's directory", - "id": "8c026be3-8e26-4774-9372-8d5d6f21daff", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and manage the active role-based access control (RBAC) assignments for your company's directory, on your behalf. This includes managing active directory role membership, and reading directory role templates, directory roles and active memberships.", - "userConsentDisplayName": "Read, update, and delete all active role assignments for your company's directory", - "value": "RoleAssignmentSchedule.ReadWrite.Directory" - }, - { - "description": "Allows the app to read and manage the eligible role-based access control (RBAC) assignments for your company's directory, on behalf of the signed-in user. This includes managing eligible directory role membership, and reading directory role templates, directory roles and eligible memberships.", - "displayName": "Read, update, and delete all eligible role assignments for your company's directory", - "id": "62ade113-f8e0-4bf9-a6ba-5acb31db32fd", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and manage the eligible role-based access control (RBAC) assignments for your company's directory, on your behalf. This includes managing eligible directory role membership, and reading directory role templates, directory roles and eligible memberships.", - "userConsentDisplayName": "Read, update, and delete all eligible role assignments for your company's directory", - "value": "RoleEligibilitySchedule.ReadWrite.Directory" - }, - { - "description": "Allows the app to read, update, and delete policies for privileged role-based access control (RBAC) assignments of your company's directory, on behalf of the signed-in user.", - "displayName": "Read, update, and delete all policies for privileged role assignments of your company's directory", - "id": "1ff1be21-34eb-448c-9ac9-ce1f506b2a68", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, and delete policies for privileged role-based access control (RBAC) assignments of your company's directory, on your behalf.", - "userConsentDisplayName": "Read, update, and delete all policies for privileged role assignments of your company's directory", - "value": "RoleManagementPolicy.ReadWrite.Directory" - }, - { - "description": "Allows the app to read the active role-based access control (RBAC) assignments for your company's directory, on behalf of the signed-in user. This includes reading directory role templates, and directory roles.", - "displayName": "Read all active role assignments for your company's directory", - "id": "344a729c-0285-42c6-9014-f12b9b8d6129", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the active role-based access control (RBAC) assignments for your company's directory, on your behalf. This includes reading directory role templates, and directory roles.", - "userConsentDisplayName": "Read all active role assignments for your company's directory", - "value": "RoleAssignmentSchedule.Read.Directory" - }, - { - "description": "Allows the app to read the eligible role-based access control (RBAC) assignments for your company's directory, on behalf of the signed-in user. This includes reading directory role templates, and directory roles.", - "displayName": "Read all eligible role assignments for your company's directory", - "id": "eb0788c2-6d4e-4658-8c9e-c0fb8053f03d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the eligible role-based access control (RBAC) assignments for your company's directory, on your behalf. This includes reading directory role templates, and directory roles.", - "userConsentDisplayName": "Read all eligible role assignments for your company's directory", - "value": "RoleEligibilitySchedule.Read.Directory" - }, - { - "description": "Allows the app to read policies for privileged role-based access control (RBAC) assignments of your company's directory, on behalf of the signed-in user.", - "displayName": "Read all policies for privileged role assignments of your company's directory", - "id": "3de2cdbe-0ff5-47d5-bdee-7f45b4749ead", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read policies for privileged role-based access control (RBAC) assignments of your company's directory, on your behalf.", - "userConsentDisplayName": "Read all policies for privileged role assignments of your company's directory", - "value": "RoleManagementPolicy.Read.Directory" - }, - { - "description": "Allows the app to read and write all Windows update deployment settings for the organization on behalf of the signed-in user.", - "displayName": "Read and write all Windows update deployment settings", - "id": "11776c0c-6138-4db3-a668-ee621bea2555", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write all Windows update deployment settings for the organization on your behalf.", - "userConsentDisplayName": "Read and write all Windows update deployment settings", - "value": "WindowsUpdates.ReadWrite.All" - }, - { - "description": "Allows the app to read and write your organization's mobility management policies on behalf of the signed-in user. For example, a mobility management policy can set the enrollment scope for a given mobility management application.", - "displayName": "Read and write your organization's mobility management policies", - "id": "a8ead177-1889-4546-9387-f25e658e2a79", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's mobility management policies on your behalf. For example, a mobility management policy can set the enrollment scope for a given mobility management application.", - "userConsentDisplayName": "Read and write your organization's mobility management policies", - "value": "Policy.ReadWrite.MobilityManagement" - }, - { - "description": "Allows the app to read basic unified group properties, memberships and owners of the group the signed-in guest is a member of.", - "displayName": "Read unified group memberships as guest", - "id": "73e75199-7c3e-41bb-9357-167164dbb415", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read basic unified group properties, memberships and owners of the group you are a member of.", - "userConsentDisplayName": "Read unified group memberships as guest", - "value": "UnifiedGroupMember.Read.AsGuest" - }, - { - "description": "Allows the app to update service principal endpoints", - "displayName": "Read and update service principal endpoints", - "id": "7297d82c-9546-4aed-91df-3d4f0a9b3ff0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to update service principal endpoints", - "userConsentDisplayName": "Read and update service principal endpoints", - "value": "ServicePrincipalEndpoint.ReadWrite.All" - }, - { - "description": "Allows the app to read service principal endpoints", - "displayName": "Read service principal endpoints", - "id": "9f9ce928-e038-4e3b-8faf-7b59049a8ddc", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read service principal endpoints", - "userConsentDisplayName": "Read service principal endpoints", - "value": "ServicePrincipalEndpoint.Read.All" - }, - { - "description": "Allows the app to create new notifications in users' teamwork activity feeds on behalf of the signed in user. These notifications may not be discoverable or be held or governed by compliance policies.", - "displayName": "Send a teamwork activity as the user", - "id": "7ab1d787-bae7-4d5d-8db6-37ea32df9186", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create new activities in your teamwork activity feed, and send new activities to other users' activity feed, on your behalf.", - "userConsentDisplayName": "Send a teamwork activity", - "value": "TeamsActivity.Send" - }, - { - "description": "Allows the app to read and write eDiscovery objects such as cases, custodians, review sets and other related objects on behalf of the signed-in user.", - "displayName": "Read and write all eDiscovery objects", - "id": "acb8f680-0834-4146-b69e-4ab1b39745ad", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write eDiscovery objects such as cases, custodians, review sets and other related objects on your behalf.", - "userConsentDisplayName": "Read and write all eDiscovery objects", - "value": "eDiscovery.ReadWrite.All" - }, - { - "description": "Allows the app to read eDiscovery objects such as cases, custodians, review sets and other related objects on behalf of the signed-in user.", - "displayName": "Read all eDiscovery objects", - "id": "99201db3-7652-4d5a-809a-bdb94f85fe3c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read eDiscovery objects such as cases, custodians, review sets and other related objects on your behalf.", - "userConsentDisplayName": "Read all eDiscovery objects", - "value": "eDiscovery.Read.All" - }, - { - "description": "Allows the app to read and write custom security attribute assignments for all principals in the tenant on behalf of a signed in user.", - "displayName": "Read and write custom security attribute assignments", - "id": "ca46335e-8453-47cd-a001-8459884efeae", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write custom security attribute assignments for all principals in the tenant on your behalf.", - "userConsentDisplayName": "Read and write custom security attribute assignments", - "value": "CustomSecAttributeAssignment.ReadWrite.All" - }, - { - "description": "Allows the app to read and write custom security attribute definitions for the tenant on behalf of a signed in user.", - "displayName": "Read and write custom security attribute definitions", - "id": "8b0160d4-5743-482b-bb27-efc0a485ca4a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write custom security attribute definitions for the tenant on your behalf.", - "userConsentDisplayName": "Read and write custom security attribute definitions", - "value": "CustomSecAttributeDefinition.ReadWrite.All" - }, - { - "description": "Allows the app to read email in the signed-in user's mailbox except body, previewBody, attachments and any extended properties.", - "displayName": "Read user basic mail", - "id": "a4b8392a-d8d1-4954-a029-8e668a39a170", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read email in the signed-in user's mailbox except body, previewBody, attachments and any extended properties.", - "userConsentDisplayName": "Read user basic mail", - "value": "Mail.ReadBasic" - }, - { - "description": "Allows the app to read and write your organization's feature rollout policies on behalf of the signed-in user. Includes abilities to assign and remove users and groups to rollout of a specific feature.", - "displayName": "Read and write your organization's feature rollout policies", - "id": "92a38652-f13b-4875-bc77-6e1dbb63e1b2", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's feature rollout policies on your behalf. Includes abilities to assign and remove users and groups to rollout of a specific feature.", - "userConsentDisplayName": "Read and write your organization's feature rollout policies", - "value": "Policy.ReadWrite.FeatureRollout" - }, - { - "description": "Allows the app to read and manage the role-based access control (RBAC) settings for your company's directory, on behalf of the signed-in user. This includes instantiating directory roles and managing directory role membership, and reading directory role templates, directory roles and memberships.", - "displayName": "Read and write directory RBAC settings", - "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and manage the role-based access control (RBAC) settings for your company's directory, on your behalf. This includes instantiating directory roles and managing directory role membership, and reading directory role templates, directory roles and memberships.", - "userConsentDisplayName": "Read and write directory RBAC settings", - "value": "RoleManagement.ReadWrite.Directory" - }, - { - "description": "Allows the app to read the role-based access control (RBAC) settings for your company's directory, on behalf of the signed-in user. This includes reading directory role templates, directory roles and memberships.", - "displayName": "Read directory RBAC settings", - "id": "741c54c3-0c1e-44a1-818b-3f97ab4e8c83", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the role-based access control (RBAC) settings for your company's directory, on your behalf. This includes reading directory role templates, directory roles and memberships.", - "userConsentDisplayName": "Read directory RBAC settings", - "value": "RoleManagement.Read.Directory" - }, - { - "description": "Allows the app to read and write the organization and related resources, on behalf of the signed-in user.\u00a0Related resources include things like subscribed skus and tenant branding information.", - "displayName": "Read and write organization information", - "id": "46ca0847-7e6b-426e-9775-ea810a948356", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the organization and related resources, on your behalf.\u00a0Related resources include things like subscribed skus and tenant branding information.", - "userConsentDisplayName": "Read and write organization information", - "value": "Organization.ReadWrite.All" - }, - { - "description": "Allows the app to read the organization and related resources, on behalf of the signed-in user.\u00a0Related resources include things like subscribed skus and tenant branding information.", - "displayName": "Read organization information", - "id": "4908d5b9-3fb2-4b1e-9336-1888b7937185", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the organization and related resources, on your behalf.\u00a0Related resources include things like subscribed skus and tenant branding information.", - "userConsentDisplayName": "Read organization information", - "value": "Organization.Read.All" - }, - { - "description": "Allows the app to read your company's places (conference rooms and room lists) for calendar events and other applications, on behalf of the signed-in user.", - "displayName": "Read all company places", - "id": "cb8f45a0-5c2e-4ea1-b803-84b870a7d7ec", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your company's places (conference rooms and room lists) for calendar events and other applications, on your behalf.", - "userConsentDisplayName": "Read all company places", - "value": "Place.Read.All" - }, - { - "description": "Allows the app to manage workforce integrations, to synchronize data from Microsoft Teams Shifts, on behalf of the signed-in user.", - "displayName": "Read and write workforce integrations", - "id": "08c4b377-0d23-4a8b-be2a-23c1c1d88545", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage workforce integrations, to synchronize data from Microsoft Teams Shifts, on your behalf.", - "userConsentDisplayName": "Read and write workforce integrations", - "value": "WorkforceIntegration.ReadWrite.All" - }, - { - "description": "Allows the app to read workforce integrations, to synchronize data from Microsoft Teams Shifts, on behalf of the signed-in user.", - "displayName": "Read workforce integrations", - "id": "f1ccd5a7-6383-466a-8db8-1a656f7d06fa", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read workforce integrations, to synchronize data from Microsoft Teams Shifts, on your behalf.", - "userConsentDisplayName": "Read workforce integrations", - "value": "WorkforceIntegration.Read.All" - }, - { - "description": "Allows the app to read, update, delete and perform actions on access reviews, reviewers, decisions and settings for group and app memberships that the signed-in user has access to in the organization.", - "displayName": "Manage access reviews for group and app memberships", - "id": "5af8c3f5-baca-439a-97b0-ea58a435e269", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update and perform action on access reviews, reviewers, decisions and settings that you have access to.", - "userConsentDisplayName": "Manage access reviews for group and app memberships", - "value": "AccessReview.ReadWrite.Membership" - }, - { - "description": "Allows the app to manage hybrid identity service configuration by creating, viewing, updating and deleting on-premises published resources, on-premises agents and agent groups, on behalf of the signed-in user.", - "displayName": "Manage on-premises published resources", - "id": "8c4d5184-71c2-4bf8-bb9d-bc3378c9ad42", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage hybrid identity service configuration by creating, viewing, updating and deleting on-premises published resources, on-premises agents and agent groups, on your behalf.", - "userConsentDisplayName": "Manage on-premises published resources", - "value": "OnPremisesPublishingProfiles.ReadWrite.All" - }, - { - "description": "Allows an app to read information protection sensitivity labels and label policy settings, on behalf of the signed-in user.", - "displayName": "Read user sensitivity labels and label policies.", - "id": "4ad84827-5578-4e18-ad7a-86530b12f884", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read information protection sensitivity labels and label policy settings, on behalf of the signed-in user.", - "userConsentDisplayName": "Read user sensitivity labels and label policies.", - "value": "InformationProtectionPolicy.Read" - }, - { - "description": "Allows the app to read administrative units and administrative unit membership on behalf of the signed-in user.", - "displayName": "Read administrative units", - "id": "3361d15d-be43-4de6-b441-3c746d05163d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read administrative units and administrative unit membership on your behalf.", - "userConsentDisplayName": "Read administrative units", - "value": "AdministrativeUnit.Read.All" - }, - { - "description": "Allows the app to create, read, update, and delete administrative units and manage administrative unit membership on behalf of the signed-in user.", - "displayName": "Read and write administrative units", - "id": "7b8a2d34-6b3f-4542-a343-54651608ad81", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create, read, update, and delete administrative units and manage administrative unit membership on your behalf.", - "userConsentDisplayName": "Read and write administrative units", - "value": "AdministrativeUnit.ReadWrite.All" - }, - { - "description": "Allows the app to read your family information, members and their basic profile.", - "displayName": "Read your family info", - "id": "3a1e4806-a744-4c70-80fc-223bf8582c46", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your family information, members and their basic profile.", - "userConsentDisplayName": "Read your family info", - "value": "Family.Read" - }, - { - "description": "Allows the app to create threat indicators, and fully manage those threat indicators (read, update and delete), on behalf of the signed-in user. \u00a0It cannot update any threat indicators it does not own.", - "displayName": "Manage threat indicators this app creates or owns", - "id": "91e7d36d-022a-490f-a748-f8e011357b42", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create threat indicators, and fully manage those threat indicators (read, update and delete), on your behalf. \u00a0It cannot update any threat indicators that it is not an owner of.", - "userConsentDisplayName": "Manage threat indicators this app creates or owns", - "value": "ThreatIndicators.ReadWrite.OwnedBy" - }, - { - "description": "Allows the app to read or update security actions, on behalf of the signed-in user.", - "displayName": "Read and update your organization's security actions", - "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and update security actions, on your behalf.", - "userConsentDisplayName": "Read and update your organization's security actions", - "value": "SecurityActions.ReadWrite.All" - }, - { - "description": "Allows the app to read security actions, on behalf of the signed-in user.", - "displayName": "Read your organization's security actions", - "id": "1638cddf-07a4-4de2-8645-69c96cacad73", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read security actions, on your behalf.", - "userConsentDisplayName": "Read your organization's security actions", - "value": "SecurityActions.Read.All" - }, - { - "description": "Allows an app to read 1 on 1 or group chats threads, on behalf of the signed-in user.", - "displayName": "Read user chat messages", - "id": "f501c180-9344-439a-bca0-6cbf209fd270", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read your 1 on 1 or group chat messages in Microsoft Teams, on your behalf.", - "userConsentDisplayName": "Read your chat messages", - "value": "Chat.Read" - }, - { - "description": "Allows an app to read and write 1 on 1 or group chats threads, on behalf of the signed-in user.", - "displayName": "Read and write user chat messages", - "id": "9ff7295e-131b-4d94-90e1-69fde507ac11", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read and write your 1 on 1 or group chat messages in Microsoft Teams, on your behalf.", - "userConsentDisplayName": "Read and write your chat messages", - "value": "Chat.ReadWrite" - }, - { - "description": "Allows the app to read and write your organization's trust framework policies on behalf of the signed-in user.", - "displayName": "Read and write your organization's trust framework policies", - "id": "cefba324-1a70-4a6e-9c1d-fd670b7ae392", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's trust framework policies on your behalf.", - "userConsentDisplayName": "Read and write trust framework policies", - "value": "Policy.ReadWrite.TrustFramework" - }, - { - "description": "Allows the app to read trust framework key set properties on behalf of the signed-in user.", - "displayName": "Read trust framework key sets", - "id": "7ad34336-f5b1-44ce-8682-31d7dfcd9ab9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read trust framework key sets, on your behalf.", - "userConsentDisplayName": "Read trust framework key sets", - "value": "TrustFrameworkKeySet.Read.All" - }, - { - "description": "Allows the app to read and write trust framework key set properties on behalf of the signed-in user.", - "displayName": "Read and write trust framework key sets", - "id": "39244520-1e7d-4b4a-aee0-57c65826e427", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read or write trust framework key sets, on your behalf.", - "userConsentDisplayName": "Read and write trust framework key sets", - "value": "TrustFrameworkKeySet.ReadWrite.All" - }, - { - "description": "Allows the app to read and update identity risk event information for all users in your organization on behalf of the signed-in user.\u00a0Update operations include confirming risk event detections.\u00a0", - "displayName": "Read and write risk event information", - "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and update identity risk event information for all users in your organization on your behalf.\u00a0Update operations include confirming risk event detections.\u00a0", - "userConsentDisplayName": "Read and write risk event information", - "value": "IdentityRiskEvent.ReadWrite.All" - }, - { - "description": "Allows the app to read and update identity risky user information for all users in your organization on behalf of the signed-in user.\u00a0Update operations include dismissing risky users.", - "displayName": "Read and write risky user information", - "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and update identity risky user information for all users in your organization on your behalf.\u00a0Update operations include dismissing risky users.", - "userConsentDisplayName": "Read and write identity risky user information", - "value": "IdentityRiskyUser.ReadWrite.All" - }, - { - "description": "Allows the app to read the signed-in user's mailbox.", - "displayName": "Read user mail ", - "id": "570282fd-fa5c-430d-a7fd-fc8dc98a9dca", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read email in your mailbox. ", - "userConsentDisplayName": "Read your mail ", - "value": "Mail.Read" - }, - { - "description": "Allows the app to read identity risky user information for all users in your organization on behalf of the signed-in user.", - "displayName": "Read identity risky user information", - "id": "d04bb851-cb7c-4146-97c7-ca3e71baf56c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read identity risky user information for all users in your organization on behalf of the signed-in user.", - "userConsentDisplayName": "Read identity risky user information", - "value": "IdentityRiskyUser.Read.All" - }, - { - "description": "Allows the app to read the signed-in user's activity statistics, such as how much time the user has spent on emails, in meetings, or in chat sessions.", - "displayName": "Read user activity statistics", - "id": "e03cf23f-8056-446a-8994-7d93dfc8b50e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your activity statistics, such as how much time you've spent on emails, in meetings, or in chat sessions.", - "userConsentDisplayName": "Read your activity statistics", - "value": "Analytics.Read" - }, - { - "description": "Allows the app to see and update the data you gave it access to, even when users are not currently using the app. This does not give the app any additional permissions.", - "displayName": "Maintain access to data you have given it access to", - "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to see and update the data you gave it access to, even when you are not currently using the app. This does not give the app any additional permissions.", - "userConsentDisplayName": "Maintain access to data you have given it access to", - "value": "offline_access" - }, - { - "description": "Allows the app to have the same access to mailboxes as the signed-in user via Exchange Web Services.", - "displayName": "Access mailboxes as the signed-in user via Exchange Web Services", - "id": "9769c687-087d-48ac-9cb3-c37dde652038", - "Origin": "Delegated", - "userConsentDescription": "Allows the app full access to your mailboxes on your behalf.", - "userConsentDisplayName": "Access your mailboxes", - "value": "EWS.AccessAsUser.All" - }, - { - "description": "Allows the app to export data (e.g. customer content or system-generated logs), associated with any user in your company, when the app is used by a privileged user (e.g. a Company Administrator).", - "displayName": "Export user's data", - "id": "405a51b5-8d8d-430b-9842-8be4b0e9f324", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to export data (e.g. customer content or system-generated logs), associated with any user in your company, when the app is used by a privileged user (e.g. a Company Administrator).", - "userConsentDisplayName": "Export user's data", - "value": "User.Export.All" - }, - { - "description": "Allows the app to deliver its notifications on behalf of signed-in users. Also allows the app to read, update, and delete the user's notification items for this app.", - "displayName": "Deliver and manage user notifications for this app", - "id": "89497502-6e42-46a2-8cb2-427fd3df970a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to deliver its notifications, on your behalf. Also allows the app to read, update, and delete your notification items for this app.", - "userConsentDisplayName": "Deliver and manage your notifications for this app", - "value": "Notifications.ReadWrite.CreatedByApp" - }, - { - "description": "Allows the app to read and write your organization's conditional access policies on behalf of the signed-in user.", - "displayName": "Read and write your organization's conditional access policies", - "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's conditional access policies on your behalf.", - "userConsentDisplayName": "Read and write your organization's conditional access policies", - "value": "Policy.ReadWrite.ConditionalAccess" - }, - { - "description": "Allows the app to read your organization's policies on behalf of the signed-in user.", - "displayName": "Read your organization's policies", - "id": "572fea84-0151-49b2-9301-11cb16974376", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization's policies on your behalf.", - "userConsentDisplayName": "Read your organization's policies", - "value": "Policy.Read.All" - }, - { - "description": "Allows the app to read access reviews, reviewers, decisions and settings that the signed-in user has access to in the organization.", - "displayName": "Read all access reviews that user can access", - "id": "ebfcd32b-babb-40f4-a14b-42706e83bd28", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read information on access reviews, reviewers, decisions and settings that you have access to.", - "userConsentDisplayName": "Read access reviews that you can access", - "value": "AccessReview.Read.All" - }, - { - "description": "Allows the app to read, update, delete and perform actions on access reviews, reviewers, decisions and settings that the signed-in user has access to in the organization.", - "displayName": "Manage all access reviews that user can access", - "id": "e4aa47b9-9a69-4109-82ed-36ec70d85ff1", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update and perform action on access reviews, reviewers, decisions and settings that you have access to.", - "userConsentDisplayName": "Manage access reviews that you can access", - "value": "AccessReview.ReadWrite.All" - }, - { - "description": "Allows the app to read programs and program controls that the signed-in user has access to in the organization.", - "displayName": "Read all programs that user can access", - "id": "c492a2e1-2f8f-4caa-b076-99bbf6e40fe4", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read information on programs and program controls that you have access to.", - "userConsentDisplayName": "Read programs that you can access", - "value": "ProgramControl.Read.All" - }, - { - "description": "Allows the app to read, update, delete and perform actions on programs and program controls that the signed-in user has access to in the organization.", - "displayName": "Manage all programs that user can access", - "id": "50fd364f-9d93-4ae1-b170-300e87cccf84", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update and perform action on programs and program controls that you have access to.", - "userConsentDisplayName": "Manage programs that you can access", - "value": "ProgramControl.ReadWrite.All" - }, - { - "description": "Allows the app to create, read, update, and delete apps in the app catalogs.", - "displayName": "Read and write to all app catalogs", - "id": "1ca167d5-1655-44a1-8adf-1414072e1ef9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create, read, update, and delete apps in the app catalogs.", - "userConsentDisplayName": "Read and write to all app catalogs", - "value": "AppCatalog.ReadWrite.All" - }, - { - "description": "Allows the app to request and manage just in time elevation (including scheduled elevation) of users to Azure AD built-in administrative roles, on behalf of signed-in users.", - "displayName": "Read and write privileged access to Azure AD", - "id": "3c3c74f5-cdaa-4a97-b7e0-4e788bfcfb37", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to request and manage just in time elevation (including scheduled elevation) of users to Azure AD built-in administrative roles, on your behalf.", - "userConsentDisplayName": "Read and write privileged access to Azure AD", - "value": "PrivilegedAccess.ReadWrite.AzureAD" - }, - { - "description": "Allows the app to read terms of use agreements on behalf of the signed-in user.", - "displayName": "Read all terms of use agreements", - "id": "af2819c9-df71-4dd3-ade7-4d7c9dc653b7", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read terms of use agreements on your behalf.", - "userConsentDisplayName": "Read all terms of use agreements", - "value": "Agreement.Read.All" - }, - { - "description": "Allows the app to read and write terms of use agreements on behalf of the signed-in user.", - "displayName": "Read and write all terms of use agreements", - "id": "ef4b5d93-3104-4664-9053-a5c49ab44218", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write terms of use agreements on your behalf.", - "userConsentDisplayName": "Read and write all terms of use agreements", - "value": "Agreement.ReadWrite.All" - }, - { - "description": "Allows the app to read terms of use acceptance statuses on behalf of the signed-in user.", - "displayName": "Read user terms of use acceptance statuses", - "id": "0b7643bb-5336-476f-80b5-18fbfbc91806", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your terms of use acceptance statuses.", - "userConsentDisplayName": "Read your terms of use acceptance statuses", - "value": "AgreementAcceptance.Read" - }, - { - "description": "Allows the app to read terms of use acceptance statuses on behalf of the signed-in user.", - "displayName": "Read terms of use acceptance statuses that user can access", - "id": "a66a5341-e66e-4897-9d52-c2df58c2bfb9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read terms of use acceptance statuses on your behalf.", - "userConsentDisplayName": "Read all terms of use acceptance statuses", - "value": "AgreementAcceptance.Read.All" - }, - { - "description": "Read activity data for your organization", - "displayName": "Allows the application to read activity data for your organization.", - "id": "594c1fb6-4f81-4475-ae41-0c394909246c", - "Origin": "Delegated (Office 365 Management)", - "userConsentDescription": "Read activity data for your organization", - "userConsentDisplayName": "Allows the application to read activity data for your organization.", - "value": "ActivityFeed.Read" - }, - { - "description": "Allows the app to read and query your audit log activities, on behalf of the signed-in user.", - "displayName": "Read audit log data", - "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and query your audit log activities, on your behalf.", - "userConsentDisplayName": "Read audit log data", - "value": "AuditLog.Read.All" - }, - { - "description": "Allows the app to read and report the signed-in user's activity in the app.", - "displayName": "Read and write app activity to users' activity feed", - "id": "47607519-5fb1-47d9-99c7-da4b48f369b1", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and report your activity in the app.", - "userConsentDisplayName": "Read and write app activity to your activity feed", - "value": "UserActivity.ReadWrite.CreatedByApp" - }, - { - "description": "Allows the app to read properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups.", - "displayName": "Read Microsoft Intune Device Configuration and Policies", - "id": "f1493658-876a-4c87-8fa7-edb559b3476a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups.", - "userConsentDisplayName": "Read Microsoft Intune Device Configuration and Policies", - "value": "DeviceManagementConfiguration.Read.All" - }, - { - "description": "Allows the app to read and write properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups.", - "displayName": "Read and write Microsoft Intune Device Configuration and Policies", - "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups.", - "userConsentDisplayName": "Read and write Microsoft Intune Device Configuration and Policies", - "value": "DeviceManagementConfiguration.ReadWrite.All" - }, - { - "description": "Allows the app to read the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune.", - "displayName": "Read Microsoft Intune apps", - "id": "4edf5f54-4666-44af-9de9-0144fb4b6e8c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune.", - "userConsentDisplayName": "Read Microsoft Intune apps", - "value": "DeviceManagementApps.Read.All" - }, - { - "description": "Allows the app to read and write the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune.", - "displayName": "Read and write Microsoft Intune apps", - "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune.", - "userConsentDisplayName": "Read and write Microsoft Intune apps", - "value": "DeviceManagementApps.ReadWrite.All" - }, - { - "description": "Allows the app to read the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings.", - "displayName": "Read Microsoft Intune RBAC settings", - "id": "49f0cc30-024c-4dfd-ab3e-82e137ee5431", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings.", - "userConsentDisplayName": "Read Microsoft Intune RBAC settings", - "value": "DeviceManagementRBAC.Read.All" - }, - { - "description": "Allows the app to read and write the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings.", - "displayName": "Read and write Microsoft Intune RBAC settings", - "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings.", - "userConsentDisplayName": "Read and write Microsoft Intune RBAC settings", - "value": "DeviceManagementRBAC.ReadWrite.All" - }, - { - "description": "Allows the app to read the properties of devices managed by Microsoft Intune.", - "displayName": "Read Microsoft Intune devices", - "id": "314874da-47d6-4978-88dc-cf0d37f0bb82", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the properties of devices managed by Microsoft Intune.", - "userConsentDisplayName": "Read devices Microsoft Intune devices", - "value": "DeviceManagementManagedDevices.Read.All" - }, - { - "description": "Allows the app to read and write the properties of devices managed by Microsoft Intune. Does not allow high impact operations such as remote wipe and password reset on the device\u2019s owner.", - "displayName": "Read and write Microsoft Intune devices", - "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the properties of devices managed by Microsoft Intune. Does not allow high impact operations such as remote wipe and password reset on the device\u2019s owner.", - "userConsentDisplayName": "Read and write Microsoft Intune devices", - "value": "DeviceManagementManagedDevices.ReadWrite.All" - }, - { - "description": "Allows the app to perform remote high impact actions such as wiping the device or resetting the passcode on devices managed by Microsoft Intune.", - "displayName": "Perform user-impacting remote actions on Microsoft Intune devices", - "id": "3404d2bf-2b13-457e-a330-c24615765193", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to perform remote high impact actions such as wiping the device or resetting the passcode on devices managed by Microsoft Intune.", - "userConsentDisplayName": "Perform user-impacting remote actions on Microsoft Intune devices", - "value": "DeviceManagementManagedDevices.PrivilegedOperations.All" - }, - { - "description": "Allows the app to read and write Microsoft Intune service properties including device enrollment and third party service connection configuration.", - "displayName": "Read and write Microsoft Intune configuration", - "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write Microsoft Intune service properties including device enrollment and third party service connection configuration.", - "userConsentDisplayName": "Read and write Microsoft Intune configuration", - "value": "DeviceManagementServiceConfig.ReadWrite.All" - }, - { - "description": "Allows the app to read Microsoft Intune service properties including device enrollment and third party service connection configuration.", - "displayName": "Read Microsoft Intune configuration", - "id": "8696daa5-bce5-4b2e-83f9-51b6defc4e1e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read Microsoft Intune service properties including device enrollment and third party service connection configuration.", - "userConsentDisplayName": "Read Microsoft Intune configuration", - "value": "DeviceManagementServiceConfig.Read.All" - }, - { - "description": "Allows the app to read your organization\u2019s security events on behalf of the signed-in user.", - "displayName": "Read your organization\u2019s security events", - "id": "64733abd-851e-478a-bffb-e47a14b18235", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization\u2019s security events on your behalf.", - "userConsentDisplayName": "Read your organization\u2019s security events", - "value": "SecurityEvents.Read.All" - }, - { - "description": "Allows the app to read your organization\u2019s security events on behalf of the signed-in user. Also allows the app to update editable properties in security events on behalf of the signed-in user.", - "displayName": "Read and update your organization\u2019s security events", - "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization\u2019s security events on your behalf. Also allows you to update editable properties in security events.", - "userConsentDisplayName": "Read and update your organization\u2019s security events", - "value": "SecurityEvents.ReadWrite.All" - }, - { - "description": "Allows the app to read a scored list of relevant people of the signed-in user or other users in the signed-in user's organization. The list can include local contacts, contacts from social networking, your organization's directory, and people from recent communications (such as email and Skype).", - "displayName": "Read all users' relevant people lists", - "id": "b89f9189-71a5-4e70-b041-9887f0bc7e4a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read a list of people in the order that is most relevant to you. Allows the app to read a list of people in the order that is most relevant to another user in your organization. These can include local contacts, contacts from social networking, people listed in your organization\u2019s directory, and people from recent communications.", - "userConsentDisplayName": "Read all users\u2019 relevant people lists", - "value": "People.Read.All" - }, - { - "description": "Manage the state and settings of all Microsoft education apps on behalf of the user.", - "displayName": "Manage education app settings", - "id": "63589852-04e3-46b4-bae9-15d5b1050748", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage the state and settings of all Microsoft education apps on your behalf.", - "userConsentDisplayName": "Manage your education app settings", - "value": "EduAdministration.ReadWrite" - }, - { - "description": "Read the state and settings of all Microsoft education apps on behalf of the user.", - "displayName": "Read education app settings", - "id": "8523895c-6081-45bf-8a5d-f062a2f12c9f", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view the state and settings of all Microsoft education apps on your behalf.", - "userConsentDisplayName": "View your education app settings", - "value": "EduAdministration.Read" - }, - { - "description": "Allows the app to read and write assignments and their grades on behalf of the user.", - "displayName": "Read and write users' class assignments and their grades", - "id": "2f233e90-164b-4501-8bce-31af2559a2d3", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view and modify your assignments on your behalf including \u00a0grades.", - "userConsentDisplayName": "View and modify your assignments and grades", - "value": "EduAssignments.ReadWrite" - }, - { - "description": "Allows the app to read assignments and their grades on behalf of the user.", - "displayName": "Read users' class assignments and their grades", - "id": "091460c9-9c4a-49b2-81ef-1f3d852acce2", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view your assignments on your behalf including grades.", - "userConsentDisplayName": "View your assignments and grades", - "value": "EduAssignments.Read" - }, - { - "description": "Allows the app to read and write assignments without grades on behalf of the user.", - "displayName": "Read and write users' class assignments without grades", - "id": "2ef770a1-622a-47c4-93ee-28d6adbed3a0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view and modify your assignments on your behalf without seeing grades.", - "userConsentDisplayName": "View and modify your assignments without grades", - "value": "EduAssignments.ReadWriteBasic" - }, - { - "description": "Allows the app to read assignments without grades on behalf of the user.", - "displayName": "Read users' class assignments without grades", - "id": "c0b0103b-c053-4b2e-9973-9f3a544ec9b8", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view your assignments on your behalf without seeing grades.", - "userConsentDisplayName": "View your assignments without grades", - "value": "EduAssignments.ReadBasic" - }, - { - "description": "Allows the app to read and write the structure of schools and classes in an organization's roster and education-specific information about users to be read and written on behalf of the user.", - "displayName": "Read and write users' view of the roster", - "id": "359e19a6-e3fa-4d7f-bcab-d28ec592b51e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view and modify information about schools and classes in your organization and education-related information about you and other users on your behalf.", - "userConsentDisplayName": "View and modify your school, class and user information", - "value": "EduRoster.ReadWrite" - }, - { - "description": "Allows the app to read the structure of schools and classes in an organization's roster and education-specific information about users to be read on behalf of the user.", - "displayName": "Read users' view of the roster", - "id": "a4389601-22d9-4096-ac18-36a927199112", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view information about schools and classes in your organization and education-related information about you and other users on your behalf.", - "userConsentDisplayName": "View your school, class and user information", - "value": "EduRoster.Read" - }, - { - "description": "Allows the app to read a limited subset of the properties from the structure of schools and classes in an organization's roster and a limited subset of properties about users to be read on behalf of the user.\u00a0Includes name, status, education role, email address and photo.", - "displayName": "Read a limited subset of users' view of the roster", - "id": "5d186531-d1bf-4f07-8cea-7c42119e1bd9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view minimal \u00a0information about both schools and classes in your organization and education-related information about you and other users on your behalf.", - "userConsentDisplayName": "View a limited subset of your school, class and user information", - "value": "EduRoster.ReadBasic" - }, - { - "description": "Allows the app to report the signed-in user's app activity information to Microsoft Timeline.", - "displayName": "Write app activity to users' timeline", - "id": "367492fc-594d-4972-a9b5-0d58c622c91c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to report your app activity information to Microsoft Timeline.", - "userConsentDisplayName": "Write app activity to your timeline", - "value": "UserTimelineActivity.Write.CreatedByApp" - }, - { - "description": "Allows the app to create, read, update, and delete user's mailbox settings. Does not include permission to send mail.", - "displayName": "Read and write user mailbox settings", - "id": "818c620a-27a9-40bd-a6a5-d96f7d610b4b", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create, and delete your mailbox settings.", - "userConsentDisplayName": "Read and write to your mailbox settings", - "value": "MailboxSettings.ReadWrite" - }, - { - "description": "Allows the app to launch another app or communicate with another app on a user's device on behalf of the signed-in user.", - "displayName": "Communicate with user devices", - "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to launch another app or communicate with another app on a device that you own.", - "userConsentDisplayName": "Communicate with your other devices", - "value": "Device.Command" - }, - { - "description": "Allows the app to read a user's list of devices on behalf of the signed-in user.", - "displayName": "Read user devices", - "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to see your list of devices.", - "userConsentDisplayName": "View your list of devices", - "value": "Device.Read" - }, - { - "description": "Allows the app to read, share, and modify OneNote notebooks that the signed-in user has access to in the organization.", - "displayName": "Read and write all OneNote notebooks that user can access", - "id": "64ac0503-b4fa-45d9-b544-71a463f05da0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, share, and modify all the OneNote notebooks that you have access to.", - "userConsentDisplayName": "Read and write all OneNote notebooks that you can access", - "value": "Notes.ReadWrite.All" - }, - { - "description": "Allows the app to read OneNote notebooks that the signed-in user has access to in the organization.", - "displayName": "Read all OneNote notebooks that user can access", - "id": "dfabfca6-ee36-4db2-8208-7a28381419b3", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all the OneNote notebooks that you have access to.", - "userConsentDisplayName": "Read all OneNote notebooks that you can access", - "value": "Notes.Read.All" - }, - { - "description": "Allows the app to read, share, and modify OneNote notebooks on behalf of the signed-in user.", - "displayName": "Read and write user OneNote notebooks", - "id": "615e26af-c38a-4150-ae3e-c3b0d4cb1d6a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, share, and modify OneNote notebooks on your behalf.", - "userConsentDisplayName": "Read and write your OneNote notebooks", - "value": "Notes.ReadWrite" - }, - { - "description": "Allows the app to read OneNote notebooks on behalf of the signed-in user.", - "displayName": "Read user OneNote notebooks", - "id": "371361e4-b9e2-4a3f-8315-2a301a3b0a3d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read OneNote notebooks on your behalf.", - "userConsentDisplayName": "Read your OneNote notebooks", - "value": "Notes.Read" - }, - { - "description": "This is deprecated! Do not use! This permission no longer has any effect. You can safely consent to it. No additional privileges will be granted to the app.", - "displayName": "Limited notebook access (deprecated)", - "id": "ed68249d-017c-4df5-9113-e684c7f8760b", - "Origin": "Delegated", - "userConsentDescription": "This permission no longer has any effect. You can safely consent to it. No additional privileges will be granted to the app.", - "userConsentDisplayName": "Limited access to your OneNote notebooks for this app (preview)", - "value": "Notes.ReadWrite.CreatedByApp" - }, - { - "description": "Allows the app to read the titles of OneNote notebooks and sections and to create new pages, notebooks, and sections on behalf of the signed-in user.", - "displayName": "Create user OneNote notebooks", - "id": "9d822255-d64d-4b7a-afdb-833b9a97ed02", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to view the titles of your OneNote notebooks and sections and to create new pages, notebooks, and sections on your behalf.", - "userConsentDisplayName": "Create your OneNote notebooks", - "value": "Notes.Create" - }, - { - "description": "Allows the app to invite guest users to the organization, on behalf of the signed-in user.", - "displayName": "Invite guest users to the organization", - "id": "63dd7cd9-b489-4adf-a28c-ac38b9a0f962", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to invite guest users to the organization, on your behalf.", - "userConsentDisplayName": "Invite guest users to the organization", - "value": "User.Invite.All" - }, - { - "description": "Allows the app to the read user's mailbox settings. Does not include permission to send mail.", - "displayName": "Read user mailbox settings", - "id": "87f447af-9fa4-4c32-9dfa-4a57a73d18ce", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your mailbox settings.", - "userConsentDisplayName": "Read your mailbox settings", - "value": "MailboxSettings.Read" - }, - { - "description": "(Preview) Allows the app to read files that the user selects. The app has access for several hours after the user selects a file.", - "displayName": "Read files that the user selects (preview)", - "id": "5447fe39-cb82-4c1a-b977-520e67e724eb", - "Origin": "Delegated", - "userConsentDescription": "(Preview) Allows the app to read files that you select. After you select a file, the app has access to the file for several hours.", - "userConsentDisplayName": "Read selected files", - "value": "Files.Read.Selected" - }, - { - "description": "(Preview) Allows the app to read and write files that the user selects. The app has access for several hours after the user selects a file.", - "displayName": "Read and write files that the user selects (preview)", - "id": "17dde5bd-8c17-420f-a486-969730c1b827", - "Origin": "Delegated", - "userConsentDescription": "(Preview) Allows the app to read and write files that you select. After you select a file, the app has access to the file for several hours.", - "userConsentDisplayName": "Read and write selected files", - "value": "Files.ReadWrite.Selected" - }, - { - "description": "(Preview) Allows the app to read, create, update and delete files in the application's folder.", - "displayName": "Have full access to the application's folder (preview)", - "id": "8019c312-3263-48e6-825e-2b833497195b", - "Origin": "Delegated", - "userConsentDescription": "(Preview) Allows the app to read, create, update and delete files in the application's folder.", - "userConsentDisplayName": "Have full access to the application's folder", - "value": "Files.ReadWrite.AppFolder" - }, - { - "description": "Allows an app to read all service usage reports on behalf of the signed-in user. Services that provide usage reports include Office 365 and Azure Active Directory.", - "displayName": "Read all usage reports", - "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read all service usage reports on your behalf. Services that provide usage reports include Office 365 and Azure Active Directory.", - "userConsentDisplayName": "Read all usage reports", - "value": "Reports.Read.All" - }, - { - "description": "Allows the application to edit or delete documents and list items in all site collections on behalf of the signed-in user.", - "displayName": "Edit or delete items in all site collections", - "id": "89fe6a52-be36-487e-b7d8-d061c450a026", - "Origin": "Delegated", - "userConsentDescription": "Allow the application to edit or delete documents and list items in all site collections on your behalf.", - "userConsentDisplayName": "Edit or delete items in all site collections", - "value": "Sites.ReadWrite.All" - }, - { - "description": "Allows the app to create, read, update, and delete tasks a user has permissions to, including their own and shared tasks.", - "displayName": "Read and write user and shared tasks", - "id": "c5ddf11b-c114-4886-8558-8a4e557cd52b", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create, and delete tasks you have permissions to access, including your own and shared tasks.", - "userConsentDisplayName": "Read and write to your and shared tasks", - "value": "Tasks.ReadWrite.Shared" - }, - { - "description": "Allows the app to read tasks a user has permissions to access, including their own and shared tasks.", - "displayName": "Read user and shared tasks", - "id": "88d21fd4-8e5a-4c32-b5e2-4a1c95f34f72", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read tasks you have permissions to access, including your own and shared tasks.", - "userConsentDisplayName": "Read your and shared tasks", - "value": "Tasks.Read.Shared" - }, - { - "description": "Allows the app to create, read, update, and delete contacts a user has permissions to, including their own and shared contacts.", - "displayName": "Read and write user and shared contacts", - "id": "afb6c84b-06be-49af-80bb-8f3f77004eab", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create, and delete contacts you have permissions to access, including your own and shared contacts.", - "userConsentDisplayName": "Read and write to your and shared contacts", - "value": "Contacts.ReadWrite.Shared" - }, - { - "description": "Allows the app to read contacts a user has permissions to access, including their own and shared contacts.", - "displayName": "Read user and shared contacts", - "id": "242b9d9e-ed24-4d09-9a52-f43769beb9d4", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read contacts you have permissions to access, including your own and shared contacts.", - "userConsentDisplayName": "Read your and shared contacts", - "value": "Contacts.Read.Shared" - }, - { - "description": "Allows the app to create, read, update and delete events in all calendars in the organization user has permissions to access. This includes delegate and shared calendars.", - "displayName": "Read and write user and shared calendars", - "id": "12466101-c9b8-439a-8589-dd09ee67e8e9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create and delete events in all calendars in your organization you have permissions to access. This includes delegate and shared calendars.", - "userConsentDisplayName": "Read and write to your and shared calendars", - "value": "Calendars.ReadWrite.Shared" - }, - { - "description": "Allows the app to read events in all calendars that the user can access, including delegate and shared calendars.", - "displayName": "Read user and shared calendars", - "id": "2b9c4092-424d-4249-948d-b43879977640", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read events in all calendars that you can access, including delegate and shared calendars.\u00a0", - "userConsentDisplayName": "Read calendars\u00a0you can access", - "value": "Calendars.Read.Shared" - }, - { - "description": "Allows the app to send mail as the signed-in user, including sending on-behalf of others.", - "displayName": "Send mail on behalf of others", - "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to send mail as you or on-behalf of someone else.", - "userConsentDisplayName": "Send mail on behalf of others or yourself", - "value": "Mail.Send.Shared" - }, - { - "description": "Allows the app to create, read, update, and delete mail a user has permission to access, including their own and shared mail. Does not include permission to send mail.", - "displayName": "Read and write user and shared mail", - "id": "5df07973-7d5d-46ed-9847-1271055cbd51", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create, and delete mail you have permission to access, including your own and shared mail. Does not allow the app to send mail on your behalf.", - "userConsentDisplayName": "Read and write mail\u00a0you can access", - "value": "Mail.ReadWrite.Shared" - }, - { - "description": "Allows the app to read mail a user can access, including their own and shared mail.", - "displayName": "Read user and shared mail", - "id": "7b9103a5-4610-446b-9670-80643382c1fa", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read mail you can access, including shared mail.", - "userConsentDisplayName": "Read mail you can access", - "value": "Mail.Read.Shared" - }, - { - "description": "Allows users to sign-in to the app, and allows the app to read the profile of signed-in users. It also allows the app to read basic company information of signed-in users.", - "displayName": "Sign in and read user profile", - "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", - "Origin": "Delegated", - "userConsentDescription": "Allows you to sign in to the app with your organizational account and let the app read your profile. It also allows the app to read basic company information.", - "userConsentDisplayName": "Sign you in and read your profile", - "value": "User.Read" - }, - { - "description": "Allows the app to read your profile. It also allows the app to update your profile information on your behalf.", - "displayName": "Read and write access to user profile", - "id": "b4e74841-8e56-480b-be8b-910348b18b4c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your profile, and discover your group membership, reports and manager. It also allows the app to update your profile information on your behalf.", - "userConsentDisplayName": "Read and update your profile", - "value": "User.ReadWrite" - }, - { - "description": "Allows the app to read a basic set of profile properties of other users in your organization on behalf of the signed-in user. This includes display name, first and last name, email address and photo.", - "displayName": "Read all users' basic profiles", - "id": "b340eb25-3456-403f-be2f-af7a0d370277", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read a basic set of profile properties of other users in your organization on your behalf. Includes display name, first and last name, email address and photo.", - "userConsentDisplayName": "Read all users' basic profiles", - "value": "User.ReadBasic.All" - }, - { - "description": "Allows the app to read the full set of profile properties, reports, and managers of other users in your organization, on behalf of the signed-in user.", - "displayName": "Read all users' full profiles", - "id": "a154be20-db9c-4678-8ab7-66f6cc099a59", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the full set of profile properties, reports, and managers of other users in your organization, on your behalf.", - "userConsentDisplayName": "Read all users' full profiles", - "value": "User.Read.All" - }, - { - "description": "Allows the app to read and write the full set of profile properties, reports, and managers of other users in your organization, on behalf of the signed-in user.", - "displayName": "Read and write all users' full profiles", - "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the full set of profile properties, reports, and managers of other users in your organization, on your behalf.", - "userConsentDisplayName": "Read and write all users' full profiles", - "value": "User.ReadWrite.All" - }, - { - "description": "Allows the app to list groups, and to read their properties and all group memberships on behalf of the signed-in user. Also allows the app to read calendar, conversations, files, and other group content for all groups the signed-in user can access. ", - "displayName": "Read all groups", - "id": "5f8c59db-677d-491f-a6b8-5f174b11ec1d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to list groups, and to read their properties and all group memberships on your behalf. Also allows the app to read calendar, conversations, files, and other group content for all groups you can access. ", - "userConsentDisplayName": "Read all groups", - "value": "Group.Read.All" - }, - { - "description": "Allows the app to create groups and read all group properties and memberships on behalf of the signed-in user. Additionally allows group owners to manage their groups and allows group members to update group content.", - "displayName": "Read and write all groups", - "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create groups and read all group properties and memberships on your behalf. Additionally allows the app to manage your groups and to update group content for groups you are a member of.", - "userConsentDisplayName": "Read and write all groups", - "value": "Group.ReadWrite.All" - }, - { - "description": "Allows the app to read data in your organization's directory, such as users, groups and apps.", - "displayName": "Read directory data", - "id": "06da0dbc-49e2-44d2-8312-53f166ab848a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read data in your organization's directory.", - "userConsentDisplayName": "Read directory data", - "value": "Directory.Read.All" - }, - { - "description": "Allows the app to read and write data in your organization's directory, such as users, and groups. It does not allow the app to delete users or groups, or reset user passwords.", - "displayName": "Read and write directory data", - "id": "c5366453-9fb0-48a5-a156-24f0c49a4b84", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write data in your organization's directory, such as other users, groups. It does not allow the app to delete users or groups, or reset user passwords.", - "userConsentDisplayName": "Read and write directory data", - "value": "Directory.ReadWrite.All" - }, - { - "description": "Allows the app to have the same access to information in the directory as the signed-in user.", - "displayName": "Access directory as the signed in user", - "id": "0e263e50-5827-48a4-b97c-d940288653c7", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to have the same access to information in your work or school directory as you do.", - "userConsentDisplayName": "Access the directory as you", - "value": "Directory.AccessAsUser.All" - }, - { - "description": "Allows the app to create, read, update, and delete email in user mailboxes. Does not include permission to send mail. ", - "displayName": "Read and write access to user mail ", - "id": "024d486e-b451-40bb-833d-3e66d98c5c73", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create and delete email in your mailbox. Does not include permission to send mail. ", - "userConsentDisplayName": "Read and write access to your mail ", - "value": "Mail.ReadWrite" - }, - { - "description": "Allows the app to send mail as users in the organization. ", - "displayName": "Send mail as a user ", - "id": "e383f46e-2787-4529-855e-0e479a3ffac0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to send mail as you. ", - "userConsentDisplayName": "Send mail as you ", - "value": "Mail.Send" - }, - { - "description": "Allows the app to read events in user calendars . ", - "displayName": "Read user calendars ", - "id": "465a38f9-76ea-45b9-9f34-9e8b0d4b0b42", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read events in your calendars. ", - "userConsentDisplayName": "Read your calendars ", - "value": "Calendars.Read" - }, - { - "description": "Allows the app to create, read, update, and delete events in user calendars. ", - "displayName": "Have full access to user calendars ", - "id": "1ec239c2-d7c9-4623-a91a-a9775856bb36", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create and delete events in your calendars. ", - "userConsentDisplayName": "Have full access to your calendars ", - "value": "Calendars.ReadWrite" - }, - { - "description": "Allows the app to read user contacts. ", - "displayName": "Read user contacts ", - "id": "ff74d97f-43af-4b68-9f2a-b77ee6968c5d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read contacts in your contact folders. ", - "userConsentDisplayName": "Read your contacts ", - "value": "Contacts.Read" - }, - { - "description": "Allows the app to create, read, update, and delete user contacts. ", - "displayName": "Have full access to user contacts ", - "id": "d56682ec-c09e-4743-aaf4-1a3aac4caa21", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create and delete contacts in your contact folders. ", - "userConsentDisplayName": "Have full access of your contacts ", - "value": "Contacts.ReadWrite" - }, - { - "description": "Allows the app to read the signed-in user's files.", - "displayName": "Read user files", - "id": "10465720-29dd-4523-a11a-6a75c743c9d9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your files.", - "userConsentDisplayName": "Read your files", - "value": "Files.Read" - }, - { - "description": "Allows the app to read, create, update and delete the signed-in user's files.", - "displayName": "Have full access to user files", - "id": "5c28f0bf-8a70-41f1-8ab2-9032436ddb65", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, create, update, and delete your files.", - "userConsentDisplayName": "Have full access to your files", - "value": "Files.ReadWrite" - }, - { - "description": "Allows the app to read all files the signed-in user can access.", - "displayName": "Read all files that user can access", - "id": "df85f4d6-205c-4ac5-a5ea-6bf408dba283", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all files you can access.", - "userConsentDisplayName": "Read all files that you have access to", - "value": "Files.Read.All" - }, - { - "description": "Allows the app to read, create, update and delete all files the signed-in user can access.", - "displayName": "Have full access to all files user can access", - "id": "863451e7-0667-486c-a5d6-d135439485f0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, create, update and delete all files that you can access.", - "userConsentDisplayName": "Have full access to all files you have access to", - "value": "Files.ReadWrite.All" - }, - { - "description": "Allows the application to read documents and list items in all site collections on behalf of the signed-in user", - "displayName": "Read items in all site collections", - "id": "205e70e5-aba6-4c52-a976-6d2d46c48043", - "Origin": "Delegated", - "userConsentDescription": "Allow the application to read documents and list items in all site collections on your behalf", - "userConsentDisplayName": "Read items in all site collections", - "value": "Sites.Read.All" - }, - { - "description": "Allows users to sign in to the app with their work or school accounts and allows the app to see basic user profile information.", - "displayName": "Sign users in", - "id": "37f7f235-527c-4136-accd-4a02d197296e", - "Origin": "Delegated", - "userConsentDescription": "Allows you to sign in to the app with your work or school account and allows the app to read your basic profile information.", - "userConsentDisplayName": "Sign in as you", - "value": "openid" - }, - { - "description": "Allows the app to read your users' primary email address", - "displayName": "View users' email address", - "id": "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your primary email address", - "userConsentDisplayName": "View your email address", - "value": "email" - }, - { - "description": "Allows the app to read identity risk event information for all users in your organization on behalf of the signed-in user. ", - "displayName": "Read identity risk event information", - "id": "8f6a01e7-0391-4ee5-aa22-a3af122cef27", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read identity risk event information for all users in your organization on behalf of the signed-in user. ", - "userConsentDisplayName": "Read identity risk event information", - "value": "IdentityRiskEvent.Read.All" - }, - { - "description": "Allows the app to read the memberships of hidden groups and administrative units on behalf of the signed-in user, for those hidden groups and administrative units that the signed-in user has access to.", - "displayName": "Read hidden memberships", - "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the memberships of hidden groups or administrative units on your behalf, for those hidden groups or adminstrative units that you have access to.", - "userConsentDisplayName": "Read your hidden memberships", - "value": "Member.Read.Hidden" - }, - { - "description": "Allows the app to read a ranked list of relevant people of the signed-in user. The list includes local contacts, contacts from social networking, your organization's directory, and people from recent communications (such as email and Skype).", - "displayName": "Read users' relevant people lists", - "id": "ba47897c-39ec-4d83-8086-ee8256fa737d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read a list of people in the order that's most relevant to you. This includes your local contacts, your contacts from social networking, people listed in your organization's directory, and people from recent communications.", - "userConsentDisplayName": "Read your relevant people list", - "value": "People.Read" - }, - { - "description": "Allows the application to create or delete document libraries and lists in all site collections on behalf of the signed-in user.", - "displayName": "Create, edit, and delete items and lists in all site collections", - "id": "65e50fdc-43b7-4915-933e-e8138f11f40a", - "Origin": "Delegated", - "userConsentDescription": "Allow the application to create or delete document libraries and lists in all site collections on your behalf.", - "userConsentDisplayName": "Create, edit, and delete items and lists in all your site collections", - "value": "Sites.Manage.All" - }, - { - "description": "Allows the application to have full control of all site collections on behalf of the signed-in user.", - "displayName": "Have full control of all site collections", - "id": "5a54b8b3-347c-476d-8f8e-42d5c7424d29", - "Origin": "Delegated", - "userConsentDescription": "Allow the application to have full control of all site collections on your behalf.", - "userConsentDisplayName": "Have full control of all your site collections", - "value": "Sites.FullControl.All" - }, - { - "description": "Allows the app to read and write your organization\u2019s identity (authentication) providers\u2019 properties on behalf of the user.", - "displayName": "Read and write identity providers", - "id": "f13ce604-1677-429f-90bd-8a10b9f01325", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization\u2019s identity (authentication) providers\u2019 properties on your behalf.", - "userConsentDisplayName": "Read and write identity providers", - "value": "IdentityProvider.ReadWrite.All" - }, - { - "description": "Allows the app to read your organization\u2019s identity (authentication) providers\u2019 properties on behalf of the user.", - "displayName": "Read identity providers", - "id": "43781733-b5a7-4d1b-98f4-e8edff23e1a9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization\u2019s identity (authentication) providers\u2019 properties on your behalf.", - "userConsentDisplayName": "Read identity providers", - "value": "IdentityProvider.Read.All" - }, - { - "description": "Allows an app to read bookings appointments, businesses, customers, services, and staff on behalf of the signed-in user.", - "displayName": "Read bookings information", - "id": "33b1df99-4b29-4548-9339-7a7b83eaeebc", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read bookings appointments, businesses, customers, services, and staff on your behalf.", - "userConsentDisplayName": "Read bookings information", - "value": "Bookings.Read.All" - }, - { - "description": "Allows an app to read and write bookings appointments and customers, and additionally allows read businesses information, services, and staff on behalf of the signed-in user.", - "displayName": "Read and write booking appointments", - "id": "02a5a114-36a6-46ff-a102-954d89d9ab02", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read and write bookings appointments and customers, and additionally allows read businesses information, services, and staff on your behalf.", - "userConsentDisplayName": "Read and write booking appointments", - "value": "BookingsAppointment.ReadWrite.All" - }, - { - "description": "Allows an app to read and write bookings appointments, businesses, customers, services, and staff on behalf of the signed-in user. Does not allow create, delete and publish of booking businesses.", - "displayName": "Read and write bookings information", - "id": "948eb538-f19d-4ec5-9ccc-f059e1ea4c72", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read and write Bookings appointments, businesses, customers, services, and staff on your behalf. Does not allow create, delete and publish of booking businesses.", - "userConsentDisplayName": "Read and write bookings information", - "value": "Bookings.ReadWrite.All" - }, - { - "description": "Allows an app to read, write and manage bookings appointments, businesses, customers, services, and staff on behalf of the signed-in user.", - "displayName": "Manage bookings information", - "id": "7f36b48e-542f-4d3b-9bcb-8406f0ab9fdb", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read, write and manage bookings appointments, businesses, customers, services, and staff on your behalf.", - "userConsentDisplayName": "Manage bookings information", - "value": "Bookings.Manage.All" - }, - { - "description": "Allows the app to have the same access to mailboxes as the signed-in user via Exchange ActiveSync.", - "displayName": "Access mailboxes via Exchange ActiveSync", - "id": "ff91d191-45a0-43fd-b837-bd682c4a0b0f", - "Origin": "Delegated", - "userConsentDescription": "Allows the app full access to your mailboxes on your behalf.", - "userConsentDisplayName": "Access your mailboxes", - "value": "EAS.AccessAsUser.All" - }, - { - "description": "Allows the app to read and write financials data on behalf of the signed-in user.", - "displayName": "Read and write financials data", - "id": "f534bf13-55d4-45a9-8f3c-c92fe64d6131", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write financials data on your behalf.", - "userConsentDisplayName": "Read and write financials data", - "value": "Financials.ReadWrite.All" - }, - { - "description": "Allows the app to read your organization's user flows, on behalf of the signed-in user.", - "displayName": "Read all identity user flows", - "id": "2903d63d-4611-4d43-99ce-a33f3f52e343", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization's user flows, on your behalf.", - "userConsentDisplayName": "Read all identity user flows", - "value": "IdentityUserFlow.Read.All" - }, - { - "description": "Allows the app to read or write your organization's user flows, on behalf of the signed-in user.", - "displayName": "Read and write all identity user flows", - "id": "281892cc-4dbf-4e3a-b6cc-b21029bb4e82", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read or write your organization's user flows, on your behalf.", - "userConsentDisplayName": "Read and write all identity user flows", - "value": "IdentityUserFlow.ReadWrite.All" - }, - { - "description": "Allows the app to read all organizational contacts on behalf of the signed-in user. \u00a0These contacts are managed by the organization and are different from a user's personal contacts.", - "displayName": "Read organizational contacts", - "id": "08432d1b-5911-483c-86df-7980af5cdee0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all organizational contacts on your behalf.\u00a0 These contacts are managed by the organization and are different from your personal contacts.", - "userConsentDisplayName": "Read organizational contacts", - "value": "OrgContact.Read.All" - }, - { - "description": "Allows the app to manage permission grants for application permissions to any API (including Microsoft Graph) and application assignments for any app, on behalf of the signed-in user.", - "displayName": "Manage app permission grants and app role assignments", - "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage permission grants for application permissions to any API (including Microsoft Graph) and application assignments for any app, on your behalf.", - "userConsentDisplayName": "Manage app permission grants and app role assignments", - "value": "AppRoleAssignment.ReadWrite.All" - }, - { - "description": "Allows the app to manage permission grants for delegated permissions exposed by any API (including Microsoft Graph), on behalf of the signed in user.", - "displayName": "Manage all delegated permission grants", - "id": "41ce6ca6-6826-4807-84f1-1c82854f7ee5", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage permission grants for delegated permissions exposed by any API (including Microsoft Graph), on your behalf. ", - "userConsentDisplayName": "Manage all delegated permission grants", - "value": "DelegatedPermissionGrant.ReadWrite.All" - }, - { - "description": "Allows the app to read online meeting details on behalf of the signed-in user.", - "displayName": "Read user's online meetings", - "id": "9be106e1-f4e3-4df5-bdff-e4bc531cbe43", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read online meeting details on your behalf.", - "userConsentDisplayName": "Read your online meetings", - "value": "OnlineMeetings.Read" - }, - { - "description": "Allows the app to read and create online meetings on behalf of the signed-in user.", - "displayName": "Read and create user's online meetings", - "id": "a65f2972-a4f8-4f5e-afd7-69ccb046d5dc", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and create online meetings on your behalf.", - "userConsentDisplayName": "Read and create your online meetings", - "value": "OnlineMeetings.ReadWrite" - }, - { - "description": "Allows the app to read the signed-in user's teamwork activity feed.", - "displayName": "Read user's teamwork activity feed", - "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your teamwork activity feed.", - "userConsentDisplayName": "Read your teamwork activity feed", - "value": "TeamsActivity.Read" - }, - { - "description": "Allows the app to request and manage time-based assignment and just-in-time elevation of user privileges to manage Azure resources (like subscriptions, resource groups, storage, compute) on behalf of the signed-in users.", - "displayName": "Read and write privileged access to Azure resources", - "id": "a84a9652-ffd3-496e-a991-22ba5529156a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to request and manage time-based assignment and just-in-time elevation of user privileges to manage \u00a0your Azure resources (like your subscriptions, resource groups, storage, compute) on your behalf.", - "userConsentDisplayName": "Read and write privileged access to Azure resources", - "value": "PrivilegedAccess.ReadWrite.AzureResources" - }, - { - "description": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD built-in and custom administrative roles, on behalf of the signed-in user.", - "displayName": "Read privileged access to Azure AD", - "id": "b3a539c9-59cb-4ad5-825a-041ddbdc2bdb", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD built-in and custom administrative roles, on your behalf.", - "userConsentDisplayName": "Read privileged access to Azure AD", - "value": "PrivilegedAccess.Read.AzureAD" - }, - { - "description": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups, on behalf of the signed-in user.", - "displayName": "Read privileged access to Azure AD groups", - "id": "d329c81c-20ad-4772-abf9-3f6fdb7e5988", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups, on your behalf.", - "userConsentDisplayName": "Read privileged access to Azure AD groups", - "value": "PrivilegedAccess.Read.AzureADGroup" - }, - { - "description": "Allows the app to read time-based assignment and just-in-time elevation of Azure resources (like your subscriptions, resource groups, storage, compute) on behalf of the signed-in user.", - "displayName": "Read privileged access to Azure resources", - "id": "1d89d70c-dcac-4248-b214-903c457af83a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read time-based assignment and just-in-time elevation of Azure resources (like your subscriptions, resource groups, storage, compute) on your behalf.", - "userConsentDisplayName": "Read privileged access to your Azure resources", - "value": "PrivilegedAccess.Read.AzureResources" - }, - { - "description": "Allows the app to request and manage time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups, on behalf of the signed-in user.", - "displayName": "Read and write privileged access to Azure AD groups", - "id": "32531c59-1f32-461f-b8df-6f8a3b89f73b", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to request and manage time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups, on your behalf.", - "userConsentDisplayName": "Read and write privileged access to Azure AD groups", - "value": "PrivilegedAccess.ReadWrite.AzureADGroup" - }, - { - "description": "Allows the app to read all the indicators for your organization, on behalf of the signed-in user.", - "displayName": "Read all threat indicators", - "id": "9cc427b4-2004-41c5-aa22-757b755e9796", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all the indicators for your organization, on your behalf.", - "userConsentDisplayName": "Read all threat indicators", - "value": "ThreatIndicators.Read.All" - }, - { - "description": "Allow the app to read external datasets and content, on behalf of the signed-in user.", - "displayName": "Read items in external datasets", - "id": "922f9392-b1b7-483c-a4be-0089be7704fb", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read external datasets and content that you have access to.", - "userConsentDisplayName": "Read items in external datasets", - "value": "ExternalItem.Read.All" - }, - { - "description": "Allows an app to edit channel messages in Microsoft Teams, on behalf of the signed-in user.", - "displayName": "Edit user's channel messages", - "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to edit channel messages in Microsoft Teams, on your behalf.", - "userConsentDisplayName": "Edit your channel messages", - "value": "ChannelMessage.Edit" - }, - { - "description": "Allows an app to send channel messages in Microsoft Teams, on behalf of the signed-in user.", - "displayName": "Send channel messages", - "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to send channel messages in Microsoft Teams, on your behalf.", - "userConsentDisplayName": "Send channel messages", - "value": "ChannelMessage.Send" - }, - { - "description": "Allows the app to manage organization places (conference rooms and room lists) for calendar events and other applications, on behalf of the signed-in user.", - "displayName": "Read and write organization places", - "id": "4c06a06a-098a-4063-868e-5dfee3827264", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage organization places (conference rooms and room lists) for calendar events and other applications, on your behalf.", - "userConsentDisplayName": "Read and write organization places", - "value": "Place.ReadWrite.All" - }, - { - "description": "Allows the app to request access to and management of access packages and related entitlement management resources on behalf of the signed-in user.", - "displayName": "Read and write entitlement management resources", - "id": "ae7a573d-81d7-432b-ad44-4ed5c9d89038", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to request access to and management of access packages and related entitlement management resources that you have access to.", - "userConsentDisplayName": "Read and write entitlement management resources", - "value": "EntitlementManagement.ReadWrite.All" - }, - { - "description": "Allows the app to send, read, update and delete user\u2019s notifications.", - "displayName": "Deliver and manage user's notifications", - "id": "26e2f3e8-b2a1-47fc-9620-89bb5b042024", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to send, read, update and delete your app-specific notifications.", - "userConsentDisplayName": "Deliver and manage your notifications", - "value": "UserNotification.ReadWrite.CreatedByApp" - }, - { - "description": "Allows the app to read applications and service principals on behalf of the signed-in user.", - "displayName": "Read applications", - "id": "c79f8feb-a9db-4090-85f9-90d820caa0eb", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read applications and service principals on your behalf.", - "userConsentDisplayName": "Read applications", - "value": "Application.Read.All" - }, - { - "description": "Allows the app to create, read, update and delete applications and service principals on behalf of the signed-in user. Does not allow management of consent grants.", - "displayName": "Read and write all applications", - "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create, read, update and delete applications and service principals on your behalf. Does not allow management of consent grants.", - "userConsentDisplayName": "Read and write applications", - "value": "Application.ReadWrite.All" - }, - { - "description": "Allows the app to read BitLocker keys on behalf of the signed-in user, for their owned devices. Allows read of the recovery key.", - "displayName": "Read BitLocker keys", - "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read BitLocker keys for your owned devices. Allows read of the recovery key.", - "userConsentDisplayName": "Read your BitLocker keys", - "value": "BitlockerKey.Read.All" - }, - { - "description": "Allows the app to read basic BitLocker key properties on behalf of the signed-in user, for their owned devices. Does not allow read of the recovery key itself.", - "displayName": "Read BitLocker keys basic information", - "id": "5a107bfc-4f00-4e1a-b67e-66451267bc68", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read basic BitLocker key properties for your owned devices. Does not allow read of the recovery key itself.", - "userConsentDisplayName": "Read your BitLocker keys basic information", - "value": "BitlockerKey.ReadBasic.All" - }, - { - "description": "Allows the app to list groups, read basic group properties and read membership of all groups the signed-in user has access to.", - "displayName": "Read group memberships", - "id": "bc024368-1153-4739-b217-4326f2e966d0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to list groups, read basic group properties and read membership of all your groups.", - "userConsentDisplayName": "Read group memberships", - "value": "GroupMember.Read.All" - }, - { - "description": "Allows the app to list groups, read basic properties, read and update the membership of the groups the signed-in user has access to. Group properties and owners cannot be updated and groups cannot be deleted.", - "displayName": "Read and write group memberships", - "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to list groups, read basic properties, read and update the membership of your groups. Group properties and owners cannot be updated and groups cannot be deleted.", - "userConsentDisplayName": "Read and write group memberships", - "value": "GroupMember.ReadWrite.All" - }, - { - "description": "Allows an app to read your organization's threat assessment requests on behalf of the signed-in user. Also allows the app to create new requests to assess threats received by your organization on behalf of the signed-in user.", - "displayName": "Read and write threat assessment requests", - "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read your organization's threat assessment requests on your behalf. Also allows the app to create new requests to assess threats received by your organization on your behalf.", - "userConsentDisplayName": "Read and write threat assessment requests", - "value": "ThreatAssessment.ReadWrite.All" - }, - { - "description": "Allows the app to read schedule, schedule groups, shifts and associated entities in the Teams or Shifts application on behalf of the signed-in user.", - "displayName": "Read user schedule items", - "id": "fccf6dd8-5706-49fa-811f-69e2e1b585d0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read schedule, schedule groups, shifts and associated entities in the Teams or Shifts application on your behalf.", - "userConsentDisplayName": "Read your schedule items", - "value": "Schedule.Read.All" - }, - { - "description": "Allows the app to manage schedule, schedule groups, shifts and associated entities in the Teams or Shifts application on behalf of the signed-in user.", - "displayName": "Read and write user schedule items", - "id": "63f27281-c9d9-4f29-94dd-6942f7f1feb0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage schedule, schedule groups, shifts and associated entities in the Teams or Shifts application on your behalf.", - "userConsentDisplayName": "Read and write your schedule items", - "value": "Schedule.ReadWrite.All" - }, - { - "description": " Allows the app to read and write authentication methods of all users in your organization that the signed-in user has access to. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", - "displayName": "Read and write all users' authentication methods.", - "id": "b7887744-6746-4312-813d-72daeaee7e2d", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write authentication methods of all users you have access to in your organization. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", - "userConsentDisplayName": "Read and write all users' authentication methods", - "value": "UserAuthenticationMethod.ReadWrite.All" - }, - { - "description": "Allows the app to read and write the signed-in user's authentication methods, including phone numbers and Authenticator app settings. This does not allow the app to see secret information like the signed-in user's passwords, or to sign-in or otherwise use the signed-in user's authentication methods. ", - "displayName": "Read and write user authentication methods", - "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your authentication methods, including phone numbers and Authenticator app settings.This does not allow the app to see secret information like your passwords, or to sign-in or otherwise use your authentication methods.", - "userConsentDisplayName": "Read and write your authentication methods", - "value": "UserAuthenticationMethod.ReadWrite" - }, - { - "description": "Allows the app to read authentication methods of all users in your organization that the signed-in user has access to. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", - "displayName": "Read all users' authentication methods", - "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read authentication methods of all users you have access to in your organization. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", - "userConsentDisplayName": "Read all users' authentication methods", - "value": "UserAuthenticationMethod.Read.All" - }, - { - "description": "Allows the app to read the signed-in user's authentication methods, including phone numbers and Authenticator app settings. This does not allow the app to see secret information like the signed-in user's passwords, or to sign-in or otherwise use the signed-in user's authentication methods.", - "displayName": "Read user authentication methods.", - "id": "1f6b61c5-2f65-4135-9c9f-31c0f8d32b52", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your authentication methods, including phone numbers and Authenticator app settings. This does not allow the app to see secret information like your passwords, or to sign-in or otherwise use your authentication methods.", - "userConsentDisplayName": "Read your authentication methods.", - "value": "UserAuthenticationMethod.Read" - }, - { - "description": "Allows the app to create tabs in any team in Microsoft Teams, on behalf of the signed-in user. This does not grant the ability to read, modify or delete tabs after they are created, or give access to the content inside the tabs.", - "displayName": "Create tabs in Microsoft Teams.", - "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create tabs in any team in Microsoft Teams, on your behalf. This does not grant the ability to read, modify or delete tabs after they are created, or give access to the content inside the tabs.", - "userConsentDisplayName": "Create tabs in Microsoft Teams.", - "value": "TeamsTab.Create" - }, - { - "description": "Read the names and settings of tabs inside any team in Microsoft Teams, on behalf of the signed-in user. This does not give access to the content inside the tabs.", - "displayName": "Read tabs in Microsoft Teams.", - "id": "59dacb05-e88d-4c13-a684-59f1afc8cc98", - "Origin": "Delegated", - "userConsentDescription": "Read the names and settings of tabs inside any team in Microsoft Teams, on your behalf. This does not give access to the content inside the tabs.", - "userConsentDisplayName": "Read tabs in Microsoft Teams.", - "value": "TeamsTab.Read.All" - }, - { - "description": "Read and write tabs in any team in Microsoft Teams, on behalf of the signed-in user. This does not give access to the content inside the tabs.", - "displayName": "Read and write tabs in Microsoft Teams.", - "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", - "Origin": "Delegated", - "userConsentDescription": "Read and write tabs in any team in Microsoft Teams, on your behalf. This does not give access to the content inside the tabs.", - "userConsentDisplayName": "Read and write tabs in Microsoft Teams.", - "value": "TeamsTab.ReadWrite.All" - }, - { - "description": "Allows the app to have the same access to mailboxes as the signed-in user via IMAP protocol.", - "displayName": "Read and write access to mailboxes via IMAP.", - "id": "652390e4-393a-48de-9484-05f9b1212954", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create and delete email in your mailbox. Does not include permission to send mail.", - "userConsentDisplayName": "Read and write access to your mail.", - "value": "IMAP.AccessAsUser.All" - }, - { - "description": "Allows the app to have the same access to mailboxes as the signed-in user via POP protocol.", - "displayName": "Read and write access to mailboxes via POP.", - "id": "d7b7f2d9-0f45-4ea1-9d42-e50810c06991", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update, create and delete email in your mailbox. Does not include permission to send mail.", - "userConsentDisplayName": "Read and write access to your mail.", - "value": "POP.AccessAsUser.All" - }, - { - "description": "Allows the app to be able to send emails from the user\u2019s mailbox using the SMTP AUTH client submission protocol.", - "displayName": "Send emails from mailboxes using SMTP AUTH.", - "id": "258f6531-6087-4cc4-bb90-092c5fb3ed3f", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to send emails on your behalf from your mailbox.", - "userConsentDisplayName": "Access to sending emails from your mailbox.", - "value": "SMTP.Send" - }, - { - "description": "Allows the app to read all domain properties on behalf of the signed-in user.", - "displayName": "Read domains.", - "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all domain properties on your behalf.", - "userConsentDisplayName": "Read domains.", - "value": "Domain.Read.All" - }, - { - "description": "Allows the app to read and write all domain properties on behalf of the signed-in user. Also allows the app to add, verify and remove domains.", - "displayName": "Read and write domains", - "id": "0b5d694c-a244-4bde-86e6-eb5cd07730fe", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write all domain properties on your behalf. Also allows the app to add, verify and remove domains.", - "userConsentDisplayName": "Read and write domains", - "value": "Domain.ReadWrite.All" - }, - { - "description": "Allows the app to read and write your organization's application configuration policies on behalf of the signed-in user. This includes policies such as activityBasedTimeoutPolicy, claimsMappingPolicy, homeRealmDiscoveryPolicy, tokenIssuancePolicy and tokenLifetimePolicy.", - "displayName": "Read and write your organization's application configuration policies", - "id": "b27add92-efb2-4f16-84f5-8108ba77985c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's application configuration policies on your behalf. This includes policies such as activityBasedTimeoutPolicy, claimsMappingPolicy, homeRealmDiscoveryPolicy, tokenIssuancePolicy and tokenLifetimePolicy.", - "userConsentDisplayName": "Read and write your organization's application configuration policies", - "value": "Policy.ReadWrite.ApplicationConfiguration" - }, - { - "description": "Allows the app to read your organization's devices' configuration information on behalf of the signed-in user.", - "displayName": "Read all devices", - "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read devices' configuration information on your behalf.", - "userConsentDisplayName": "Read all devices", - "value": "Device.Read.All" - }, - { - "description": "Allows the app to read, update and delete identities that are associated with a user's account that the signed-in user has access to. This controls the identities users can sign-in with.", - "displayName": "Manage user identities", - "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, update and delete identities that are associated with a user's account that you have access to. This controls the identities users can sign-in with.", - "userConsentDisplayName": "Manage user identities", - "value": "User.ManageIdentities.All" - }, - { - "description": "Allows the app to read access packages and related entitlement management resources on behalf of the signed-in user.", - "displayName": "Read all entitlement management resources", - "id": "5449aa12-1393-4ea2-a7c7-d0e06c1a56b2", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read access packages and related entitlement management resources that you have access to.", - "userConsentDisplayName": "Read all entitlement management resources", - "value": "EntitlementManagement.Read.All" - }, - { - "description": "Create channels in any team, on behalf of the signed-in user.", - "displayName": "Create channels", - "id": "101147cf-4178-4455-9d58-02b5c164e759", - "Origin": "Delegated", - "userConsentDescription": "Create channels in any team, on your behalf.", - "userConsentDisplayName": "Create channels", - "value": "Channel.Create" - }, - { - "description": "Delete channels in any team, on behalf of the signed-in user.", - "displayName": "Delete channels", - "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", - "Origin": "Delegated", - "userConsentDescription": "Delete channels in any team, on your behalf.", - "userConsentDisplayName": "Delete channels", - "value": "Channel.Delete.All" - }, - { - "description": "Read all channel names, channel descriptions, and channel settings, on behalf of the signed-in user.", - "displayName": "Read the names, descriptions, and settings of channels", - "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", - "Origin": "Delegated", - "userConsentDescription": "Read all channel names, channel descriptions, and channel settings, on your behalf.", - "userConsentDisplayName": "Read the names, descriptions, and settings of channels", - "value": "ChannelSettings.Read.All" - }, - { - "description": "Read and write the names, descriptions, and settings of all channels, on behalf of the signed-in user.", - "displayName": "Read and write the names, descriptions, and settings of channels", - "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", - "Origin": "Delegated", - "userConsentDescription": "Read and write the names, descriptions, and settings of all channels, on your behalf.", - "userConsentDisplayName": "Read and write the names, descriptions, and settings of channels", - "value": "ChannelSettings.ReadWrite.All" - }, - { - "description": "Allows the app to read all webhook subscriptions on behalf of the signed-in user.", - "displayName": "Read all webhook subscriptions ", - "id": "5f88184c-80bb-4d52-9ff2-757288b2e9b7", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all webhook subscriptions on your behalf.", - "userConsentDisplayName": "Read all webhook subscriptions ", - "value": "Subscription.Read.All" - }, - { - "description": "Read the names and descriptions of teams, on behalf of the signed-in user.", - "displayName": "Read the names and descriptions of teams", - "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", - "Origin": "Delegated", - "userConsentDescription": "Read the names and descriptions of teams, on your behalf.", - "userConsentDisplayName": "Read the names and descriptions of teams", - "value": "Team.ReadBasic.All" - }, - { - "description": "Read channel names and channel descriptions, on behalf of the signed-in user.", - "displayName": "Read the names and descriptions of channels", - "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", - "Origin": "Delegated", - "userConsentDescription": "Read channel names and channel descriptions, on your behalf.", - "userConsentDisplayName": "Read the names and descriptions of channels", - "value": "Channel.ReadBasic.All" - }, - { - "description": "Read all teams' settings, on behalf of the signed-in user.", - "displayName": "Read teams' settings", - "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", - "Origin": "Delegated", - "userConsentDescription": "Read all teams' settings, on your behalf.", - "userConsentDisplayName": "Read teams' settings", - "value": "TeamSettings.Read.All" - }, - { - "description": "Read and change all teams' settings, on behalf of the signed-in user.", - "displayName": "Read and change teams' settings", - "id": "39d65650-9d3e-4223-80db-a335590d027e", - "Origin": "Delegated", - "userConsentDescription": "Read and change all teams' settings, on your behalf.", - "userConsentDisplayName": "Read and change teams' settings", - "value": "TeamSettings.ReadWrite.All" - }, - { - "description": "Read the members of teams, on behalf of the signed-in user.", - "displayName": "Read the members of teams", - "id": "2497278c-d82d-46a2-b1ce-39d4cdde5570", - "Origin": "Delegated", - "userConsentDescription": "Read the members of teams, on your behalf.", - "userConsentDisplayName": "Read the members of teams", - "value": "TeamMember.Read.All" - }, - { - "description": "Add and remove members from teams, on behalf of the signed-in user. Also allows changing a member's role, for example from owner to non-owner.", - "displayName": "Add and remove members from teams", - "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", - "Origin": "Delegated", - "userConsentDescription": "Add and remove members from teams, on your behalf. Also allows changing a member's role, for example from owner to non-owner.", - "userConsentDisplayName": "Add and remove members from teams and channels", - "value": "TeamMember.ReadWrite.All" - }, - { - "description": "Allows the app to read consent requests and approvals on behalf of the signed-in user.", - "displayName": "Read consent requests", - "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read consent requests and approvals, on your behalf.", - "userConsentDisplayName": "Read consent requests", - "value": "ConsentRequest.Read.All" - }, - { - "description": "Allows the app to read app consent requests and approvals, and deny or approve those requests on behalf of the signed-in user.", - "displayName": "Read and write consent requests", - "id": "497d9dfa-3bd1-481a-baab-90895e54568c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read app consent requests for your approval, and deny or approve those request on your behalf.", - "userConsentDisplayName": "Read and write consent requests", - "value": "ConsentRequest.ReadWrite.All" - }, - { - "description": "Allows the app to read and write your organization's consent requests policy on behalf of the signed-in user.", - "displayName": "Read and write consent request policy", - "id": "4d135e65-66b8-41a8-9f8b-081452c91774", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's consent request policy on your behalf.", - "userConsentDisplayName": "Read and write consent request policy", - "value": "Policy.ReadWrite.ConsentRequest" - }, - { - "description": "Allows the app to read presence information on behalf of the signed-in user. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", - "displayName": "Read user's presence information", - "id": "76bc735e-aecd-4a1d-8b4c-2b915deabb79", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your presence information on your behalf. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", - "userConsentDisplayName": "Read your presence information", - "value": "Presence.Read" - }, - { - "description": "Allows the app to read presence information of all users in the directory on behalf of the signed-in user. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", - "displayName": "Read presence information of all users in your organization", - "id": "9c7a330d-35b3-4aa1-963d-cb2b9f927841", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read presence information of all users in the directory on your behalf. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", - "userConsentDisplayName": "Read presence information of all users in your organization", - "value": "Presence.Read.All" - }, - { - "description": "Read the members of channels, on behalf of the signed-in user.", - "displayName": "Read the members of channels", - "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", - "Origin": "Delegated", - "userConsentDescription": "Read the members of channels, on your behalf.", - "userConsentDisplayName": "Read the members of teams and channels", - "value": "ChannelMember.Read.All" - }, - { - "description": "Add and remove members from channels, on behalf of the signed-in user. Also allows changing a member's role, for example from owner to non-owner.", - "displayName": "Add and remove members from channels", - "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", - "Origin": "Delegated", - "userConsentDescription": "Add and remove members from channels, on your behalf. Also allows changing a member's role, for example from owner to non-owner.", - "userConsentDisplayName": "Add and remove members from teams and channels", - "value": "ChannelMember.ReadWrite.All" - }, - { - "description": "Allows the app to read and write the authentication flow policies, on behalf of the signed-in user. ", - "displayName": "Read and write authentication flow policies", - "id": "edb72de9-4252-4d03-a925-451deef99db7", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the authentication flow policies for your tenant, on your behalf.", - "userConsentDisplayName": "Read and write your authentication flow policies", - "value": "Policy.ReadWrite.AuthenticationFlows" - }, - { - "description": "Allows an app to read a channel's messages in Microsoft Teams, on behalf of the signed-in user.", - "displayName": "Read user channel messages", - "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read a channel's messages in Microsoft Teams, on your behalf.", - "userConsentDisplayName": "Read your channel messages", - "value": "ChannelMessage.Read.All" - }, - { - "description": "Allows the app to read the apps in the app catalogs.", - "displayName": "Read all app catalogs", - "id": "88e58d74-d3df-44f3-ad47-e89edf4472e4", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read apps in the app catalogs.", - "userConsentDisplayName": "Read all app catalogs", - "value": "AppCatalog.Read.All" - }, - { - "description": "Allows the app to read and write the authentication method policies, on behalf of the signed-in user.\u00a0", - "displayName": "Read and write authentication method policies", - "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the authentication method policies for your tenant, on your behalf.", - "userConsentDisplayName": "Read and write your authentication method policies ", - "value": "Policy.ReadWrite.AuthenticationMethod" - }, - { - "description": "Allows the app to read and write your organization's authorization policy on behalf of the signed-in user. For example, authorization policies can control some of the permissions that the out-of-the-box user role has by default.", - "displayName": "Read and write your organization's authorization policy", - "id": "edd3c878-b384-41fd-95ad-e7407dd775be", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's authorization policy on your behalf. For example, authorization policies can control some of the permissions that the out-of-the-box user role has by default.", - "userConsentDisplayName": "Read and write your organization's authorization policy", - "value": "Policy.ReadWrite.Authorization" - }, - { - "description": "Allows the app to read policies related to consent and permission grants for applications, on behalf of the signed-in user.", - "displayName": "Read consent and permission grant policies", - "id": "414de6ea-2d92-462f-b120-6e2a809a6d01", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read policies related to consent and permission grants for applications, on your behalf.", - "userConsentDisplayName": "Read consent and permission grant policies", - "value": "Policy.Read.PermissionGrant" - }, - { - "description": "Allows the app to manage policies related to consent and permission grants for applications, on behalf of the signed-in user.", - "displayName": "Manage consent and permission grant policies", - "id": "2672f8bb-fd5e-42e0-85e1-ec764dd2614e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage policies related to consent and permission grants for applications, on behalf of the signed-in user.", - "userConsentDisplayName": "Manage consent and permission grant policies", - "value": "Policy.ReadWrite.PermissionGrant" - }, - { - "description": "Allows the application to create (register) printers on behalf of the signed-in user.\u00a0", - "displayName": "Register printers\u202f\u00a0", - "id": "90c30bed-6fd1-4279-bf39-714069619721", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to create (register) printers on your behalf.\u00a0", - "userConsentDisplayName": "Register printers\u202f\u00a0", - "value": "Printer.Create" - }, - { - "description": "Allows the application to create (register), read, update, and delete (unregister) printers on behalf of the signed-in user.\u00a0", - "displayName": "Register, read, update, and unregister printers", - "id": "93dae4bd-43a1-4a23-9a1a-92957e1d9121", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to create (register), read, update, and delete (unregister) printers on your behalf.\u00a0\u00a0", - "userConsentDisplayName": "Register, read, update, and unregister printers", - "value": "Printer.FullControl.All" - }, - { - "description": "Allows the application to read printers on behalf of the signed-in user.\u00a0", - "displayName": "Read printers", - "id": "3a736c8a-018e-460a-b60c-863b2683e8bf", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read printers on your behalf.\u00a0", - "userConsentDisplayName": "Read printers", - "value": "Printer.Read.All" - }, - { - "description": "Allows the application to read and update printers on behalf of the signed-in user.\u00a0Does not allow creating (registering) or deleting (unregistering) printers.", - "displayName": "Read and update printers", - "id": "89f66824-725f-4b8f-928e-e1c5258dc565", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and update printers on your behalf.\u00a0Does not allow creating (registering) or deleting (unregistering) printers.", - "userConsentDisplayName": "Read and update printers", - "value": "Printer.ReadWrite.All" - }, - { - "description": "Allows the application to read printer shares on behalf of the signed-in user.\u00a0", - "displayName": "Read printer shares", - "id": "ed11134d-2f3f-440d-a2e1-411efada2502", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read printer shares on your behalf.\u00a0", - "userConsentDisplayName": "Read printer shares", - "value": "PrinterShare.Read.All" - }, - { - "description": "Allows the application to read and update printer shares on behalf of the signed-in user.\u00a0", - "displayName": "Read and write printer shares", - "id": "06ceea37-85e2-40d7-bec3-91337a46038f", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and update printer shares on your behalf.\u00a0", - "userConsentDisplayName": "Read and update printer shares", - "value": "PrinterShare.ReadWrite.All" - }, - { - "description": "Allows the application to read the metadata and document content of print jobs that the signed-in user created.", - "displayName": "Read user's print jobs", - "id": "248f5528-65c0-4c88-8326-876c7236df5e", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read the metadata and document content of print jobs that you created.", - "userConsentDisplayName": "Read your print jobs", - "value": "PrintJob.Read" - }, - { - "description": "Allows the application to read the metadata and document content of print jobs on behalf of the signed-in user.\u00a0", - "displayName": "Read print jobs", - "id": "afdd6933-a0d8-40f7-bd1a-b5d778e8624b", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read the metadata and document content of print jobs on your behalf.\u00a0", - "userConsentDisplayName": "Read print jobs", - "value": "PrintJob.Read.All" - }, - { - "description": "Allows the application to read the metadata of print jobs that the signed-in user created. Does not allow access to print job document content.", - "displayName": "Read basic information of user's print jobs", - "id": "6a71a747-280f-4670-9ca0-a9cbf882b274", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read the metadata of print jobs that you created. Does not allow access to print job document content.", - "userConsentDisplayName": "Read basic information of your print jobs", - "value": "PrintJob.ReadBasic" - }, - { - "description": "Allows the application to read the metadata of print jobs on behalf of the signed-in user.\u00a0Does not allow access to print job document content.", - "displayName": "Read basic information of print jobs", - "id": "04ce8d60-72ce-4867-85cf-6d82f36922f3", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read the metadata of print jobs on your behalf.\u00a0Does not allow access to print job document content.", - "userConsentDisplayName": "Read basic information of print jobs", - "value": "PrintJob.ReadBasic.All" - }, - { - "description": "Allows the application to read and update the metadata and document content of print jobs that the signed-in user created.", - "displayName": "Read and write user's print jobs", - "id": "b81dd597-8abb-4b3f-a07a-820b0316ed04", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and update the metadata and document content of print jobs that you created.", - "userConsentDisplayName": "Read and update your print jobs", - "value": "PrintJob.ReadWrite" - }, - { - "description": "Allows the application to read and update the metadata and document content of print jobs on behalf of the signed-in user.\u00a0", - "displayName": "Read and write print jobs", - "id": "036b9544-e8c5-46ef-900a-0646cc42b271", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and update the metadata and document content of print jobs on your behalf.\u00a0", - "userConsentDisplayName": "Read and update print jobs", - "value": "PrintJob.ReadWrite.All" - }, - { - "description": "Allows the application to read and update the metadata of print jobs that the signed-in user created. Does not allow access to print job document content.", - "displayName": "Read and write basic information of user's print jobs", - "id": "6f2d22f2-1cb6-412c-a17c-3336817eaa82", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and update the metadata of print jobs that you created. Does not allow access to print job document content.", - "userConsentDisplayName": "Read and write basic information of your print jobs", - "value": "PrintJob.ReadWriteBasic" - }, - { - "description": "Allows the application to read and update the metadata of print jobs on behalf of the signed-in user.\u00a0Does not allow access to print job document content.", - "displayName": "Read and write basic information of print jobs", - "id": "3a0db2f6-0d2a-4c19-971b-49109b19ad3d", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and update the metadata of print jobs on your behalf.\u00a0Does not allow access to print job document content.", - "userConsentDisplayName": "Read and write basic information of print jobs", - "value": "PrintJob.ReadWriteBasic.All" - }, - { - "description": "Allows the app to read and write your organization's device configuration policies on behalf of the signed-in user. For example, device registration policy can limit initial provisioning controls using quota restrictions, additional authentication and authorization checks.", - "displayName": "Read and write your organization's device configuration policies", - "id": "40b534c3-9552-4550-901b-23879c90bcf9", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write your organization's device configuration policies on your behalf. For example, device registration policy can limit initial provisioning controls using quota restrictions, additional authentication and authorization checks.", - "userConsentDisplayName": "Read and write your organization's device configuration policies", - "value": "Policy.ReadWrite.DeviceConfiguration" - }, - { - "description": "Allows the app to submit application packages to the catalog and cancel submissions that are pending review on behalf of the signed-in user.", - "displayName": "Submit application packages to the catalog and cancel pending submissions", - "id": "3db89e36-7fa6-4012-b281-85f3d9d9fd2e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to submit application packages to the catalog and cancel submissions that are pending review on your behalf.", - "userConsentDisplayName": "Submit application packages to your organization's catalog and cancel pending submissions", - "value": "AppCatalog.Submit" - }, - { - "description": "Allows the app to read the Teams apps that are installed in chats the signed-in user can access. Does not give the ability to read application-specific settings.", - "displayName": "Read installed Teams apps in chats", - "id": "bf3fbf03-f35f-4e93-963e-47e4d874c37a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the Teams apps that are installed in chats that you can access. Does not give the ability to read application-specific settings.", - "userConsentDisplayName": "Read installed Teams apps in chats", - "value": "TeamsAppInstallation.ReadForChat" - }, - { - "description": "Allows the app to read the Teams apps that are installed in teams the signed-in user can access. Does not give the ability to read application-specific settings.", - "displayName": "Read installed Teams apps in teams", - "id": "5248dcb1-f83b-4ec3-9f4d-a4428a961a72", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the Teams apps that are installed in teams that you can access. Does not give the ability to read application-specific settings.", - "userConsentDisplayName": "Read installed Teams apps in teams", - "value": "TeamsAppInstallation.ReadForTeam" - }, - { - "description": "Allows the app to read the Teams apps that are installed for the signed-in user. Does not give the ability to read application-specific settings.", - "displayName": "Read user's installed Teams apps", - "id": "c395395c-ff9a-4dba-bc1f-8372ba9dca84", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the Teams apps that are installed for you. Does not give the ability to read application-specific settings.", - "userConsentDisplayName": "Read your installed Teams apps", - "value": "TeamsAppInstallation.ReadForUser" - }, - { - "description": "Allows the app to read, install, upgrade, and uninstall Teams apps in teams the signed-in user can access. Does not give the ability to read application-specific settings.", - "displayName": "Manage installed Teams apps in teams", - "id": "2e25a044-2580-450d-8859-42eeb6e996c0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, install, upgrade, and uninstall Teams apps in teams you can access. Does not give the ability to read application-specific settings.", - "userConsentDisplayName": "Manage installed Teams apps in teams", - "value": "TeamsAppInstallation.ReadWriteForTeam" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall itself in chats the signed-in user can access.", - "displayName": "Allow the Teams app to manage itself in chats", - "id": "0ce33576-30e8-43b7-99e5-62f8569a4002", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall itself in chats you can access.", - "userConsentDisplayName": "Allow the Teams app to manage itself in chats", - "value": "TeamsAppInstallation.ReadWriteSelfForChat" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall itself for the signed-in user.", - "displayName": "Allow the Teams app to manage itself for a user", - "id": "207e0cb1-3ce7-4922-b991-5a760c346ebc", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall itself for you.", - "userConsentDisplayName": "Allow the Teams app to manage itself for you", - "value": "TeamsAppInstallation.ReadWriteSelfForUser" - }, - { - "description": "Allows the app to read, install, upgrade, and uninstall Teams apps installed for the signed-in user. Does not give the ability to read application-specific settings.", - "displayName": "Manage user's installed Teams apps", - "id": "093f8818-d05f-49b8-95bc-9d2a73e9a43c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, install, upgrade, and uninstall Teams apps installed for you. Does not give the ability to read application-specific settings.", - "userConsentDisplayName": "Manage your installed Teams apps", - "value": "TeamsAppInstallation.ReadWriteForUser" - }, - { - "description": "Allows the app to create teams on behalf of the signed-in user.", - "displayName": "Create teams", - "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create teams on your behalf.\u00a0", - "userConsentDisplayName": "Create teams", - "value": "Team.Create" - }, - { - "description": "Add and remove members from all teams, on behalf of the signed-in user. Does not allow adding or removing a member with the owner role. Additionally, does not allow the app to elevate an existing member to the owner role.", - "displayName": "Add and remove members with non-owner role for all teams", - "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", - "Origin": "Delegated", - "userConsentDescription": "Add and remove members from all teams, on your behalf. Does not allow adding or removing a member with the owner role. Additionally, does not allow the app to elevate an existing member to the owner role.", - "userConsentDisplayName": "Add and remove members with non-owner role for all teams", - "value": "TeamMember.ReadWriteNonOwnerRole.All" - }, - { - "description": "Allows the app to read the term store data that the signed-in user has access to. This includes all sets, groups and terms in the term store.", - "displayName": "Read term store data", - "id": "297f747b-0005-475b-8fef-c890f5152b38", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the term store data that you have access to. This includes all sets, groups and terms in the term store.", - "userConsentDisplayName": "Read term store data", - "value": "TermStore.Read.All" - }, - { - "description": "Allows the app to read or modify data that the signed-in user has access to.\u00a0This includes all sets, groups and terms in the term store.", - "displayName": "Read and write term store data", - "id": "6c37c71d-f50f-4bff-8fd3-8a41da390140", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read or modify data that you have access to. This includes all sets, groups and terms in the term store.", - "userConsentDisplayName": "Read and write term store data", - "value": "TermStore.ReadWrite.All" - }, - { - "description": "Allows the app to read your tenant's service announcement messages on behalf of the signed-in user. Messages may include information about new or changed features.", - "displayName": "Read service announcement messages", - "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your tenant's service announcement messages on your behalf. Messages may include information about new or changed features.", - "userConsentDisplayName": "Read service messages", - "value": "ServiceMessage.Read.All" - }, - { - "description": "Allows the app to read your tenant's service health information on behalf of the signed-in user. Health information may include service issues or service health overviews.", - "displayName": "Read service health", - "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your tenant's service health information on your behalf.Health information may include service issues or service health overviews.", - "userConsentDisplayName": "Read service health", - "value": "ServiceHealth.Read.All" - }, - { - "description": "Allows the app to read all the short notes a sign-in user has access to.", - "displayName": "Read short notes of the signed-in user", - "id": "50f66e47-eb56-45b7-aaa2-75057d9afe08", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your short notes.", - "userConsentDisplayName": "Read your short notes", - "value": "ShortNotes.Read" - }, - { - "description": "Allows the app to read, create, edit, and delete short notes of a signed-in user.", - "displayName": "Read, create, edit, and delete short notes of the signed-in user", - "id": "328438b7-4c01-4c07-a840-e625a749bb89", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, create, edit, and delete your short notes.", - "userConsentDisplayName": "Read, create, edit, and delete your short notes", - "value": "ShortNotes.ReadWrite" - }, - { - "description": "Allows the app to read your organization's conditional access policies on behalf of the signed-in user.", - "displayName": "Read your organization's conditional access policies", - "id": "633e0fce-8c58-4cfb-9495-12bbd5a24f7c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization's conditional access policies on your behalf.", - "userConsentDisplayName": "Read your organization's conditional access policies", - "value": "Policy.Read.ConditionalAccess" - }, - { - "description": "Allows the app to read the role-based access control (RBAC) settings for all RBAC providers, on behalf of the signed-in user. This includes reading role definitions and role assignments.", - "displayName": "Read role management data for all RBAC providers", - "id": "48fec646-b2ba-4019-8681-8eb31435aded", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the role-based access control (RBAC) settings for all RBAC providers, on your behalf. This includes reading role definitions and role assignments.", - "userConsentDisplayName": "Read role management data for all RBAC providers", - "value": "RoleManagement.Read.All" - }, - { - "description": "Allows an app to send one-to-one and group chat messages in Microsoft Teams, on behalf of the signed-in user.", - "displayName": "Send user chat messages", - "id": "116b7235-7cc6-461e-b163-8e55691d839e", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to send one-to-one and group chat messages in Microsoft Teams, on your behalf.", - "userConsentDisplayName": "Send chat messages", - "value": "ChatMessage.Send" - }, - { - "description": "Allows an app to read the members and descriptions of one-to-one and group chat threads, on behalf of the signed-in user.", - "displayName": "Read names and members of user chat threads", - "id": "9547fcb5-d03f-419d-9948-5928bbf71b0f", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read the members and descriptions of one-to-one and group chat threads, on your behalf.", - "userConsentDisplayName": "Read names and members of your chat threads", - "value": "Chat.ReadBasic" - }, - { - "description": "Allows the app to read and write the properties of Cloud PCs on behalf of the signed-in user.", - "displayName": "Read and write Cloud PCs", - "id": "9d77138f-f0e2-47ba-ab33-cd246c8b79d1", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the properties of Cloud PCs, on your behalf.", - "userConsentDisplayName": "Read and write Cloud PCs", - "value": "CloudPC.ReadWrite.All" - }, - { - "description": "Allows the app to read the properties of Cloud PCs on behalf of the signed-in user.", - "displayName": "Read Cloud PCs", - "id": "5252ec4e-fd40-4d92-8c68-89dd1d3c6110", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the properties of Cloud PCs, on your behalf.", - "userConsentDisplayName": "Read Cloud PCs", - "value": "CloudPC.Read.All" - }, - { - "description": "Allows the app to read, install, upgrade, and uninstall Teams apps in chats the signed-in user can access. Does not give the ability to read application-specific settings.", - "displayName": "Manage installed Teams apps in chats", - "id": "aa85bf13-d771-4d5d-a9e6-bca04ce44edf", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, install, upgrade, and uninstall Teams apps in chats you can access. Does not give the ability to read application-specific settings.", - "userConsentDisplayName": "Manage installed Teams apps in chats", - "value": "TeamsAppInstallation.ReadWriteForChat" - }, - { - "description": "Allows the app to create, read, update, and delete the signed-in user's tasks and task lists, including any shared with the user.", - "displayName": "Create, read, update, and delete user\u2019s tasks and task lists", - "id": "2219042f-cab5-40cc-b0d2-16b1540b4c5f", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create, read, update, and delete your tasks and task lists, including any shared with you.", - "userConsentDisplayName": "Create, read, update, and delete your tasks and task lists", - "value": "Tasks.ReadWrite" - }, - { - "description": "Allows the app to read the signed-in user\u2019s tasks and task lists, including any shared with the user. Doesn't include permission to create, delete, or update anything.", - "displayName": "Read user's tasks and task lists", - "id": "f45671fb-e0fe-4b4b-be20-3d3ce43f1bcb", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your tasks and task lists, including any shared with you. Doesn't include permission to create, delete, or update anything.", - "userConsentDisplayName": "Read your tasks and task lists", - "value": "Tasks.Read" - }, - { - "description": "Allows an app to read one-to-one and group chat messages, on behalf of the signed-in user.", - "displayName": "Read user chat messages", - "id": "cdcdac3a-fd45-410d-83ef-554db620e5c7", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read one-to-one or group chat messages in Microsoft Teams, on your behalf.", - "userConsentDisplayName": "Read user chat messages", - "value": "ChatMessage.Read" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs in chats the signed-in user can access.", - "displayName": "Allow the Teams app to manage all tabs in chats", - "id": "ee928332-e9c2-4747-b4a0-f8c164b68de6", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall all tabs in chats you can access.", - "userConsentDisplayName": "Allow the Teams app to manage all tabs in chats", - "value": "TeamsTab.ReadWriteForChat" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs to teams the signed-in user can access.", - "displayName": "Allow the Teams app to manage all tabs in teams", - "id": "c975dd04-a06e-4fbb-9704-62daad77bb49", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall all tabs to teams you can access.", - "userConsentDisplayName": "Allow the app to manage all tabs in teams", - "value": "TeamsTab.ReadWriteForTeam" - }, - { - "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs for the signed-in user.", - "displayName": "Allow the Teams app to manage all tabs for a user", - "id": "c37c9b61-7762-4bff-a156-afc0005847a0", - "Origin": "Delegated", - "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall all tabs for you.", - "userConsentDisplayName": "Allow the Teams app to manage all tabs for you", - "value": "TeamsTab.ReadWriteForUser" - }, - { - "description": "Allows the app to read the API connectors used in user authentication flows, on behalf of the signed-in user.", - "displayName": "Read API connectors for authentication flows", - "id": "1b6ff35f-31df-4332-8571-d31ea5a4893f", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the API connectors used in user authentication flows, on your behalf.", - "userConsentDisplayName": "Read API connectors for authentication flows", - "value": "APIConnectors.Read.All" - }, - { - "description": "Allows the app to read, create and manage the API connectors used in user authentication flows, on behalf of the signed-in user.", - "displayName": "Read and write API connectors for authentication flows", - "id": "c67b52c5-7c69-48b6-9d48-7b3af3ded914", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read, create and manage the API connectors used in user authentication flows, on your behalf.", - "userConsentDisplayName": "Read and write API connectors for authentication flows", - "value": "APIConnectors.ReadWrite.All" - }, - { - "description": "Read the members of chats, on behalf of the signed-in user.", - "displayName": "Read the members of chats", - "id": "c5a9e2b1-faf6-41d4-8875-d381aa549b24", - "Origin": "Delegated", - "userConsentDescription": "Read the members of chats, on your behalf.", - "userConsentDisplayName": "Read the members of chats", - "value": "ChatMember.Read" - }, - { - "description": "Add and remove members from chats, on behalf of the signed-in user.", - "displayName": "Add and remove members from chats", - "id": "dea13482-7ea6-488f-8b98-eb5bbecf033d", - "Origin": "Delegated", - "userConsentDescription": "Add and remove members from chats, on your behalf.", - "userConsentDisplayName": "Add and remove members from chats", - "value": "ChatMember.ReadWrite" - }, - { - "description": "Allows the app to create chats on behalf of the signed-in user.", - "displayName": "Create chats", - "id": "38826093-1258-4dea-98f0-00003be2b8d0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create chats on your behalf.\u00a0", - "userConsentDisplayName": "Create chats", - "value": "Chat.Create" - }, - { - "description": "Allows the application to read and write tenant-wide print settings on behalf of the signed-in user.", - "displayName": "Read and write tenant-wide print settings", - "id": "9ccc526a-c51c-4e5c-a1fd-74726ef50b8f", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and write tenant-wide print settings on your behalf.", - "userConsentDisplayName": "Read and write tenant-wide print settings", - "value": "PrintSettings.ReadWrite.All" - }, - { - "description": "Allows the application to read tenant-wide print settings on behalf of the signed-in user.", - "displayName": "Read tenant-wide print settings", - "id": "490f32fd-d90f-4dd7-a601-ff6cdc1a3f6c", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read tenant-wide print settings on your behalf.", - "userConsentDisplayName": "Read tenant-wide print settings", - "value": "PrintSettings.Read.All" - }, - { - "description": "Allows the application to read and write print connectors on behalf of the signed-in user. ", - "displayName": "Read and write print connectors", - "id": "79ef9967-7d59-4213-9c64-4b10687637d8", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and write print connectors on your behalf.", - "userConsentDisplayName": "Read and write print connectors", - "value": "PrintConnector.ReadWrite.All" - }, - { - "description": "Allows the application to read print connectors on behalf of the signed-in user.", - "displayName": "Read print connectors", - "id": "d69c2d6d-4f72-4f99-a6b9-663e32f8cf68", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read print connectors on your behalf.", - "userConsentDisplayName": "Read print connectors", - "value": "PrintConnector.Read.All" - }, - { - "description": "Allows the application to read basic information about printer shares on behalf of the signed-in user. Does not allow reading access control information.", - "displayName": "Read basic information about printer shares", - "id": "5fa075e9-b951-4165-947b-c63396ff0a37", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read basic information about printer shares on your behalf.", - "userConsentDisplayName": "Read basic information about printer shares", - "value": "PrinterShare.ReadBasic.All" - }, - { - "description": "Allows the application to create print jobs on behalf of the signed-in user and upload document content to print jobs that the signed-in user created.", - "displayName": "Create print jobs", - "id": "21f0d9c0-9f13-48b3-94e0-b6b231c7d320", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to create print jobs on your behalf and upload document content to print jobs that you created.", - "userConsentDisplayName": "Create your print jobs", - "value": "PrintJob.Create" - }, - { - "description": "Allows the app to read Azure AD recommendations, on behalf of the signed-in user.", - "displayName": "Read Azure AD recommendations", - "id": "34d3bd24-f6a6-468c-b67c-0c365c1d6410", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read Azure AD recommendations, on your behalf.", - "userConsentDisplayName": "Read Azure AD recommendations", - "value": "DirectoryRecommendations.Read.All" - }, - { - "description": "Allows the application to list and query user profile information associated with the current tenant on behalf of the signed-in user.\u00a0 It also permits the application to export and remove external user data (e.g. customer content or system-generated logs), associated with the current tenant on behalf of the signed-in user.", - "displayName": "Read shared cross-tenant user profile and export or delete data", - "id": "eed0129d-dc60-4f30-8641-daf337a39ffd", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to list and query shared user profile information associated with the current tenant on your behalf.\u00a0 It also permits the application to export and remove your external user data (e.g. customer content or system-generated logs), associated with the current tenant on your behalf.", - "userConsentDisplayName": "Read shared cross-tenant user profile and export or delete data", - "value": "CrossTenantUserProfileSharing.ReadWrite" - }, - { - "description": "Allows the app to manage restricted resources based on the other permissions granted to the app, on behalf of the signed-in user.", - "displayName": "Manage restricted resources in the directory", - "id": "cba5390f-ed6a-4b7f-b657-0efc2210ed20", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage restricted resources based on the other permissions granted to the app, on your behalf.", - "userConsentDisplayName": "Manage restricted resources in the directory", - "value": "Directory.Write.Restricted" - }, - { - "description": "Allows the app to read your organization's threat submission policies on behalf of the signed-in user. Also allows the app to create new threat submission policies on behalf of the signed-in user.", - "displayName": "Read and write all threat submission policies", - "id": "059e5840-5353-4c68-b1da-666a033fc5e8", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization's threat submission policies on your behalf. Also allows the app to create new threat submission policies on your behalf.", - "userConsentDisplayName": "Read and write all threat submission policies", - "value": "ThreatSubmissionPolicy.ReadWrite.All" - }, - { - "description": "Allows an app to read the browser site lists configured for your organization, on behalf of the signed-in user.", - "displayName": "Read browser site lists for your organization", - "id": "fb9be2b7-a7fc-4182-aec1-eda4597c43d5", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read the browser site lists configured for your organization, on your behalf.", - "userConsentDisplayName": "Read browser site lists for your organization", - "value": "BrowserSiteLists.Read.All" - }, - { - "description": "Allows the application to list and query any shared user profile information associated with the current tenant on behalf of the signed-in user.\u00a0 It also permits the application to export and remove external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant on behalf of the signed-in user.", - "displayName": "Read all shared cross-tenant user profiles and export or delete their data", - "id": "64dfa325-cbf8-48e3-938d-51224a0cac01", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to list and query any shared user profile information associated with the current tenant on your behalf.\u00a0 It also permits the application to export and remove external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant on your behalf.", - "userConsentDisplayName": "Read any shared cross-tenant user profiles and export or delete data", - "value": "CrossTenantUserProfileSharing.ReadWrite.All" - }, - { - "description": "Allows the app to read the threat submissions and threat submission policies owned by the signed-in user.", - "displayName": "Read threat submissions", - "id": "fd5353c6-26dd-449f-a565-c4e16b9fce78", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the threat submissions and threat submission policies that you own on your behalf.", - "userConsentDisplayName": "Read threat submissions", - "value": "ThreatSubmission.Read" - }, - { - "description": "Allows the app to read the threat submissions and threat submission policies owned by the signed-in user. Also allows the app to create new threat submissions on behalf of the signed-in user.", - "displayName": "Read and write threat submissions", - "id": "68a3156e-46c9-443c-b85c-921397f082b5", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the threat submissions and threat submission policies that you own. Also allows the app to create new threat submissions on your behalf.", - "userConsentDisplayName": "Read and write threat submissions", - "value": "ThreatSubmission.ReadWrite" - }, - { - "description": "Allows the app to read all recordings of online meetings, on behalf of the signed-in user.", - "displayName": "Read all recordings of online meetings.", - "id": "190c2bb6-1fdd-4fec-9aa2-7d571b5e1fe3", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all recordings of online meetings, on your behalf.\u00a0", - "userConsentDisplayName": "Read all recordings of online meetings.\u00a0", - "value": "OnlineMeetingRecording.Read.All" - }, - { - "description": "Allows the application to obtain basic tenant information about another target tenant within the Azure AD ecosystem on behalf of the signed-in user.", - "displayName": "Read cross-tenant basic information", - "id": "81594d25-e88e-49cf-ac8c-fecbff49f994", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to obtain basic tenant information about another target tenant within the Azure AD ecosystem on your behalf.", - "userConsentDisplayName": "Read cross-tenant basic information", - "value": "CrossTenantInformation.ReadBasic.All" - }, - { - "description": "Allows the app to read your organization's authentication event listeners on behalf of the signed-in user.", - "displayName": "Read your organization's authentication event listeners", - "id": "f7dd3bed-5eec-48da-bc73-1c0ef50bc9a1", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization's authentication event listeners on your behalf.", - "userConsentDisplayName": "Read your organization's authentication event listeners", - "value": "EventListener.Read.All" - }, - { - "description": "Allows the app to read the Teams app settings on behalf of the signed-in user.", - "displayName": "Read Teams app settings", - "id": "44e060c4-bbdc-4256-a0b9-dcc0396db368", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the Teams app settings on your behalf.", - "userConsentDisplayName": "Read Teams app settings", - "value": "TeamworkAppSettings.Read.All" - }, - { - "description": "Allows\u00a0the\u00a0app\u00a0to\u00a0manage learning\u00a0content\u00a0in\u00a0the\u00a0organization's\u00a0directory, on behalf of the signed-in user.", - "displayName": "Manage\u00a0learning\u00a0content", - "id": "53cec1c4-a65f-4981-9dc1-ad75dbf1c077", - "Origin": "Delegated", - "userConsentDescription": "Allows\u00a0the\u00a0app\u00a0to\u00a0manage learning\u00a0content\u00a0in\u00a0the\u00a0organization's\u00a0directory, on your behalf.", - "userConsentDisplayName": "Manage learning content", - "value": "LearningContent.ReadWrite.All" - }, - { - "description": "Allows the app to create, update, read, and delete data for the learning provider in the organization's directory, on behalf of the signed-in user.", - "displayName": "Manage\u00a0learning\u00a0provider", - "id": "40c2eb57-abaf-49f5-9331-e90fd01f7130", - "Origin": "Delegated", - "userConsentDescription": "Allows\u00a0the\u00a0app\u00a0to\u00a0create, update, read, and delete\u00a0data\u00a0for\u00a0the learning\u00a0provider\u00a0in\u00a0the organization's\u00a0directory, on your behalf.", - "userConsentDisplayName": "Manage learning provider", - "value": "LearningProvider.ReadWrite" - }, - { - "description": "Allows the app to read the lifecycle information like employeeLeaveDateTime of users in your organization, on behalf of the signed-in user.", - "displayName": "Read all users' lifecycle information", - "id": "ed8d2a04-0374-41f1-aefe-da8ac87ccc87", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read the lifecycle information like employeeLeaveDateTime of users in your organization, on behalf of the signed-in user.", - "userConsentDisplayName": "Read all users' lifecycle information", - "value": "User-LifeCycleInfo.Read.All" - }, - { - "description": "Allows an app to read and write the browser site lists configured for your organization, on behalf of the signed-in user.", - "displayName": "Read and write browser site lists for your organization", - "id": "83b34c85-95bf-497b-a04e-b58eca9d49d0", - "Origin": "Delegated", - "userConsentDescription": "Allows an app to read and write the browser site lists configured for your organization, on your behalf.", - "userConsentDisplayName": "Read and write browser site lists for your organization", - "value": "BrowserSiteLists.ReadWrite.All" - }, - { - "description": "Allows the application to list and query user profile information associated with the current tenant on behalf of the signed-in user.\u00a0 It also permits the application to export external user data (e.g. customer content or system-generated logs), associated with the current tenant on behalf of the signed-in user.", - "displayName": "Read shared cross-tenant user profile and export data", - "id": "cb1ba48f-d22b-4325-a07f-74135a62ee41", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to list and query shared user profile information associated with the current tenant on your behalf.\u00a0 It also permits the application to export your external user data (e.g. customer content or system-generated logs), associated with the current tenant on your behalf.", - "userConsentDisplayName": "Read shared cross-tenant user profile and export data", - "value": "CrossTenantUserProfileSharing.Read" - }, - { - "description": "Allows the app to read admin report settings, such as whether to display concealed information in reports, on behalf of the signed-in user", - "displayName": "Read admin report settings", - "id": "84fac5f4-33a9-4100-aa38-a20c6d29e5e7", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read admin report settings, such as whether to display concealed information in reports, on your behalf.", - "userConsentDisplayName": "Read admin report settings", - "value": "ReportSettings.Read.All" - }, - { - "description": "Allows the app to read and write the lifecycle information like employeeLeaveDateTime of users in your organization, on behalf of the signed-in user.", - "displayName": "Read and write all users' lifecycle information", - "id": "7ee7473e-bd4b-4c9f-987c-bd58481f5fa2", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the lifecycle information like employeeLeaveDateTime of users in your organization, on behalf of the signed-in user.", - "userConsentDisplayName": "Read and write all users' lifecycle information", - "value": "User-LifeCycleInfo.ReadWrite.All" - }, - { - "description": "Allows the app to read and update Azure AD recommendations, on behalf of the signed-in user. ", - "displayName": "Read and update Azure AD recommendations", - "id": "f37235e8-90a0-4189-93e2-e55b53867ccd", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and update Azure AD recommendations, on your behalf.", - "userConsentDisplayName": "Read and update Azure AD recommendations", - "value": "DirectoryRecommendations.ReadWrite.All" - }, - { - "description": "Allows the app to read your organization's threat submissions and threat submission policies on behalf of the signed-in user.", - "displayName": "Read all threat submissions", - "id": "7083913a-4966-44b6-9886-c5822a5fd910", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization's threat submissions and threat submission policies on your behalf.", - "userConsentDisplayName": "Read all threat submissions", - "value": "ThreatSubmission.Read.All" - }, - { - "description": "Allows the app to read learning content in the organization's directory, on behalf of the signed-in user.", - "displayName": "Read learning content", - "id": "ea4c1fd9-6a9f-4432-8e5d-86e06cc0da77", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read learning content in the organization's directory, on your behalf.", - "userConsentDisplayName": "Read learning content", - "value": "LearningContent.Read.All" - }, - { - "description": "Allows the app to read data for the learning provider in the organization's directory, on behalf of the signed-in user.", - "displayName": "Read learning provider", - "id": "dd8ce36f-9245-45ea-a99e-8ac398c22861", - "Origin": "Delegated", - "userConsentDescription": "Allows\u00a0the\u00a0app\u00a0to\u00a0read\u00a0data\u00a0for\u00a0the learning\u00a0provider\u00a0in\u00a0the organization's\u00a0directory, on your behalf.", - "userConsentDisplayName": "Read learning provider", - "value": "LearningProvider.Read" - }, - { - "description": "Allows the app to create, update, list, read and delete all workflows, tasks and related lifecycle workflows resources on behalf of the signed-in user.", - "displayName": "Read and write all lifecycle workflows resources", - "id": "84b9d731-7db8-4454-8c90-fd9e95350179", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to create, update, list, read and delete all workflows, tasks and related lifecycle workflows resources on your behalf.", - "userConsentDisplayName": "Read and write all lifecycle workflows resources", - "value": "LifecycleWorkflows.ReadWrite.All" - }, - { - "description": "Allows an app to read all bookmarks that the signed-in user can access.", - "displayName": "Read all bookmarks that the user can access", - "id": "98b17b35-f3b1-4849-a85f-9f13733002f0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all bookmarks you can access.", - "userConsentDisplayName": "Read all bookmarks that you have access to", - "value": "Bookmark.Read.All" - }, - { - "description": "Allows the application to read and change the tenant-level settings of SharePoint and OneDrive on behalf of the signed-in user.", - "displayName": "Read and change SharePoint and OneDrive tenant settings", - "id": "aa07f155-3612-49b8-a147-6c590df35536", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read and change the tenant-level settings of SharePoint and OneDrive on your behalf.", - "userConsentDisplayName": "Read and change SharePoint and OneDrive tenant settings", - "value": "SharePointTenantSettings.ReadWrite.All" - }, - { - "description": "Allows the app to read or write your organization's authentication event listeners on behalf of the signed-in user.", - "displayName": "Read and write your organization's authentication event listeners", - "id": "d11625a6-fe21-4fc6-8d3d-063eba5525ad", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read or write your organization's authentication event listeners on your behalf.", - "userConsentDisplayName": "Read and write your organization's authentication event listeners", - "value": "EventListener.ReadWrite.All" - }, - { - "description": "Allows the app to read and write the Teams app settings on behalf of the signed-in user.", - "displayName": "Read and write Teams app settings", - "id": "87c556f0-2bd9-4eed-bd74-5dd8af6eaf7e", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write the Teams app settings on your behalf.", - "userConsentDisplayName": "Read and write Teams app settings", - "value": "TeamworkAppSettings.ReadWrite.All" - }, - { - "description": "Allows the app to read all authentication context information in your organization on behalf of the signed-in user.", - "displayName": "Read all authentication context information", - "id": "57b030f1-8c35-469c-b0d9-e4a077debe70", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all authentication context information in your organization on your behalf.", - "userConsentDisplayName": "Read all authentication context information", - "value": "AuthenticationContext.Read.All" - }, - { - "description": "Allows the app to read and update all authentication context information in your organization on behalf of the signed-in user.", - "displayName": "Read and write all authentication context information", - "id": "ba6d575a-1344-4516-b777-1404f5593057", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and update all authentication context information in your organization on your behalf.", - "userConsentDisplayName": "Read and write all authentication context information", - "value": "AuthenticationContext.ReadWrite.All" - }, - { - "description": "Allows the app to read and update admin report settings, such as whether to display concealed information in reports, on behalf of the signed-in user.", - "displayName": "Read and write admin report settings", - "id": "b955410e-7715-4a88-a940-dfd551018df3", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and update admin report settings, such as whether to display concealed information in reports, on your behalf.", - "userConsentDisplayName": "Read and write admin report settings", - "value": "ReportSettings.ReadWrite.All" - }, - { - "description": "Allows the app to list and read all workflows, tasks and related lifecycle workflows resources on behalf of the signed-in user.", - "displayName": "Read all lifecycle workflows resources", - "id": "9bcb9916-765a-42af-bf77-02282e26b01a", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to list and read all workflows, tasks and related lifecycle workflows resources on your behalf.", - "userConsentDisplayName": "Read all lifecycle workflows resources", - "value": "LifecycleWorkflows.Read.All" - }, - { - "description": "Allows the application to list and query any shared user profile information associated with the current tenant on behalf of the signed-in user.\u00a0 It also permits the application to export external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant on behalf of the signed-in user.", - "displayName": "Read all shared cross-tenant user profiles and export their data", - "id": "759dcd16-3c90-463c-937e-abf89f991c18", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to list and query any shared user profile information associated with the current tenant on your behalf.\u00a0 It also permits the application to export external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant on your behalf.", - "userConsentDisplayName": "Read any shared cross-tenant user profiles and export data", - "value": "CrossTenantUserProfileSharing.Read.All" - }, - { - "description": "Allows the application to read the tenant-level settings in SharePoint and OneDrive on behalf of the signed-in user.", - "displayName": "Read SharePoint and OneDrive tenant settings", - "id": "2ef70e10-5bfd-4ede-a5f6-67720500b258", - "Origin": "Delegated", - "userConsentDescription": "Allows the application to read the tenant-level settings in SharePoint and OneDrive on your behalf.", - "userConsentDisplayName": "Read SharePoint and OneDrive tenant settings", - "value": "SharePointTenantSettings.Read.All" - }, - { - "description": "Allows the app to read or write your organization's custom authentication extensions on behalf of the signed-in user.", - "displayName": "Read and write your organization's custom authentication extensions", - "id": "8dfcf82f-15d0-43b3-bc78-a958a13a5792", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read or write your organization's custom authentication extensions on your behalf.", - "userConsentDisplayName": "Read and write your organization's custom authentication extensions", - "value": "CustomAuthenticationExtension.ReadWrite.All" - }, - { - "description": "Allows an app to manage license assignments for users and groups, on behalf of the signed-in user.", - "displayName": "Manage all license assignments", - "id": "f55016cc-149c-447e-8f21-7cf3ec1d6350", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to manage all license assignments, on your behalf.", - "userConsentDisplayName": "Manage all license assignments", - "value": "LicenseAssignment.ReadWrite.All" - }, - { - "description": "Allows an app to read all acronyms that the signed-in user can access.", - "displayName": "Read all acronyms that the user can access", - "id": "9084c10f-a2d6-4713-8732-348def50fe02", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all acronyms you can access.", - "userConsentDisplayName": "Read all acronyms that you have access to", - "value": "Acronym.Read.All" - }, - { - "description": "Allows the app to read your organization's custom authentication extensions on behalf of the signed-in user.", - "displayName": "Read your oganization's custom authentication extensions", - "id": "b2052569-c98c-4f36-a5fb-43e5c111e6d0", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read your organization's custom authentication extensions on your behalf.", - "userConsentDisplayName": "Read your organization's custom authentication extensions", - "value": "CustomAuthenticationExtension.Read.All" - }, - { - "description": "Allows the app to read all transcripts of online meetings, on behalf of the signed-in user.", - "displayName": "Read all transcripts of online meetings. ", - "id": "30b87d18-ebb1-45db-97f8-82ccb1f0190c", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read all transcripts of online meetings, on your behalf.", - "userConsentDisplayName": "Read all transcripts of online meetings.", - "value": "OnlineMeetingTranscript.Read.All" - }, - { - "description": "Allows the app to read and write channel messages, on behalf of the signed-in user. This doesn't allow the app to edit the policyViolation of a channel message.", - "displayName": "Read and write user channel messages", - "id": "5922d31f-46c8-4404-9eaf-2117e390a8a4", - "Origin": "Delegated", - "userConsentDescription": "Allows the app to read and write channel messages, on your behalf. This doesn't allow the app to edit the policyViolation of a channel message.", - "userConsentDisplayName": "Read and write user channel messages", - "value": "ChannelMessage.ReadWrite" - }, - { - "description": "Read Threat and Vulnerability Management vulnerability information", - "displayName": "Allows the app to read any Threat and Vulnerability Management vulnerability information", - "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", - "Origin": "Application (WindowsDefenderATP)", - "userConsentDescription": "Allows the app to read any Threat and Vulnerability Management vulnerability information", - "userConsentDisplayName": "Allows the app to read any Threat and Vulnerability Management vulnerability information", - "value": "Vulnerability.Read.All" - }, - { - "description": "Allows the app to read Threat and Vulnerability Management vulnerability information on behalf of the signed-in user", - "displayName": "Read Threat and Vulnerability Management vulnerability information", - "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", - "Origin": "Delegated (WindowsDefenderATP)", - "userConsentDescription": "Allows the app to read Threat and Vulnerability Management vulnerability information on behalf of the signed-in user", - "userConsentDisplayName": "Read Threat and Vulnerability Management vulnerability information", - "value": "Vulnerability.Read" - }, - { - "description": "Allows the app to manage Exchange Online", - "displayName": "Manage Exchange online", - "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", - "Origin": "Delegated (Office 365 Exchange Online)", - "userConsentDescription": "Allows the app to read Threat and Vulnerability Management vulnerability information on behalf of the signed-in user", - "userConsentDisplayName": "Read Threat and Vulnerability Management vulnerability information", - "value": "Exchange.Manage" - }, - { - "description": "Allows the app to create, read, update and delete events in all calendars in the organization user has permissions to access. This includes delegate and shared calendars", - "displayName": "Read and write user and shared calendars", - "id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415", - "Origin": "Delegated (Office 365 Exchange Online)", - "userConsentDescription": "Allows the app to read, update, create and delete events in all calendars in your organization you have permissions to access. This includes delegate and shared calendars", - "userConsentDisplayName": "Read and write to your and shared calendars", - "value": "Calendars.ReadWrite.All" - }, - { - "description": "Allows the app to create, read, update, and delete user's mailbox settings. Does not include permission to send mail.", - "displayName": "Read and write user mailbox settings", - "id": "2e83d72d-8895-4b66-9eea-abb43449ab8b", - "Origin": "Delegated (Office 365 Exchange Online)", - "userConsentDescription": "Allows the app to read, update, create, and delete your mailbox settings.", - "userConsentDisplayName": "Read and write to your mailbox settings", - "value": "MailboxSettings.ReadWrite" - }, - { - "description": "Allows the app to have full control of all site collections on behalf of the signed-in user.", - "displayName": "Manage Sharepoint Online", - "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", - "Origin": "Delegated (Office 365 SharePoint Online)", - "userConsentDescription": "Have full control of all site collections", - "userConsentDisplayName": "Allows the app to have full control of all site collections on your behalf.", - "value": "AllSites.FullControl" - }, - { - "description": "Allows to read the LAPs passwords.", - "displayName": "Manage LAPs passwords", - "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", - "Origin": "Delegated", - "userConsentDescription": "Allows to read the LAPs passwords.", - "userConsentDisplayName": "Manage LAPs passwords", - "value": "DeviceLocalCredential.Read.All" - }, - { - "description": "Access Microsoft Teams and Skype for Business data as the signed in user", - "displayName": "Access Microsoft Teams and Skype for Business data based on the user's role membership", - "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", - "Origin": "Delegated (Skype and Teams Tenant Admin API)", - "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" - } -] +[ + { + "description": "Allows Exchange Management as app", + "displayName": "Manage Exchange As Application ", + "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", + "origin": "Application (Office 365 Exchange Online)", + "value": "Exchange.ManageAsApp" + }, + { + "description": "Allows the app to read a basic set of profile properties of other users in your organization without a signed-in user. Includes display name, first and last name, email address, open extensions, and photo.", + "displayName": "Read all users' basic profiles", + "id": "97235f07-e226-4f63-ace3-39588e11d3a1", + "origin": "Application", + "value": "User.ReadBasic.All" + }, + { + "description": "Allows the app to read all\u00a0class assignments without grades for all users without a signed-in user.", + "displayName": "Read all class assignments without grades", + "id": "6e0a958b-b7fc-4348-b7c4-a6ab9fd3dd0e", + "origin": "Application", + "value": "EduAssignments.ReadBasic.All" + }, + { + "description": "Allows the app to create, read, update and delete all\u00a0class assignments without grades for all users without a signed-in user.", + "displayName": "Create, read, update and delete all\u00a0class assignments without grades", + "id": "f431cc63-a2de-48c4-8054-a34bc093af84", + "origin": "Application", + "value": "EduAssignments.ReadWriteBasic.All" + }, + { + "description": "Allows the app to read all\u00a0class assignments with grades for all users without a signed-in user.", + "displayName": "Read all class assignments with grades", + "id": "4c37e1b6-35a1-43bf-926a-6f30f2cdf585", + "origin": "Application", + "value": "EduAssignments.Read.All" + }, + { + "description": "Allows the app to create, read, update and delete all\u00a0class assignments with grades for all users without a signed-in user.", + "displayName": "Create, read, update and delete all\u00a0class assignments with grades", + "id": "0d22204b-6cad-4dd0-8362-3e3f2ae699d9", + "origin": "Application", + "value": "EduAssignments.ReadWrite.All" + }, + { + "description": "Allows\u00a0the\u00a0app\u00a0to\u00a0read\u00a0subject\u00a0rights requests\u00a0without a\u00a0signed-in\u00a0user.", + "displayName": "Read\u00a0all subject\u00a0rights requests", + "id": "ee1460f0-368b-4153-870a-4e1ca7e72c42", + "origin": "Application", + "value": "SubjectRightsRequest.Read.All" + }, + { + "description": "Allows\u00a0the\u00a0app\u00a0to\u00a0read\u00a0and\u00a0write subject\u00a0rights requests\u00a0without a signed in user.", + "displayName": "Read\u00a0and\u00a0write\u00a0all subject\u00a0rights requests", + "id": "8387eaa4-1a3c-41f5-b261-f888138e6041", + "origin": "Application", + "value": "SubjectRightsRequest.ReadWrite.All" + }, + { + "description": "Allows the app to read attack simulation and training data for an organization without a signed-in user.", + "displayName": "Read attack simulation data of an organization", + "id": "93283d0a-6322-4fa8-966b-8c121624760d", + "origin": "Application", + "value": "AttackSimulation.Read.All" + }, + { + "description": "Allows custom authentication extensions associated with the app to receive HTTP requests triggered by an authentication event. The request can include information about a user, client and resource service principals, and other information about the authentication.", + "displayName": "Receive custom authentication extension HTTP requests", + "id": "214e810f-fda8-4fd7-a475-29461495eb00", + "origin": "Application", + "value": "CustomAuthenticationExtension.Receive.Payload" + }, + { + "description": "Allows the app to read and write your organization's directory access review default policy without a signed-in user.", + "displayName": "Read and write your organization's directory access review default policy", + "id": "77c863fd-06c0-47ce-a7eb-49773e89d319", + "origin": "Application", + "value": "Policy.ReadWrite.AccessReview" + }, + { + "description": "Allows the app to create groups, read all group properties and memberships, update group properties and memberships, and delete groups. Also allows the app to read and write conversations. All of these operations can be performed by the app without a signed-in user.", + "displayName": "Read and write all groups", + "id": "62a82d76-70ea-41e2-9197-370581804d09", + "origin": "Application", + "value": "Group.ReadWrite.All" + }, + { + "description": "Allows the app to read group properties and memberships, and read\u00a0conversations for all groups, without a signed-in user.", + "displayName": "Read all groups", + "id": "5b567255-7703-4780-807c-7be8301ae99b", + "origin": "Application", + "value": "Group.Read.All" + }, + { + "description": "Allows the app to read your organization's threat submissions and threat submission policies without a signed-in user. Also allows the app to create new threat submissions without a signed-in user.", + "displayName": "Read and write all of the organization's threat submissions", + "id": "d72bdbf4-a59b-405c-8b04-5995895819ac", + "origin": "Application", + "value": "ThreatSubmission.ReadWrite.All" + }, + { + "description": "Allows an app to read Bookings appointments, businesses, customers, services, and staff without a signed-in user. ", + "displayName": "Read all Bookings related resources.", + "id": "6e98f277-b046-4193-a4f2-6bf6a78cd491", + "origin": "Application", + "value": "Bookings.Read.All" + }, + { + "description": "Allows an app to read and write Bookings appointments and customers, and additionally allows reading businesses, services, and staff without a signed-in user. ", + "displayName": "Read and write all Bookings related resources.", + "id": "9769393e-5a9f-4302-9e3d-7e018ecb64a7", + "origin": "Application", + "value": "BookingsAppointment.ReadWrite.All" + }, + { + "description": "Allows the application to read any data from Records Management, such as configuration, labels, and policies without the signed in user.", + "displayName": "Read Records Management configuration,\u00a0labels and policies", + "id": "ac3a2b8e-03a3-4da9-9ce0-cbe28bf1accd", + "origin": "Application", + "value": "RecordsManagement.Read.All" + }, + { + "description": "Allow the application to create, update and delete any data from Records Management, such as configuration, labels, and policies without the signed in user.", + "displayName": "Read and write Records Management configuration, labels and policies", + "id": "eb158f57-df43-4751-8b21-b8932adb3d34", + "origin": "Application", + "value": "RecordsManagement.ReadWrite.All" + }, + { + "description": "Allows the app to read details of delegated admin relationships with customers like access details (that includes roles) and the duration as well as specific role assignments to security groups without a signed-in user.", + "displayName": "Read Delegated Admin relationships with customers", + "id": "f6e9e124-4586-492f-adc0-c6f96e4823fd", + "origin": "Application", + "value": "DelegatedAdminRelationship.Read.All" + }, + { + "description": "Allows the app to manage (create-update-terminate) Delegated Admin relationships with customers and role assignments to security groups for active Delegated Admin relationships without a signed-in user.", + "displayName": "Manage Delegated Admin relationships with customers", + "id": "cc13eba4-8cd8-44c6-b4d4-f93237adce58", + "origin": "Application", + "value": "DelegatedAdminRelationship.ReadWrite.All" + }, + { + "description": "Allows the app to read and manage the Cloud PC role-based access control (RBAC) settings, without a signed-in user. This includes reading and managing Cloud PC role definitions and memberships.", + "displayName": "Read and write all Cloud PC RBAC settings", + "id": "274d0592-d1b6-44bd-af1d-26d259bcb43a", + "origin": "Application", + "value": "RoleManagement.ReadWrite.CloudPC" + }, + { + "description": "Allows the app to read the Cloud PC role-based access control (RBAC) settings, without a signed-in user.", + "displayName": "Read Cloud PC RBAC settings", + "id": "031a549a-bb80-49b6-8032-2068448c6a3c", + "origin": "Application", + "value": "RoleManagement.Read.CloudPC" + }, + { + "description": "Allows the app to read custom security attribute assignments for all principals in the tenant without a signed in user.", + "displayName": "Read custom security attribute assignments", + "id": "3b37c5a4-1226-493d-bec3-5d6c6b866f3f", + "origin": "Application", + "value": "CustomSecAttributeAssignment.Read.All" + }, + { + "description": "Allows the app to read custom security attribute definitions for the tenant without a signed in user.", + "displayName": "Read custom security attribute definitions", + "id": "b185aa14-d8d2-42c1-a685-0f5596613624", + "origin": "Application", + "value": "CustomSecAttributeDefinition.Read.All" + }, + { + "description": "Allows the app to read all external connections without a signed-in user.", + "displayName": "Read all external connections", + "id": "1914711b-a1cb-4793-b019-c2ce0ed21b8c", + "origin": "Application", + "value": "ExternalConnection.Read.All" + }, + { + "description": "Allows the app to read and write all external connections without a signed-in user.", + "displayName": "Read and write all external connections", + "id": "34c37bc0-2b40-4d5e-85e1-2365cd256d79", + "origin": "Application", + "value": "ExternalConnection.ReadWrite.All" + }, + { + "description": "Allows the app to read all external items without a signed-in user.", + "displayName": "Read all external items", + "id": "7a7cffad-37d2-4f48-afa4-c6ab129adcc2", + "origin": "Application", + "value": "ExternalItem.Read.All" + }, + { + "description": "Allows the app to read and write your organization's cross tenant access policies without a signed-in user.", + "displayName": "Read and write your organization's cross tenant access policies", + "id": "338163d7-f101-4c92-94ba-ca46fe52447c", + "origin": "Application", + "value": "Policy.ReadWrite.CrossTenantAccess" + }, + { + "description": "Allows the app to read and write custom security attribute definitions for the tenant without a signed in user.", + "displayName": "Read and write custom security attribute definitions", + "id": "12338004-21f4-4896-bf5e-b75dfaf1016d", + "origin": "Application", + "value": "CustomSecAttributeDefinition.ReadWrite.All" + }, + { + "description": "Allows the app to read and write custom security attribute assignments for all principals in the tenant without a signed in user.", + "displayName": "Read and write custom security attribute assignments", + "id": "de89b5e4-5b8f-48eb-8925-29c2b33bd8bd", + "origin": "Application", + "value": "CustomSecAttributeAssignment.ReadWrite.All" + }, + { + "description": "Allows the app to read and write to all security incidents, without a signed-in user.", + "displayName": "Read and write to all security incidents", + "id": "34bf0e97-1971-4929-b999-9e2442d941d7", + "origin": "Application", + "value": "SecurityIncident.ReadWrite.All" + }, + { + "description": "Allows the app to read all security incidents, without a signed-in user.", + "displayName": "Read all security incidents", + "id": "45cc0394-e837-488b-a098-1918f48d186c", + "origin": "Application", + "value": "SecurityIncident.Read.All" + }, + { + "description": "Allows the app to read and write to all security alerts, without a signed-in user.", + "displayName": "Read and write to all security alerts", + "id": "ed4fca05-be46-441f-9803-1873825f8fdb", + "origin": "Application", + "value": "SecurityAlert.ReadWrite.All" + }, + { + "description": "Allows the app to read all security alerts, without a signed-in user.", + "displayName": "Read all security alerts", + "id": "472e4a4d-bb4a-4026-98d1-0b0d74cb74a5", + "origin": "Application", + "value": "SecurityAlert.Read.All" + }, + { + "description": "Allows the app to read and write eDiscovery objects such as cases, custodians, review sets and other related objects without a signed-in user.", + "displayName": "Read and write all eDiscovery objects", + "id": "b2620db1-3bf7-4c5b-9cb9-576d29eac736", + "origin": "Application", + "value": "eDiscovery.ReadWrite.All" + }, + { + "description": "Allows the app to read eDiscovery objects such as cases, custodians, review sets and other related objects without a signed-in user.", + "displayName": "Read all eDiscovery objects", + "id": "50180013-6191-4d1e-a373-e590ff4e66af", + "origin": "Application", + "value": "eDiscovery.Read.All" + }, + { + "description": "Allows the app to run hunting queries, without a signed-in user.", + "displayName": "Run hunting queries", + "id": "dd98c7f5-2d42-42d3-a0e4-633161547251", + "origin": "Application", + "value": "ThreatHunting.Read.All" + }, + { + "description": "Allow the app to read the management data for Teams devices, without a signed-in user.", + "displayName": "Read Teams devices", + "id": "0591bafd-7c1c-4c30-a2a5-2b9aacb1dfe8", + "origin": "Application", + "value": "TeamworkDevice.Read.All" + }, + { + "description": "Allow the app to read and write the management data for Teams devices, without a signed-in user.", + "displayName": "Read and write Teams devices", + "id": "79c02f5b-bd4f-4713-bc2c-a8a4a66e127b", + "origin": "Application", + "value": "TeamworkDevice.ReadWrite.All" + }, + { + "description": "Allows the app to read and update identity risky service principal for your organization, without a signed-in user.", + "displayName": "Read and write all identity risky service principal information", + "id": "cb8d6980-6bcb-4507-afec-ed6de3a2d798", + "origin": "Application", + "value": "IdentityRiskyServicePrincipal.ReadWrite.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs for any user, without a signed-in user.", + "displayName": "Allow the Teams app to manage only its own tabs for all users", + "id": "3c42dec6-49e8-4a0a-b469-36cff0d9da93", + "origin": "Application", + "value": "TeamsTab.ReadWriteSelfForUser.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs in any team, without a signed-in user.", + "displayName": "Allow the Teams app to manage only its own tabs for all teams", + "id": "91c32b81-0ef0-453f-a5c7-4ce2e562f449", + "origin": "Application", + "value": "TeamsTab.ReadWriteSelfForTeam.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs for any chat, without a signed-in user.", + "displayName": "Allow the Teams app to manage only its own tabs for all chats", + "id": "9f62e4a2-a2d6-4350-b28b-d244728c4f86", + "origin": "Application", + "value": "TeamsTab.ReadWriteSelfForChat.All" + }, + { + "description": "Allows the app to read all risky service principal information for your organization, without a signed-in user.", + "displayName": "Read all identity risky service principal information", + "id": "607c7344-0eed-41e5-823a-9695ebe1b7b0", + "origin": "Application", + "value": "IdentityRiskyServicePrincipal.Read.All" + }, + { + "description": "Allows the app to read and write search configurations, without a signed-in user.", + "displayName": "Read and write your organization's search configuration", + "id": "0e778b85-fefa-466d-9eec-750569d92122", + "origin": "Application", + "value": "SearchConfiguration.ReadWrite.All" + }, + { + "description": "Allows the app to read search configurations, without a signed-in user.", + "displayName": "Read your organization's search configuration", + "id": "ada977a5-b8b1-493b-9a91-66c206d76ecf", + "origin": "Application", + "value": "SearchConfiguration.Read.All" + }, + { + "description": "Allows the app to read online meeting artifacts in your organization, without a signed-in user.", + "displayName": "Read online meeting artifacts", + "id": "df01ed3b-eb61-4eca-9965-6b3d789751b2", + "origin": "Application", + "value": "OnlineMeetingArtifact.Read.All" + }, + { + "description": "Allows the app to create, read, update, and delete apps in the app catalogs without a signed-in user.", + "displayName": "Read and write to all app catalogs", + "id": "dc149144-f292-421e-b185-5953f2e98d7f", + "origin": "Application", + "value": "AppCatalog.ReadWrite.All" + }, + { + "description": "Allows the app to read apps in the app catalogs without a signed-in user.", + "displayName": "Read all app catalogs", + "id": "e12dae10-5a57-4817-b79d-dfbec5348930", + "origin": "Application", + "value": "AppCatalog.Read.All" + }, + { + "description": "Allows the app to manage workforce integrations to synchronize data from Microsoft Teams Shifts, without a signed-in user.", + "displayName": "Read and write workforce integrations", + "id": "202bf709-e8e6-478e-bcfd-5d63c50b68e3", + "origin": "Application", + "value": "WorkforceIntegration.ReadWrite.All" + }, + { + "description": "Allows the app to read all presence information and write activity and availability of all users in the directory without a signed-in user. Presence information includes activity, availability, status note, calendar out-of-office message, time zone and location.", + "displayName": "Read and write presence information for all users", + "id": "83cded22-8297-4ff6-a7fa-e97e9545a259", + "origin": "Application", + "value": "Presence.ReadWrite.All" + }, + { + "description": "Allows the app to read and write tags in Teams without a signed-in user.", + "displayName": "Read and write tags in Teams", + "id": "a3371ca5-911d-46d6-901c-42c8c7a937d8", + "origin": "Application", + "value": "TeamworkTag.ReadWrite.All" + }, + { + "description": "Allows the app to read\u00a0tags in Teams\u00a0without a signed-in user.", + "displayName": "Read tags in Teams", + "id": "b74fd6c4-4bde-488e-9695-eeb100e4907f", + "origin": "Application", + "value": "TeamworkTag.Read.All" + }, + { + "description": "Allows the app to read and write all Windows update deployment settings for the organization without a signed-in user.", + "displayName": "Read and write all Windows update deployment settings", + "id": "7dd1be58-6e76-4401-bf8d-31d1e8180d5b", + "origin": "Application", + "value": "WindowsUpdates.ReadWrite.All" + }, + { + "description": "Allows the app to read and write external connections without a signed-in user. The app can only read and write external connections that it is authorized to, or it can create new external connections. ", + "displayName": "Read and write external connections", + "id": "f431331c-49a6-499f-be1c-62af19c34a9d", + "origin": "Application", + "value": "ExternalConnection.ReadWrite.OwnedBy" + }, + { + "description": "Allows the app to read and write external items without a signed-in user. The app can only read external items of the connection that it is authorized to.", + "displayName": "Read and write external items", + "id": "8116ae0f-55c2-452d-9944-d18420f5b2c8", + "origin": "Application", + "value": "ExternalItem.ReadWrite.OwnedBy" + }, + { + "description": "Allow the application to access a subset of site collections without a signed in user.\u00a0\u00a0The specific site collections and the permissions granted will be configured in SharePoint Online.", + "displayName": "Access selected site collections", + "id": "883ea226-0bf2-4a8f-9f9d-92c9162a727d", + "origin": "Application", + "value": "Sites.Selected" + }, + { + "description": "Allows the app to read documents and list items in all site collections without a signed in user.", + "displayName": "Read items in all site collections ", + "id": "332a536c-c7ef-4017-ab91-336970924f0d", + "origin": "Application", + "value": "Sites.Read.All" + }, + { + "description": "Allows the app to create, read, update, and delete documents and list items in all site collections without a signed in user.", + "displayName": "Read and write items in all site collections", + "id": "9492366f-7969-46a4-8d15-ed1a20078fff", + "origin": "Application", + "value": "Sites.ReadWrite.All" + }, + { + "description": "Allows the app to read and write the properties of Cloud PCs, without a signed-in user.", + "displayName": "Read and write Cloud PCs", + "id": "3b4349e1-8cf5-45a3-95b7-69d1751d3e6a", + "origin": "Application", + "value": "CloudPC.ReadWrite.All" + }, + { + "description": "Allows the app to read the properties of Cloud PCs, without a signed-in user.", + "displayName": "Read Cloud PCs", + "id": "a9e09520-8ed4-4cde-838e-4fdea192c227", + "origin": "Application", + "value": "CloudPC.Read.All" + }, + { + "description": "Allows the app to update service principal endpoints", + "displayName": "Read and update service principal endpoints", + "id": "89c8469c-83ad-45f7-8ff2-6e3d4285709e", + "origin": "Application", + "value": "ServicePrincipalEndpoint.ReadWrite.All" + }, + { + "description": "Allows the app to read service principal endpoints", + "displayName": "Read service principal endpoints", + "id": "5256681e-b7f6-40c0-8447-2d9db68797a0", + "origin": "Application", + "value": "ServicePrincipalEndpoint.Read.All" + }, + { + "description": "Allows the app to create new notifications in users' teamwork activity feeds without a signed in user. These notifications may not be discoverable or be held or governed by compliance policies.", + "displayName": "Send a teamwork activity to any user", + "id": "a267235f-af13-44dc-8385-c1dc93023186", + "origin": "Application", + "value": "TeamsActivity.Send" + }, + { + "description": "Allows the app to read terms of use acceptance statuses, without a signed in user.", + "displayName": "Read all terms of use acceptance statuses", + "id": "d8e4ec18-f6c0-4620-8122-c8b1f2bf400e", + "origin": "Application", + "value": "AgreementAcceptance.Read.All" + }, + { + "description": "Allows the app to read and write terms of use agreements, without a signed in user.", + "displayName": "Read and write all terms of use agreements", + "id": "c9090d00-6101-42f0-a729-c41074260d47", + "origin": "Application", + "value": "Agreement.ReadWrite.All" + }, + { + "description": "Allows the app to read terms of use agreements, without a signed in user.", + "displayName": "Read all terms of use agreements", + "id": "2f3e6f8c-093b-4c57-a58b-ba5ce494a169", + "origin": "Application", + "value": "Agreement.Read.All" + }, + { + "description": "Allows the app to read app consent requests and approvals, and deny or approve those requests without a signed-in user.", + "displayName": "Read and write all consent requests", + "id": "9f1b81a7-0223-4428-bfa4-0bcb5535f27d", + "origin": "Application", + "value": "ConsentRequest.ReadWrite.All" + }, + { + "description": "Allows the app to read and write your organization's consent requests policy without a signed-in user.", + "displayName": "Read and write your organization's consent request policy", + "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", + "origin": "Application", + "value": "Policy.ReadWrite.ConsentRequest" + }, + { + "description": "Allows the app to read consent requests and approvals without a signed-in user.", + "displayName": "Read all consent requests", + "id": "1260ad83-98fb-4785-abbb-d6cc1806fd41", + "origin": "Application", + "value": "ConsentRequest.Read.All" + }, + { + "description": "Allows the app to read basic mail properties in all mailboxes without a signed-in user. Includes all properties except body, previewBody, attachments and any extended properties.", + "displayName": "Read basic mail in all mailboxes", + "id": "693c5e45-0940-467d-9b8a-1022fb9d42ef", + "origin": "Application", + "value": "Mail.ReadBasic.All" + }, + { + "description": "Allows the app to read basic mail properties in all mailboxes without a signed-in user. Includes all properties except body, previewBody, attachments and any extended properties.", + "displayName": "Read basic mail in all mailboxes", + "id": "6be147d2-ea4f-4b5a-a3fa-3eab6f3c140a", + "origin": "Application", + "value": "Mail.ReadBasic" + }, + { + "description": "Allows the app to read and write feature rollout policies without a signed-in user. Includes abilities to assign and remove users and groups to rollout of a specific feature.", + "displayName": "Read and write feature rollout policies", + "id": "2044e4f1-e56c-435b-925c-44cd8f6ba89a", + "origin": "Application", + "value": "Policy.ReadWrite.FeatureRollout" + }, + { + "description": "Allows the app to read and manage the role-based access control (RBAC) settings for your company's directory, without a signed-in user. This includes instantiating directory roles and managing directory role membership, and reading directory role templates, directory roles and memberships.", + "displayName": "Read and write all directory RBAC settings", + "id": "9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8", + "origin": "Application", + "value": "RoleManagement.ReadWrite.Directory" + }, + { + "description": "Allows the app to read the role-based access control (RBAC) settings for your company's directory, without a signed-in user. This includes reading directory role templates, directory roles and memberships.", + "displayName": "Read all directory RBAC settings", + "id": "483bed4a-2ad3-4361-a73b-c83ccdbdc53c", + "origin": "Application", + "value": "RoleManagement.Read.Directory" + }, + { + "description": "Allows the app to read and write the organization and related resources, without a signed-in user.\u00a0Related resources include things like subscribed skus and tenant branding information.", + "displayName": "Read and write organization information", + "id": "292d869f-3427-49a8-9dab-8c70152b74e9", + "origin": "Application", + "value": "Organization.ReadWrite.All" + }, + { + "description": "Allows the app to read the organization and related resources, without a signed-in user.\u00a0Related resources include things like subscribed skus and tenant branding information.", + "displayName": "Read organization information", + "id": "498476ce-e0fe-48b0-b801-37ba7e2685c6", + "origin": "Application", + "value": "Organization.Read.All" + }, + { + "description": "Allows the app to read company places (conference rooms and room lists) for calendar events and other applications, without a signed-in user.", + "displayName": "Read all company places", + "id": "913b9306-0ce1-42b8-9137-6a7df690a760", + "origin": "Application", + "value": "Place.Read.All" + }, + { + "description": "Allows the app to read the memberships of hidden groups and administrative units without a signed-in user.", + "displayName": "Read all hidden memberships", + "id": "658aa5d8-239f-45c4-aa12-864f4fc7e490", + "origin": "Application", + "value": "Member.Read.Hidden" + }, + { + "description": "Allow the app to read or write items in all external datasets that the app is authorized to access", + "displayName": "Read and write items in external datasets", + "id": "38c3d6ee-69ee-422f-b954-e17819665354", + "origin": "Application", + "value": "ExternalItem.ReadWrite.All" + }, + { + "description": "Allows the app to read, update, delete and perform actions on access reviews, reviewers, decisions and settings in the organization for group and app memberships, without a signed-in user.", + "displayName": "Manage access reviews for group and app memberships", + "id": "18228521-a591-40f1-b215-5fad4488c117", + "origin": "Application", + "value": "AccessReview.ReadWrite.Membership" + }, + { + "description": "Allows the app to read properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups, without a signed-in user.", + "displayName": "Read Microsoft Intune device configuration and policies", + "id": "dc377aa6-52d8-4e23-b271-2a7ae04cedf3", + "origin": "Application", + "value": "DeviceManagementConfiguration.Read.All" + }, + { + "description": "Allows the app to read the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune, without a signed-in user.", + "displayName": "Read Microsoft Intune apps", + "id": "7a6ee1e7-141e-4cec-ae74-d9db155731ff", + "origin": "Application", + "value": "DeviceManagementApps.Read.All" + }, + { + "description": "Allows the app to read the properties of devices managed by Microsoft Intune, without a signed-in user.", + "displayName": "Read Microsoft Intune devices", + "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", + "origin": "Application", + "value": "DeviceManagementManagedDevices.Read.All" + }, + { + "description": "Allows the app to read the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings, without a signed-in user.", + "displayName": "Read Microsoft Intune RBAC settings", + "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", + "origin": "Application", + "value": "DeviceManagementRBAC.Read.All" + }, + { + "description": "Allows the app to read Microsoft Intune service properties including device enrollment and third party service connection configuration, without a signed-in user.", + "displayName": "Read Microsoft Intune configuration", + "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", + "origin": "Application", + "value": "DeviceManagementServiceConfig.Read.All" + }, + { + "description": "Allows the app to create, view, update and delete on-premises published resources, on-premises agents and agent groups, as part of a hybrid identity configuration, without a signed in user.", + "displayName": "Manage on-premises published resources", + "id": "0b57845e-aa49-4e6f-8109-ce654fffa618", + "origin": "Application", + "value": "OnPremisesPublishingProfiles.ReadWrite.All" + }, + { + "description": "Allows the app to read and write trust framework key set properties without a signed-in user.", + "displayName": "Read and write trust framework key sets", + "id": "4a771c9a-1cf2-4609-b88e-3d3e02d539cd", + "origin": "Application", + "value": "TrustFrameworkKeySet.ReadWrite.All" + }, + { + "description": "Allows the app to read trust framework key set properties without a signed-in user.", + "displayName": "Read trust framework key sets", + "id": "fff194f1-7dce-4428-8301-1badb5518201", + "origin": "Application", + "value": "TrustFrameworkKeySet.Read.All" + }, + { + "description": "Allows the app to read and write your organization's trust framework policies without a signed in user.", + "displayName": "Read and write your organization's trust framework policies", + "id": "79a677f7-b79d-40d0-a36a-3e6f8688dd7a", + "origin": "Application", + "value": "Policy.ReadWrite.TrustFramework" + }, + { + "description": "Allows the app to read all your organization's policies without a signed in user.", + "displayName": "Read your organization's policies", + "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", + "origin": "Application", + "value": "Policy.Read.All" + }, + { + "description": "Allows the app to read and write your organization\u2019s identity (authentication) providers\u2019 properties without a signed in user.", + "displayName": "Read and write identity providers", + "id": "90db2b9a-d928-4d33-a4dd-8442ae3d41e4", + "origin": "Application", + "value": "IdentityProvider.ReadWrite.All" + }, + { + "description": "Allows the app to read your organization\u2019s identity (authentication) providers\u2019 properties without a signed in user.", + "displayName": "Read identity providers", + "id": "e321f0bb-e7f7-481e-bb28-e3b0b32d4bd0", + "origin": "Application", + "value": "IdentityProvider.Read.All" + }, + { + "description": "Allows the app to create, read, update, and delete administrative units and manage administrative unit membership without a signed-in user.", + "displayName": "Read and write all administrative units", + "id": "5eb59dd3-1da2-4329-8733-9dabdc435916", + "origin": "Application", + "value": "AdministrativeUnit.ReadWrite.All" + }, + { + "description": "Allows the app to read administrative units and administrative unit membership without a signed-in user.", + "displayName": "Read all administrative units", + "id": "134fd756-38ce-4afd-ba33-e9623dbe66c2", + "origin": "Application", + "value": "AdministrativeUnit.Read.All" + }, + { + "description": "Allows an app to read published sensitivity labels and label policy settings for the entire organization or a specific user, without a signed in user.", + "displayName": "Read all published labels and label policies for an organization.", + "id": "19da66cb-0fb0-4390-b071-ebc76a349482", + "origin": "Application", + "value": "InformationProtectionPolicy.Read.All" + }, + { + "description": "Allows the app to read all the OneNote notebooks in your organization, without a signed-in user.", + "displayName": "Read all OneNote notebooks", + "id": "3aeca27b-ee3a-4c2b-8ded-80376e2134a4", + "origin": "Application", + "value": "Notes.Read.All" + }, + { + "description": "Allows the app to invite guest users to the organization, without a signed-in user.", + "displayName": "Invite guest users to the organization", + "id": "09850681-111b-4a89-9bed-3f2cae46d706", + "origin": "Application", + "value": "User.Invite.All" + }, + { + "description": "Allows the app to read, create, update and delete all files in all site collections without a signed in user. ", + "displayName": "Read and write files in all site collections", + "id": "75359482-378d-4052-8f01-80520e7db3cd", + "origin": "Application", + "value": "Files.ReadWrite.All" + }, + { + "description": "Allows the app to create threat indicators, and fully manage those threat indicators (read, update and delete), without a signed-in user. \u00a0It cannot update any threat indicators it does not own.", + "displayName": "Manage threat indicators this app creates or owns", + "id": "21792b6c-c986-4ffc-85de-df9da54b52fa", + "origin": "Application", + "value": "ThreatIndicators.ReadWrite.OwnedBy" + }, + { + "description": "Allows the app to read or update security actions, without a signed-in user.", + "displayName": "Read and update your organization's security actions", + "id": "f2bf083f-0179-402a-bedb-b2784de8a49b", + "origin": "Application", + "value": "SecurityActions.ReadWrite.All" + }, + { + "description": "Allows the app to read security actions, without a signed-in user.", + "displayName": "Read your organization's security actions", + "id": "5e0edab9-c148-49d0-b423-ac253e121825", + "origin": "Application", + "value": "SecurityActions.Read.All" + }, + { + "description": "Allows the app to read your organization\u2019s security events without a signed-in user. Also allows the app to update editable properties in security events.", + "displayName": "Read and update your organization\u2019s security events", + "id": "d903a879-88e0-4c09-b0c9-82f6a1333f84", + "origin": "Application", + "value": "SecurityEvents.ReadWrite.All" + }, + { + "description": "Allows the app to read your organization\u2019s security events without a signed-in user.", + "displayName": "Read your organization\u2019s security events", + "id": "bf394140-e372-4bf9-a898-299cfc7564e5", + "origin": "Application", + "value": "SecurityEvents.Read.All" + }, + { + "description": "Allows an app to read and write all chat messages in Microsoft Teams, without a signed-in user.", + "displayName": "Read and write all chat messages", + "id": "294ce7c9-31ba-490a-ad7d-97a7d075e4ed", + "origin": "Application", + "value": "Chat.ReadWrite.All" + }, + { + "description": "Allows the app to read and update identity risk detection information for your organization without a signed-in user. Update operations include confirming risk event detections.\u00a0", + "displayName": "Read and write all risk detection information", + "id": "db06fb33-1953-4b7b-a2ac-f1e2c854f7ae", + "origin": "Application", + "value": "IdentityRiskEvent.ReadWrite.All" + }, + { + "description": "Allows the app to read and update identity risky user information for your organization without a signed-in user. \u00a0Update operations include dismissing risky users.", + "displayName": "Read and write all risky user information", + "id": "656f6061-f9fe-4807-9708-6a2e0934df76", + "origin": "Application", + "value": "IdentityRiskyUser.ReadWrite.All" + }, + { + "description": "Allows the app to read all files in all site collections without a signed in user.", + "displayName": "Read files in all site collections", + "id": "01d4889c-1287-42c6-ac1f-5d1e02578ef6", + "origin": "Application", + "value": "Files.Read.All" + }, + { + "description": "Allows the app to read the identity risk event information for your organization without a signed in user.", + "displayName": "Read all identity risk event information", + "id": "6e472fd1-ad78-48da-a0f0-97ab2c6b769e", + "origin": "Application", + "value": "IdentityRiskEvent.Read.All" + }, + { + "description": "Allows the app to read a limited subset of properties from both the structure of schools and classes in the organization's roster and education-specific information about all users. Includes name, status, role, email address and photo.", + "displayName": "Read a limited subset of the organization's roster", + "id": "0d412a8c-a06c-439f-b3ec-8abcf54d2f96", + "origin": "Application", + "value": "EduRoster.ReadBasic.All" + }, + { + "description": "Allows the app to read the structure of schools and classes in the organization's roster and education-specific information about all users to be read.", + "displayName": "Read the organization's roster", + "id": "e0ac9e1b-cb65-4fc5-87c5-1a8bc181f648", + "origin": "Application", + "value": "EduRoster.Read.All" + }, + { + "description": "Allows the app to read and write the structure of schools and classes in the organization's roster and education-specific information about all users to be read and written.", + "displayName": "Read and write the organization's roster", + "id": "d1808e82-ce13-47af-ae0d-f9b254e6d58a", + "origin": "Application", + "value": "EduRoster.ReadWrite.All" + }, + { + "description": "Read the state and settings of all Microsoft education apps.", + "displayName": "Read Education app settings", + "id": "7c9db06a-ec2d-4e7b-a592-5a1e30992566", + "origin": "Application", + "value": "EduAdministration.Read.All" + }, + { + "description": "Manage the state and settings of all Microsoft education apps.", + "displayName": "Manage education app settings", + "id": "9bc431c3-b8bc-4a8d-a219-40f10f92eff6", + "origin": "Application", + "value": "EduAdministration.ReadWrite.All" + }, + { + "description": "Allows the app to read the identity risky user information for your organization without a signed in user.", + "displayName": "Read all identity risky user information", + "id": "dc5007c0-2d7d-4c42-879c-2dab87571379", + "origin": "Application", + "value": "IdentityRiskyUser.Read.All" + }, + { + "description": "Allows the app to read and update user profiles without a signed in user.", + "displayName": "Read and write all users' full profiles", + "id": "741f803b-c850-494e-b5df-cde7c675a1ca", + "origin": "Application", + "value": "User.ReadWrite.All" + }, + { + "description": "Allows the app to read user profiles without a signed in user.", + "displayName": "Read all users' full profiles", + "id": "df021288-bdef-4463-88db-98f22de89214", + "origin": "Application", + "value": "User.Read.All" + }, + { + "description": "Allows the app to read and query your audit log activities, without a signed-in user.", + "displayName": "Read all audit log data", + "id": "b0afded3-3588-46d8-8b3d-9842eff778da", + "origin": "Application", + "value": "AuditLog.Read.All" + }, + { + "description": "Allows the app to create other applications, and fully manage those applications (read, update, update application secrets and delete), without a signed-in user. \u00a0It cannot update any apps that it is not an owner of.", + "displayName": "Manage apps that this app creates or owns", + "id": "18a4783c-866b-4cc7-a460-3d5e5662c884", + "origin": "Application", + "value": "Application.ReadWrite.OwnedBy" + }, + { + "description": "Allows the app to export data (e.g. customer content or system-generated logs), associated with any user in your company, when the app is used by a privileged user (e.g. a Company Administrator).", + "displayName": "Export user's data", + "id": "405a51b5-8d8d-430b-9842-8be4b0e9f324", + "origin": "Application", + "value": "User.Export.All" + }, + { + "description": "Allows the app to read, update, delete and perform actions on programs and program controls in the organization, without a signed-in user.", + "displayName": "Manage all programs", + "id": "60a901ed-09f7-4aa5-a16e-7dd3d6f9de36", + "origin": "Application", + "value": "ProgramControl.ReadWrite.All" + }, + { + "description": "Allows the app to read programs and program controls in the organization, without a signed-in user.", + "displayName": "Read all programs", + "id": "eedb7fdd-7539-4345-a38b-4839e4a84cbd", + "origin": "Application", + "value": "ProgramControl.Read.All" + }, + { + "description": "Allows the app to read, update, delete and perform actions on access reviews, reviewers, decisions and settings in the organization, without a signed-in user.", + "displayName": "Manage all access reviews", + "id": "ef5f7d5c-338f-44b0-86c3-351f46c8bb5f", + "origin": "Application", + "value": "AccessReview.ReadWrite.All" + }, + { + "description": "Allows the app to read access reviews, reviewers, decisions and settings in the organization, without a signed-in user.", + "displayName": "Read all access reviews", + "id": "d07a8cc0-3d51-4b77-b3b0-32704d1f69fa", + "origin": "Application", + "value": "AccessReview.Read.All" + }, + { + "description": "Allows an app to read all service usage reports without a signed-in user. Services that provide usage reports include Office 365 and Azure Active Directory.", + "displayName": "Read all usage reports", + "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", + "origin": "Application", + "value": "Reports.Read.All" + }, + { + "description": "Allows the app to read any user's scored list of relevant people, without a signed-in user. The list can include local contacts, contacts from social networking, your organization's directory, and people from recent communications (such as email and Skype).", + "displayName": "Read all users' relevant people lists", + "id": "b528084d-ad10-4598-8b93-929746b4d7d6", + "origin": "Application", + "value": "People.Read.All" + }, + { + "description": "Allows the app to update Microsoft Teams 1-to-1 or group chat messages by patching a set of Data Loss Prevention (DLP) policy violation properties to handle the output of DLP processing.", + "displayName": "Flag chat messages for violating policy", + "id": "7e847308-e030-4183-9899-5235d7270f58", + "origin": "Application", + "value": "Chat.UpdatePolicyViolation.All" + }, + { + "description": "Allows the app to read all 1-to-1 or group chat messages in Microsoft Teams.", + "displayName": "Read all chat messages", + "id": "6b7d71aa-70aa-4810-a8d9-5d9fb2830017", + "origin": "Application", + "value": "Chat.Read.All" + }, + { + "description": "Allows the app to read all channel messages in Microsoft Teams", + "displayName": "Read all channel messages", + "id": "7b2449af-6ccd-4f4d-9f78-e550c193f0d1", + "origin": "Application", + "value": "ChannelMessage.Read.All" + }, + { + "description": "Allows the app to update Microsoft Teams channel messages by patching a set of Data Loss Prevention (DLP) policy violation properties to handle the output of DLP processing.", + "displayName": "Flag channel messages for violating policy", + "id": "4d02b0cc-d90b-441f-8d82-4fb55c34d6bb", + "origin": "Application", + "value": "ChannelMessage.UpdatePolicyViolation.All" + }, + { + "description": "Allows the app to create, read, update and delete applications and service principals without a signed-in user. Does not allow management of consent grants.", + "displayName": "Read and write all applications", + "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", + "origin": "Application", + "value": "Application.ReadWrite.All" + }, + { + "description": "Allows the app to create, read, update, and delete user's mailbox settings without a signed-in user. Does not include permission to send mail.", + "displayName": "Read and write all user mailbox settings", + "id": "6931bccd-447a-43d1-b442-00a195474933", + "origin": "Application", + "value": "MailboxSettings.ReadWrite" + }, + { + "description": "Allows the app to read and write all domain properties without a signed in user. \u00a0Also allows the app to add, \u00a0verify and remove domains.", + "displayName": "Read and write domains", + "id": "7e05723c-0bb0-42da-be95-ae9f08a6e53c", + "origin": "Application", + "value": "Domain.ReadWrite.All" + }, + { + "description": "Allows the app to read user's mailbox settings without a signed-in user. Does not include permission to send mail.", + "displayName": "Read all user mailbox settings", + "id": "40f97065-369a-49f4-947c-6a255697ae91", + "origin": "Application", + "value": "MailboxSettings.Read" + }, + { + "description": "Allows the app to read mail in all mailboxes without a signed-in user.", + "displayName": "Read mail in all mailboxes", + "id": "810c84a8-4a9e-49e6-bf7d-12d183f40d01", + "origin": "Application", + "value": "Mail.Read" + }, + { + "description": "Allows the app to create, read, update, and delete mail in all mailboxes without a signed-in user. Does not include permission to send mail.", + "displayName": "Read and write mail in all mailboxes", + "id": "e2a3a72e-5f79-4c64-b1b1-878b674786c9", + "origin": "Application", + "value": "Mail.ReadWrite" + }, + { + "description": "Allows the app to send mail as any user without a signed-in user.", + "displayName": "Send mail as any user", + "id": "b633e1c5-b582-4048-a93e-9f11b44c7e96", + "origin": "Application", + "value": "Mail.Send" + }, + { + "description": "Allows the app to read all contacts in all mailboxes without a signed-in user.", + "displayName": "Read contacts in all mailboxes", + "id": "089fe4d0-434a-44c5-8827-41ba8a0b17f5", + "origin": "Application", + "value": "Contacts.Read" + }, + { + "description": "Allows the app to create, read, update, and delete all contacts in all mailboxes without a signed-in user.", + "displayName": "Read and write contacts in all mailboxes", + "id": "6918b873-d17a-4dc1-b314-35f528134491", + "origin": "Application", + "value": "Contacts.ReadWrite" + }, + { + "description": "Allows the app to read data in your organization's directory, such as users, groups and apps, without a signed-in user.", + "displayName": "Read directory data", + "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", + "origin": "Application", + "value": "Directory.Read.All" + }, + { + "description": "Allows the app to read and write data in your organization's directory, such as users, and groups, without a signed-in user. Does not allow user or group deletion.", + "displayName": "Read and write directory data", + "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", + "origin": "Application", + "value": "Directory.ReadWrite.All" + }, + { + "description": "Allows the app to read and write all device properties without a signed in user. Does not allow device creation, device deletion or update of device alternative security identifiers.", + "displayName": "Read and write devices", + "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", + "origin": "Application", + "value": "Device.ReadWrite.All" + }, + { + "description": "Allows the app to read events of all calendars without a signed-in user.", + "displayName": "Read calendars in all mailboxes", + "id": "798ee544-9d2d-430c-a058-570e29e34338", + "origin": "Application", + "value": "Calendars.Read" + }, + { + "description": "Allows the app to create, read, update, and delete events of all calendars without a signed-in user.", + "displayName": "Read and write calendars in all mailboxes", + "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", + "origin": "Application (Office 365 Exchange Online)", + "value": "Calendars.ReadWrite.All" + }, + { + "description": "Allows the app to create, read, update, and delete user's mailbox settings without a signed-in user. Does not include permission to send mail.", + "displayName": "Read and write all user mailbox settings", + "id": "f9156939-25cd-4ba8-abfe-7fabcf003749", + "origin": "Application (Office 365 Exchange Online)", + "value": "Mailbox.Settings.ReadWrite" + }, + { + "description": "Allows the app to read your organization's user flows, without a signed-in user.", + "displayName": "Read all identity user flows", + "id": "1b0c317f-dd31-4305-9932-259a8b6e8099", + "origin": "Application", + "value": "IdentityUserFlow.Read.All" + }, + { + "description": "Allows the app to read or write your organization's user flows, without a signed-in user.", + "displayName": "Read and write all identity user flows", + "id": "65319a09-a2be-469d-8782-f6b07debf789", + "origin": "Application", + "value": "IdentityUserFlow.ReadWrite.All" + }, + { + "description": "Allows the app to read and create online meetings as an application in your organization.", + "displayName": "Read and create online meetings", + "id": "b8bb2037-6e08-44ac-a4ea-4674e010e2a4", + "origin": "Application", + "value": "OnlineMeetings.ReadWrite.All" + }, + { + "description": "Allows the app to read online meeting details in your organization, without a signed-in user.", + "displayName": "Read online meeting details", + "id": "c1684f21-1984-47fa-9d61-2dc8c296bb70", + "origin": "Application", + "value": "OnlineMeetings.Read.All" + }, + { + "description": "Allows the app to get direct access to media streams in a call, without a signed-in user.", + "displayName": "Access media streams in a call as an app", + "id": "a7a681dc-756e-4909-b988-f160edc6655f", + "origin": "Application", + "value": "Calls.AccessMedia.All" + }, + { + "description": "Allows the app to anonymously join group calls and scheduled meetings in your organization, without a signed-in user. \u00a0The app will be joined as a guest to meetings in your organization.", + "displayName": "Join group calls and meetings as a guest", + "id": "fd7ccf6b-3d28-418b-9701-cd10f5cd2fd4", + "origin": "Application", + "value": "Calls.JoinGroupCallAsGuest.All" + }, + { + "description": "Allows the app to join group calls and scheduled meetings in your organization, without a signed-in user. \u00a0The app will be joined with the privileges of a directory user to meetings in your organization.", + "displayName": "Join group calls and meetings as an app", + "id": "f6b49018-60ab-4f81-83bd-22caeabfed2d", + "origin": "Application", + "value": "Calls.JoinGroupCall.All" + }, + { + "description": "Allows the app to place outbound calls to multiple users and add participants to meetings in your organization, without a signed-in user.", + "displayName": "Initiate outgoing group calls from the app", + "id": "4c277553-8a09-487b-8023-29ee378d8324", + "origin": "Application", + "value": "Calls.InitiateGroupCall.All" + }, + { + "description": "Allows the app to place outbound calls to a single user and transfer calls to users in your organization\u2019s directory, without a signed-in user.", + "displayName": "Initiate outgoing 1 to 1 calls from the app", + "id": "284383ee-7f6e-4e40-a2a8-e85dcb029101", + "origin": "Application", + "value": "Calls.Initiate.All" + }, + { + "description": "Allows the app to read all organizational contacts without a signed-in user. These contacts are managed by the organization and are different from a user's personal contacts.", + "displayName": "Read organizational contacts", + "id": "e1a88a34-94c4-4418-be12-c87b00e26bea", + "origin": "Application", + "value": "OrgContact.Read.All" + }, + { + "description": "Allows the app to read and write the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune, without a signed-in user.", + "displayName": "Read and write Microsoft Intune apps", + "id": "78145de6-330d-4800-a6ce-494ff2d33d07", + "origin": "Application", + "value": "DeviceManagementApps.ReadWrite.All" + }, + { + "description": "Allows the app to read and write properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups, without a signed-in user.", + "displayName": "Read and write Microsoft Intune device configuration and policies", + "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", + "origin": "Application", + "value": "DeviceManagementConfiguration.ReadWrite.All" + }, + { + "description": "Allows the app to perform remote high impact actions such as wiping the device or resetting the passcode on devices managed by Microsoft Intune, without a signed-in user.", + "displayName": "Perform user-impacting remote actions on Microsoft Intune devices", + "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", + "origin": "Application", + "value": "DeviceManagementManagedDevices.PrivilegedOperations.All" + }, + { + "description": "Allows the app to read and write the properties of devices managed by Microsoft Intune, without a signed-in user. Does not allow high impact operations such as remote wipe and password reset on the device\u2019s owner", + "displayName": "Read and write Microsoft Intune devices", + "id": "243333ab-4d21-40cb-a475-36241daa0842", + "origin": "Application", + "value": "DeviceManagementManagedDevices.ReadWrite.All" + }, + { + "description": "Allows the app to read and write the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings, without a signed-in user.", + "displayName": "Read and write Microsoft Intune RBAC settings", + "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", + "origin": "Application", + "value": "DeviceManagementRBAC.ReadWrite.All" + }, + { + "description": "Allows the app to read and write Microsoft Intune service properties including device enrollment and third party service connection configuration, without a signed-in user.", + "displayName": "Read and write Microsoft Intune configuration", + "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", + "origin": "Application", + "value": "DeviceManagementServiceConfig.ReadWrite.All" + }, + { + "description": "Allows the app to manage permission grants for application permissions to any API (including Microsoft Graph) and application assignments for any app, without a signed-in user.", + "displayName": "Manage app permission grants and app role assignments", + "id": "06b708a9-e830-4db3-a914-8e69da51d44f", + "origin": "Application", + "value": "AppRoleAssignment.ReadWrite.All" + }, + { + "description": "Allows the app to manage permission grants for delegated permissions exposed by any API (including Microsoft Graph), without a signed-in user.", + "displayName": "Manage all delegated permission grants", + "id": "8e8e4742-1d95-4f68-9d56-6ee75648c72a", + "origin": "Application", + "value": "DelegatedPermissionGrant.ReadWrite.All" + }, + { + "description": "Allows the app to read all users' teamwork activity feed, without a signed-in user.", + "displayName": "Read all users' teamwork activity feed", + "id": "70dec828-f620-4914-aa83-a29117306807", + "origin": "Application", + "value": "TeamsActivity.Read.All" + }, + { + "description": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD built-in and custom administrative roles in your organization, without a signed-in user.", + "displayName": "Read privileged access to Azure AD roles", + "id": "4cdc2547-9148-4295-8d11-be0db1391d6b", + "origin": "Application", + "value": "PrivilegedAccess.Read.AzureAD" + }, + { + "description": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups in your organization, without a signed-in user.", + "displayName": "Read privileged access to Azure AD groups", + "id": "01e37dc9-c035-40bd-b438-b2879c4870a6", + "origin": "Application", + "value": "PrivilegedAccess.Read.AzureADGroup" + }, + { + "description": "Allows the app to read time-based assignment and just-in-time elevation of user privileges to audit Azure resources in your organization, without a signed-in user.", + "displayName": "Read privileged access to Azure resources", + "id": "5df6fe86-1be0-44eb-b916-7bd443a71236", + "origin": "Application", + "value": "PrivilegedAccess.Read.AzureResources" + }, + { + "description": "Allows the app to request and manage time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD built-in and custom administrative roles in your organization, without a signed-in user.", + "displayName": "Read and write privileged access to Azure AD roles", + "id": "854d9ab1-6657-4ec8-be45-823027bcd009", + "origin": "Application", + "value": "PrivilegedAccess.ReadWrite.AzureAD" + }, + { + "description": "Allows the app to request and manage time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups in your organization, without a signed-in user.", + "displayName": "Read and write privileged access to Azure AD groups", + "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", + "origin": "Application", + "value": "PrivilegedAccess.ReadWrite.AzureADGroup" + }, + { + "description": "Allows the app to request and manage time-based assignment and just-in-time elevation of Azure resources (like your subscriptions, resource groups, storage, compute) in your organization, without a signed-in user.", + "displayName": "Read and write privileged access to Azure resources", + "id": "6f9d5abc-2db6-400b-a267-7de22a40fb87", + "origin": "Application", + "value": "PrivilegedAccess.ReadWrite.AzureResources" + }, + { + "description": "Allows the app to read all the indicators for your organization, without a signed-in user.", + "displayName": "Read all threat indicators", + "id": "197ee4e9-b993-4066-898f-d6aecc55125b", + "origin": "Application", + "value": "ThreatIndicators.Read.All" + }, + { + "description": "Allows the app to send, read, update and delete user\u2019s notifications, without a signed-in user.", + "displayName": "Deliver and manage all user's notifications", + "id": "4e774092-a092-48d1-90bd-baad67c7eb47", + "origin": "Application", + "value": "UserNotification.ReadWrite.CreatedByApp" + }, + { + "description": "Allows the app to read all applications and service principals without a signed-in user.", + "displayName": "Read all applications", + "id": "9a5d68dd-52b0-4cc2-bd40-abcf44ac3a30", + "origin": "Application", + "value": "Application.Read.All" + }, + { + "description": "Allows the app to read memberships and basic group properties for all groups without a signed-in user.", + "displayName": "Read all group memberships", + "id": "98830695-27a2-44f7-8c18-0c3ebc9698f6", + "origin": "Application", + "value": "GroupMember.Read.All" + }, + { + "description": "Allows the app to list groups, read basic properties, read and update the membership of the groups this app has access to without a signed-in user. Group properties and owners cannot be updated and groups cannot be deleted.", + "displayName": "Read and write all group memberships", + "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", + "origin": "Application", + "value": "GroupMember.ReadWrite.All" + }, + { + "description": "Allows the app to create groups without a signed-in user.", + "displayName": "Create groups", + "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", + "origin": "Application", + "value": "Group.Create" + }, + { + "description": "Allows an app to read your organization's threat assessment requests, without a signed-in user.", + "displayName": "Read threat assessment requests", + "id": "f8f035bb-2cce-47fb-8bf5-7baf3ecbee48", + "origin": "Application", + "value": "ThreatAssessment.Read.All" + }, + { + "description": "Allows the app to read all schedules, schedule groups, shifts and associated entities in the Teams or Shifts application without a signed-in user.", + "displayName": "Read all schedule items", + "id": "7b2ebf90-d836-437f-b90d-7b62722c4456", + "origin": "Application", + "value": "Schedule.Read.All" + }, + { + "description": "Allows the app to manage all schedules, schedule groups, shifts and associated entities in the Teams or Shifts application without a signed-in user.", + "displayName": "Read and write all schedule items", + "id": "b7760610-0545-4e8a-9ec3-cce9e63db01c", + "origin": "Application", + "value": "Schedule.ReadWrite.All" + }, + { + "description": "Allows the app to read call records for all calls and online meetings without a signed-in user.", + "displayName": "Read all call records", + "id": "45bbb07e-7321-4fd7-a8f6-3ff27e6a81c8", + "origin": "Application", + "value": "CallRecords.Read.All" + }, + { + "description": "Allows the app to read and write your organization's conditional access policies, without a signed-in user.", + "displayName": "Read and write your organization's conditional access policies", + "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", + "origin": "Application", + "value": "Policy.ReadWrite.ConditionalAccess" + }, + { + "description": "Allows the application to read and write authentication methods of all users in your organization, without a signed-in user. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods", + "displayName": "Read and write all users' authentication methods ", + "id": "50483e42-d915-4231-9639-7fdb7fd190e5", + "origin": "Application", + "value": "UserAuthenticationMethod.ReadWrite.All" + }, + { + "description": " Allows the app to read authentication methods of all users in your organization, without a signed-in user. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", + "displayName": " Read all users' authentication methods", + "id": "38d9df27-64da-44fd-b7c5-a6fbac20248f", + "origin": "Application", + "value": "UserAuthenticationMethod.Read.All" + }, + { + "description": "Allows the app to create tabs in any team in Microsoft Teams, without a signed-in user. This does not grant the ability to read, modify or delete tabs after they are created, or give access to the content inside the tabs.", + "displayName": "Create tabs in Microsoft Teams.", + "id": "49981c42-fd7b-4530-be03-e77b21aed25e", + "origin": "Application", + "value": "TeamsTab.Create" + }, + { + "description": "Read the names and settings of tabs inside any team in Microsoft Teams, without a signed-in user. This does not give access to the content inside the tabs. ", + "displayName": "Read tabs in Microsoft Teams.", + "id": "46890524-499a-4bb2-ad64-1476b4f3e1cf", + "origin": "Application", + "value": "TeamsTab.Read.All" + }, + { + "description": "Read and write tabs in any team in Microsoft Teams, without a signed-in user. This does not give access to the content inside the tabs.", + "displayName": "Read and write tabs in Microsoft Teams.", + "id": "a96d855f-016b-47d7-b51c-1218a98d791c", + "origin": "Application", + "value": "TeamsTab.ReadWrite.All" + }, + { + "description": "Allows the app to read all domain properties without a signed-in user.", + "displayName": "Read domains", + "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", + "origin": "Application", + "value": "Domain.Read.All" + }, + { + "description": "Allows the app to read and write your organization's application configuration policies, without a signed-in user. This includes policies such as activityBasedTimeoutPolicy, claimsMappingPolicy, homeRealmDiscoveryPolicy, tokenIssuancePolicy and tokenLifetimePolicy.", + "displayName": "Read and write your organization's application configuration policies", + "id": "be74164b-cff1-491c-8741-e671cb536e13", + "origin": "Application", + "value": "Policy.ReadWrite.ApplicationConfiguration" + }, + { + "description": "Allows the app to read your organization's devices' configuration information without a signed-in user.", + "displayName": "Read all devices", + "id": "7438b122-aefc-4978-80ed-43db9fcc7715", + "origin": "Application", + "value": "Device.Read.All" + }, + { + "description": "Allows the app to read, update and delete identities that are associated with a user's account, without a signed in user. This controls the identities users can sign-in with.", + "displayName": "Manage all users' identities", + "id": "c529cfca-c91b-489c-af2b-d92990b66ce6", + "origin": "Application", + "value": "User.ManageIdentities.All" + }, + { + "description": "Allows the app to read all users' shift schedule preferences without a signed-in user.", + "displayName": "Read all user shift preferences", + "id": "de023814-96df-4f53-9376-1e2891ef5a18", + "origin": "Application", + "value": "UserShiftPreferences.Read.All" + }, + { + "description": "Allows the app to manage all users' shift schedule preferences without a signed-in user.", + "displayName": "Read and write all user shift preferences", + "id": "d1eec298-80f3-49b0-9efb-d90e224798ac", + "origin": "Application", + "value": "UserShiftPreferences.ReadWrite.All" + }, + { + "description": "Allows the app to read all the OneNote notebooks in your organization, without a signed-in user.", + "displayName": "Read and write all OneNote notebooks", + "id": "0c458cef-11f3-48c2-a568-c66751c238c0", + "origin": "Application", + "value": "Notes.ReadWrite.All" + }, + { + "description": "Allows the app to have full control of all site collections without a signed in user.", + "displayName": "Have full control of all site collections", + "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", + "origin": "Application", + "value": "Sites.FullControl.All" + }, + { + "description": "Allows the app to create or delete document libraries and lists in all site collections without a signed in user.", + "displayName": "Create, edit, and delete items and lists in all site collections", + "id": "0c0bf378-bf22-4481-8f81-9e89a9b4960a", + "origin": "Application", + "value": "Sites.Manage.All" + }, + { + "description": "Allows the app to read access packages and related entitlement management resources without a signed-in user.", + "displayName": "Read all entitlement management resources", + "id": "c74fd47d-ed3c-45c3-9a9e-b8676de685d2", + "origin": "Application", + "value": "EntitlementManagement.Read.All" + }, + { + "description": "Allows the app to read and write access packages and related entitlement management resources without a signed-in user.", + "displayName": "Read and write all entitlement management resources", + "id": "9acd699f-1e81-4958-b001-93b1d2506e19", + "origin": "Application", + "value": "EntitlementManagement.ReadWrite.All" + }, + { + "description": "Create channels in any team, without a signed-in user.", + "displayName": "Create channels", + "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", + "origin": "Application", + "value": "Channel.Create" + }, + { + "description": "Delete channels in any team, without a signed-in user.", + "displayName": "Delete channels", + "id": "6a118a39-1227-45d4-af0c-ea7b40d210bc", + "origin": "Application", + "value": "Channel.Delete.All" + }, + { + "description": "Read all channel names, channel descriptions, and channel settings, without a signed-in user.", + "displayName": "Read the names, descriptions, and settings of all channels", + "id": "c97b873f-f59f-49aa-8a0e-52b32d762124", + "origin": "Application", + "value": "ChannelSettings.Read.All" + }, + { + "description": "Read and write the names, descriptions, and settings of all channels, without a signed-in user.", + "displayName": "Read and write the names, descriptions, and settings of all channels", + "id": "243cded2-bd16-4fd6-a953-ff8177894c3d", + "origin": "Application", + "value": "ChannelSettings.ReadWrite.All" + }, + { + "description": "Get a list of all teams, without a signed-in user.", + "displayName": "Get a list of all teams", + "id": "2280dda6-0bfd-44ee-a2f4-cb867cfc4c1e", + "origin": "Application", + "value": "Team.ReadBasic.All" + }, + { + "description": "Read all channel names and channel descriptions, without a signed-in user.", + "displayName": "Read the names and descriptions of all channels", + "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", + "origin": "Application", + "value": "Channel.ReadBasic.All" + }, + { + "description": "Read and change all teams' settings, without a signed-in user.", + "displayName": "Read and change all teams' settings", + "id": "bdd80a03-d9bc-451d-b7c4-ce7c63fe3c8f", + "origin": "Application", + "value": "TeamSettings.ReadWrite.All" + }, + { + "description": "Read all team's settings, without a signed-in user.", + "displayName": "Read all teams' settings", + "id": "242607bd-1d2c-432c-82eb-bdb27baa23ab", + "origin": "Application", + "value": "TeamSettings.Read.All" + }, + { + "description": "Read the members of all teams, without a signed-in user.", + "displayName": "Read the members of all teams", + "id": "660b7406-55f1-41ca-a0ed-0b035e182f3e", + "origin": "Application", + "value": "TeamMember.Read.All" + }, + { + "description": "Add and remove members from all teams, without a signed-in user. Also allows changing a team member's role, for example from owner to non-owner.", + "displayName": "Add and remove members from all teams", + "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", + "origin": "Application", + "value": "TeamMember.ReadWrite.All" + }, + { + "description": "Read the members of all channels, without a signed-in user.", + "displayName": "Read the members of all channels", + "id": "3b55498e-47ec-484f-8136-9013221c06a9", + "origin": "Application", + "value": "ChannelMember.Read.All" + }, + { + "description": "Add and remove members from all channels, without a signed-in user. Also allows changing a member's role, for example from owner to non-owner.", + "displayName": "Add and remove members from all channels", + "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", + "origin": "Application", + "value": "ChannelMember.ReadWrite.All" + }, + { + "description": "Allows the app to read and write all authentication flow policies for the tenant, without a signed-in user.", + "displayName": "Read and write authentication flow policies", + "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", + "origin": "Application", + "value": "Policy.ReadWrite.AuthenticationFlows" + }, + { + "description": "Allows the app to read and write all authentication method policies for the tenant, without a signed-in user.\u00a0", + "displayName": "Read and write all authentication method policies\u00a0", + "id": "29c18626-4985-4dcd-85c0-193eef327366", + "origin": "Application", + "value": "Policy.ReadWrite.AuthenticationMethod" + }, + { + "description": "Allows the app to read and write your organization's authorization policy without a signed in user. For example, authorization policies can control some of the permissions that the out-of-the-box user role has by default.", + "displayName": "Read and write your organization's authorization policy", + "id": "fb221be6-99f2-473f-bd32-01c6a0e9ca3b", + "origin": "Application", + "value": "Policy.ReadWrite.Authorization" + }, + { + "description": "Read names and members of all one-to-one and group chats in Microsoft Teams, without a signed-in user.", + "displayName": "Read names and members of all chat threads", + "id": "b2e060da-3baf-4687-9611-f4ebc0f0cbde", + "origin": "Application", + "value": "Chat.ReadBasic.All" + }, + { + "description": "Allows the app to read policies related to consent and permission grants for applications, without a signed-in user.", + "displayName": "Read consent and permission grant policies", + "id": "9e640839-a198-48fb-8b9a-013fd6f6cbcd", + "origin": "Application", + "value": "Policy.Read.PermissionGrant" + }, + { + "description": "Allows the app to manage policies related to consent and permission grants for applications, without a signed-in user.", + "displayName": "Manage consent and permission grant policies", + "id": "a402ca1c-2696-4531-972d-6e5ee4aa11ea", + "origin": "Application", + "value": "Policy.ReadWrite.PermissionGrant" + }, + { + "description": "Allows the application to read printers without a signed-in user.\u00a0", + "displayName": "Read printers", + "id": "9709bb33-4549-49d4-8ed9-a8f65e45bb0f", + "origin": "Application", + "value": "Printer.Read.All" + }, + { + "description": "Allows the application to read and update printers without a signed-in user. Does not allow creating (registering) or deleting (unregistering) printers.", + "displayName": "Read and update printers", + "id": "f5b3f73d-6247-44df-a74c-866173fddab0", + "origin": "Application", + "value": "Printer.ReadWrite.All" + }, + { + "description": "Allows the application to perform advanced operations like redirecting a print job to another printer without a signed-in user. Also allows the application to read and update the metadata of print jobs.", + "displayName": "Perform advanced operations on print jobs", + "id": "58a52f47-9e36-4b17-9ebe-ce4ef7f3e6c8", + "origin": "Application", + "value": "PrintJob.Manage.All" + }, + { + "description": "Allows the application to read the metadata and document content of print jobs without a signed-in user.\u00a0", + "displayName": "Read print jobs", + "id": "ac6f956c-edea-44e4-bd06-64b1b4b9aec9", + "origin": "Application", + "value": "PrintJob.Read.All" + }, + { + "description": "Allows the application to read the metadata of print jobs without a signed-in user.\u00a0Does not allow access to print job document content.", + "displayName": "Read basic information for print jobs", + "id": "fbf67eee-e074-4ef7-b965-ab5ce1c1f689", + "origin": "Application", + "value": "PrintJob.ReadBasic.All" + }, + { + "description": "Allows the application to read and update the metadata and document content of print jobs without a signed-in user.", + "displayName": "Read and write print jobs", + "id": "5114b07b-2898-4de7-a541-53b0004e2e13", + "origin": "Application", + "value": "PrintJob.ReadWrite.All" + }, + { + "description": "Allows the application to read and update the metadata of print jobs without a signed-in user.\u00a0Does not allow access to print job document content.", + "displayName": "Read and write basic information for print jobs", + "id": "57878358-37f4-4d3a-8c20-4816e0d457b1", + "origin": "Application", + "value": "PrintJob.ReadWriteBasic.All" + }, + { + "description": "Allows the application to read and update print task definitions without a signed-in user.\u00a0", + "displayName": "Read, write and update print task definitions", + "id": "456b71a7-0ee0-4588-9842-c123fcc8f664", + "origin": "Application", + "value": "PrintTaskDefinition.ReadWrite.All" + }, + { + "description": "Allows the app to create chat and channel messages, without a signed in user. The app specifies which user appears as the sender, and can backdate the message to appear as if it was sent long ago. The messages can be sent to any chat or channel in the organization.", + "displayName": "Create chat and channel messages with anyone's identity and with any timestamp", + "id": "dfb0dd15-61de-45b2-be36-d6a69fba3c79", + "origin": "Application", + "value": "Teamwork.Migrate.All" + }, + { + "description": "Allows the app to read the Teams apps that are installed in any chat, without a signed-in user. Does not give the ability to read application-specific settings.", + "displayName": "Read installed Teams apps for all chats", + "id": "cc7e7635-2586-41d6-adaa-a8d3bcad5ee5", + "origin": "Application", + "value": "TeamsAppInstallation.ReadForChat.All" + }, + { + "description": "Allows the app to read the Teams apps that are installed in any team, without a signed-in user. Does not give the ability to read application-specific settings.", + "displayName": "Read installed Teams apps for all teams", + "id": "1f615aea-6bf9-4b05-84bd-46388e138537", + "origin": "Application", + "value": "TeamsAppInstallation.ReadForTeam.All" + }, + { + "description": "Allows the app to read the Teams apps that are installed for any user, without a signed-in user. Does not give the ability to read application-specific settings.", + "displayName": "Read installed Teams apps for all users", + "id": "9ce09611-f4f7-4abd-a629-a05450422a97", + "origin": "Application", + "value": "TeamsAppInstallation.ReadForUser.All" + }, + { + "description": "Allows the app to read, install, upgrade, and uninstall Teams apps in any chat, without a signed-in user. Does not give the ability to read application-specific settings.", + "displayName": "Manage Teams apps for all chats", + "id": "9e19bae1-2623-4c4f-ab6e-2664615ff9a0", + "origin": "Application", + "value": "TeamsAppInstallation.ReadWriteForChat.All" + }, + { + "description": "Allows the app to read, install, upgrade, and uninstall Teams apps in any team, without a signed-in user. Does not give the ability to read application-specific settings.", + "displayName": "Manage Teams apps for all teams", + "id": "5dad17ba-f6cc-4954-a5a2-a0dcc95154f0", + "origin": "Application", + "value": "TeamsAppInstallation.ReadWriteForTeam.All" + }, + { + "description": "Allows the app to read, install, upgrade, and uninstall Teams apps for any user, without a signed-in user. Does not give the ability to read application-specific settings.", + "displayName": "Manage Teams apps for all users", + "id": "74ef0291-ca83-4d02-8c7e-d2391e6a444f", + "origin": "Application", + "value": "TeamsAppInstallation.ReadWriteForUser.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall itself for any chat, without a signed-in user.", + "displayName": "Allow the Teams app to manage itself for all chats", + "id": "73a45059-f39c-4baf-9182-4954ac0e55cf", + "origin": "Application", + "value": "TeamsAppInstallation.ReadWriteSelfForChat.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall itself in any team, without a signed-in user.", + "displayName": "Allow the Teams app to manage itself for all teams", + "id": "9f67436c-5415-4e7f-8ac1-3014a7132630", + "origin": "Application", + "value": "TeamsAppInstallation.ReadWriteSelfForTeam.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall itself to any user, without a signed-in user.", + "displayName": "Allow the app to manage itself for all users", + "id": "908de74d-f8b2-4d6b-a9ed-2a17b3b78179", + "origin": "Application", + "value": "TeamsAppInstallation.ReadWriteSelfForUser.All" + }, + { + "description": "Allows the app to create teams without a signed-in user.\u00a0", + "displayName": "Create teams", + "id": "23fc2474-f741-46ce-8465-674744c5c361", + "origin": "Application", + "value": "Team.Create" + }, + { + "description": "Add and remove members from all teams, without a signed-in user. Does not allow adding or removing a member with the owner role. Additionally, does not allow the app to elevate an existing member to the owner role.", + "displayName": "Add and remove members with non-owner role for all teams", + "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", + "origin": "Application", + "value": "TeamMember.ReadWriteNonOwnerRole.All" + }, + { + "description": "Allows the app to read all term store data, without a signed-in user. This includes all sets, groups and terms in the term store.", + "displayName": "Read all term store data", + "id": "ea047cc2-df29-4f3e-83a3-205de61501ca", + "origin": "Application", + "value": "TermStore.Read.All" + }, + { + "description": "Allows the app to read, edit or write all term store data, without a signed-in user. This includes all sets, groups and terms in the term store.", + "displayName": "Read and write all term store data", + "id": "f12eb8d6-28e3-46e6-b2c0-b7e4dc69fc95", + "origin": "Application", + "value": "TermStore.ReadWrite.All" + }, + { + "description": "Allows the app to read your tenant's service health information, without a signed-in user. Health information may include service issues or service health overviews.", + "displayName": "Read service health", + "id": "79c261e0-fe76-4144-aad5-bdc68fbe4037", + "origin": "Application", + "value": "ServiceHealth.Read.All" + }, + { + "description": "Allows the app to read your tenant's service announcement messages, without a signed-in user. Messages may include information about new or changed features.", + "displayName": "Read service messages", + "id": "1b620472-6534-4fe6-9df2-4680e8aa28ec", + "origin": "Application", + "value": "ServiceMessage.Read.All" + }, + { + "description": "Allows the app to read all the short notes without a signed-in user.", + "displayName": "Read all users' short notes", + "id": "0c7d31ec-31ca-4f58-b6ec-9950b6b0de69", + "origin": "Application", + "value": "ShortNotes.Read.All" + }, + { + "description": "Allows the app to read, create, edit, and delete all the short notes without a signed-in user.", + "displayName": "Read, create, edit, and delete all users' short notes", + "id": "842c284c-763d-4a97-838d-79787d129bab", + "origin": "Application", + "value": "ShortNotes.ReadWrite.All" + }, + { + "description": "Allows the app to read your organization's conditional access policies, without a signed-in user.", + "displayName": "Read your organization's conditional access policies", + "id": "37730810-e9ba-4e46-b07e-8ca78d182097", + "origin": "Application", + "value": "Policy.Read.ConditionalAccess" + }, + { + "description": "Allows the app to read role-based access control (RBAC) settings for all RBAC providers without a signed-in user. This includes reading role definitions and role assignments.", + "displayName": "Read role management data for all RBAC providers", + "id": "c7fbd983-d9aa-4fa7-84b8-17382c103bc4", + "origin": "Application", + "value": "RoleManagement.Read.All" + }, + { + "description": "Allows the app to read all PSTN and direct routing call log data without a signed-in user.", + "displayName": "Read PSTN and direct routing call log data", + "id": "a2611786-80b3-417e-adaa-707d4261a5f0", + "origin": "Application", + "value": "CallRecord-PstnCalls.Read.All" + }, + { + "description": "Allows the app to read all one-to-one and group chats messages in Microsoft Teams, without a signed-in user.", + "displayName": "Read all chat messages", + "id": "b9bb2381-47a4-46cd-aafb-00cb12f68504", + "origin": "Application", + "value": "ChatMessage.Read.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs for any chat, without a signed-in user.", + "displayName": "Allow the Teams app to manage all tabs for all chats", + "id": "fd9ce730-a250-40dc-bd44-8dc8d20f39ea", + "origin": "Application", + "value": "TeamsTab.ReadWriteForChat.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs in any team, without a signed-in user.", + "displayName": "Allow the Teams app to manage all tabs for all teams", + "id": "6163d4f4-fbf8-43da-a7b4-060fe85ed148", + "origin": "Application", + "value": "TeamsTab.ReadWriteForTeam.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs for any user, without a signed-in user.", + "displayName": "Allow the app to manage all tabs for all users", + "id": "425b4b59-d5af-45c8-832f-bb0b7402348a", + "origin": "Application", + "value": "TeamsTab.ReadWriteForUser.All" + }, + { + "description": "Allows the app to read the API connectors used in user authentication flows, without a signed-in user.", + "displayName": "Read API connectors for authentication flows", + "id": "b86848a7-d5b1-41eb-a9b4-54a4e6306e97", + "origin": "Application", + "value": "APIConnectors.Read.All" + }, + { + "description": "Allows the app to read, create and manage the API connectors used in user authentication flows, without a signed-in user.", + "displayName": "Read and write API connectors for authentication flows", + "id": "1dfe531a-24a6-4f1b-80f4-7a0dc5a0a171", + "origin": "Application", + "value": "APIConnectors.ReadWrite.All" + }, + { + "description": "Read the members of all chats, without a signed-in user.", + "displayName": "Read the members of all chats", + "id": "a3410be2-8e48-4f32-8454-c29a7465209d", + "origin": "Application", + "value": "ChatMember.Read.All" + }, + { + "description": "Add and remove members from all chats, without a signed-in user.", + "displayName": "Add and remove members from all chats", + "id": "57257249-34ce-4810-a8a2-a03adf0c5693", + "origin": "Application", + "value": "ChatMember.ReadWrite.All" + }, + { + "description": "Allows the app to create chats without a signed-in user.\u00a0", + "displayName": "Create chats", + "id": "d9c48af6-9ad9-47ad-82c3-63757137b9af", + "origin": "Application", + "value": "Chat.Create" + }, + { + "description": "Allows the application to read tenant-wide print settings without a signed-in user.", + "displayName": "Read tenant-wide print settings", + "id": "b5991872-94cf-4652-9765-29535087c6d8", + "origin": "Application", + "value": "PrintSettings.Read.All" + }, + { + "description": "Allows an app to read and write all browser site lists configured for your organization, without a signed-in user.", + "displayName": "Read and write all browser site lists for your organization", + "id": "8349ca94-3061-44d5-9bfb-33774ea5e4f9", + "origin": "Application", + "value": "BrowserSiteLists.ReadWrite.All" + }, + { + "description": "Allows the application to read and change the tenant-level settings of SharePoint and OneDrive, without a signed-in user.", + "displayName": "Read and change SharePoint and OneDrive tenant settings", + "id": "19b94e34-907c-4f43-bde9-38b1909ed408", + "origin": "Application", + "value": "SharePointTenantSettings.ReadWrite.All" + }, + { + "description": "Allows the app to read your organization's authentication event listeners without a signed-in user.", + "displayName": "Read all authentication event listeners", + "id": "b7f6385c-6ce6-4639-a480-e23c42ed9784", + "origin": "Application", + "value": "EventListener.Read.All" + }, + { + "description": "Allows the app to read or write your organization's authentication event listeners without a signed-in user.", + "displayName": "Read and write all authentication event listeners", + "id": "0edf5e9e-4ce8-468a-8432-d08631d18c43", + "origin": "Application", + "value": "EventListener.ReadWrite.All" + }, + { + "description": "Allows the app to read your organization's custom authentication extensions without a signed-in user.", + "displayName": "Read all custom authentication extensions", + "id": "88bb2658-5d9e-454f-aacd-a3933e079526", + "origin": "Application", + "value": "CustomAuthenticationExtension.Read.All" + }, + { + "description": "Allows the app to read all users\u2019 tasks and task lists in your organization, without a signed-in user.", + "displayName": "Read all users\u2019 tasks and tasklist", + "id": "f10e1f91-74ed-437f-a6fd-d6ae88e26c1f", + "origin": "Application", + "value": "Tasks.Read.All" + }, + { + "description": "Allows the app to create, update, list, read and delete all workflows, tasks and related lifecycle workflows resources without a signed-in user.", + "displayName": "Read and write all lifecycle workflows resources", + "id": "5c505cf4-8424-4b8e-aa14-ee06e3bb23e3", + "origin": "Application", + "value": "LifecycleWorkflows.ReadWrite.All" + }, + { + "description": "Allows an app to read all bookmarks without a signed-in user.", + "displayName": "Read all bookmarks", + "id": "be95e614-8ef3-49eb-8464-1c9503433b86", + "origin": "Application", + "value": "Bookmark.Read.All" + }, + { + "description": "Allows the application to obtain basic tenant information about another target tenant within the Azure AD ecosystem without a signed-in user.", + "displayName": "Read cross-tenant basic information", + "id": "cac88765-0581-4025-9725-5ebc13f729ee", + "origin": "Application", + "value": "CrossTenantInformation.ReadBasic.All" + }, + { + "description": "Allows the application to list and query any shared user profile information associated with the current tenant without a signed-in user.\u00a0 It also permits the application to export and remove external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant without a signed-in user.", + "displayName": "Read all shared cross-tenant user profiles and export or delete their data", + "id": "306785c5-c09b-4ba0-a4ee-023f3da165cb", + "origin": "Application", + "value": "CrossTenantUserProfileSharing.ReadWrite.All" + }, + { + "description": "Allows the app to read all learning content in the organization's directory, without a signed-in user.", + "displayName": "Read all learning content", + "id": "8740813e-d8aa-4204-860e-2a0f8f84dbc8", + "origin": "Application", + "value": "LearningContent.Read.All" + }, + { + "description": "Allows the app to read and update the authentication context information in your organization without a signed-in user.", + "displayName": "Read and write all authentication context information", + "id": "a88eef72-fed0-4bf7-a2a9-f19df33f8b83", + "origin": "Application", + "value": "AuthenticationContext.ReadWrite.All" + }, + { + "description": "Allows the app to read all admin report settings, such as whether to display concealed information in reports, without a signed-in user.", + "displayName": "Read all admin report settings", + "id": "ee353f83-55ef-4b78-82da-555bfa2b4b95", + "origin": "Application", + "value": "ReportSettings.Read.All" + }, + { + "description": "Allows the app to read the members of all chats where the associated Teams application is installed, without a signed-in user.", + "displayName": "Read the members of all chats where the associated Teams application is installed.", + "id": "93e7c9e4-54c5-4a41-b796-f2a5adaacda7", + "origin": "Application", + "value": "ChatMember.Read.WhereInstalled" + }, + { + "description": "Allows the app to add and remove members from all chats where the associated Teams application is installed, without a signed-in user.", + "displayName": "Add and remove members from all chats where the associated Teams application is installed.", + "id": "e32c2cd9-0124-4e44-88fc-772cd98afbdb", + "origin": "Application", + "value": "ChatMember.ReadWrite.WhereInstalled" + }, + { + "description": "Allows the app to read your organization's threat submissions and to view threat submission policies without a signed-in user.", + "displayName": "Read all of the organization's threat submissions", + "id": "86632667-cd15-4845-ad89-48a88e8412e1", + "origin": "Application", + "value": "ThreatSubmission.Read.All" + }, + { + "description": "Allows an app to sign digests for data without a signed-in user.", + "displayName": "Sign digests for data", + "id": "cbe6c7e4-09aa-4b8d-b3c3-2dbb59af4b54", + "origin": "Application", + "value": "InformationProtectionContent.Sign.All" + }, + { + "description": "Allows the app to read your organization's threat submission policies without a signed-in user. Also allows the app to create new threat submission polices without a signed-in user.", + "displayName": "Read and write all of the organization's threat submission policies", + "id": "926a6798-b100-4a20-a22f-a4918f13951d", + "origin": "Application", + "value": "ThreatSubmissionPolicy.ReadWrite.All" + }, + { + "description": "Allows the app to read all one-to-one or group chat messages in Microsoft Teams for chats where the associated Teams application is installed, without a signed-in user.", + "displayName": "Read all chat messages for chats where the associated Teams application is installed.", + "id": "1c1b4c8e-3cc7-4c58-8470-9b92c9d5848b", + "origin": "Application", + "value": "Chat.Read.WhereInstalled" + }, + { + "description": "Allows the app to read and write all chat messages in Microsoft Teams for chats where the associated Teams application is installed, without a signed-in user.", + "displayName": "Read and write all chat messages for chats where the associated Teams application is installed.", + "id": "ad73ce80-f3cd-40ce-b325-df12c33df713", + "origin": "Application", + "value": "Chat.ReadWrite.WhereInstalled" + }, + { + "description": "Allows the app to read and update all Azure AD recommendations, without a signed-in user. ", + "displayName": "Read and update all Azure AD recommendations", + "id": "0e9eea12-4f01-45f6-9b8d-3ea4c8144158", + "origin": "Application", + "value": "DirectoryRecommendations.ReadWrite.All" + }, + { + "description": "Allows the app to read all recordings of all online meetings, without a signed-in user.", + "displayName": "Read all recordings of online meetings.", + "id": "a4a08342-c95d-476b-b943-97e100569c8d", + "origin": "Application", + "value": "OnlineMeetingRecording.Read.All" + }, + { + "description": "Allows an app to manage license assignments for users and groups, without a signed-in user.", + "displayName": "Manage all license assignments", + "id": "5facf0c1-8979-4e95-abcf-ff3d079771c0", + "origin": "Application", + "value": "LicenseAssignment.ReadWrite.All" + }, + { + "description": "Allows the app to read and write the Teams app settings without a signed-in user.", + "displayName": "Read and write Teams app settings", + "id": "ab5b445e-8f10-45f4-9c79-dd3f8062cc4e", + "origin": "Application", + "value": "TeamworkAppSettings.ReadWrite.All" + }, + { + "description": "Allows the app to read and write the lifecycle information like employeeLeaveDateTime of users in your organization, without a signed-in user.", + "displayName": "Read and write all users' lifecycle information", + "id": "925f1248-0f97-47b9-8ec8-538c54e01325", + "origin": "Application", + "value": "User-LifeCycleInfo.ReadWrite.All" + }, + { + "description": "Allows the app to read all Azure AD recommendations, without a signed-in user. ", + "displayName": "Read all Azure AD recommendations", + "id": "ae73097b-cb2a-4447-b064-5d80f6093921", + "origin": "Application", + "value": "DirectoryRecommendations.Read.All" + }, + { + "description": "Allows the application to list and query any shared user profile information associated with the current tenant without a signed-in user.\u00a0 It also permits the application to export external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant without a signed-in user.", + "displayName": "Read all shared cross-tenant user profiles and export their data", + "id": "8b919d44-6192-4f3d-8a3b-f86f8069ae3c", + "origin": "Application", + "value": "CrossTenantUserProfileSharing.Read.All" + }, + { + "description": "Allows the app to manage restricted resources based on the other permissions granted to the app, without a signed-in user.", + "displayName": "Manage restricted resources in the directory", + "id": "f20584af-9290-4153-9280-ff8bb2c0ea7f", + "origin": "Application", + "value": "Directory.Write.Restricted" + }, + { + "description": "Allows the app to read all transcripts of all online meetings, without a signed-in user.", + "displayName": "Read all transcripts of online meetings.", + "id": "a4a80d8d-d283-4bd8-8504-555ec3870630", + "origin": "Application", + "value": "OnlineMeetingTranscript.Read.All" + }, + { + "description": "Allows\u00a0the\u00a0app\u00a0to\u00a0manage all learning\u00a0content\u00a0in\u00a0the\u00a0organization's\u00a0directory, without a signed-in user.", + "displayName": "Manage all\u00a0learning\u00a0content", + "id": "444d6fcb-b738-41e5-b103-ac4f2a2628a3", + "origin": "Application", + "value": "LearningContent.ReadWrite.All" + }, + { + "description": "Allows the application to read the tenant-level settings of SharePoint and OneDrive, without a signed-in user.", + "displayName": "Read SharePoint and OneDrive tenant settings", + "id": "83d4163d-a2d8-4d3b-9695-4ae3ca98f888", + "origin": "Application", + "value": "SharePointTenantSettings.Read.All" + }, + { + "description": "Allows the app to read or write your organization's custom authentication extensions without a signed-in user.", + "displayName": "Read and write all custom authentication extensions", + "id": "c2667967-7050-4e7e-b059-4cbbb3811d03", + "origin": "Application", + "value": "CustomAuthenticationExtension.ReadWrite.All" + }, + { + "description": "Allows the app to read names and members of all one-to-one and group chats in Microsoft Teams where the associated Teams application is installed, without a signed-in user.", + "displayName": "Read names and members of all chat threads where the associated Teams application is installed.", + "id": "818ba5bd-5b3e-4fe0-bbe6-aa4686669073", + "origin": "Application", + "value": "Chat.ReadBasic.WhereInstalled" + }, + { + "description": "Allows the app to list and read all workflows, tasks and related lifecycle workflows resources without a signed-in user.", + "displayName": "Read all lifecycle workflows resources", + "id": "7c67316a-232a-4b84-be22-cea2c0906404", + "origin": "Application", + "value": "LifecycleWorkflows.Read.All" + }, + { + "description": "Allows the app to create protected content without a signed-in user. ", + "displayName": "Create protected content", + "id": "287bd98c-e865-4e8c-bade-1a85523195b9", + "origin": "Application", + "value": "InformationProtectionContent.Write.All" + }, + { + "description": "Allows the app to create, read, update and delete all users\u2019 tasks and task lists in your organization, without a signed-in user", + "displayName": "Read and write all users\u2019 tasks and tasklists", + "id": "44e666d1-d276-445b-a5fc-8815eeb81d55", + "origin": "Application", + "value": "Tasks.ReadWrite.All" + }, + { + "description": "Allows the app to read the Teams app settings without a signed-in user.", + "displayName": "Read Teams app settings", + "id": "475ebe88-f071-4bd7-af2b-642952bd4986", + "origin": "Application", + "value": "TeamworkAppSettings.Read.All" + }, + { + "description": "Allows the app to read the authentication context information in your organization without a signed-in user.", + "displayName": "Read all authentication context information", + "id": "381f742f-e1f8-4309-b4ab-e3d91ae4c5c1", + "origin": "Application", + "value": "AuthenticationContext.Read.All" + }, + { + "description": "Allows the app to read and update all admin report settings, such as whether to display concealed information in reports, without a signed-in user.", + "displayName": "Read and write all admin report settings", + "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", + "origin": "Application", + "value": "ReportSettings.ReadWrite.All" + }, + { + "description": "Allows an app to read all browser site lists configured for your organization, without a signed-in user.", + "displayName": "Read all browser site lists for your organization", + "id": "c5ee1f21-fc7f-4937-9af0-c91648ff9597", + "origin": "Application", + "value": "BrowserSiteLists.Read.All" + }, + { + "description": "Allows the app to read the lifecycle information like employeeLeaveDateTime of users in your organization, without a signed-in user.", + "displayName": "Read all users' lifecycle information", + "id": "8556a004-db57-4d7a-8b82-97a13428e96f", + "origin": "Application", + "value": "User-LifeCycleInfo.Read.All" + }, + { + "description": "Allows an app to read all acronyms without a signed-in user.", + "displayName": "Read all acronyms", + "id": "8c0aed2c-0c61-433d-b63c-6370ddc73248", + "origin": "Application", + "value": "Acronym.Read.All" + }, + { + "description": "Allows the app to see your users' basic profile (e.g., name, picture, user name, email address)", + "displayName": "View users' basic profile", + "id": "14dad69e-099b-42c9-810b-d002981feec1", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to see your basic profile (e.g., name, picture, user name, email address)", + "userConsentDisplayName": "View your basic profile", + "value": "profile" + }, + { + "description": "Allows the app to read attack simulation and training data for an organization for the signed-in user.", + "displayName": "Read attack simulation data of an organization", + "id": "104a7a4b-ca76-4677-b7e7-2f4bc482f381", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read attack simulation and training data for an organization on your behalf.", + "userConsentDisplayName": "Read attack simulation data of an organization", + "value": "AttackSimulation.Read.All" + }, + { + "description": "Allows the app to read and write your organization's directory access review default policy on behalf of the signed-in user.", + "displayName": "Read and write your organization's directory access review default policy", + "id": "4f5bc9c8-ea54-4772-973a-9ca119cb0409", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's directory access review default policy on your behalf.", + "userConsentDisplayName": "Read and write your organization's directory access review default policy", + "value": "Policy.ReadWrite.AccessReview" + }, + { + "description": "Allows the app to read your organization's threat submissions and threat submission policies on behalf of the signed-in user. Also allows the app to create new threat submissions on behalf of the signed-in user.", + "displayName": "Read and write all threat submissions", + "id": "8458e264-4eb9-4922-abe9-768d58f13c7f", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization's threat submissions and threat submission policies on your behalf. Also allows the app to create new threat submissions on your behalf.", + "userConsentDisplayName": "Read and write all threat submissions", + "value": "ThreatSubmission.ReadWrite.All" + }, + { + "description": "Allows the application to read any data from Records Management, such as configuration, labels, and policies on behalf of the signed-in user.", + "displayName": "Read Records Management configuration,\u00a0labels, and policies", + "id": "07f995eb-fc67-4522-ad66-2b8ca8ea3efd", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read any data from Records Management, such as configuration, labels and policies on your behalf.", + "userConsentDisplayName": "Read Records Management configuration,\u00a0labels, and policies", + "value": "RecordsManagement.Read.All" + }, + { + "description": "Allow the application to create, update and delete any data from Records Management, such as configuration, labels, and policies on behalf of the signed-in user.", + "displayName": "Read and write Records Management configuration, labels, and policies", + "id": "f2833d75-a4e6-40ab-86d4-6dfe73c97605", + "Origin": "Delegated", + "userConsentDescription": "Allow the application to create, update and delete any data from Records Management, such as configuration, labels, and policies on your behalf.", + "userConsentDisplayName": "Read and write Records Management configuration, labels, and policies", + "value": "RecordsManagement.ReadWrite.All" + }, + { + "description": "Allows the app to read details of delegated admin relationships with customers like access details (that includes roles) and the duration as well as specific role assignments to security groups on behalf of the signed-in user.", + "displayName": "Read Delegated Admin relationships with customers", + "id": "0c0064ea-477b-4130-82a5-4c2cc4ff68aa", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read details of Delegated Admin relationships with customers like access details (that includes roles) and the duration as well as specific role assignments to security groups on your behalf.", + "userConsentDisplayName": "Read Delegated Admin relationships with customers", + "value": "DelegatedAdminRelationship.Read.All" + }, + { + "description": "Allows the app to manage (create-update-terminate) Delegated Admin relationships with customers as well as role assignments to security groups for active Delegated Admin relationships on behalf of the signed-in user.", + "displayName": "Manage Delegated Admin relationships with customers", + "id": "885f682f-a990-4bad-a642-36736a74b0c7", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage (create-update-terminate) Delegated Admin relationships with customers and role assignments to security groups for active Delegated Admin relationships on your behalf.", + "userConsentDisplayName": "Manage Delegated Admin relationships with customers", + "value": "DelegatedAdminRelationship.ReadWrite.All" + }, + { + "description": "Allows the app to read and write all managed tenant information on behalf of the signed-in user.", + "displayName": "Read and write all managed tenant information", + "id": "b31fa710-c9b3-4d9e-8f5e-8036eecddab9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write all managed tenant information on your behalf.", + "userConsentDisplayName": "Read and write all managed tenant information", + "value": "ManagedTenants.ReadWrite.All" + }, + { + "description": "Allows the app to read all managed tenant information on behalf of the signed-in user.", + "displayName": "Read all managed tenant information", + "id": "dc34164e-6c4a-41a0-be89-3ae2fbad7cd3", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all managed tenant information on your behalf.", + "userConsentDisplayName": "Read all managed tenant information", + "value": "ManagedTenants.Read.All" + }, + { + "description": "Allows the app to read and manage the Cloud PC role-based access control (RBAC) settings, on behalf of the signed-in user. This includes reading and managing Cloud PC role definitions and role assignments.", + "displayName": "Read and write Cloud PC RBAC settings", + "id": "501d06f8-07b8-4f18-b5c6-c191a4af7a82", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and manage the Cloud PC role-based access control (RBAC) settings, on your behalf. This includes reading and managing Cloud PC role definitions and memberships.", + "userConsentDisplayName": "Read and write Cloud PC RBAC settings", + "value": "RoleManagement.ReadWrite.CloudPC" + }, + { + "description": "Allows the app to read the Cloud PC role-based access control (RBAC) settings, on behalf of the signed-in user.\u00a0 This includes reading Cloud PC role definitions and role assignments.", + "displayName": "Read Cloud PC RBAC settings", + "id": "9619b88a-8a25-48a7-9571-d23be0337a79", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the Cloud PC role-based access control (RBAC) settings, on your behalf.\u00a0 This includes reading Cloud PC role definitions and role assignments.", + "userConsentDisplayName": "Read Cloud PC RBAC settings", + "value": "RoleManagement.Read.CloudPC" + }, + { + "description": "Allows the app to read and write settings of external connections on behalf of a signed-in user. The signed-in user must be an administrator. The app can only read and write settings of connections that it is authorized to.", + "displayName": "Read and write external connections", + "id": "4082ad95-c812-4f02-be92-780c4c4f1830", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write external connections on your behalf. The signed-in user must be an administrator. The app can only read and write external connections that it is authorized to, or it can create new external connections. ", + "userConsentDisplayName": "Read and write external connections", + "value": "ExternalConnection.ReadWrite.OwnedBy" + }, + { + "description": "Allows the app to read all external connections on behalf of a signed-in user. The signed-in user must be an administrator.", + "displayName": "Read all external connections", + "id": "a38267a5-26b6-4d76-9493-935b7599116b", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all external connections on your behalf. The signed-in user must be an administrator.", + "userConsentDisplayName": "Read all external connections", + "value": "ExternalConnection.Read.All" + }, + { + "description": "Allows the app to read and write all external connections on behalf of a signed-in user. The signed-in user must be an administrator.", + "displayName": "Read and write all external connections", + "id": "bbbbd9b3-3566-4931-ac37-2b2180d9e334", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write all external connections on your behalf. The signed-in user must be an administrator.", + "userConsentDisplayName": "Read and write all external connections", + "value": "ExternalConnection.ReadWrite.All" + }, + { + "description": "Allows the app to read and write external items on behalf of a signed-in user. The signed-in user must be an administrator. The app can only read external items of the connection that it is authorized to.", + "displayName": "Read and write external items", + "id": "4367b9d7-cee7-4995-853c-a0bdfe95c1f9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write external items on your behalf. The signed-in user must be an administrator. The app can only read external items of the connection that it is authorized to.", + "userConsentDisplayName": "Read and write external items", + "value": "ExternalItem.ReadWrite.OwnedBy" + }, + { + "description": "Allows the app to read and write all external items on behalf of a signed-in user. The signed-in user must be an administrator.", + "displayName": "Read and write all external items", + "id": "b02c54f8-eb48-4c50-a9f0-a149e5a2012f", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write all external items on your behalf. The signed-in user must be an administrator.", + "userConsentDisplayName": "Read and write all external items", + "value": "ExternalItem.ReadWrite.All" + }, + { + "description": "Allows the app to read custom security attribute assignments for all principals in the tenant on behalf of a signed in user.", + "displayName": "Read custom security attribute assignments", + "id": "b46ffa80-fe3d-4822-9a1a-c200932d54d0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read custom security attribute assignments for all principals in the tenant on your behalf.", + "userConsentDisplayName": "Read custom security attribute assignments", + "value": "CustomSecAttributeAssignment.Read.All" + }, + { + "description": "Allows the app to read custom security attribute definitions for the tenant on behalf of a signed in user.", + "displayName": "Read custom security attribute definitions", + "id": "ce026878-a0ff-4745-a728-d4fedd086c07", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read custom security attribute definitions for the tenant on your behalf.", + "userConsentDisplayName": "Read custom security attribute definitions", + "value": "CustomSecAttributeDefinition.Read.All" + }, + { + "description": "Allows the app to read and write your organization's cross tenant access policies on behalf of the signed-in user.", + "displayName": "Read and write your organization's cross tenant access policies", + "id": "014b43d0-6ed4-4fc6-84dc-4b6f7bae7d85", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's cross tenant access policies on your behalf.", + "userConsentDisplayName": "Read and write your organization's cross tenant access policies", + "value": "Policy.ReadWrite.CrossTenantAccess" + }, + { + "description": "Allows the app to read and write tags in Teams, on behalf of the signed-in user.", + "displayName": "Read and write tags in Teams", + "id": "539dabd7-b5b6-4117-b164-d60cd15a8671", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write tags in Teams, on your behalf.", + "userConsentDisplayName": "Read and write tags in Teams", + "value": "TeamworkTag.ReadWrite" + }, + { + "description": "Allows the app to read tags in Teams, on behalf of the signed-in user.", + "displayName": "Read tags in Teams", + "id": "57587d0b-8399-45be-b207-8050cec54575", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read tags in Teams, on your behalf.", + "userConsentDisplayName": "Read tags in Teams", + "value": "TeamworkTag.Read" + }, + { + "description": "Allows the app to read and write security incidents, on behalf of the signed-in user.", + "displayName": "Read and write to incidents", + "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write to all security incidents that you have access to.", + "userConsentDisplayName": "Read and write to security incidents", + "value": "SecurityIncident.ReadWrite.All" + }, + { + "description": "Allows the app to read security incidents, on behalf of the signed-in user.", + "displayName": "Read incidents", + "id": "b9abcc4f-94fc-4457-9141-d20ce80ec952", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all security incidents that you have access to.", + "userConsentDisplayName": "Read security incidents", + "value": "SecurityIncident.Read.All" + }, + { + "description": "Allows the app to read and write to all security alerts, on behalf of the signed-in user.", + "displayName": "Read and write to all security alerts", + "id": "471f2a7f-2a42-4d45-a2bf-594d0838070d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write all alerts that you have access to.", + "userConsentDisplayName": "Read and write all alerts", + "value": "SecurityAlert.ReadWrite.All" + }, + { + "description": "Allows the app to read all security alerts, on behalf of the signed-in user.", + "displayName": "Read all security alerts", + "id": "bc257fb8-46b4-4b15-8713-01e91bfbe4ea", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all security alerts that you have access to.", + "userConsentDisplayName": "Read all alerts", + "value": "SecurityAlert.Read.All" + }, + { + "description": "Allows the app to update service announcement messages' user status on behalf of the signed-in user. The message status can be marked as read, archive, or favorite.", + "displayName": "Update user status on service announcement messages", + "id": "636e1b0b-1cc2-4b1c-9aa9-4eeed9b9761b", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to update service announcement messages' status on your behalf. Your status for messages can be marked as read, archive, or favorite.", + "userConsentDisplayName": "Update your user status on service announcement messages", + "value": "ServiceMessageViewpoint.Write" + }, + { + "description": "Allows the app to run hunting queries, on behalf of the signed-in user.", + "displayName": "Run hunting queries", + "id": "b152eca8-ea73-4a48-8c98-1a6742673d99", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to run hunting queries that you can execute.", + "userConsentDisplayName": "Run hunting queries", + "value": "ThreatHunting.Read.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall itself to teams the signed-in user can access.", + "displayName": "Allow the app to manage itself in teams", + "id": "0f4595f7-64b1-4e13-81bc-11a249df07a9", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall itself to teams you can access.", + "userConsentDisplayName": "Allow the Teams app to manage itself in teams", + "value": "TeamsAppInstallation.ReadWriteSelfForTeam" + }, + { + "description": "Allow the app to read the management data for Teams devices on behalf of the signed-in user.", + "displayName": "Read Teams devices", + "id": "b659488b-9d28-4208-b2be-1c6652b3c970", + "Origin": "Delegated", + "userConsentDescription": "Allow the app to read the management data for Teams devices on your behalf.", + "userConsentDisplayName": "Read Teams devices", + "value": "TeamworkDevice.Read.All" + }, + { + "description": "Allow the app to read and write the management data for Teams devices on behalf of the signed-in user.", + "displayName": "Read and write Teams devices", + "id": "ddd97ecb-5c31-43db-a235-0ee20e635c40", + "Origin": "Delegated", + "userConsentDescription": "Allow the app to read and write the management data for Teams devices on your behalf.", + "userConsentDisplayName": "Read and write Teams devices", + "value": "TeamworkDevice.ReadWrite.All" + }, + { + "description": "Allows the app to read all identity risky service principal information for your organization, on behalf of the signed-in user.", + "displayName": "Read all identity risky service principal information", + "id": "ea5c4ab0-5a73-4f35-8272-5d5337884e5d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all identity risky service principal information for your organization, on your behalf.", + "userConsentDisplayName": "Read all identity risky service principal information", + "value": "IdentityRiskyServicePrincipal.Read.All" + }, + { + "description": "Allows the app to read and update identity risky service principal information for all service principals in your organization, on behalf of the signed-in user. Update operations include dismissing risky service principals.", + "displayName": "Read and write all identity risky service principal information", + "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and update identity risky service principal information for all service principals in your organization, on your behalf. Update operations include dismissing risky service principals.", + "userConsentDisplayName": "Read and write all identity risky service principal information", + "value": "IdentityRiskyServicePrincipal.ReadWrite.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs to teams the signed-in user can access.", + "displayName": "Allow the Teams app to manage only its own tabs in teams", + "id": "f266662f-120a-4314-b26a-99b08617c7ef", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs to teams you can access.", + "userConsentDisplayName": "Allow the Teams app to manage only its own tabs in teams", + "value": "TeamsTab.ReadWriteSelfForTeam" + }, + { + "description": "Allows the app to read the presence information and write activity and availability on behalf of the signed-in user. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", + "displayName": "Read and write a user's presence information", + "id": "8d3c54a7-cf58-4773-bf81-c0cd6ad522bb", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the presence information and write activity and availability on your behalf. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", + "userConsentDisplayName": "Read and write your presence information", + "value": "Presence.ReadWrite" + }, + { + "description": "Allows the app to read subject rights requests on behalf of the signed-in user", + "displayName": "Read subject rights requests", + "id": "9c3af74c-fd0f-4db4-b17a-71939e2a9d77", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read subject rights requests on your behalf.", + "userConsentDisplayName": "Read data subject requests", + "value": "SubjectRightsRequest.Read.All" + }, + { + "description": "Allows the app to read and write subject rights requests on behalf of the signed-in user", + "displayName": "Read and write subject rights requests", + "id": "2b8fcc74-bce1-4ae3-a0e8-60c53739299d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write subject rights requests on your behalf.", + "userConsentDisplayName": "Read and write data subject requests", + "value": "SubjectRightsRequest.ReadWrite.All" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs for the signed-in user.", + "displayName": "Allow the Teams app to manage only its own tabs for a user", + "id": "395dfec1-a0b9-465f-a783-8250a430cb8c", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs for you.", + "userConsentDisplayName": "Allow the Teams app to manage only its own tabs for you", + "value": "TeamsTab.ReadWriteSelfForUser" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs in chats the signed-in user can access.", + "displayName": "Allow the Teams app to manage only its own tabs in chats", + "id": "0c219d04-3abf-47f7-912d-5cca239e90e6", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall its own tabs in chats you can access.", + "userConsentDisplayName": "Allow the Teams app to manage only its own tabs in chats", + "value": "TeamsTab.ReadWriteSelfForChat" + }, + { + "description": "Allows the app to read and write search configuration, on behalf of the signed-in user.", + "displayName": "Read and write your organization's search configuration", + "id": "b1a7d408-cab0-47d2-a2a5-a74a3733600d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write search configuration, on your behalf.", + "userConsentDisplayName": "Read and write your organization's search configuration", + "value": "SearchConfiguration.ReadWrite.All" + }, + { + "description": "Allows the app to read search configuration, on behalf of the signed-in user.", + "displayName": "Read your organization's search configuration", + "id": "7d307522-aa38-4cd0-bd60-90c6f0ac50bd", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read search configuration, on your behalf.", + "userConsentDisplayName": "Read your organization's search configuration", + "value": "SearchConfiguration.Read.All" + }, + { + "description": "Allows the app to read online meeting artifacts on behalf of the signed-in user.", + "displayName": "Read user's online meeting artifacts", + "id": "110e5abb-a10c-4b59-8b55-9b4daa4ef743", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read online meeting artifacts on your behalf.", + "userConsentDisplayName": "Read user's online meeting artifacts", + "value": "OnlineMeetingArtifact.Read.All" + }, + { + "description": "Allows the app to read and manage the active role-based access control (RBAC) assignments for your company's directory, on behalf of the signed-in user. This includes managing active directory role membership, and reading directory role templates, directory roles and active memberships.", + "displayName": "Read, update, and delete all active role assignments for your company's directory", + "id": "8c026be3-8e26-4774-9372-8d5d6f21daff", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and manage the active role-based access control (RBAC) assignments for your company's directory, on your behalf. This includes managing active directory role membership, and reading directory role templates, directory roles and active memberships.", + "userConsentDisplayName": "Read, update, and delete all active role assignments for your company's directory", + "value": "RoleAssignmentSchedule.ReadWrite.Directory" + }, + { + "description": "Allows the app to read and manage the eligible role-based access control (RBAC) assignments for your company's directory, on behalf of the signed-in user. This includes managing eligible directory role membership, and reading directory role templates, directory roles and eligible memberships.", + "displayName": "Read, update, and delete all eligible role assignments for your company's directory", + "id": "62ade113-f8e0-4bf9-a6ba-5acb31db32fd", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and manage the eligible role-based access control (RBAC) assignments for your company's directory, on your behalf. This includes managing eligible directory role membership, and reading directory role templates, directory roles and eligible memberships.", + "userConsentDisplayName": "Read, update, and delete all eligible role assignments for your company's directory", + "value": "RoleEligibilitySchedule.ReadWrite.Directory" + }, + { + "description": "Allows the app to read, update, and delete policies for privileged role-based access control (RBAC) assignments of your company's directory, on behalf of the signed-in user.", + "displayName": "Read, update, and delete all policies for privileged role assignments of your company's directory", + "id": "1ff1be21-34eb-448c-9ac9-ce1f506b2a68", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, and delete policies for privileged role-based access control (RBAC) assignments of your company's directory, on your behalf.", + "userConsentDisplayName": "Read, update, and delete all policies for privileged role assignments of your company's directory", + "value": "RoleManagementPolicy.ReadWrite.Directory" + }, + { + "description": "Allows the app to read the active role-based access control (RBAC) assignments for your company's directory, on behalf of the signed-in user. This includes reading directory role templates, and directory roles.", + "displayName": "Read all active role assignments for your company's directory", + "id": "344a729c-0285-42c6-9014-f12b9b8d6129", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the active role-based access control (RBAC) assignments for your company's directory, on your behalf. This includes reading directory role templates, and directory roles.", + "userConsentDisplayName": "Read all active role assignments for your company's directory", + "value": "RoleAssignmentSchedule.Read.Directory" + }, + { + "description": "Allows the app to read the eligible role-based access control (RBAC) assignments for your company's directory, on behalf of the signed-in user. This includes reading directory role templates, and directory roles.", + "displayName": "Read all eligible role assignments for your company's directory", + "id": "eb0788c2-6d4e-4658-8c9e-c0fb8053f03d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the eligible role-based access control (RBAC) assignments for your company's directory, on your behalf. This includes reading directory role templates, and directory roles.", + "userConsentDisplayName": "Read all eligible role assignments for your company's directory", + "value": "RoleEligibilitySchedule.Read.Directory" + }, + { + "description": "Allows the app to read policies for privileged role-based access control (RBAC) assignments of your company's directory, on behalf of the signed-in user.", + "displayName": "Read all policies for privileged role assignments of your company's directory", + "id": "3de2cdbe-0ff5-47d5-bdee-7f45b4749ead", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read policies for privileged role-based access control (RBAC) assignments of your company's directory, on your behalf.", + "userConsentDisplayName": "Read all policies for privileged role assignments of your company's directory", + "value": "RoleManagementPolicy.Read.Directory" + }, + { + "description": "Allows the app to read and write all Windows update deployment settings for the organization on behalf of the signed-in user.", + "displayName": "Read and write all Windows update deployment settings", + "id": "11776c0c-6138-4db3-a668-ee621bea2555", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write all Windows update deployment settings for the organization on your behalf.", + "userConsentDisplayName": "Read and write all Windows update deployment settings", + "value": "WindowsUpdates.ReadWrite.All" + }, + { + "description": "Allows the app to read and write your organization's mobility management policies on behalf of the signed-in user. For example, a mobility management policy can set the enrollment scope for a given mobility management application.", + "displayName": "Read and write your organization's mobility management policies", + "id": "a8ead177-1889-4546-9387-f25e658e2a79", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's mobility management policies on your behalf. For example, a mobility management policy can set the enrollment scope for a given mobility management application.", + "userConsentDisplayName": "Read and write your organization's mobility management policies", + "value": "Policy.ReadWrite.MobilityManagement" + }, + { + "description": "Allows the app to read basic unified group properties, memberships and owners of the group the signed-in guest is a member of.", + "displayName": "Read unified group memberships as guest", + "id": "73e75199-7c3e-41bb-9357-167164dbb415", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read basic unified group properties, memberships and owners of the group you are a member of.", + "userConsentDisplayName": "Read unified group memberships as guest", + "value": "UnifiedGroupMember.Read.AsGuest" + }, + { + "description": "Allows the app to update service principal endpoints", + "displayName": "Read and update service principal endpoints", + "id": "7297d82c-9546-4aed-91df-3d4f0a9b3ff0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to update service principal endpoints", + "userConsentDisplayName": "Read and update service principal endpoints", + "value": "ServicePrincipalEndpoint.ReadWrite.All" + }, + { + "description": "Allows the app to read service principal endpoints", + "displayName": "Read service principal endpoints", + "id": "9f9ce928-e038-4e3b-8faf-7b59049a8ddc", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read service principal endpoints", + "userConsentDisplayName": "Read service principal endpoints", + "value": "ServicePrincipalEndpoint.Read.All" + }, + { + "description": "Allows the app to create new notifications in users' teamwork activity feeds on behalf of the signed in user. These notifications may not be discoverable or be held or governed by compliance policies.", + "displayName": "Send a teamwork activity as the user", + "id": "7ab1d787-bae7-4d5d-8db6-37ea32df9186", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create new activities in your teamwork activity feed, and send new activities to other users' activity feed, on your behalf.", + "userConsentDisplayName": "Send a teamwork activity", + "value": "TeamsActivity.Send" + }, + { + "description": "Allows the app to read and write eDiscovery objects such as cases, custodians, review sets and other related objects on behalf of the signed-in user.", + "displayName": "Read and write all eDiscovery objects", + "id": "acb8f680-0834-4146-b69e-4ab1b39745ad", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write eDiscovery objects such as cases, custodians, review sets and other related objects on your behalf.", + "userConsentDisplayName": "Read and write all eDiscovery objects", + "value": "eDiscovery.ReadWrite.All" + }, + { + "description": "Allows the app to read eDiscovery objects such as cases, custodians, review sets and other related objects on behalf of the signed-in user.", + "displayName": "Read all eDiscovery objects", + "id": "99201db3-7652-4d5a-809a-bdb94f85fe3c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read eDiscovery objects such as cases, custodians, review sets and other related objects on your behalf.", + "userConsentDisplayName": "Read all eDiscovery objects", + "value": "eDiscovery.Read.All" + }, + { + "description": "Allows the app to read and write custom security attribute assignments for all principals in the tenant on behalf of a signed in user.", + "displayName": "Read and write custom security attribute assignments", + "id": "ca46335e-8453-47cd-a001-8459884efeae", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write custom security attribute assignments for all principals in the tenant on your behalf.", + "userConsentDisplayName": "Read and write custom security attribute assignments", + "value": "CustomSecAttributeAssignment.ReadWrite.All" + }, + { + "description": "Allows the app to read and write custom security attribute definitions for the tenant on behalf of a signed in user.", + "displayName": "Read and write custom security attribute definitions", + "id": "8b0160d4-5743-482b-bb27-efc0a485ca4a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write custom security attribute definitions for the tenant on your behalf.", + "userConsentDisplayName": "Read and write custom security attribute definitions", + "value": "CustomSecAttributeDefinition.ReadWrite.All" + }, + { + "description": "Allows the app to read email in the signed-in user's mailbox except body, previewBody, attachments and any extended properties.", + "displayName": "Read user basic mail", + "id": "a4b8392a-d8d1-4954-a029-8e668a39a170", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read email in the signed-in user's mailbox except body, previewBody, attachments and any extended properties.", + "userConsentDisplayName": "Read user basic mail", + "value": "Mail.ReadBasic" + }, + { + "description": "Allows the app to read and write your organization's feature rollout policies on behalf of the signed-in user. Includes abilities to assign and remove users and groups to rollout of a specific feature.", + "displayName": "Read and write your organization's feature rollout policies", + "id": "92a38652-f13b-4875-bc77-6e1dbb63e1b2", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's feature rollout policies on your behalf. Includes abilities to assign and remove users and groups to rollout of a specific feature.", + "userConsentDisplayName": "Read and write your organization's feature rollout policies", + "value": "Policy.ReadWrite.FeatureRollout" + }, + { + "description": "Allows the app to read and manage the role-based access control (RBAC) settings for your company's directory, on behalf of the signed-in user. This includes instantiating directory roles and managing directory role membership, and reading directory role templates, directory roles and memberships.", + "displayName": "Read and write directory RBAC settings", + "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and manage the role-based access control (RBAC) settings for your company's directory, on your behalf. This includes instantiating directory roles and managing directory role membership, and reading directory role templates, directory roles and memberships.", + "userConsentDisplayName": "Read and write directory RBAC settings", + "value": "RoleManagement.ReadWrite.Directory" + }, + { + "description": "Allows the app to read the role-based access control (RBAC) settings for your company's directory, on behalf of the signed-in user. This includes reading directory role templates, directory roles and memberships.", + "displayName": "Read directory RBAC settings", + "id": "741c54c3-0c1e-44a1-818b-3f97ab4e8c83", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the role-based access control (RBAC) settings for your company's directory, on your behalf. This includes reading directory role templates, directory roles and memberships.", + "userConsentDisplayName": "Read directory RBAC settings", + "value": "RoleManagement.Read.Directory" + }, + { + "description": "Allows the app to read and write the organization and related resources, on behalf of the signed-in user.\u00a0Related resources include things like subscribed skus and tenant branding information.", + "displayName": "Read and write organization information", + "id": "46ca0847-7e6b-426e-9775-ea810a948356", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the organization and related resources, on your behalf.\u00a0Related resources include things like subscribed skus and tenant branding information.", + "userConsentDisplayName": "Read and write organization information", + "value": "Organization.ReadWrite.All" + }, + { + "description": "Allows the app to read the organization and related resources, on behalf of the signed-in user.\u00a0Related resources include things like subscribed skus and tenant branding information.", + "displayName": "Read organization information", + "id": "4908d5b9-3fb2-4b1e-9336-1888b7937185", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the organization and related resources, on your behalf.\u00a0Related resources include things like subscribed skus and tenant branding information.", + "userConsentDisplayName": "Read organization information", + "value": "Organization.Read.All" + }, + { + "description": "Allows the app to read your company's places (conference rooms and room lists) for calendar events and other applications, on behalf of the signed-in user.", + "displayName": "Read all company places", + "id": "cb8f45a0-5c2e-4ea1-b803-84b870a7d7ec", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your company's places (conference rooms and room lists) for calendar events and other applications, on your behalf.", + "userConsentDisplayName": "Read all company places", + "value": "Place.Read.All" + }, + { + "description": "Allows the app to manage workforce integrations, to synchronize data from Microsoft Teams Shifts, on behalf of the signed-in user.", + "displayName": "Read and write workforce integrations", + "id": "08c4b377-0d23-4a8b-be2a-23c1c1d88545", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage workforce integrations, to synchronize data from Microsoft Teams Shifts, on your behalf.", + "userConsentDisplayName": "Read and write workforce integrations", + "value": "WorkforceIntegration.ReadWrite.All" + }, + { + "description": "Allows the app to read workforce integrations, to synchronize data from Microsoft Teams Shifts, on behalf of the signed-in user.", + "displayName": "Read workforce integrations", + "id": "f1ccd5a7-6383-466a-8db8-1a656f7d06fa", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read workforce integrations, to synchronize data from Microsoft Teams Shifts, on your behalf.", + "userConsentDisplayName": "Read workforce integrations", + "value": "WorkforceIntegration.Read.All" + }, + { + "description": "Allows the app to read, update, delete and perform actions on access reviews, reviewers, decisions and settings for group and app memberships that the signed-in user has access to in the organization.", + "displayName": "Manage access reviews for group and app memberships", + "id": "5af8c3f5-baca-439a-97b0-ea58a435e269", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update and perform action on access reviews, reviewers, decisions and settings that you have access to.", + "userConsentDisplayName": "Manage access reviews for group and app memberships", + "value": "AccessReview.ReadWrite.Membership" + }, + { + "description": "Allows the app to manage hybrid identity service configuration by creating, viewing, updating and deleting on-premises published resources, on-premises agents and agent groups, on behalf of the signed-in user.", + "displayName": "Manage on-premises published resources", + "id": "8c4d5184-71c2-4bf8-bb9d-bc3378c9ad42", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage hybrid identity service configuration by creating, viewing, updating and deleting on-premises published resources, on-premises agents and agent groups, on your behalf.", + "userConsentDisplayName": "Manage on-premises published resources", + "value": "OnPremisesPublishingProfiles.ReadWrite.All" + }, + { + "description": "Allows an app to read information protection sensitivity labels and label policy settings, on behalf of the signed-in user.", + "displayName": "Read user sensitivity labels and label policies.", + "id": "4ad84827-5578-4e18-ad7a-86530b12f884", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read information protection sensitivity labels and label policy settings, on behalf of the signed-in user.", + "userConsentDisplayName": "Read user sensitivity labels and label policies.", + "value": "InformationProtectionPolicy.Read" + }, + { + "description": "Allows the app to read administrative units and administrative unit membership on behalf of the signed-in user.", + "displayName": "Read administrative units", + "id": "3361d15d-be43-4de6-b441-3c746d05163d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read administrative units and administrative unit membership on your behalf.", + "userConsentDisplayName": "Read administrative units", + "value": "AdministrativeUnit.Read.All" + }, + { + "description": "Allows the app to create, read, update, and delete administrative units and manage administrative unit membership on behalf of the signed-in user.", + "displayName": "Read and write administrative units", + "id": "7b8a2d34-6b3f-4542-a343-54651608ad81", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create, read, update, and delete administrative units and manage administrative unit membership on your behalf.", + "userConsentDisplayName": "Read and write administrative units", + "value": "AdministrativeUnit.ReadWrite.All" + }, + { + "description": "Allows the app to read your family information, members and their basic profile.", + "displayName": "Read your family info", + "id": "3a1e4806-a744-4c70-80fc-223bf8582c46", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your family information, members and their basic profile.", + "userConsentDisplayName": "Read your family info", + "value": "Family.Read" + }, + { + "description": "Allows the app to create threat indicators, and fully manage those threat indicators (read, update and delete), on behalf of the signed-in user. \u00a0It cannot update any threat indicators it does not own.", + "displayName": "Manage threat indicators this app creates or owns", + "id": "91e7d36d-022a-490f-a748-f8e011357b42", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create threat indicators, and fully manage those threat indicators (read, update and delete), on your behalf. \u00a0It cannot update any threat indicators that it is not an owner of.", + "userConsentDisplayName": "Manage threat indicators this app creates or owns", + "value": "ThreatIndicators.ReadWrite.OwnedBy" + }, + { + "description": "Allows the app to read or update security actions, on behalf of the signed-in user.", + "displayName": "Read and update your organization's security actions", + "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and update security actions, on your behalf.", + "userConsentDisplayName": "Read and update your organization's security actions", + "value": "SecurityActions.ReadWrite.All" + }, + { + "description": "Allows the app to read security actions, on behalf of the signed-in user.", + "displayName": "Read your organization's security actions", + "id": "1638cddf-07a4-4de2-8645-69c96cacad73", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read security actions, on your behalf.", + "userConsentDisplayName": "Read your organization's security actions", + "value": "SecurityActions.Read.All" + }, + { + "description": "Allows an app to read 1 on 1 or group chats threads, on behalf of the signed-in user.", + "displayName": "Read user chat messages", + "id": "f501c180-9344-439a-bca0-6cbf209fd270", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read your 1 on 1 or group chat messages in Microsoft Teams, on your behalf.", + "userConsentDisplayName": "Read your chat messages", + "value": "Chat.Read" + }, + { + "description": "Allows an app to read and write 1 on 1 or group chats threads, on behalf of the signed-in user.", + "displayName": "Read and write user chat messages", + "id": "9ff7295e-131b-4d94-90e1-69fde507ac11", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read and write your 1 on 1 or group chat messages in Microsoft Teams, on your behalf.", + "userConsentDisplayName": "Read and write your chat messages", + "value": "Chat.ReadWrite" + }, + { + "description": "Allows the app to read and write your organization's trust framework policies on behalf of the signed-in user.", + "displayName": "Read and write your organization's trust framework policies", + "id": "cefba324-1a70-4a6e-9c1d-fd670b7ae392", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's trust framework policies on your behalf.", + "userConsentDisplayName": "Read and write trust framework policies", + "value": "Policy.ReadWrite.TrustFramework" + }, + { + "description": "Allows the app to read trust framework key set properties on behalf of the signed-in user.", + "displayName": "Read trust framework key sets", + "id": "7ad34336-f5b1-44ce-8682-31d7dfcd9ab9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read trust framework key sets, on your behalf.", + "userConsentDisplayName": "Read trust framework key sets", + "value": "TrustFrameworkKeySet.Read.All" + }, + { + "description": "Allows the app to read and write trust framework key set properties on behalf of the signed-in user.", + "displayName": "Read and write trust framework key sets", + "id": "39244520-1e7d-4b4a-aee0-57c65826e427", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read or write trust framework key sets, on your behalf.", + "userConsentDisplayName": "Read and write trust framework key sets", + "value": "TrustFrameworkKeySet.ReadWrite.All" + }, + { + "description": "Allows the app to read and update identity risk event information for all users in your organization on behalf of the signed-in user.\u00a0Update operations include confirming risk event detections.\u00a0", + "displayName": "Read and write risk event information", + "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and update identity risk event information for all users in your organization on your behalf.\u00a0Update operations include confirming risk event detections.\u00a0", + "userConsentDisplayName": "Read and write risk event information", + "value": "IdentityRiskEvent.ReadWrite.All" + }, + { + "description": "Allows the app to read and update identity risky user information for all users in your organization on behalf of the signed-in user.\u00a0Update operations include dismissing risky users.", + "displayName": "Read and write risky user information", + "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and update identity risky user information for all users in your organization on your behalf.\u00a0Update operations include dismissing risky users.", + "userConsentDisplayName": "Read and write identity risky user information", + "value": "IdentityRiskyUser.ReadWrite.All" + }, + { + "description": "Allows the app to read the signed-in user's mailbox.", + "displayName": "Read user mail ", + "id": "570282fd-fa5c-430d-a7fd-fc8dc98a9dca", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read email in your mailbox. ", + "userConsentDisplayName": "Read your mail ", + "value": "Mail.Read" + }, + { + "description": "Allows the app to read identity risky user information for all users in your organization on behalf of the signed-in user.", + "displayName": "Read identity risky user information", + "id": "d04bb851-cb7c-4146-97c7-ca3e71baf56c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read identity risky user information for all users in your organization on behalf of the signed-in user.", + "userConsentDisplayName": "Read identity risky user information", + "value": "IdentityRiskyUser.Read.All" + }, + { + "description": "Allows the app to read the signed-in user's activity statistics, such as how much time the user has spent on emails, in meetings, or in chat sessions.", + "displayName": "Read user activity statistics", + "id": "e03cf23f-8056-446a-8994-7d93dfc8b50e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your activity statistics, such as how much time you've spent on emails, in meetings, or in chat sessions.", + "userConsentDisplayName": "Read your activity statistics", + "value": "Analytics.Read" + }, + { + "description": "Allows the app to see and update the data you gave it access to, even when users are not currently using the app. This does not give the app any additional permissions.", + "displayName": "Maintain access to data you have given it access to", + "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to see and update the data you gave it access to, even when you are not currently using the app. This does not give the app any additional permissions.", + "userConsentDisplayName": "Maintain access to data you have given it access to", + "value": "offline_access" + }, + { + "description": "Allows the app to have the same access to mailboxes as the signed-in user via Exchange Web Services.", + "displayName": "Access mailboxes as the signed-in user via Exchange Web Services", + "id": "9769c687-087d-48ac-9cb3-c37dde652038", + "Origin": "Delegated", + "userConsentDescription": "Allows the app full access to your mailboxes on your behalf.", + "userConsentDisplayName": "Access your mailboxes", + "value": "EWS.AccessAsUser.All" + }, + { + "description": "Allows the app to export data (e.g. customer content or system-generated logs), associated with any user in your company, when the app is used by a privileged user (e.g. a Company Administrator).", + "displayName": "Export user's data", + "id": "405a51b5-8d8d-430b-9842-8be4b0e9f324", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to export data (e.g. customer content or system-generated logs), associated with any user in your company, when the app is used by a privileged user (e.g. a Company Administrator).", + "userConsentDisplayName": "Export user's data", + "value": "User.Export.All" + }, + { + "description": "Allows the app to deliver its notifications on behalf of signed-in users. Also allows the app to read, update, and delete the user's notification items for this app.", + "displayName": "Deliver and manage user notifications for this app", + "id": "89497502-6e42-46a2-8cb2-427fd3df970a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to deliver its notifications, on your behalf. Also allows the app to read, update, and delete your notification items for this app.", + "userConsentDisplayName": "Deliver and manage your notifications for this app", + "value": "Notifications.ReadWrite.CreatedByApp" + }, + { + "description": "Allows the app to read and write your organization's conditional access policies on behalf of the signed-in user.", + "displayName": "Read and write your organization's conditional access policies", + "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's conditional access policies on your behalf.", + "userConsentDisplayName": "Read and write your organization's conditional access policies", + "value": "Policy.ReadWrite.ConditionalAccess" + }, + { + "description": "Allows the app to read your organization's policies on behalf of the signed-in user.", + "displayName": "Read your organization's policies", + "id": "572fea84-0151-49b2-9301-11cb16974376", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization's policies on your behalf.", + "userConsentDisplayName": "Read your organization's policies", + "value": "Policy.Read.All" + }, + { + "description": "Allows the app to read access reviews, reviewers, decisions and settings that the signed-in user has access to in the organization.", + "displayName": "Read all access reviews that user can access", + "id": "ebfcd32b-babb-40f4-a14b-42706e83bd28", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read information on access reviews, reviewers, decisions and settings that you have access to.", + "userConsentDisplayName": "Read access reviews that you can access", + "value": "AccessReview.Read.All" + }, + { + "description": "Allows the app to read, update, delete and perform actions on access reviews, reviewers, decisions and settings that the signed-in user has access to in the organization.", + "displayName": "Manage all access reviews that user can access", + "id": "e4aa47b9-9a69-4109-82ed-36ec70d85ff1", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update and perform action on access reviews, reviewers, decisions and settings that you have access to.", + "userConsentDisplayName": "Manage access reviews that you can access", + "value": "AccessReview.ReadWrite.All" + }, + { + "description": "Allows the app to read programs and program controls that the signed-in user has access to in the organization.", + "displayName": "Read all programs that user can access", + "id": "c492a2e1-2f8f-4caa-b076-99bbf6e40fe4", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read information on programs and program controls that you have access to.", + "userConsentDisplayName": "Read programs that you can access", + "value": "ProgramControl.Read.All" + }, + { + "description": "Allows the app to read, update, delete and perform actions on programs and program controls that the signed-in user has access to in the organization.", + "displayName": "Manage all programs that user can access", + "id": "50fd364f-9d93-4ae1-b170-300e87cccf84", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update and perform action on programs and program controls that you have access to.", + "userConsentDisplayName": "Manage programs that you can access", + "value": "ProgramControl.ReadWrite.All" + }, + { + "description": "Allows the app to create, read, update, and delete apps in the app catalogs.", + "displayName": "Read and write to all app catalogs", + "id": "1ca167d5-1655-44a1-8adf-1414072e1ef9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create, read, update, and delete apps in the app catalogs.", + "userConsentDisplayName": "Read and write to all app catalogs", + "value": "AppCatalog.ReadWrite.All" + }, + { + "description": "Allows the app to request and manage just in time elevation (including scheduled elevation) of users to Azure AD built-in administrative roles, on behalf of signed-in users.", + "displayName": "Read and write privileged access to Azure AD", + "id": "3c3c74f5-cdaa-4a97-b7e0-4e788bfcfb37", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to request and manage just in time elevation (including scheduled elevation) of users to Azure AD built-in administrative roles, on your behalf.", + "userConsentDisplayName": "Read and write privileged access to Azure AD", + "value": "PrivilegedAccess.ReadWrite.AzureAD" + }, + { + "description": "Allows the app to read terms of use agreements on behalf of the signed-in user.", + "displayName": "Read all terms of use agreements", + "id": "af2819c9-df71-4dd3-ade7-4d7c9dc653b7", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read terms of use agreements on your behalf.", + "userConsentDisplayName": "Read all terms of use agreements", + "value": "Agreement.Read.All" + }, + { + "description": "Allows the app to read and write terms of use agreements on behalf of the signed-in user.", + "displayName": "Read and write all terms of use agreements", + "id": "ef4b5d93-3104-4664-9053-a5c49ab44218", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write terms of use agreements on your behalf.", + "userConsentDisplayName": "Read and write all terms of use agreements", + "value": "Agreement.ReadWrite.All" + }, + { + "description": "Allows the app to read terms of use acceptance statuses on behalf of the signed-in user.", + "displayName": "Read user terms of use acceptance statuses", + "id": "0b7643bb-5336-476f-80b5-18fbfbc91806", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your terms of use acceptance statuses.", + "userConsentDisplayName": "Read your terms of use acceptance statuses", + "value": "AgreementAcceptance.Read" + }, + { + "description": "Allows the app to read terms of use acceptance statuses on behalf of the signed-in user.", + "displayName": "Read terms of use acceptance statuses that user can access", + "id": "a66a5341-e66e-4897-9d52-c2df58c2bfb9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read terms of use acceptance statuses on your behalf.", + "userConsentDisplayName": "Read all terms of use acceptance statuses", + "value": "AgreementAcceptance.Read.All" + }, + { + "description": "Read activity data for your organization", + "displayName": "Allows the application to read activity data for your organization.", + "id": "594c1fb6-4f81-4475-ae41-0c394909246c", + "Origin": "Delegated (Office 365 Management)", + "userConsentDescription": "Read activity data for your organization", + "userConsentDisplayName": "Allows the application to read activity data for your organization.", + "value": "ActivityFeed.Read" + }, + { + "description": "Allows the app to read and query your audit log activities, on behalf of the signed-in user.", + "displayName": "Read audit log data", + "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and query your audit log activities, on your behalf.", + "userConsentDisplayName": "Read audit log data", + "value": "AuditLog.Read.All" + }, + { + "description": "Allows the app to read and report the signed-in user's activity in the app.", + "displayName": "Read and write app activity to users' activity feed", + "id": "47607519-5fb1-47d9-99c7-da4b48f369b1", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and report your activity in the app.", + "userConsentDisplayName": "Read and write app activity to your activity feed", + "value": "UserActivity.ReadWrite.CreatedByApp" + }, + { + "description": "Allows the app to read properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups.", + "displayName": "Read Microsoft Intune Device Configuration and Policies", + "id": "f1493658-876a-4c87-8fa7-edb559b3476a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups.", + "userConsentDisplayName": "Read Microsoft Intune Device Configuration and Policies", + "value": "DeviceManagementConfiguration.Read.All" + }, + { + "description": "Allows the app to read and write properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups.", + "displayName": "Read and write Microsoft Intune Device Configuration and Policies", + "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write properties of Microsoft Intune-managed device configuration and device compliance policies and their assignment to groups.", + "userConsentDisplayName": "Read and write Microsoft Intune Device Configuration and Policies", + "value": "DeviceManagementConfiguration.ReadWrite.All" + }, + { + "description": "Allows the app to read the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune.", + "displayName": "Read Microsoft Intune apps", + "id": "4edf5f54-4666-44af-9de9-0144fb4b6e8c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune.", + "userConsentDisplayName": "Read Microsoft Intune apps", + "value": "DeviceManagementApps.Read.All" + }, + { + "description": "Allows the app to read and write the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune.", + "displayName": "Read and write Microsoft Intune apps", + "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the properties, group assignments and status of apps, app configurations and app protection policies managed by Microsoft Intune.", + "userConsentDisplayName": "Read and write Microsoft Intune apps", + "value": "DeviceManagementApps.ReadWrite.All" + }, + { + "description": "Allows the app to read the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings.", + "displayName": "Read Microsoft Intune RBAC settings", + "id": "49f0cc30-024c-4dfd-ab3e-82e137ee5431", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings.", + "userConsentDisplayName": "Read Microsoft Intune RBAC settings", + "value": "DeviceManagementRBAC.Read.All" + }, + { + "description": "Allows the app to read and write the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings.", + "displayName": "Read and write Microsoft Intune RBAC settings", + "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the properties relating to the Microsoft Intune Role-Based Access Control (RBAC) settings.", + "userConsentDisplayName": "Read and write Microsoft Intune RBAC settings", + "value": "DeviceManagementRBAC.ReadWrite.All" + }, + { + "description": "Allows the app to read the properties of devices managed by Microsoft Intune.", + "displayName": "Read Microsoft Intune devices", + "id": "314874da-47d6-4978-88dc-cf0d37f0bb82", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the properties of devices managed by Microsoft Intune.", + "userConsentDisplayName": "Read devices Microsoft Intune devices", + "value": "DeviceManagementManagedDevices.Read.All" + }, + { + "description": "Allows the app to read and write the properties of devices managed by Microsoft Intune. Does not allow high impact operations such as remote wipe and password reset on the device\u2019s owner.", + "displayName": "Read and write Microsoft Intune devices", + "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the properties of devices managed by Microsoft Intune. Does not allow high impact operations such as remote wipe and password reset on the device\u2019s owner.", + "userConsentDisplayName": "Read and write Microsoft Intune devices", + "value": "DeviceManagementManagedDevices.ReadWrite.All" + }, + { + "description": "Allows the app to perform remote high impact actions such as wiping the device or resetting the passcode on devices managed by Microsoft Intune.", + "displayName": "Perform user-impacting remote actions on Microsoft Intune devices", + "id": "3404d2bf-2b13-457e-a330-c24615765193", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to perform remote high impact actions such as wiping the device or resetting the passcode on devices managed by Microsoft Intune.", + "userConsentDisplayName": "Perform user-impacting remote actions on Microsoft Intune devices", + "value": "DeviceManagementManagedDevices.PrivilegedOperations.All" + }, + { + "description": "Allows the app to read and write Microsoft Intune service properties including device enrollment and third party service connection configuration.", + "displayName": "Read and write Microsoft Intune configuration", + "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write Microsoft Intune service properties including device enrollment and third party service connection configuration.", + "userConsentDisplayName": "Read and write Microsoft Intune configuration", + "value": "DeviceManagementServiceConfig.ReadWrite.All" + }, + { + "description": "Allows the app to read Microsoft Intune service properties including device enrollment and third party service connection configuration.", + "displayName": "Read Microsoft Intune configuration", + "id": "8696daa5-bce5-4b2e-83f9-51b6defc4e1e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read Microsoft Intune service properties including device enrollment and third party service connection configuration.", + "userConsentDisplayName": "Read Microsoft Intune configuration", + "value": "DeviceManagementServiceConfig.Read.All" + }, + { + "description": "Allows the app to read your organization\u2019s security events on behalf of the signed-in user.", + "displayName": "Read your organization\u2019s security events", + "id": "64733abd-851e-478a-bffb-e47a14b18235", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization\u2019s security events on your behalf.", + "userConsentDisplayName": "Read your organization\u2019s security events", + "value": "SecurityEvents.Read.All" + }, + { + "description": "Allows the app to read your organization\u2019s security events on behalf of the signed-in user. Also allows the app to update editable properties in security events on behalf of the signed-in user.", + "displayName": "Read and update your organization\u2019s security events", + "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization\u2019s security events on your behalf. Also allows you to update editable properties in security events.", + "userConsentDisplayName": "Read and update your organization\u2019s security events", + "value": "SecurityEvents.ReadWrite.All" + }, + { + "description": "Allows the app to read a scored list of relevant people of the signed-in user or other users in the signed-in user's organization. The list can include local contacts, contacts from social networking, your organization's directory, and people from recent communications (such as email and Skype).", + "displayName": "Read all users' relevant people lists", + "id": "b89f9189-71a5-4e70-b041-9887f0bc7e4a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read a list of people in the order that is most relevant to you. Allows the app to read a list of people in the order that is most relevant to another user in your organization. These can include local contacts, contacts from social networking, people listed in your organization\u2019s directory, and people from recent communications.", + "userConsentDisplayName": "Read all users\u2019 relevant people lists", + "value": "People.Read.All" + }, + { + "description": "Manage the state and settings of all Microsoft education apps on behalf of the user.", + "displayName": "Manage education app settings", + "id": "63589852-04e3-46b4-bae9-15d5b1050748", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage the state and settings of all Microsoft education apps on your behalf.", + "userConsentDisplayName": "Manage your education app settings", + "value": "EduAdministration.ReadWrite" + }, + { + "description": "Read the state and settings of all Microsoft education apps on behalf of the user.", + "displayName": "Read education app settings", + "id": "8523895c-6081-45bf-8a5d-f062a2f12c9f", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view the state and settings of all Microsoft education apps on your behalf.", + "userConsentDisplayName": "View your education app settings", + "value": "EduAdministration.Read" + }, + { + "description": "Allows the app to read and write assignments and their grades on behalf of the user.", + "displayName": "Read and write users' class assignments and their grades", + "id": "2f233e90-164b-4501-8bce-31af2559a2d3", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view and modify your assignments on your behalf including \u00a0grades.", + "userConsentDisplayName": "View and modify your assignments and grades", + "value": "EduAssignments.ReadWrite" + }, + { + "description": "Allows the app to read assignments and their grades on behalf of the user.", + "displayName": "Read users' class assignments and their grades", + "id": "091460c9-9c4a-49b2-81ef-1f3d852acce2", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view your assignments on your behalf including grades.", + "userConsentDisplayName": "View your assignments and grades", + "value": "EduAssignments.Read" + }, + { + "description": "Allows the app to read and write assignments without grades on behalf of the user.", + "displayName": "Read and write users' class assignments without grades", + "id": "2ef770a1-622a-47c4-93ee-28d6adbed3a0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view and modify your assignments on your behalf without seeing grades.", + "userConsentDisplayName": "View and modify your assignments without grades", + "value": "EduAssignments.ReadWriteBasic" + }, + { + "description": "Allows the app to read assignments without grades on behalf of the user.", + "displayName": "Read users' class assignments without grades", + "id": "c0b0103b-c053-4b2e-9973-9f3a544ec9b8", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view your assignments on your behalf without seeing grades.", + "userConsentDisplayName": "View your assignments without grades", + "value": "EduAssignments.ReadBasic" + }, + { + "description": "Allows the app to read and write the structure of schools and classes in an organization's roster and education-specific information about users to be read and written on behalf of the user.", + "displayName": "Read and write users' view of the roster", + "id": "359e19a6-e3fa-4d7f-bcab-d28ec592b51e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view and modify information about schools and classes in your organization and education-related information about you and other users on your behalf.", + "userConsentDisplayName": "View and modify your school, class and user information", + "value": "EduRoster.ReadWrite" + }, + { + "description": "Allows the app to read the structure of schools and classes in an organization's roster and education-specific information about users to be read on behalf of the user.", + "displayName": "Read users' view of the roster", + "id": "a4389601-22d9-4096-ac18-36a927199112", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view information about schools and classes in your organization and education-related information about you and other users on your behalf.", + "userConsentDisplayName": "View your school, class and user information", + "value": "EduRoster.Read" + }, + { + "description": "Allows the app to read a limited subset of the properties from the structure of schools and classes in an organization's roster and a limited subset of properties about users to be read on behalf of the user.\u00a0Includes name, status, education role, email address and photo.", + "displayName": "Read a limited subset of users' view of the roster", + "id": "5d186531-d1bf-4f07-8cea-7c42119e1bd9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view minimal \u00a0information about both schools and classes in your organization and education-related information about you and other users on your behalf.", + "userConsentDisplayName": "View a limited subset of your school, class and user information", + "value": "EduRoster.ReadBasic" + }, + { + "description": "Allows the app to report the signed-in user's app activity information to Microsoft Timeline.", + "displayName": "Write app activity to users' timeline", + "id": "367492fc-594d-4972-a9b5-0d58c622c91c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to report your app activity information to Microsoft Timeline.", + "userConsentDisplayName": "Write app activity to your timeline", + "value": "UserTimelineActivity.Write.CreatedByApp" + }, + { + "description": "Allows the app to create, read, update, and delete user's mailbox settings. Does not include permission to send mail.", + "displayName": "Read and write user mailbox settings", + "id": "818c620a-27a9-40bd-a6a5-d96f7d610b4b", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create, and delete your mailbox settings.", + "userConsentDisplayName": "Read and write to your mailbox settings", + "value": "MailboxSettings.ReadWrite" + }, + { + "description": "Allows the app to launch another app or communicate with another app on a user's device on behalf of the signed-in user.", + "displayName": "Communicate with user devices", + "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to launch another app or communicate with another app on a device that you own.", + "userConsentDisplayName": "Communicate with your other devices", + "value": "Device.Command" + }, + { + "description": "Allows the app to read a user's list of devices on behalf of the signed-in user.", + "displayName": "Read user devices", + "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to see your list of devices.", + "userConsentDisplayName": "View your list of devices", + "value": "Device.Read" + }, + { + "description": "Allows the app to read, share, and modify OneNote notebooks that the signed-in user has access to in the organization.", + "displayName": "Read and write all OneNote notebooks that user can access", + "id": "64ac0503-b4fa-45d9-b544-71a463f05da0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, share, and modify all the OneNote notebooks that you have access to.", + "userConsentDisplayName": "Read and write all OneNote notebooks that you can access", + "value": "Notes.ReadWrite.All" + }, + { + "description": "Allows the app to read OneNote notebooks that the signed-in user has access to in the organization.", + "displayName": "Read all OneNote notebooks that user can access", + "id": "dfabfca6-ee36-4db2-8208-7a28381419b3", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all the OneNote notebooks that you have access to.", + "userConsentDisplayName": "Read all OneNote notebooks that you can access", + "value": "Notes.Read.All" + }, + { + "description": "Allows the app to read, share, and modify OneNote notebooks on behalf of the signed-in user.", + "displayName": "Read and write user OneNote notebooks", + "id": "615e26af-c38a-4150-ae3e-c3b0d4cb1d6a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, share, and modify OneNote notebooks on your behalf.", + "userConsentDisplayName": "Read and write your OneNote notebooks", + "value": "Notes.ReadWrite" + }, + { + "description": "Allows the app to read OneNote notebooks on behalf of the signed-in user.", + "displayName": "Read user OneNote notebooks", + "id": "371361e4-b9e2-4a3f-8315-2a301a3b0a3d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read OneNote notebooks on your behalf.", + "userConsentDisplayName": "Read your OneNote notebooks", + "value": "Notes.Read" + }, + { + "description": "This is deprecated! Do not use! This permission no longer has any effect. You can safely consent to it. No additional privileges will be granted to the app.", + "displayName": "Limited notebook access (deprecated)", + "id": "ed68249d-017c-4df5-9113-e684c7f8760b", + "Origin": "Delegated", + "userConsentDescription": "This permission no longer has any effect. You can safely consent to it. No additional privileges will be granted to the app.", + "userConsentDisplayName": "Limited access to your OneNote notebooks for this app (preview)", + "value": "Notes.ReadWrite.CreatedByApp" + }, + { + "description": "Allows the app to read the titles of OneNote notebooks and sections and to create new pages, notebooks, and sections on behalf of the signed-in user.", + "displayName": "Create user OneNote notebooks", + "id": "9d822255-d64d-4b7a-afdb-833b9a97ed02", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to view the titles of your OneNote notebooks and sections and to create new pages, notebooks, and sections on your behalf.", + "userConsentDisplayName": "Create your OneNote notebooks", + "value": "Notes.Create" + }, + { + "description": "Allows the app to invite guest users to the organization, on behalf of the signed-in user.", + "displayName": "Invite guest users to the organization", + "id": "63dd7cd9-b489-4adf-a28c-ac38b9a0f962", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to invite guest users to the organization, on your behalf.", + "userConsentDisplayName": "Invite guest users to the organization", + "value": "User.Invite.All" + }, + { + "description": "Allows the app to the read user's mailbox settings. Does not include permission to send mail.", + "displayName": "Read user mailbox settings", + "id": "87f447af-9fa4-4c32-9dfa-4a57a73d18ce", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your mailbox settings.", + "userConsentDisplayName": "Read your mailbox settings", + "value": "MailboxSettings.Read" + }, + { + "description": "(Preview) Allows the app to read files that the user selects. The app has access for several hours after the user selects a file.", + "displayName": "Read files that the user selects (preview)", + "id": "5447fe39-cb82-4c1a-b977-520e67e724eb", + "Origin": "Delegated", + "userConsentDescription": "(Preview) Allows the app to read files that you select. After you select a file, the app has access to the file for several hours.", + "userConsentDisplayName": "Read selected files", + "value": "Files.Read.Selected" + }, + { + "description": "(Preview) Allows the app to read and write files that the user selects. The app has access for several hours after the user selects a file.", + "displayName": "Read and write files that the user selects (preview)", + "id": "17dde5bd-8c17-420f-a486-969730c1b827", + "Origin": "Delegated", + "userConsentDescription": "(Preview) Allows the app to read and write files that you select. After you select a file, the app has access to the file for several hours.", + "userConsentDisplayName": "Read and write selected files", + "value": "Files.ReadWrite.Selected" + }, + { + "description": "(Preview) Allows the app to read, create, update and delete files in the application's folder.", + "displayName": "Have full access to the application's folder (preview)", + "id": "8019c312-3263-48e6-825e-2b833497195b", + "Origin": "Delegated", + "userConsentDescription": "(Preview) Allows the app to read, create, update and delete files in the application's folder.", + "userConsentDisplayName": "Have full access to the application's folder", + "value": "Files.ReadWrite.AppFolder" + }, + { + "description": "Allows an app to read all service usage reports on behalf of the signed-in user. Services that provide usage reports include Office 365 and Azure Active Directory.", + "displayName": "Read all usage reports", + "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read all service usage reports on your behalf. Services that provide usage reports include Office 365 and Azure Active Directory.", + "userConsentDisplayName": "Read all usage reports", + "value": "Reports.Read.All" + }, + { + "description": "Allows the application to edit or delete documents and list items in all site collections on behalf of the signed-in user.", + "displayName": "Edit or delete items in all site collections", + "id": "89fe6a52-be36-487e-b7d8-d061c450a026", + "Origin": "Delegated", + "userConsentDescription": "Allow the application to edit or delete documents and list items in all site collections on your behalf.", + "userConsentDisplayName": "Edit or delete items in all site collections", + "value": "Sites.ReadWrite.All" + }, + { + "description": "Allows the app to create, read, update, and delete tasks a user has permissions to, including their own and shared tasks.", + "displayName": "Read and write user and shared tasks", + "id": "c5ddf11b-c114-4886-8558-8a4e557cd52b", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create, and delete tasks you have permissions to access, including your own and shared tasks.", + "userConsentDisplayName": "Read and write to your and shared tasks", + "value": "Tasks.ReadWrite.Shared" + }, + { + "description": "Allows the app to read tasks a user has permissions to access, including their own and shared tasks.", + "displayName": "Read user and shared tasks", + "id": "88d21fd4-8e5a-4c32-b5e2-4a1c95f34f72", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read tasks you have permissions to access, including your own and shared tasks.", + "userConsentDisplayName": "Read your and shared tasks", + "value": "Tasks.Read.Shared" + }, + { + "description": "Allows the app to create, read, update, and delete contacts a user has permissions to, including their own and shared contacts.", + "displayName": "Read and write user and shared contacts", + "id": "afb6c84b-06be-49af-80bb-8f3f77004eab", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create, and delete contacts you have permissions to access, including your own and shared contacts.", + "userConsentDisplayName": "Read and write to your and shared contacts", + "value": "Contacts.ReadWrite.Shared" + }, + { + "description": "Allows the app to read contacts a user has permissions to access, including their own and shared contacts.", + "displayName": "Read user and shared contacts", + "id": "242b9d9e-ed24-4d09-9a52-f43769beb9d4", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read contacts you have permissions to access, including your own and shared contacts.", + "userConsentDisplayName": "Read your and shared contacts", + "value": "Contacts.Read.Shared" + }, + { + "description": "Allows the app to create, read, update and delete events in all calendars in the organization user has permissions to access. This includes delegate and shared calendars.", + "displayName": "Read and write user and shared calendars", + "id": "12466101-c9b8-439a-8589-dd09ee67e8e9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create and delete events in all calendars in your organization you have permissions to access. This includes delegate and shared calendars.", + "userConsentDisplayName": "Read and write to your and shared calendars", + "value": "Calendars.ReadWrite.Shared" + }, + { + "description": "Allows the app to read events in all calendars that the user can access, including delegate and shared calendars.", + "displayName": "Read user and shared calendars", + "id": "2b9c4092-424d-4249-948d-b43879977640", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read events in all calendars that you can access, including delegate and shared calendars.\u00a0", + "userConsentDisplayName": "Read calendars\u00a0you can access", + "value": "Calendars.Read.Shared" + }, + { + "description": "Allows the app to send mail as the signed-in user, including sending on-behalf of others.", + "displayName": "Send mail on behalf of others", + "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to send mail as you or on-behalf of someone else.", + "userConsentDisplayName": "Send mail on behalf of others or yourself", + "value": "Mail.Send.Shared" + }, + { + "description": "Allows the app to create, read, update, and delete mail a user has permission to access, including their own and shared mail. Does not include permission to send mail.", + "displayName": "Read and write user and shared mail", + "id": "5df07973-7d5d-46ed-9847-1271055cbd51", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create, and delete mail you have permission to access, including your own and shared mail. Does not allow the app to send mail on your behalf.", + "userConsentDisplayName": "Read and write mail\u00a0you can access", + "value": "Mail.ReadWrite.Shared" + }, + { + "description": "Allows the app to read mail a user can access, including their own and shared mail.", + "displayName": "Read user and shared mail", + "id": "7b9103a5-4610-446b-9670-80643382c1fa", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read mail you can access, including shared mail.", + "userConsentDisplayName": "Read mail you can access", + "value": "Mail.Read.Shared" + }, + { + "description": "Allows users to sign-in to the app, and allows the app to read the profile of signed-in users. It also allows the app to read basic company information of signed-in users.", + "displayName": "Sign in and read user profile", + "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", + "Origin": "Delegated", + "userConsentDescription": "Allows you to sign in to the app with your organizational account and let the app read your profile. It also allows the app to read basic company information.", + "userConsentDisplayName": "Sign you in and read your profile", + "value": "User.Read" + }, + { + "description": "Allows the app to read your profile. It also allows the app to update your profile information on your behalf.", + "displayName": "Read and write access to user profile", + "id": "b4e74841-8e56-480b-be8b-910348b18b4c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your profile, and discover your group membership, reports and manager. It also allows the app to update your profile information on your behalf.", + "userConsentDisplayName": "Read and update your profile", + "value": "User.ReadWrite" + }, + { + "description": "Allows the app to read a basic set of profile properties of other users in your organization on behalf of the signed-in user. This includes display name, first and last name, email address and photo.", + "displayName": "Read all users' basic profiles", + "id": "b340eb25-3456-403f-be2f-af7a0d370277", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read a basic set of profile properties of other users in your organization on your behalf. Includes display name, first and last name, email address and photo.", + "userConsentDisplayName": "Read all users' basic profiles", + "value": "User.ReadBasic.All" + }, + { + "description": "Allows the app to read the full set of profile properties, reports, and managers of other users in your organization, on behalf of the signed-in user.", + "displayName": "Read all users' full profiles", + "id": "a154be20-db9c-4678-8ab7-66f6cc099a59", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the full set of profile properties, reports, and managers of other users in your organization, on your behalf.", + "userConsentDisplayName": "Read all users' full profiles", + "value": "User.Read.All" + }, + { + "description": "Allows the app to read and write the full set of profile properties, reports, and managers of other users in your organization, on behalf of the signed-in user.", + "displayName": "Read and write all users' full profiles", + "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the full set of profile properties, reports, and managers of other users in your organization, on your behalf.", + "userConsentDisplayName": "Read and write all users' full profiles", + "value": "User.ReadWrite.All" + }, + { + "description": "Allows the app to list groups, and to read their properties and all group memberships on behalf of the signed-in user. Also allows the app to read calendar, conversations, files, and other group content for all groups the signed-in user can access. ", + "displayName": "Read all groups", + "id": "5f8c59db-677d-491f-a6b8-5f174b11ec1d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to list groups, and to read their properties and all group memberships on your behalf. Also allows the app to read calendar, conversations, files, and other group content for all groups you can access. ", + "userConsentDisplayName": "Read all groups", + "value": "Group.Read.All" + }, + { + "description": "Allows the app to create groups and read all group properties and memberships on behalf of the signed-in user. Additionally allows group owners to manage their groups and allows group members to update group content.", + "displayName": "Read and write all groups", + "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create groups and read all group properties and memberships on your behalf. Additionally allows the app to manage your groups and to update group content for groups you are a member of.", + "userConsentDisplayName": "Read and write all groups", + "value": "Group.ReadWrite.All" + }, + { + "description": "Allows the app to read data in your organization's directory, such as users, groups and apps.", + "displayName": "Read directory data", + "id": "06da0dbc-49e2-44d2-8312-53f166ab848a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read data in your organization's directory.", + "userConsentDisplayName": "Read directory data", + "value": "Directory.Read.All" + }, + { + "description": "Allows the app to read and write data in your organization's directory, such as users, and groups. It does not allow the app to delete users or groups, or reset user passwords.", + "displayName": "Read and write directory data", + "id": "c5366453-9fb0-48a5-a156-24f0c49a4b84", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write data in your organization's directory, such as other users, groups. It does not allow the app to delete users or groups, or reset user passwords.", + "userConsentDisplayName": "Read and write directory data", + "value": "Directory.ReadWrite.All" + }, + { + "description": "Allows the app to have the same access to information in the directory as the signed-in user.", + "displayName": "Access directory as the signed in user", + "id": "0e263e50-5827-48a4-b97c-d940288653c7", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to have the same access to information in your work or school directory as you do.", + "userConsentDisplayName": "Access the directory as you", + "value": "Directory.AccessAsUser.All" + }, + { + "description": "Allows the app to create, read, update, and delete email in user mailboxes. Does not include permission to send mail. ", + "displayName": "Read and write access to user mail ", + "id": "024d486e-b451-40bb-833d-3e66d98c5c73", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create and delete email in your mailbox. Does not include permission to send mail. ", + "userConsentDisplayName": "Read and write access to your mail ", + "value": "Mail.ReadWrite" + }, + { + "description": "Allows the app to send mail as users in the organization. ", + "displayName": "Send mail as a user ", + "id": "e383f46e-2787-4529-855e-0e479a3ffac0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to send mail as you. ", + "userConsentDisplayName": "Send mail as you ", + "value": "Mail.Send" + }, + { + "description": "Allows the app to read events in user calendars . ", + "displayName": "Read user calendars ", + "id": "465a38f9-76ea-45b9-9f34-9e8b0d4b0b42", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read events in your calendars. ", + "userConsentDisplayName": "Read your calendars ", + "value": "Calendars.Read" + }, + { + "description": "Allows the app to create, read, update, and delete events in user calendars. ", + "displayName": "Have full access to user calendars ", + "id": "1ec239c2-d7c9-4623-a91a-a9775856bb36", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create and delete events in your calendars. ", + "userConsentDisplayName": "Have full access to your calendars ", + "value": "Calendars.ReadWrite" + }, + { + "description": "Allows the app to read user contacts. ", + "displayName": "Read user contacts ", + "id": "ff74d97f-43af-4b68-9f2a-b77ee6968c5d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read contacts in your contact folders. ", + "userConsentDisplayName": "Read your contacts ", + "value": "Contacts.Read" + }, + { + "description": "Allows the app to create, read, update, and delete user contacts. ", + "displayName": "Have full access to user contacts ", + "id": "d56682ec-c09e-4743-aaf4-1a3aac4caa21", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create and delete contacts in your contact folders. ", + "userConsentDisplayName": "Have full access of your contacts ", + "value": "Contacts.ReadWrite" + }, + { + "description": "Allows the app to read the signed-in user's files.", + "displayName": "Read user files", + "id": "10465720-29dd-4523-a11a-6a75c743c9d9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your files.", + "userConsentDisplayName": "Read your files", + "value": "Files.Read" + }, + { + "description": "Allows the app to read, create, update and delete the signed-in user's files.", + "displayName": "Have full access to user files", + "id": "5c28f0bf-8a70-41f1-8ab2-9032436ddb65", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, create, update, and delete your files.", + "userConsentDisplayName": "Have full access to your files", + "value": "Files.ReadWrite" + }, + { + "description": "Allows the app to read all files the signed-in user can access.", + "displayName": "Read all files that user can access", + "id": "df85f4d6-205c-4ac5-a5ea-6bf408dba283", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all files you can access.", + "userConsentDisplayName": "Read all files that you have access to", + "value": "Files.Read.All" + }, + { + "description": "Allows the app to read, create, update and delete all files the signed-in user can access.", + "displayName": "Have full access to all files user can access", + "id": "863451e7-0667-486c-a5d6-d135439485f0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, create, update and delete all files that you can access.", + "userConsentDisplayName": "Have full access to all files you have access to", + "value": "Files.ReadWrite.All" + }, + { + "description": "Allows the application to read documents and list items in all site collections on behalf of the signed-in user", + "displayName": "Read items in all site collections", + "id": "205e70e5-aba6-4c52-a976-6d2d46c48043", + "Origin": "Delegated", + "userConsentDescription": "Allow the application to read documents and list items in all site collections on your behalf", + "userConsentDisplayName": "Read items in all site collections", + "value": "Sites.Read.All" + }, + { + "description": "Allows users to sign in to the app with their work or school accounts and allows the app to see basic user profile information.", + "displayName": "Sign users in", + "id": "37f7f235-527c-4136-accd-4a02d197296e", + "Origin": "Delegated", + "userConsentDescription": "Allows you to sign in to the app with your work or school account and allows the app to read your basic profile information.", + "userConsentDisplayName": "Sign in as you", + "value": "openid" + }, + { + "description": "Allows the app to read your users' primary email address", + "displayName": "View users' email address", + "id": "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your primary email address", + "userConsentDisplayName": "View your email address", + "value": "email" + }, + { + "description": "Allows the app to read identity risk event information for all users in your organization on behalf of the signed-in user. ", + "displayName": "Read identity risk event information", + "id": "8f6a01e7-0391-4ee5-aa22-a3af122cef27", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read identity risk event information for all users in your organization on behalf of the signed-in user. ", + "userConsentDisplayName": "Read identity risk event information", + "value": "IdentityRiskEvent.Read.All" + }, + { + "description": "Allows the app to read the memberships of hidden groups and administrative units on behalf of the signed-in user, for those hidden groups and administrative units that the signed-in user has access to.", + "displayName": "Read hidden memberships", + "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the memberships of hidden groups or administrative units on your behalf, for those hidden groups or adminstrative units that you have access to.", + "userConsentDisplayName": "Read your hidden memberships", + "value": "Member.Read.Hidden" + }, + { + "description": "Allows the app to read a ranked list of relevant people of the signed-in user. The list includes local contacts, contacts from social networking, your organization's directory, and people from recent communications (such as email and Skype).", + "displayName": "Read users' relevant people lists", + "id": "ba47897c-39ec-4d83-8086-ee8256fa737d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read a list of people in the order that's most relevant to you. This includes your local contacts, your contacts from social networking, people listed in your organization's directory, and people from recent communications.", + "userConsentDisplayName": "Read your relevant people list", + "value": "People.Read" + }, + { + "description": "Allows the application to create or delete document libraries and lists in all site collections on behalf of the signed-in user.", + "displayName": "Create, edit, and delete items and lists in all site collections", + "id": "65e50fdc-43b7-4915-933e-e8138f11f40a", + "Origin": "Delegated", + "userConsentDescription": "Allow the application to create or delete document libraries and lists in all site collections on your behalf.", + "userConsentDisplayName": "Create, edit, and delete items and lists in all your site collections", + "value": "Sites.Manage.All" + }, + { + "description": "Allows the application to have full control of all site collections on behalf of the signed-in user.", + "displayName": "Have full control of all site collections", + "id": "5a54b8b3-347c-476d-8f8e-42d5c7424d29", + "Origin": "Delegated", + "userConsentDescription": "Allow the application to have full control of all site collections on your behalf.", + "userConsentDisplayName": "Have full control of all your site collections", + "value": "Sites.FullControl.All" + }, + { + "description": "Allows the app to read and write your organization\u2019s identity (authentication) providers\u2019 properties on behalf of the user.", + "displayName": "Read and write identity providers", + "id": "f13ce604-1677-429f-90bd-8a10b9f01325", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization\u2019s identity (authentication) providers\u2019 properties on your behalf.", + "userConsentDisplayName": "Read and write identity providers", + "value": "IdentityProvider.ReadWrite.All" + }, + { + "description": "Allows the app to read your organization\u2019s identity (authentication) providers\u2019 properties on behalf of the user.", + "displayName": "Read identity providers", + "id": "43781733-b5a7-4d1b-98f4-e8edff23e1a9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization\u2019s identity (authentication) providers\u2019 properties on your behalf.", + "userConsentDisplayName": "Read identity providers", + "value": "IdentityProvider.Read.All" + }, + { + "description": "Allows an app to read bookings appointments, businesses, customers, services, and staff on behalf of the signed-in user.", + "displayName": "Read bookings information", + "id": "33b1df99-4b29-4548-9339-7a7b83eaeebc", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read bookings appointments, businesses, customers, services, and staff on your behalf.", + "userConsentDisplayName": "Read bookings information", + "value": "Bookings.Read.All" + }, + { + "description": "Allows an app to read and write bookings appointments and customers, and additionally allows read businesses information, services, and staff on behalf of the signed-in user.", + "displayName": "Read and write booking appointments", + "id": "02a5a114-36a6-46ff-a102-954d89d9ab02", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read and write bookings appointments and customers, and additionally allows read businesses information, services, and staff on your behalf.", + "userConsentDisplayName": "Read and write booking appointments", + "value": "BookingsAppointment.ReadWrite.All" + }, + { + "description": "Allows an app to read and write bookings appointments, businesses, customers, services, and staff on behalf of the signed-in user. Does not allow create, delete and publish of booking businesses.", + "displayName": "Read and write bookings information", + "id": "948eb538-f19d-4ec5-9ccc-f059e1ea4c72", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read and write Bookings appointments, businesses, customers, services, and staff on your behalf. Does not allow create, delete and publish of booking businesses.", + "userConsentDisplayName": "Read and write bookings information", + "value": "Bookings.ReadWrite.All" + }, + { + "description": "Allows an app to read, write and manage bookings appointments, businesses, customers, services, and staff on behalf of the signed-in user.", + "displayName": "Manage bookings information", + "id": "7f36b48e-542f-4d3b-9bcb-8406f0ab9fdb", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read, write and manage bookings appointments, businesses, customers, services, and staff on your behalf.", + "userConsentDisplayName": "Manage bookings information", + "value": "Bookings.Manage.All" + }, + { + "description": "Allows the app to have the same access to mailboxes as the signed-in user via Exchange ActiveSync.", + "displayName": "Access mailboxes via Exchange ActiveSync", + "id": "ff91d191-45a0-43fd-b837-bd682c4a0b0f", + "Origin": "Delegated", + "userConsentDescription": "Allows the app full access to your mailboxes on your behalf.", + "userConsentDisplayName": "Access your mailboxes", + "value": "EAS.AccessAsUser.All" + }, + { + "description": "Allows the app to read and write financials data on behalf of the signed-in user.", + "displayName": "Read and write financials data", + "id": "f534bf13-55d4-45a9-8f3c-c92fe64d6131", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write financials data on your behalf.", + "userConsentDisplayName": "Read and write financials data", + "value": "Financials.ReadWrite.All" + }, + { + "description": "Allows the app to read your organization's user flows, on behalf of the signed-in user.", + "displayName": "Read all identity user flows", + "id": "2903d63d-4611-4d43-99ce-a33f3f52e343", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization's user flows, on your behalf.", + "userConsentDisplayName": "Read all identity user flows", + "value": "IdentityUserFlow.Read.All" + }, + { + "description": "Allows the app to read or write your organization's user flows, on behalf of the signed-in user.", + "displayName": "Read and write all identity user flows", + "id": "281892cc-4dbf-4e3a-b6cc-b21029bb4e82", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read or write your organization's user flows, on your behalf.", + "userConsentDisplayName": "Read and write all identity user flows", + "value": "IdentityUserFlow.ReadWrite.All" + }, + { + "description": "Allows the app to read all organizational contacts on behalf of the signed-in user. \u00a0These contacts are managed by the organization and are different from a user's personal contacts.", + "displayName": "Read organizational contacts", + "id": "08432d1b-5911-483c-86df-7980af5cdee0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all organizational contacts on your behalf.\u00a0 These contacts are managed by the organization and are different from your personal contacts.", + "userConsentDisplayName": "Read organizational contacts", + "value": "OrgContact.Read.All" + }, + { + "description": "Allows the app to manage permission grants for application permissions to any API (including Microsoft Graph) and application assignments for any app, on behalf of the signed-in user.", + "displayName": "Manage app permission grants and app role assignments", + "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage permission grants for application permissions to any API (including Microsoft Graph) and application assignments for any app, on your behalf.", + "userConsentDisplayName": "Manage app permission grants and app role assignments", + "value": "AppRoleAssignment.ReadWrite.All" + }, + { + "description": "Allows the app to manage permission grants for delegated permissions exposed by any API (including Microsoft Graph), on behalf of the signed in user.", + "displayName": "Manage all delegated permission grants", + "id": "41ce6ca6-6826-4807-84f1-1c82854f7ee5", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage permission grants for delegated permissions exposed by any API (including Microsoft Graph), on your behalf. ", + "userConsentDisplayName": "Manage all delegated permission grants", + "value": "DelegatedPermissionGrant.ReadWrite.All" + }, + { + "description": "Allows the app to read online meeting details on behalf of the signed-in user.", + "displayName": "Read user's online meetings", + "id": "9be106e1-f4e3-4df5-bdff-e4bc531cbe43", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read online meeting details on your behalf.", + "userConsentDisplayName": "Read your online meetings", + "value": "OnlineMeetings.Read" + }, + { + "description": "Allows the app to read and create online meetings on behalf of the signed-in user.", + "displayName": "Read and create user's online meetings", + "id": "a65f2972-a4f8-4f5e-afd7-69ccb046d5dc", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and create online meetings on your behalf.", + "userConsentDisplayName": "Read and create your online meetings", + "value": "OnlineMeetings.ReadWrite" + }, + { + "description": "Allows the app to read the signed-in user's teamwork activity feed.", + "displayName": "Read user's teamwork activity feed", + "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your teamwork activity feed.", + "userConsentDisplayName": "Read your teamwork activity feed", + "value": "TeamsActivity.Read" + }, + { + "description": "Allows the app to request and manage time-based assignment and just-in-time elevation of user privileges to manage Azure resources (like subscriptions, resource groups, storage, compute) on behalf of the signed-in users.", + "displayName": "Read and write privileged access to Azure resources", + "id": "a84a9652-ffd3-496e-a991-22ba5529156a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to request and manage time-based assignment and just-in-time elevation of user privileges to manage \u00a0your Azure resources (like your subscriptions, resource groups, storage, compute) on your behalf.", + "userConsentDisplayName": "Read and write privileged access to Azure resources", + "value": "PrivilegedAccess.ReadWrite.AzureResources" + }, + { + "description": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD built-in and custom administrative roles, on behalf of the signed-in user.", + "displayName": "Read privileged access to Azure AD", + "id": "b3a539c9-59cb-4ad5-825a-041ddbdc2bdb", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD built-in and custom administrative roles, on your behalf.", + "userConsentDisplayName": "Read privileged access to Azure AD", + "value": "PrivilegedAccess.Read.AzureAD" + }, + { + "description": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups, on behalf of the signed-in user.", + "displayName": "Read privileged access to Azure AD groups", + "id": "d329c81c-20ad-4772-abf9-3f6fdb7e5988", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups, on your behalf.", + "userConsentDisplayName": "Read privileged access to Azure AD groups", + "value": "PrivilegedAccess.Read.AzureADGroup" + }, + { + "description": "Allows the app to read time-based assignment and just-in-time elevation of Azure resources (like your subscriptions, resource groups, storage, compute) on behalf of the signed-in user.", + "displayName": "Read privileged access to Azure resources", + "id": "1d89d70c-dcac-4248-b214-903c457af83a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read time-based assignment and just-in-time elevation of Azure resources (like your subscriptions, resource groups, storage, compute) on your behalf.", + "userConsentDisplayName": "Read privileged access to your Azure resources", + "value": "PrivilegedAccess.Read.AzureResources" + }, + { + "description": "Allows the app to request and manage time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups, on behalf of the signed-in user.", + "displayName": "Read and write privileged access to Azure AD groups", + "id": "32531c59-1f32-461f-b8df-6f8a3b89f73b", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to request and manage time-based assignment and just-in-time elevation (including scheduled elevation) of Azure AD groups, on your behalf.", + "userConsentDisplayName": "Read and write privileged access to Azure AD groups", + "value": "PrivilegedAccess.ReadWrite.AzureADGroup" + }, + { + "description": "Allows the app to read all the indicators for your organization, on behalf of the signed-in user.", + "displayName": "Read all threat indicators", + "id": "9cc427b4-2004-41c5-aa22-757b755e9796", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all the indicators for your organization, on your behalf.", + "userConsentDisplayName": "Read all threat indicators", + "value": "ThreatIndicators.Read.All" + }, + { + "description": "Allow the app to read external datasets and content, on behalf of the signed-in user.", + "displayName": "Read items in external datasets", + "id": "922f9392-b1b7-483c-a4be-0089be7704fb", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read external datasets and content that you have access to.", + "userConsentDisplayName": "Read items in external datasets", + "value": "ExternalItem.Read.All" + }, + { + "description": "Allows an app to edit channel messages in Microsoft Teams, on behalf of the signed-in user.", + "displayName": "Edit user's channel messages", + "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to edit channel messages in Microsoft Teams, on your behalf.", + "userConsentDisplayName": "Edit your channel messages", + "value": "ChannelMessage.Edit" + }, + { + "description": "Allows an app to send channel messages in Microsoft Teams, on behalf of the signed-in user.", + "displayName": "Send channel messages", + "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to send channel messages in Microsoft Teams, on your behalf.", + "userConsentDisplayName": "Send channel messages", + "value": "ChannelMessage.Send" + }, + { + "description": "Allows the app to manage organization places (conference rooms and room lists) for calendar events and other applications, on behalf of the signed-in user.", + "displayName": "Read and write organization places", + "id": "4c06a06a-098a-4063-868e-5dfee3827264", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage organization places (conference rooms and room lists) for calendar events and other applications, on your behalf.", + "userConsentDisplayName": "Read and write organization places", + "value": "Place.ReadWrite.All" + }, + { + "description": "Allows the app to request access to and management of access packages and related entitlement management resources on behalf of the signed-in user.", + "displayName": "Read and write entitlement management resources", + "id": "ae7a573d-81d7-432b-ad44-4ed5c9d89038", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to request access to and management of access packages and related entitlement management resources that you have access to.", + "userConsentDisplayName": "Read and write entitlement management resources", + "value": "EntitlementManagement.ReadWrite.All" + }, + { + "description": "Allows the app to send, read, update and delete user\u2019s notifications.", + "displayName": "Deliver and manage user's notifications", + "id": "26e2f3e8-b2a1-47fc-9620-89bb5b042024", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to send, read, update and delete your app-specific notifications.", + "userConsentDisplayName": "Deliver and manage your notifications", + "value": "UserNotification.ReadWrite.CreatedByApp" + }, + { + "description": "Allows the app to read applications and service principals on behalf of the signed-in user.", + "displayName": "Read applications", + "id": "c79f8feb-a9db-4090-85f9-90d820caa0eb", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read applications and service principals on your behalf.", + "userConsentDisplayName": "Read applications", + "value": "Application.Read.All" + }, + { + "description": "Allows the app to create, read, update and delete applications and service principals on behalf of the signed-in user. Does not allow management of consent grants.", + "displayName": "Read and write all applications", + "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create, read, update and delete applications and service principals on your behalf. Does not allow management of consent grants.", + "userConsentDisplayName": "Read and write applications", + "value": "Application.ReadWrite.All" + }, + { + "description": "Allows the app to read BitLocker keys on behalf of the signed-in user, for their owned devices. Allows read of the recovery key.", + "displayName": "Read BitLocker keys", + "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read BitLocker keys for your owned devices. Allows read of the recovery key.", + "userConsentDisplayName": "Read your BitLocker keys", + "value": "BitlockerKey.Read.All" + }, + { + "description": "Allows the app to read basic BitLocker key properties on behalf of the signed-in user, for their owned devices. Does not allow read of the recovery key itself.", + "displayName": "Read BitLocker keys basic information", + "id": "5a107bfc-4f00-4e1a-b67e-66451267bc68", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read basic BitLocker key properties for your owned devices. Does not allow read of the recovery key itself.", + "userConsentDisplayName": "Read your BitLocker keys basic information", + "value": "BitlockerKey.ReadBasic.All" + }, + { + "description": "Allows the app to list groups, read basic group properties and read membership of all groups the signed-in user has access to.", + "displayName": "Read group memberships", + "id": "bc024368-1153-4739-b217-4326f2e966d0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to list groups, read basic group properties and read membership of all your groups.", + "userConsentDisplayName": "Read group memberships", + "value": "GroupMember.Read.All" + }, + { + "description": "Allows the app to list groups, read basic properties, read and update the membership of the groups the signed-in user has access to. Group properties and owners cannot be updated and groups cannot be deleted.", + "displayName": "Read and write group memberships", + "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to list groups, read basic properties, read and update the membership of your groups. Group properties and owners cannot be updated and groups cannot be deleted.", + "userConsentDisplayName": "Read and write group memberships", + "value": "GroupMember.ReadWrite.All" + }, + { + "description": "Allows an app to read your organization's threat assessment requests on behalf of the signed-in user. Also allows the app to create new requests to assess threats received by your organization on behalf of the signed-in user.", + "displayName": "Read and write threat assessment requests", + "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read your organization's threat assessment requests on your behalf. Also allows the app to create new requests to assess threats received by your organization on your behalf.", + "userConsentDisplayName": "Read and write threat assessment requests", + "value": "ThreatAssessment.ReadWrite.All" + }, + { + "description": "Allows the app to read schedule, schedule groups, shifts and associated entities in the Teams or Shifts application on behalf of the signed-in user.", + "displayName": "Read user schedule items", + "id": "fccf6dd8-5706-49fa-811f-69e2e1b585d0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read schedule, schedule groups, shifts and associated entities in the Teams or Shifts application on your behalf.", + "userConsentDisplayName": "Read your schedule items", + "value": "Schedule.Read.All" + }, + { + "description": "Allows the app to manage schedule, schedule groups, shifts and associated entities in the Teams or Shifts application on behalf of the signed-in user.", + "displayName": "Read and write user schedule items", + "id": "63f27281-c9d9-4f29-94dd-6942f7f1feb0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage schedule, schedule groups, shifts and associated entities in the Teams or Shifts application on your behalf.", + "userConsentDisplayName": "Read and write your schedule items", + "value": "Schedule.ReadWrite.All" + }, + { + "description": " Allows the app to read and write authentication methods of all users in your organization that the signed-in user has access to. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", + "displayName": "Read and write all users' authentication methods.", + "id": "b7887744-6746-4312-813d-72daeaee7e2d", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write authentication methods of all users you have access to in your organization. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", + "userConsentDisplayName": "Read and write all users' authentication methods", + "value": "UserAuthenticationMethod.ReadWrite.All" + }, + { + "description": "Allows the app to read and write the signed-in user's authentication methods, including phone numbers and Authenticator app settings. This does not allow the app to see secret information like the signed-in user's passwords, or to sign-in or otherwise use the signed-in user's authentication methods. ", + "displayName": "Read and write user authentication methods", + "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your authentication methods, including phone numbers and Authenticator app settings.This does not allow the app to see secret information like your passwords, or to sign-in or otherwise use your authentication methods.", + "userConsentDisplayName": "Read and write your authentication methods", + "value": "UserAuthenticationMethod.ReadWrite" + }, + { + "description": "Allows the app to read authentication methods of all users in your organization that the signed-in user has access to. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", + "displayName": "Read all users' authentication methods", + "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read authentication methods of all users you have access to in your organization. Authentication methods include things like a user\u2019s phone numbers and Authenticator app settings. This does not allow the app to see secret information like passwords, or to sign-in or otherwise use the authentication methods.", + "userConsentDisplayName": "Read all users' authentication methods", + "value": "UserAuthenticationMethod.Read.All" + }, + { + "description": "Allows the app to read the signed-in user's authentication methods, including phone numbers and Authenticator app settings. This does not allow the app to see secret information like the signed-in user's passwords, or to sign-in or otherwise use the signed-in user's authentication methods.", + "displayName": "Read user authentication methods.", + "id": "1f6b61c5-2f65-4135-9c9f-31c0f8d32b52", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your authentication methods, including phone numbers and Authenticator app settings. This does not allow the app to see secret information like your passwords, or to sign-in or otherwise use your authentication methods.", + "userConsentDisplayName": "Read your authentication methods.", + "value": "UserAuthenticationMethod.Read" + }, + { + "description": "Allows the app to create tabs in any team in Microsoft Teams, on behalf of the signed-in user. This does not grant the ability to read, modify or delete tabs after they are created, or give access to the content inside the tabs.", + "displayName": "Create tabs in Microsoft Teams.", + "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create tabs in any team in Microsoft Teams, on your behalf. This does not grant the ability to read, modify or delete tabs after they are created, or give access to the content inside the tabs.", + "userConsentDisplayName": "Create tabs in Microsoft Teams.", + "value": "TeamsTab.Create" + }, + { + "description": "Read the names and settings of tabs inside any team in Microsoft Teams, on behalf of the signed-in user. This does not give access to the content inside the tabs.", + "displayName": "Read tabs in Microsoft Teams.", + "id": "59dacb05-e88d-4c13-a684-59f1afc8cc98", + "Origin": "Delegated", + "userConsentDescription": "Read the names and settings of tabs inside any team in Microsoft Teams, on your behalf. This does not give access to the content inside the tabs.", + "userConsentDisplayName": "Read tabs in Microsoft Teams.", + "value": "TeamsTab.Read.All" + }, + { + "description": "Read and write tabs in any team in Microsoft Teams, on behalf of the signed-in user. This does not give access to the content inside the tabs.", + "displayName": "Read and write tabs in Microsoft Teams.", + "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", + "Origin": "Delegated", + "userConsentDescription": "Read and write tabs in any team in Microsoft Teams, on your behalf. This does not give access to the content inside the tabs.", + "userConsentDisplayName": "Read and write tabs in Microsoft Teams.", + "value": "TeamsTab.ReadWrite.All" + }, + { + "description": "Allows the app to have the same access to mailboxes as the signed-in user via IMAP protocol.", + "displayName": "Read and write access to mailboxes via IMAP.", + "id": "652390e4-393a-48de-9484-05f9b1212954", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create and delete email in your mailbox. Does not include permission to send mail.", + "userConsentDisplayName": "Read and write access to your mail.", + "value": "IMAP.AccessAsUser.All" + }, + { + "description": "Allows the app to have the same access to mailboxes as the signed-in user via POP protocol.", + "displayName": "Read and write access to mailboxes via POP.", + "id": "d7b7f2d9-0f45-4ea1-9d42-e50810c06991", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update, create and delete email in your mailbox. Does not include permission to send mail.", + "userConsentDisplayName": "Read and write access to your mail.", + "value": "POP.AccessAsUser.All" + }, + { + "description": "Allows the app to be able to send emails from the user\u2019s mailbox using the SMTP AUTH client submission protocol.", + "displayName": "Send emails from mailboxes using SMTP AUTH.", + "id": "258f6531-6087-4cc4-bb90-092c5fb3ed3f", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to send emails on your behalf from your mailbox.", + "userConsentDisplayName": "Access to sending emails from your mailbox.", + "value": "SMTP.Send" + }, + { + "description": "Allows the app to read all domain properties on behalf of the signed-in user.", + "displayName": "Read domains.", + "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all domain properties on your behalf.", + "userConsentDisplayName": "Read domains.", + "value": "Domain.Read.All" + }, + { + "description": "Allows the app to read and write all domain properties on behalf of the signed-in user. Also allows the app to add, verify and remove domains.", + "displayName": "Read and write domains", + "id": "0b5d694c-a244-4bde-86e6-eb5cd07730fe", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write all domain properties on your behalf. Also allows the app to add, verify and remove domains.", + "userConsentDisplayName": "Read and write domains", + "value": "Domain.ReadWrite.All" + }, + { + "description": "Allows the app to read and write your organization's application configuration policies on behalf of the signed-in user. This includes policies such as activityBasedTimeoutPolicy, claimsMappingPolicy, homeRealmDiscoveryPolicy, tokenIssuancePolicy and tokenLifetimePolicy.", + "displayName": "Read and write your organization's application configuration policies", + "id": "b27add92-efb2-4f16-84f5-8108ba77985c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's application configuration policies on your behalf. This includes policies such as activityBasedTimeoutPolicy, claimsMappingPolicy, homeRealmDiscoveryPolicy, tokenIssuancePolicy and tokenLifetimePolicy.", + "userConsentDisplayName": "Read and write your organization's application configuration policies", + "value": "Policy.ReadWrite.ApplicationConfiguration" + }, + { + "description": "Allows the app to read your organization's devices' configuration information on behalf of the signed-in user.", + "displayName": "Read all devices", + "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read devices' configuration information on your behalf.", + "userConsentDisplayName": "Read all devices", + "value": "Device.Read.All" + }, + { + "description": "Allows the app to read, update and delete identities that are associated with a user's account that the signed-in user has access to. This controls the identities users can sign-in with.", + "displayName": "Manage user identities", + "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, update and delete identities that are associated with a user's account that you have access to. This controls the identities users can sign-in with.", + "userConsentDisplayName": "Manage user identities", + "value": "User.ManageIdentities.All" + }, + { + "description": "Allows the app to read access packages and related entitlement management resources on behalf of the signed-in user.", + "displayName": "Read all entitlement management resources", + "id": "5449aa12-1393-4ea2-a7c7-d0e06c1a56b2", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read access packages and related entitlement management resources that you have access to.", + "userConsentDisplayName": "Read all entitlement management resources", + "value": "EntitlementManagement.Read.All" + }, + { + "description": "Create channels in any team, on behalf of the signed-in user.", + "displayName": "Create channels", + "id": "101147cf-4178-4455-9d58-02b5c164e759", + "Origin": "Delegated", + "userConsentDescription": "Create channels in any team, on your behalf.", + "userConsentDisplayName": "Create channels", + "value": "Channel.Create" + }, + { + "description": "Delete channels in any team, on behalf of the signed-in user.", + "displayName": "Delete channels", + "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", + "Origin": "Delegated", + "userConsentDescription": "Delete channels in any team, on your behalf.", + "userConsentDisplayName": "Delete channels", + "value": "Channel.Delete.All" + }, + { + "description": "Read all channel names, channel descriptions, and channel settings, on behalf of the signed-in user.", + "displayName": "Read the names, descriptions, and settings of channels", + "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", + "Origin": "Delegated", + "userConsentDescription": "Read all channel names, channel descriptions, and channel settings, on your behalf.", + "userConsentDisplayName": "Read the names, descriptions, and settings of channels", + "value": "ChannelSettings.Read.All" + }, + { + "description": "Read and write the names, descriptions, and settings of all channels, on behalf of the signed-in user.", + "displayName": "Read and write the names, descriptions, and settings of channels", + "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", + "Origin": "Delegated", + "userConsentDescription": "Read and write the names, descriptions, and settings of all channels, on your behalf.", + "userConsentDisplayName": "Read and write the names, descriptions, and settings of channels", + "value": "ChannelSettings.ReadWrite.All" + }, + { + "description": "Allows the app to read all webhook subscriptions on behalf of the signed-in user.", + "displayName": "Read all webhook subscriptions ", + "id": "5f88184c-80bb-4d52-9ff2-757288b2e9b7", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all webhook subscriptions on your behalf.", + "userConsentDisplayName": "Read all webhook subscriptions ", + "value": "Subscription.Read.All" + }, + { + "description": "Read the names and descriptions of teams, on behalf of the signed-in user.", + "displayName": "Read the names and descriptions of teams", + "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", + "Origin": "Delegated", + "userConsentDescription": "Read the names and descriptions of teams, on your behalf.", + "userConsentDisplayName": "Read the names and descriptions of teams", + "value": "Team.ReadBasic.All" + }, + { + "description": "Read channel names and channel descriptions, on behalf of the signed-in user.", + "displayName": "Read the names and descriptions of channels", + "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", + "Origin": "Delegated", + "userConsentDescription": "Read channel names and channel descriptions, on your behalf.", + "userConsentDisplayName": "Read the names and descriptions of channels", + "value": "Channel.ReadBasic.All" + }, + { + "description": "Read all teams' settings, on behalf of the signed-in user.", + "displayName": "Read teams' settings", + "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", + "Origin": "Delegated", + "userConsentDescription": "Read all teams' settings, on your behalf.", + "userConsentDisplayName": "Read teams' settings", + "value": "TeamSettings.Read.All" + }, + { + "description": "Read and change all teams' settings, on behalf of the signed-in user.", + "displayName": "Read and change teams' settings", + "id": "39d65650-9d3e-4223-80db-a335590d027e", + "Origin": "Delegated", + "userConsentDescription": "Read and change all teams' settings, on your behalf.", + "userConsentDisplayName": "Read and change teams' settings", + "value": "TeamSettings.ReadWrite.All" + }, + { + "description": "Read the members of teams, on behalf of the signed-in user.", + "displayName": "Read the members of teams", + "id": "2497278c-d82d-46a2-b1ce-39d4cdde5570", + "Origin": "Delegated", + "userConsentDescription": "Read the members of teams, on your behalf.", + "userConsentDisplayName": "Read the members of teams", + "value": "TeamMember.Read.All" + }, + { + "description": "Add and remove members from teams, on behalf of the signed-in user. Also allows changing a member's role, for example from owner to non-owner.", + "displayName": "Add and remove members from teams", + "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", + "Origin": "Delegated", + "userConsentDescription": "Add and remove members from teams, on your behalf. Also allows changing a member's role, for example from owner to non-owner.", + "userConsentDisplayName": "Add and remove members from teams and channels", + "value": "TeamMember.ReadWrite.All" + }, + { + "description": "Allows the app to read consent requests and approvals on behalf of the signed-in user.", + "displayName": "Read consent requests", + "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read consent requests and approvals, on your behalf.", + "userConsentDisplayName": "Read consent requests", + "value": "ConsentRequest.Read.All" + }, + { + "description": "Allows the app to read app consent requests and approvals, and deny or approve those requests on behalf of the signed-in user.", + "displayName": "Read and write consent requests", + "id": "497d9dfa-3bd1-481a-baab-90895e54568c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read app consent requests for your approval, and deny or approve those request on your behalf.", + "userConsentDisplayName": "Read and write consent requests", + "value": "ConsentRequest.ReadWrite.All" + }, + { + "description": "Allows the app to read and write your organization's consent requests policy on behalf of the signed-in user.", + "displayName": "Read and write consent request policy", + "id": "4d135e65-66b8-41a8-9f8b-081452c91774", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's consent request policy on your behalf.", + "userConsentDisplayName": "Read and write consent request policy", + "value": "Policy.ReadWrite.ConsentRequest" + }, + { + "description": "Allows the app to read presence information on behalf of the signed-in user. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", + "displayName": "Read user's presence information", + "id": "76bc735e-aecd-4a1d-8b4c-2b915deabb79", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your presence information on your behalf. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", + "userConsentDisplayName": "Read your presence information", + "value": "Presence.Read" + }, + { + "description": "Allows the app to read presence information of all users in the directory on behalf of the signed-in user. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", + "displayName": "Read presence information of all users in your organization", + "id": "9c7a330d-35b3-4aa1-963d-cb2b9f927841", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read presence information of all users in the directory on your behalf. Presence information includes activity, availability, status note, calendar out-of-office message, timezone and location.", + "userConsentDisplayName": "Read presence information of all users in your organization", + "value": "Presence.Read.All" + }, + { + "description": "Read the members of channels, on behalf of the signed-in user.", + "displayName": "Read the members of channels", + "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", + "Origin": "Delegated", + "userConsentDescription": "Read the members of channels, on your behalf.", + "userConsentDisplayName": "Read the members of teams and channels", + "value": "ChannelMember.Read.All" + }, + { + "description": "Add and remove members from channels, on behalf of the signed-in user. Also allows changing a member's role, for example from owner to non-owner.", + "displayName": "Add and remove members from channels", + "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", + "Origin": "Delegated", + "userConsentDescription": "Add and remove members from channels, on your behalf. Also allows changing a member's role, for example from owner to non-owner.", + "userConsentDisplayName": "Add and remove members from teams and channels", + "value": "ChannelMember.ReadWrite.All" + }, + { + "description": "Allows the app to read and write the authentication flow policies, on behalf of the signed-in user. ", + "displayName": "Read and write authentication flow policies", + "id": "edb72de9-4252-4d03-a925-451deef99db7", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the authentication flow policies for your tenant, on your behalf.", + "userConsentDisplayName": "Read and write your authentication flow policies", + "value": "Policy.ReadWrite.AuthenticationFlows" + }, + { + "description": "Allows an app to read a channel's messages in Microsoft Teams, on behalf of the signed-in user.", + "displayName": "Read user channel messages", + "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read a channel's messages in Microsoft Teams, on your behalf.", + "userConsentDisplayName": "Read your channel messages", + "value": "ChannelMessage.Read.All" + }, + { + "description": "Allows the app to read the apps in the app catalogs.", + "displayName": "Read all app catalogs", + "id": "88e58d74-d3df-44f3-ad47-e89edf4472e4", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read apps in the app catalogs.", + "userConsentDisplayName": "Read all app catalogs", + "value": "AppCatalog.Read.All" + }, + { + "description": "Allows the app to read and write the authentication method policies, on behalf of the signed-in user.\u00a0", + "displayName": "Read and write authentication method policies", + "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the authentication method policies for your tenant, on your behalf.", + "userConsentDisplayName": "Read and write your authentication method policies ", + "value": "Policy.ReadWrite.AuthenticationMethod" + }, + { + "description": "Allows the app to read and write your organization's authorization policy on behalf of the signed-in user. For example, authorization policies can control some of the permissions that the out-of-the-box user role has by default.", + "displayName": "Read and write your organization's authorization policy", + "id": "edd3c878-b384-41fd-95ad-e7407dd775be", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's authorization policy on your behalf. For example, authorization policies can control some of the permissions that the out-of-the-box user role has by default.", + "userConsentDisplayName": "Read and write your organization's authorization policy", + "value": "Policy.ReadWrite.Authorization" + }, + { + "description": "Allows the app to read policies related to consent and permission grants for applications, on behalf of the signed-in user.", + "displayName": "Read consent and permission grant policies", + "id": "414de6ea-2d92-462f-b120-6e2a809a6d01", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read policies related to consent and permission grants for applications, on your behalf.", + "userConsentDisplayName": "Read consent and permission grant policies", + "value": "Policy.Read.PermissionGrant" + }, + { + "description": "Allows the app to manage policies related to consent and permission grants for applications, on behalf of the signed-in user.", + "displayName": "Manage consent and permission grant policies", + "id": "2672f8bb-fd5e-42e0-85e1-ec764dd2614e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage policies related to consent and permission grants for applications, on behalf of the signed-in user.", + "userConsentDisplayName": "Manage consent and permission grant policies", + "value": "Policy.ReadWrite.PermissionGrant" + }, + { + "description": "Allows the application to create (register) printers on behalf of the signed-in user.\u00a0", + "displayName": "Register printers\u202f\u00a0", + "id": "90c30bed-6fd1-4279-bf39-714069619721", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to create (register) printers on your behalf.\u00a0", + "userConsentDisplayName": "Register printers\u202f\u00a0", + "value": "Printer.Create" + }, + { + "description": "Allows the application to create (register), read, update, and delete (unregister) printers on behalf of the signed-in user.\u00a0", + "displayName": "Register, read, update, and unregister printers", + "id": "93dae4bd-43a1-4a23-9a1a-92957e1d9121", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to create (register), read, update, and delete (unregister) printers on your behalf.\u00a0\u00a0", + "userConsentDisplayName": "Register, read, update, and unregister printers", + "value": "Printer.FullControl.All" + }, + { + "description": "Allows the application to read printers on behalf of the signed-in user.\u00a0", + "displayName": "Read printers", + "id": "3a736c8a-018e-460a-b60c-863b2683e8bf", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read printers on your behalf.\u00a0", + "userConsentDisplayName": "Read printers", + "value": "Printer.Read.All" + }, + { + "description": "Allows the application to read and update printers on behalf of the signed-in user.\u00a0Does not allow creating (registering) or deleting (unregistering) printers.", + "displayName": "Read and update printers", + "id": "89f66824-725f-4b8f-928e-e1c5258dc565", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and update printers on your behalf.\u00a0Does not allow creating (registering) or deleting (unregistering) printers.", + "userConsentDisplayName": "Read and update printers", + "value": "Printer.ReadWrite.All" + }, + { + "description": "Allows the application to read printer shares on behalf of the signed-in user.\u00a0", + "displayName": "Read printer shares", + "id": "ed11134d-2f3f-440d-a2e1-411efada2502", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read printer shares on your behalf.\u00a0", + "userConsentDisplayName": "Read printer shares", + "value": "PrinterShare.Read.All" + }, + { + "description": "Allows the application to read and update printer shares on behalf of the signed-in user.\u00a0", + "displayName": "Read and write printer shares", + "id": "06ceea37-85e2-40d7-bec3-91337a46038f", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and update printer shares on your behalf.\u00a0", + "userConsentDisplayName": "Read and update printer shares", + "value": "PrinterShare.ReadWrite.All" + }, + { + "description": "Allows the application to read the metadata and document content of print jobs that the signed-in user created.", + "displayName": "Read user's print jobs", + "id": "248f5528-65c0-4c88-8326-876c7236df5e", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read the metadata and document content of print jobs that you created.", + "userConsentDisplayName": "Read your print jobs", + "value": "PrintJob.Read" + }, + { + "description": "Allows the application to read the metadata and document content of print jobs on behalf of the signed-in user.\u00a0", + "displayName": "Read print jobs", + "id": "afdd6933-a0d8-40f7-bd1a-b5d778e8624b", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read the metadata and document content of print jobs on your behalf.\u00a0", + "userConsentDisplayName": "Read print jobs", + "value": "PrintJob.Read.All" + }, + { + "description": "Allows the application to read the metadata of print jobs that the signed-in user created. Does not allow access to print job document content.", + "displayName": "Read basic information of user's print jobs", + "id": "6a71a747-280f-4670-9ca0-a9cbf882b274", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read the metadata of print jobs that you created. Does not allow access to print job document content.", + "userConsentDisplayName": "Read basic information of your print jobs", + "value": "PrintJob.ReadBasic" + }, + { + "description": "Allows the application to read the metadata of print jobs on behalf of the signed-in user.\u00a0Does not allow access to print job document content.", + "displayName": "Read basic information of print jobs", + "id": "04ce8d60-72ce-4867-85cf-6d82f36922f3", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read the metadata of print jobs on your behalf.\u00a0Does not allow access to print job document content.", + "userConsentDisplayName": "Read basic information of print jobs", + "value": "PrintJob.ReadBasic.All" + }, + { + "description": "Allows the application to read and update the metadata and document content of print jobs that the signed-in user created.", + "displayName": "Read and write user's print jobs", + "id": "b81dd597-8abb-4b3f-a07a-820b0316ed04", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and update the metadata and document content of print jobs that you created.", + "userConsentDisplayName": "Read and update your print jobs", + "value": "PrintJob.ReadWrite" + }, + { + "description": "Allows the application to read and update the metadata and document content of print jobs on behalf of the signed-in user.\u00a0", + "displayName": "Read and write print jobs", + "id": "036b9544-e8c5-46ef-900a-0646cc42b271", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and update the metadata and document content of print jobs on your behalf.\u00a0", + "userConsentDisplayName": "Read and update print jobs", + "value": "PrintJob.ReadWrite.All" + }, + { + "description": "Allows the application to read and update the metadata of print jobs that the signed-in user created. Does not allow access to print job document content.", + "displayName": "Read and write basic information of user's print jobs", + "id": "6f2d22f2-1cb6-412c-a17c-3336817eaa82", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and update the metadata of print jobs that you created. Does not allow access to print job document content.", + "userConsentDisplayName": "Read and write basic information of your print jobs", + "value": "PrintJob.ReadWriteBasic" + }, + { + "description": "Allows the application to read and update the metadata of print jobs on behalf of the signed-in user.\u00a0Does not allow access to print job document content.", + "displayName": "Read and write basic information of print jobs", + "id": "3a0db2f6-0d2a-4c19-971b-49109b19ad3d", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and update the metadata of print jobs on your behalf.\u00a0Does not allow access to print job document content.", + "userConsentDisplayName": "Read and write basic information of print jobs", + "value": "PrintJob.ReadWriteBasic.All" + }, + { + "description": "Allows the app to read and write your organization's device configuration policies on behalf of the signed-in user. For example, device registration policy can limit initial provisioning controls using quota restrictions, additional authentication and authorization checks.", + "displayName": "Read and write your organization's device configuration policies", + "id": "40b534c3-9552-4550-901b-23879c90bcf9", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write your organization's device configuration policies on your behalf. For example, device registration policy can limit initial provisioning controls using quota restrictions, additional authentication and authorization checks.", + "userConsentDisplayName": "Read and write your organization's device configuration policies", + "value": "Policy.ReadWrite.DeviceConfiguration" + }, + { + "description": "Allows the app to submit application packages to the catalog and cancel submissions that are pending review on behalf of the signed-in user.", + "displayName": "Submit application packages to the catalog and cancel pending submissions", + "id": "3db89e36-7fa6-4012-b281-85f3d9d9fd2e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to submit application packages to the catalog and cancel submissions that are pending review on your behalf.", + "userConsentDisplayName": "Submit application packages to your organization's catalog and cancel pending submissions", + "value": "AppCatalog.Submit" + }, + { + "description": "Allows the app to read the Teams apps that are installed in chats the signed-in user can access. Does not give the ability to read application-specific settings.", + "displayName": "Read installed Teams apps in chats", + "id": "bf3fbf03-f35f-4e93-963e-47e4d874c37a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the Teams apps that are installed in chats that you can access. Does not give the ability to read application-specific settings.", + "userConsentDisplayName": "Read installed Teams apps in chats", + "value": "TeamsAppInstallation.ReadForChat" + }, + { + "description": "Allows the app to read the Teams apps that are installed in teams the signed-in user can access. Does not give the ability to read application-specific settings.", + "displayName": "Read installed Teams apps in teams", + "id": "5248dcb1-f83b-4ec3-9f4d-a4428a961a72", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the Teams apps that are installed in teams that you can access. Does not give the ability to read application-specific settings.", + "userConsentDisplayName": "Read installed Teams apps in teams", + "value": "TeamsAppInstallation.ReadForTeam" + }, + { + "description": "Allows the app to read the Teams apps that are installed for the signed-in user. Does not give the ability to read application-specific settings.", + "displayName": "Read user's installed Teams apps", + "id": "c395395c-ff9a-4dba-bc1f-8372ba9dca84", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the Teams apps that are installed for you. Does not give the ability to read application-specific settings.", + "userConsentDisplayName": "Read your installed Teams apps", + "value": "TeamsAppInstallation.ReadForUser" + }, + { + "description": "Allows the app to read, install, upgrade, and uninstall Teams apps in teams the signed-in user can access. Does not give the ability to read application-specific settings.", + "displayName": "Manage installed Teams apps in teams", + "id": "2e25a044-2580-450d-8859-42eeb6e996c0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, install, upgrade, and uninstall Teams apps in teams you can access. Does not give the ability to read application-specific settings.", + "userConsentDisplayName": "Manage installed Teams apps in teams", + "value": "TeamsAppInstallation.ReadWriteForTeam" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall itself in chats the signed-in user can access.", + "displayName": "Allow the Teams app to manage itself in chats", + "id": "0ce33576-30e8-43b7-99e5-62f8569a4002", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall itself in chats you can access.", + "userConsentDisplayName": "Allow the Teams app to manage itself in chats", + "value": "TeamsAppInstallation.ReadWriteSelfForChat" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall itself for the signed-in user.", + "displayName": "Allow the Teams app to manage itself for a user", + "id": "207e0cb1-3ce7-4922-b991-5a760c346ebc", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall itself for you.", + "userConsentDisplayName": "Allow the Teams app to manage itself for you", + "value": "TeamsAppInstallation.ReadWriteSelfForUser" + }, + { + "description": "Allows the app to read, install, upgrade, and uninstall Teams apps installed for the signed-in user. Does not give the ability to read application-specific settings.", + "displayName": "Manage user's installed Teams apps", + "id": "093f8818-d05f-49b8-95bc-9d2a73e9a43c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, install, upgrade, and uninstall Teams apps installed for you. Does not give the ability to read application-specific settings.", + "userConsentDisplayName": "Manage your installed Teams apps", + "value": "TeamsAppInstallation.ReadWriteForUser" + }, + { + "description": "Allows the app to create teams on behalf of the signed-in user.", + "displayName": "Create teams", + "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create teams on your behalf.\u00a0", + "userConsentDisplayName": "Create teams", + "value": "Team.Create" + }, + { + "description": "Add and remove members from all teams, on behalf of the signed-in user. Does not allow adding or removing a member with the owner role. Additionally, does not allow the app to elevate an existing member to the owner role.", + "displayName": "Add and remove members with non-owner role for all teams", + "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", + "Origin": "Delegated", + "userConsentDescription": "Add and remove members from all teams, on your behalf. Does not allow adding or removing a member with the owner role. Additionally, does not allow the app to elevate an existing member to the owner role.", + "userConsentDisplayName": "Add and remove members with non-owner role for all teams", + "value": "TeamMember.ReadWriteNonOwnerRole.All" + }, + { + "description": "Allows the app to read the term store data that the signed-in user has access to. This includes all sets, groups and terms in the term store.", + "displayName": "Read term store data", + "id": "297f747b-0005-475b-8fef-c890f5152b38", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the term store data that you have access to. This includes all sets, groups and terms in the term store.", + "userConsentDisplayName": "Read term store data", + "value": "TermStore.Read.All" + }, + { + "description": "Allows the app to read or modify data that the signed-in user has access to.\u00a0This includes all sets, groups and terms in the term store.", + "displayName": "Read and write term store data", + "id": "6c37c71d-f50f-4bff-8fd3-8a41da390140", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read or modify data that you have access to. This includes all sets, groups and terms in the term store.", + "userConsentDisplayName": "Read and write term store data", + "value": "TermStore.ReadWrite.All" + }, + { + "description": "Allows the app to read your tenant's service announcement messages on behalf of the signed-in user. Messages may include information about new or changed features.", + "displayName": "Read service announcement messages", + "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your tenant's service announcement messages on your behalf. Messages may include information about new or changed features.", + "userConsentDisplayName": "Read service messages", + "value": "ServiceMessage.Read.All" + }, + { + "description": "Allows the app to read your tenant's service health information on behalf of the signed-in user. Health information may include service issues or service health overviews.", + "displayName": "Read service health", + "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your tenant's service health information on your behalf.Health information may include service issues or service health overviews.", + "userConsentDisplayName": "Read service health", + "value": "ServiceHealth.Read.All" + }, + { + "description": "Allows the app to read all the short notes a sign-in user has access to.", + "displayName": "Read short notes of the signed-in user", + "id": "50f66e47-eb56-45b7-aaa2-75057d9afe08", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your short notes.", + "userConsentDisplayName": "Read your short notes", + "value": "ShortNotes.Read" + }, + { + "description": "Allows the app to read, create, edit, and delete short notes of a signed-in user.", + "displayName": "Read, create, edit, and delete short notes of the signed-in user", + "id": "328438b7-4c01-4c07-a840-e625a749bb89", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, create, edit, and delete your short notes.", + "userConsentDisplayName": "Read, create, edit, and delete your short notes", + "value": "ShortNotes.ReadWrite" + }, + { + "description": "Allows the app to read your organization's conditional access policies on behalf of the signed-in user.", + "displayName": "Read your organization's conditional access policies", + "id": "633e0fce-8c58-4cfb-9495-12bbd5a24f7c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization's conditional access policies on your behalf.", + "userConsentDisplayName": "Read your organization's conditional access policies", + "value": "Policy.Read.ConditionalAccess" + }, + { + "description": "Allows the app to read the role-based access control (RBAC) settings for all RBAC providers, on behalf of the signed-in user. This includes reading role definitions and role assignments.", + "displayName": "Read role management data for all RBAC providers", + "id": "48fec646-b2ba-4019-8681-8eb31435aded", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the role-based access control (RBAC) settings for all RBAC providers, on your behalf. This includes reading role definitions and role assignments.", + "userConsentDisplayName": "Read role management data for all RBAC providers", + "value": "RoleManagement.Read.All" + }, + { + "description": "Allows an app to send one-to-one and group chat messages in Microsoft Teams, on behalf of the signed-in user.", + "displayName": "Send user chat messages", + "id": "116b7235-7cc6-461e-b163-8e55691d839e", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to send one-to-one and group chat messages in Microsoft Teams, on your behalf.", + "userConsentDisplayName": "Send chat messages", + "value": "ChatMessage.Send" + }, + { + "description": "Allows an app to read the members and descriptions of one-to-one and group chat threads, on behalf of the signed-in user.", + "displayName": "Read names and members of user chat threads", + "id": "9547fcb5-d03f-419d-9948-5928bbf71b0f", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read the members and descriptions of one-to-one and group chat threads, on your behalf.", + "userConsentDisplayName": "Read names and members of your chat threads", + "value": "Chat.ReadBasic" + }, + { + "description": "Allows the app to read and write the properties of Cloud PCs on behalf of the signed-in user.", + "displayName": "Read and write Cloud PCs", + "id": "9d77138f-f0e2-47ba-ab33-cd246c8b79d1", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the properties of Cloud PCs, on your behalf.", + "userConsentDisplayName": "Read and write Cloud PCs", + "value": "CloudPC.ReadWrite.All" + }, + { + "description": "Allows the app to read the properties of Cloud PCs on behalf of the signed-in user.", + "displayName": "Read Cloud PCs", + "id": "5252ec4e-fd40-4d92-8c68-89dd1d3c6110", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the properties of Cloud PCs, on your behalf.", + "userConsentDisplayName": "Read Cloud PCs", + "value": "CloudPC.Read.All" + }, + { + "description": "Allows the app to read, install, upgrade, and uninstall Teams apps in chats the signed-in user can access. Does not give the ability to read application-specific settings.", + "displayName": "Manage installed Teams apps in chats", + "id": "aa85bf13-d771-4d5d-a9e6-bca04ce44edf", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, install, upgrade, and uninstall Teams apps in chats you can access. Does not give the ability to read application-specific settings.", + "userConsentDisplayName": "Manage installed Teams apps in chats", + "value": "TeamsAppInstallation.ReadWriteForChat" + }, + { + "description": "Allows the app to create, read, update, and delete the signed-in user's tasks and task lists, including any shared with the user.", + "displayName": "Create, read, update, and delete user\u2019s tasks and task lists", + "id": "2219042f-cab5-40cc-b0d2-16b1540b4c5f", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create, read, update, and delete your tasks and task lists, including any shared with you.", + "userConsentDisplayName": "Create, read, update, and delete your tasks and task lists", + "value": "Tasks.ReadWrite" + }, + { + "description": "Allows the app to read the signed-in user\u2019s tasks and task lists, including any shared with the user. Doesn't include permission to create, delete, or update anything.", + "displayName": "Read user's tasks and task lists", + "id": "f45671fb-e0fe-4b4b-be20-3d3ce43f1bcb", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your tasks and task lists, including any shared with you. Doesn't include permission to create, delete, or update anything.", + "userConsentDisplayName": "Read your tasks and task lists", + "value": "Tasks.Read" + }, + { + "description": "Allows an app to read one-to-one and group chat messages, on behalf of the signed-in user.", + "displayName": "Read user chat messages", + "id": "cdcdac3a-fd45-410d-83ef-554db620e5c7", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read one-to-one or group chat messages in Microsoft Teams, on your behalf.", + "userConsentDisplayName": "Read user chat messages", + "value": "ChatMessage.Read" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs in chats the signed-in user can access.", + "displayName": "Allow the Teams app to manage all tabs in chats", + "id": "ee928332-e9c2-4747-b4a0-f8c164b68de6", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall all tabs in chats you can access.", + "userConsentDisplayName": "Allow the Teams app to manage all tabs in chats", + "value": "TeamsTab.ReadWriteForChat" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs to teams the signed-in user can access.", + "displayName": "Allow the Teams app to manage all tabs in teams", + "id": "c975dd04-a06e-4fbb-9704-62daad77bb49", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall all tabs to teams you can access.", + "userConsentDisplayName": "Allow the app to manage all tabs in teams", + "value": "TeamsTab.ReadWriteForTeam" + }, + { + "description": "Allows a Teams app to read, install, upgrade, and uninstall all tabs for the signed-in user.", + "displayName": "Allow the Teams app to manage all tabs for a user", + "id": "c37c9b61-7762-4bff-a156-afc0005847a0", + "Origin": "Delegated", + "userConsentDescription": "Allows a Teams app to read, install, upgrade, and uninstall all tabs for you.", + "userConsentDisplayName": "Allow the Teams app to manage all tabs for you", + "value": "TeamsTab.ReadWriteForUser" + }, + { + "description": "Allows the app to read the API connectors used in user authentication flows, on behalf of the signed-in user.", + "displayName": "Read API connectors for authentication flows", + "id": "1b6ff35f-31df-4332-8571-d31ea5a4893f", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the API connectors used in user authentication flows, on your behalf.", + "userConsentDisplayName": "Read API connectors for authentication flows", + "value": "APIConnectors.Read.All" + }, + { + "description": "Allows the app to read, create and manage the API connectors used in user authentication flows, on behalf of the signed-in user.", + "displayName": "Read and write API connectors for authentication flows", + "id": "c67b52c5-7c69-48b6-9d48-7b3af3ded914", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read, create and manage the API connectors used in user authentication flows, on your behalf.", + "userConsentDisplayName": "Read and write API connectors for authentication flows", + "value": "APIConnectors.ReadWrite.All" + }, + { + "description": "Read the members of chats, on behalf of the signed-in user.", + "displayName": "Read the members of chats", + "id": "c5a9e2b1-faf6-41d4-8875-d381aa549b24", + "Origin": "Delegated", + "userConsentDescription": "Read the members of chats, on your behalf.", + "userConsentDisplayName": "Read the members of chats", + "value": "ChatMember.Read" + }, + { + "description": "Add and remove members from chats, on behalf of the signed-in user.", + "displayName": "Add and remove members from chats", + "id": "dea13482-7ea6-488f-8b98-eb5bbecf033d", + "Origin": "Delegated", + "userConsentDescription": "Add and remove members from chats, on your behalf.", + "userConsentDisplayName": "Add and remove members from chats", + "value": "ChatMember.ReadWrite" + }, + { + "description": "Allows the app to create chats on behalf of the signed-in user.", + "displayName": "Create chats", + "id": "38826093-1258-4dea-98f0-00003be2b8d0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create chats on your behalf.\u00a0", + "userConsentDisplayName": "Create chats", + "value": "Chat.Create" + }, + { + "description": "Allows the application to read and write tenant-wide print settings on behalf of the signed-in user.", + "displayName": "Read and write tenant-wide print settings", + "id": "9ccc526a-c51c-4e5c-a1fd-74726ef50b8f", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and write tenant-wide print settings on your behalf.", + "userConsentDisplayName": "Read and write tenant-wide print settings", + "value": "PrintSettings.ReadWrite.All" + }, + { + "description": "Allows the application to read tenant-wide print settings on behalf of the signed-in user.", + "displayName": "Read tenant-wide print settings", + "id": "490f32fd-d90f-4dd7-a601-ff6cdc1a3f6c", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read tenant-wide print settings on your behalf.", + "userConsentDisplayName": "Read tenant-wide print settings", + "value": "PrintSettings.Read.All" + }, + { + "description": "Allows the application to read and write print connectors on behalf of the signed-in user. ", + "displayName": "Read and write print connectors", + "id": "79ef9967-7d59-4213-9c64-4b10687637d8", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and write print connectors on your behalf.", + "userConsentDisplayName": "Read and write print connectors", + "value": "PrintConnector.ReadWrite.All" + }, + { + "description": "Allows the application to read print connectors on behalf of the signed-in user.", + "displayName": "Read print connectors", + "id": "d69c2d6d-4f72-4f99-a6b9-663e32f8cf68", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read print connectors on your behalf.", + "userConsentDisplayName": "Read print connectors", + "value": "PrintConnector.Read.All" + }, + { + "description": "Allows the application to read basic information about printer shares on behalf of the signed-in user. Does not allow reading access control information.", + "displayName": "Read basic information about printer shares", + "id": "5fa075e9-b951-4165-947b-c63396ff0a37", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read basic information about printer shares on your behalf.", + "userConsentDisplayName": "Read basic information about printer shares", + "value": "PrinterShare.ReadBasic.All" + }, + { + "description": "Allows the application to create print jobs on behalf of the signed-in user and upload document content to print jobs that the signed-in user created.", + "displayName": "Create print jobs", + "id": "21f0d9c0-9f13-48b3-94e0-b6b231c7d320", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to create print jobs on your behalf and upload document content to print jobs that you created.", + "userConsentDisplayName": "Create your print jobs", + "value": "PrintJob.Create" + }, + { + "description": "Allows the app to read Azure AD recommendations, on behalf of the signed-in user.", + "displayName": "Read Azure AD recommendations", + "id": "34d3bd24-f6a6-468c-b67c-0c365c1d6410", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read Azure AD recommendations, on your behalf.", + "userConsentDisplayName": "Read Azure AD recommendations", + "value": "DirectoryRecommendations.Read.All" + }, + { + "description": "Allows the application to list and query user profile information associated with the current tenant on behalf of the signed-in user.\u00a0 It also permits the application to export and remove external user data (e.g. customer content or system-generated logs), associated with the current tenant on behalf of the signed-in user.", + "displayName": "Read shared cross-tenant user profile and export or delete data", + "id": "eed0129d-dc60-4f30-8641-daf337a39ffd", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to list and query shared user profile information associated with the current tenant on your behalf.\u00a0 It also permits the application to export and remove your external user data (e.g. customer content or system-generated logs), associated with the current tenant on your behalf.", + "userConsentDisplayName": "Read shared cross-tenant user profile and export or delete data", + "value": "CrossTenantUserProfileSharing.ReadWrite" + }, + { + "description": "Allows the app to manage restricted resources based on the other permissions granted to the app, on behalf of the signed-in user.", + "displayName": "Manage restricted resources in the directory", + "id": "cba5390f-ed6a-4b7f-b657-0efc2210ed20", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage restricted resources based on the other permissions granted to the app, on your behalf.", + "userConsentDisplayName": "Manage restricted resources in the directory", + "value": "Directory.Write.Restricted" + }, + { + "description": "Allows the app to read your organization's threat submission policies on behalf of the signed-in user. Also allows the app to create new threat submission policies on behalf of the signed-in user.", + "displayName": "Read and write all threat submission policies", + "id": "059e5840-5353-4c68-b1da-666a033fc5e8", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization's threat submission policies on your behalf. Also allows the app to create new threat submission policies on your behalf.", + "userConsentDisplayName": "Read and write all threat submission policies", + "value": "ThreatSubmissionPolicy.ReadWrite.All" + }, + { + "description": "Allows an app to read the browser site lists configured for your organization, on behalf of the signed-in user.", + "displayName": "Read browser site lists for your organization", + "id": "fb9be2b7-a7fc-4182-aec1-eda4597c43d5", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read the browser site lists configured for your organization, on your behalf.", + "userConsentDisplayName": "Read browser site lists for your organization", + "value": "BrowserSiteLists.Read.All" + }, + { + "description": "Allows the application to list and query any shared user profile information associated with the current tenant on behalf of the signed-in user.\u00a0 It also permits the application to export and remove external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant on behalf of the signed-in user.", + "displayName": "Read all shared cross-tenant user profiles and export or delete their data", + "id": "64dfa325-cbf8-48e3-938d-51224a0cac01", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to list and query any shared user profile information associated with the current tenant on your behalf.\u00a0 It also permits the application to export and remove external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant on your behalf.", + "userConsentDisplayName": "Read any shared cross-tenant user profiles and export or delete data", + "value": "CrossTenantUserProfileSharing.ReadWrite.All" + }, + { + "description": "Allows the app to read the threat submissions and threat submission policies owned by the signed-in user.", + "displayName": "Read threat submissions", + "id": "fd5353c6-26dd-449f-a565-c4e16b9fce78", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the threat submissions and threat submission policies that you own on your behalf.", + "userConsentDisplayName": "Read threat submissions", + "value": "ThreatSubmission.Read" + }, + { + "description": "Allows the app to read the threat submissions and threat submission policies owned by the signed-in user. Also allows the app to create new threat submissions on behalf of the signed-in user.", + "displayName": "Read and write threat submissions", + "id": "68a3156e-46c9-443c-b85c-921397f082b5", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the threat submissions and threat submission policies that you own. Also allows the app to create new threat submissions on your behalf.", + "userConsentDisplayName": "Read and write threat submissions", + "value": "ThreatSubmission.ReadWrite" + }, + { + "description": "Allows the app to read all recordings of online meetings, on behalf of the signed-in user.", + "displayName": "Read all recordings of online meetings.", + "id": "190c2bb6-1fdd-4fec-9aa2-7d571b5e1fe3", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all recordings of online meetings, on your behalf.\u00a0", + "userConsentDisplayName": "Read all recordings of online meetings.\u00a0", + "value": "OnlineMeetingRecording.Read.All" + }, + { + "description": "Allows the application to obtain basic tenant information about another target tenant within the Azure AD ecosystem on behalf of the signed-in user.", + "displayName": "Read cross-tenant basic information", + "id": "81594d25-e88e-49cf-ac8c-fecbff49f994", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to obtain basic tenant information about another target tenant within the Azure AD ecosystem on your behalf.", + "userConsentDisplayName": "Read cross-tenant basic information", + "value": "CrossTenantInformation.ReadBasic.All" + }, + { + "description": "Allows the app to read your organization's authentication event listeners on behalf of the signed-in user.", + "displayName": "Read your organization's authentication event listeners", + "id": "f7dd3bed-5eec-48da-bc73-1c0ef50bc9a1", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization's authentication event listeners on your behalf.", + "userConsentDisplayName": "Read your organization's authentication event listeners", + "value": "EventListener.Read.All" + }, + { + "description": "Allows the app to read the Teams app settings on behalf of the signed-in user.", + "displayName": "Read Teams app settings", + "id": "44e060c4-bbdc-4256-a0b9-dcc0396db368", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the Teams app settings on your behalf.", + "userConsentDisplayName": "Read Teams app settings", + "value": "TeamworkAppSettings.Read.All" + }, + { + "description": "Allows\u00a0the\u00a0app\u00a0to\u00a0manage learning\u00a0content\u00a0in\u00a0the\u00a0organization's\u00a0directory, on behalf of the signed-in user.", + "displayName": "Manage\u00a0learning\u00a0content", + "id": "53cec1c4-a65f-4981-9dc1-ad75dbf1c077", + "Origin": "Delegated", + "userConsentDescription": "Allows\u00a0the\u00a0app\u00a0to\u00a0manage learning\u00a0content\u00a0in\u00a0the\u00a0organization's\u00a0directory, on your behalf.", + "userConsentDisplayName": "Manage learning content", + "value": "LearningContent.ReadWrite.All" + }, + { + "description": "Allows the app to create, update, read, and delete data for the learning provider in the organization's directory, on behalf of the signed-in user.", + "displayName": "Manage\u00a0learning\u00a0provider", + "id": "40c2eb57-abaf-49f5-9331-e90fd01f7130", + "Origin": "Delegated", + "userConsentDescription": "Allows\u00a0the\u00a0app\u00a0to\u00a0create, update, read, and delete\u00a0data\u00a0for\u00a0the learning\u00a0provider\u00a0in\u00a0the organization's\u00a0directory, on your behalf.", + "userConsentDisplayName": "Manage learning provider", + "value": "LearningProvider.ReadWrite" + }, + { + "description": "Allows the app to read the lifecycle information like employeeLeaveDateTime of users in your organization, on behalf of the signed-in user.", + "displayName": "Read all users' lifecycle information", + "id": "ed8d2a04-0374-41f1-aefe-da8ac87ccc87", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read the lifecycle information like employeeLeaveDateTime of users in your organization, on behalf of the signed-in user.", + "userConsentDisplayName": "Read all users' lifecycle information", + "value": "User-LifeCycleInfo.Read.All" + }, + { + "description": "Allows an app to read and write the browser site lists configured for your organization, on behalf of the signed-in user.", + "displayName": "Read and write browser site lists for your organization", + "id": "83b34c85-95bf-497b-a04e-b58eca9d49d0", + "Origin": "Delegated", + "userConsentDescription": "Allows an app to read and write the browser site lists configured for your organization, on your behalf.", + "userConsentDisplayName": "Read and write browser site lists for your organization", + "value": "BrowserSiteLists.ReadWrite.All" + }, + { + "description": "Allows the application to list and query user profile information associated with the current tenant on behalf of the signed-in user.\u00a0 It also permits the application to export external user data (e.g. customer content or system-generated logs), associated with the current tenant on behalf of the signed-in user.", + "displayName": "Read shared cross-tenant user profile and export data", + "id": "cb1ba48f-d22b-4325-a07f-74135a62ee41", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to list and query shared user profile information associated with the current tenant on your behalf.\u00a0 It also permits the application to export your external user data (e.g. customer content or system-generated logs), associated with the current tenant on your behalf.", + "userConsentDisplayName": "Read shared cross-tenant user profile and export data", + "value": "CrossTenantUserProfileSharing.Read" + }, + { + "description": "Allows the app to read admin report settings, such as whether to display concealed information in reports, on behalf of the signed-in user", + "displayName": "Read admin report settings", + "id": "84fac5f4-33a9-4100-aa38-a20c6d29e5e7", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read admin report settings, such as whether to display concealed information in reports, on your behalf.", + "userConsentDisplayName": "Read admin report settings", + "value": "ReportSettings.Read.All" + }, + { + "description": "Allows the app to read and write the lifecycle information like employeeLeaveDateTime of users in your organization, on behalf of the signed-in user.", + "displayName": "Read and write all users' lifecycle information", + "id": "7ee7473e-bd4b-4c9f-987c-bd58481f5fa2", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the lifecycle information like employeeLeaveDateTime of users in your organization, on behalf of the signed-in user.", + "userConsentDisplayName": "Read and write all users' lifecycle information", + "value": "User-LifeCycleInfo.ReadWrite.All" + }, + { + "description": "Allows the app to read and update Azure AD recommendations, on behalf of the signed-in user. ", + "displayName": "Read and update Azure AD recommendations", + "id": "f37235e8-90a0-4189-93e2-e55b53867ccd", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and update Azure AD recommendations, on your behalf.", + "userConsentDisplayName": "Read and update Azure AD recommendations", + "value": "DirectoryRecommendations.ReadWrite.All" + }, + { + "description": "Allows the app to read your organization's threat submissions and threat submission policies on behalf of the signed-in user.", + "displayName": "Read all threat submissions", + "id": "7083913a-4966-44b6-9886-c5822a5fd910", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization's threat submissions and threat submission policies on your behalf.", + "userConsentDisplayName": "Read all threat submissions", + "value": "ThreatSubmission.Read.All" + }, + { + "description": "Allows the app to read learning content in the organization's directory, on behalf of the signed-in user.", + "displayName": "Read learning content", + "id": "ea4c1fd9-6a9f-4432-8e5d-86e06cc0da77", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read learning content in the organization's directory, on your behalf.", + "userConsentDisplayName": "Read learning content", + "value": "LearningContent.Read.All" + }, + { + "description": "Allows the app to read data for the learning provider in the organization's directory, on behalf of the signed-in user.", + "displayName": "Read learning provider", + "id": "dd8ce36f-9245-45ea-a99e-8ac398c22861", + "Origin": "Delegated", + "userConsentDescription": "Allows\u00a0the\u00a0app\u00a0to\u00a0read\u00a0data\u00a0for\u00a0the learning\u00a0provider\u00a0in\u00a0the organization's\u00a0directory, on your behalf.", + "userConsentDisplayName": "Read learning provider", + "value": "LearningProvider.Read" + }, + { + "description": "Allows the app to create, update, list, read and delete all workflows, tasks and related lifecycle workflows resources on behalf of the signed-in user.", + "displayName": "Read and write all lifecycle workflows resources", + "id": "84b9d731-7db8-4454-8c90-fd9e95350179", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to create, update, list, read and delete all workflows, tasks and related lifecycle workflows resources on your behalf.", + "userConsentDisplayName": "Read and write all lifecycle workflows resources", + "value": "LifecycleWorkflows.ReadWrite.All" + }, + { + "description": "Allows an app to read all bookmarks that the signed-in user can access.", + "displayName": "Read all bookmarks that the user can access", + "id": "98b17b35-f3b1-4849-a85f-9f13733002f0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all bookmarks you can access.", + "userConsentDisplayName": "Read all bookmarks that you have access to", + "value": "Bookmark.Read.All" + }, + { + "description": "Allows the application to read and change the tenant-level settings of SharePoint and OneDrive on behalf of the signed-in user.", + "displayName": "Read and change SharePoint and OneDrive tenant settings", + "id": "aa07f155-3612-49b8-a147-6c590df35536", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read and change the tenant-level settings of SharePoint and OneDrive on your behalf.", + "userConsentDisplayName": "Read and change SharePoint and OneDrive tenant settings", + "value": "SharePointTenantSettings.ReadWrite.All" + }, + { + "description": "Allows the app to read or write your organization's authentication event listeners on behalf of the signed-in user.", + "displayName": "Read and write your organization's authentication event listeners", + "id": "d11625a6-fe21-4fc6-8d3d-063eba5525ad", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read or write your organization's authentication event listeners on your behalf.", + "userConsentDisplayName": "Read and write your organization's authentication event listeners", + "value": "EventListener.ReadWrite.All" + }, + { + "description": "Allows the app to read and write the Teams app settings on behalf of the signed-in user.", + "displayName": "Read and write Teams app settings", + "id": "87c556f0-2bd9-4eed-bd74-5dd8af6eaf7e", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write the Teams app settings on your behalf.", + "userConsentDisplayName": "Read and write Teams app settings", + "value": "TeamworkAppSettings.ReadWrite.All" + }, + { + "description": "Allows the app to read all authentication context information in your organization on behalf of the signed-in user.", + "displayName": "Read all authentication context information", + "id": "57b030f1-8c35-469c-b0d9-e4a077debe70", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all authentication context information in your organization on your behalf.", + "userConsentDisplayName": "Read all authentication context information", + "value": "AuthenticationContext.Read.All" + }, + { + "description": "Allows the app to read and update all authentication context information in your organization on behalf of the signed-in user.", + "displayName": "Read and write all authentication context information", + "id": "ba6d575a-1344-4516-b777-1404f5593057", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and update all authentication context information in your organization on your behalf.", + "userConsentDisplayName": "Read and write all authentication context information", + "value": "AuthenticationContext.ReadWrite.All" + }, + { + "description": "Allows the app to read and update admin report settings, such as whether to display concealed information in reports, on behalf of the signed-in user.", + "displayName": "Read and write admin report settings", + "id": "b955410e-7715-4a88-a940-dfd551018df3", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and update admin report settings, such as whether to display concealed information in reports, on your behalf.", + "userConsentDisplayName": "Read and write admin report settings", + "value": "ReportSettings.ReadWrite.All" + }, + { + "description": "Allows the app to list and read all workflows, tasks and related lifecycle workflows resources on behalf of the signed-in user.", + "displayName": "Read all lifecycle workflows resources", + "id": "9bcb9916-765a-42af-bf77-02282e26b01a", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to list and read all workflows, tasks and related lifecycle workflows resources on your behalf.", + "userConsentDisplayName": "Read all lifecycle workflows resources", + "value": "LifecycleWorkflows.Read.All" + }, + { + "description": "Allows the application to list and query any shared user profile information associated with the current tenant on behalf of the signed-in user.\u00a0 It also permits the application to export external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant on behalf of the signed-in user.", + "displayName": "Read all shared cross-tenant user profiles and export their data", + "id": "759dcd16-3c90-463c-937e-abf89f991c18", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to list and query any shared user profile information associated with the current tenant on your behalf.\u00a0 It also permits the application to export external user data (e.g. customer content or system-generated logs), for any user associated with the current tenant on your behalf.", + "userConsentDisplayName": "Read any shared cross-tenant user profiles and export data", + "value": "CrossTenantUserProfileSharing.Read.All" + }, + { + "description": "Allows the application to read the tenant-level settings in SharePoint and OneDrive on behalf of the signed-in user.", + "displayName": "Read SharePoint and OneDrive tenant settings", + "id": "2ef70e10-5bfd-4ede-a5f6-67720500b258", + "Origin": "Delegated", + "userConsentDescription": "Allows the application to read the tenant-level settings in SharePoint and OneDrive on your behalf.", + "userConsentDisplayName": "Read SharePoint and OneDrive tenant settings", + "value": "SharePointTenantSettings.Read.All" + }, + { + "description": "Allows the app to read or write your organization's custom authentication extensions on behalf of the signed-in user.", + "displayName": "Read and write your organization's custom authentication extensions", + "id": "8dfcf82f-15d0-43b3-bc78-a958a13a5792", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read or write your organization's custom authentication extensions on your behalf.", + "userConsentDisplayName": "Read and write your organization's custom authentication extensions", + "value": "CustomAuthenticationExtension.ReadWrite.All" + }, + { + "description": "Allows an app to manage license assignments for users and groups, on behalf of the signed-in user.", + "displayName": "Manage all license assignments", + "id": "f55016cc-149c-447e-8f21-7cf3ec1d6350", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to manage all license assignments, on your behalf.", + "userConsentDisplayName": "Manage all license assignments", + "value": "LicenseAssignment.ReadWrite.All" + }, + { + "description": "Allows an app to read all acronyms that the signed-in user can access.", + "displayName": "Read all acronyms that the user can access", + "id": "9084c10f-a2d6-4713-8732-348def50fe02", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all acronyms you can access.", + "userConsentDisplayName": "Read all acronyms that you have access to", + "value": "Acronym.Read.All" + }, + { + "description": "Allows the app to read your organization's custom authentication extensions on behalf of the signed-in user.", + "displayName": "Read your oganization's custom authentication extensions", + "id": "b2052569-c98c-4f36-a5fb-43e5c111e6d0", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read your organization's custom authentication extensions on your behalf.", + "userConsentDisplayName": "Read your organization's custom authentication extensions", + "value": "CustomAuthenticationExtension.Read.All" + }, + { + "description": "Allows the app to read all transcripts of online meetings, on behalf of the signed-in user.", + "displayName": "Read all transcripts of online meetings. ", + "id": "30b87d18-ebb1-45db-97f8-82ccb1f0190c", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read all transcripts of online meetings, on your behalf.", + "userConsentDisplayName": "Read all transcripts of online meetings.", + "value": "OnlineMeetingTranscript.Read.All" + }, + { + "description": "Allows the app to read and write channel messages, on behalf of the signed-in user. This doesn't allow the app to edit the policyViolation of a channel message.", + "displayName": "Read and write user channel messages", + "id": "5922d31f-46c8-4404-9eaf-2117e390a8a4", + "Origin": "Delegated", + "userConsentDescription": "Allows the app to read and write channel messages, on your behalf. This doesn't allow the app to edit the policyViolation of a channel message.", + "userConsentDisplayName": "Read and write user channel messages", + "value": "ChannelMessage.ReadWrite" + }, + { + "description": "Read Threat and Vulnerability Management vulnerability information", + "displayName": "Allows the app to read any Threat and Vulnerability Management vulnerability information", + "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", + "Origin": "Application (WindowsDefenderATP)", + "userConsentDescription": "Allows the app to read any Threat and Vulnerability Management vulnerability information", + "userConsentDisplayName": "Allows the app to read any Threat and Vulnerability Management vulnerability information", + "value": "Vulnerability.Read.All" + }, + { + "description": "Allows the app to read Threat and Vulnerability Management vulnerability information on behalf of the signed-in user", + "displayName": "Read Threat and Vulnerability Management vulnerability information", + "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", + "Origin": "Delegated (WindowsDefenderATP)", + "userConsentDescription": "Allows the app to read Threat and Vulnerability Management vulnerability information on behalf of the signed-in user", + "userConsentDisplayName": "Read Threat and Vulnerability Management vulnerability information", + "value": "Vulnerability.Read" + }, + { + "description": "Allows the app to manage Exchange Online", + "displayName": "Manage Exchange online", + "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", + "Origin": "Delegated (Office 365 Exchange Online)", + "userConsentDescription": "Allows the app to read Threat and Vulnerability Management vulnerability information on behalf of the signed-in user", + "userConsentDisplayName": "Read Threat and Vulnerability Management vulnerability information", + "value": "Exchange.Manage" + }, + { + "description": "Allows the app to create, read, update and delete events in all calendars in the organization user has permissions to access. This includes delegate and shared calendars", + "displayName": "Read and write user and shared calendars", + "id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415", + "Origin": "Delegated (Office 365 Exchange Online)", + "userConsentDescription": "Allows the app to read, update, create and delete events in all calendars in your organization you have permissions to access. This includes delegate and shared calendars", + "userConsentDisplayName": "Read and write to your and shared calendars", + "value": "Calendars.ReadWrite.All" + }, + { + "description": "Allows the app to create, read, update, and delete user's mailbox settings. Does not include permission to send mail.", + "displayName": "Read and write user mailbox settings", + "id": "2e83d72d-8895-4b66-9eea-abb43449ab8b", + "Origin": "Delegated (Office 365 Exchange Online)", + "userConsentDescription": "Allows the app to read, update, create, and delete your mailbox settings.", + "userConsentDisplayName": "Read and write to your mailbox settings", + "value": "MailboxSettings.ReadWrite" + }, + { + "description": "Allows the app to have full control of all site collections on behalf of the signed-in user.", + "displayName": "Manage Sharepoint Online", + "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", + "Origin": "Delegated (Office 365 SharePoint Online)", + "userConsentDescription": "Have full control of all site collections", + "userConsentDisplayName": "Allows the app to have full control of all site collections on your behalf.", + "value": "AllSites.FullControl" + }, + { + "description": "Allows to read the LAPs passwords.", + "displayName": "Manage LAPs passwords", + "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", + "Origin": "Delegated", + "userConsentDescription": "Allows to read the LAPs passwords.", + "userConsentDisplayName": "Manage LAPs passwords", + "value": "DeviceLocalCredential.Read.All" + }, + { + "description": "Access Microsoft Teams and Skype for Business data as the signed in user", + "displayName": "Access Microsoft Teams and Skype for Business data based on the user's role membership", + "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", + "Origin": "Delegated (Skype and Teams Tenant Admin API)", + "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/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index 71b6a3fdcbbc..65854b0c5db1 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -1,193 +1,193 @@ -{ - "isFallbackPublicClient": true, - "signInAudience": "AzureADMultipleOrgs", - "displayName": "CIPP-SAM", - "web": { - "redirectUris": [ - "https://login.microsoftonline.com/common/oauth2/nativeclient", - "https://localhost", - "http://localhost", - "http://localhost:8400" - ] - }, - "requiredResourceAccess": [ - { - "resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85", - "resourceAccess": [ - { "id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f", "type": "Scope" } - ] - }, - { - "resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd", - "resourceAccess": [ - { "id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a", "type": "Scope" } - ] - }, - { - "resourceAppId": "00000003-0000-0000-c000-000000000000", - "resourceAccess": [ - { "id": "aa07f155-3612-49b8-a147-6c590df35536", "type": "Scope" }, - { "id": "73e75199-7c3e-41bb-9357-167164dbb415", "type": "Scope" }, - { "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", "type": "Scope" }, - { "id": "46ca0847-7e6b-426e-9775-ea810a948356", "type": "Scope" }, - { "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", "type": "Scope" }, - { "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", "type": "Scope" }, - { "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", "type": "Scope" }, - { "id": "572fea84-0151-49b2-9301-11cb16974376", "type": "Scope" }, - { "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", "type": "Scope" }, - { "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", "type": "Scope" }, - { "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", "type": "Scope" }, - { "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", "type": "Scope" }, - { "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", "type": "Scope" }, - { "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", "type": "Scope" }, - { "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", "type": "Scope" }, - { "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", "type": "Scope" }, - { "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", "type": "Scope" }, - { "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", "type": "Scope" }, - { "id": "89fe6a52-be36-487e-b7d8-d061c450a026", "type": "Scope" }, - { "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", "type": "Scope" }, - { "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", "type": "Scope" }, - { "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", "type": "Scope" }, - { "id": "0e263e50-5827-48a4-b97c-d940288653c7", "type": "Scope" }, - { "id": "e383f46e-2787-4529-855e-0e479a3ffac0", "type": "Scope" }, - { "id": "37f7f235-527c-4136-accd-4a02d197296e", "type": "Scope" }, - { "id": "14dad69e-099b-42c9-810b-d002981feec1", "type": "Scope" }, - { "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", "type": "Scope" }, - { "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", "type": "Scope" }, - { "id": "a84a9652-ffd3-496e-a991-22ba5529156a", "type": "Scope" }, - { "id": "1d89d70c-dcac-4248-b214-903c457af83a", "type": "Scope" }, - { "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", "type": "Scope" }, - { "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", "type": "Scope" }, - { "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", "type": "Scope" }, - { "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", "type": "Scope" }, - { "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", "type": "Scope" }, - { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" }, - { "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", "type": "Scope" }, - { "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", "type": "Scope" }, - { "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", "type": "Scope" }, - { "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", "type": "Scope" }, - { "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", "type": "Scope" }, - { "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", "type": "Scope" }, - { "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", "type": "Scope" }, - { "id": "101147cf-4178-4455-9d58-02b5c164e759", "type": "Scope" }, - { "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", "type": "Scope" }, - { "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", "type": "Scope" }, - { "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", "type": "Scope" }, - { "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", "type": "Scope" }, - { "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", "type": "Scope" }, - { "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", "type": "Scope" }, - { "id": "39d65650-9d3e-4223-80db-a335590d027e", "type": "Scope" }, - { "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", "type": "Scope" }, - { "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", "type": "Scope" }, - { "id": "4d135e65-66b8-41a8-9f8b-081452c91774", "type": "Scope" }, - { "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", "type": "Scope" }, - { "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", "type": "Scope" }, - { "id": "edb72de9-4252-4d03-a925-451deef99db7", "type": "Scope" }, - { "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", "type": "Scope" }, - { "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", "type": "Scope" }, - { "id": "edd3c878-b384-41fd-95ad-e7407dd775be", "type": "Scope" }, - { "id": "40b534c3-9552-4550-901b-23879c90bcf9", "type": "Scope" }, - { "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", "type": "Scope" }, - { "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", "type": "Scope" }, - { "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", "type": "Scope" }, - { "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", "type": "Scope" }, - { "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", "type": "Scope" }, - { "id": "b27add92-efb2-4f16-84f5-8108ba77985c", "type": "Scope" }, - { "id": "3404d2bf-2b13-457e-a330-c24615765193", "type": "Scope" }, - { "id": "b955410e-7715-4a88-a940-dfd551018df3", "type": "Scope" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, - { "id": "19b94e34-907c-4f43-bde9-38b1909ed408", "type": "Role" }, - { "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", "type": "Role" }, - { "id": "292d869f-3427-49a8-9dab-8c70152b74e9", "type": "Role" }, - { "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", "type": "Role" }, - { "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", "type": "Role" }, - { "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", "type": "Role" }, - { "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", "type": "Role" }, - { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, - { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, - { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, - { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, - { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, - { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, - { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, - { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, - { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, - { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, - { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, - { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, - { "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", "type": "Role" }, - { "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", "type": "Role" }, - { "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", "type": "Role" }, - { "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", "type": "Role" }, - { "id": "50483e42-d915-4231-9639-7fdb7fd190e5", "type": "Role" }, - { "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", "type": "Role" }, - { "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", "type": "Role" }, - { "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", "type": "Role" }, - { "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", "type": "Role" }, - { "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", "type": "Role" }, - { "id": "3b55498e-47ec-484f-8136-9013221c06a9", "type": "Role" }, - { "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", "type": "Role" }, - { "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", "type": "Role" }, - { "id": "29c18626-4985-4dcd-85c0-193eef327366", "type": "Role" }, - { "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", "type": "Role" }, - { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, - { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, - { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, - { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, - { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, - { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, - { "id": "75359482-378d-4052-8f01-80520e7db3cd", "type": "Role" }, - { "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", "type": "Role" }, - { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, - { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, - { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, - { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, - { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, - { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, - { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, - { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, - { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" }, - { "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", "type": "Scope" }, - { "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", "type": "Scope" }, - { "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" } - ] - }, - { - "resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92", - "resourceAccess": [ - { "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", "type": "Scope" }, - { "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", "type": "Role" } - ] - }, - { - "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, - { "id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415", "type": "Scope" }, - { "id": "2e83d72d-8895-4b66-9eea-abb43449ab8b", "type": "Scope" }, - { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" }, - { "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", "type": "Role" }, - { "id": "f9156939-25cd-4ba8-abfe-7fabcf003749", "type": "Role" } - ] - }, - { - "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", "type": "Scope" } - ] - }, - { - "resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239", - "resourceAccess": [ - { "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", "type": "Scope" } - ] - }, - { - "resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2", - "resourceAccess": [ - { "id": "594c1fb6-4f81-4475-ae41-0c394909246c", "type": "Scope" } - ] - } - ] -} +{ + "isFallbackPublicClient": true, + "signInAudience": "AzureADMultipleOrgs", + "displayName": "CIPP-SAM", + "web": { + "redirectUris": [ + "https://login.microsoftonline.com/common/oauth2/nativeclient", + "https://localhost", + "http://localhost", + "http://localhost:8400" + ] + }, + "requiredResourceAccess": [ + { + "resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85", + "resourceAccess": [ + { "id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f", "type": "Scope" } + ] + }, + { + "resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd", + "resourceAccess": [ + { "id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a", "type": "Scope" } + ] + }, + { + "resourceAppId": "00000003-0000-0000-c000-000000000000", + "resourceAccess": [ + { "id": "aa07f155-3612-49b8-a147-6c590df35536", "type": "Scope" }, + { "id": "73e75199-7c3e-41bb-9357-167164dbb415", "type": "Scope" }, + { "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", "type": "Scope" }, + { "id": "46ca0847-7e6b-426e-9775-ea810a948356", "type": "Scope" }, + { "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", "type": "Scope" }, + { "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", "type": "Scope" }, + { "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", "type": "Scope" }, + { "id": "572fea84-0151-49b2-9301-11cb16974376", "type": "Scope" }, + { "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", "type": "Scope" }, + { "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", "type": "Scope" }, + { "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", "type": "Scope" }, + { "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", "type": "Scope" }, + { "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", "type": "Scope" }, + { "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", "type": "Scope" }, + { "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", "type": "Scope" }, + { "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", "type": "Scope" }, + { "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", "type": "Scope" }, + { "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", "type": "Scope" }, + { "id": "89fe6a52-be36-487e-b7d8-d061c450a026", "type": "Scope" }, + { "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", "type": "Scope" }, + { "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", "type": "Scope" }, + { "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", "type": "Scope" }, + { "id": "0e263e50-5827-48a4-b97c-d940288653c7", "type": "Scope" }, + { "id": "e383f46e-2787-4529-855e-0e479a3ffac0", "type": "Scope" }, + { "id": "37f7f235-527c-4136-accd-4a02d197296e", "type": "Scope" }, + { "id": "14dad69e-099b-42c9-810b-d002981feec1", "type": "Scope" }, + { "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", "type": "Scope" }, + { "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", "type": "Scope" }, + { "id": "a84a9652-ffd3-496e-a991-22ba5529156a", "type": "Scope" }, + { "id": "1d89d70c-dcac-4248-b214-903c457af83a", "type": "Scope" }, + { "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", "type": "Scope" }, + { "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", "type": "Scope" }, + { "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", "type": "Scope" }, + { "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", "type": "Scope" }, + { "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", "type": "Scope" }, + { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" }, + { "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", "type": "Scope" }, + { "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", "type": "Scope" }, + { "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", "type": "Scope" }, + { "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", "type": "Scope" }, + { "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", "type": "Scope" }, + { "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", "type": "Scope" }, + { "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", "type": "Scope" }, + { "id": "101147cf-4178-4455-9d58-02b5c164e759", "type": "Scope" }, + { "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", "type": "Scope" }, + { "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", "type": "Scope" }, + { "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", "type": "Scope" }, + { "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", "type": "Scope" }, + { "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", "type": "Scope" }, + { "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", "type": "Scope" }, + { "id": "39d65650-9d3e-4223-80db-a335590d027e", "type": "Scope" }, + { "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", "type": "Scope" }, + { "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", "type": "Scope" }, + { "id": "4d135e65-66b8-41a8-9f8b-081452c91774", "type": "Scope" }, + { "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", "type": "Scope" }, + { "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", "type": "Scope" }, + { "id": "edb72de9-4252-4d03-a925-451deef99db7", "type": "Scope" }, + { "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", "type": "Scope" }, + { "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", "type": "Scope" }, + { "id": "edd3c878-b384-41fd-95ad-e7407dd775be", "type": "Scope" }, + { "id": "40b534c3-9552-4550-901b-23879c90bcf9", "type": "Scope" }, + { "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", "type": "Scope" }, + { "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", "type": "Scope" }, + { "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", "type": "Scope" }, + { "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", "type": "Scope" }, + { "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", "type": "Scope" }, + { "id": "b27add92-efb2-4f16-84f5-8108ba77985c", "type": "Scope" }, + { "id": "3404d2bf-2b13-457e-a330-c24615765193", "type": "Scope" }, + { "id": "b955410e-7715-4a88-a940-dfd551018df3", "type": "Scope" }, + { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, + { "id": "19b94e34-907c-4f43-bde9-38b1909ed408", "type": "Role" }, + { "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", "type": "Role" }, + { "id": "292d869f-3427-49a8-9dab-8c70152b74e9", "type": "Role" }, + { "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", "type": "Role" }, + { "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", "type": "Role" }, + { "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", "type": "Role" }, + { "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", "type": "Role" }, + { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, + { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, + { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, + { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, + { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, + { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, + { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, + { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, + { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, + { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, + { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, + { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, + { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, + { "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", "type": "Role" }, + { "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", "type": "Role" }, + { "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", "type": "Role" }, + { "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", "type": "Role" }, + { "id": "50483e42-d915-4231-9639-7fdb7fd190e5", "type": "Role" }, + { "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", "type": "Role" }, + { "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", "type": "Role" }, + { "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", "type": "Role" }, + { "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", "type": "Role" }, + { "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", "type": "Role" }, + { "id": "3b55498e-47ec-484f-8136-9013221c06a9", "type": "Role" }, + { "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", "type": "Role" }, + { "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", "type": "Role" }, + { "id": "29c18626-4985-4dcd-85c0-193eef327366", "type": "Role" }, + { "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", "type": "Role" }, + { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, + { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, + { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, + { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, + { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, + { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, + { "id": "75359482-378d-4052-8f01-80520e7db3cd", "type": "Role" }, + { "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", "type": "Role" }, + { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, + { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, + { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, + { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, + { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, + { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, + { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, + { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, + { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" }, + { "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", "type": "Scope" }, + { "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", "type": "Scope" }, + { "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" } + ] + }, + { + "resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92", + "resourceAccess": [ + { "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", "type": "Scope" }, + { "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", "type": "Role" } + ] + }, + { + "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", + "resourceAccess": [ + { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, + { "id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415", "type": "Scope" }, + { "id": "2e83d72d-8895-4b66-9eea-abb43449ab8b", "type": "Scope" }, + { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" }, + { "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", "type": "Role" }, + { "id": "f9156939-25cd-4ba8-abfe-7fabcf003749", "type": "Role" } + ] + }, + { + "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", + "resourceAccess": [ + { "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", "type": "Scope" } + ] + }, + { + "resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239", + "resourceAccess": [ + { "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", "type": "Scope" } + ] + }, + { + "resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2", + "resourceAccess": [ + { "id": "594c1fb6-4f81-4475-ae41-0c394909246c", "type": "Scope" } + ] + } + ] +} From 38b1e35e5d28702a52e0152d000028192bcf8e9f Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Sun, 4 May 2025 20:02:17 +0800 Subject: [PATCH 006/149] updated mailbox report api for frontend --- ...Invoke-ListSharedMailboxAccountEnabled.ps1 | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSharedMailboxAccountEnabled.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSharedMailboxAccountEnabled.ps1 index eaea73fa0129..3b51959fa9d1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSharedMailboxAccountEnabled.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSharedMailboxAccountEnabled.ps1 @@ -20,27 +20,29 @@ 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,onPremisesSyncEnabled' -tenantid $TenantFilter - $EnabledUsersWithSharedMailbox = foreach ($SharedMailbox in $SharedMailboxList) { + $AllUsersInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?$select=id,userPrincipalName,accountEnabled,displayName,givenName,surname,onPremisesSyncEnabled,assignedLicenses' -tenantid $TenantFilter + $SharedMailboxDetails = foreach ($SharedMailbox in $SharedMailboxList) { # Match the User - $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 } }, ` - @{Name = 'displayName'; Expression = { $User.displayName } }, - @{Name = 'givenName'; Expression = { $User.givenName } }, - @{Name = 'surname'; Expression = { $User.surname } }, - @{Name = 'accountEnabled'; Expression = { $User.accountEnabled } }, - @{Name = 'id'; Expression = { $User.id } }, - @{Name = 'onPremisesSyncEnabled'; Expression = { $User.onPremisesSyncEnabled } } - + $User = $AllUsersInfo | Where-Object { $_.userPrincipalName -eq $SharedMailbox.userPrincipalName } | Select-Object -First 1 + + if ($User) { + # Return all shared mailboxes with license information + [PSCustomObject]@{ + UserPrincipalName = $User.userPrincipalName + displayName = $User.displayName + givenName = $User.givenName + surname = $User.surname + accountEnabled = $User.accountEnabled + assignedLicenses = $User.assignedLicenses + id = $User.id + onPremisesSyncEnabled = $User.onPremisesSyncEnabled + } } } } catch { - Write-LogMessage -API 'Tenant' -tenant $TenantFilter -message "Shared Mailbox Enabled Accounts on $($TenantFilter). Error: $($_.exception.message)" -sev 'Error' + Write-LogMessage -API 'Tenant' -tenant $TenantFilter -message "Shared Mailbox List on $($TenantFilter). Error: $($_.exception.message)" -sev 'Error' } - - $GraphRequest = $EnabledUsersWithSharedMailbox + $GraphRequest = $SharedMailboxDetails # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK From e12b48135ec6d12ef16106c2c439d6b5580b89b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 5 May 2025 23:50:12 +0200 Subject: [PATCH 007/149] fix: alert deduplication logData JSON conversion bug that caused identical logdata to trigger an alert --- .../CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1 index 787ccba38f5e..9408d9e5dca0 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1 @@ -1,22 +1,22 @@ function Write-AlertTrace { <# .FUNCTIONALITY - Internal function. Pleases most of write-alertmessage for alerting purposes + Internal function. Pleases most of Write-AlertTrace for alerting purposes #> Param( $cmdletName, $data, $tenantFilter - ) + ) $Table = Get-CIPPTable -tablename AlertLastRun $PartitionKey = (Get-Date -UFormat '%Y%m%d').ToString() #Get current row and compare the $logData object. If it's the same, don't write it. $Row = Get-CIPPAzDataTableEntity @table -Filter "RowKey eq '$($tenantFilter)-$($cmdletName)' and PartitionKey eq '$PartitionKey'" try { $RowData = $Row.LogData - $Compare = Compare-Object $RowData ($data | ConvertTo-Json -Compress -Depth 10 | Out-String) + $Compare = Compare-Object $RowData (ConvertTo-Json -InputObject $data -Compress -Depth 10 | Out-String) if ($Compare) { - $LogData = ConvertTo-Json $data -Compress -Depth 10 | Out-String + $LogData = ConvertTo-Json -InputObject $data -Compress -Depth 10 | Out-String $TableRow = @{ 'PartitionKey' = $PartitionKey 'RowKey' = "$($tenantFilter)-$($cmdletName)" @@ -27,7 +27,7 @@ function Write-AlertTrace { return $data } } catch { - $LogData = ConvertTo-Json $data -Compress -Depth 10 | Out-String + $LogData = ConvertTo-Json -InputObject $data -Compress -Depth 10 | Out-String $TableRow = @{ 'PartitionKey' = $PartitionKey 'RowKey' = "$($tenantFilter)-$($cmdletName)" @@ -38,4 +38,4 @@ function Write-AlertTrace { return $data } -} \ No newline at end of file +} From bdf181553601bdd53b5b16928416f830da5b5894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 5 May 2025 23:51:56 +0200 Subject: [PATCH 008/149] change encoding to LF --- Cache_SAMSetup/SAMManifest.json | 386 ++++++++++++++++---------------- 1 file changed, 193 insertions(+), 193 deletions(-) diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index 71b6a3fdcbbc..e8ca63984dbe 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -1,193 +1,193 @@ -{ - "isFallbackPublicClient": true, - "signInAudience": "AzureADMultipleOrgs", - "displayName": "CIPP-SAM", - "web": { - "redirectUris": [ - "https://login.microsoftonline.com/common/oauth2/nativeclient", - "https://localhost", - "http://localhost", - "http://localhost:8400" - ] - }, - "requiredResourceAccess": [ - { - "resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85", - "resourceAccess": [ - { "id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f", "type": "Scope" } - ] - }, - { - "resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd", - "resourceAccess": [ - { "id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a", "type": "Scope" } - ] - }, - { - "resourceAppId": "00000003-0000-0000-c000-000000000000", - "resourceAccess": [ - { "id": "aa07f155-3612-49b8-a147-6c590df35536", "type": "Scope" }, - { "id": "73e75199-7c3e-41bb-9357-167164dbb415", "type": "Scope" }, - { "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", "type": "Scope" }, - { "id": "46ca0847-7e6b-426e-9775-ea810a948356", "type": "Scope" }, - { "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", "type": "Scope" }, - { "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", "type": "Scope" }, - { "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", "type": "Scope" }, - { "id": "572fea84-0151-49b2-9301-11cb16974376", "type": "Scope" }, - { "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", "type": "Scope" }, - { "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", "type": "Scope" }, - { "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", "type": "Scope" }, - { "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", "type": "Scope" }, - { "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", "type": "Scope" }, - { "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", "type": "Scope" }, - { "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", "type": "Scope" }, - { "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", "type": "Scope" }, - { "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", "type": "Scope" }, - { "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", "type": "Scope" }, - { "id": "89fe6a52-be36-487e-b7d8-d061c450a026", "type": "Scope" }, - { "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", "type": "Scope" }, - { "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", "type": "Scope" }, - { "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", "type": "Scope" }, - { "id": "0e263e50-5827-48a4-b97c-d940288653c7", "type": "Scope" }, - { "id": "e383f46e-2787-4529-855e-0e479a3ffac0", "type": "Scope" }, - { "id": "37f7f235-527c-4136-accd-4a02d197296e", "type": "Scope" }, - { "id": "14dad69e-099b-42c9-810b-d002981feec1", "type": "Scope" }, - { "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", "type": "Scope" }, - { "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", "type": "Scope" }, - { "id": "a84a9652-ffd3-496e-a991-22ba5529156a", "type": "Scope" }, - { "id": "1d89d70c-dcac-4248-b214-903c457af83a", "type": "Scope" }, - { "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", "type": "Scope" }, - { "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", "type": "Scope" }, - { "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", "type": "Scope" }, - { "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", "type": "Scope" }, - { "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", "type": "Scope" }, - { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" }, - { "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", "type": "Scope" }, - { "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", "type": "Scope" }, - { "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", "type": "Scope" }, - { "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", "type": "Scope" }, - { "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", "type": "Scope" }, - { "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", "type": "Scope" }, - { "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", "type": "Scope" }, - { "id": "101147cf-4178-4455-9d58-02b5c164e759", "type": "Scope" }, - { "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", "type": "Scope" }, - { "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", "type": "Scope" }, - { "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", "type": "Scope" }, - { "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", "type": "Scope" }, - { "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", "type": "Scope" }, - { "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", "type": "Scope" }, - { "id": "39d65650-9d3e-4223-80db-a335590d027e", "type": "Scope" }, - { "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", "type": "Scope" }, - { "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", "type": "Scope" }, - { "id": "4d135e65-66b8-41a8-9f8b-081452c91774", "type": "Scope" }, - { "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", "type": "Scope" }, - { "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", "type": "Scope" }, - { "id": "edb72de9-4252-4d03-a925-451deef99db7", "type": "Scope" }, - { "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", "type": "Scope" }, - { "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", "type": "Scope" }, - { "id": "edd3c878-b384-41fd-95ad-e7407dd775be", "type": "Scope" }, - { "id": "40b534c3-9552-4550-901b-23879c90bcf9", "type": "Scope" }, - { "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", "type": "Scope" }, - { "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", "type": "Scope" }, - { "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", "type": "Scope" }, - { "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", "type": "Scope" }, - { "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", "type": "Scope" }, - { "id": "b27add92-efb2-4f16-84f5-8108ba77985c", "type": "Scope" }, - { "id": "3404d2bf-2b13-457e-a330-c24615765193", "type": "Scope" }, - { "id": "b955410e-7715-4a88-a940-dfd551018df3", "type": "Scope" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, - { "id": "19b94e34-907c-4f43-bde9-38b1909ed408", "type": "Role" }, - { "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", "type": "Role" }, - { "id": "292d869f-3427-49a8-9dab-8c70152b74e9", "type": "Role" }, - { "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", "type": "Role" }, - { "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", "type": "Role" }, - { "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", "type": "Role" }, - { "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", "type": "Role" }, - { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, - { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, - { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, - { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, - { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, - { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, - { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, - { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, - { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, - { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, - { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, - { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, - { "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", "type": "Role" }, - { "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", "type": "Role" }, - { "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", "type": "Role" }, - { "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", "type": "Role" }, - { "id": "50483e42-d915-4231-9639-7fdb7fd190e5", "type": "Role" }, - { "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", "type": "Role" }, - { "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", "type": "Role" }, - { "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", "type": "Role" }, - { "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", "type": "Role" }, - { "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", "type": "Role" }, - { "id": "3b55498e-47ec-484f-8136-9013221c06a9", "type": "Role" }, - { "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", "type": "Role" }, - { "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", "type": "Role" }, - { "id": "29c18626-4985-4dcd-85c0-193eef327366", "type": "Role" }, - { "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", "type": "Role" }, - { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, - { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, - { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, - { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, - { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, - { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, - { "id": "75359482-378d-4052-8f01-80520e7db3cd", "type": "Role" }, - { "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", "type": "Role" }, - { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, - { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, - { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, - { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, - { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, - { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, - { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, - { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, - { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" }, - { "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", "type": "Scope" }, - { "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", "type": "Scope" }, - { "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" } - ] - }, - { - "resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92", - "resourceAccess": [ - { "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", "type": "Scope" }, - { "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", "type": "Role" } - ] - }, - { - "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, - { "id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415", "type": "Scope" }, - { "id": "2e83d72d-8895-4b66-9eea-abb43449ab8b", "type": "Scope" }, - { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" }, - { "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", "type": "Role" }, - { "id": "f9156939-25cd-4ba8-abfe-7fabcf003749", "type": "Role" } - ] - }, - { - "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", "type": "Scope" } - ] - }, - { - "resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239", - "resourceAccess": [ - { "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", "type": "Scope" } - ] - }, - { - "resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2", - "resourceAccess": [ - { "id": "594c1fb6-4f81-4475-ae41-0c394909246c", "type": "Scope" } - ] - } - ] -} +{ + "isFallbackPublicClient": true, + "signInAudience": "AzureADMultipleOrgs", + "displayName": "CIPP-SAM", + "web": { + "redirectUris": [ + "https://login.microsoftonline.com/common/oauth2/nativeclient", + "https://localhost", + "http://localhost", + "http://localhost:8400" + ] + }, + "requiredResourceAccess": [ + { + "resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85", + "resourceAccess": [ + { "id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f", "type": "Scope" } + ] + }, + { + "resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd", + "resourceAccess": [ + { "id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a", "type": "Scope" } + ] + }, + { + "resourceAppId": "00000003-0000-0000-c000-000000000000", + "resourceAccess": [ + { "id": "aa07f155-3612-49b8-a147-6c590df35536", "type": "Scope" }, + { "id": "73e75199-7c3e-41bb-9357-167164dbb415", "type": "Scope" }, + { "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", "type": "Scope" }, + { "id": "46ca0847-7e6b-426e-9775-ea810a948356", "type": "Scope" }, + { "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", "type": "Scope" }, + { "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", "type": "Scope" }, + { "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", "type": "Scope" }, + { "id": "572fea84-0151-49b2-9301-11cb16974376", "type": "Scope" }, + { "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", "type": "Scope" }, + { "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", "type": "Scope" }, + { "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", "type": "Scope" }, + { "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", "type": "Scope" }, + { "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", "type": "Scope" }, + { "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", "type": "Scope" }, + { "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", "type": "Scope" }, + { "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", "type": "Scope" }, + { "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", "type": "Scope" }, + { "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", "type": "Scope" }, + { "id": "89fe6a52-be36-487e-b7d8-d061c450a026", "type": "Scope" }, + { "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", "type": "Scope" }, + { "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", "type": "Scope" }, + { "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", "type": "Scope" }, + { "id": "0e263e50-5827-48a4-b97c-d940288653c7", "type": "Scope" }, + { "id": "e383f46e-2787-4529-855e-0e479a3ffac0", "type": "Scope" }, + { "id": "37f7f235-527c-4136-accd-4a02d197296e", "type": "Scope" }, + { "id": "14dad69e-099b-42c9-810b-d002981feec1", "type": "Scope" }, + { "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", "type": "Scope" }, + { "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", "type": "Scope" }, + { "id": "a84a9652-ffd3-496e-a991-22ba5529156a", "type": "Scope" }, + { "id": "1d89d70c-dcac-4248-b214-903c457af83a", "type": "Scope" }, + { "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", "type": "Scope" }, + { "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", "type": "Scope" }, + { "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", "type": "Scope" }, + { "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", "type": "Scope" }, + { "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", "type": "Scope" }, + { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" }, + { "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", "type": "Scope" }, + { "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", "type": "Scope" }, + { "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", "type": "Scope" }, + { "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", "type": "Scope" }, + { "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", "type": "Scope" }, + { "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", "type": "Scope" }, + { "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", "type": "Scope" }, + { "id": "101147cf-4178-4455-9d58-02b5c164e759", "type": "Scope" }, + { "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", "type": "Scope" }, + { "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", "type": "Scope" }, + { "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", "type": "Scope" }, + { "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", "type": "Scope" }, + { "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", "type": "Scope" }, + { "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", "type": "Scope" }, + { "id": "39d65650-9d3e-4223-80db-a335590d027e", "type": "Scope" }, + { "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", "type": "Scope" }, + { "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", "type": "Scope" }, + { "id": "4d135e65-66b8-41a8-9f8b-081452c91774", "type": "Scope" }, + { "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", "type": "Scope" }, + { "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", "type": "Scope" }, + { "id": "edb72de9-4252-4d03-a925-451deef99db7", "type": "Scope" }, + { "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", "type": "Scope" }, + { "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", "type": "Scope" }, + { "id": "edd3c878-b384-41fd-95ad-e7407dd775be", "type": "Scope" }, + { "id": "40b534c3-9552-4550-901b-23879c90bcf9", "type": "Scope" }, + { "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", "type": "Scope" }, + { "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", "type": "Scope" }, + { "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", "type": "Scope" }, + { "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", "type": "Scope" }, + { "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", "type": "Scope" }, + { "id": "b27add92-efb2-4f16-84f5-8108ba77985c", "type": "Scope" }, + { "id": "3404d2bf-2b13-457e-a330-c24615765193", "type": "Scope" }, + { "id": "b955410e-7715-4a88-a940-dfd551018df3", "type": "Scope" }, + { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, + { "id": "19b94e34-907c-4f43-bde9-38b1909ed408", "type": "Role" }, + { "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", "type": "Role" }, + { "id": "292d869f-3427-49a8-9dab-8c70152b74e9", "type": "Role" }, + { "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", "type": "Role" }, + { "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", "type": "Role" }, + { "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", "type": "Role" }, + { "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", "type": "Role" }, + { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, + { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, + { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, + { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, + { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, + { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, + { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, + { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, + { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, + { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, + { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, + { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, + { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, + { "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", "type": "Role" }, + { "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", "type": "Role" }, + { "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", "type": "Role" }, + { "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", "type": "Role" }, + { "id": "50483e42-d915-4231-9639-7fdb7fd190e5", "type": "Role" }, + { "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", "type": "Role" }, + { "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", "type": "Role" }, + { "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", "type": "Role" }, + { "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", "type": "Role" }, + { "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", "type": "Role" }, + { "id": "3b55498e-47ec-484f-8136-9013221c06a9", "type": "Role" }, + { "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", "type": "Role" }, + { "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", "type": "Role" }, + { "id": "29c18626-4985-4dcd-85c0-193eef327366", "type": "Role" }, + { "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", "type": "Role" }, + { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, + { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, + { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, + { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, + { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, + { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, + { "id": "75359482-378d-4052-8f01-80520e7db3cd", "type": "Role" }, + { "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", "type": "Role" }, + { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, + { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, + { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, + { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, + { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, + { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, + { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, + { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, + { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" }, + { "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", "type": "Scope" }, + { "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", "type": "Scope" }, + { "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" } + ] + }, + { + "resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92", + "resourceAccess": [ + { "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", "type": "Scope" }, + { "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", "type": "Role" } + ] + }, + { + "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", + "resourceAccess": [ + { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, + { "id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415", "type": "Scope" }, + { "id": "2e83d72d-8895-4b66-9eea-abb43449ab8b", "type": "Scope" }, + { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" }, + { "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", "type": "Role" }, + { "id": "f9156939-25cd-4ba8-abfe-7fabcf003749", "type": "Role" } + ] + }, + { + "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", + "resourceAccess": [ + { "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", "type": "Scope" } + ] + }, + { + "resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239", + "resourceAccess": [ + { "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", "type": "Scope" } + ] + }, + { + "resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2", + "resourceAccess": [ + { "id": "594c1fb6-4f81-4475-ae41-0c394909246c", "type": "Scope" } + ] + } + ] +} From 63ea0e49350b9e6349ddecbb26142a6e2b35c92c Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Tue, 6 May 2025 10:39:25 +0800 Subject: [PATCH 009/149] handles individual and multiple values correctly --- .../Spamfilter/Invoke-AddTenantAllowBlockList.ps1 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddTenantAllowBlockList.ps1 index d43b14b56a9a..e04e28394375 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddTenantAllowBlockList.ps1 @@ -17,13 +17,19 @@ Function Invoke-AddTenantAllowBlockList { $BlockListObject = $Request.Body if ($Request.Body.tenantId -eq 'AllTenants') { $Tenants = (Get-Tenants).defaultDomainName } else { $Tenants = @($Request.body.tenantId) } $Results = [System.Collections.Generic.List[string]]::new() + $Entries = @() + if ($BlockListObject.entries -is [array]) { + $Entries = $BlockListObject.entries + } else { + $Entries = @($BlockListObject.entries -split "[,;]" | Where-Object { $_ -ne "" } | ForEach-Object { $_.Trim() }) + } foreach ($Tenant in $Tenants) { try { $ExoRequest = @{ tenantid = $Tenant cmdlet = 'New-TenantAllowBlockListItems' cmdParams = @{ - Entries = [string[]]$BlockListObject.entries + Entries = $Entries ListType = [string]$BlockListObject.listType Notes = [string]$BlockListObject.notes $BlockListObject.listMethod = [bool]$true @@ -32,6 +38,8 @@ Function Invoke-AddTenantAllowBlockList { if ($BlockListObject.NoExpiration -eq $true) { $ExoRequest.cmdParams.NoExpiration = $true + } elseif ($BlockListObject.RemoveAfter -eq $true) { + $ExoRequest.cmdParams.RemoveAfter = 45 } New-ExoRequest @ExoRequest From 11d7a1651cd5f4db8b47ced972ee21508950c834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= <31723128+kris6673@users.noreply.github.com> Date: Wed, 7 May 2025 12:47:51 +0200 Subject: [PATCH 010/149] Update SAMManifest.json --- Cache_SAMSetup/SAMManifest.json | 1 - 1 file changed, 1 deletion(-) diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index 793afe75de86..65854b0c5db1 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -12,7 +12,6 @@ }, "requiredResourceAccess": [ { - "resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85", "resourceAccess": [ { "id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f", "type": "Scope" } From effedec77d7b5400b11f781d8a5fce0fbd82c2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 7 May 2025 19:45:09 +0200 Subject: [PATCH 011/149] Refactor password assignment logic in Invoke-ExecJITAdmin function for clarity --- .../Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 index 7180fda9dc90..3e008bc1b898 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 @@ -121,11 +121,8 @@ function Invoke-ExecJITAdmin { $PasswordExpiration = $TapRequest.LifetimeInMinutes $PasswordLink = New-PwPushLink -Payload $TempPass - if ($PasswordLink) { - $Password = $PasswordLink - } else { - $Password = $TempPass - } + $Password = $PasswordLink ? $PasswordLink : $TempPass + $Results.Add("Temporary Access Pass: $Password") $Results.Add("This TAP is usable starting at $($TapRequest.startDateTime) UTC for the next $PasswordExpiration minutes") } catch { From bd6aa3e2d7cf448ee67e97c8ce2f6b93a7ac8346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 7 May 2025 19:46:19 +0200 Subject: [PATCH 012/149] Refactor New-CIPPTAP to return object thats better to copy in the frontend, while adding properties to make API module ease of use better --- Modules/CIPPCore/Public/New-CIPPTAP.ps1 | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Modules/CIPPCore/Public/New-CIPPTAP.ps1 b/Modules/CIPPCore/Public/New-CIPPTAP.ps1 index 3f500f41a30d..9e87986718bc 100644 --- a/Modules/CIPPCore/Public/New-CIPPTAP.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPTAP.ps1 @@ -10,19 +10,20 @@ function New-CIPPTAP { try { $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/authentication/temporaryAccessPassMethods" -tenantid $TenantFilter -type POST -body '{}' -verbose Write-LogMessage -headers $Headers -API $APIName -message "Created Temporary Access Password (TAP) for $userid" -Sev 'Info' -tenant $TenantFilter - $Results = [System.Collections.Generic.List[string]]::new() - $Results.Add("The TAP for this user is $($GraphRequest.temporaryAccessPass) - This TAP is usable for the next $($GraphRequest.LifetimeInMinutes) minutes") - $Results.Add("$($GraphRequest.temporaryAccessPass)") - return $Results + return @{ + resultText = "The TAP for this user is $($GraphRequest.temporaryAccessPass) - This TAP is usable for the next $($GraphRequest.LifetimeInMinutes) minutes" + copyField = $GraphRequest.temporaryAccessPass + temporaryAccessPass = $GraphRequest.temporaryAccessPass + lifetimeInMinutes = $GraphRequest.LifetimeInMinutes + startDateTime = $GraphRequest.startDateTime + state = 'success' + } } catch { $ErrorMessage = Get-CippException -Exception $_ $Result = "Failed to create Temporary Access Password (TAP) for $($userid): $($ErrorMessage.NormalizedError)" Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - throw @{ Results = $Result } - - + throw $Result } - } From 765f70a0ef3f346e43b9e921db905756478aa295 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 8 May 2025 10:00:06 +0200 Subject: [PATCH 013/149] chore: SetOoO consistent variables --- .../Administration/Invoke-ExecSetOoO.ps1 | 30 +++++++++---------- .../CIPPCore/Public/Set-CIPPOutOfoffice.ps1 | 4 +-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetOoO.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetOoO.ps1 index 952506bdc815..c3c814a7712c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetOoO.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetOoO.ps1 @@ -11,33 +11,33 @@ Function Invoke-ExecSetOoO { param($Request, $TriggerMetadata) try { $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Username = $request.body.userId - $Tenantfilter = $request.body.tenantfilter - if ($Request.body.input) { - $InternalMessage = $Request.body.input - $ExternalMessage = $Request.body.input + Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $Username = $Request.Body.userId + $TenantFilter = $Request.Body.tenantFilter + if ($Request.Body.input) { + $InternalMessage = $Request.Body.input + $ExternalMessage = $Request.Body.input } else { - $InternalMessage = $Request.body.InternalMessage - $ExternalMessage = $Request.body.ExternalMessage + $InternalMessage = $Request.Body.InternalMessage + $ExternalMessage = $Request.Body.ExternalMessage } #if starttime and endtime are a number, they are unix timestamps and need to be converted to datetime, otherwise just use them. - $StartTime = if ($Request.body.StartTime -match '^\d+$') { [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.body.StartTime).DateTime } else { $Request.body.StartTime } - $EndTime = if ($Request.body.EndTime -match '^\d+$') { [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.body.EndTime).DateTime } else { $Request.body.EndTime } + $StartTime = if ($Request.Body.StartTime -match '^\d+$') { [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.Body.StartTime).DateTime } else { $Request.Body.StartTime } + $EndTime = if ($Request.Body.EndTime -match '^\d+$') { [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.Body.EndTime).DateTime } else { $Request.Body.EndTime } $Results = try { if ($Request.Body.AutoReplyState.value -ne 'Scheduled') { - Set-CIPPOutOfOffice -userid $Username -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -State $Request.Body.AutoReplyState.value + Set-CIPPOutOfOffice -userid $Username -tenantFilter $TenantFilter -APIName $APIName -Headers $Request.Headers -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -State $Request.Body.AutoReplyState.value } else { - Set-CIPPOutOfOffice -userid $Username -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -StartTime $StartTime -EndTime $EndTime -State $Request.Body.AutoReplyState.value + Set-CIPPOutOfOffice -userid $Username -tenantFilter $TenantFilter -APIName $APIName -Headers $Request.Headers -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -StartTime $StartTime -EndTime $EndTime -State $Request.Body.AutoReplyState.value } } catch { - "Could not add out of office message for $($username). Error: $($_.Exception.Message)" + "Could not add out of office message for $($Username). Error: $($_.Exception.Message)" } - $body = [pscustomobject]@{'Results' = $($results) } + $Body = [PSCustomObject]@{'Results' = $($Results) } } catch { - $body = [pscustomobject]@{'Results' = "Could not set Out of Office user: $($_.Exception.message)" } + $Body = [PSCustomObject]@{'Results' = "Could not set Out of Office user: $($_.Exception.Message)" } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 b/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 index 7581fc0c2286..6ee8d1ea49b1 100644 --- a/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 @@ -21,8 +21,8 @@ function Set-CIPPOutOfOffice { } if ($State -ne 'Scheduled') { $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-MailboxAutoReplyConfiguration' -cmdParams @{Identity = $userid; AutoReplyState = $State; InternalMessage = $InternalMessage; ExternalMessage = $ExternalMessage } -Anchor $userid - Write-LogMessage -headers $Headers -API $APIName -message "Set Out-of-office for $($userid) to $state" -Sev 'Info' -tenant $TenantFilter - return "Set Out-of-office for $($userid) to $state." + Write-LogMessage -headers $Headers -API $APIName -message "Set Out-of-office for $($userid) to $State" -Sev 'Info' -tenant $TenantFilter + return "Set Out-of-office for $($userid) to $State." } else { $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-MailboxAutoReplyConfiguration' -cmdParams @{Identity = $userid; AutoReplyState = $State; InternalMessage = $InternalMessage; ExternalMessage = $ExternalMessage; StartTime = $StartTime; EndTime = $EndTime } -Anchor $userid Write-LogMessage -headers $Headers -API $APIName -message "Scheduled Out-of-office for $($userid) between $StartTime and $EndTime" -Sev 'Info' -tenant $TenantFilter From 9bb4001164bba257b58df804235852df09deab81 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 8 May 2025 10:06:52 +0200 Subject: [PATCH 014/149] fix: use correct Intune Template PolicyName --- .../Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 index 43117a472282..764d98142507 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 @@ -120,7 +120,7 @@ function Invoke-CIPPStandardIntuneTemplate { Set-CIPPIntunePolicy -TemplateType $TemplateFile.body.Type -Description $TemplateFile.description -DisplayName $TemplateFile.displayname -RawJSON $templateFile.rawJSON -AssignTo $TemplateFile.AssignTo -ExcludeGroup $TemplateFile.excludeGroup -tenantFilter $Tenant } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Intune Template $PolicyName, Error: $ErrorMessage" -sev 'Error' + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Intune Template $($TemplateFile.displayname), Error: $ErrorMessage" -sev 'Error' } } From ec3dfb1d8874096818edf6c8f7ebfb635f41f448 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 8 May 2025 15:03:08 +0200 Subject: [PATCH 015/149] feat: Anti-Phishing additional defaults * Enable user to protect by default * Enable include custom domains by default * Resolves https://discord.com/channels/905453405936447518/1199069319850639410/1370012245488046112 --- .../Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index deb7eddd23bc..616d70246e6b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -73,7 +73,7 @@ function Invoke-CIPPStandardAntiPhishPolicy { } $CurrentState = $ExistingPolicy | - Select-Object Name, Enabled, PhishThresholdLevel, EnableMailboxIntelligence, EnableMailboxIntelligenceProtection, EnableSpoofIntelligence, EnableFirstContactSafetyTips, EnableSimilarUsersSafetyTips, EnableSimilarDomainsSafetyTips, EnableUnusualCharactersSafetyTips, EnableUnauthenticatedSender, EnableViaTag, AuthenticationFailAction, SpoofQuarantineTag, MailboxIntelligenceProtectionAction, MailboxIntelligenceQuarantineTag, TargetedUserProtectionAction, TargetedUserQuarantineTag, TargetedDomainProtectionAction, TargetedDomainQuarantineTag, EnableOrganizationDomainsProtection + Select-Object Name, Enabled, PhishThresholdLevel, EnableMailboxIntelligence, EnableMailboxIntelligenceProtection, EnableSpoofIntelligence, EnableFirstContactSafetyTips, EnableSimilarUsersSafetyTips, EnableSimilarDomainsSafetyTips, EnableUnusualCharactersSafetyTips, EnableUnauthenticatedSender, EnableViaTag, AuthenticationFailAction, SpoofQuarantineTag, MailboxIntelligenceProtectionAction, MailboxIntelligenceQuarantineTag, TargetedUserProtectionAction, TargetedUserQuarantineTag, TargetedDomainProtectionAction, TargetedDomainQuarantineTag, EnableOrganizationDomainsProtection, EnableTargetedDomainsProtection, EnableTargetedUserProtection if ($MDOLicensed) { $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and @@ -96,6 +96,8 @@ function Invoke-CIPPStandardAntiPhishPolicy { ($CurrentState.TargetedUserQuarantineTag -eq $Settings.TargetedUserQuarantineTag) -and ($CurrentState.TargetedDomainProtectionAction -eq $Settings.TargetedDomainProtectionAction) -and ($CurrentState.TargetedDomainQuarantineTag -eq $Settings.TargetedDomainQuarantineTag) -and + ($CurrentState.EnableTargetedDomainsProtection -eq $true) -and + ($CurrentState.EnableTargetedUserProtection -eq $true) -and ($CurrentState.EnableOrganizationDomainsProtection -eq $true) } else { $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and @@ -144,6 +146,8 @@ function Invoke-CIPPStandardAntiPhishPolicy { TargetedUserQuarantineTag = $Settings.TargetedUserQuarantineTag TargetedDomainProtectionAction = $Settings.TargetedDomainProtectionAction TargetedDomainQuarantineTag = $Settings.TargetedDomainQuarantineTag + EnableTargetedDomainsProtection = $true + EnableTargetedUserProtection = $true EnableOrganizationDomainsProtection = $true } } else { @@ -218,8 +222,9 @@ function Invoke-CIPPStandardAntiPhishPolicy { } if ($Settings.report -eq $true) { - Set-CIPPStandardsCompareField -FieldName 'standards.AntiPhishPolicy' -FieldValue $StateIsCorrect -TenantFilter $tenant - Add-CIPPBPAField -FieldName 'AntiPhishPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + $FieldValue = $StateIsCorrect ? $true : $CurrentState + Set-CIPPStandardsCompareField -FieldName 'standards.AntiPhishPolicy' -FieldValue $FieldValue -TenantFilter $Tenant + Add-CIPPBPAField -FieldName 'AntiPhishPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant } } From 47220272e6ecf2ce0b1f1ce5095ab7d854868835 Mon Sep 17 00:00:00 2001 From: Luke Steward <87503131+sfaxluke@users.noreply.github.com> Date: Fri, 9 May 2025 14:07:34 +0100 Subject: [PATCH 016/149] Adjusted Microsoft URL's Adjusted URL's to match the new format for Exchange and Admin centre and aligned the Intune URL's to new endpoint --- .../Public/Hudu/Invoke-HuduExtensionSync.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 b/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 index 1ae846b59bc9..e62b9d856c84 100644 --- a/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 +++ b/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 @@ -122,12 +122,12 @@ function Invoke-HuduExtensionSync { $Links = @( @{ Title = 'M365 Admin Portal' - URL = 'https://admin.microsoft.com/Partner/BeginClientSession.aspx?CTID={0}&CSDEST=o365admincenter' -f $Tenant.customerId + URL = 'https://admin.cloud.microsoft/?delegatedOrg={0}' -f $Tenant.initialDomainName Icon = 'fas fa-cogs' } @{ Title = 'Exchange Admin Portal' - URL = 'https://admin.exchange.microsoft.com/?landingpage=homepage&form=mac_sidebar&delegatedOrg={0}' -f $Tenant.initialDomainName + URL = 'https://admin.cloud.microsoft/exchange/?delegatedOrg={0}' -f $Tenant.initialDomainName Icon = 'fas fa-mail-bulk' } @{ @@ -432,9 +432,9 @@ function Invoke-HuduExtensionSync { TotalItemSize = $TotalItemSize } - $userDevices = ($devices | Where-Object { $_.userPrincipalName -eq $user.userPrincipalName } | Select-Object @{N = 'Name'; E = { "$($_.deviceName) ($($_.operatingSystem))" } }).name -join '
' + $userDevices = ($devices | Where-Object { $_.userPrincipalName -eq $user.userPrincipalName } | Select-Object @{N = 'Name'; E = { "
$($_.deviceName) ($($_.operatingSystem))" } }).name -join '
' - $UserDevicesDetailsRaw = $devices | Where-Object { $_.userPrincipalName -eq $user.userPrincipalName } | Select-Object @{N = 'Name'; E = { "
$($_.deviceName)" } }, @{n = 'Owner'; e = { $_.managedDeviceOwnerType } }, ` + $UserDevicesDetailsRaw = $devices | Where-Object { $_.userPrincipalName -eq $user.userPrincipalName } | Select-Object @{N = 'Name'; E = { "$($_.deviceName)" } }, @{n = 'Owner'; e = { $_.managedDeviceOwnerType } }, ` @{n = 'Enrolled'; e = { $_.enrolledDateTime } }, ` @{n = 'Last Sync'; e = { $_.lastSyncDateTime } }, ` @{n = 'OS'; e = { $_.operatingSystem } }, ` @@ -443,7 +443,7 @@ function Invoke-HuduExtensionSync { @{n = 'Model'; e = { $_.model } }, ` @{n = 'Manufacturer'; e = { $_.manufacturer } }, deviceName, - @{n = 'url'; e = { "https://endpoint.microsoft.com/$($Tenant.defaultDomainName)/#blade/Microsoft_Intune_Devices/DeviceSettingsBlade/overview/mdmDeviceId/$($_.id)" } } + @{n = 'url'; e = { "https://intune.microsoft.com/$($Tenant.defaultDomainName)/#blade/Microsoft_Intune_Devices/DeviceSettingsBlade/overview/mdmDeviceId/$($_.id)" } } $aliases = (($user.proxyAddresses | Where-Object { $_ -cnotmatch 'SMTP' -and $_ -notmatch '.onmicrosoft.com' }) -replace 'SMTP:', ' ') -join ', ' @@ -781,7 +781,7 @@ function Invoke-HuduExtensionSync { } [System.Collections.Generic.List[PSCustomObject]]$DeviceLinksFormatted = @() - $DeviceLinksFormatted.add((Get-HuduLinkBlock -URL "https://endpoint.microsoft.com/$($Tenant.defaultDomainName)/#blade/Microsoft_Intune_Devices/DeviceSettingsBlade/overview/mdmDeviceId/$($Device.id)" -Icon 'fas fa-laptop' -Title 'Endpoint Manager')) + $DeviceLinksFormatted.add((Get-HuduLinkBlock -URL "https://intune.microsoft.com/$($Tenant.defaultDomainName)/#blade/Microsoft_Intune_Devices/DeviceSettingsBlade/overview/mdmDeviceId/$($Device.id)" -Icon 'fas fa-laptop' -Title 'Endpoint Manager')) if ($HuduDevice) { $DRMMCard = $HuduDevice.cards | Where-Object { $_.integrator_name -eq 'dattormm' } From d2ef2a288ffcf93c43b26300be0faa62b678143b Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Sun, 11 May 2025 07:38:28 +0800 Subject: [PATCH 017/149] fix ninja ms365 admin links --- .../Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 index fe45288c05e7..7d29a6b80503 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 @@ -1523,12 +1523,12 @@ function Invoke-NinjaOneTenantSync { $ManagementLinksData = @( @{ Name = 'M365 Admin Portal' - Link = "https://portal.office.com/Partner/BeginClientSession.aspx?CTID=$($customer.customerId)&CSDEST=o365admincenter" + Link = "https://admin.cloud.microsoft/?delegatedOrg=$($customer.defaultDomainName)" Icon = 'fas fa-cogs' }, @{ Name = 'Exchange Portal' - Link = "https://admin.exchange.microsoft.com/?landingpage=homepage&form=mac_sidebar&delegatedOrg=$($Customer.defaultDomainName)#" + Link = "https://admin.cloud.microsoft/exchange?delegatedOrg=$($Customer.defaultDomainName)" Icon = 'fas fa-mail-bulk' }, @{ @@ -1538,7 +1538,7 @@ function Invoke-NinjaOneTenantSync { }, @{ Name = 'Intune Portal' - Link = "https://endpoint.microsoft.com/$($customer.defaultDomainName)/" + Link = "https://intune.microsoft.com/$($customer.defaultDomainName)/" Icon = 'fas fa-laptop' }, @{ From f0c1c685890fca4d8c05e90822eca4097971dbbe Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 12 May 2025 10:06:40 -0400 Subject: [PATCH 018/149] Update SAMManifest.json --- Cache_SAMSetup/SAMManifest.json | 386 ++++++++++++++++---------------- 1 file changed, 193 insertions(+), 193 deletions(-) diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index 71b6a3fdcbbc..65854b0c5db1 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -1,193 +1,193 @@ -{ - "isFallbackPublicClient": true, - "signInAudience": "AzureADMultipleOrgs", - "displayName": "CIPP-SAM", - "web": { - "redirectUris": [ - "https://login.microsoftonline.com/common/oauth2/nativeclient", - "https://localhost", - "http://localhost", - "http://localhost:8400" - ] - }, - "requiredResourceAccess": [ - { - "resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85", - "resourceAccess": [ - { "id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f", "type": "Scope" } - ] - }, - { - "resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd", - "resourceAccess": [ - { "id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a", "type": "Scope" } - ] - }, - { - "resourceAppId": "00000003-0000-0000-c000-000000000000", - "resourceAccess": [ - { "id": "aa07f155-3612-49b8-a147-6c590df35536", "type": "Scope" }, - { "id": "73e75199-7c3e-41bb-9357-167164dbb415", "type": "Scope" }, - { "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", "type": "Scope" }, - { "id": "46ca0847-7e6b-426e-9775-ea810a948356", "type": "Scope" }, - { "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", "type": "Scope" }, - { "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", "type": "Scope" }, - { "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", "type": "Scope" }, - { "id": "572fea84-0151-49b2-9301-11cb16974376", "type": "Scope" }, - { "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", "type": "Scope" }, - { "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", "type": "Scope" }, - { "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", "type": "Scope" }, - { "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", "type": "Scope" }, - { "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", "type": "Scope" }, - { "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", "type": "Scope" }, - { "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", "type": "Scope" }, - { "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", "type": "Scope" }, - { "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", "type": "Scope" }, - { "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", "type": "Scope" }, - { "id": "89fe6a52-be36-487e-b7d8-d061c450a026", "type": "Scope" }, - { "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", "type": "Scope" }, - { "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", "type": "Scope" }, - { "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", "type": "Scope" }, - { "id": "0e263e50-5827-48a4-b97c-d940288653c7", "type": "Scope" }, - { "id": "e383f46e-2787-4529-855e-0e479a3ffac0", "type": "Scope" }, - { "id": "37f7f235-527c-4136-accd-4a02d197296e", "type": "Scope" }, - { "id": "14dad69e-099b-42c9-810b-d002981feec1", "type": "Scope" }, - { "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", "type": "Scope" }, - { "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", "type": "Scope" }, - { "id": "a84a9652-ffd3-496e-a991-22ba5529156a", "type": "Scope" }, - { "id": "1d89d70c-dcac-4248-b214-903c457af83a", "type": "Scope" }, - { "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", "type": "Scope" }, - { "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", "type": "Scope" }, - { "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", "type": "Scope" }, - { "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", "type": "Scope" }, - { "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", "type": "Scope" }, - { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" }, - { "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", "type": "Scope" }, - { "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", "type": "Scope" }, - { "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", "type": "Scope" }, - { "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", "type": "Scope" }, - { "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", "type": "Scope" }, - { "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", "type": "Scope" }, - { "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", "type": "Scope" }, - { "id": "101147cf-4178-4455-9d58-02b5c164e759", "type": "Scope" }, - { "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", "type": "Scope" }, - { "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", "type": "Scope" }, - { "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", "type": "Scope" }, - { "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", "type": "Scope" }, - { "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", "type": "Scope" }, - { "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", "type": "Scope" }, - { "id": "39d65650-9d3e-4223-80db-a335590d027e", "type": "Scope" }, - { "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", "type": "Scope" }, - { "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", "type": "Scope" }, - { "id": "4d135e65-66b8-41a8-9f8b-081452c91774", "type": "Scope" }, - { "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", "type": "Scope" }, - { "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", "type": "Scope" }, - { "id": "edb72de9-4252-4d03-a925-451deef99db7", "type": "Scope" }, - { "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", "type": "Scope" }, - { "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", "type": "Scope" }, - { "id": "edd3c878-b384-41fd-95ad-e7407dd775be", "type": "Scope" }, - { "id": "40b534c3-9552-4550-901b-23879c90bcf9", "type": "Scope" }, - { "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", "type": "Scope" }, - { "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", "type": "Scope" }, - { "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", "type": "Scope" }, - { "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", "type": "Scope" }, - { "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", "type": "Scope" }, - { "id": "b27add92-efb2-4f16-84f5-8108ba77985c", "type": "Scope" }, - { "id": "3404d2bf-2b13-457e-a330-c24615765193", "type": "Scope" }, - { "id": "b955410e-7715-4a88-a940-dfd551018df3", "type": "Scope" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, - { "id": "19b94e34-907c-4f43-bde9-38b1909ed408", "type": "Role" }, - { "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", "type": "Role" }, - { "id": "292d869f-3427-49a8-9dab-8c70152b74e9", "type": "Role" }, - { "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", "type": "Role" }, - { "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", "type": "Role" }, - { "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", "type": "Role" }, - { "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", "type": "Role" }, - { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, - { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, - { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, - { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, - { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, - { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, - { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, - { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, - { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, - { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, - { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, - { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, - { "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", "type": "Role" }, - { "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", "type": "Role" }, - { "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", "type": "Role" }, - { "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", "type": "Role" }, - { "id": "50483e42-d915-4231-9639-7fdb7fd190e5", "type": "Role" }, - { "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", "type": "Role" }, - { "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", "type": "Role" }, - { "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", "type": "Role" }, - { "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", "type": "Role" }, - { "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", "type": "Role" }, - { "id": "3b55498e-47ec-484f-8136-9013221c06a9", "type": "Role" }, - { "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", "type": "Role" }, - { "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", "type": "Role" }, - { "id": "29c18626-4985-4dcd-85c0-193eef327366", "type": "Role" }, - { "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", "type": "Role" }, - { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, - { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, - { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, - { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, - { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, - { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, - { "id": "75359482-378d-4052-8f01-80520e7db3cd", "type": "Role" }, - { "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", "type": "Role" }, - { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, - { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, - { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, - { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, - { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, - { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, - { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, - { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, - { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" }, - { "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", "type": "Scope" }, - { "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", "type": "Scope" }, - { "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" } - ] - }, - { - "resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92", - "resourceAccess": [ - { "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", "type": "Scope" }, - { "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", "type": "Role" } - ] - }, - { - "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, - { "id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415", "type": "Scope" }, - { "id": "2e83d72d-8895-4b66-9eea-abb43449ab8b", "type": "Scope" }, - { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" }, - { "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", "type": "Role" }, - { "id": "f9156939-25cd-4ba8-abfe-7fabcf003749", "type": "Role" } - ] - }, - { - "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", "type": "Scope" } - ] - }, - { - "resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239", - "resourceAccess": [ - { "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", "type": "Scope" } - ] - }, - { - "resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2", - "resourceAccess": [ - { "id": "594c1fb6-4f81-4475-ae41-0c394909246c", "type": "Scope" } - ] - } - ] -} +{ + "isFallbackPublicClient": true, + "signInAudience": "AzureADMultipleOrgs", + "displayName": "CIPP-SAM", + "web": { + "redirectUris": [ + "https://login.microsoftonline.com/common/oauth2/nativeclient", + "https://localhost", + "http://localhost", + "http://localhost:8400" + ] + }, + "requiredResourceAccess": [ + { + "resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85", + "resourceAccess": [ + { "id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f", "type": "Scope" } + ] + }, + { + "resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd", + "resourceAccess": [ + { "id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a", "type": "Scope" } + ] + }, + { + "resourceAppId": "00000003-0000-0000-c000-000000000000", + "resourceAccess": [ + { "id": "aa07f155-3612-49b8-a147-6c590df35536", "type": "Scope" }, + { "id": "73e75199-7c3e-41bb-9357-167164dbb415", "type": "Scope" }, + { "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", "type": "Scope" }, + { "id": "46ca0847-7e6b-426e-9775-ea810a948356", "type": "Scope" }, + { "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", "type": "Scope" }, + { "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", "type": "Scope" }, + { "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", "type": "Scope" }, + { "id": "572fea84-0151-49b2-9301-11cb16974376", "type": "Scope" }, + { "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", "type": "Scope" }, + { "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", "type": "Scope" }, + { "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", "type": "Scope" }, + { "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", "type": "Scope" }, + { "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", "type": "Scope" }, + { "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", "type": "Scope" }, + { "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", "type": "Scope" }, + { "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", "type": "Scope" }, + { "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", "type": "Scope" }, + { "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", "type": "Scope" }, + { "id": "89fe6a52-be36-487e-b7d8-d061c450a026", "type": "Scope" }, + { "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", "type": "Scope" }, + { "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", "type": "Scope" }, + { "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", "type": "Scope" }, + { "id": "0e263e50-5827-48a4-b97c-d940288653c7", "type": "Scope" }, + { "id": "e383f46e-2787-4529-855e-0e479a3ffac0", "type": "Scope" }, + { "id": "37f7f235-527c-4136-accd-4a02d197296e", "type": "Scope" }, + { "id": "14dad69e-099b-42c9-810b-d002981feec1", "type": "Scope" }, + { "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", "type": "Scope" }, + { "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", "type": "Scope" }, + { "id": "a84a9652-ffd3-496e-a991-22ba5529156a", "type": "Scope" }, + { "id": "1d89d70c-dcac-4248-b214-903c457af83a", "type": "Scope" }, + { "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", "type": "Scope" }, + { "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", "type": "Scope" }, + { "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", "type": "Scope" }, + { "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", "type": "Scope" }, + { "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", "type": "Scope" }, + { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" }, + { "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", "type": "Scope" }, + { "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", "type": "Scope" }, + { "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", "type": "Scope" }, + { "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", "type": "Scope" }, + { "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", "type": "Scope" }, + { "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", "type": "Scope" }, + { "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", "type": "Scope" }, + { "id": "101147cf-4178-4455-9d58-02b5c164e759", "type": "Scope" }, + { "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", "type": "Scope" }, + { "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", "type": "Scope" }, + { "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", "type": "Scope" }, + { "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", "type": "Scope" }, + { "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", "type": "Scope" }, + { "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", "type": "Scope" }, + { "id": "39d65650-9d3e-4223-80db-a335590d027e", "type": "Scope" }, + { "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", "type": "Scope" }, + { "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", "type": "Scope" }, + { "id": "4d135e65-66b8-41a8-9f8b-081452c91774", "type": "Scope" }, + { "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", "type": "Scope" }, + { "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", "type": "Scope" }, + { "id": "edb72de9-4252-4d03-a925-451deef99db7", "type": "Scope" }, + { "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", "type": "Scope" }, + { "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", "type": "Scope" }, + { "id": "edd3c878-b384-41fd-95ad-e7407dd775be", "type": "Scope" }, + { "id": "40b534c3-9552-4550-901b-23879c90bcf9", "type": "Scope" }, + { "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", "type": "Scope" }, + { "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", "type": "Scope" }, + { "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", "type": "Scope" }, + { "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", "type": "Scope" }, + { "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", "type": "Scope" }, + { "id": "b27add92-efb2-4f16-84f5-8108ba77985c", "type": "Scope" }, + { "id": "3404d2bf-2b13-457e-a330-c24615765193", "type": "Scope" }, + { "id": "b955410e-7715-4a88-a940-dfd551018df3", "type": "Scope" }, + { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, + { "id": "19b94e34-907c-4f43-bde9-38b1909ed408", "type": "Role" }, + { "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", "type": "Role" }, + { "id": "292d869f-3427-49a8-9dab-8c70152b74e9", "type": "Role" }, + { "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", "type": "Role" }, + { "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", "type": "Role" }, + { "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", "type": "Role" }, + { "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", "type": "Role" }, + { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, + { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, + { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, + { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, + { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, + { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, + { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, + { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, + { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, + { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, + { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, + { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, + { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, + { "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", "type": "Role" }, + { "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", "type": "Role" }, + { "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", "type": "Role" }, + { "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", "type": "Role" }, + { "id": "50483e42-d915-4231-9639-7fdb7fd190e5", "type": "Role" }, + { "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", "type": "Role" }, + { "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", "type": "Role" }, + { "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", "type": "Role" }, + { "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", "type": "Role" }, + { "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", "type": "Role" }, + { "id": "3b55498e-47ec-484f-8136-9013221c06a9", "type": "Role" }, + { "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", "type": "Role" }, + { "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", "type": "Role" }, + { "id": "29c18626-4985-4dcd-85c0-193eef327366", "type": "Role" }, + { "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", "type": "Role" }, + { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, + { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, + { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, + { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, + { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, + { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, + { "id": "75359482-378d-4052-8f01-80520e7db3cd", "type": "Role" }, + { "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", "type": "Role" }, + { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, + { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, + { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, + { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, + { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, + { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, + { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, + { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, + { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" }, + { "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", "type": "Scope" }, + { "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", "type": "Scope" }, + { "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" } + ] + }, + { + "resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92", + "resourceAccess": [ + { "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", "type": "Scope" }, + { "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", "type": "Role" } + ] + }, + { + "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", + "resourceAccess": [ + { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, + { "id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415", "type": "Scope" }, + { "id": "2e83d72d-8895-4b66-9eea-abb43449ab8b", "type": "Scope" }, + { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" }, + { "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", "type": "Role" }, + { "id": "f9156939-25cd-4ba8-abfe-7fabcf003749", "type": "Role" } + ] + }, + { + "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", + "resourceAccess": [ + { "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", "type": "Scope" } + ] + }, + { + "resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239", + "resourceAccess": [ + { "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", "type": "Scope" } + ] + }, + { + "resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2", + "resourceAccess": [ + { "id": "594c1fb6-4f81-4475-ae41-0c394909246c", "type": "Scope" } + ] + } + ] +} From f2449110987a9212147dfddc5710a22e248595ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 12 May 2025 20:56:39 +0200 Subject: [PATCH 019/149] fix: mailbox rules orchestrator cant start multiple times if the user refreshes before its done anymore --- .../Invoke-ListMailboxRules.ps1 | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxRules.ps1 index c92734c3b651..0c0b1c954322 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxRules.ps1 @@ -22,13 +22,24 @@ Function Invoke-ListMailboxRules { $Table.Filter = "Tenant eq '$TenantFilter'" } $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) + $PartitionKey = 'MailboxRules' + $QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey + $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -notmatch 'Completed' -and $_.Status -notmatch 'Failed' } $Metadata = @{} - if (!$Rows -or ($TenantFilter -eq 'AllTenants' -and ($Rows | Measure-Object).Count -eq 1)) { + # If a queue is running, we will not start a new one + if ($RunningQueue) { $Metadata = [PSCustomObject]@{ - QueueMessage = 'Loading data. Please check back in 1 minute' + QueueMessage = "Still loading data for $TenantFilter. Please check back in a few more minutes" + } + [PSCustomObject]@{ + Waiting = $true + } + } elseif ((!$Rows -and !$RunningQueue) -or ($TenantFilter -eq 'AllTenants' -and ($Rows | Measure-Object).Count -eq 1)) { + # If no rows are found and no queue is running, we will start a new one + $Metadata = [PSCustomObject]@{ + QueueMessage = "Loading data for $TenantFilter. Please check back in 1 minute" } - $GraphRequest = @() if ($TenantFilter -eq 'AllTenants') { $Tenants = Get-Tenants -IncludeErrors | Select-Object defaultDomainName @@ -37,7 +48,7 @@ Function Invoke-ListMailboxRules { $Tenants = @(@{ defaultDomainName = $TenantFilter }) $Type = $TenantFilter } - $Queue = New-CippQueueEntry -Name "Mailbox Rules ($Type)" -TotalTasks ($Tenants | Measure-Object).Count + $Queue = New-CippQueueEntry -Name "Mailbox Rules ($Type)" -Reference $QueueReference -TotalTasks ($Tenants | Measure-Object).Count $Batch = $Tenants | Select-Object defaultDomainName, @{Name = 'FunctionName'; Expression = { 'ListMailboxRulesQueue' } }, @{Name = 'QueueName'; Expression = { $_.defaultDomainName } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } } if (($Batch | Measure-Object).Count -gt 0) { $InputObject = [PSCustomObject]@{ @@ -53,6 +64,7 @@ Function Invoke-ListMailboxRules { } else { if ($TenantFilter -ne 'AllTenants') { $Rows = $Rows | Where-Object -Property Tenant -EQ $TenantFilter + $Rows = $Rows } $GraphRequest = $Rows | ForEach-Object { $NewObj = $_.Rules | ConvertFrom-Json -ErrorAction SilentlyContinue @@ -61,6 +73,8 @@ Function Invoke-ListMailboxRules { } } + # If no results are found, we will return an empty message to prevent null reference errors in the frontend + $GraphRequest = $GraphRequest ?? @() $Body = @{ Results = @($GraphRequest) Metadata = $Metadata From 34b3f769382f5fec6c970543f41f2947918b1453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 12 May 2025 20:56:48 +0200 Subject: [PATCH 020/149] forgive me for i have sinned --- .../Activity Triggers/Push-ListMailboxRulesQueue.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListMailboxRulesQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListMailboxRulesQueue.ps1 index c64592b7aab2..1c826fbfa0cb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListMailboxRulesQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListMailboxRulesQueue.ps1 @@ -26,7 +26,7 @@ function Push-ListMailboxRulesQueue { Rules = [string]($Rule | ConvertTo-Json) RowKey = [string](New-Guid).guid Tenant = [string]$domainName - PartitionKey = 'mailboxrules' + PartitionKey = 'MailboxRules' } } @@ -38,7 +38,7 @@ function Push-ListMailboxRulesQueue { Rules = [string]$Rules RowKey = [string]$domainName Tenant = [string]$domainName - PartitionKey = 'mailboxrules' + PartitionKey = 'MailboxRules' } } } catch { @@ -49,7 +49,7 @@ function Push-ListMailboxRulesQueue { Rules = [string]$Rules RowKey = [string]$domainName Tenant = [string]$domainName - PartitionKey = 'mailboxrules' + PartitionKey = 'MailboxRules' } } Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null From 8f8d65dcc671982b9987b9ab8ca9ac5ebcc20dd1 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 12 May 2025 23:47:57 +0200 Subject: [PATCH 021/149] audit log tenant searches improvements --- .../Webhooks/Push-AuditLogTenantDownload.ps1 | 2 +- .../Start-AuditLogSearchCreation.ps1 | 3 +- .../Functions/Expand-CIPPTenantGroups.ps1 | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 Modules/CIPPCore/Public/Functions/Expand-CIPPTenantGroups.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantDownload.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantDownload.ps1 index 51556092951f..88ae358c98a2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantDownload.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantDownload.ps1 @@ -51,7 +51,7 @@ function Push-AuditLogTenantDownload { $SearchEntity.CippStatus = 'Processing' Add-CIPPAzDataTableEntity @LogSearchesTable -Entity $SearchEntity -Force try { - Write-Information "Audit Log search: Processing search ID: $($Search.id) for tenant: $TenantFilter" + Write-Information "Audit Log search: Processing search ID: $($Search.id) for tenant: $TenantFilter" $Downloads = New-CIPPAuditLogSearchResultsCache -TenantFilter $TenantFilter -searchId $Search.id $SearchEntity.CippStatus = 'Downloaded' } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogSearchCreation.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogSearchCreation.ps1 index ed470848c331..a8fb469b7edb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogSearchCreation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogSearchCreation.ps1 @@ -17,8 +17,9 @@ function Start-AuditLogSearchCreation { Write-Information 'Audit Logs: Creating new searches' foreach ($Tenant in $TenantList) { + $TenantsList = Expand-CIPPTenantGroups -TenantFilter ($ConfigEntries.Tenants | ConvertFrom-Json) $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } - if ($Configuration) { + if ($Configuration -and $Tenant -in $TenantsList) { $ServiceFilters = $Configuration | Select-Object -Property type | Sort-Object -Property type -Unique | ForEach-Object { $_.type.split('.')[1] } try { $LogSearch = @{ diff --git a/Modules/CIPPCore/Public/Functions/Expand-CIPPTenantGroups.ps1 b/Modules/CIPPCore/Public/Functions/Expand-CIPPTenantGroups.ps1 new file mode 100644 index 000000000000..3f8405c0d619 --- /dev/null +++ b/Modules/CIPPCore/Public/Functions/Expand-CIPPTenantGroups.ps1 @@ -0,0 +1,35 @@ +function Expand-CIPPTenantGroups { + <# + .SYNOPSIS + Expands a list of groups to their members. + .DESCRIPTION + This function takes a a tenant filter object and expands it to include all members of the groups. + .EXAMPLE + + #> + [CmdletBinding(SupportsShouldProcess = $true)] + param ( + [Parameter(Mandatory = $true)] + $TenantFilter + ) + $TenantList = Get-Tenants -IncludeErrors + $ExpandedGroups = $TenantFilter | ForEach-Object { + $FilterValue = $_ + # Group lookup + if ($_.type -eq 'Group') { + $members = (Get-TenantGroups -GroupId $_.value).members + $TenantList | Where-Object -Property customerId -In $members.customerId | ForEach-Object { + $GroupMember = $_ + [PSCustomObject]@{ + value = $GroupMember.defaultDomainName + label = $GroupMember.displayName + addedFields = $GroupMember | Select-Object defaultDomainName, displayName, customerId + type = 'Tenant' + } + } + } else { + $FilterValue + } + } + return $ExpandedGroups | Sort-Object -Property value -Unique +} From df997af85d40285d25f45d60aaac407f15b5e6f2 Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Tue, 13 May 2025 12:06:02 +0800 Subject: [PATCH 022/149] Add ip type to returned block/allow listed items --- .../Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 index 13896c11c0d5..38950fcb4c00 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 @@ -16,7 +16,7 @@ Function Invoke-ListTenantAllowBlockList { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.tenantFilter - $ListTypes = 'Sender', 'Url', 'FileHash' + $ListTypes = 'Sender', 'Url', 'FileHash', 'IP' try { $Results = $ListTypes | ForEach-Object -Parallel { Import-Module CIPPCore From 316755d786001bba614aa44542dc55bde8dd6e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 13 May 2025 15:21:19 +0200 Subject: [PATCH 023/149] only compare to default policy Update standard comments --- .../Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 | 4 ++-- .../Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 | 2 +- .../Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 index dac20405a8f3..c616f54b9c6b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 @@ -14,12 +14,12 @@ function Invoke-CIPPStandardAutopilotProfile { Device Management Standards TAG DISABLEDFEATURES - {"report":true,"warn":true,"remediate":false} + {"report":false,"warn":false,"remediate":false} ADDEDCOMPONENT {"type":"textField","name":"standards.AutopilotProfile.DisplayName","label":"Profile Display Name"} {"type":"textField","name":"standards.AutopilotProfile.Description","label":"Profile Description"} {"type":"textField","name":"standards.AutopilotProfile.DeviceNameTemplate","label":"Unique Device Name Template"} - {"type":"autoComplete","multiple":false,"creatable":false,"name":"standards.AutopilotProfile.Languages","label":"Languages","api":{"url":"/languageList.json","labelField":"language","valueField":"tag"}} + {"type":"autoComplete","multiple":false,"creatable":false,"required":false,"name":"standards.AutopilotProfile.Languages","label":"Languages","api":{"url":"/languageList.json","labelField":"language","valueField":"tag"}} {"type":"switch","name":"standards.AutopilotProfile.CollectHash","label":"Convert all targeted devices to Autopilot","defaultValue":true} {"type":"switch","name":"standards.AutopilotProfile.AssignToAllDevices","label":"Assign to all devices","defaultValue":true} {"type":"switch","name":"standards.AutopilotProfile.SelfDeployingMode","label":"Enable Self-deploying Mode","defaultValue":true} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 index f592f409ee59..0a1b4241144c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 @@ -14,7 +14,7 @@ function Invoke-CIPPStandardAutopilotStatusPage { Device Management Standards TAG DISABLEDFEATURES - {"report":true,"warn":true,"remediate":false} + {"report":false,"warn":false,"remediate":false} ADDEDCOMPONENT {"type":"number","name":"standards.AutopilotStatusPage.TimeOutInMinutes","label":"Timeout in minutes","defaultValue":60} {"type":"textField","name":"standards.AutopilotStatusPage.ErrorMessage","label":"Custom Error Message","required":false} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 index ee8cbd3db58a..bfd0d7263cce 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 @@ -32,7 +32,7 @@ function Invoke-CIPPStandardOutBoundSpamAlert { param($Tenant, $Settings) - $CurrentInfo = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-HostedOutboundSpamFilterPolicy' -useSystemMailbox $true + $CurrentInfo = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-HostedOutboundSpamFilterPolicy' -cmdParams @{ Identity = 'Default' } -useSystemMailbox $true if ($Settings.remediate -eq $true) { From adf260d27c2edbbc4e04bb3d11aad3684960d2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 13 May 2025 16:54:36 +0200 Subject: [PATCH 024/149] feat: Add new Set Exchange Outbound Spam Limits standard --- ...voke-CIPPStandardEXOOutboundSpamLimits.ps1 | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXOOutboundSpamLimits.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXOOutboundSpamLimits.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXOOutboundSpamLimits.ps1 new file mode 100644 index 000000000000..81dd57b818ee --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXOOutboundSpamLimits.ps1 @@ -0,0 +1,112 @@ +function Invoke-CIPPStandardEXOOutboundSpamLimits { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) EXOOutboundSpamLimits + .SYNOPSIS + (Label) Set Exchange Outbound Spam Limits + .DESCRIPTION + (Helptext) Configures the outbound spam recipient limits (external per hour, internal per hour, per day) and the action to take when a limit is reached. The 'Set Outbound Spam Alert e-mail' standard is recommended to configure together with this one. + (DocsDescription) Configures the Exchange Online outbound spam recipient limits for external per hour, internal per hour, and per day, along with the action to take (e.g., BlockUser, Alert) when these limits are exceeded. This helps prevent abuse and manage email flow. Microsoft's recommendations can be found [here.](https://learn.microsoft.com/en-us/defender-office-365/recommended-settings-for-eop-and-office365#eop-outbound-spam-policy-settings) The 'Set Outbound Spam Alert e-mail' standard is recommended to configure together with this one. + .NOTES + CAT + Exchange Standards + TAG + "CIS" + ADDEDCOMPONENT + {"type":"number","name":"standards.EXOOutboundSpamLimits.RecipientLimitExternalPerHour","label":"External Recipient Limit Per Hour","defaultValue":400} + {"type":"number","name":"standards.EXOOutboundSpamLimits.RecipientLimitInternalPerHour","label":"Internal Recipient Limit Per Hour","defaultValue":800} + {"type":"number","name":"standards.EXOOutboundSpamLimits.RecipientLimitPerDay","label":"Daily Recipient Limit","defaultValue":800} + {"type":"autoComplete","multiple":false,"creatable":false,"name":"standards.EXOOutboundSpamLimits.ActionWhenThresholdReached","label":"Action When Threshold Reached","options":[{"label":"Alert","value":"Alert"},{"label":"Block User","value":"BlockUser"},{"label":"Block user from sending mail for the rest of the day","value":"BlockUserForToday"}]} + IMPACT + Low Impact + ADDEDDATE + 2025-05-13 + POWERSHELLEQUIVALENT + Set-HostedOutboundSpamFilterPolicy + RECOMMENDEDBY + "CIPP" + "CIS" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact + #> + + param($Tenant, $Settings) + + # Make sure it handles the frontend being both autocomplete and a text field + $ActionWhenThresholdReached = $Settings.ActionWhenThresholdReached.value ?? $Settings.ActionWhenThresholdReached + + # Input validation + if ([Int32]$Settings.RecipientLimitExternalPerHour -lt 0 -or [Int32]$Settings.RecipientLimitExternalPerHour -gt 10000) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'EXOOutboundSpamLimits: Invalid RecipientLimitExternalPerHour parameter set. Must be between 0 and 10000.' -sev Error + return + } + + if ([Int32]$Settings.RecipientLimitInternalPerHour -lt 0 -or [Int32]$Settings.RecipientLimitInternalPerHour -gt 10000) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'EXOOutboundSpamLimits: Invalid RecipientLimitInternalPerHour parameter set. Must be between 0 and 10000.' -sev Error + return + } + + if ([Int32]$Settings.RecipientLimitPerDay -lt 0 -or [Int32]$Settings.RecipientLimitPerDay -gt 10000) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'EXOOutboundSpamLimits: Invalid RecipientLimitPerDay parameter set. Must be between 0 and 10000.' -sev Error + return + } + + $ValidActions = @('Alert', 'BlockUser', 'BlockUserForToday') + if ($ActionWhenThresholdReached -notin $ValidActions) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'EXOOutboundSpamLimits: Invalid ActionWhenThresholdReached parameter set. Must be one of: Alert, BlockUser, BlockUserForToday.' -sev Error + return + } + + # Get current settings + $CurrentInfo = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-HostedOutboundSpamFilterPolicy' -cmdParams @{Identity = 'Default' } -Select 'RecipientLimitExternalPerHour, RecipientLimitInternalPerHour, RecipientLimitPerDay, ActionWhenThresholdReached' -useSystemMailbox $true | Select-Object -ExcludeProperty *data.type* + + # Check if settings are already correct + $StateIsCorrect = ($CurrentInfo.RecipientLimitExternalPerHour -eq $Settings.RecipientLimitExternalPerHour) -and + ($CurrentInfo.RecipientLimitInternalPerHour -eq $Settings.RecipientLimitInternalPerHour) -and + ($CurrentInfo.RecipientLimitPerDay -eq $Settings.RecipientLimitPerDay) -and + ($CurrentInfo.ActionWhenThresholdReached -eq $ActionWhenThresholdReached) + + # Remediation + If ($Settings.remediate -eq $true) { + Write-Host 'Time to remediate' + if ($StateIsCorrect -eq $false) { + try { + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-HostedOutboundSpamFilterPolicy' -cmdParams @{ + Identity = 'Default' + RecipientLimitExternalPerHour = $Settings.RecipientLimitExternalPerHour + RecipientLimitInternalPerHour = $Settings.RecipientLimitInternalPerHour + RecipientLimitPerDay = $Settings.RecipientLimitPerDay + ActionWhenThresholdReached = $ActionWhenThresholdReached + } -useSystemMailbox $true + + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set outbound spam limits: External=$($Settings.RecipientLimitExternalPerHour), Internal=$($Settings.RecipientLimitInternalPerHour), Daily=$($Settings.RecipientLimitPerDay), Action=$($ActionWhenThresholdReached)" -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not set outbound spam limits. $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + } + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Outbound spam limits are already set correctly' -sev Info + } + } + + # Alert + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Outbound spam limits are correctly configured: External=$($Settings.RecipientLimitExternalPerHour), Internal=$($Settings.RecipientLimitInternalPerHour), Daily=$($Settings.RecipientLimitPerDay), Action=$($ActionWhenThresholdReached)" -sev Info + } else { + Write-StandardsAlert -message 'Outbound spam limits are not configured correctly' -object $CurrentInfo -tenant $Tenant -standardName 'EXOOutboundSpamLimits' -standardId $Settings.standardId + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Outbound spam limits are not configured correctly' -sev Info + } + } + + # Report + if ($Settings.report -eq $true) { + $State = $StateIsCorrect ? $true : $CurrentInfo + Set-CIPPStandardsCompareField -FieldName 'standards.EXOOutboundSpamLimits' -FieldValue $State -TenantFilter $Tenant + Add-CIPPBPAField -FieldName 'OutboundSpamLimitsConfigured' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} From d5763a00014531c69cd6aa6c2b44138228bc44ba Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Tue, 13 May 2025 17:17:29 +0200 Subject: [PATCH 025/149] Fix alert no MFA admin alert --- Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 index e9f6021ca691..6e5a304ad013 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 @@ -18,7 +18,7 @@ function Get-CIPPAlertMFAAdmins { } } if (!$DuoActive) { - $users = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?`$top=999&filter=IsAdmin eq true and isMfaRegistered eq false and userType eq 'member'&`$select=userPrincipalName,lastUpdatedDateTime,isMfaRegistered,IsAdmin" -tenantid $($TenantFilter) -AsApp $true | Where-Object { $_.userDisplayName -ne 'On-Premises Directory Synchronization Service Account' } + $users = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?`$top=999&filter=IsAdmin eq true and isMfaRegistered eq false and userType eq 'member'&`$select=userDisplayName,userPrincipalName,lastUpdatedDateTime,isMfaRegistered,IsAdmin" -tenantid $($TenantFilter) -AsApp $true | Where-Object { $_.userDisplayName -ne 'On-Premises Directory Synchronization Service Account' } if ($users.UserPrincipalName) { $AlertData = "The following admins do not have MFA registered: $($users.UserPrincipalName -join ', ')" Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData From 0b38f078abe3fb4e6a3bd9410077e11c13d54b49 Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Tue, 13 May 2025 17:18:09 +0200 Subject: [PATCH 026/149] Fix alert no MFA user alert --- Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 index 89b0f1de3039..e56ce8fe2b04 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 @@ -12,7 +12,7 @@ function Get-CIPPAlertMFAAlertUsers { ) try { - $users = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?`$top=999&filter=IsAdmin eq false and isMfaRegistered eq false and userType eq 'member'&`$select=userPrincipalName,lastUpdatedDateTime,isMfaRegistered,IsAdmin" -tenantid $($TenantFilter) -AsApp $true | Where-Object { $_.userDisplayName -ne 'On-Premises Directory Synchronization Service Account' } + $users = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?`$top=999&filter=IsAdmin eq false and isMfaRegistered eq false and userType eq 'member'&`$select=userDisplayName,userPrincipalName,lastUpdatedDateTime,isMfaRegistered,IsAdmin" -tenantid $($TenantFilter) -AsApp $true | Where-Object { $_.userDisplayName -ne 'On-Premises Directory Synchronization Service Account' } if ($users.UserPrincipalName) { $AlertData = "The following $($users.Count) users do not have MFA registered: $($users.UserPrincipalName -join ', ')" Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData From 31fb2be60b5bb326cd993e1206194bb879e8ca80 Mon Sep 17 00:00:00 2001 From: Chris Brannon Date: Tue, 13 May 2025 11:47:10 -0400 Subject: [PATCH 027/149] Fix 90 Day Guest Filter --- .../Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 index f474b09d1ad5..5faf7964760c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 @@ -32,11 +32,12 @@ function Invoke-CIPPStandardDisableGuests { param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DisableGuests' - $Lookup = (Get-Date).AddDays(-90).ToUniversalTime().ToString('o') + $90Days = (Get-Date).AddDays(-90).ToUniversalTime() + $Lookup = $90Days.ToString('o') $AuditLookup = (Get-Date).AddDays(-7).ToUniversalTime().ToString('o') - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$filter=(signInActivity/lastSuccessfulSignInDateTime le $Lookup)&`$select=id,UserPrincipalName,signInActivity,mail,userType,accountEnabled" -scope 'https://graph.microsoft.com/.default' -tenantid $Tenant | - Where-Object { $_.userType -eq 'Guest' -and $_.AccountEnabled -eq $true } + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$filter=createdDateTime le $Lookup and userType eq 'Guest' and accountEnabled eq true &`$select=id,UserPrincipalName,signInActivity,mail,userType,accountEnabled,createdDateTime,externalUserState" -scope 'https://graph.microsoft.com/.default' -tenantid $Tenant | + Where-Object { $_.signInActivity.lastSuccessfulSignInDateTime -le $90Days } $RecentlyReactivatedUsers = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/directoryAudits?`$filter=activityDisplayName eq 'Enable account' and activityDateTime ge $AuditLookup" -scope 'https://graph.microsoft.com/.default' -tenantid $Tenant | ForEach-Object { $_.targetResources[0].id } | Select-Object -Unique) From 4f3fb33328c95084c7742a481ec822df56245965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 13 May 2025 18:04:48 +0200 Subject: [PATCH 028/149] fix: Remove 'Device' from types in Invoke-ListDeletedItems function --- .../Identity/Administration/Users/Invoke-ListDeletedItems.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListDeletedItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListDeletedItems.ps1 index b9dbdfb4da4f..3daf823de1a3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListDeletedItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListDeletedItems.ps1 @@ -16,7 +16,7 @@ Function Invoke-ListDeletedItems { Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $Types = 'Application', 'User', 'Device', 'Group' + $Types = 'Application', 'User', 'Group' $GraphRequest = foreach ($Type in $Types) { (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directory/deletedItems/microsoft.graph.$($Type)" -tenantid $TenantFilter) | Where-Object -Property '@odata.context' -NotLike '*graph.microsoft.com*' | From 360dadc2000afe176664842ff0643a586c593366 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 13 May 2025 15:32:04 -0400 Subject: [PATCH 029/149] increase concurrency --- host.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/host.json b/host.json index 4e9888399363..e10643770e53 100644 --- a/host.json +++ b/host.json @@ -10,8 +10,8 @@ "functionTimeout": "00:10:00", "extensions": { "durableTask": { - "maxConcurrentActivityFunctions": 1, - "maxConcurrentOrchestratorFunctions": 1 + "maxConcurrentActivityFunctions": 5, + "maxConcurrentOrchestratorFunctions": 2 } } -} +} \ No newline at end of file From 7b2d29218921566bb53ef2479d8b4d048c225c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 14 May 2025 16:56:14 +0200 Subject: [PATCH 030/149] Fix casing of tenantFilter in Invoke-ExecRestoreDeleted function and enhance logging messages for restored items --- .../Users/Invoke-ExecRestoreDeleted.ps1 | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 index b2c0ba22fb52..c4988f6ff856 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 @@ -15,18 +15,26 @@ Function Invoke-ExecRestoreDeleted { Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter ?? $Request.Body.TenantFilter + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter $RequestID = $Request.Query.ID ?? $Request.Body.ID + $UserPrincipalName = $Request.Body.userPrincipalName + $DisplayName = $Request.Body.displayName try { $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/directory/deletedItems/$($RequestID)/restore" -tenantid $TenantFilter -type POST -body '{}' -Verbose - $Result = "Successfully restored deleted item with ID: $($RequestID)" - Write-LogMessage -headers $Request.Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Info' + $Result = "Successfully restored deleted item with ID: '$($RequestID)'" + if ($UserPrincipalName) { $Result += " User Principal Name: '$($UserPrincipalName)'" } + if ($DisplayName) { $Result += " Display Name: '$($DisplayName)'" } + + Write-LogMessage -headers $Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Info' $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - $Result = "Failed to restore deleted item with ID: $($RequestID). Error: $($ErrorMessage.NormalizedError)" - Write-LogMessage -headers $Request.Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $Result = "Failed to restore deleted item with ID: '$($RequestID)'. Error: $($ErrorMessage.NormalizedError)" + if ($UserPrincipalName) { $Result += " User Principal Name: '$($UserPrincipalName)'" } + if ($DisplayName) { $Result += " Display Name: '$($DisplayName)'" } + + Write-LogMessage -headers $Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage $StatusCode = [HttpStatusCode]::InternalServerError } From 3b8bcc29398842d93bb28ffb5fb9b1833a1b3dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 14 May 2025 16:56:20 +0200 Subject: [PATCH 031/149] Add Invoke-RemoveDeletedObject function for permanently deleting directory items --- .../Users/Invoke-RemoveDeletedObject.ps1 | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveDeletedObject.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveDeletedObject.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveDeletedObject.ps1 new file mode 100644 index 000000000000..4dbf1cbe8849 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveDeletedObject.ps1 @@ -0,0 +1,48 @@ +using namespace System.Net + +Function Invoke-RemoveDeletedObject { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.Directory.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $RequestID = $Request.Query.ID ?? $Request.Body.ID + $UserPrincipalName = $Request.Body.userPrincipalName + $DisplayName = $Request.Body.displayName + + try { + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/directory/deletedItems/$($RequestID)" -tenantid $TenantFilter -type DELETE -body '{}' -Verbose + $Result = "Successfully permanently deleted item with ID: '$($RequestID)'" + if ($UserPrincipalName) { $Result += " User Principal Name: '$($UserPrincipalName)'" } + if ($DisplayName) { $Result += " Display Name: '$($DisplayName)'" } + + Write-LogMessage -headers $Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to permanently delete item with ID: $($RequestID). Error: $($ErrorMessage.NormalizedError)" + if ($UserPrincipalName) { $Result += " User Principal Name: '$($UserPrincipalName)'" } + if ($DisplayName) { $Result += " Display Name: '$($DisplayName)'" } + + Write-LogMessage -headers $Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + $Results = [pscustomobject]@{'Results' = $Result } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Results + }) + +} From 46124ab85ba76d967ba1070d18e3bf3fb32cd6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 14 May 2025 17:41:16 +0200 Subject: [PATCH 032/149] Change so the error is at the end --- .../Administration/Users/Invoke-ExecRestoreDeleted.ps1 | 3 ++- .../Administration/Users/Invoke-RemoveDeletedObject.ps1 | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 index c4988f6ff856..cf4300a8054d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 @@ -30,9 +30,10 @@ Function Invoke-ExecRestoreDeleted { $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - $Result = "Failed to restore deleted item with ID: '$($RequestID)'. Error: $($ErrorMessage.NormalizedError)" + $Result = "Failed to restore deleted item with ID: '$($RequestID)'" if ($UserPrincipalName) { $Result += " User Principal Name: '$($UserPrincipalName)'" } if ($DisplayName) { $Result += " Display Name: '$($DisplayName)'" } + $Result += " Error: $($ErrorMessage.NormalizedError)" Write-LogMessage -headers $Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage $StatusCode = [HttpStatusCode]::InternalServerError diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveDeletedObject.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveDeletedObject.ps1 index 4dbf1cbe8849..da4e516d6462 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveDeletedObject.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveDeletedObject.ps1 @@ -30,9 +30,10 @@ Function Invoke-RemoveDeletedObject { $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - $Result = "Failed to permanently delete item with ID: $($RequestID). Error: $($ErrorMessage.NormalizedError)" + $Result = "Failed to permanently delete item with ID: $($RequestID)" if ($UserPrincipalName) { $Result += " User Principal Name: '$($UserPrincipalName)'" } if ($DisplayName) { $Result += " Display Name: '$($DisplayName)'" } + $Result += " Error: $($ErrorMessage.NormalizedError)" Write-LogMessage -headers $Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage $StatusCode = [HttpStatusCode]::InternalServerError From ccd9c4f63bfa7bcf392a4d0f470dcb6a4d365a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 14 May 2025 17:49:11 +0200 Subject: [PATCH 033/149] Enhance user deletion logging in Invoke-RemoveUser function --- .../Identity/Administration/Users/Invoke-RemoveUser.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUser.ps1 index dc21f41c14ac..6b5db1ad6733 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUser.ps1 @@ -17,17 +17,20 @@ Function Invoke-RemoveUser { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter $UserID = $Request.Query.ID ?? $Request.Body.ID + $UserPrincipalName = $Request.Query.userPrincipalName ?? $Request.Body.userPrincipalName if (!$UserID) { exit } try { $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserID)" -type DELETE -tenant $TenantFilter - $Result = "Successfully deleted $UserID." + $Result = "Successfully deleted user with ID: '$UserID'" + if ($UserPrincipalName) { $Result += " and User Principal Name: '$UserPrincipalName'" } Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Info' -tenant $TenantFilter $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - $Result = "Could not delete user $($UserID). $($ErrorMessage.NormalizedError)" + $Result = "Failed to delete user $($UserID). $($ErrorMessage.NormalizedError)" + if ($UserPrincipalName) { $Result += " User Principal Name: '$($UserPrincipalName)'" } Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage $StatusCode = [HttpStatusCode]::InternalServerError } From 058d8ef2a3ca57e8ee52379b1e670ed37c4e9b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Thu, 15 May 2025 18:29:46 +0200 Subject: [PATCH 034/149] feat: Add Invoke-ExecSetMailboxEmailSize and Set-CippMaxEmailSize functions to set max send/receive size for mailboxes --- .../Invoke-ExecSetMailboxEmailSize.ps1 | 49 ++++++++++++++++ .../CIPPCore/Public/Set-CippMaxEmailSize.ps1 | 57 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxEmailSize.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CippMaxEmailSize.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxEmailSize.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxEmailSize.ps1 new file mode 100644 index 000000000000..ec36ffbea20d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxEmailSize.ps1 @@ -0,0 +1,49 @@ +using namespace System.Net + +Function Invoke-ExecSetMailboxEmailSize { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $User -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $Tenant = $Request.Body.tenantFilter + $UserPrincipalName = $Request.Body.UPN + $UserID = $Request.Body.id + $MaxSendSize = $Request.Body.maxSendSize + $MaxReceiveSize = $Request.Body.maxReceiveSize + + try { + $Params = @{ + TenantFilter = $Tenant + APIName = $APIName + Headers = $Headers + UserPrincipalName = $UserPrincipalName + UserID = $UserID + MaxSendSize = $MaxSendSize + MaxReceiveSize = $MaxReceiveSize + } + if ([string]::IsNullOrWhiteSpace($MaxSendSize)) { $Params.Remove('MaxSendSize') } + if ([string]::IsNullOrWhiteSpace($MaxReceiveSize)) { $Params.Remove('MaxReceiveSize') } + $Result = Set-CippMaxEmailSize @Params + $StatusCode = [HttpStatusCode]::OK + } catch { + $Result = "$($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{ Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Set-CippMaxEmailSize.ps1 b/Modules/CIPPCore/Public/Set-CippMaxEmailSize.ps1 new file mode 100644 index 000000000000..c7af1dec9790 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CippMaxEmailSize.ps1 @@ -0,0 +1,57 @@ +function Set-CippMaxEmailSize { + [CmdletBinding()] + param ( + $Headers, + $TenantFilter, + $APIName = 'Mailbox Max Send/Receive Size', + $UserPrincipalName, + $UserID, + [ValidateRange(1, 150)] + [Int32]$MaxSendSize, + [ValidateRange(1, 150)] + [Int32]$MaxReceiveSize + ) + + try { + # Id the ID is provided, use it. Otherwise, use the UPN + $Identity = $UserID ?? $UserPrincipalName + if ([string]::IsNullOrWhiteSpace($Identity)) { + $Result = 'No identity provided. Cannot set mailbox email max size.' + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev Error -tenant $TenantFilter + throw $Result + } + + if ($MaxSendSize -eq 0 -and $MaxReceiveSize -eq 0) { + $Result = 'No max send or receive size provided. Cannot set mailbox email max size.' + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev Error -tenant $TenantFilter + throw $Result + } + + $cmdletParams = @{ + Identity = $Identity + } + # Set the max send and receive size if they are provided. Convert to bytes + if ($MaxSendSize -gt 0) { $cmdletParams['MaxSendSize'] = $MaxSendSize * 1MB } + if ($MaxReceiveSize -gt 0) { $cmdletParams['MaxReceiveSize'] = $MaxReceiveSize * 1MB } + + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams $cmdletParams + + # Use UPN for logging if provided + $Identity = $UserPrincipalName ?? $UserID + $Result = "Set mailbox email max size for $($Identity) to " + if ($MaxSendSize -gt 0) { $Result += "Send: $($MaxSendSize)MB " } + if ($MaxReceiveSize -gt 0) { $Result += "Receive: $($MaxReceiveSize)MB" } + + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev Info -tenant $TenantFilter + return $Result + } catch { + $ErrorMessage = Get-CippException -Exception $_ + + # Use UPN for logging if provided + $Identity = $UserPrincipalName ?? $UserID + $Result = "Failed to set mailbox email max size for $($Identity). Error: $($ErrorMessage)" + + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev Error -tenant $TenantFilter -LogData $ErrorMessage + throw $Result + } +} From 7e5fe3c80750adbe00f34860e7c01a161fc247e3 Mon Sep 17 00:00:00 2001 From: lsmith090 <47199231+lsmith090@users.noreply.github.com> Date: Thu, 15 May 2025 13:00:24 -0400 Subject: [PATCH 035/149] fix logic for checking existing group membership --- .../Tenant/Administration/Tenant/Invoke-EditTenant.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 index e100c89b8e2d..f063373b48f0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-EditTenant { +function Invoke-EditTenant { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -46,9 +46,9 @@ Function Invoke-EditTenant { } # Update tenant groups - $CurrentMembers = Get-CIPPAzDataTableEntity @GroupMembersTable -Filter "customerId eq '$customerId'" + $CurrentGroupMemberships = Get-CIPPAzDataTableEntity @GroupMembersTable -Filter "customerId eq '$customerId'" foreach ($Group in $tenantGroups) { - $GroupEntity = $CurrentMembers | Where-Object { $_.GroupId -eq $Group.groupId } + $GroupEntity = $CurrentGroupMemberships | Where-Object { $_.GroupId -eq $Group.groupId } if (!$GroupEntity) { $GroupEntity = @{ PartitionKey = 'Member' @@ -61,8 +61,8 @@ Function Invoke-EditTenant { } # Remove any groups that are no longer selected - foreach ($Group in $CurrentMembers) { - if ($tenantGroups -notcontains $Group.GroupId) { + foreach ($Group in $CurrentGroupMemberships) { + if ($tenantGroups.GroupId -notcontains $Group.GroupId) { Remove-AzDataTableEntity @GroupMembersTable -Entity $Group } } From 4b033795f80cada016a07f2c7d8c5c8397c59d2a Mon Sep 17 00:00:00 2001 From: lsmith090 <47199231+lsmith090@users.noreply.github.com> Date: Thu, 15 May 2025 13:00:24 -0400 Subject: [PATCH 036/149] fix logic for checking existing group membership --- .../Administration/Tenant/Invoke-EditTenant.ps1 | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 index e100c89b8e2d..b0fa498d20ed 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-EditTenant { +function Invoke-EditTenant { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -11,8 +11,9 @@ Function Invoke-EditTenant { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' $customerId = $Request.Body.customerId $tenantAlias = $Request.Body.tenantAlias @@ -46,9 +47,9 @@ Function Invoke-EditTenant { } # Update tenant groups - $CurrentMembers = Get-CIPPAzDataTableEntity @GroupMembersTable -Filter "customerId eq '$customerId'" + $CurrentGroupMemberships = Get-CIPPAzDataTableEntity @GroupMembersTable -Filter "customerId eq '$customerId'" foreach ($Group in $tenantGroups) { - $GroupEntity = $CurrentMembers | Where-Object { $_.GroupId -eq $Group.groupId } + $GroupEntity = $CurrentGroupMemberships | Where-Object { $_.GroupId -eq $Group.groupId } if (!$GroupEntity) { $GroupEntity = @{ PartitionKey = 'Member' @@ -61,8 +62,8 @@ Function Invoke-EditTenant { } # Remove any groups that are no longer selected - foreach ($Group in $CurrentMembers) { - if ($tenantGroups -notcontains $Group.GroupId) { + foreach ($Group in $CurrentGroupMemberships) { + if ($tenantGroups.GroupId -notcontains $Group.GroupId) { Remove-AzDataTableEntity @GroupMembersTable -Entity $Group } } @@ -76,7 +77,7 @@ Function Invoke-EditTenant { Body = $response }) } catch { - Write-LogMessage -headers $Request.Headers -tenant $customerId -API $APINAME -message "Edit Tenant failed. The error is: $($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -headers $Headers -tenant $customerId -API $APINAME -message "Edit Tenant failed. The error is: $($_.Exception.Message)" -Sev 'Error' $response = @{ state = 'error' resultText = $_.Exception.Message From 0abaa44b421748c7b729d2b6a56eaa82e646ef5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Thu, 15 May 2025 19:13:26 +0200 Subject: [PATCH 037/149] Fix: enable graph part of standard again, now that it works via GDAP --- .../Invoke-CIPPStandardProfilePhotos.ps1 | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 index c7d6b3e55b8f..303dab289f99 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 @@ -42,25 +42,18 @@ function Invoke-CIPPStandardProfilePhotos { # true if wanted state is enabled, false if disabled $DesiredState = $StateValue -eq 'enabled' - <# - HACK This does not work, as the API endpoint is not available via GDAP it seems? It works in the Graph Explorer, but not here. - The error is: "Authorization failed because of missing requirement(s)." - I'm keeping the code here for now, so it's much easier to re-enable if Microsoft makes it possible someday. -Bobby - #> - # Get current Graph policy state - # $Uri = 'https://graph.microsoft.com/beta/admin/people/photoUpdateSettings' - # $CurrentGraphState = New-GraphGetRequest -uri $Uri -tenantid $Tenant - # $UsersCanChangePhotos = if (($CurrentGraphState.allowedRoles -contains 'fe930be7-5e62-47db-91af-98c3a49a38b1' -and $CurrentGraphState.allowedRoles -contains '62e90394-69f5-4237-9190-012177145e10') -or - # $null -ne $CurrentGraphState.allowedRoles) { $false } else { $true } - # $GraphStateCorrect = $UsersCanChangePhotos -eq $DesiredState - + $Uri = 'https://graph.microsoft.com/beta/admin/people/photoUpdateSettings' + $CurrentGraphState = New-GraphGetRequest -uri $Uri -tenantid $Tenant + $UsersCanChangePhotos = if (($CurrentGraphState.allowedRoles -contains 'fe930be7-5e62-47db-91af-98c3a49a38b1' -and $CurrentGraphState.allowedRoles -contains '62e90394-69f5-4237-9190-012177145e10') -or + $null -ne $CurrentGraphState.allowedRoles) { $false } else { $true } + $GraphStateCorrect = $UsersCanChangePhotos -eq $DesiredState # Get current OWA mailbox policy state $CurrentOWAState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OwaMailboxPolicy' -cmdParams @{Identity = 'OwaMailboxPolicy-Default' } -Select 'Identity,SetPhotoEnabled' $OWAStateCorrect = $CurrentOWAState.SetPhotoEnabled -eq $DesiredState - # $CurrentStatesCorrect = $GraphStateCorrect -eq $true -and $OWAStateCorrect -eq $true - $CurrentStatesCorrect = $OWAStateCorrect -eq $true + + $CurrentStatesCorrect = $GraphStateCorrect -eq $true -and $OWAStateCorrect -eq $true if ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' @@ -72,7 +65,7 @@ function Invoke-CIPPStandardProfilePhotos { Write-Host 'Enabling' # Enable photo updates $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OwaMailboxPolicy' -cmdParams @{Identity = $CurrentOWAState.Identity; SetPhotoEnabled = $true } -useSystemMailbox $true - # $null = New-GraphRequest -uri $Uri -tenant $Tenant -type DELETE + $null = New-GraphPostRequest -uri $Uri -tenant $Tenant -type DELETE -AsApp $true Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Profile photo settings to $StateValue" -sev Info } else { @@ -80,15 +73,15 @@ function Invoke-CIPPStandardProfilePhotos { # Disable photo updates $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OwaMailboxPolicy' -cmdParams @{Identity = $CurrentOWAState.Identity; SetPhotoEnabled = $false } -useSystemMailbox $true - # $body = @{ - # source = 'cloud' - # allowedRoles = @( - # 'fe930be7-5e62-47db-91af-98c3a49a38b1', # Global admin - # '62e90394-69f5-4237-9190-012177145e10' # User admin - # ) - # } - # $body = ConvertTo-Json -InputObject $body -Depth 5 -Compress - # $null = New-GraphPostRequest -uri $Uri -tenant $Tenant -body $body -type PATCH -AsApp $true + $body = @{ + source = 'cloud' + allowedRoles = @( + 'fe930be7-5e62-47db-91af-98c3a49a38b1', # Global admin + '62e90394-69f5-4237-9190-012177145e10' # User admin + ) + } + $body = ConvertTo-Json -InputObject $body -Depth 5 -Compress + $null = New-GraphPostRequest -uri $Uri -tenant $Tenant -body $body -type PATCH -AsApp $true Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Profile photo settings to $StateValue" -sev Info } } catch { @@ -115,7 +108,10 @@ function Invoke-CIPPStandardProfilePhotos { if ($CurrentStatesCorrect) { $FieldValue = $true } else { - $FieldValue = $CurrentOWAState + $FieldValue = [PSCustomObject]@{ + OwaStateCorrect = $OWAStateCorrect + GraphStateCorrect = $GraphStateCorrect + } } Set-CIPPStandardsCompareField -FieldName 'standards.ProfilePhotos' -FieldValue $FieldValue -Tenant $Tenant } From cc8e91f9b64381479a78c4c2d92d2f49624865c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Thu, 15 May 2025 19:51:37 +0200 Subject: [PATCH 038/149] clumsy looking but functional --- .../Standards/Invoke-CIPPStandardProfilePhotos.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 index 303dab289f99..9a3f76a85da6 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 @@ -45,14 +45,19 @@ function Invoke-CIPPStandardProfilePhotos { # Get current Graph policy state $Uri = 'https://graph.microsoft.com/beta/admin/people/photoUpdateSettings' $CurrentGraphState = New-GraphGetRequest -uri $Uri -tenantid $Tenant - $UsersCanChangePhotos = if (($CurrentGraphState.allowedRoles -contains 'fe930be7-5e62-47db-91af-98c3a49a38b1' -and $CurrentGraphState.allowedRoles -contains '62e90394-69f5-4237-9190-012177145e10') -or - $null -ne $CurrentGraphState.allowedRoles) { $false } else { $true } + $UsersCanChangePhotos = if ([string]::IsNullOrWhiteSpace($CurrentGraphState.allowedRoles) ) { $true } else { $false } $GraphStateCorrect = $UsersCanChangePhotos -eq $DesiredState + if ($UsersCanChangePhotos -eq $false -and $DesiredState -eq $false) { + # Check if the correct roles are present + $GraphStateCorrect = $CurrentGraphState.allowedRoles -contains '62e90394-69f5-4237-9190-012177145e10' -and $CurrentGraphState.allowedRoles -contains 'fe930be7-5e62-47db-91af-98c3a49a38b1' + } + # Get current OWA mailbox policy state $CurrentOWAState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OwaMailboxPolicy' -cmdParams @{Identity = 'OwaMailboxPolicy-Default' } -Select 'Identity,SetPhotoEnabled' $OWAStateCorrect = $CurrentOWAState.SetPhotoEnabled -eq $DesiredState + # Check if both states are correct $CurrentStatesCorrect = $GraphStateCorrect -eq $true -and $OWAStateCorrect -eq $true if ($Settings.remediate -eq $true) { From eb9bcaaa62138e4d147ed7dce7b33543da16b874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Thu, 15 May 2025 23:35:32 +0200 Subject: [PATCH 039/149] Refactor Invoke-ExecDeviceAction and New-CIPPDeviceAction to improve logging and add support for changing primary user --- .../Endpoint/MEM/Invoke-ExecDeviceAction.ps1 | 47 +++++++++++-------- .../CIPPCore/Public/New-CIPPDeviceAction.ps1 | 27 +++++++---- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 index bb14abf9e099..5600b3984fce 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 @@ -15,36 +15,45 @@ Function Invoke-ExecDeviceAction { Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' # Interact with Body parameters or the body of the request. - + $Action = $Request.Body.Action + $DeviceFilter = $Request.Body.GUID + $TenantFilter = $Request.Body.tenantFilter try { - if ($Request.Body.Action -eq 'setDeviceName') { - $ActionBody = @{ deviceName = $Request.Body.input } | ConvertTo-Json -Compress - } - else { - $ActionBody = $Request.Body | ConvertTo-Json -Compress + switch ($Action) { + 'setDeviceName' { + $ActionBody = @{ deviceName = $Request.Body.input } | ConvertTo-Json -Compress + break + } + 'users' { + $ActionBody = @{ '@odata.id' = "https://graph.microsoft.com/beta/users('$($Request.Body.user.value)')" } | ConvertTo-Json -Compress + Write-Host "ActionBody: $ActionBody" + break + } + Default { $ActionBody = $Request.Body | ConvertTo-Json -Compress } } - $cmdparams = @{ - Action = $Request.Body.Action - ActionBody = $ActionBody - DeviceFilter = $Request.Body.GUID - TenantFilter = $Request.Body.TenantFilter - Headers = $Request.Headers - APINAME = $APINAME + $cmdParams = @{ + Action = $Action + ActionBody = $ActionBody + DeviceFilter = $DeviceFilter + TenantFilter = $TenantFilter + Headers = $Headers + APINAME = $APIName } - $ActionResult = New-CIPPDeviceAction @cmdparams + $ActionResult = New-CIPPDeviceAction @cmdParams - $body = [pscustomobject]@{'Results' = "$ActionResult" } + $StatusCode = [HttpStatusCode]::OK + $Results = "$ActionResult" } catch { - $body = [pscustomobject]@{'Results' = "Failed to queue action $action on $DeviceFilter $($_.Exception.Message)" } + $StatusCode = [HttpStatusCode]::InternalServerError + $Results = "$($_.Exception.Message)" } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{ 'Results' = $Results } }) - } diff --git a/Modules/CIPPCore/Public/New-CIPPDeviceAction.ps1 b/Modules/CIPPCore/Public/New-CIPPDeviceAction.ps1 index 931d28dc38af..33b42b971a78 100644 --- a/Modules/CIPPCore/Public/New-CIPPDeviceAction.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPDeviceAction.ps1 @@ -6,20 +6,27 @@ function New-CIPPDeviceAction { $DeviceFilter, $TenantFilter, $Headers, - $APINAME + $APIName ) try { - if ($action -eq 'delete') { - $null = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices/$DeviceFilter" -type DELETE -tenantid $TenantFilter - Write-LogMessage -headers $Headers -API $APINAME -tenant $TenantFilter -message "Queued $Action on $DeviceFilter" -Sev 'Info' - return "Queued $Action on $DeviceFilter" + if ($Action -eq 'delete') { + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices/$DeviceFilter" -type DELETE -tenantid $TenantFilter + } elseif ($Action -eq 'users') { + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices('$DeviceFilter')/$($Action)/`$ref" -type POST -tenantid $TenantFilter -body $ActionBody + $regex = "(?<=\(')([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})(?='|\))" + $PrimaryUser = $ActionBody | Select-String -Pattern $regex -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value + $Result = "Changed primary user on device $DeviceFilter to $PrimaryUser" + } else { + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices('$DeviceFilter')/$($Action)" -type POST -tenantid $TenantFilter -body $ActionBody + $Result = "Queued $Action on $DeviceFilter" } - $null = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices('$DeviceFilter')/$($Action)" -type POST -tenantid $TenantFilter -body $ActionBody - Write-LogMessage -headers $Headers -API $APINAME -tenant $TenantFilter -message "Queued $Action on $DeviceFilter" -Sev 'Info' - return "Queued $Action on $DeviceFilter" + + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info + return $Result } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APINAME -tenant $TenantFilter -message "Failed to queue action $Action on $DeviceFilter : $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - return "Failed to queue action $Action on $DeviceFilter $($ErrorMessage.NormalizedError)" + $Result = "Failed to queue action $Action on $DeviceFilter : $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Error -LogData $ErrorMessage + throw $Result } } From 7c09f632ebc432d22bdae1fd08dbcb7e455b126b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 16 May 2025 02:41:51 +0200 Subject: [PATCH 040/149] DeviceCodeLogin API --- .../CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 new file mode 100644 index 000000000000..bd4966322035 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 @@ -0,0 +1,82 @@ +using namespace System.Net + +Function Invoke-ExecDeviceCodeLogon { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.AppSettings.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) + if ('admin' -notin $UserCreds.userRoles) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + ContentType = 'application/json' + StatusCode = [HttpStatusCode]::Forbidden + Body = @{ + error = 'Forbidden' + errorMessage = 'You do not have permission to perform this action' + } | ConvertTo-Json + }) + exit + } + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + try { + $clientId = $Request.Query.clientId + $scope = $Request.Query.scope + $tenantId = $Request.Query.tenantId + $deviceCode = $Request.Query.deviceCode + + if (!$scope) { + $scope = 'https://graph.microsoft.com/.default' + } + if ($Request.Query.operation -eq 'getDeviceCode') { + $deviceCodeInfo = New-DeviceLogin -clientid $clientId -scope $scope -FirstLogon -TenantId $tenantId + $Results = @{ + user_code = $deviceCodeInfo.user_code + device_code = $deviceCodeInfo.device_code + verification_uri = $deviceCodeInfo.verification_uri + expires_in = $deviceCodeInfo.expires_in + interval = $deviceCodeInfo.interval + message = $deviceCodeInfo.message + } + } elseif ($Request.Query.operation -eq 'checkToken') { + $tokenInfo = New-DeviceLogin -clientid $clientId -scope $scope -device_code $deviceCode + + if ($tokenInfo.refresh_token) { + $Results = @{ + status = 'success' + access_token = $tokenInfo.access_token + refresh_token = $tokenInfo.refresh_token + id_token = $tokenInfo.id_token + expires_in = $tokenInfo.expires_in + ext_expires_in = $tokenInfo.ext_expires_in + } + } else { + $Results = @{ + status = 'pending' + error = $tokenInfo.error + error_description = $tokenInfo.error_description + } + } + } + } catch { + $Results = @{ + error = 'server_error' + error_description = "An error occurred: $($_.Exception.Message)" + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results | ConvertTo-Json + Headers = @{'Content-Type' = 'application/json' } + }) +} From d605650a5d657d882fe9af215340d7816250739a Mon Sep 17 00:00:00 2001 From: Esco Date: Fri, 16 May 2025 10:41:17 +0200 Subject: [PATCH 041/149] fix: Skype Consumer Interoperability with Teams is no longer supported --- ...-CIPPStandardTeamsExternalAccessPolicy.ps1 | 20 ++++++++----------- ...PPStandardTeamsFederationConfiguration.ps1 | 5 +---- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 index 6fccb1a51fa1..4d760b73749d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 @@ -15,7 +15,6 @@ function Invoke-CIPPStandardTeamsExternalAccessPolicy { TAG ADDEDCOMPONENT {"type":"switch","name":"standards.TeamsExternalAccessPolicy.EnableFederationAccess","label":"Allow communication from trusted organizations"} - {"type":"switch","name":"standards.TeamsExternalAccessPolicy.EnablePublicCloudAccess","label":"Allow user to communicate with Skype users"} {"type":"switch","name":"standards.TeamsExternalAccessPolicy.EnableTeamsConsumerAccess","label":"Allow communication with unmanaged Teams accounts"} IMPACT Medium Impact @@ -35,13 +34,11 @@ function Invoke-CIPPStandardTeamsExternalAccessPolicy { $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsExternalAccessPolicy' -CmdParams @{Identity = 'Global' } | Select-Object * - if ($null -eq $Settings.EnableFederationAccess) { $Settings.EnableFederationAccess = $false } - if ($null -eq $Settings.EnablePublicCloudAccess) { $Settings.EnablePublicCloudAccess = $false } - if ($null -eq $Settings.EnableTeamsConsumerAccess) { $Settings.EnableTeamsConsumerAccess = $false } + $EnableFederationAccess = $Settings.EnableFederationAccess ?? $false + $EnableTeamsConsumerAccess = $Settings.EnableTeamsConsumerAccess ?? $false - $StateIsCorrect = ($CurrentState.EnableFederationAccess -eq $Settings.EnableFederationAccess) -and - ($CurrentState.EnablePublicCloudAccess -eq $Settings.EnablePublicCloudAccess) -and - ($CurrentState.EnableTeamsConsumerAccess -eq $Settings.EnableTeamsConsumerAccess) + $StateIsCorrect = ($CurrentState.EnableFederationAccess -eq $EnableFederationAccess) -and + ($CurrentState.EnableTeamsConsumerAccess -eq $EnableTeamsConsumerAccess) if ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { @@ -49,9 +46,8 @@ function Invoke-CIPPStandardTeamsExternalAccessPolicy { } else { $cmdParams = @{ Identity = 'Global' - EnableFederationAccess = $Settings.EnableFederationAccess - EnablePublicCloudAccess = $Settings.EnablePublicCloudAccess - EnableTeamsConsumerAccess = $Settings.EnableTeamsConsumerAccess + EnableFederationAccess = $EnableFederationAccess + EnableTeamsConsumerAccess = $EnableTeamsConsumerAccess } try { @@ -76,10 +72,10 @@ function Invoke-CIPPStandardTeamsExternalAccessPolicy { if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'TeamsExternalAccessPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - if ($StateIsCorrect) { + if ($StateIsCorrect -eq $true) { $FieldValue = $true } else { - $FieldValue = $CurrentState | Select-Object EnableFederationAccess, EnablePublicCloudAccess, EnableTeamsConsumerAccess + $FieldValue = $CurrentState | Select-Object EnableFederationAccess, EnableTeamsConsumerAccess } Set-CIPPStandardsCompareField -FieldName 'standards.TeamsExternalAccessPolicy' -FieldValue $FieldValue -Tenant $Tenant diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 index e339a02fd911..56de1b3d5499 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 @@ -15,7 +15,6 @@ function Invoke-CIPPStandardTeamsFederationConfiguration { TAG ADDEDCOMPONENT {"type":"switch","name":"standards.TeamsFederationConfiguration.AllowTeamsConsumer","label":"Allow users to communicate with other organizations"} - {"type":"switch","name":"standards.TeamsFederationConfiguration.AllowPublicUsers","label":"Allow users to communicate with Skype Users"} {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"name":"standards.TeamsFederationConfiguration.DomainControl","label":"Communication Mode","options":[{"label":"Allow all external domains","value":"AllowAllExternal"},{"label":"Block all external domains","value":"BlockAllExternal"},{"label":"Allow specific external domains","value":"AllowSpecificExternal"},{"label":"Block specific external domains","value":"BlockSpecificExternal"}]} {"type":"textField","name":"standards.TeamsFederationConfiguration.DomainList","label":"Domains, Comma separated","required":false} IMPACT @@ -87,7 +86,6 @@ function Invoke-CIPPStandardTeamsFederationConfiguration { $BlockedDomainsMatches = -not (Compare-Object -ReferenceObject $BlockedDomains -DifferenceObject $CurrentState.BlockedDomains) $StateIsCorrect = ($CurrentState.AllowTeamsConsumer -eq $Settings.AllowTeamsConsumer) -and - ($CurrentState.AllowPublicUsers -eq $Settings.AllowPublicUsers) -and ($CurrentState.AllowFederatedUsers -eq $AllowFederatedUsers) -and $AllowedDomainsMatches -and $BlockedDomainsMatches @@ -99,7 +97,6 @@ function Invoke-CIPPStandardTeamsFederationConfiguration { $cmdParams = @{ Identity = 'Global' AllowTeamsConsumer = $Settings.AllowTeamsConsumer - AllowPublicUsers = $Settings.AllowPublicUsers AllowFederatedUsers = $AllowFederatedUsers BlockedDomains = $BlockedDomains } @@ -134,7 +131,7 @@ function Invoke-CIPPStandardTeamsFederationConfiguration { if ($StateIsCorrect -eq $true) { $FieldValue = $true } else { - $FieldValue = $CurrentState + $FieldValue = $CurrentState | Select-Object AllowTeamsConsumer, AllowFederatedUsers, AllowedDomains, BlockedDomains } Set-CIPPStandardsCompareField -FieldName 'standards.TeamsFederationConfiguration' -FieldValue $FieldValue -Tenant $Tenant } From 02b234e6ec09b09a71454a738119ec6579739cdb Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 16 May 2025 12:33:03 -0400 Subject: [PATCH 042/149] fix listgraphrequest alltenants --- Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 | 4 ++-- .../CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 index 9f340b1fb0ae..ddfa6ad0408b 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -4,7 +4,7 @@ function New-GraphGetRequest { Internal #> [CmdletBinding()] - Param( + param( [string]$uri, [string]$tenantid, [string]$scope, @@ -67,7 +67,7 @@ function New-GraphGetRequest { $NextURL = $null } else { if ($Data.PSObject.Properties.Name -contains 'value') { $data.value } else { $Data } - if ($noPagination) { + if ($noPagination -eq $true) { if ($Caller -eq 'Get-GraphRequestList') { @{ 'nextLink' = $data.'@odata.nextLink' } } diff --git a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 index 2f3e24a93a45..1370345fe9a1 100644 --- a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 +++ b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 @@ -47,7 +47,7 @@ function Get-GraphRequestList { #> [CmdletBinding()] - Param( + param( [string]$TenantFilter = $env:TenantID, [Parameter(Mandatory = $true)] [string]$Endpoint, @@ -69,7 +69,7 @@ function Get-GraphRequestList { ) $SingleTenantThreshold = 8000 - + Write-Information "Tenant: $TenantFilter" $TableName = ('cache{0}' -f ($Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join '' Write-Information "Table: $TableName" $Endpoint = $Endpoint -replace '^/', '' @@ -93,7 +93,7 @@ function Get-GraphRequestList { } } $GraphQuery.Query = $ParamCollection.ToString() - $PartitionKey = Get-StringHash -String (@($Endpoint, $ParamCollection.ToString()) -join '-') + $PartitionKey = Get-StringHash -String (@($Endpoint, $ParamCollection.ToString(), 'v2') -join '-') Write-Information "PK: $PartitionKey" # Perform $count check before caching From 6998d430b23404c67becde684508864c34b66914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 16 May 2025 19:13:50 +0200 Subject: [PATCH 043/149] feat: add EntraConnectSyncStatus alert --- .../Get-CIPPAlertEntraConnectSyncStatus.ps1 | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Modules/CIPPCore/Public/Alerts/Get-CIPPAlertEntraConnectSyncStatus.ps1 diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertEntraConnectSyncStatus.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertEntraConnectSyncStatus.ps1 new file mode 100644 index 000000000000..3326efd47f3a --- /dev/null +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertEntraConnectSyncStatus.ps1 @@ -0,0 +1,33 @@ + +function Get-CIPPAlertEntraConnectSyncStatus { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [Alias('input')] + $InputValue, + $TenantFilter + ) + try { + # Set Hours with fallback to 72 hours + $Hours = if ($InputValue) { [int]$InputValue } else { 72 } + $ConnectSyncStatus = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization?$select=onPremisesLastPasswordSyncDateTime,onPremisesLastSyncDateTime,onPremisesSyncEnabled' -tenantid $TenantFilter + + if ($ConnectSyncStatus.onPremisesSyncEnabled -eq $true) { + $LastPasswordSync = $ConnectSyncStatus.onPremisesLastPasswordSyncDateTime + $SyncDateTime = $ConnectSyncStatus.onPremisesLastSyncDateTime + # Get the older of the two sync times + $LastSync = if ($SyncDateTime -lt $LastPasswordSync) { $SyncDateTime } else { $LastPasswordSync } + + if ($LastSync -lt (Get-Date).AddHours(-$Hours).ToUniversalTime()) { + $AlertData = "Entra Connect Sync for $($TenantFilter) has not run for over $Hours hours. Last sync was at $($LastSync.ToString('o'))" + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData + } + } + } catch { + Write-AlertMessage -tenant $($TenantFilter) -message "Could not get Entra Connect Sync Status for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)" + } +} From 8e7104147bc66a68ec16be4ef65da76280f9a9b4 Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Sat, 17 May 2025 02:08:45 +0800 Subject: [PATCH 044/149] Add username to TAP response --- .../Users/Invoke-ExecCreateTAP.ps1 | 17 ++++++++++++++--- Modules/CIPPCore/Public/New-CIPPTAP.ps1 | 3 ++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 index 8aed811cfd84..58187b2f6640 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 @@ -19,17 +19,28 @@ Function Invoke-ExecCreateTAP { $UserID = $Request.Query.ID ?? $Request.Body.ID try { - $Result = New-CIPPTAP -userid $UserID -TenantFilter $TenantFilter -APIName $APIName -Headers $Headers + $TAPResult = New-CIPPTAP -userid $UserID -TenantFilter $TenantFilter -APIName $APIName -Headers $Headers + + # Create results array with both TAP and UserID as separate items + $Results = @( + $TAPResult, + @{ + resultText = "User ID: $UserID" + copyField = $UserID + state = 'success' + } + ) + $StatusCode = [HttpStatusCode]::OK } catch { - $Result = Get-NormalizedError -message $($_.Exception.Message) + $Results = Get-NormalizedError -message $($_.Exception.Message) $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = @{'Results' = $Result } + Body = @{'Results' = $Results } }) } diff --git a/Modules/CIPPCore/Public/New-CIPPTAP.ps1 b/Modules/CIPPCore/Public/New-CIPPTAP.ps1 index 9e87986718bc..1d934411dff1 100644 --- a/Modules/CIPPCore/Public/New-CIPPTAP.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPTAP.ps1 @@ -11,7 +11,8 @@ function New-CIPPTAP { $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/authentication/temporaryAccessPassMethods" -tenantid $TenantFilter -type POST -body '{}' -verbose Write-LogMessage -headers $Headers -API $APIName -message "Created Temporary Access Password (TAP) for $userid" -Sev 'Info' -tenant $TenantFilter return @{ - resultText = "The TAP for this user is $($GraphRequest.temporaryAccessPass) - This TAP is usable for the next $($GraphRequest.LifetimeInMinutes) minutes" + resultText = "The TAP for $userid is $($GraphRequest.temporaryAccessPass) - This TAP is usable for the next $($GraphRequest.LifetimeInMinutes) minutes" + userid = $userid copyField = $GraphRequest.temporaryAccessPass temporaryAccessPass = $GraphRequest.temporaryAccessPass lifetimeInMinutes = $GraphRequest.LifetimeInMinutes From 557948833b20d8bebac087c33125b51a57e63891 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 16 May 2025 16:01:53 -0400 Subject: [PATCH 045/149] Fix HaloPSA ticket creation add _novalidate - thanks to Rewst community Add PSA test option for notification settings --- .../CIPP/Core/Invoke-ExecAddAlert.ps1 | 19 ++++++++++++++----- Modules/CIPPCore/Public/Send-CIPPAlert.ps1 | 3 +-- .../Public/Halo/New-HaloPSATicket.ps1 | 9 ++++++--- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 index b32a0c137efb..f93622fee27c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecAddAlert { +function Invoke-ExecAddAlert { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -16,9 +16,9 @@ Function Invoke-ExecAddAlert { $Severity = 'Alert' - $Result = if ($Request.Body.sendEmailNow -or $Request.Body.sendWebhookNow -eq $true -or $Request.Body.writeLog -eq $true) { + $Result = if ($Request.Body.sendEmailNow -or $Request.Body.sendWebhookNow -eq $true -or $Request.Body.writeLog -eq $true -or $Request.Body.sendPsaNow -eq $true) { $Title = 'CIPP Notification Test' - if ($Request.Body.sendEmailNow) { + if ($Request.Body.sendEmailNow -eq $true) { $CIPPAlert = @{ Type = 'email' Title = $Title @@ -26,7 +26,7 @@ Function Invoke-ExecAddAlert { } Send-CIPPAlert @CIPPAlert } - if ($Request.Body.sendWebhookNow) { + if ($Request.Body.sendWebhookNow -eq $true) { $JSONContent = @{ Title = $Title Text = $Request.Body.text @@ -38,7 +38,16 @@ Function Invoke-ExecAddAlert { } Send-CIPPAlert @CIPPAlert } - if ($Request.Body.writeLog) { + if ($Request.Body.sendPsaNow -eq $true) { + $CIPPAlert = @{ + Type = 'psa' + Title = $Title + HTMLContent = $Request.Body.text + } + Send-CIPPAlert @CIPPAlert + } + + if ($Request.Body.writeLog -eq $true) { Write-LogMessage -headers $Headers -API 'Alerts' -message $Request.Body.text -Sev $Severity 'Successfully generated alert.' } diff --git a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 index 3a186dc0b27c..90f3e36c3649 100644 --- a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 +++ b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 @@ -106,9 +106,9 @@ function Send-CIPPAlert { Write-LogMessage -API 'Webhook Alerts' -message "Could not send alerts to webhook: $($ErrorMessage.NormalizedError)" -tenant $TenantFilter -sev error -LogData $ErrorMessage } } - Write-Information 'Trying to send to PSA' if ($Type -eq 'psa') { + Write-Information 'Trying to send to PSA' if ($config.sendtoIntegration) { if ($PSCmdlet.ShouldProcess('PSA', 'Sending alert')) { try { @@ -119,7 +119,6 @@ function Send-CIPPAlert { } New-CippExtAlert -Alert $Alert Write-LogMessage -API 'Webhook Alerts' -tenant $TenantFilter -message "Sent PSA alert $title" -sev info - } catch { $ErrorMessage = Get-CippException -Exception $_ Write-Information "Could not send alerts to ticketing system: $($ErrorMessage.NormalizedError)" diff --git a/Modules/CippExtensions/Public/Halo/New-HaloPSATicket.ps1 b/Modules/CippExtensions/Public/Halo/New-HaloPSATicket.ps1 index aec4c496d852..537b6a72f438 100644 --- a/Modules/CippExtensions/Public/Halo/New-HaloPSATicket.ps1 +++ b/Modules/CippExtensions/Public/Halo/New-HaloPSATicket.ps1 @@ -32,9 +32,9 @@ function New-HaloPSATicket { try { if ($PSCmdlet.ShouldProcess('Add note to HaloPSA ticket', 'Add note')) { $Action = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/actions" -ContentType 'application/json; charset=utf-8' -Method Post -Body $body -Headers @{Authorization = "Bearer $($token.access_token)" } - Write-Information "Note added to ticket in HaloPSA: $($Action.id)" + Write-Information "Note added to ticket in HaloPSA: $($ExistingTicket.TicketID)" } - return + return "Note added to ticket in HaloPSA: $($ExistingTicket.TicketID)" } catch { $Message = if ($_.ErrorDetails.Message) { Get-NormalizedError -Message $_.ErrorDetails.Message @@ -44,7 +44,7 @@ function New-HaloPSATicket { Write-LogMessage -message "Failed to add note to HaloPSA ticket: $Message" -API 'HaloPSATicket' -sev Error -LogData (Get-CippException -Exception $_) Write-Information "Failed to add note to HaloPSA ticket: $Message" Write-Information "Body we tried to ship: $body" - return + return "Failed to add note to HaloPSA ticket: $Message" } } } @@ -66,6 +66,7 @@ function New-HaloPSATicket { details_html = $description donotapplytemplateintheapi = $true attachments = @() + _novalidate = $true } if ($Configuration.TicketType) { @@ -93,6 +94,7 @@ function New-HaloPSATicket { Add-CIPPAzDataTableEntity @TicketTable -Entity $TicketObject -Force Write-Information 'Ticket added to consolidation table' } + return "Ticket created in HaloPSA: $($Ticket.id)" } } catch { $Message = if ($_.ErrorDetails.Message) { @@ -103,5 +105,6 @@ function New-HaloPSATicket { Write-LogMessage -message "Failed to send ticket to HaloPSA: $Message" -API 'HaloPSATicket' -sev Error -LogData (Get-CippException -Exception $_) Write-Information "Failed to send ticket to HaloPSA: $Message" Write-Information "Body we tried to ship: $body" + return "Failed to send ticket to HaloPSA: $Message" } } From 5f43d865733c90b6196b791d29b923cd46574e5d Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Fri, 16 May 2025 22:27:35 +0200 Subject: [PATCH 046/149] Added function for Custom Quarantine Policies --- .../Invoke-CIPPStandardQuarantineTemplate.ps1 | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 new file mode 100644 index 000000000000..05d7cdda04ae --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 @@ -0,0 +1,250 @@ +function Invoke-CIPPStandardQuarantineTemplate { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) QuarantineTemplate + .SYNOPSIS + (Label) Custom Quarantine Policy + .DESCRIPTION + (Helptext) This standard creates a Custom Quarantine Policies that can be used in Anti-Spam and all MDO365 policies. Quarantine Policies can be used to specify recipients permissions, enable end-user spam notifications, and specify the release action preference + (DocsDescription) This standard creates a Custom Quarantine Policies that can be used in Anti-Spam and all MDO365 policies. Quarantine Policies can be used to specify recipients permissions, enable end-user spam notifications, and specify the release action preference + .NOTES + CAT + Defender Standards + DISABLEDFEATURES + {"report":false,"warn":false,"remediate":false} + TAG + ADDEDCOMPONENT + {"type":"autoComplete","multiple":false,"creatable":true,"name":"displayName","label":"Quarantine Display Name","required":true} + {"type":"switch","label":"Enable end-user spam notifications","name":"ESNEnabled","defaultValue":true,"required":false} + {"type":"select","multiple":false,"label":"Select release action preference","name":"ReleaseAction","options":[{"label":"Allow recipients to request a message to be released from quarantine","value":"PermissionToRequestRelease"},{"label":"Allow recipients to release a message from quarantine","value":"PermissionToRelease"}]} + {"type":"switch","label":"Include Messages From Blocked Sender Address","name":"IncludeMessagesFromBlockedSenderAddress","defaultValue":false,"required":false} + {"type":"switch","label":"Allow recipients to delete message","name":"PermissionToDelete","defaultValue":false,"required":false} + {"type":"switch","label":"Allow recipients to preview message","name":"PermissionToPreview","defaultValue":false,"required":false} + {"type":"switch","label":"Allow recipients to block Sender Address","name":"PermissionToBlockSender","defaultValue":false,"required":false} + {"type":"switch","label":"Allow recipients to whitelist Sender Address","name":"PermissionToAllowSender","defaultValue":false,"required":false} + MULTIPLE + True + IMPACT + Low Impact + ADDEDDATE + 2025-05-16 + POWERSHELLEQUIVALENT + Set-QuarantinePolicy or New-QuarantinePolicy + RECOMMENDEDBY + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact + #> + + param($Tenant, $Settings) + + + function Convert-HashtableToEndUserQuarantinePermissionsValue { + param ( + [hashtable]$InputHashtable + ) + #Converts hashtable with selected end user quarantine permissions to decimal value used by EndUserQuarantinePermissionsValue property in New-QuarantinePolicy and Set-QuarantinePolicy + try { + $EndUserQuarantinePermissionsValue = 0 + $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToViewHeader * 128 + $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToDownload * 64 + $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToAllowSender * 32 + $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToBlockSender * 16 + $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToRequestRelease * 8 + $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToRelease * 4 + $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToPreview * 2 + $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToDelete * 1 + return $EndUserQuarantinePermissionsValue + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + throw "Convert-HashtableToEndUserQuarantinePermissionsValue: Failed to hashtable QuarantinePermissionsValue. Error: $ErrorMessage" + } + } + + function Convert-StringToHashtable { + param ( + [string]$InputString + ) + #Converts string value with EndUserQuarantinePermissions received from Get-QuarantinePolicy + try { + # Remove square brackets and split into lines + $InputString = $InputString.Trim('[', ']') + $hashtable = @{} + $InputString -split "`n" | ForEach-Object { + $key, $value = $_ -split ":\s*" + $hashtable[$key.Trim()] = [System.Convert]::ToBoolean($value.Trim()) + } + return $hashtable + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + throw "Convert-StringToHashtable: Failed to convert string to hashtable. Error: $ErrorMessage" + } + } + + try { + # Get the current custom quarantine policies + $CurrentPolicies = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-QuarantinePolicy' | Where-Object -Property Guid -ne '00000000-0000-0000-0000-000000000000' -ErrorAction Stop + + # Compare the settings from standard with the current policies + $CompareList = foreach ($Policy in $Settings) { + try { + # prepare the cmdParams used in New-ExoRequest + $cmdParams = @{ + ESNEnabled = $Policy.ESNEnabled + IncludeMessagesFromBlockedSenderAddress = $Policy.IncludeMessagesFromBlockedSenderAddress + } + + # Create hashtable with desired EndUserQuarantinePermissions + $EndUserQuarantinePermissions = @{ + PermissionToBlockSender = $Policy.PermissionToBlockSender + PermissionToDelete = $Policy.PermissionToDelete + PermissionToDownload = $false + PermissionToPreview = $Policy.PermissionToPreview + PermissionToRelease = if ($Policy.ReleaseAction -eq "PermissionToRelease") { $true } else { $false } + PermissionToRequestRelease = if ($Policy.ReleaseAction -eq "PermissionToRequestRelease") { $true } else { $false } + PermissionToViewHeader = $true + PermissionToAllowSender = $Policy.PermissionToAllowSender + } + + # If the Quarantine Policy already exists + if ($Policy.displayName.value -in $CurrentPolicies.Name) { + #Get the current policy and convert EndUserQuarantinePermissions from string to hashtable for compare + $ExistingPolicy = $CurrentPolicies | Where-Object -Property Name -eq $Policy.displayName.value + $ExistingPolicyEndUserQuarantinePermissions = Convert-StringToHashtable -InputString $ExistingPolicy.EndUserQuarantinePermissions -ErrorAction Stop + + #Compare the current policy + $StateIsCorrect = ($ExistingPolicy.Name -eq $Policy.displayName.value) -and + ($ExistingPolicy.ESNEnabled -eq $Policy.ESNEnabled) -and + ($ExistingPolicy.IncludeMessagesFromBlockedSenderAddress -eq $Policy.IncludeMessagesFromBlockedSenderAddress) -and + (!(Compare-Object @($ExistingPolicyEndUserQuarantinePermissions.values) @($EndUserQuarantinePermissions.values))) + + # If the current policy is correct + if ($StateIsCorrect -eq $true) { + [PSCustomObject]@{ + missing = $false + StateIsCorrect = $StateIsCorrect + displayName = $Policy.displayName.value + EndUserQuarantinePermissions = $EndUserQuarantinePermissions + cmdParams = $cmdParams + remediate = $Policy.remediate + alert = $Policy.alert + report = $Policy.report + } + } + #If the current policy doesn't match the desired settings + else { + [PSCustomObject]@{ + missing = $false + StateIsCorrect = $StateIsCorrect + displayName = $Policy.displayName.value + EndUserQuarantinePermissions = $EndUserQuarantinePermissions + cmdParams = $cmdParams + remediate = $Policy.remediate + alert = $Policy.alert + report = $Policy.report + } + } + } + #If no existing Quarantine Policy with the same name was found + else { + [PSCustomObject]@{ + missing = $true + StateIsCorrect = $false + displayName = $Policy.displayName.value + EndUserQuarantinePermissions = $EndUserQuarantinePermissions + cmdParams = $cmdParams + remediate = $Policy.remediate + alert = $Policy.alert + report = $Policy.report + } + } + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to compare Quarantine policy $($Policy.displayName.value), Error: $ErrorMessage" -sev 'Error' + } + } + + + If ($true -in $Settings.remediate) { + # Remediate each policy which is incorrect or missing + foreach ($Policy in $CompareList | Where-Object { $_.remediate -EQ $true -and $_.StateIsCorrect -eq $false }) { + try { + # Convert desired EndUserQuarantinePermissions to decimal value + $EndUserQuarantinePermissionsValue = Convert-HashtableToEndUserQuarantinePermissionsValue -InputHashtable $Policy.EndUserQuarantinePermissions -ErrorAction Stop + $cmdParams = $Policy.cmdParams + + # Create policy if missing + if ($Policy.missing) { + try { + #Add the rest of the desired settings to cmdParams + $cmdParams.Add('Name', $Policy.displayName) + $cmdParams.Add('EndUserQuarantinePermissionsValue', $EndUserQuarantinePermissionsValue) + + New-ExoRequest -tenantid $Tenant -cmdlet 'New-QuarantinePolicy' -cmdParams $cmdParams -UseSystemMailbox $true -ErrorAction Stop + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Custom Quarantine Policy $($Policy.displayName)" -sev Info + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create Quarantine policy $($Policy.displayName), Error: $ErrorMessage" -sev 'Error' + } + } + # Update policy if incorrect + else { + try { + #Add the rest of the desired settings to cmdParams + $cmdParams.Add('Identity', $Policy.displayName) + $cmdParams.Add('EndUserQuarantinePermissionsValue', $EndUserQuarantinePermissionsValue) + + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-QuarantinePolicy' -cmdParams $cmdParams -UseSystemMailbox $true -ErrorAction Stop + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Custom Quarantine Policy $($Policy.displayName)" -sev Info + } + catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Custom Quarantine Policy $($Policy.displayName)" -sev Error -LogData $_ + } + } + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Quarantine policy $($Policy.displayName), Error: $ErrorMessage" -sev 'Error' + } + } + } + + if ($true -in $Settings.alert) { + foreach ($Policy in $CompareList | Where-Object -Property alert -EQ $true) { + if ($Policy.StateIsCorrect) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Quarantine policy $($Policy.displayName) has the correct configuration." -sev Info + } + else { + if ($Policy.missing) { + $CurrentInfo = $Policy | Select-Object -Property displayName, missing + Write-StandardsAlert -message "Quarantine policy $($Policy.displayName) is missing." -object $CurrentInfo -tenant $Tenant -standardName 'QuarantineTemplate' -standardId $Settings.templateId + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Quarantine policy $($Policy.displayName) is missing." -sev info + } + else { + $CurrentInfo = $CurrentPolicies | Where-Object -Property Name -eq $Policy.displayName | Select-Object -Property Name, ESNEnabled, IncludeMessagesFromBlockedSenderAddress, EndUserQuarantinePermissions + Write-StandardsAlert -message "Quarantine policy $($Policy.displayName) does not match the expected configuration." -object $CurrentInfo -tenant $Tenant -standardName 'QuarantineTemplate' -standardId $Settings.templateId + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Quarantine policy $($Policy.displayName) does not match the expected configuration. We've generated an alert" -sev info + } + } + } + } + + if ($true -in $Settings.report) { + # This could do with an improvement. But will work for now or else reporting could be disabled for now + foreach ($Policy in $CompareList | Where-Object -Property report -EQ $true) { + Set-CIPPStandardsCompareField -FieldName "standards.QuarantineTemplate" -FieldValue $Policy.StateIsCorrect -TenantFilter $Tenant + } + } + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Quarantine policy/policies, Error: $ErrorMessage" -sev 'Error' + } +} From 9e04c5f9499c550a1f5df382c391c65ae4583979 Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Fri, 16 May 2025 22:28:12 +0200 Subject: [PATCH 047/149] Ran Update-StandardsComments --- .../Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 | 8 ++++---- .../Invoke-CIPPStandardMalwareFilterPolicy.ps1 | 2 +- .../Invoke-CIPPStandardSafeAttachmentPolicy.ps1 | 2 +- .../Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index 616d70246e6b..475fd682e14d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -28,13 +28,13 @@ function Invoke-CIPPStandardAntiPhishPolicy { {"type":"switch","label":"Show domain impersonation safety tip","name":"standards.AntiPhishPolicy.EnableSimilarDomainsSafetyTips","defaultValue":true} {"type":"switch","label":"Show user impersonation unusual characters safety tip","name":"standards.AntiPhishPolicy.EnableUnusualCharactersSafetyTips","defaultValue":true} {"type":"select","multiple":false,"label":"If the message is detected as spoof by spoof intelligence","name":"standards.AntiPhishPolicy.AuthenticationFailAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move to Junk Folder","value":"MoveToJmf"}]} - {"type":"select","multiple":false,"label":"Quarantine policy for Spoof","name":"standards.AntiPhishPolicy.SpoofQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"select","multiple":false,"creatable":true,"label":"Quarantine policy for Spoof","name":"standards.AntiPhishPolicy.SpoofQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"select","multiple":false,"label":"If a message is detected as user impersonation","name":"standards.AntiPhishPolicy.TargetedUserProtectionAction","options":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} - {"type":"select","multiple":false,"label":"Quarantine policy for user impersonation","name":"standards.AntiPhishPolicy.TargetedUserQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"select","multiple":false,"creatable":true,"label":"Quarantine policy for user impersonation","name":"standards.AntiPhishPolicy.TargetedUserQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"select","multiple":false,"label":"If a message is detected as domain impersonation","name":"standards.AntiPhishPolicy.TargetedDomainProtectionAction","options":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} - {"type":"select","multiple":false,"label":"Quarantine policy for domain impersonation","name":"standards.AntiPhishPolicy.TargetedDomainQuarantineTag","options":[{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"},{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"}]} + {"type":"select","multiple":false,"creatable":true,"label":"Quarantine policy for domain impersonation","name":"standards.AntiPhishPolicy.TargetedDomainQuarantineTag","options":[{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"},{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"}]} {"type":"select","multiple":false,"label":"If Mailbox Intelligence detects an impersonated user","name":"standards.AntiPhishPolicy.MailboxIntelligenceProtectionAction","options":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} - {"type":"select","multiple":false,"label":"Apply quarantine policy","name":"standards.AntiPhishPolicy.MailboxIntelligenceQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"select","multiple":false,"creatable":true,"label":"Apply quarantine policy","name":"standards.AntiPhishPolicy.MailboxIntelligenceQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} IMPACT Low Impact ADDEDDATE diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 index d5044ec3e36a..fe8b8bf7e5b9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 @@ -20,7 +20,7 @@ function Invoke-CIPPStandardMalwareFilterPolicy { ADDEDCOMPONENT {"type":"select","multiple":false,"label":"FileTypeAction","name":"standards.MalwareFilterPolicy.FileTypeAction","options":[{"label":"Reject","value":"Reject"},{"label":"Quarantine the message","value":"Quarantine"}]} {"type":"textField","name":"standards.MalwareFilterPolicy.OptionalFileTypes","required":false,"label":"Optional File Types, Comma separated"} - {"type":"select","multiple":false,"label":"QuarantineTag","name":"standards.MalwareFilterPolicy.QuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"select","multiple":false,"creatable":true,"label":"QuarantineTag","name":"standards.MalwareFilterPolicy.QuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"switch","label":"Enable Internal Sender Admin Notifications","required":false,"name":"standards.MalwareFilterPolicy.EnableInternalSenderAdminNotifications"} {"type":"textField","name":"standards.MalwareFilterPolicy.InternalSenderAdminAddress","required":false,"label":"Internal Sender Admin Address"} {"type":"switch","label":"Enable External Sender Admin Notifications","required":false,"name":"standards.MalwareFilterPolicy.EnableExternalSenderAdminNotifications"} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 index 7c37a8cc98da..f6d3c895de4e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 @@ -19,7 +19,7 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { "mdo_safeattachmentpolicy" ADDEDCOMPONENT {"type":"select","multiple":false,"label":"Safe Attachment Action","name":"standards.SafeAttachmentPolicy.SafeAttachmentAction","options":[{"label":"Allow","value":"Allow"},{"label":"Block","value":"Block"},{"label":"DynamicDelivery","value":"DynamicDelivery"}]} - {"type":"select","multiple":false,"label":"QuarantineTag","name":"standards.SafeAttachmentPolicy.QuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"select","multiple":false,"creatable":true,"label":"QuarantineTag","name":"standards.SafeAttachmentPolicy.QuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"switch","label":"Redirect","name":"standards.SafeAttachmentPolicy.Redirect"} {"type":"textField","name":"standards.SafeAttachmentPolicy.RedirectAddress","label":"Redirect Address","required":false} IMPACT diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 index c21bf3472820..e20f3d2d2469 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 @@ -16,14 +16,14 @@ function Invoke-CIPPStandardSpamFilterPolicy { ADDEDCOMPONENT {"type":"number","label":"Bulk email threshold (Default 7)","name":"standards.SpamFilterPolicy.BulkThreshold","defaultValue":7} {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"Spam Action","name":"standards.SpamFilterPolicy.SpamAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} - {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"Spam Quarantine Tag","name":"standards.SpamFilterPolicy.SpamQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","required":true,"multiple":false,"creatable":true,"label":"Spam Quarantine Tag","name":"standards.SpamFilterPolicy.SpamQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"High Confidence Spam Action","name":"standards.SpamFilterPolicy.HighConfidenceSpamAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} - {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"High Confidence Spam Quarantine Tag","name":"standards.SpamFilterPolicy.HighConfidenceSpamQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","required":true,"multiple":false,"creatable":true,"label":"High Confidence Spam Quarantine Tag","name":"standards.SpamFilterPolicy.HighConfidenceSpamQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"Bulk Spam Action","name":"standards.SpamFilterPolicy.BulkSpamAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} - {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"Bulk Quarantine Tag","name":"standards.SpamFilterPolicy.BulkQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","required":true,"multiple":false,"creatable":true,"label":"Bulk Quarantine Tag","name":"standards.SpamFilterPolicy.BulkQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"Phish Spam Action","name":"standards.SpamFilterPolicy.PhishSpamAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} - {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"Phish Quarantine Tag","name":"standards.SpamFilterPolicy.PhishQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} - {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"label":"High Confidence Phish Quarantine Tag","name":"standards.SpamFilterPolicy.HighConfidencePhishQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","required":true,"multiple":false,"creatable":true,"label":"Phish Quarantine Tag","name":"standards.SpamFilterPolicy.PhishQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","required":true,"multiple":false,"creatable":true,"label":"High Confidence Phish Quarantine Tag","name":"standards.SpamFilterPolicy.HighConfidencePhishQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"switch","name":"standards.SpamFilterPolicy.IncreaseScoreWithImageLinks","label":"Increase score if message contains image links to remote websites","defaultValue":false} {"type":"switch","name":"standards.SpamFilterPolicy.IncreaseScoreWithBizOrInfoUrls","label":"Increase score if message contains links to .biz or .info domains","defaultValue":false} {"type":"switch","name":"standards.SpamFilterPolicy.MarkAsSpamFramesInHtml","label":"Mark as spam if message contains HTML or iframe tags","defaultValue":false} From 58be7eafe5848e3dc14aab4bdcf8fd77a5d17e8b Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Fri, 16 May 2025 21:54:12 +0100 Subject: [PATCH 048/149] Enhance Set-CIPPCalendarPermission to include CanViewPrivateItems parameter for improved calendar access control --- .../Invoke-ExecEditCalendarPermissions.ps1 | 3 ++- Modules/CIPPCore/Public/Set-CIPPCalendarPermission.ps1 | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEditCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEditCalendarPermissions.ps1 index 3c7f89d02c4a..279374c781c1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEditCalendarPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEditCalendarPermissions.ps1 @@ -21,12 +21,13 @@ function Invoke-ExecEditCalendarPermissions { $Permissions = $Request.Query.Permissions ?? $Request.Body.Permissions.value $FolderName = $Request.Query.FolderName ?? $Request.Body.FolderName $RemoveAccess = $Request.Query.RemoveAccess ?? $Request.Body.RemoveAccess.value + $CanViewPrivateItems = $Request.Query.CanViewPrivateItems ?? $Request.Body.CanViewPrivateItems try { if ($RemoveAccess) { $Result = Set-CIPPCalendarPermission -Headers $Headers -UserID $UserID -FolderName $FolderName -RemoveAccess $RemoveAccess -TenantFilter $TenantFilter } else { - $Result = Set-CIPPCalendarPermission -Headers $Headers -UserID $UserID -FolderName $FolderName -TenantFilter $TenantFilter -UserToGetPermissions $UserToGetPermissions -Permissions $Permissions + $Result = Set-CIPPCalendarPermission -Headers $Headers -UserID $UserID -FolderName $FolderName -TenantFilter $TenantFilter -UserToGetPermissions $UserToGetPermissions -Permissions $Permissions -CanViewPrivateItems $CanViewPrivateItems } $StatusCode = [HttpStatusCode]::OK } catch { diff --git a/Modules/CIPPCore/Public/Set-CIPPCalendarPermission.ps1 b/Modules/CIPPCore/Public/Set-CIPPCalendarPermission.ps1 index afd96d259b08..72abad183130 100644 --- a/Modules/CIPPCore/Public/Set-CIPPCalendarPermission.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPCalendarPermission.ps1 @@ -9,7 +9,8 @@ function Set-CIPPCalendarPermission { $folderName, $UserToGetPermissions, $LoggingName, - $Permissions + $Permissions, + [bool]$CanViewPrivateItems ) try { @@ -26,6 +27,10 @@ function Set-CIPPCalendarPermission { AccessRights = @($Permissions) User = $UserToGetPermissions } + + if ($CanViewPrivateItems) { + $CalParam | Add-Member -NotePropertyName 'SharingPermissionFlags' -NotePropertyValue 'Delegate,CanViewPrivateItems' + } if ($RemoveAccess) { if ($PSCmdlet.ShouldProcess("$UserID\$folderName", "Remove permissions for $LoggingName")) { @@ -42,6 +47,9 @@ function Set-CIPPCalendarPermission { } Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Successfully set Calendar permissions $Permissions for $LoggingName on $UserID." -sev Info $Result = "Successfully set permissions on folder $($CalParam.Identity). The user $LoggingName now has $Permissions permissions on this folder." + if ($CanViewPrivateItems) { + $Result += " The user can also view private items." + } } } } catch { From 06951798058f2afaf5df6f4ae27085d76f2e09e4 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Sat, 17 May 2025 12:58:35 +0200 Subject: [PATCH 049/149] new sam wizard steps --- .../CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 | 102 ++++++++++++++++++ .../CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 2 + 2 files changed, 104 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 new file mode 100644 index 000000000000..2b9c63ce352b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 @@ -0,0 +1,102 @@ +using namespace System.Net + +Function Invoke-ExecCreateSAMApp { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.AppSettings.ReadWrite. + #> + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $KV = $env:WEBSITE_DEPLOYMENT_ID + + try { + $Token = $Request.body + if ($Token) { + $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 + $TenantId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/organization' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method GET -ContentType 'application/json').value.id + #Find Existing app registration + $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method GET -ContentType 'application/json' -Body "{ `"filter`": `"displayName eq 'CIPP-SAM'`" }").value | Select-Object -Last 1 + #Check if the appId has the redirect URI, if not, add it. + if ($AppId) { + Write-Host "Found existing app: $($AppId.id). Reusing." + $state = 'updated' + if ($AppId.web.redirectUris -notcontains $URL) { + $ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase + $SamManifestFile = Get-Item (Join-Path $ModuleBase 'Public\SAMManifest.json') + $app = Get-Content $SamManifestFile.FullName | ConvertFrom-Json + $App.web.redirectUris = @($App.web.redirectUris + $URL) #change to SPA URL. + $app = $app | ConvertTo-Json -Depth 15 + Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppId.id)" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method PATCH -Body $app -ContentType 'application/json' + } + } else { + $state = 'created' + $ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase + $SamManifestFile = Get-Item (Join-Path $ModuleBase 'Public\SAMManifest.json') + $app = Get-Content $SamManifestFile.FullName | ConvertFrom-Json + $App.web.redirectUris = @($App.web.redirectUris + $URL) #change to SPA URL. + $app = $app | ConvertTo-Json -Depth 15 + $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body $app -ContentType 'application/json') + $attempt = 0 + do { + try { + try { + $SPNDefender = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"fc780465-2017-40d4-a0c5-307022471b92`" }" -ContentType 'application/json') + } catch { + Write-Information "didn't deploy spn for defender, probably already there." + } + try { + $SPNTeams = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"48ac35b8-9aa8-4d74-927d-1f4a14a0b239`" }" -ContentType 'application/json') + } catch { + Write-Information "didn't deploy spn for Teams, probably already there." + } + try { + $SPNO365Manage = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"c5393580-f805-4401-95e8-94b7a6ef2fc2`" }" -ContentType 'application/json') + } catch { + Write-Information "didn't deploy spn for O365 Management, probably already there." + } + try { + $SPNPartnerCenter = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd`" }" -ContentType 'application/json') + } catch { + Write-Information "didn't deploy spn for PartnerCenter, probably already there." + } + $SPN = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"$($AppId.appId)`" }" -ContentType 'application/json') + Start-Sleep 2 + $attempt ++ + } catch { + $attempt ++ + } + } until ($attempt -gt 3) + } + $AppPassword = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppId.id)/addPassword" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body '{"passwordCredential":{"displayName":"CIPPInstall"}}' -ContentType 'application/json').secretText + + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" + $Secret.TenantId = $TenantId + $Secret.ApplicationId = $AppId.appId + $Secret.ApplicationSecret = $AppPassword + Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force + Write-Information ($Secret | ConvertTo-Json -Depth 5) + } else { + Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $TenantId -AsPlainText -Force) + Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appId -AsPlainText -Force) + Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $AppPassword -AsPlainText -Force) + } + $Results = @{'message' = "Succesfully $state the application registration. The application ID is $($AppId.id). You may continue to the next step."; severity = 'success' } + } + + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)"; severity = 'failed' } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 index c9ec1f5bec39..d921f78911e0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 @@ -6,6 +6,8 @@ Function Invoke-ExecSAMSetup { Entrypoint,AnyTenant .ROLE CIPP.AppSettings.ReadWrite + .LEGACY + This function is a legacy function that was used to set up the CIPP application in Azure AD. It is not used in the current version of CIPP, look at Invoke-ExecCreateSAMApp for the new version. #> [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] [CmdletBinding()] From c7de828236250b056d27c7314330ad0a53190662 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Sun, 18 May 2025 01:11:49 +0200 Subject: [PATCH 050/149] updates to new sam wizard --- .../CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 | 27 +++--- .../CIPP/Setup/Invoke-ExecTokenExchange.ps1 | 90 +++++++++++++++++++ .../Setup/Invoke-ExecUpdateRefreshToken.ps1 | 49 ++++++++++ .../Entrypoints/Invoke-ExecListAppId.ps1 | 11 ++- .../Public/Get-CIPPAuthentication.ps1 | 1 + 5 files changed, 163 insertions(+), 15 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 index 2b9c63ce352b..8a4d5c523898 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 @@ -16,7 +16,7 @@ Function Invoke-ExecCreateSAMApp { try { $Token = $Request.body if ($Token) { - $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 + $URL = ($Request.headers.'x-ms-original-url').split('/api') | Select-Object -First 1 $TenantId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/organization' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method GET -ContentType 'application/json').value.id #Find Existing app registration $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method GET -ContentType 'application/json' -Body "{ `"filter`": `"displayName eq 'CIPP-SAM'`" }").value | Select-Object -Last 1 @@ -24,20 +24,19 @@ Function Invoke-ExecCreateSAMApp { if ($AppId) { Write-Host "Found existing app: $($AppId.id). Reusing." $state = 'updated' - if ($AppId.web.redirectUris -notcontains $URL) { - $ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase - $SamManifestFile = Get-Item (Join-Path $ModuleBase 'Public\SAMManifest.json') - $app = Get-Content $SamManifestFile.FullName | ConvertFrom-Json - $App.web.redirectUris = @($App.web.redirectUris + $URL) #change to SPA URL. - $app = $app | ConvertTo-Json -Depth 15 - Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppId.id)" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method PATCH -Body $app -ContentType 'application/json' - } + #remove the entire web object from the app registration + $ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase + $SamManifestFile = Get-Item (Join-Path $ModuleBase 'Public\SAMManifest.json') + $app = Get-Content $SamManifestFile.FullName | ConvertFrom-Json + $app.web.redirectUris = @("$($url)/authredirect") + $app = ConvertTo-Json -Depth 15 -Compress -InputObject $app + Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppId.id)" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method PATCH -Body $app -ContentType 'application/json' } else { $state = 'created' $ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase $SamManifestFile = Get-Item (Join-Path $ModuleBase 'Public\SAMManifest.json') $app = Get-Content $SamManifestFile.FullName | ConvertFrom-Json - $App.web.redirectUris = @($App.web.redirectUris + $URL) #change to SPA URL. + $app.web.redirectUris = @("$($url)/authredirect") $app = $app | ConvertTo-Json -Depth 15 $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body $app -ContentType 'application/json') $attempt = 0 @@ -76,9 +75,9 @@ Function Invoke-ExecCreateSAMApp { if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" - $Secret.TenantId = $TenantId - $Secret.ApplicationId = $AppId.appId - $Secret.ApplicationSecret = $AppPassword + $Secret | Add-Member -MemberType NoteProperty -Name 'tenantid' -Value $TenantId -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'applicationid' -Value $AppId.appId -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'applicationsecret' -Value $AppPassword -Force Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force Write-Information ($Secret | ConvertTo-Json -Depth 5) } else { @@ -86,7 +85,7 @@ Function Invoke-ExecCreateSAMApp { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appId -AsPlainText -Force) Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $AppPassword -AsPlainText -Force) } - $Results = @{'message' = "Succesfully $state the application registration. The application ID is $($AppId.id). You may continue to the next step."; severity = 'success' } + $Results = @{'message' = "Succesfully $state the application registration. The application ID is $($AppId.appid). You may continue to the next step."; severity = 'success' } } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 new file mode 100644 index 000000000000..184f8c12bbad --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 @@ -0,0 +1,90 @@ +using namespace System.Net + +Function Invoke-ExecTokenExchange { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.AppSettings.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + # Get the key vault name + $KV = $env:WEBSITE_DEPLOYMENT_ID + $APIName = $Request.Params.CIPPEndpoint + + try { + if (!$Request.Body) { + Write-LogMessage -API $APIName -message 'Request body is missing' -Sev 'Error' + throw 'Request body is missing' + } + + $TokenRequest = $Request.Body.tokenRequest + $TokenUrl = $Request.Body.tokenUrl + $TenantId = $Request.Body.tenantId + + if (!$TokenRequest -or !$TokenUrl) { + Write-LogMessage -API $APIName -message 'Missing required parameters: tokenRequest or tokenUrl' -Sev 'Error' + throw 'Missing required parameters: tokenRequest or tokenUrl' + } + + Write-LogMessage -API $APIName -message "Making token request to $TokenUrl" -Sev 'Info' + + # Make sure we get the latest authentication + $auth = Get-CIPPAuthentication + + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" + $ClientSecret = $Secret.applicationsecret + Write-LogMessage -API $APIName -message 'Retrieved client secret from development secrets' -Sev 'Info' + } else { + try { + $ClientSecret = (Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText).SecretValue + Write-LogMessage -API $APIName -message 'Retrieved client secret from key vault' -Sev 'Info' + } catch { + Write-LogMessage -API $APIName -message "Failed to retrieve client secret: $($_.Exception.Message)" -Sev 'Error' + throw "Failed to retrieve client secret: $($_.Exception.Message)" + } + } + + if (!$ClientSecret) { + Write-LogMessage -API $APIName -message 'Client secret is empty or null' -Sev 'Error' + throw 'Client secret is empty or null' + } + + # Convert token request to form data and add client secret + $FormData = @{} + foreach ($key in $TokenRequest.PSObject.Properties.Name) { + $FormData[$key] = $TokenRequest.$key + } + + # Add client_secret to the form data if not already present + if (!$FormData.ContainsKey('client_secret')) { + $FormData['client_secret'] = $ClientSecret + } + + Write-Host "Posting this data: $($FormData | ConvertTo-Json -Depth 15)" + $Results = Invoke-RestMethod -Uri $TokenUrl -Method Post -Body $FormData -ContentType 'application/x-www-form-urlencoded' -ErrorAction Stop -SkipHttpErrorCheck + } catch { + $ErrorMessage = $_.Exception + $Results = @{ + error = 'server_error' + error_description = "Token exchange failed: $ErrorMessage" + } + } + if ($Results.error) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = $Results + Headers = @{'Content-Type' = 'application/json' } + }) + } else { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + Headers = @{'Content-Type' = 'application/json' } + }) + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 new file mode 100644 index 000000000000..aed9b85e95fe --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -0,0 +1,49 @@ +using namespace System.Net + +Function Invoke-ExecUpdateRefreshToken { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.AppSettings.ReadWrite. + #> + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $KV = $env:WEBSITE_DEPLOYMENT_ID + + try { + # Handle refresh token update + #make sure we get the latest authentication: + $auth = Get-CIPPAuthentication + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" + if ($env:ApplicationId -eq $Request.body.tenantId) { + $Secret.RefreshToken = $Request.body.RefreshToken + } else { + Write-Host "$($env:Applicationid) does not match $($Request.body.tenantId)" + $secret | Add-Member -MemberType NoteProperty -Name $($Request.body.tenantId) -Value $Request.body.refreshtoken -Force + } + Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force + } else { + if ($env:ApplicationId -eq $Request.body.tenantId) { + Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) + } else { + Set-AzKeyVaultSecret -VaultName $kv -Name $Request.body.tenantId -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) + } + } + $InstanceId = Start-UpdatePermissionsOrchestrator #start the CPV refresh immediately while wizard still runs. + $Results = @{'message' = "Successfully updated your stored authentication for $($request.body.tenantId)."; severity = 'success' } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)"; severity = 'failed' } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index 579a6f8f16fe..1355939a6b3c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -14,7 +14,16 @@ Function Invoke-ExecListAppId { $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $ResponseURL = "$(($Request.headers.'x-ms-original-url').replace('/api/ExecListAppId','/api/ExecSAMSetup'))" - + #make sure we get the very latest version of the appid from kv: + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" + $env:ApplicationID = $Secret.ApplicationID + $env:TenantID = $Secret.TenantID + } else { + $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $env:WEBSITE_DEPLOYMENT_ID -Name 'ApplicationID').SecretValueText + $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $env:WEBSITE_DEPLOYMENT_ID -Name 'TenantID').SecretValueText + } $Results = @{ applicationId = $env:ApplicationID tenantId = $env:TenantID diff --git a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 index ce8a064639dc..07f6b976aa4f 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 @@ -18,6 +18,7 @@ function Get-CIPPAuthentication { Set-Item -Path env:$Var -Value $Secret.$Var -Force -ErrorAction Stop } } + Write-Host "Got secrets from dev storage. ApplicationID: $env:ApplicationID" } else { Write-Information 'Connecting to Azure' Connect-AzAccount -Identity From 875df46defd8f723efecb32f8f672149e9d19c87 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Sun, 18 May 2025 23:22:29 +0200 Subject: [PATCH 051/149] New APIs for single tenant mode --- .../CIPP/Setup/Invoke-ExecAddTenant.ps1 | 89 +++++++++++++++++++ .../Setup/Invoke-ExecUpdateRefreshToken.ps1 | 15 +++- .../Public/GraphHelper/Get-GraphToken.ps1 | 1 + 3 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 new file mode 100644 index 000000000000..cdd57390d607 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 @@ -0,0 +1,89 @@ +using namespace System.Net + +Function Invoke-ExecAddTenant { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.AppSettings.ReadWrite. + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + try { + # Get the tenant ID from the request body + $tenantId = $Request.body.tenantId + $displayName = $Request.body.displayName + $defaultDomainName = $Request.body.defaultDomainName + + # Get the Tenants table + $TenantsTable = Get-CippTable -tablename 'Tenants' + + # Check if tenant already exists + $ExistingTenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter "PartitionKey eq 'Tenants' and RowKey eq '$tenantId'" + + if ($ExistingTenant) { + # Update existing tenant + $ExistingTenant.delegatedPrivilegeStatus = 'directTenant' + Add-CIPPAzDataTableEntity @TenantsTable -Entity $ExistingTenant -Force | Out-Null + $Results = @{'message' = 'Successfully updated tenant.'; 'severity' = 'success' } + } else { + # Create new tenant entry + try { + # Get organization info + $Organization = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/organization' -tenantid $tenantId -NoAuthCheck:$true -ErrorAction Stop + + if (-not $displayName) { + $displayName = $Organization[0].displayName + } + + if (-not $defaultDomainName) { + # Try to get domains + try { + $Domains = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantId -NoAuthCheck:$true -ErrorAction Stop + $defaultDomainName = ($Domains | Where-Object { $_.isDefault -eq $true }).id + $initialDomainName = ($Domains | Where-Object { $_.isInitial -eq $true }).id + } catch { + # If we can't get domains, use verified domains from organization + $defaultDomainName = ($Organization[0].verifiedDomains | Where-Object { $_.isDefault -eq $true }).name + $initialDomainName = ($Organization[0].verifiedDomains | Where-Object { $_.isInitial -eq $true }).name + } + } + } catch { + Write-LogMessage -API 'Add-Tenant' -message "Failed to get information for tenant $tenantId - $($_.Exception.Message)" -Sev 'Critical' + throw "Failed to get information for tenant $tenantId. Make sure the tenant is properly authenticated." + } + + # Create new tenant object + $NewTenant = [PSCustomObject]@{ + PartitionKey = 'Tenants' + RowKey = $tenantId + customerId = $tenantId + displayName = $displayName + defaultDomainName = $defaultDomainName + initialDomainName = $initialDomainName + delegatedPrivilegeStatus = 'directTenant' + domains = '' + Excluded = $false + ExcludeUser = '' + ExcludeDate = '' + GraphErrorCount = 0 + LastGraphError = '' + RequiresRefresh = $false + LastRefresh = (Get-Date).ToUniversalTime() + } + + # Add tenant to table + Add-CIPPAzDataTableEntity @TenantsTable -Entity $NewTenant -Force | Out-Null + $Results = @{'message' = "Successfully added tenant $tenantId to the tenant list with directTenant status."; 'severity' = 'success' } + } + } catch { + $Results = @{'message' = "Failed to add tenant: $($_.Exception.Message)"; 'state' = 'error'; 'severity' = 'error' } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 index aed9b85e95fe..db670c3a693a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -24,18 +24,27 @@ Function Invoke-ExecUpdateRefreshToken { $Secret.RefreshToken = $Request.body.RefreshToken } else { Write-Host "$($env:Applicationid) does not match $($Request.body.tenantId)" - $secret | Add-Member -MemberType NoteProperty -Name $($Request.body.tenantId) -Value $Request.body.refreshtoken -Force + $name = $Request.body.tenantId -replace '-', '_' + $secret | Add-Member -MemberType NoteProperty -Name $name -Value $Request.body.refreshtoken -Force } Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force } else { if ($env:ApplicationId -eq $Request.body.tenantId) { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) } else { - Set-AzKeyVaultSecret -VaultName $kv -Name $Request.body.tenantId -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) + $name = $Request.body.tenantId -replace '-', '_' + Set-AzKeyVaultSecret -VaultName $kv -Name $name -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) } } $InstanceId = Start-UpdatePermissionsOrchestrator #start the CPV refresh immediately while wizard still runs. - $Results = @{'message' = "Successfully updated your stored authentication for $($request.body.tenantId)."; severity = 'success' } + + + $Results = @{ + 'message' = "Successfully updated your stored authentication for $($request.body.tenantId)." + 'severity' = 'success' + 'state' = 'success' + 'tenantId' = $Request.body.tenantId + } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)"; severity = 'failed' } } diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index 49e9f7de1b37..1f907ec6d89c 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -5,6 +5,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT #> if (!$scope) { $scope = 'https://graph.microsoft.com/.default' } if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } + #If the $env:<$tenantid> is set, use that instead of the refreshtoken for all tenants. $AuthBody = @{ client_id = $env:ApplicationID client_secret = $env:ApplicationSecret From 3822556cb91dd0da3063229d6493ea312a8c0019 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 19 May 2025 10:35:15 +0200 Subject: [PATCH 052/149] direct tenant add --- .../Public/Get-CIPPAuthentication.ps1 | 25 +++++++++++++++++++ .../Public/GraphHelper/Get-GraphToken.ps1 | 11 ++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 index 07f6b976aa4f..70977926a0d0 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 @@ -19,6 +19,18 @@ function Get-CIPPAuthentication { } } Write-Host "Got secrets from dev storage. ApplicationID: $env:ApplicationID" + #Get list of tenants that have 'directTenant' set to true + $tenants = Get-Tenants | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' + if ($tenants) { + Write-Host "Found $($tenants.Count) tenants with directTenant set to true" + $tenants | ForEach-Object { + $name = $_.customerId -replace '-', '_' + if ($secret.$name) { + $name = $_.customerId + Set-Item -Path env:$name -Value $secret.$name -Force + } + } + } } else { Write-Information 'Connecting to Azure' Connect-AzAccount -Identity @@ -37,6 +49,19 @@ function Get-CIPPAuthentication { } $keyvaultname = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] + #Get list of tenants that have 'directTenant' set to true + $tenants = Get-Tenants | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' + if ($tenants) { + $tenants | ForEach-Object { + $name = $_.tenantId -replace '-', '_' + $secret = Get-AzKeyVaultSecret -VaultName $keyvaultname -Name $name -AsPlainText -ErrorAction Stop + if ($secret) { + #set the name back to the original tenantId + $name = $_.customerId + Set-Item -Path env:$name -Value $secret -Force + } + } + } $Variables | ForEach-Object { Set-Item -Path env:$_ -Value (Get-AzKeyVaultSecret -VaultName $keyvaultname -Name $_ -AsPlainText -ErrorAction Stop) -Force } diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index 1f907ec6d89c..76ada322f53a 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -6,11 +6,18 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT if (!$scope) { $scope = 'https://graph.microsoft.com/.default' } if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } #If the $env:<$tenantid> is set, use that instead of the refreshtoken for all tenants. + $ClientRefreshToken = Get-Item env:$tenantid -ErrorAction SilentlyContinue + if ($ClientRefreshToken) { + $refreshToken = $ClientRefreshToken + } else { + $refreshToken = $env:RefreshToken + } + $AuthBody = @{ client_id = $env:ApplicationID client_secret = $env:ApplicationSecret scope = $Scope - refresh_token = $env:RefreshToken + refresh_token = $refreshToken grant_type = 'refresh_token' } if ($asApp -eq $true) { @@ -25,7 +32,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT if ($null -ne $AppID -and $null -ne $refreshToken) { $AuthBody = @{ client_id = $appid - refresh_token = $RefreshToken + refresh_token = $refreshToken scope = $Scope grant_type = 'refresh_token' } From 1947b316fc45d4feb776839e5f364ec7b922f403 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 19 May 2025 10:59:57 +0200 Subject: [PATCH 053/149] changes --- .../CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 index db670c3a693a..e0cb22ec44c0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -40,9 +40,7 @@ Function Invoke-ExecUpdateRefreshToken { $Results = @{ - 'message' = "Successfully updated your stored authentication for $($request.body.tenantId)." - 'severity' = 'success' - 'state' = 'success' + 'message' = "Successfully updated your stored authentication for $($request.body.tenantId)." 'tenantId' = $Request.body.tenantId } } catch { From e05affbe39b9fd52342d83417db3cc75bbc36416 Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 19 May 2025 17:45:16 +0800 Subject: [PATCH 054/149] Return sorted tenant groups --- .../HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 index 790ccae6ff2c..d06567c53a2d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 @@ -12,7 +12,8 @@ function Invoke-ListTenantGroups { $groupFilter = $Request.Query.groupId ?? $Request.Body.groupId $TenantGroups = (Get-TenantGroups -GroupId $groupFilter) ?? @() - $Body = @{ Results = @($TenantGroups) } + $SortedTenantGroups = $TenantGroups | Sort-Object Name + $Body = @{ Results = @($SortedTenantGroups) } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK From 4b5b11b8763dbd43a3a604535859798da264461b Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 19 May 2025 17:56:54 +0800 Subject: [PATCH 055/149] Sort both tenant groups and tenants in a group --- .../CIPP/Settings/Invoke-ListTenantGroups.ps1 | 3 +-- .../CIPPCore/Public/Functions/Get-TenantGroups.ps1 | 11 ++++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 index d06567c53a2d..790ccae6ff2c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListTenantGroups.ps1 @@ -12,8 +12,7 @@ function Invoke-ListTenantGroups { $groupFilter = $Request.Query.groupId ?? $Request.Body.groupId $TenantGroups = (Get-TenantGroups -GroupId $groupFilter) ?? @() - $SortedTenantGroups = $TenantGroups | Sort-Object Name - $Body = @{ Results = @($SortedTenantGroups) } + $Body = @{ Results = @($TenantGroups) } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 b/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 index 4006228d24ca..b5059d95eaf1 100644 --- a/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 +++ b/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 @@ -43,18 +43,21 @@ function Get-TenantGroups { } if ($TenantFilter -and $TenantFilter -ne 'allTenants') { + $Results = @() $Memberships = $AllMembers | Where-Object { $_.customerId -eq $Tenants.customerId } foreach ($Group in $Memberships) { $Group = $Groups | Where-Object { $_.RowKey -eq $Group.GroupId } if ($Group) { - [PSCustomObject]@{ + $Results += [PSCustomObject]@{ Id = $Group.RowKey Name = $Group.Name Description = $Group.Description } } } + return $Results | Sort-Object Name } else { + $Results = @() $Groups | ForEach-Object { $Group = $_ $Members = $AllMembers | Where-Object { $_.GroupId -eq $Group.RowKey } @@ -75,14 +78,16 @@ function Get-TenantGroups { } if (!$Members) { $Members = @() + } else { + $Members = $Members | Sort-Object displayName } - - [PSCustomObject]@{ + $Results += [PSCustomObject]@{ Id = $Group.RowKey Name = $Group.Name Description = $Group.Description Members = @($Members) } } + return $Results | Sort-Object Name } } From 49548069979d6eb045dd426e5bc2a8a68251285d Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 19 May 2025 18:29:17 +0800 Subject: [PATCH 056/149] brrrrr --- .../Public/Functions/Get-TenantGroups.ps1 | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 b/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 index b5059d95eaf1..39a0d53e9383 100644 --- a/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 +++ b/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 @@ -43,50 +43,45 @@ function Get-TenantGroups { } if ($TenantFilter -and $TenantFilter -ne 'allTenants') { - $Results = @() + $Results = New-Object System.Collections.ArrayList $Memberships = $AllMembers | Where-Object { $_.customerId -eq $Tenants.customerId } foreach ($Group in $Memberships) { $Group = $Groups | Where-Object { $_.RowKey -eq $Group.GroupId } if ($Group) { - $Results += [PSCustomObject]@{ + $null = $Results.Add([PSCustomObject]@{ Id = $Group.RowKey Name = $Group.Name Description = $Group.Description - } + }) } } return $Results | Sort-Object Name } else { - $Results = @() - $Groups | ForEach-Object { - $Group = $_ + $Results = New-Object System.Collections.ArrayList + foreach ($Group in $Groups) { $Members = $AllMembers | Where-Object { $_.GroupId -eq $Group.RowKey } - if (!$Members) { - $Members = @() - } - - $Members = $Members | ForEach-Object { - $Member = $_ - $Tenant = $Tenants | Where-Object { $Member.customerId -eq $_.customerId } - if ($Tenant) { - @{ - customerId = $Tenant.customerId - displayName = $Tenant.displayName - defaultDomainName = $Tenant.defaultDomainName + $MembersList = New-Object System.Collections.ArrayList + if ($Members) { + foreach ($Member in $Members) { + $Tenant = $Tenants | Where-Object { $Member.customerId -eq $_.customerId } + if ($Tenant) { + $null = $MembersList.Add(@{ + customerId = $Tenant.customerId + displayName = $Tenant.displayName + defaultDomainName = $Tenant.defaultDomainName + }) } } - } - if (!$Members) { - $Members = @() + $SortedMembers = $MembersList | Sort-Object displayName } else { - $Members = $Members | Sort-Object displayName + $SortedMembers = @() } - $Results += [PSCustomObject]@{ + $null = $Results.Add([PSCustomObject]@{ Id = $Group.RowKey Name = $Group.Name Description = $Group.Description - Members = @($Members) - } + Members = @($SortedMembers) + }) } return $Results | Sort-Object Name } From fef71a18b0343dffa4cf07e3b710e3017b9d2a18 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 19 May 2025 17:38:03 +0200 Subject: [PATCH 057/149] version update --- .../CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 | 16 ++++++++++------ .../CIPPCore/Public/Get-CIPPAuthentication.ps1 | 12 +++++++----- .../Public/GraphHelper/Get-AuthorisedRequest.ps1 | 2 +- .../Public/GraphHelper/Get-GraphToken.ps1 | 10 +++++----- profile.ps1 | 2 +- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 index e0cb22ec44c0..1e83d9d5db0d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -20,10 +20,10 @@ Function Invoke-ExecUpdateRefreshToken { if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" - if ($env:ApplicationId -eq $Request.body.tenantId) { + if ($env:TenantID -eq $Request.body.tenantId) { $Secret.RefreshToken = $Request.body.RefreshToken } else { - Write-Host "$($env:Applicationid) does not match $($Request.body.tenantId)" + Write-Host "$($env:TenantID) does not match $($Request.body.tenantId)" $name = $Request.body.tenantId -replace '-', '_' $secret | Add-Member -MemberType NoteProperty -Name $name -Value $Request.body.refreshtoken -Force } @@ -38,13 +38,17 @@ Function Invoke-ExecUpdateRefreshToken { } $InstanceId = Start-UpdatePermissionsOrchestrator #start the CPV refresh immediately while wizard still runs. - + if ($request.body.tenantId -eq $env:TenantID) { + $TenantName = 'your partner tenant' + } else { + $TenantName = $request.body.tenantId + } $Results = @{ - 'message' = "Successfully updated your stored authentication for $($request.body.tenantId)." - 'tenantId' = $Request.body.tenantId + 'message' = "Successfully updated the credentials for $($TenantName). You may continue to the next step, or add additional tenants if required." + 'severity' = 'success' } } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)"; severity = 'failed' } + $Results = [pscustomobject]@{'Results' = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)"; severity = 'failed' } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 index 70977926a0d0..3ed6a0f79a01 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 @@ -20,14 +20,16 @@ function Get-CIPPAuthentication { } Write-Host "Got secrets from dev storage. ApplicationID: $env:ApplicationID" #Get list of tenants that have 'directTenant' set to true - $tenants = Get-Tenants | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' + $tenants = Get-Tenants -IncludeErrors | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' if ($tenants) { Write-Host "Found $($tenants.Count) tenants with directTenant set to true" $tenants | ForEach-Object { - $name = $_.customerId -replace '-', '_' - if ($secret.$name) { + $secretname = $_.customerId -replace '-', '_' + if ($secret.$secretname) { $name = $_.customerId - Set-Item -Path env:$name -Value $secret.$name -Force + Write-Host "Setting $name to $($secret.$secretname)" + + Set-Item -Path env:$name -Value $secret.$secretname -Force } } } @@ -50,7 +52,7 @@ function Get-CIPPAuthentication { $keyvaultname = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] #Get list of tenants that have 'directTenant' set to true - $tenants = Get-Tenants | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' + $tenants = Get-Tenants -IncludeErrors | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' if ($tenants) { $tenants | ForEach-Object { $name = $_.tenantId -replace '-', '_' diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 index 15ae8b23dc70..7cdc576078d0 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 @@ -16,7 +16,7 @@ function Get-AuthorisedRequest { if ($Uri -like 'https://graph.microsoft.com/beta/contracts*' -or $Uri -like '*/customers/*' -or $Uri -eq 'https://graph.microsoft.com/v1.0/me/sendMail' -or $Uri -like '*/tenantRelationships/*' -or $Uri -like '*/security/partner/*') { return $true } - $Tenant = Get-Tenants -TenantFilter $TenantID | Where-Object { $_.Excluded -eq $false } + $Tenant = Get-Tenants -IncludeErrors -TenantFilter $TenantID | Where-Object { $_.Excluded -eq $false } if ($Tenant) { return $true diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index 76ada322f53a..9ac15c0413ea 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -6,11 +6,11 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT if (!$scope) { $scope = 'https://graph.microsoft.com/.default' } if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } #If the $env:<$tenantid> is set, use that instead of the refreshtoken for all tenants. - $ClientRefreshToken = Get-Item env:$tenantid -ErrorAction SilentlyContinue - if ($ClientRefreshToken) { - $refreshToken = $ClientRefreshToken - } else { - $refreshToken = $env:RefreshToken + $refreshToken = $env:Refreshtoken + $ClientType = Get-Tenants -IncludeErrors -TenantFilter $tenantid + if ($clientType.delegatedPrivilegeStatus -eq 'directTenant') { + $ClientRefreshToken = Get-Item -Path "env:\$($clientType.customerId)" -ErrorAction SilentlyContinue + $refreshToken = $ClientRefreshToken.Value } $AuthBody = @{ diff --git a/profile.ps1 b/profile.ps1 index 9fa3401f75db..cfcf29575171 100644 --- a/profile.ps1 +++ b/profile.ps1 @@ -62,7 +62,7 @@ if (!$LastStartup -or $CurrentVersion -ne $LastStartup.Version) { Version = $CurrentVersion } } - Update-AzDataTableEntity @Table -Entity $LastStartup -Force + Update-AzDataTableEntity @Table -Entity $LastStartup -Force -ErrorAction SilentlyContinue try { Clear-CippDurables } catch { From 1b4a7a63d5258e376053da496c22ae4d9c6392b0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 19 May 2025 12:48:25 -0400 Subject: [PATCH 058/149] Entra Group Auth --- .../Authentication/Get-CIPPAccessRole.ps1 | 22 ++ .../Authentication/Set-CIPPAccessRole.ps1 | 51 ++++ .../Public/Authentication/Test-CIPPAccess.ps1 | 218 ++++++++++++++---- .../Test-CIPPAccessUserRole.ps1 | 66 ++++++ .../CIPP/Settings/Invoke-ExecCustomRole.ps1 | 95 ++++++-- .../CIPP/Settings/Invoke-ListCustomRole.ps1 | 85 ++++--- Modules/CippEntrypoints/CippEntrypoints.psm1 | 13 +- 7 files changed, 464 insertions(+), 86 deletions(-) create mode 100644 Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1 create mode 100644 Modules/CIPPCore/Public/Authentication/Set-CIPPAccessRole.ps1 create mode 100644 Modules/CIPPCore/Public/Authentication/Test-CIPPAccessUserRole.ps1 diff --git a/Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1 new file mode 100644 index 000000000000..88872027bd99 --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1 @@ -0,0 +1,22 @@ +function Get-CIPPAccessRole { + <# + .SYNOPSIS + Get the access role for the current user + + .DESCRIPTION + Get the access role for the current user + + .PARAMETER TenantID + The tenant ID to check the access role for + + .EXAMPLE + Get-CippAccessRole -UserId $UserId + + .FUNCTIONALITY + Internal + #> + [CmdletBinding()] + Param() + + +} diff --git a/Modules/CIPPCore/Public/Authentication/Set-CIPPAccessRole.ps1 b/Modules/CIPPCore/Public/Authentication/Set-CIPPAccessRole.ps1 new file mode 100644 index 000000000000..f74e8a3e9f65 --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/Set-CIPPAccessRole.ps1 @@ -0,0 +1,51 @@ +function Set-CIPPAccessRole { + <# + .SYNOPSIS + Set the access role mappings + + .DESCRIPTION + Set the access role mappings for Entra groups + + .PARAMETER Role + The role to set (e.g. 'superadmin','admin','editor','readonly','customrole') + + .PARAMETER Group + The Entra group to set the role for + + .FUNCTIONALITY + Internal + #> + [CmdletBinding(SupportsShouldProcess = $true)] + Param( + [Parameter(Mandatory = $true)] + [string]$Role, + [Parameter(Mandatory = $true)] + [string]$Group + ) + + $BlacklistedRoles = @('authenticated', 'anonymous') + + if ($BlacklistedRoles -contains $Role) { + throw 'Role group cannot be set for authenticated or anonymous roles' + } + + if (!$Group.id -or !$Group.displayName) { + throw 'Group is not valid' + } + + $Role = $Role.ToLower().Trim() -replace ' ', '' + + $Table = Get-CippTable -TableName AccessRoleGroups + $AccessGroup = Get-CIPPAzDataTableEntity @Table -Filter "RowKey = '$Role'" + + $AccessGroup = [PSCustomObject]@{ + PartitionKey = [string]'AccessRole' + RowKey = [string]$Role + GroupId = [string]$Group.id + GroupName = [string]$Group.displayName + } + + if ($PSCmdlet.ShouldProcess("Setting access role $Role for group $($Group.displayName)")) { + Add-CIPPAzDataTableEntity -Table $Table -Entity $AccessGroup -Force + } +} diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index dea7c6587adf..caf5a4605113 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -7,7 +7,10 @@ function Test-CIPPAccess { # Get function help $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint - $Help = Get-Help $FunctionName + + try { + $Help = Get-Help $FunctionName -ErrorAction Stop + } catch {} # Check help for role $APIRole = $Help.Role @@ -21,7 +24,27 @@ function Test-CIPPAccess { $CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent $BaseRoles = Get-Content -Path $CIPPRoot\Config\cipp-roles.json | ConvertFrom-Json + if ($APIRole -eq 'Public') { + return $true + } + + # Get default roles from config + $CIPPCoreModuleRoot = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase + $CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent + $BaseRoles = Get-Content -Path $CIPPRoot\Config\cipp-roles.json | ConvertFrom-Json + $DefaultRoles = @('superadmin', 'admin', 'editor', 'readonly', 'anonymous', 'authenticated') + + if ($APIRole -eq 'Public') { + return $true + } + + # Get default roles from config + $CIPPCoreModuleRoot = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase + $CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent + $BaseRoles = Get-Content -Path $CIPPRoot\Config\cipp-roles.json | ConvertFrom-Json + if ($Request.Headers.'x-ms-client-principal-idp' -eq 'aad' -and $Request.Headers.'x-ms-client-principal-name' -match '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') { + $Type = 'APIClient' # Direct API Access $ForwardedFor = $Request.Headers.'x-forwarded-for' -split ',' | Select-Object -First 1 $IPRegex = '^(?(?:\d{1,3}(?:\.\d{1,3}){3}|\[[0-9a-fA-F:]+\]|[0-9a-fA-F:]+))(?::\d+)?$' @@ -44,7 +67,20 @@ function Test-CIPPAccess { if ($IPMatched) { if ($Client.Role) { - $CustomRoles = @($Client.Role) + $CustomRoles = $Client.Role | ForEach-Object { + if ($DefaultRoles -notcontains $_) { + $_ + } + } + $BaseRole = $null + foreach ($Role in $BaseRoles.PSObject.Properties) { + foreach ($ClientRole in $Client.Role) { + if ($Role.Name -eq $ClientRole) { + $BaseRole = $Role + break + } + } + } } else { $CustomRoles = @('cipp-api') } @@ -56,18 +92,28 @@ function Test-CIPPAccess { Write-Information "API Access: AppId=$($Request.Headers.'x-ms-client-principal-name'), IP=$IPAddress" } } else { - $DefaultRoles = @('admin', 'editor', 'readonly', 'anonymous', 'authenticated') + $Type = 'User' $User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json - if (!$TenantList.IsPresent -and $APIRole -match 'SuperAdmin' -and $User.userRoles -notcontains 'superadmin') { - throw 'Access to this CIPP API endpoint is not allowed, the user does not have the required permission' + # Check for roles granted via group membership + if (($User.userRoles | Measure-Object).Count -eq 2 -and $User.userRoles -contains 'authenticated' -and $User.userRoles -contains 'anonymous') { + $User = Test-CIPPAccessUserRole -User $User + } + + Write-Information ($User | ConvertTo-Json -Depth 5) + # Return user permissions + if ($Request.Params.CIPPEndpoint -eq 'me') { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = (@{ 'clientPrincipal' = $User } | ConvertTo-Json -Depth 5) + }) + return } if ($User.userRoles -contains 'admin' -or $User.userRoles -contains 'superadmin') { if ($TenantList.IsPresent) { return @('AllTenants') } - return $true } $CustomRoles = $User.userRoles | ForEach-Object { @@ -75,54 +121,134 @@ function Test-CIPPAccess { $_ } } + + $BaseRole = $null + foreach ($Role in $BaseRoles.PSObject.Properties) { + foreach ($UserRole in $User.userRoles) { + if ($Role.Name -eq $UserRole) { + $BaseRole = $Role + break + } + } + } } - if (($CustomRoles | Measure-Object).Count -gt 0) { - $Tenants = Get-Tenants -IncludeErrors - $PermissionsFound = $false - $PermissionSet = foreach ($CustomRole in $CustomRoles) { - try { - Get-CIPPRolePermissions -Role $CustomRole - $PermissionsFound = $true - } catch { - Write-Information $_.Exception.Message - continue + + # Check base role permissions before continuing to custom roles + if ($null -ne $BaseRole) { + Write-Information "Base Role: $($BaseRole.Name)" + $BaseRoleAllowed = $false + foreach ($Include in $BaseRole.Value.include) { + if ($APIRole -like $Include) { + $BaseRoleAllowed = $true + break } } - if ($PermissionsFound) { - if ($TenantList.IsPresent) { - $LimitedTenantList = foreach ($Permission in $PermissionSet) { - if ((($Permission.AllowedTenants | Measure-Object).Count -eq 0 -or $Permission.AllowedTenants -contains 'AllTenants') -and (($Permission.BlockedTenants | Measure-Object).Count -eq 0)) { - @('AllTenants') - } else { - if ($Permission.AllowedTenants -contains 'AllTenants') { - $Permission.AllowedTenants = $Tenants.customerId + foreach ($Exclude in $BaseRole.Value.exclude) { + if ($APIRole -like $Exclude) { + $BaseRoleAllowed = $false + break + } + } + if (!$BaseRoleAllowed) { + throw "Access to this CIPP API endpoint is not allowed, the '$($BaseRole.Name)' base role does not have the required permission: $APIRole" + } + } + + # Check custom role permissions for limitations on api calls or tenants + if ($null -eq $BaseRole.Name -and $Type -eq 'User' -and ($CustomRoles | Measure-Object).Count -eq 0) { + Write-Information $BaseRole.Name + throw 'Access to this CIPP API endpoint is not allowed, the user does not have the required permission' + } elseif (($CustomRoles | Measure-Object).Count -gt 0) { + if (@('admin', 'superadmin') -contains $BaseRole.Name) { + return $true + } else { + $Tenants = Get-Tenants -IncludeErrors + $PermissionsFound = $false + $PermissionSet = foreach ($CustomRole in $CustomRoles) { + try { + Get-CIPPRolePermissions -Role $CustomRole + $PermissionsFound = $true + } catch { + Write-Information $_.Exception.Message + continue + } + } + if ($PermissionsFound) { + if ($TenantList.IsPresent) { + $LimitedTenantList = foreach ($Permission in $PermissionSet) { + if ((($Permission.AllowedTenants | Measure-Object).Count -eq 0 -or $Permission.AllowedTenants -contains 'AllTenants') -and (($Permission.BlockedTenants | Measure-Object).Count -eq 0)) { + @('AllTenants') + } else { + if ($Permission.AllowedTenants -contains 'AllTenants') { + $Permission.AllowedTenants = $Tenants.customerId + } + $Permission.AllowedTenants | Where-Object { $Permission.BlockedTenants -notcontains $_ } } - $Permission.AllowedTenants | Where-Object { $Permission.BlockedTenants -notcontains $_ } } + return $LimitedTenantList } - return $LimitedTenantList - } - foreach ($Role in $PermissionSet) { - # Loop through each custom role permission and check API / Tenant access + $TenantAllowed = $false $APIAllowed = $false + foreach ($Role in $PermissionSet) { + foreach ($Perm in $Role.Permissions) { + if ($Perm -match $APIRole) { + $APIAllowed = $true + break + } + } - foreach ($Perm in $Role.Permissions) { - if ($Perm -match $APIRole) { - $APIAllowed = $true - break + if ($APIAllowed) { + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter ?? $Request.Body.tenantFilter.value ?? $Request.Query.tenantId ?? $Request.Body.tenantId ?? $Request.Body.tenantId.value ?? $env:TenantID + # Check tenant level access + if (($Role.BlockedTenants | Measure-Object).Count -eq 0 -and $Role.AllowedTenants -contains 'AllTenants') { + $TenantAllowed = $true + } elseif ($TenantFilter -eq 'AllTenants') { + $TenantAllowed = $false + } else { + $Tenant = ($Tenants | Where-Object { $TenantFilter -eq $_.customerId -or $TenantFilter -eq $_.defaultDomainName }).customerId + if ($Role.AllowedTenants -contains 'AllTenants') { + $AllowedTenants = $Tenants.customerId + } else { + $AllowedTenants = $Role.AllowedTenants + } + if ($Tenant) { + $TenantAllowed = $AllowedTenants -contains $Tenant -and $Role.BlockedTenants -notcontains $Tenant + if (!$TenantAllowed) { continue } + break + } else { + $TenantAllowed = $true + break + } + } } } + if (!$APIAllowed) { + throw "Access to this CIPP API endpoint is not allowed, you do not have the required permission: $APIRole" + } + if (!$TenantAllowed -and $Help.Functionality -notmatch 'AnyTenant') { + throw 'Access to this tenant is not allowed' + } else { + return $true + } + } else { + # No permissions found for any roles + if ($TenantList.IsPresent) { + return @('AllTenants') + } + return $true if ($APIAllowed) { $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter ?? $Request.Query.tenantId ?? $Request.Body.tenantId ?? $env:TenantID # Check tenant level access if (($Role.BlockedTenants | Measure-Object).Count -eq 0 -and $Role.AllowedTenants -contains 'AllTenants') { $TenantAllowed = $true } elseif ($TenantFilter -eq 'AllTenants') { + $TenantAllowed = $false } else { $Tenant = ($Tenants | Where-Object { $TenantFilter -eq $_.customerId -or $TenantFilter -eq $_.defaultDomainName }).customerId + if ($Role.AllowedTenants -contains 'AllTenants') { $AllowedTenants = $Tenants.customerId } else { @@ -140,14 +266,19 @@ function Test-CIPPAccess { } } - if (!$APIAllowed) { - throw "Access to this CIPP API endpoint is not allowed, you do not have the required permission: $APIRole" - } if (!$TenantAllowed -and $Help.Functionality -notmatch 'AnyTenant') { - Write-Information "Tenant not allowed: $TenantFilter" - throw 'Access to this tenant is not allowed' - } else { - return $true + + if (!$APIAllowed) { + throw "Access to this CIPP API endpoint is not allowed, you do not have the required permission: $APIRole" + } + if (!$TenantAllowed -and $Help.Functionality -notmatch 'AnyTenant') { + Write-Information "Tenant not allowed: $TenantFilter" + + throw 'Access to this tenant is not allowed' + } else { + return $true + } + } } else { # No permissions found for any roles @@ -156,7 +287,10 @@ function Test-CIPPAccess { } return $true } - } else { - return $true } + + if ($TenantList.IsPresent) { + return @('AllTenants') + } + return $true } diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccessUserRole.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccessUserRole.ps1 new file mode 100644 index 000000000000..d5293966cf77 --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccessUserRole.ps1 @@ -0,0 +1,66 @@ +function Test-CIPPAccessUserRole { + <# + .SYNOPSIS + Get the access role for the current user + + .DESCRIPTION + Get the access role for the current user + + .PARAMETER TenantID + The tenant ID to check the access role for + + .EXAMPLE + Get-CippAccessRole -UserId $UserId + + .FUNCTIONALITY + Internal + #> + [CmdletBinding()] + param( + $User + ) + $Roles = @() + $Table = Get-CippTable -TableName cacheAccessUserRoles + $Filter = "PartitionKey eq 'AccessRole' and RowKey eq '$($User.userDetails)' and Timestamp ge datetime'$((Get-Date).AddMinutes(-15).ToString('yyyy-MM-ddTHH:mm:ss'))'" + $UserRole = Get-CIPPAzDataTableEntity @Table -Filter $Filter + if ($UserRole) { + Write-Information "Found cached user role for $($User.userDetails)" + $Roles = $UserRole.Role | ConvertFrom-Json + } else { + try { + $uri = "https://graph.microsoft.com/beta/users/$($User.userDetails)/transitiveMemberOf" + $Memberships = New-GraphGetRequest -uri $uri -NoAuthCheck $true | Where-Object { $_.'@odata.type' -eq '#microsoft.graph.group' } + if ($Memberships) { + Write-Information "Found user roles for $($User.userDetails)" + } else { + Write-Information "No user roles found for $($User.userDetails)" + } + } catch { + Write-Information "Could not get user roles for $($User.userDetails). $($_.Exception.Message)" + return $User + } + + $AccessGroupsTable = Get-CippTable -TableName AccessRoleGroups + $AccessGroups = Get-CIPPAzDataTableEntity @AccessGroupsTable + + $Roles = foreach ($AccessGroup in $AccessGroups) { + if ($Memberships.id -contains $AccessGroup.GroupId) { + $AccessGroup.RowKey + } + } + + $Roles = @($Roles) + @($User.userRoles) + + if (($Roles | Measure-Object).Count -gt 0) { + $UserRole = [PSCustomObject]@{ + PartitionKey = 'AccessUser' + RowKey = [string]$User.userDetails + Role = [string](ConvertTo-Json -Compress -InputObject $Roles) + } + Add-CIPPAzDataTableEntity @Table -Entity $UserRole -Force + } + } + $User.userRoles = $Roles + + return $User +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 index 8206c0d0b0d3..738aacfd7183 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 @@ -9,28 +9,76 @@ function Invoke-ExecCustomRole { param($Request, $TriggerMetadata) $Table = Get-CippTable -tablename 'CustomRoles' - switch ($Request.Query.Action) { + $AccessRoleGroupTable = Get-CippTable -tablename 'AccessRoleGroups' + $Action = $Request.Query.Action ?? $Request.Body.Action + + $DefaultRoles = @('readonly', 'editor', 'admin', 'superadmin') + $BlockedRoles = @('anonymous', 'authenticated') + + if ($Request.Body.RoleName -in $BlockedRoles) { + throw "Role name $($Request.Body.RoleName) cannot be used" + } + + switch ($Action) { 'AddUpdate' { - Write-LogMessage -headers $Request.Headers -API 'ExecCustomRole' -message "Saved custom role $($Request.Body.RoleName)" -Sev 'Info' - $Role = @{ - 'PartitionKey' = 'CustomRoles' - 'RowKey' = "$($Request.Body.RoleName.ToLower())" - 'Permissions' = "$($Request.Body.Permissions | ConvertTo-Json -Compress)" - 'AllowedTenants' = "$($Request.Body.AllowedTenants | ConvertTo-Json -Compress)" - 'BlockedTenants' = "$($Request.Body.BlockedTenants | ConvertTo-Json -Compress)" + try { + $Results = [System.Collections.Generic.List[string]]::new() + Write-LogMessage -headers $Request.Headers -API 'ExecCustomRole' -message "Saved custom role $($Request.Body.RoleName)" -Sev 'Info' + if ($Request.Body.RoleName -notin $DefaultRoles) { + $Role = @{ + 'PartitionKey' = 'CustomRoles' + 'RowKey' = "$($Request.Body.RoleName.ToLower())" + 'Permissions' = "$($Request.Body.Permissions | ConvertTo-Json -Compress)" + 'AllowedTenants' = "$($Request.Body.AllowedTenants | ConvertTo-Json -Compress)" + 'BlockedTenants' = "$($Request.Body.BlockedTenants | ConvertTo-Json -Compress)" + } + Add-CIPPAzDataTableEntity @Table -Entity $Role -Force | Out-Null + $Results.Add("Custom role $($Request.Body.RoleName) saved") + } + if ($Request.Body.EntraGroup) { + $RoleGroup = @{ + 'PartitionKey' = 'AccessRoleGroups' + 'RowKey' = "$($Request.Body.RoleName.ToLower())" + 'GroupId' = $Request.Body.EntraGroup.value + 'GroupName' = $Request.Body.EntraGroup.label + } + Add-CIPPAzDataTableEntity @AccessRoleGroupTable -Entity $RoleGroup -Force | Out-Null + $Results.Add("Security group '$($Request.Body.EntraGroup.label)' assigned to the '$($Request.Body.RoleName)' role.") + Write-LogMessage -headers $Request.Headers -API 'ExecCustomRole' -message "Security group '$($Request.Body.EntraGroup.label)' assigned to the '$($Request.Body.RoleName)' role." -Sev 'Info' + } else { + $AccessRoleGroup = Get-CIPPAzDataTableEntity @AccessRoleGroupTable -Filter "RowKey eq '$($Request.Body.RoleName)'" + if ($AccessRoleGroup) { + Remove-AzDataTableEntity -Force @AccessRoleGroupTable -Entity $AccessRoleGroup + $Results.Add("Security group '$($AccessRoleGroup.GroupName)' removed from the '$($Request.Body.RoleName)' role.") + Write-LogMessage -headers $Request.Headers -API 'ExecCustomRole' -message "Security group '$($AccessRoleGroup.GroupName)' removed from the '$($Request.Body.RoleName)' role." -Sev 'Info' + } + } + $Body = @{Results = $Results } + } catch { + Write-Warning "Failed to save custom role $($Request.Body.RoleName): $($_.Exception.Message)" + Write-Warning $_.InvocationInfo.PositionMessage + $Body = @{Results = "Failed to save custom role $($Request.Body.RoleName)" } } - Add-CIPPAzDataTableEntity @Table -Entity $Role -Force | Out-Null - $Body = @{Results = 'Custom role saved' } } 'Delete' { - Write-LogMessage -headers $Request.Headers -API 'ExecCustomRole' -message "Deleted custom role $($Request.Body.RoleName)" -Sev 'Info' + Write-Information "Deleting custom role $($Request.Body.RoleName)" $Role = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Body.RoleName)'" -Property RowKey, PartitionKey Remove-AzDataTableEntity -Force @Table -Entity $Role $Body = @{Results = 'Custom role deleted' } + Write-LogMessage -headers $Request.Headers -API 'ExecCustomRole' -message "Deleted custom role $($Request.Body.RoleName)" -Sev 'Info' + } + 'ListEntraGroups' { + $Groups = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups?$filter=securityEnabled eq true' -tenantid $env:TenantID -NoAuthCheck $true + $Body = @{ + Results = @($Groups) + Metadata = @{ + GroupCount = $Groups.Count + } + } } default { $Body = Get-CIPPAzDataTableEntity @Table - + $EntraRoleGroups = Get-CIPPAzDataTableEntity @AccessRoleGroupTable if (!$Body) { $Body = @( @{ @@ -38,7 +86,7 @@ function Invoke-ExecCustomRole { } ) } else { - $Body = foreach ($Role in $Body) { + $CustomRoles = foreach ($Role in $Body) { try { $Role.Permissions = $Role.Permissions | ConvertFrom-Json } catch { @@ -62,9 +110,28 @@ function Invoke-ExecCustomRole { } else { $Role | Add-Member -NotePropertyName BlockedTenants -NotePropertyValue @() -Force } + $EntraRoleGroup = $EntraRoleGroups | Where-Object -Property RowKey -EQ $Role.RowKey + if ($EntraRoleGroup) { + $EntraGroup = $EntraRoleGroups | Where-Object -Property RowKey -EQ $Role.RowKey | Select-Object @{Name = 'label'; Expression = { $_.GroupName } }, @{Name = 'value'; Expression = { $_.GroupId } } + + $Role | Add-Member -NotePropertyName EntraGroup -NotePropertyValue $EntraGroup -Force + } + $Role + } + $DefaultRoles = foreach ($DefaultRole in $DefaultRoles) { + $Role = @{ + RowKey = $DefaultRole + Permissions = '' + AllowedTenants = @('AllTenants') + BlockedTenants = @('') + } + $EntraRoleGroup = $EntraRoleGroups | Where-Object -Property RowKey -EQ $Role.RowKey + if ($EntraRoleGroup) { + $Role.EntraGroup = $EntraRoleGroups | Where-Object -Property RowKey -EQ $Role.RowKey | Select-Object @{Name = 'label'; Expression = { $_.GroupName } }, @{Name = 'value'; Expression = { $_.GroupId } } + } $Role } - $Body = @($Body) + $Body = @($DefaultRoles + $CustomRoles) } } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomRole.ps1 index 0d98b1797043..a3c89065b371 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomRole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomRole.ps1 @@ -12,48 +12,81 @@ function Invoke-ListCustomRole { $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $DefaultRoles = @('readonly', 'editor', 'admin', 'superadmin') $Table = Get-CippTable -tablename 'CustomRoles' + $CustomRoles = Get-CIPPAzDataTableEntity @Table - $Body = Get-CIPPAzDataTableEntity @Table + $AccessRoleGroupTable = Get-CippTable -tablename 'AccessRoleGroups' + $RoleGroups = Get-CIPPAzDataTableEntity @AccessRoleGroupTable - if (!$Body) { - $Body = @( - @{ - RowKey = 'No custom roles found' - } - ) - } else { - $Body = foreach ($Role in $Body) { + $TenantList = Get-Tenants -IncludeErrors + + $RoleList = [System.Collections.Generic.List[pscustomobject]]::new() + foreach ($Role in $DefaultRoles) { + $RoleGroup = $RoleGroups | Where-Object -Property RowKey -EQ $Role + + $RoleList.Add([pscustomobject]@{ + RoleName = $Role + Type = 'Built-In' + Permissions = '' + AllowedTenants = @('AllTenants') + BlockedTenants = @() + EntraGroup = $RoleGroup.GroupName ?? $null + EntraGroupId = $RoleGroup.GroupId ?? $null + }) + } + foreach ($Role in $CustomRoles) { + $Role | Add-Member -NotePropertyName RoleName -NotePropertyValue $Role.RowKey -Force + $Role | Add-Member -NotePropertyName Type -NotePropertyValue 'Custom' -Force + + if ($Role.Permissions) { try { $Role.Permissions = $Role.Permissions | ConvertFrom-Json } catch { $Role.Permissions = '' } - if ($Role.AllowedTenants) { - try { - $Role.AllowedTenants = @($Role.AllowedTenants | ConvertFrom-Json) - } catch { - $Role.AllowedTenants = '' + } + if ($Role.AllowedTenants) { + try { + $AllowedTenants = $Role.AllowedTenants | ConvertFrom-Json -ErrorAction Stop | ForEach-Object { + $TenantId = $_ + $TenantList | Where-Object { $_.customerId -eq $TenantId } | Select-Object -ExpandProperty defaultDomainName } - } else { - $Role | Add-Member -NotePropertyName AllowedTenants -NotePropertyValue @() -Force + $AllowedTenants = $AllowedTenants ?? @('AllTenants') + $Role.AllowedTenants = @($AllowedTenants) + } catch { + $Role.AllowedTenants = @('AllTenants') } - if ($Role.BlockedTenants) { - try { - $Role.BlockedTenants = @($Role.BlockedTenants | ConvertFrom-Json) - } catch { - $Role.BlockedTenants = '' + } else { + $Role | Add-Member -NotePropertyName AllowedTenants -NotePropertyValue @() -Force + } + if ($Role.BlockedTenants) { + try { + $BlockedTenants = $Role.BlockedTenants | ConvertFrom-Json -ErrorAction Stop | ForEach-Object { + $TenantId = $_ + $TenantList | Where-Object { $_.customerId -eq $TenantId } | Select-Object -ExpandProperty defaultDomainName } - } else { - $Role | Add-Member -NotePropertyName BlockedTenants -NotePropertyValue @() -Force + $BlockedTenants = $BlockedTenants ?? @() + $Role.BlockedTenants = @($BlockedTenants) + } catch { + $Role.BlockedTenants = @() } - $Role + } else { + $Role | Add-Member -NotePropertyName BlockedTenants -NotePropertyValue @() -Force + } + + $RoleGroup = $RoleGroups | Where-Object -Property RowKey -EQ $Role.RowKey + if ($RoleGroup) { + $EntraGroup = $RoleGroups | Where-Object -Property RowKey -EQ $Role.RowKey | Select-Object GroupName, GroupId + $Role | Add-Member -NotePropertyName EntraGroup -NotePropertyValue $EntraGroup.GroupName -Force + $Role | Add-Member -NotePropertyName EntraGroupId -NotePropertyValue $EntraGroup.GroupId -Force } - $Body = @($Body) + $RoleList.Add($Role) } + $Body = @($RoleList) Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = $Body + Body = ConvertTo-Json -InputObject $Body -Depth 5 }) } diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index c3ef710b52b2..76def2143679 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -13,7 +13,7 @@ function Receive-CippHttpTrigger { .FUNCTIONALITY Entrypoint #> - Param( + param( $Request, $TriggerMetadata ) @@ -47,15 +47,19 @@ function Receive-CippHttpTrigger { TriggerMetadata = $TriggerMetadata } - if (Get-Command -Name $FunctionName -ErrorAction SilentlyContinue) { + if ((Get-Command -Name $FunctionName -ErrorAction SilentlyContinue) -or $FunctionName -eq 'Invoke-Me') { try { $Access = Test-CIPPAccess -Request $Request + if ($FunctionName -eq 'Invoke-Me') { + return + } + Write-Information "Access: $Access" if ($Access) { & $FunctionName @HttpTrigger } } catch { - Write-Information $_.Exception.Message + Write-Warning "Exception occurred on HTTP trigger ($FunctionName): $($_.Exception.Message)" Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::Forbidden Body = $_.Exception.Message @@ -67,6 +71,7 @@ function Receive-CippHttpTrigger { Body = 'Endpoint not found' }) } + return } function Receive-CippOrchestrationTrigger { @@ -161,7 +166,7 @@ function Receive-CippActivityTrigger { .FUNCTIONALITY Entrypoint #> - Param($Item) + param($Item) Write-Warning "Hey Boo, the activity function is running. Here's some info: $($Item | ConvertTo-Json -Depth 10 -Compress)" try { $Start = Get-Date From a3c90a8bf0b79be27022e0e314cc7de982947580 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 19 May 2025 13:17:02 -0400 Subject: [PATCH 059/149] Update Get-GraphToken.ps1 --- Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index 9ac15c0413ea..f936affd8da6 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -6,7 +6,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT if (!$scope) { $scope = 'https://graph.microsoft.com/.default' } if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } #If the $env:<$tenantid> is set, use that instead of the refreshtoken for all tenants. - $refreshToken = $env:Refreshtoken + $refreshToken = $env:RefreshToken $ClientType = Get-Tenants -IncludeErrors -TenantFilter $tenantid if ($clientType.delegatedPrivilegeStatus -eq 'directTenant') { $ClientRefreshToken = Get-Item -Path "env:\$($clientType.customerId)" -ErrorAction SilentlyContinue From 76044a9522aab52fcb1f7326208abe5dafd817bd Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 19 May 2025 13:23:18 -0400 Subject: [PATCH 060/149] Update Test-CIPPAccess.ps1 --- Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index caf5a4605113..004b327c21a5 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -100,7 +100,7 @@ function Test-CIPPAccess { $User = Test-CIPPAccessUserRole -User $User } - Write-Information ($User | ConvertTo-Json -Depth 5) + #Write-Information ($User | ConvertTo-Json -Depth 5) # Return user permissions if ($Request.Params.CIPPEndpoint -eq 'me') { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ From 55c1b0d93c8eef671ae04103c9c0a4193f4f4ca4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 19 May 2025 15:02:13 -0400 Subject: [PATCH 061/149] fix links --- .../Tenant/Administration/Tenant/Invoke-ListTenants.ps1 | 4 ++-- .../CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 | 4 ++-- .../Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 index dc988dae26b5..d91f6d5a2392 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 @@ -96,9 +96,9 @@ function Invoke-ListTenants { if ($Request.Query.Mode -eq 'TenantList') { # add portal link properties $Body = $Body | Select-Object *, @{Name = 'portal_m365'; Expression = { "https://admin.cloud.microsoft/?delegatedOrg=$($_.initialDomainName)" } }, - @{Name = 'portal_exchange'; Expression = { "https://admin.cloud.microsoft/exchange/?delegatedOrg=$($_.initialDomainName)" } }, + @{Name = 'portal_exchange'; Expression = { "https://admin.cloud.microsoft/exchange?delegatedOrg=$($_.initialDomainName)" } }, @{Name = 'portal_entra'; Expression = { "https://entra.microsoft.com/$($_.defaultDomainName)" } }, - @{Name = 'portal_teams'; Expression = { "https://admin.teams.microsoft.com/?delegatedOrg=$($_.initialDomainName)" } }, + @{Name = 'portal_teams'; Expression = { "https://admin.teams.microsoft.com?delegatedOrg=$($_.initialDomainName)" } }, @{Name = 'portal_azure'; Expression = { "https://portal.azure.com/$($_.defaultDomainName)" } }, @{Name = 'portal_intune'; Expression = { "https://intune.microsoft.com/$($_.defaultDomainName)" } }, @{Name = 'portal_security'; Expression = { "https://security.microsoft.com/?tid=$($_.customerId)" } }, diff --git a/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 b/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 index e62b9d856c84..9e0b5cda5eb6 100644 --- a/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 +++ b/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 @@ -122,12 +122,12 @@ function Invoke-HuduExtensionSync { $Links = @( @{ Title = 'M365 Admin Portal' - URL = 'https://admin.cloud.microsoft/?delegatedOrg={0}' -f $Tenant.initialDomainName + URL = 'https://admin.cloud.microsoft?delegatedOrg={0}' -f $Tenant.initialDomainName Icon = 'fas fa-cogs' } @{ Title = 'Exchange Admin Portal' - URL = 'https://admin.cloud.microsoft/exchange/?delegatedOrg={0}' -f $Tenant.initialDomainName + URL = 'https://admin.cloud.microsoft/exchange?delegatedOrg={0}' -f $Tenant.initialDomainName Icon = 'fas fa-mail-bulk' } @{ diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 index 7d29a6b80503..1451ef6eb377 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 @@ -1523,7 +1523,7 @@ function Invoke-NinjaOneTenantSync { $ManagementLinksData = @( @{ Name = 'M365 Admin Portal' - Link = "https://admin.cloud.microsoft/?delegatedOrg=$($customer.defaultDomainName)" + Link = "https://admin.cloud.microsoft?delegatedOrg=$($customer.defaultDomainName)" Icon = 'fas fa-cogs' }, @{ @@ -1548,7 +1548,7 @@ function Invoke-NinjaOneTenantSync { }, @{ Name = 'Teams Admin' - Link = "https://admin.teams.microsoft.com/?delegatedOrg=$($Customer.defaultDomainName)" + Link = "https://admin.teams.microsoft.com?delegatedOrg=$($Customer.defaultDomainName)" Icon = 'fas fa-users' }, @{ From e269eee2d28671f609e90b05a32fecd4779a18ff Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 19 May 2025 22:12:35 +0200 Subject: [PATCH 062/149] remove directTenant from CPV --- .../Start-UpdatePermissionsOrchestrator.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 index 10caa27d3383..26fab2b3200b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 @@ -15,7 +15,7 @@ function Start-UpdatePermissionsOrchestrator { 'displayName' = '*Partner Tenant' } - $TenantList = Get-Tenants -IncludeAll | Where-Object { $_.Excluded -eq $false } + $TenantList = Get-Tenants -IncludeAll | Where-Object { $_.Excluded -eq $false -and $_.delegatedPrivilegeStatus -eq 'directTenant' } $Tenants = [System.Collections.Generic.List[object]]::new() foreach ($Tenant in $TenantList) { From 3b66cf0c8003b331bad302fc8dd9c6317a226a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 19 May 2025 22:39:09 +0200 Subject: [PATCH 063/149] Add DKIM domain exclusions add comment --- .../Push-DomainAnalyserTenant.ps1 | 2 +- .../Standards/Invoke-CIPPStandardAddDKIM.ps1 | 31 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1 index fc530103ede9..34ed6784f272 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1 @@ -20,7 +20,7 @@ function Push-DomainAnalyserTenant { return } else { try { - # Remove domains that are not wanted, and used for cloud signature services + # Remove domains that are not wanted, and used for cloud signature services. Same exclusions also found in Invoke-CIPPStandardAddDKIM $ExclusionDomains = @( '*.microsoftonline.com' '*.exclaimer.cloud' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index ceec4b0ba1b4..bf2691646404 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 @@ -66,9 +66,36 @@ function Invoke-CIPPStandardAddDKIM { return } + # Same exclusions also found in Push-DomainAnalyserTenant + $ExclusionDomains = @( + '*.microsoftonline.com' + '*.exclaimer.cloud' + '*.excl.cloud' + '*.codetwo.online' + '*.call2teams.com' + '*.signature365.net' + '*.myteamsconnect.io' + '*.teams.dstny.com' + ) - $AllDomains = ($BatchResults | Where-Object { $_.DomainName }).DomainName - $DKIM = $BatchResults | Where-Object { $_.Domain } | Select-Object Domain, Enabled, Status + $AllDomains = ($BatchResults | Where-Object { $_.DomainName }).DomainName | ForEach-Object { + $Domain = $_ + foreach ($ExclusionDomain in $ExclusionDomains) { + if ($Domain -like $ExclusionDomain) { + $Domain = $null + } + } + if ($null -ne $Domain) { $Domain } + } + $DKIM = $BatchResults | Where-Object { $_.Domain } | Select-Object Domain, Enabled, Status | ForEach-Object { + $Domain = $_ + foreach ($ExclusionDomain in $ExclusionDomains) { + if ($Domain.Domain -like $ExclusionDomain) { + $Domain = $null + } + } + if ($null -ne $Domain) { $Domain } + } # List of domains for each way to enable DKIM $NewDomains = $AllDomains | Where-Object { $DKIM.Domain -notcontains $_ } From 763cb4bf898ee01b46cd9f82f6431364b45bbd78 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 19 May 2025 23:47:32 +0200 Subject: [PATCH 064/149] updates --- Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 | 3 --- Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 index 3ed6a0f79a01..b9803fddd5f0 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 @@ -22,13 +22,10 @@ function Get-CIPPAuthentication { #Get list of tenants that have 'directTenant' set to true $tenants = Get-Tenants -IncludeErrors | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' if ($tenants) { - Write-Host "Found $($tenants.Count) tenants with directTenant set to true" $tenants | ForEach-Object { $secretname = $_.customerId -replace '-', '_' if ($secret.$secretname) { $name = $_.customerId - Write-Host "Setting $name to $($secret.$secretname)" - Set-Item -Path env:$name -Value $secret.$secretname -Force } } diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index f936affd8da6..bd2419714a92 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -7,8 +7,10 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } #If the $env:<$tenantid> is set, use that instead of the refreshtoken for all tenants. $refreshToken = $env:RefreshToken + if (!$tenantid) { $tenantid = $env:TenantID } $ClientType = Get-Tenants -IncludeErrors -TenantFilter $tenantid if ($clientType.delegatedPrivilegeStatus -eq 'directTenant') { + Write-Host "Using direct tenant refresh token for $($clientType.customerId)" $ClientRefreshToken = Get-Item -Path "env:\$($clientType.customerId)" -ErrorAction SilentlyContinue $refreshToken = $ClientRefreshToken.Value } @@ -47,7 +49,6 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT } } - if (!$tenantid) { $tenantid = $env:TenantID } $TokenKey = '{0}-{1}-{2}' -f $tenantid, $scope, $asApp From d3b92b7e4c08f16669f79c9619111aed3301951c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 19 May 2025 20:07:21 -0400 Subject: [PATCH 065/149] permission sets --- .../Invoke-ExecAppPermissionTemplate.ps1 | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 index 1549381f3f50..777f9f9799fd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 @@ -1,7 +1,7 @@ function Invoke-ExecAppPermissionTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint,AnyTenant .ROLE Tenant.Application.ReadWrite #> @@ -12,7 +12,9 @@ function Invoke-ExecAppPermissionTemplate { $User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json - switch ($Request.Query.Action) { + $Action = $Request.Query.Action ?? $Request.Body.Action + + switch ($Action) { 'Save' { try { $Permissions = $Request.Body.Permissions @@ -25,8 +27,11 @@ function Invoke-ExecAppPermissionTemplate { } $null = Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force $Body = @{ - 'Results' = 'Template Saved' - 'TemplateId' = $Entity.RowKey + 'Results' = 'Template Saved' + 'Metadata' = @{ + 'TemplateName' = $Entity.TemplateName + 'TemplateId' = $Entity.RowKey + } } Write-LogMessage -headers $Request.Headers -API 'ExecAppPermissionTemplate' -message "Permissions Saved for template: $($Request.Body.TemplateName)" -Sev 'Info' -LogData $Permissions } catch { @@ -35,8 +40,39 @@ function Invoke-ExecAppPermissionTemplate { } } } + 'Delete' { + try { + $TemplateId = $Request.Body.TemplateId + $Template = (Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Templates' and RowKey eq '$TemplateId'") + $TemplateName = $Template.TemplateName + + if ($TemplateId) { + $null = Remove-AzDataTableEntity @Table -Entity $Template -Force + $Body = @{ + 'Results' = "Successfully deleted template '$TemplateName'" + } + Write-LogMessage -headers $Request.Headers -API 'ExecAppPermissionTemplate' -message "Permission template deleted: $TemplateName" -Sev 'Info' + } else { + $Body = @{ + 'Results' = 'No Template ID provided for deletion' + } + } + } catch { + $Body = @{ + 'Results' = "Failed to delete template: $($_.Exception.Message)" + } + } + } default { - $Body = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Templates'" | ForEach-Object { + # Check if TemplateId is provided to filter results + $filter = "PartitionKey eq 'Templates'" + if ($Request.Query.TemplateId) { + $templateId = $Request.Query.TemplateId + $filter = "PartitionKey eq 'Templates' and RowKey eq '$templateId'" + Write-LogMessage -headers $Request.Headers -API 'ExecAppPermissionTemplate' -message "Retrieved specific template: $templateId" -Sev 'Info' + } + + $Body = Get-CIPPAzDataTableEntity @Table -Filter $filter | ForEach-Object { [PSCustomObject]@{ TemplateId = $_.RowKey TemplateName = $_.TemplateName From 288c9ef5a20c6b84806764214e60498c198d5e04 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 19 May 2025 21:48:09 -0400 Subject: [PATCH 066/149] app deployment templates --- .../Invoke-ExecAppDeploymentTemplate.ps1 | 154 ++++++++++++++++++ .../Invoke-ListAppDeploymentTemplates.ps1 | 68 ++++++++ 2 files changed, 222 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppDeploymentTemplate.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppDeploymentTemplates.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppDeploymentTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppDeploymentTemplate.ps1 new file mode 100644 index 000000000000..75a36bc5975f --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppDeploymentTemplate.ps1 @@ -0,0 +1,154 @@ +function Invoke-ExecAppDeploymentTemplate { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + Tenant.Application.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $Table = Get-CIPPTable -TableName 'templates' + $User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json + + $Action = $Request.Query.Action ?? $Request.Body.Action + + switch ($Action) { + 'Save' { + try { + $GUID = $Request.Body.TemplateId ?? (New-Guid).GUID + + # Create structured object for the template + $templateObject = $Request.Body | Select-Object -Property * -ExcludeProperty Action, TemplateId + + # Add additional metadata + $templateObject | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID + $templateObject | Add-Member -NotePropertyName 'CreatedBy' -NotePropertyValue ($User.UserDetails ?? 'CIPP-API') + $templateObject | Add-Member -NotePropertyName 'CreatedOn' -NotePropertyValue (Get-Date).ToString('o') + + # If updating an existing template, add UpdatedBy and UpdatedOn + if ($Request.Body.TemplateId) { + $templateObject | Add-Member -NotePropertyName 'UpdatedBy' -NotePropertyValue ($User.UserDetails ?? 'CIPP-API') + $templateObject | Add-Member -NotePropertyName 'UpdatedOn' -NotePropertyValue (Get-Date).ToString('o') + } + + # Convert to JSON, preserving the original structure + $templateJson = $templateObject | ConvertTo-Json -Depth 10 -Compress + + # Add to templates table with AppDeploymentTemplate partition key + $Table.Force = $true + Add-CIPPAzDataTableEntity @Table -Entity @{ + JSON = [string]$templateJson + RowKey = "$GUID" + PartitionKey = 'AppDeploymentTemplate' + } + + # Return a proper array with ONE element containing the TemplateId + $Body = @( + [PSCustomObject]@{ + 'Results' = 'Template Saved' + 'Metadata' = @{ + 'TemplateName' = $Request.Body.TemplateName + 'TemplateId' = $GUID + } + } + ) + + Write-LogMessage -headers $Request.Headers -API $APIName -message "App Deployment Template Saved: $($Request.Body.TemplateName)" -Sev 'Info' + } catch { + $Body = @{ + 'Results' = $_.Exception.Message + } + Write-LogMessage -headers $Request.Headers -API $APIName -message "App Deployment Template Save failed: $($_.Exception.Message)" -Sev 'Error' + } + } + 'Delete' { + try { + $TemplateId = $Request.Body.TemplateId + + # Get the template to delete + $Template = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'AppDeploymentTemplate' and RowKey eq '$TemplateId'" + + if ($Template) { + $TemplateData = $Template.JSON | ConvertFrom-Json + $TemplateName = $TemplateData.TemplateName + + # Remove the template + $null = Remove-AzDataTableEntity @Table -Entity $Template -Force + + $Body = @{ + 'Results' = "Successfully deleted template '$TemplateName'" + } + Write-LogMessage -headers $Request.Headers -API $APIName -message "App Deployment Template deleted: $TemplateName" -Sev 'Info' + } else { + $Body = @{ + 'Results' = 'No template found with the provided ID' + } + } + } catch { + $Body = @{ + 'Results' = "Failed to delete template: $($_.Exception.Message)" + } + Write-LogMessage -headers $Request.Headers -API $APIName -message "App Deployment Template Delete failed: $($_.Exception.Message)" -Sev 'Error' + } + } + 'Get' { + # Check if TemplateId is provided to filter results + $filter = "PartitionKey eq 'AppDeploymentTemplate'" + if ($Request.Query.TemplateId) { + $templateId = $Request.Query.TemplateId + $filter = "PartitionKey eq 'AppDeploymentTemplate' and RowKey eq '$templateId'" + Write-LogMessage -headers $Request.Headers -API $APIName -message "Retrieved specific template: $templateId" -Sev 'Info' + } + + $Templates = Get-CIPPAzDataTableEntity @Table -Filter $filter + + $Body = $Templates | ForEach-Object { + # Parse the JSON + $templateData = $_.JSON | ConvertFrom-Json + + # Create output object preserving original structure + $outputObject = $templateData | Select-Object -Property * + + # Add the TemplateId (RowKey) to the output + $outputObject | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $_.RowKey -Force + + # Add timestamp from the table entity + $outputObject | Add-Member -NotePropertyName 'Timestamp' -NotePropertyValue $_.Timestamp.DateTime.ToString('yyyy-MM-ddTHH:mm:ssZ') -Force + + return $outputObject + } + } + default { + # Default action - list all templates + $filter = "PartitionKey eq 'AppDeploymentTemplate'" + + $Templates = Get-CIPPAzDataTableEntity @Table -Filter $filter + + $Body = $Templates | ForEach-Object { + # Parse the JSON + $templateData = $_.JSON | ConvertFrom-Json + + # Create output object preserving original structure + $outputObject = $templateData | Select-Object -Property * + + # Add the TemplateId (RowKey) to the output + $outputObject | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $_.RowKey -Force + + # Add timestamp from the table entity + $outputObject | Add-Member -NotePropertyName 'Timestamp' -NotePropertyValue $_.Timestamp.DateTime.ToString('yyyy-MM-ddTHH:mm:ssZ') -Force + + return $outputObject + } + } + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = ConvertTo-Json -Depth 10 -InputObject @($Body) + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppDeploymentTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppDeploymentTemplates.ps1 new file mode 100644 index 000000000000..def1e5ba1621 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppDeploymentTemplates.ps1 @@ -0,0 +1,68 @@ +function Invoke-ListAppDeploymentTemplates { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + Tenant.Application.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $Table = Get-CIPPTable -TableName 'templates' + + try { + # Use the templates table with AppDeploymentTemplate partition key + $filter = "PartitionKey eq 'AppDeploymentTemplate'" + + $Templates = Get-CIPPAzDataTableEntity @Table -Filter $filter + + $Body = $Templates | ForEach-Object { + try { + # Safely parse the JSON data - handle potential invalid JSON format + $TemplateData = $null + if ($_.JSON) { + $TemplateData = $_.JSON | ConvertFrom-Json -ErrorAction Stop + } + + # Create a base object with properties directly from the table entity + $templateObject = [PSCustomObject]@{ + TemplateId = $_.RowKey + Timestamp = $_.Timestamp.DateTime.ToString('yyyy-MM-ddTHH:mm:ssZ') + } + + # Add all properties from the JSON data if available + if ($TemplateData) { + foreach ($property in $TemplateData.PSObject.Properties) { + $templateObject | Add-Member -NotePropertyName $property.Name -NotePropertyValue $property.Value -Force + } + } + + return $templateObject + } catch { + Write-LogMessage -headers $Headers -API $APIName -message "Error processing template $($_.RowKey): $($_.Exception.Message)" -Sev 'Error' + return [PSCustomObject]@{ + TemplateId = $_.RowKey + TemplateName = 'Error parsing template data' + Error = $_.Exception.Message + Timestamp = $_.Timestamp.DateTime.ToString('yyyy-MM-ddTHH:mm:ssZ') + } + } + } + + Write-LogMessage -headers $Headers -API $APIName -message "Listed App Deployment Templates: $($Body.Count) templates found" -Sev 'Info' + } catch { + $Body = @{ + Results = "Failed to list app deployment templates: $($_.Exception.Message)" + } + Write-LogMessage -headers $Headers -API $APIName -message "Failed to list App Deployment Templates: $($_.Exception.Message)" -Sev 'Error' + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = ConvertTo-Json -Depth 10 -InputObject @($Body) + }) +} From 8f5ae2511e33f12647628f76c2e8ac5b2e883d10 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 09:38:08 -0400 Subject: [PATCH 067/149] rename apis --- ...late.ps1 => Invoke-ExecAppApprovalTemplate.ps1} | 14 +++++++------- ...tes.ps1 => Invoke-ListAppApprovalTemplates.ps1} | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) rename Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/{Invoke-ExecAppDeploymentTemplate.ps1 => Invoke-ExecAppApprovalTemplate.ps1} (93%) rename Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/{Invoke-ListAppDeploymentTemplates.ps1 => Invoke-ListAppApprovalTemplates.ps1} (93%) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppDeploymentTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppApprovalTemplate.ps1 similarity index 93% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppDeploymentTemplate.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppApprovalTemplate.ps1 index 75a36bc5975f..f604328df1c1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppDeploymentTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppApprovalTemplate.ps1 @@ -1,4 +1,4 @@ -function Invoke-ExecAppDeploymentTemplate { +function Invoke-ExecAppApprovalTemplate { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -39,12 +39,12 @@ function Invoke-ExecAppDeploymentTemplate { # Convert to JSON, preserving the original structure $templateJson = $templateObject | ConvertTo-Json -Depth 10 -Compress - # Add to templates table with AppDeploymentTemplate partition key + # Add to templates table with AppApprovalTemplate partition key $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ JSON = [string]$templateJson RowKey = "$GUID" - PartitionKey = 'AppDeploymentTemplate' + PartitionKey = 'AppApprovalTemplate' } # Return a proper array with ONE element containing the TemplateId @@ -71,7 +71,7 @@ function Invoke-ExecAppDeploymentTemplate { $TemplateId = $Request.Body.TemplateId # Get the template to delete - $Template = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'AppDeploymentTemplate' and RowKey eq '$TemplateId'" + $Template = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'AppApprovalTemplate' and RowKey eq '$TemplateId'" if ($Template) { $TemplateData = $Template.JSON | ConvertFrom-Json @@ -98,10 +98,10 @@ function Invoke-ExecAppDeploymentTemplate { } 'Get' { # Check if TemplateId is provided to filter results - $filter = "PartitionKey eq 'AppDeploymentTemplate'" + $filter = "PartitionKey eq 'AppApprovalTemplate'" if ($Request.Query.TemplateId) { $templateId = $Request.Query.TemplateId - $filter = "PartitionKey eq 'AppDeploymentTemplate' and RowKey eq '$templateId'" + $filter = "PartitionKey eq 'AppApprovalTemplate' and RowKey eq '$templateId'" Write-LogMessage -headers $Request.Headers -API $APIName -message "Retrieved specific template: $templateId" -Sev 'Info' } @@ -125,7 +125,7 @@ function Invoke-ExecAppDeploymentTemplate { } default { # Default action - list all templates - $filter = "PartitionKey eq 'AppDeploymentTemplate'" + $filter = "PartitionKey eq 'AppApprovalTemplate'" $Templates = Get-CIPPAzDataTableEntity @Table -Filter $filter diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppDeploymentTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppApprovalTemplates.ps1 similarity index 93% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppDeploymentTemplates.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppApprovalTemplates.ps1 index def1e5ba1621..ba016fd5946c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppDeploymentTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppApprovalTemplates.ps1 @@ -1,4 +1,4 @@ -function Invoke-ListAppDeploymentTemplates { +function Invoke-ListAppApprovalTemplates { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -15,8 +15,8 @@ function Invoke-ListAppDeploymentTemplates { $Table = Get-CIPPTable -TableName 'templates' try { - # Use the templates table with AppDeploymentTemplate partition key - $filter = "PartitionKey eq 'AppDeploymentTemplate'" + # Use the templates table with AppApprovalTemplate partition key + $filter = "PartitionKey eq 'AppApprovalTemplate'" $Templates = Get-CIPPAzDataTableEntity @Table -Filter $filter From 40a5b84e0cf9ac31c9d2c5952718497adb8079a7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 10:02:40 -0400 Subject: [PATCH 068/149] add import logic for AppPermissions --- .../Public/Tools/Import-CommunityTemplate.ps1 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Modules/CIPPCore/Public/Tools/Import-CommunityTemplate.ps1 b/Modules/CIPPCore/Public/Tools/Import-CommunityTemplate.ps1 index 2d3686a1702d..6b5ee473988c 100644 --- a/Modules/CIPPCore/Public/Tools/Import-CommunityTemplate.ps1 +++ b/Modules/CIPPCore/Public/Tools/Import-CommunityTemplate.ps1 @@ -43,6 +43,22 @@ function Import-CommunityTemplate { $NewJSON.excludedTenants = $excludedTenants } } + + if ($Template.PartitionKey -eq 'AppApprovalTemplate') { + # Extract the Permission Set name,id,permissions from the JSON and add to the AppPermissions table + $AppPermissionsTable = Get-CIPPTable -TableName 'AppPermissions' + $Permissions = $NewJSON.Permissions + $Entity = @{ + 'PartitionKey' = 'Templates' + 'RowKey' = $NewJSON.PermissionSetId + 'TemplateName' = $NewJSON.PermissionSetName + 'Permissions' = [string]($Permissions | ConvertTo-Json -Depth 10 -Compress) + 'UpdatedBy' = $NewJSON.UpdatedBy ?? $NewJSON.CreatedBy ?? 'System' + } + $null = Add-CIPPAzDataTableEntity @AppPermissionsTable -Entity $Entity -Force + Write-Information 'Added App Permissions to AppPermissions table' + } + # Re-compress JSON and save to table $NewJSON = [string]($NewJSON | ConvertTo-Json -Depth 100 -Compress) $Template.JSON = $NewJSON From 1e982e69ca1ff1ba9c9d6411a95179e0493084ec Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 13:29:16 -0400 Subject: [PATCH 069/149] Update Invoke-ExecAppPermissionTemplate.ps1 --- .../Invoke-ExecAppPermissionTemplate.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 index 777f9f9799fd..982dc7cf17be 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 @@ -16,11 +16,12 @@ function Invoke-ExecAppPermissionTemplate { switch ($Action) { 'Save' { + $RowKey = $Request.Body.TemplateId ?? [guid]::NewGuid().ToString() try { $Permissions = $Request.Body.Permissions $Entity = @{ 'PartitionKey' = 'Templates' - 'RowKey' = [string]($Request.Body.TemplateId ?? [guid]::NewGuid().ToString()) + 'RowKey' = [string]$RowKey 'TemplateName' = [string]$Request.Body.TemplateName 'Permissions' = [string]($Permissions | ConvertTo-Json -Depth 10 -Compress) 'UpdatedBy' = $User.UserDetails ?? 'CIPP-API' @@ -30,7 +31,7 @@ function Invoke-ExecAppPermissionTemplate { 'Results' = 'Template Saved' 'Metadata' = @{ 'TemplateName' = $Entity.TemplateName - 'TemplateId' = $Entity.RowKey + 'TemplateId' = $RowKey } } Write-LogMessage -headers $Request.Headers -API 'ExecAppPermissionTemplate' -message "Permissions Saved for template: $($Request.Body.TemplateName)" -Sev 'Info' -LogData $Permissions From f871ae2a8063578ee839644bd57c981d4550e1c7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 13:39:29 -0400 Subject: [PATCH 070/149] Update Invoke-ExecAppPermissionTemplate.ps1 --- .../Application Approval/Invoke-ExecAppPermissionTemplate.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 index 982dc7cf17be..87f8185a6628 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppPermissionTemplate.ps1 @@ -16,8 +16,8 @@ function Invoke-ExecAppPermissionTemplate { switch ($Action) { 'Save' { - $RowKey = $Request.Body.TemplateId ?? [guid]::NewGuid().ToString() try { + $RowKey = $Request.Body.TemplateId ?? [guid]::NewGuid().ToString() $Permissions = $Request.Body.Permissions $Entity = @{ 'PartitionKey' = 'Templates' @@ -36,6 +36,7 @@ function Invoke-ExecAppPermissionTemplate { } Write-LogMessage -headers $Request.Headers -API 'ExecAppPermissionTemplate' -message "Permissions Saved for template: $($Request.Body.TemplateName)" -Sev 'Info' -LogData $Permissions } catch { + Write-Information "Failed to save template: $($_.Exception.Message) - $($_.InvocationInfo.PositionMessage)" $Body = @{ 'Results' = $_.Exception.Message } From c8c04b343e8fc667e40c396ec76bccd1b2c8dcef Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 20 May 2025 23:32:26 +0200 Subject: [PATCH 071/149] latest execsdsamapp --- .../HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 index 8a4d5c523898..e439329713fd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 @@ -75,11 +75,14 @@ Function Invoke-ExecCreateSAMApp { if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" + if (!$Secret) { $Secret = New-Object -TypeName PSObject } + $Secret | Add-Member -MemberType NoteProperty -Name 'PartitionKey' -Value 'Secret' -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'RowKey' -Value 'Secret' -Force $Secret | Add-Member -MemberType NoteProperty -Name 'tenantid' -Value $TenantId -Force $Secret | Add-Member -MemberType NoteProperty -Name 'applicationid' -Value $AppId.appId -Force $Secret | Add-Member -MemberType NoteProperty -Name 'applicationsecret' -Value $AppPassword -Force - Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force Write-Information ($Secret | ConvertTo-Json -Depth 5) + Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force } else { Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $TenantId -AsPlainText -Force) Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appId -AsPlainText -Force) From 75e73ce11add55972d9a273f23c0ceb0406cb636 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 17:36:03 -0400 Subject: [PATCH 072/149] app approval template deployment --- .../Push-ExecAppApprovalTemplate.ps1 | 36 ++++++++ .../Core/Invoke-ExecServicePrincipals.ps1 | 31 +++++-- .../Invoke-ExecAddMultiTenantApp.ps1 | 91 +++++++++++-------- 3 files changed, 112 insertions(+), 46 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1 new file mode 100644 index 000000000000..dc789b848831 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1 @@ -0,0 +1,36 @@ +function Push-ExecAppApprovalTemplate { + <# + .FUNCTIONALITY + Entrypoint + #> + param($Item) + + try { + $Item = $Item | ConvertTo-Json -Depth 10 | ConvertFrom-Json + $TemplateId = $Item.templateId + + $TemplateTable = Get-CIPPTable -TableName 'templates' + $Filter = "RowKey eq '$TemplateId' and PartitionKey eq 'AppApprovalTemplate'" + $Template = (Get-CIPPAzDataTableEntity @TemplateTable -Filter $Filter).JSON | ConvertFrom-Json -ErrorAction SilentlyContinue + + if (!$Template) { + Write-LogMessage -message "Template $TemplateId not found" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Error + return + } + + $Permissions = $Template.Permissions + + Write-Host "$($Item | ConvertTo-Json -Depth 10)" + $ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=AppId,id,displayName&`$top=999" -tenantid $Item.Tenant + if ($Item.AppId -notin $ServicePrincipalList.appId) { + $PostResults = New-GraphPostRequest 'https://graph.microsoft.com/beta/servicePrincipals' -type POST -tenantid $Item.tenant -body "{ `"appId`": `"$($Item.appId)`" }" + Write-LogMessage -message "Added $($Item.AppId) to tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Info + } else { + Write-LogMessage -message "This app already exists in tenant $($Item.Tenant). We're adding the required permissions." -tenant $Item.Tenant -API 'Add Multitenant App' -sev Info + } + Add-CIPPApplicationPermission -RequiredResourceAccess ($Item.applicationResourceAccess) -ApplicationId $Item.AppId -Tenantfilter $Item.Tenant + Add-CIPPDelegatedPermission -RequiredResourceAccess ($Item.DelegateResourceAccess) -ApplicationId $Item.AppId -Tenantfilter $Item.Tenant + } catch { + Write-LogMessage -message "Error adding application to tenant $($Item.Tenant) - $($_.Exception.Message)" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Error + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 index f81044bb5263..c0f7873d34ac 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 @@ -20,17 +20,32 @@ function Invoke-ExecServicePrincipals { try { switch ($Request.Query.Action) { 'Create' { + $BlockList = @( + 'e9a7fea1-1cc0-4cd9-a31b-9137ca5deedd', # eM Client + 'ff8d92dc-3d82-41d6-bcbd-b9174d163620', # PerfectData Software + 'a245e8c0-b53c-4b67-9b45-751d1dff8e6b', # Newsletter Software Supermailer + 'b15665d9-eda6-4092-8539-0eec376afd59', # rclone + 'a43e5392-f48b-46a4-a0f1-098b5eeb4757', # CloudSponge + 'caffae8c-0882-4c81-9a27-d1803af53a40' # SigParser + ) $Action = 'Create' + if ($Request.Query.AppId -match '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$') { - $Body = @{ - 'appId' = $Request.Query.AppId - } | ConvertTo-Json -Compress - try { - $ServicePrincipal = New-GraphPostRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals' -tenantid $TenantFilter -type POST -body $Body -NoAuthCheck $true - $Results = "Created service principal for $($ServicePrincipal.displayName) ($($ServicePrincipal.appId))" - } catch { - $Results = "Unable to create service principal: $($_.Exception.Message)" + + if ($BlockList -contains $Request.Query.AppId) { + $Results = 'Service Principal creation is blocked for this AppId' $Success = $false + } else { + $Body = @{ + 'appId' = $Request.Query.AppId + } | ConvertTo-Json -Compress + try { + $ServicePrincipal = New-GraphPostRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals' -tenantid $TenantFilter -type POST -body $Body -NoAuthCheck $true + $Results = "Created service principal for $($ServicePrincipal.displayName) ($($ServicePrincipal.appId))" + } catch { + $Results = "Unable to create service principal: $($_.Exception.Message)" + $Success = $false + } } } else { $Results = 'Invalid AppId' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 index b85e6bf5f9c2..9607388dbd15 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 @@ -12,51 +12,66 @@ function Invoke-ExecAddMultiTenantApp { $APIName = $Request.Params.CIPPEndpoint $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $DelegateResources = $request.body.permissions | Where-Object -Property origin -EQ 'Delegated' | ForEach-Object { @{ id = $_.id; type = 'Scope' } } - $DelegateResourceAccess = @{ ResourceAppId = '00000003-0000-0000-c000-000000000000'; resourceAccess = $DelegateResources } - $ApplicationResources = $request.body.permissions | Where-Object -Property origin -EQ 'Application' | ForEach-Object { @{ id = $_.id; type = 'Role' } } - $ApplicationResourceAccess = @{ ResourceAppId = '00000003-0000-0000-c000-000000000000'; resourceAccess = $ApplicationResources } - $Results = try { - if ($Request.Body.CopyPermissions -eq $true) { - $Command = 'ExecApplicationCopy' - } else { - $Command = 'ExecAddMultiTenantApp' - } - if ('allTenants' -in $Request.Body.tenantFilter.value) { - $TenantFilter = (Get-Tenants).defaultDomainName - } else { - $TenantFilter = $Request.Body.tenantFilter.value - } + if ($Request.Body.configMode -eq 'manual') { + $DelegateResources = $request.body.permissions | Where-Object -Property origin -EQ 'Delegated' | ForEach-Object { @{ id = $_.id; type = 'Scope' } } + $DelegateResourceAccess = @{ ResourceAppId = '00000003-0000-0000-c000-000000000000'; resourceAccess = $DelegateResources } + $ApplicationResources = $request.body.permissions | Where-Object -Property origin -EQ 'Application' | ForEach-Object { @{ id = $_.id; type = 'Role' } } + $ApplicationResourceAccess = @{ ResourceAppId = '00000003-0000-0000-c000-000000000000'; resourceAccess = $ApplicationResources } + + $Results = try { + if ($Request.Body.CopyPermissions -eq $true) { + $Command = 'ExecApplicationCopy' + } else { + $Command = 'ExecAddMultiTenantApp' + } + if ('allTenants' -in $Request.Body.tenantFilter.value) { + $TenantFilter = (Get-Tenants).defaultDomainName + } else { + $TenantFilter = $Request.Body.tenantFilter.value + } - $TenantCount = ($TenantFilter | Measure-Object).Count - $Queue = New-CippQueueEntry -Name 'Application Approval' -TotalTasks $TenantCount - foreach ($Tenant in $TenantFilter) { - try { - $InputObject = @{ - OrchestratorName = 'ExecMultiTenantAppOrchestrator' - Batch = @([pscustomobject]@{ - FunctionName = $Command - Tenant = $tenant - AppId = $Request.Body.AppId - applicationResourceAccess = $ApplicationResourceAccess - delegateResourceAccess = $DelegateResourceAccess - QueueId = $Queue.RowKey - }) - SkipLog = $true + $TenantCount = ($TenantFilter | Measure-Object).Count + $Queue = New-CippQueueEntry -Name 'Application Approval' -TotalTasks $TenantCount + foreach ($Tenant in $TenantFilter) { + try { + $InputObject = @{ + OrchestratorName = 'ExecMultiTenantAppOrchestrator' + Batch = @([pscustomobject]@{ + FunctionName = $Command + Tenant = $tenant + AppId = $Request.Body.AppId + applicationResourceAccess = $ApplicationResourceAccess + delegateResourceAccess = $DelegateResourceAccess + QueueId = $Queue.RowKey + }) + SkipLog = $true + } + $null = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) + "Queued application to tenant $Tenant. See the logbook for deployment details" + } catch { + "Error queuing application to tenant $Tenant - $($_.Exception.Message)" } - $null = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) - "Queued application to tenant $Tenant. See the logbook for deployment details" - } catch { - "Error queuing application to tenant $Tenant - $($_.Exception.Message)" } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMsg = Get-NormalizedError -message $($_.Exception.Message) + $Results = "Function Error: $ErrorMsg" + $StatusCode = [HttpStatusCode]::BadRequest } + } elseif ($Request.Body.configMode -eq 'template') { + Write-Information 'Application Approval - Template Mode' + Write-Information ($Request.Body | ConvertTo-Json -Depth 5) + + + + + + + $Results = 'Deploying {0} to {1}' -f $Request.Body.selectedTemplate.label, ($Request.Body.tenantFilter.label -join ', ') $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMsg = Get-NormalizedError -message $($_.Exception.Message) - $Results = "Function Error: $ErrorMsg" - $StatusCode = [HttpStatusCode]::BadRequest } + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode From 497b750fee7a9f94668dec2286b8642a610a610e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 18:32:42 -0400 Subject: [PATCH 073/149] app approval template support --- .../Public/Add-CIPPApplicationPermission.ps1 | 30 +++++++- .../Public/Add-CIPPDelegatedPermission.ps1 | 29 ++++++++ .../Push-ExecAppApprovalTemplate.ps1 | 18 ++--- .../Invoke-ExecAddMultiTenantApp.ps1 | 74 ++++++++++++------- 4 files changed, 113 insertions(+), 38 deletions(-) diff --git a/Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1 b/Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1 index 8841b33e8abc..80241c161acf 100644 --- a/Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1 @@ -2,6 +2,7 @@ function Add-CIPPApplicationPermission { [CmdletBinding()] param( $RequiredResourceAccess, + $TemplateId, $ApplicationId, $Tenantfilter ) @@ -31,7 +32,34 @@ function Add-CIPPApplicationPermission { $RequiredResourceAccess.Add($Resource) } + } else { + if (!$RequiredResourceAccess -and $TemplateId) { + Write-Information "Adding application permissions for template $TemplateId" + $TemplateTable = Get-CIPPTable -TableName 'templates' + $Filter = "RowKey eq '$TemplateId' and PartitionKey eq 'AppApprovalTemplate'" + $Template = (Get-CIPPAzDataTableEntity @TemplateTable -Filter $Filter).JSON | ConvertFrom-Json -ErrorAction SilentlyContinue + $ApplicationId = $Template.AppId + $Permissions = $Template.Permissions + $RequiredResourceAccess = [System.Collections.Generic.List[object]]::new() + foreach ($AppId in $Permissions.PSObject.Properties.Name) { + $AppPermissions = @($Permissions.$AppId.applicationPermissions) + $Resource = @{ + resourceAppId = $AppId + resourceAccess = [System.Collections.Generic.List[object]]::new() + } + foreach ($Permission in $AppPermissions) { + $Resource.ResourceAccess.Add(@{ + id = $Permission.id + type = 'Role' + }) + } + + $RequiredResourceAccess.Add($Resource) + } + } } + + $ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=AppId,id,displayName&`$top=999" -skipTokenCache $true -tenantid $Tenantfilter -NoAuthCheck $true $ourSVCPrincipal = $ServicePrincipalList | Where-Object -Property AppId -EQ $ApplicationId if (!$ourSVCPrincipal) { @@ -59,7 +87,7 @@ function Add-CIPPApplicationPermission { } } foreach ($SingleResource in $App.ResourceAccess | Where-Object -Property Type -EQ 'Role') { - if ($SingleResource.id -In $CurrentRoles.appRoleId) { continue } + if ($SingleResource.id -in $CurrentRoles.appRoleId) { continue } [pscustomobject]@{ principalId = $($ourSVCPrincipal.id) resourceId = $($svcPrincipalId.id) diff --git a/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 b/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 index 8b1b50702035..83b4e2bfe025 100644 --- a/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 @@ -2,6 +2,7 @@ function Add-CIPPDelegatedPermission { [CmdletBinding()] param( $RequiredResourceAccess, + $TemplateId, $ApplicationId, $NoTranslateRequired, $Tenantfilter @@ -40,7 +41,34 @@ function Add-CIPPDelegatedPermission { # remove the partner center permission if not pushing to partner tenant $RequiredResourceAccess = $RequiredResourceAccess | Where-Object { $_.resourceAppId -ne 'fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd' } } + } else { + if (!$RequiredResourceAccess -and $TemplateId) { + Write-Information "Adding delegated permissions for template $TemplateId" + $TemplateTable = Get-CIPPTable -TableName 'templates' + $Filter = "RowKey eq '$TemplateId' and PartitionKey eq 'AppApprovalTemplate'" + $Template = (Get-CIPPAzDataTableEntity @TemplateTable -Filter $Filter).JSON | ConvertFrom-Json -ErrorAction SilentlyContinue + $ApplicationId = $Template.AppId + $Permissions = $Template.Permissions + $NoTranslateRequired = $true + $RequiredResourceAccess = [System.Collections.Generic.List[object]]::new() + foreach ($AppId in $Permissions.PSObject.Properties.Name) { + $DelegatedPermissions = @($Permissions.$AppId.delegatedPermissions) + $ResourceAccess = [System.Collections.Generic.List[object]]::new() + foreach ($Permission in $DelegatedPermissions) { + $ResourceAccess.Add(@{ + id = $Permission.value + type = 'Scope' + }) + } + $Resource = @{ + resourceAppId = $AppId + resourceAccess = @($ResourceAccess) + } + $RequiredResourceAccess.Add($Resource) + } + } } + $Translator = Get-Content '.\PermissionsTranslator.json' | ConvertFrom-Json $ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=appId,id,displayName&`$top=999" -tenantid $Tenantfilter -skipTokenCache $true -NoAuthCheck $true $ourSVCPrincipal = $ServicePrincipalList | Where-Object -Property appId -EQ $ApplicationId @@ -66,6 +94,7 @@ function Add-CIPPDelegatedPermission { } $DelegatedScopes = $App.resourceAccess | Where-Object -Property type -EQ 'Scope' + if ($NoTranslateRequired) { $NewScope = @($DelegatedScopes | ForEach-Object { $_.id } | Sort-Object -Unique) -join ' ' } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1 index dc789b848831..5c55136cccaf 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecAppApprovalTemplate.ps1 @@ -8,29 +8,23 @@ function Push-ExecAppApprovalTemplate { try { $Item = $Item | ConvertTo-Json -Depth 10 | ConvertFrom-Json $TemplateId = $Item.templateId - - $TemplateTable = Get-CIPPTable -TableName 'templates' - $Filter = "RowKey eq '$TemplateId' and PartitionKey eq 'AppApprovalTemplate'" - $Template = (Get-CIPPAzDataTableEntity @TemplateTable -Filter $Filter).JSON | ConvertFrom-Json -ErrorAction SilentlyContinue - - if (!$Template) { - Write-LogMessage -message "Template $TemplateId not found" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Error + if (!$TemplateId) { + Write-LogMessage -message 'No template specified' -tenant $Item.Tenant -API 'Add Multitenant App' -sev Error return } - $Permissions = $Template.Permissions - - Write-Host "$($Item | ConvertTo-Json -Depth 10)" $ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=AppId,id,displayName&`$top=999" -tenantid $Item.Tenant if ($Item.AppId -notin $ServicePrincipalList.appId) { + Write-Information "Adding $($Item.AppId) to tenant $($Item.Tenant)." $PostResults = New-GraphPostRequest 'https://graph.microsoft.com/beta/servicePrincipals' -type POST -tenantid $Item.tenant -body "{ `"appId`": `"$($Item.appId)`" }" Write-LogMessage -message "Added $($Item.AppId) to tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Info } else { Write-LogMessage -message "This app already exists in tenant $($Item.Tenant). We're adding the required permissions." -tenant $Item.Tenant -API 'Add Multitenant App' -sev Info } - Add-CIPPApplicationPermission -RequiredResourceAccess ($Item.applicationResourceAccess) -ApplicationId $Item.AppId -Tenantfilter $Item.Tenant - Add-CIPPDelegatedPermission -RequiredResourceAccess ($Item.DelegateResourceAccess) -ApplicationId $Item.AppId -Tenantfilter $Item.Tenant + Add-CIPPApplicationPermission -TemplateId $TemplateId -Tenantfilter $Item.Tenant + Add-CIPPDelegatedPermission -TemplateId $TemplateId -Tenantfilter $Item.Tenant } catch { Write-LogMessage -message "Error adding application to tenant $($Item.Tenant) - $($_.Exception.Message)" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Error + Write-Error $_.Exception.Message } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 index 9607388dbd15..678ae951fb76 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 @@ -33,26 +33,30 @@ function Invoke-ExecAddMultiTenantApp { $TenantCount = ($TenantFilter | Measure-Object).Count $Queue = New-CippQueueEntry -Name 'Application Approval' -TotalTasks $TenantCount - foreach ($Tenant in $TenantFilter) { - try { - $InputObject = @{ - OrchestratorName = 'ExecMultiTenantAppOrchestrator' - Batch = @([pscustomobject]@{ - FunctionName = $Command - Tenant = $tenant - AppId = $Request.Body.AppId - applicationResourceAccess = $ApplicationResourceAccess - delegateResourceAccess = $DelegateResourceAccess - QueueId = $Queue.RowKey - }) - SkipLog = $true - } - $null = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) - "Queued application to tenant $Tenant. See the logbook for deployment details" - } catch { - "Error queuing application to tenant $Tenant - $($_.Exception.Message)" + $Batch = foreach ($Tenant in $TenantFilter) { + [pscustomobject]@{ + FunctionName = $Command + Tenant = $tenant + AppId = $Request.Body.AppId + applicationResourceAccess = $ApplicationResourceAccess + delegateResourceAccess = $DelegateResourceAccess + QueueId = $Queue.RowKey } } + + try { + $InputObject = @{ + OrchestratorName = 'ExecMultiTenantAppOrchestrator' + Batch = @($Batch) + SkipLog = $true + } + $null = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) + $Results = 'Deploying {0} to {1}, see the logbook for details' -f $Request.Body.AppId, ($Request.Body.tenantFilter.label -join ', ') + } catch { + $ErrorMsg = Get-NormalizedError -message $($_.Exception.Message) + $Results = "Function Error: $ErrorMsg" + } + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMsg = Get-NormalizedError -message $($_.Exception.Message) @@ -61,14 +65,34 @@ function Invoke-ExecAddMultiTenantApp { } } elseif ($Request.Body.configMode -eq 'template') { Write-Information 'Application Approval - Template Mode' - Write-Information ($Request.Body | ConvertTo-Json -Depth 5) - - - - - + if ('allTenants' -in $Request.Body.tenantFilter.value) { + $TenantFilter = (Get-Tenants).defaultDomainName + } else { + $TenantFilter = $Request.Body.tenantFilter.value + } + $TenantCount = ($TenantFilter | Measure-Object).Count + $Queue = New-CippQueueEntry -Name 'Application Approval (Template)' -TotalTasks $TenantCount - $Results = 'Deploying {0} to {1}' -f $Request.Body.selectedTemplate.label, ($Request.Body.tenantFilter.label -join ', ') + $Batch = foreach ($Tenant in $TenantFilter) { + [pscustomobject]@{ + FunctionName = 'ExecAppApprovalTemplate' + Tenant = $tenant + TemplateId = $Request.Body.selectedTemplate.value + AppId = $Request.Body.selectedTemplate.addedFields.AppId + QueueId = $Queue.RowKey + } + } + try { + $InputObject = @{ + OrchestratorName = 'ExecMultiTenantAppOrchestrator' + Batch = @($Batch) + SkipLog = $true + } + $null = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) + $Results = 'Deploying {0} to {1}, see the logbook for details' -f $Request.Body.selectedTemplate.label, ($Request.Body.tenantFilter.label -join ', ') + } catch { + $Results = "Error queuing application - $($_.Exception.Message)" + } $StatusCode = [HttpStatusCode]::OK } From 09c821dcb4614249af3c98114cfe4728227c7c05 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 19:44:35 -0400 Subject: [PATCH 074/149] app deployment standard tweaks --- .../Invoke-ListAppApprovalTemplates.ps1 | 2 - .../Invoke-CIPPStandardAppDeploy.ps1 | 66 ++++++++++++++----- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppApprovalTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppApprovalTemplates.ps1 index ba016fd5946c..5c43a217d76e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppApprovalTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ListAppApprovalTemplates.ps1 @@ -53,12 +53,10 @@ function Invoke-ListAppApprovalTemplates { } } - Write-LogMessage -headers $Headers -API $APIName -message "Listed App Deployment Templates: $($Body.Count) templates found" -Sev 'Info' } catch { $Body = @{ Results = "Failed to list app deployment templates: $($_.Exception.Message)" } - Write-LogMessage -headers $Headers -API $APIName -message "Failed to list App Deployment Templates: $($_.Exception.Message)" -Sev 'Error' } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 index d9542b9e435d..2adbd34d30fb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 @@ -29,34 +29,63 @@ function Invoke-CIPPStandardAppDeploy { #> param($Tenant, $Settings) + Write-Information "Running AppDeploy standard for tenant $($Tenant)." + $AppsToAdd = $Settings.appids -split ',' $AppExists = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/servicePrincipals?$top=999' -tenantid $Tenant + $Mode = $Settings.mode ?? 'copy' + + if ($Mode -eq 'template') { + $AppsToAdd = $Settings.templateIds.addedFields.AppId + } + $MissingApps = foreach ($App in $AppsToAdd) { + if ($App -notin $AppExists.appId) { + $App + } + } if ($Settings.remediate -eq $true) { - foreach ($App In $AppsToAdd) { - $App = $App.Trim() - if (!$App) { - continue + if ($Mode -eq 'copy') { + foreach ($App in $AppsToAdd) { + $App = $App.Trim() + if (!$App) { + continue + } + $Application = $AppExists | Where-Object -Property appId -EQ $App + try { + New-CIPPApplicationCopy -App $App -Tenant $Tenant + Write-LogMessage -API 'Standards' -tenant $tenant -message "Added application $($Application.displayName) ($App) to $Tenant and updated it's permissions" -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to add app $($Application.displayName) ($App). Error: $ErrorMessage" -sev Error + } + } + } elseif ($Mode -eq 'template') { + $TemplateIds = $Settings.templateIds.value + $TemplateName = $Settings.templateIds.label + $AppIds = $Settings.templateIds.addedFields.AppId + + foreach ($AppId in $AppIds) { + if ($AppId -notin $AppExists.appId) { + Write-Information "Adding $($AppId) to tenant $($Tenant)." + $PostResults = New-GraphPostRequest 'https://graph.microsoft.com/beta/servicePrincipals' -type POST -tenantid $Item.tenant -body "{ `"appId`": `"$($Item.appId)`" }" + Write-LogMessage -message "Added $($Item.AppId) to tenant $($Item.Tenant)" -tenant $Item.Tenant -API 'Add Multitenant App' -sev Info + } } - $Application = $AppExists | Where-Object -Property appId -EQ $App - try { - New-CIPPApplicationCopy -App $App -Tenant $Tenant - Write-LogMessage -API 'Standards' -tenant $tenant -message "Added application $($Application.displayName) ($App) to $Tenant and updated it's permissions" -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to add app $($Application.displayName) ($App). Error: $ErrorMessage" -sev Error + foreach ($TemplateId in $TemplateIds) { + try { + Add-CIPPApplicationPermission -TemplateId $TemplateId -Tenantfilter $Tenant + Add-CIPPDelegatedPermission -TemplateId $TemplateId -Tenantfilter $Tenant + Write-LogMessage -API 'Standards' -tenant $tenant -message "Added application(s) from template $($TemplateName) and updated it's permissions" -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to add app from approval template $($TemplateName). Error: $ErrorMessage" -sev Error + } } } } if ($Settings.alert) { - - $MissingApps = foreach ($App in $AppsToAdd) { - if ($App -notin $AppExists.appId) { - $App - } - } - if ($MissingApps.Count -gt 0) { Write-StandardsAlert -message "The following applications are not deployed: $($MissingApps -join ', ')" -object (@{ 'Missing Apps' = $MissingApps -join ',' }) -tenant $Tenant -standardName 'AppDeploy' -standardId $Settings.standardId Write-LogMessage -API 'Standards' -tenant $tenant -message "The following applications are not deployed: $($MissingApps -join ', ')" -sev Info @@ -70,4 +99,5 @@ function Invoke-CIPPStandardAppDeploy { Set-CIPPStandardsCompareField -FieldName 'standards.AppDeploy' -FieldValue $StateIsCorrect -TenantFilter $tenant Add-CIPPBPAField -FieldName 'AppDeploy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } + } From 806de1ce5666a5cc96e0ffe129b22d605a2521b4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 23:15:42 -0400 Subject: [PATCH 075/149] Update Push-CIPPStandard.ps1 --- .../Activity Triggers/Standards/Push-CIPPStandard.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 index 27b206bbc513..9934bc2900a4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 @@ -21,7 +21,9 @@ function Push-CIPPStandard { } try { & $FunctionName -Tenant $Item.Tenant -Settings $Item.Settings -ErrorAction Stop + Write-Information "Standard $($Standard) completed for tenant $($Tenant)" } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Error running standard $($Standard) for tenant $($Tenant) - $($_.Exception.Message)" -sev Error -LogData (Get-CippException -Exception $_) throw $_.Exception.Message } } From 62595ccc8989ca47ef86beff7b6b8da594521bd3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 23:17:08 -0400 Subject: [PATCH 076/149] add more logging --- .../Activity Triggers/Standards/Push-CIPPStandard.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 index 9934bc2900a4..04402cf8662f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 @@ -24,6 +24,8 @@ function Push-CIPPStandard { Write-Information "Standard $($Standard) completed for tenant $($Tenant)" } catch { Write-LogMessage -API 'Standards' -tenant $Tenant -message "Error running standard $($Standard) for tenant $($Tenant) - $($_.Exception.Message)" -sev Error -LogData (Get-CippException -Exception $_) + Write-Warning "Error running standard $($Standard) for tenant $($Tenant) - $($_.Exception.Message)" + Write-Information $_.InvocationInfo.PositionMessage throw $_.Exception.Message } } From da70c01be7eea3897138308d57335e20bb54fd40 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 23:21:48 -0400 Subject: [PATCH 077/149] fix ninja logging --- .../Public/NinjaOne/Invoke-NinjaOneSync.ps1 | 2 +- .../NinjaOne/Invoke-NinjaOneTenantSync.ps1 | 44 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneSync.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneSync.ps1 index 54a0c2c28a67..24f64e54d351 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneSync.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneSync.ps1 @@ -32,7 +32,7 @@ function Invoke-NinjaOneSync { Add-AzDataTableEntity @Table -Entity $AddObject -Force - Write-LogMessage -API 'NinjaOneAutoMap_Queue' -Headers'CIPP' -message "NinjaOne Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -Headers 'CIPP' -message "NinjaOne Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' } catch { Write-LogMessage -API 'Scheduler_Billing' -tenant 'none' -message "Could not start NinjaOne Sync $($_.Exception.Message)" -sev Error } diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 index 1451ef6eb377..1603da37c897 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 @@ -23,7 +23,7 @@ function Invoke-NinjaOneTenantSync { $EndDate = try { Get-Date($CurrentItem.lastEndTime) } catch { $Null } if (($null -ne $CurrentItem.lastStartTime) -and ($StartDate -gt (Get-Date).ToUniversalTime().AddMinutes(-10)) -and ( $Null -eq $CurrentItem.lastEndTime -or ($StartDate -gt $EndDate))) { - Throw "NinjaOne Sync for Tenant $($MappedTenant.RowKey) is still running, please wait 10 minutes and try again." + throw "NinjaOne Sync for Tenant $($MappedTenant.RowKey) is still running, please wait 10 minutes and try again." } # Set Last Start Time @@ -45,10 +45,10 @@ function Invoke-NinjaOneTenantSync { $Customer = Get-Tenants -IncludeErrors | Where-Object { $_.customerId -eq $MappedTenant.RowKey } Write-Information "Processing: $($Customer.displayName) - Queued for $((New-TimeSpan -Start $StartQueueTime -End $StartTime).TotalSeconds)" - Write-LogMessage -API 'NinjaOneSync' -Headers'NinjaOneSync' -message "Processing NinjaOne Synchronization for $($Customer.displayName) - Queued for $((New-TimeSpan -Start $StartQueueTime -End $StartTime).TotalSeconds)" -Sev 'Info' + Write-LogMessage -tenant $Customer.defaultDomainName -API 'NinjaOneSync' -message "Processing NinjaOne Synchronization for $($Customer.displayName) - Queued for $((New-TimeSpan -Start $StartQueueTime -End $StartTime).TotalSeconds)" -Sev 'Info' if (($Customer | Measure-Object).count -ne 1) { - Throw "Unable to match the recieved ID to a tenant QueueItem: $($QueueItem | ConvertTo-Json -Depth 100 | Out-String) Matched Customer: $($Customer| ConvertTo-Json -Depth 100 | Out-String)" + throw "Unable to match the recieved ID to a tenant QueueItem: $($QueueItem | ConvertTo-Json -Depth 100 | Out-String) Matched Customer: $($Customer| ConvertTo-Json -Depth 100 | Out-String)" } $TenantFilter = $Customer.defaultDomainName @@ -303,7 +303,7 @@ function Invoke-NinjaOneTenantSync { $MaxSecureScore = $CurrentSecureScore.maxScore - [System.Collections.Generic.List[PSCustomObject]]$SecureScoreParsed = Foreach ($Score in $CurrentSecureScore.controlScores) { + [System.Collections.Generic.List[PSCustomObject]]$SecureScoreParsed = foreach ($Score in $CurrentSecureScore.controlScores) { $MatchedProfile = $SecureScoreProfiles | Where-Object { $_.id -eq $Score.controlName } [PSCustomObject]@{ Category = $Score.controlCategory @@ -448,7 +448,7 @@ function Invoke-NinjaOneTenantSync { } # Parse Devices - Foreach ($Device in $Devices | Where-Object { $_.id -notin $ParsedDevices.id }) { + foreach ($Device in $Devices | Where-Object { $_.id -notin $ParsedDevices.id }) { # First lets match on serial $MatchedNinjaDevice = $NinjaDevices | Where-Object { $_.system.biosSerialNumber -eq $Device.SerialNumber -or $_.system.serialNumber -eq $Device.SerialNumber } @@ -489,7 +489,7 @@ function Invoke-NinjaOneTenantSync { - Foreach ($DeviceUser in $Device.usersloggedon) { + foreach ($DeviceUser in $Device.usersloggedon) { $FoundUser = ($Users | Where-Object { $_.id -eq $DeviceUser.userid }) $DeviceUsers.add($FoundUser.DisplayName) $DeviceUserIDs.add($DeviceUser.userId) @@ -753,7 +753,7 @@ function Invoke-NinjaOneTenantSync { $NinjaOneUser = $NinjaOneUserDocs | Where-Object { $_.ParsedFields.cippUserID -eq $User.ID } if (($NinjaOneUser | Measure-Object).count -gt 1) { - Throw 'Multiple Users with the same ID found' + throw 'Multiple Users with the same ID found' } @@ -847,7 +847,7 @@ function Invoke-NinjaOneTenantSync { } # OS Icon - $OSIcon = Switch ($UserDevice.OS) { + $OSIcon = switch ($UserDevice.OS) { 'Windows' { '' } 'iOS' { '' } 'Android' { '' } @@ -1180,7 +1180,7 @@ function Invoke-NinjaOneTenantSync { Remove-AzDataTableEntity -Force @UsersUpdateTable -Entity $NinjaUserCreation [System.Collections.Generic.List[PSCustomObject]]$NinjaUserCreation = @() } - } Catch { + } catch { Write-Information "Bulk Creation Error, but may have been successful as only 1 record with an issue could have been the cause: $_" } @@ -1192,7 +1192,7 @@ function Invoke-NinjaOneTenantSync { Remove-AzDataTableEntity -Force @UsersUpdateTable -Entity $NinjaUserUpdates [System.Collections.Generic.List[PSCustomObject]]$NinjaUserUpdates = @() } - } Catch { + } catch { Write-Information "Bulk Update Errored, but may have been successful as only 1 record with an issue could have been the cause: $_" } @@ -1255,7 +1255,7 @@ function Invoke-NinjaOneTenantSync { Remove-AzDataTableEntity -Force @UsersUpdateTable -Entity $NinjaUserCreation } - } Catch { + } catch { Write-Information "Bulk Creation Error, but may have been successful as only 1 record with an issue could have been the cause: $_" } @@ -1266,7 +1266,7 @@ function Invoke-NinjaOneTenantSync { [System.Collections.Generic.List[PSCustomObject]]$UpdatedUsers = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method PATCH -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json; charset=utf-8' -Body ("[$($NinjaUserUpdates.body -join ',')]") -EA Stop).content | ConvertFrom-Json -Depth 100 Remove-AzDataTableEntity -Force @UsersUpdateTable -Entity $NinjaUserUpdates } - } Catch { + } catch { Write-Information "Bulk Update Errored, but may have been successful as only 1 record with an issue could have been the cause: $_" } @@ -1311,10 +1311,10 @@ function Invoke-NinjaOneTenantSync { # Relate Users to Devices - Foreach ($LinkDevice in $ParsedDevices | Where-Object { $null -ne $_.NinjaDevice }) { + foreach ($LinkDevice in $ParsedDevices | Where-Object { $null -ne $_.NinjaDevice }) { $RelatedItems = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/related-items/with-entity/NODE/$($LinkDevice.NinjaDevice.id)" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -Depth 100 [System.Collections.Generic.List[PSCustomObject]]$Relations = @() - Foreach ($LinkUser in $LinkDevice.UserIDs) { + foreach ($LinkUser in $LinkDevice.UserIDs) { $MatchedUser = $UsersMap | Where-Object { $_.M365ID -eq $LinkUser } if (($MatchedUser | Measure-Object).count -eq 1) { $ExistingRelation = $RelatedItems | Where-Object { $_.relEntityType -eq 'DOCUMENT' -and $_.relEntityId -eq $MatchedUser.NinjaOneID } @@ -1338,7 +1338,7 @@ function Invoke-NinjaOneTenantSync { $Null = Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/related-items/entity/NODE/$($LinkDevice.NinjaDevice.id)/relations" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ($Relations | ConvertTo-Json -Depth 100 -AsArray) -EA Stop Write-Information 'Completed Update' } - } Catch { + } catch { Write-Information "Creating Relations Failed: $_" } } @@ -1449,7 +1449,7 @@ function Invoke-NinjaOneTenantSync { Write-Information 'Creating NinjaOne Licenses' [System.Collections.Generic.List[PSCustomObject]]$CreatedLicenses = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json; charset=utf-8' -Body ($NinjaLicenseCreation | ConvertTo-Json -Depth 100 -AsArray) -EA Stop).content | ConvertFrom-Json -Depth 100 } - } Catch { + } catch { Write-Information "Bulk Creation Error, but may have been successful as only 1 record with an issue could have been the cause: $_" } @@ -1460,7 +1460,7 @@ function Invoke-NinjaOneTenantSync { [System.Collections.Generic.List[PSCustomObject]]$UpdatedLicenses = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method PATCH -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json; charset=utf-8' -Body ($NinjaLicenseUpdates | ConvertTo-Json -Depth 100 -AsArray) -EA Stop).content | ConvertFrom-Json -Depth 100 Write-Information 'Completed Update' } - } Catch { + } catch { Write-Information "Bulk Update Errored, but may have been successful as only 1 record with an issue could have been the cause: $_" } @@ -1468,13 +1468,13 @@ function Invoke-NinjaOneTenantSync { if ($Configuration.LicenseDocumentsEnabled -eq $True -and $Configuration.UserDocumentsEnabled -eq $True) { # Relate Subscriptions to Users - Foreach ($LinkLic in $LicenseDetails) { + foreach ($LinkLic in $LicenseDetails) { $MatchedLicDoc = $LicenseDocs | Where-Object { $_.documentName -eq $LinkLic.name } if (($MatchedLicDoc | Measure-Object).count -eq 1) { # Remove existing relations $RelatedItems = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/related-items/with-entity/DOCUMENT/$($MatchedLicDoc.documentId)" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -Depth 100 [System.Collections.Generic.List[PSCustomObject]]$Relations = @() - Foreach ($LinkUser in $LinkLic.Users) { + foreach ($LinkUser in $LinkLic.Users) { $ExistingRelation = $RelatedItems | Where-Object { $_.relEntityType -eq 'DOCUMENT' -and $_.relEntityId -eq $LinkUser } if (!$ExistingRelation) { $Relations.Add( @@ -1494,7 +1494,7 @@ function Invoke-NinjaOneTenantSync { $Null = Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/related-items/entity/DOCUMENT/$($($MatchedLicDoc.documentId))/relations" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ($Relations | ConvertTo-Json -Depth 100 -AsArray) -EA Stop Write-Information 'Completed Update' } - } Catch { + } catch { Write-Information "Creating Relations Failed: $_" } @@ -2126,7 +2126,7 @@ function Invoke-NinjaOneTenantSync { $CurrentItem | Add-Member -NotePropertyName lastStatus -NotePropertyValue 'Completed' -Force Add-CIPPAzDataTableEntity @MappingTable -Entity $CurrentItem -Force - Write-LogMessage -API 'NinjaOneSync' -Headers'NinjaOneSync' -message "Completed NinjaOne Sync for $($Customer.displayName). Queued for $((New-TimeSpan -Start $StartQueueTime -End $StartTime).TotalSeconds) seconds. Data fetched in $((New-TimeSpan -Start $StartTime -End $FetchEnd).TotalSeconds) seconds. Total processing time $((New-TimeSpan -Start $StartTime -End (Get-Date)).TotalSeconds) seconds" -Sev 'info' + Write-LogMessage -tenant $Customer.defaultDomainName -API 'NinjaOneSync' -message "Completed NinjaOne Sync for $($Customer.displayName). Queued for $((New-TimeSpan -Start $StartQueueTime -End $StartTime).TotalSeconds) seconds. Data fetched in $((New-TimeSpan -Start $StartTime -End $FetchEnd).TotalSeconds) seconds. Total processing time $((New-TimeSpan -Start $StartTime -End (Get-Date)).TotalSeconds) seconds" -Sev 'info' } catch { $Message = if ($_.ErrorDetails.Message) { @@ -2136,7 +2136,7 @@ function Invoke-NinjaOneTenantSync { $_.Exception.message } Write-Error "Failed NinjaOne Processing for $($Customer.displayName) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" - Write-LogMessage -API 'NinjaOneSync' -Headers'NinjaOneSync' -message "Failed NinjaOne Processing for $($Customer.displayName) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" -Sev 'Error' + Write-LogMessage -tenant $Customer.defaultDomainName -API 'NinjaOneSync' -message "Failed NinjaOne Processing for $($Customer.displayName) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" -Sev 'Error' $CurrentItem | Add-Member -NotePropertyName lastEndTime -NotePropertyValue ([string]$((Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ'))) -Force $CurrentItem | Add-Member -NotePropertyName lastStatus -NotePropertyValue 'Failed' -Force Add-CIPPAzDataTableEntity @MappingTable -Entity $CurrentItem -Force From fd635b66b517d802bfcbc2022ae332191af7ddbc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 May 2025 23:23:48 -0400 Subject: [PATCH 078/149] cleanup logging --- .../Start-CIPPGraphSubscriptionRenewalTimer.ps1 | 7 +------ .../Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPGraphSubscriptionRenewalTimer.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPGraphSubscriptionRenewalTimer.ps1 index ee96995ee6f4..70aac093b08e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPGraphSubscriptionRenewalTimer.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPGraphSubscriptionRenewalTimer.ps1 @@ -7,11 +7,6 @@ function Start-CIPPGraphSubscriptionRenewalTimer { param() if ($PSCmdlet.ShouldProcess('Start-CIPPGraphSubscriptionRenewalTimer', 'Starting Graph Subscription Renewal Timer')) { - try { - Write-LogMessage -API 'Scheduler_RenewGraphSubscriptions' -tenant 'none' -message 'Starting Graph Subscription Renewal' -sev Info - Invoke-CippGraphWebhookRenewal - } catch { - Write-LogMessage -API 'Scheduler_RenewGraphSubscriptions' -tenant 'none' -message 'Failed to renew graph subscriptions' -sev Info - } + Invoke-CippGraphWebhookRenewal } } diff --git a/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 index 5ff8f3631212..28e35e5abeda 100644 --- a/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 @@ -12,6 +12,7 @@ function Invoke-CippGraphWebhookRenewal { } if (($WebhookData | Measure-Object).Count -gt 0) { + Write-LogMessage -API 'Scheduler_RenewGraphSubscriptions' -tenant 'none' -message 'Starting Graph Subscription Renewal' -sev Info foreach ($UpdateSub in $WebhookData) { try { $TenantFilter = $UpdateSub.PartitionKey From 67a642ff69204a42f593a142ebf33adc2d918eec Mon Sep 17 00:00:00 2001 From: Esco Date: Wed, 21 May 2025 09:35:08 +0200 Subject: [PATCH 079/149] feat: PhishSimSpoofIntelligence replace switch --- ...-CIPPStandardPhishSimSpoofIntelligence.ps1 | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishSimSpoofIntelligence.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishSimSpoofIntelligence.ps1 index d50a2f57055b..bf14d2d3496c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishSimSpoofIntelligence.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishSimSpoofIntelligence.ps1 @@ -35,8 +35,12 @@ function Invoke-CIPPStandardPhishSimSpoofIntelligence { [String[]]$AddDomain = $Settings.AllowedDomains.value | Where-Object { $_ -notin $DomainState.SendingInfrastructure } - $RemoveDomain = $DomainState | Where-Object { $_.SendingInfrastructure -notin $Settings.AllowedDomains.value } | - Select-Object -Property Identity,SendingInfrastructure + if ($Settings.RemoveExtraDomains -eq $true) { + $RemoveDomain = $DomainState | Where-Object { $_.SendingInfrastructure -notin $Settings.AllowedDomains.value } | + Select-Object -Property Identity,SendingInfrastructure + } else { + $RemoveDomain = @() + } $StateIsCorrect = ($AddDomain.Count -eq 0 -and $RemoveDomain.Count -eq 0) @@ -51,15 +55,17 @@ function Invoke-CIPPStandardPhishSimSpoofIntelligence { } Else { $BulkRequests = New-Object System.Collections.Generic.List[Hashtable] - # Prepare removal requests - If ($RemoveDomain.Count -gt 0) { - Write-Host "Removing $($RemoveDomain.Count) domains from Spoof Intelligence" - $BulkRequests.Add(@{ - CmdletInput = @{ - CmdletName = 'Remove-TenantAllowBlockListSpoofItems' - Parameters = @{ Identity = 'default'; Ids = $RemoveDomain.Identity } - } - }) + if ($Settings.RemoveExtraDomains -eq $true) { + # Prepare removal requests + If ($RemoveDomain.Count -gt 0) { + Write-Host "Removing $($RemoveDomain.Count) domains from Spoof Intelligence" + $BulkRequests.Add(@{ + CmdletInput = @{ + CmdletName = 'Remove-TenantAllowBlockListSpoofItems' + Parameters = @{ Identity = 'default'; Ids = $RemoveDomain.Identity } + } + }) + } } # Prepare addition requests From 895d8d807dac589c4c5dfffd6e56aad2b5497c29 Mon Sep 17 00:00:00 2001 From: Esco Date: Wed, 21 May 2025 10:06:41 +0200 Subject: [PATCH 080/149] feat: PhishingSimulations replace switch --- ...Invoke-CIPPStandardPhishingSimulations.ps1 | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishingSimulations.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishingSimulations.ps1 index ca24d4c37370..73b822ee2192 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishingSimulations.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishingSimulations.ps1 @@ -45,10 +45,18 @@ function Invoke-CIPPStandardPhishingSimulations { Select-Object -Property Identity,Name,SenderIpRanges,Domains,SenderDomainIs [String[]]$AddSenderIpRanges = $Settings.SenderIpRanges.value | Where-Object { $_ -notin $RuleState.SenderIpRanges } - [String[]]$RemoveSenderIpRanges = $RuleState.SenderIpRanges | Where-Object { $_ -notin $Settings.SenderIpRanges.value } + if ($Settings.RemoveExtraUrls -eq $true) { + [String[]]$RemoveSenderIpRanges = $RuleState.SenderIpRanges | Where-Object { $_ -notin $Settings.SenderIpRanges.value } + } else { + $RemoveSenderIpRanges = @() + } [String[]]$AddDomains = $Settings.Domains.value | Where-Object { $_ -notin $RuleState.Domains } - [String[]]$RemoveDomains = $RuleState.Domains | Where-Object { $_ -notin $Settings.Domains.value } + if ($Settings.RemoveExtraUrls -eq $true) { + [String[]]$RemoveDomains = $RuleState.Domains | Where-Object { $_ -notin $Settings.Domains.value } + } else { + $RemoveDomains = @() + } $RuleIsCorrect = ($RuleState.Name -like "*PhishSimOverr*") -and ($AddSenderIpRanges.Count -eq 0 -and $RemoveSenderIpRanges.Count -eq 0) -and @@ -59,7 +67,11 @@ function Invoke-CIPPStandardPhishingSimulations { Select-Object -Property Value [String[]]$AddEntries = $Settings.PhishingSimUrls.value | Where-Object { $_ -notin $SimUrlState.value } - [String[]]$RemoveEntries = $SimUrlState.value | Where-Object { $_ -notin $Settings.PhishingSimUrls.value } + if ($Settings.RemoveExtraUrls -eq $true) { + [String[]]$RemoveEntries = $SimUrlState.value | Where-Object { $_ -notin $Settings.PhishingSimUrls.value } + } else { + $RemoveEntries = @() + } $PhishingSimUrlsIsCorrect = ($AddEntries.Count -eq 0 -and $RemoveEntries.Count -eq 0) @@ -133,14 +145,16 @@ function Invoke-CIPPStandardPhishingSimulations { ListType = 'Url' ListSubType = 'AdvancedDelivery' } - # Remove entries that are not in the settings - If ($RemoveEntries.Count -gt 0) { - $cmdParams.Entries = $RemoveEntries - Try { - $null = New-ExoRequest -TenantId $Tenant -cmdlet 'Remove-TenantAllowBlockListItems' -cmdParams $cmdParams - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Removed Phishing Simulation URLs from Allowlist." -sev Info - } Catch { - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to remove Phishing Simulation URLs from Allowlist." -sev Error -LogData $_ + if ($Settings.RemoveExtraUrls -eq $true) { + # Remove entries that are not in the settings + If ($RemoveEntries.Count -gt 0) { + $cmdParams.Entries = $RemoveEntries + Try { + $null = New-ExoRequest -TenantId $Tenant -cmdlet 'Remove-TenantAllowBlockListItems' -cmdParams $cmdParams + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Removed Phishing Simulation URLs from Allowlist." -sev Info + } Catch { + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to remove Phishing Simulation URLs from Allowlist." -sev Error -LogData $_ + } } } # Add entries that are in the settings From 2f6e6ea04b8623dc08f98c62b4c481cffca3a57d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 21 May 2025 14:22:12 +0200 Subject: [PATCH 081/149] add single tenants improvements --- .../CIPP/Setup/Invoke-ExecAddTenant.ps1 | 30 ++++++------------- .../Public/Get-CIPPAuthentication.ps1 | 9 ++++-- .../Public/GraphHelper/Get-GraphToken.ps1 | 7 ++++- .../Public/GraphHelper/Get-Tenants.ps1 | 9 ++++-- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 index cdd57390d607..7764294b94a5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 @@ -13,12 +13,12 @@ Function Invoke-ExecAddTenant { try { # Get the tenant ID from the request body $tenantId = $Request.body.tenantId - $displayName = $Request.body.displayName $defaultDomainName = $Request.body.defaultDomainName # Get the Tenants table $TenantsTable = Get-CippTable -tablename 'Tenants' - + #force a refresh of the authentication info + $auth = Get-CIPPAuthentication # Check if tenant already exists $ExistingTenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter "PartitionKey eq 'Tenants' and RowKey eq '$tenantId'" @@ -30,25 +30,13 @@ Function Invoke-ExecAddTenant { } else { # Create new tenant entry try { - # Get organization info - $Organization = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/organization' -tenantid $tenantId -NoAuthCheck:$true -ErrorAction Stop - - if (-not $displayName) { - $displayName = $Organization[0].displayName - } - - if (-not $defaultDomainName) { - # Try to get domains - try { - $Domains = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantId -NoAuthCheck:$true -ErrorAction Stop - $defaultDomainName = ($Domains | Where-Object { $_.isDefault -eq $true }).id - $initialDomainName = ($Domains | Where-Object { $_.isInitial -eq $true }).id - } catch { - # If we can't get domains, use verified domains from organization - $defaultDomainName = ($Organization[0].verifiedDomains | Where-Object { $_.isDefault -eq $true }).name - $initialDomainName = ($Organization[0].verifiedDomains | Where-Object { $_.isInitial -eq $true }).name - } - } + # Get tenant information from Microsoft Graph + $headers = @{ Authorization = "Bearer $($request.body.access_token)" } + $Organization = (Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/organization' -Headers $headers -Method GET -ContentType 'application/json' -ErrorAction Stop).value + $displayName = $Organization.displayName + $Domains = (Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/domains?$top=999' -Headers $headers -Method GET -ContentType 'application/json' -ErrorAction Stop).value + $defaultDomainName = ($Domains | Where-Object { $_.isDefault -eq $true }).id + $initialDomainName = ($Domains | Where-Object { $_.isInitial -eq $true }).id } catch { Write-LogMessage -API 'Add-Tenant' -message "Failed to get information for tenant $tenantId - $($_.Exception.Message)" -Sev 'Critical' throw "Failed to get information for tenant $tenantId. Make sure the tenant is properly authenticated." diff --git a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 index b9803fddd5f0..e88452db366f 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 @@ -20,7 +20,10 @@ function Get-CIPPAuthentication { } Write-Host "Got secrets from dev storage. ApplicationID: $env:ApplicationID" #Get list of tenants that have 'directTenant' set to true - $tenants = Get-Tenants -IncludeErrors | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' + #get directtenants directly from table, avoid get-tenants due to performance issues + $TenantsTable = Get-CippTable -tablename 'Tenants' + $Filter = "PartitionKey eq 'Tenants' and delegatedPrivilegeStatus eq 'directTenant'" + $tenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter if ($tenants) { $tenants | ForEach-Object { $secretname = $_.customerId -replace '-', '_' @@ -49,7 +52,9 @@ function Get-CIPPAuthentication { $keyvaultname = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] #Get list of tenants that have 'directTenant' set to true - $tenants = Get-Tenants -IncludeErrors | Where-Object -Property delegatedPrivilegeStatus -EQ 'directTenant' + $TenantsTable = Get-CippTable -tablename 'Tenants' + $Filter = "PartitionKey eq 'Tenants' and delegatedPrivilegeStatus eq 'directTenant'" + $tenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter if ($tenants) { $tenants | ForEach-Object { $name = $_.tenantId -replace '-', '_' diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index bd2419714a92..5473f274f54c 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -4,11 +4,16 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT Internal #> if (!$scope) { $scope = 'https://graph.microsoft.com/.default' } + if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } #If the $env:<$tenantid> is set, use that instead of the refreshtoken for all tenants. $refreshToken = $env:RefreshToken if (!$tenantid) { $tenantid = $env:TenantID } - $ClientType = Get-Tenants -IncludeErrors -TenantFilter $tenantid + #Get list of tenants that have 'directTenant' set to true + #get directtenants directly from table, avoid get-tenants due to performance issues + $TenantsTable = Get-CippTable -tablename 'Tenants' + $Filter = "PartitionKey eq 'Tenants' and delegatedPrivilegeStatus eq 'directTenant'" + $ClientType = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter | Where-Object { $_.customerId -eq $tenantid -or $_.defaultDomainName -eq $tenantid } if ($clientType.delegatedPrivilegeStatus -eq 'directTenant') { Write-Host "Using direct tenant refresh token for $($clientType.customerId)" $ClientRefreshToken = Get-Item -Path "env:\$($clientType.customerId)" -ErrorAction SilentlyContinue diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 index d9423da54ce4..cd87d5cbe512 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 @@ -14,7 +14,10 @@ function Get-Tenants { [switch]$CleanOld, [string]$TenantFilter ) - + $caller = $MyInvocation.InvocationName + $scriptName = $MyInvocation.ScriptName + Write-Host "Called by: $caller" + Write-Host "In script: $scriptName" $TenantsTable = Get-CippTable -tablename 'Tenants' $ExcludedFilter = "PartitionKey eq 'Tenants' and Excluded eq true" @@ -75,7 +78,9 @@ function Get-Tenants { if (($BuildRequired -or $TriggerRefresh.IsPresent) -and $PartnerTenantState.state -ne 'owntenant') { # Get TenantProperties table $PropertiesTable = Get-CippTable -TableName 'TenantProperties' - + if (!$env:RefreshToken) { + throw 'RefreshToken not set. Cannot get tenant list.' + } #get the full list of tenants $GDAPRelationships = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships?`$filter=status eq 'active' and not startsWith(displayName,'MLT_')$RelationshipFilter&`$select=customer,autoExtendDuration,endDateTime&`$top=300" -NoAuthCheck:$true $GDAPList = foreach ($Relationship in $GDAPRelationships) { From d2aac3e087c2a41fe0528976850b7fd4063b9ed9 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 May 2025 10:26:17 -0400 Subject: [PATCH 082/149] log alerting tweaks --- .../Push-SchedulerCIPPNotifications.ps1 | 26 +++++++++++++++++-- .../Public/GraphHelper/Write-LogMessage.ps1 | 4 +-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-SchedulerCIPPNotifications.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-SchedulerCIPPNotifications.ps1 index 258ec34cd1c0..23e199078efc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-SchedulerCIPPNotifications.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-SchedulerCIPPNotifications.ps1 @@ -25,7 +25,7 @@ function Push-SchedulerCIPPNotifications { $PartitionKey = Get-Date -UFormat '%Y%m%d' $Filter = "PartitionKey eq '{0}'" -f $PartitionKey $Currentlog = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Where-Object { - $_.API -in $Settings -and $_.SentAsAlert -ne $true -and $_.Severity -in $severity + $_.API -in $Settings -and $_.sentAsAlert -ne $true -and $_.Severity -in $severity } $StandardsTable = Get-CIPPTable -tablename CippStandardsAlerts $CurrentStandardsLogs = Get-CIPPAzDataTableEntity @StandardsTable -Filter $Filter | Where-Object { @@ -50,12 +50,34 @@ function Push-SchedulerCIPPNotifications { $Subject = "$($Tenant): CIPP Alert: Alerts found starting at $((Get-Date).AddMinutes(-15))" $HTMLContent = New-CIPPAlertTemplate -Data $Data -Format 'html' -InputObject 'table' -CIPPURL $CIPPURL Send-CIPPAlert -Type 'email' -Title $Subject -HTMLContent $HTMLContent.htmlcontent -TenantFilter $tenant -APIName 'Alerts' + $UpdateLogs = $CurrentLog | ForEach-Object { + if ($_.PSObject.Properties.Name -contains 'sentAsAlert') { + $_.sentAsAlert = $true + } else { + $_ | Add-Member -MemberType NoteProperty -Name sentAsAlert -Value $true -Force + } + $_ + } + if ($UpdateLogs) { + Add-CIPPAzDataTableEntity @Table -Entity $UpdateLogs -Force + } } } else { $Data = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity) $Subject = "CIPP Alert: Alerts found starting at $((Get-Date).AddMinutes(-15))" $HTMLContent = New-CIPPAlertTemplate -Data $Data -Format 'html' -InputObject 'table' -CIPPURL $CIPPURL Send-CIPPAlert -Type 'email' -Title $Subject -HTMLContent $HTMLContent.htmlcontent -TenantFilter $tenant -APIName 'Alerts' + $UpdateLogs = $CurrentLog | ForEach-Object { + if ($_.PSObject.Properties.Name -contains 'sentAsAlert') { + $_.sentAsAlert = $true + } else { + $_ | Add-Member -MemberType NoteProperty -Name sentAsAlert -Value $true -Force + } + $_ + } + if ($UpdateLogs) { + Add-CIPPAzDataTableEntity @Table -Entity $UpdateLogs -Force + } } } if ($CurrentStandardsLogs) { @@ -88,7 +110,7 @@ function Push-SchedulerCIPPNotifications { if ($Currentlog) { $JSONContent = $Currentlog | ConvertTo-Json -Compress Send-CIPPAlert -Type 'webhook' -JSONContent $JSONContent -TenantFilter $Tenant -APIName 'Alerts' - $UpdateLogs = $CurrentLog | ForEach-Object { $_.SentAsAlert = $true; $_ } + $UpdateLogs = $CurrentLog | ForEach-Object { $_.sentAsAlert = $true; $_ } if ($UpdateLogs) { Add-CIPPAzDataTableEntity @Table -Entity $UpdateLogs -Force } } diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 index 6c8a5f518e20..c47827703549 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 @@ -3,7 +3,7 @@ function Write-LogMessage { .FUNCTIONALITY Internal #> - Param( + param( $message, $tenant = 'None', $API = 'None', @@ -51,7 +51,7 @@ function Write-LogMessage { 'Message' = [string]$message 'Username' = [string]$username 'Severity' = [string]$sev - 'SentAsAlert' = $false + 'sentAsAlert' = $false 'PartitionKey' = [string]$PartitionKey 'RowKey' = [string]([guid]::NewGuid()).ToString() 'FunctionNode' = [string]$env:WEBSITE_SITE_NAME From 2b049504aff8dd08bb4a08a43c5fa04e8d6a4e6f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 May 2025 14:13:04 -0400 Subject: [PATCH 083/149] update editintunescript to support other script types --- .../Endpoint/MEM/Invoke-EditIntuneScript.ps1 | 119 ++++++++++++++---- 1 file changed, 97 insertions(+), 22 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-EditIntuneScript.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-EditIntuneScript.ps1 index 138c59f7a51b..715bdd7b3c52 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-EditIntuneScript.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-EditIntuneScript.ps1 @@ -14,35 +14,110 @@ function Invoke-EditIntuneScript { $Headers = $Request.Headers Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev Debug - $graphUrl = "https://graph.microsoft.com/beta" - switch($Request.Method) { - "GET" { - $parms = @{ - uri = "$graphUrl/deviceManagement/deviceManagementScripts/$($Request.Query.ScriptId)" - tenantid = $Request.Query.TenantFilter + $graphUrl = 'https://graph.microsoft.com/beta' + + # Define the endpoint based on script type + function Get-ScriptEndpoint { + param ( + [Parameter(Mandatory = $true)] + [string]$ScriptType + ) + + switch ($ScriptType) { + 'Windows' { return 'deviceManagement/deviceManagementScripts' } + 'MacOS' { return 'deviceManagement/deviceShellScripts' } + 'Remediation' { return 'deviceManagement/deviceHealthScripts' } + 'Linux' { return 'deviceManagement/configurationPolicies' } + default { return 'deviceManagement/deviceManagementScripts' } + } + } + + switch ($Request.Method) { + 'GET' { + # First get the script type by querying the script ID + $scriptId = $Request.Query.ScriptId + $scriptTypeFound = $false + + # Try each endpoint to find the script + foreach ($scriptType in @('Windows', 'MacOS', 'Remediation', 'Linux')) { + $endpoint = Get-ScriptEndpoint -ScriptType $scriptType + $parms = @{ + uri = "$graphUrl/$endpoint/$scriptId" + tenantid = $Request.Query.TenantFilter + } + + try { + $intuneScript = New-GraphGetRequest @parms -ErrorAction Stop + if ($intuneScript) { + $intuneScript | Add-Member -MemberType NoteProperty -Name scriptType -Value $scriptType -Force + $scriptTypeFound = $true + break + } + } catch { + # Script not found in this endpoint, try next one + continue + } } - $intuneScript = New-GraphGetRequest @parms - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $intuneScript - }) + if ($scriptTypeFound) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $intuneScript + }) + } else { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::NotFound + Body = "Script with ID $scriptId was not found in any endpoint." + }) + } } - "PATCH" { + 'PATCH' { + # Parse the script data to determine type + $scriptData = $Request.Body.IntuneScript | ConvertFrom-Json + $scriptType = $Request.Body.ScriptType + + if (-not $scriptType) { + # Try to determine script type from the request body + if ($scriptData.PSObject.Properties.Name -contains '@odata.type') { + switch ($scriptData.'@odata.type') { + '#microsoft.graph.deviceManagementScript' { $scriptType = 'Windows' } + '#microsoft.graph.deviceShellScript' { $scriptType = 'MacOS' } + '#microsoft.graph.deviceHealthScript' { $scriptType = 'Remediation' } + default { + if ($scriptData.platforms -eq 'linux' -and $scriptData.templateReference.templateFamily -eq 'deviceConfigurationScripts') { + $scriptType = 'Linux' + } else { + $scriptType = 'Windows' # Default to Windows if no definitive type found + } + } + } + } + } + + $endpoint = Get-ScriptEndpoint -ScriptType $scriptType $parms = @{ - uri = "$graphUrl/deviceManagement/deviceManagementScripts/$($Request.Body.ScriptId)" + uri = "$graphUrl/$endpoint/$($Request.Body.ScriptId)" tenantid = $Request.Body.TenantFilter - body = $Request.Body.IntuneScript + body = $Request.Body.IntuneScript + } + + try { + $patchResult = New-GraphPOSTRequest @parms -type 'PATCH' + $body = [pscustomobject]@{'Results' = $patchResult } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = "Failed to update script: $($ErrorMessage.NormalizedError)" + }) } - $patchResult = New-GraphPOSTRequest @parms -type "PATCH" - $body = [pscustomobject]@{'Results' = $patchResult } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) } - "POST" { - Write-Output "Adding script" + 'POST' { + Write-Output 'Adding script' } } } From a65b81a5a77901f3bd8265d6eea13570589ed2a1 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 21 May 2025 21:41:23 +0200 Subject: [PATCH 084/149] notification fixes --- .../CIPP/Core/Invoke-ExecAddAlert.ps1 | 15 ++++++++ .../Invoke-ExecNotificationConfig.ps1 | 36 ++++-------------- .../Public/Set-CIPPNotificationConfig.ps1 | 38 +++++++++++++++++++ 3 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 Modules/CIPPCore/Public/Set-CIPPNotificationConfig.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 index f93622fee27c..13d70f847619 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 @@ -17,6 +17,21 @@ function Invoke-ExecAddAlert { $Severity = 'Alert' $Result = if ($Request.Body.sendEmailNow -or $Request.Body.sendWebhookNow -eq $true -or $Request.Body.writeLog -eq $true -or $Request.Body.sendPsaNow -eq $true) { + $sev = ([pscustomobject]$Request.body.Severity).value -join (',') + if ($Request.body.email -or $Request.body.webhook) { + Write-Host 'found config, setting' + $config = @{ + email = $Request.body.email + webhook = $Request.body.webhook + onepertenant = $Request.body.onePerTenant + logsToInclude = $Request.body.logsToInclude + sendtoIntegration = $true + sev = $sev + } + Write-Host "setting notification config to $($config | ConvertTo-Json)" + $Results = Set-cippNotificationConfig @Config + Write-Host $Results + } $Title = 'CIPP Notification Test' if ($Request.Body.sendEmailNow -eq $true) { $CIPPAlert = @{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 index 8436f9152a1f..c05eb0e58b01 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 @@ -14,36 +14,16 @@ Function Invoke-ExecNotificationConfig { $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - - $sev = ([pscustomobject]$Request.body.Severity).value -join (',') - $results = try { - $Table = Get-CIPPTable -TableName SchedulerConfig - $SchedulerConfig = @{ - 'tenant' = 'Any' - 'tenantid' = 'TenantId' - 'type' = 'CIPPNotifications' - 'schedule' = 'Every 15 minutes' - 'Severity' = [string]$sev - 'email' = "$($Request.Body.email)" - 'webhook' = "$($Request.Body.webhook)" - 'onePerTenant' = [boolean]$Request.Body.onePerTenant - 'sendtoIntegration' = [boolean]$Request.Body.sendtoIntegration - 'includeTenantId' = [boolean]$Request.Body.includeTenantId - 'PartitionKey' = 'CippNotifications' - 'RowKey' = 'CippNotifications' - } - foreach ($logvalue in [pscustomobject]$Request.body.logsToInclude) { - $SchedulerConfig[([pscustomobject]$logvalue.value)] = $true - } - - Add-CIPPAzDataTableEntity @Table -Entity $SchedulerConfig -Force | Out-Null - 'Successfully set the configuration' - } catch { - "Failed to set configuration: $($_.Exception.message)" + $config = @{ + email = $Request.body.email + webhook = $Request.body.webhook + onepertenant = $Request.body.onePerTenant + logsToInclude = $Request.body.logsToInclude + sendtoIntegration = $Request.body.sendtoIntegration + sev = $sev } - - + $Results = Set-cippNotificationConfig @Config $body = [pscustomobject]@{'Results' = $Results } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Set-CIPPNotificationConfig.ps1 b/Modules/CIPPCore/Public/Set-CIPPNotificationConfig.ps1 new file mode 100644 index 000000000000..7c6acb63d582 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPNotificationConfig.ps1 @@ -0,0 +1,38 @@ +function Set-CIPPNotificationConfig { + [CmdletBinding()] + param ( + $email, + $webhook, + $onepertenant, + $logsToInclude, + $sendtoIntegration, + $sev, + $APIName = 'Set Notification Config' + ) + + $results = try { + $Table = Get-CIPPTable -TableName SchedulerConfig + $SchedulerConfig = @{ + 'tenant' = 'Any' + 'tenantid' = 'TenantId' + 'type' = 'CIPPNotifications' + 'schedule' = 'Every 15 minutes' + 'Severity' = [string]$sev + 'email' = "$($email)" + 'webhook' = "$($webhook)" + 'onePerTenant' = [boolean]$onePerTenant + 'sendtoIntegration' = [boolean]$sendtoIntegration + 'includeTenantId' = $true + 'PartitionKey' = 'CippNotifications' + 'RowKey' = 'CippNotifications' + } + foreach ($logvalue in [pscustomobject]$logsToInclude) { + $SchedulerConfig[([pscustomobject]$logvalue.value)] = $true + } + + Add-CIPPAzDataTableEntity @Table -Entity $SchedulerConfig -Force | Out-Null + return 'Successfully set the configuration' + } catch { + return "Failed to set configuration: $($_.Exception.message)" + } +} From 02be9d3cf15e5e39e800542205f4b6b65d7be852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 16 May 2025 19:27:54 +0200 Subject: [PATCH 085/149] progress stuffs --- .../Push-ExecJITAdminListAllTenants.ps1 | 113 +++++++++++++ .../Users/Invoke-ExecJITAdmin.ps1 | 149 +++++++++++++----- .../Public/Test-CIPPAccessPermissions.ps1 | 2 +- 3 files changed, 226 insertions(+), 38 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecJITAdminListAllTenants.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecJITAdminListAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecJITAdminListAllTenants.ps1 new file mode 100644 index 000000000000..2fae0e12a319 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecJITAdminListAllTenants.ps1 @@ -0,0 +1,113 @@ +function Push-ExecJITAdminListAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + param($Item) + + $Tenant = Get-Tenants -TenantFilter $Item.customerId + $DomainName = $Tenant.defaultDomainName + Write-Host "Processing push queue for JIT Admin for tenant: $DomainName" + $Table = Get-CIPPTable -TableName CacheJITAdmin + + try { + # Get schema extensions + $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } | Select-Object -First 1 + + # Query users with JIT Admin enabled + $Query = @{ + TenantFilter = $DomainName # Use $DomainName for the current tenant + Endpoint = 'users' + Parameters = @{ + '$count' = 'true' + '$select' = "id,accountEnabled,displayName,userPrincipalName,$($Schema.id)" + '$filter' = "$($Schema.id)/jitAdminEnabled eq true or $($Schema.id)/jitAdminEnabled eq false" # Fetches both states to cache current status + } + } + $Users = Get-GraphRequestList @Query | Where-Object { $_.id } + + if ($Users) { + # Get role memberships + $BulkRequests = $Users | ForEach-Object { @( + @{ + id = $_.id + method = 'GET' + url = "users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName" + } + ) + } + # Ensure $BulkRequests is not empty or null before making the bulk request + if ($BulkRequests -and $BulkRequests.Count -gt 0) { + $RoleResults = New-GraphBulkRequest -tenantid $DomainName -Requests @($BulkRequests) + + # Format the data + $Results = $Users | ForEach-Object { + $currentUser = $_ # Capture current user in the loop + $MemberOf = @() # Initialize as empty array + if ($RoleResults) { + $userRoleResult = $RoleResults | Where-Object -Property id -EQ $currentUser.id + if ($userRoleResult -and $userRoleResult.body -and $userRoleResult.body.value) { + $MemberOf = $userRoleResult.body.value | Select-Object displayName, id + } + } + + $jitAdminData = $currentUser.($Schema.id) + $jitAdminEnabled = if ($jitAdminData -and $jitAdminData.PSObject.Properties['jitAdminEnabled']) { $jitAdminData.jitAdminEnabled } else { $false } + $jitAdminExpiration = if ($jitAdminData -and $jitAdminData.PSObject.Properties['jitAdminExpiration']) { $jitAdminData.jitAdminExpiration } else { $null } + + [PSCustomObject]@{ + id = $currentUser.id + displayName = $currentUser.displayName + userPrincipalName = $currentUser.userPrincipalName + accountEnabled = $currentUser.accountEnabled + jitAdminEnabled = $jitAdminEnabled + jitAdminExpiration = $jitAdminExpiration + memberOf = ($MemberOf | ConvertTo-Json -Depth 5 -Compress) # Store as JSON string + } + } + + # Add to Azure Table + foreach ($result in $Results) { + $GUID = (New-Guid).Guid + $GraphRequest = @{ + JITAdminUser = ($result | ConvertTo-Json -Depth 10 -Compress) + RowKey = [string]$GUID + PartitionKey = 'JITAdminUsers' # Use the specified partition key + Tenant = [string]$DomainName + UserId = [string]$result.id # Add UserId for easier querying if needed + UserUPN = [string]$result.userPrincipalName # Add UserUPN for easier querying + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + } + } else { + # No users with JIT Admin attributes found, or no users at all + Write-Host "No JIT Admin users or no users found to process for tenant $DomainName." + } + } else { + Write-Host "No users found for tenant $DomainName." + } + + } catch { + $GUID = (New-Guid).Guid + $ErrorRecord = $_ | Select-Object * + $ErrorMessage = "Could not process JIT Admin users for Tenant: $($DomainName). Error: $($_.Exception.Message)" + if ($_.ScriptStackTrace) { + $ErrorMessage += " StackTrace: $($_.ScriptStackTrace)" + } + $ErrorJson = ConvertTo-Json -InputObject @{ + Tenant = $DomainName + Error = $ErrorMessage + Exception = ($_.Exception | ConvertTo-Json -Depth 3 -Compress) + FullError = ($ErrorRecord | ConvertTo-Json -Depth 3 -Compress) + Timestamp = (Get-Date).ToString('s') + } + $GraphRequest = @{ + JITAdminUserError = [string]$ErrorJson + RowKey = [string]$GUID + PartitionKey = 'JITAdminUsers_Error' # Differentiate errors + Tenant = [string]$DomainName + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + Write-Error ('Error processing JIT Admin for {0}: {1}' -f $DomainName, $_.Exception.Message) + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 index 3e008bc1b898..1e57e32559a8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 @@ -10,51 +10,126 @@ function Invoke-ExecJITAdmin { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = 'ExecJITAdmin' + $APIName = $Request.Params.CIPPEndpoint $User = $Request.Headers - $TenantFilter = $Request.body.TenantFilter.value ? $Request.body.TenantFilter.value : $Request.body.TenantFilter - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Body.tenantFilter.value ? $Request.Body.tenantFilter.value : $Request.Body.tenantFilter + Write-LogMessage -Headers $User -API $APIName -message 'Accessed this API' -Sev 'Debug' if ($Request.Query.Action -eq 'List') { $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } | Select-Object -First 1 - $Query = @{ - TenantFilter = $Request.Query.TenantFilter - Endpoint = 'users' - Parameters = @{ - '$count' = 'true' - '$select' = "id,accountEnabled,displayName,userPrincipalName,$($Schema.id)" - '$filter' = "$($Schema.id)/jitAdminEnabled eq true or $($Schema.id)/jitAdminEnabled eq false" + if ($TenantFilter -ne 'AllTenants') { + $Query = @{ + TenantFilter = $Request.Query.TenantFilter + Endpoint = 'users' + Parameters = @{ + '$count' = 'true' + '$select' = "id,accountEnabled,displayName,userPrincipalName,$($Schema.id)" + '$filter' = "$($Schema.id)/jitAdminEnabled eq true or $($Schema.id)/jitAdminEnabled eq false" + } } - } - $Users = Get-GraphRequestList @Query | Where-Object { $_.id } - $BulkRequests = $Users | ForEach-Object { @( - @{ - id = $_.id - method = 'GET' - url = "users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName" + $Users = Get-GraphRequestList @Query | Where-Object { $_.id } + $BulkRequests = $Users | ForEach-Object { @( + @{ + id = $_.id + method = 'GET' + url = "users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName" + } + ) + } + # Use $TenantFilter consistently, which is derived from Body or Query params at line 15 + $RoleResults = New-GraphBulkRequest -tenantid $Request.Query.TenantFilter -Requests @($BulkRequests) + #Write-Information ($RoleResults | ConvertTo-Json -Depth 10 ) + $Results = $Users | ForEach-Object { + $MemberOf = ($RoleResults | Where-Object -Property id -EQ $_.id).body.value | Select-Object displayName, id + [PSCustomObject]@{ + id = $_.id + displayName = $_.displayName + userPrincipalName = $_.userPrincipalName + accountEnabled = $_.accountEnabled + jitAdminEnabled = $_.($Schema.id).jitAdminEnabled + jitAdminExpiration = $_.($Schema.id).jitAdminExpiration + memberOf = $MemberOf } - ) - } - $RoleResults = New-GraphBulkRequest -tenantid $Request.Query.TenantFilter -Requests @($BulkRequests) - #Write-Information ($RoleResults | ConvertTo-Json -Depth 10 ) - $Results = $Users | ForEach-Object { - $MemberOf = ($RoleResults | Where-Object -Property id -EQ $_.id).body.value | Select-Object displayName, id - [PSCustomObject]@{ - id = $_.id - displayName = $_.displayName - userPrincipalName = $_.userPrincipalName - accountEnabled = $_.accountEnabled - jitAdminEnabled = $_.($Schema.id).jitAdminEnabled - jitAdminExpiration = $_.($Schema.id).jitAdminExpiration - memberOf = $MemberOf } - } - #Write-Information ($Results | ConvertTo-Json -Depth 10) - $Body = @{ - Results = @($Results) - Metadata = @{ - Parameters = $Query.Parameters + #Write-Information ($Results | ConvertTo-Json -Depth 10) + $Body = @{ + Results = @($Results) + Metadata = @{ + Parameters = $Query.Parameters + } + } + } else { + # AllTenants logic + $Results = [System.Collections.Generic.List[object]]::new() + $Metadata = @{} + # Assumed table name for JIT Admin cache. User might need to adjust. + $Table = Get-CIPPTable -TableName CacheJITAdmin + $PartitionKey = 'JITAdminUsers' # Assumed partition key + + # Filter for recent data, e.g., last 60 minutes. Orchestrator populates this. + $Filter = "PartitionKey eq '$PartitionKey'" + $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-1) + + $QueueReference = '{0}-{1}' -f $Request.Query.TenantFilter, $PartitionKey # $TenantFilter is 'AllTenants' + $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -notmatch 'Completed' -and $_.Status -notmatch 'Failed' } + + if ($RunningQueue) { + $Metadata = [PSCustomObject]@{ + QueueMessage = 'Still loading JIT Admin data for all tenants. Please check back in a few more minutes.' + } + $Results.Add([PSCustomObject]@{ Waiting = $true }) + } elseif (!$dRows -and !$RunningQueue) { + $TenantList = Get-Tenants -IncludeErrors + $QueueLink = if ($Request.RequestUri) { $Request.RequestUri.ToString() -replace $Request.Query.Action, 'List' } else { '/identity/administration/users/jit-admin?Action=List&TenantFilter=AllTenants' } # Fallback link + $Queue = New-CippQueueEntry -Name 'JIT Admin List - All Tenants' -Link $QueueLink -Reference $QueueReference -TotalTasks ($TenantList | Measure-Object).Count + + $Metadata = [PSCustomObject]@{ + QueueMessage = 'Loading JIT Admin data for all tenants. Please check back in a few minutes.' + } + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'JITAdminListAllTenantsOrchestrator' # Assumed orchestrator name + QueueFunction = @{ + FunctionName = 'GetTenants' # Generic entry, durable function handles per-tenant logic + QueueId = $Queue.RowKey + TenantParams = @{ + IncludeErrors = $true + } + DurableName = 'ExecJITAdminListAllTenants' + } + SkipLog = $true + } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) + $Results.Add([PSCustomObject]@{ Waiting = $true }) + } else { + # $dRows exist + foreach ($row in $Rows) { + # Assuming $row.JITUserObject contains the serialized PSCustomObject for the user's JIT details + # And $row.TenantId (or $row.TenantDisplayName) contains the tenant identifier + try { + $UserObject = $row.JITUserObject | ConvertFrom-Json + $Results.Add( + [PSCustomObject]@{ + Tenant = $row.TenantId # Or TenantDisplayName, ensure orchestrator stores this + id = $UserObject.id + displayName = $UserObject.displayName + userPrincipalName = $UserObject.userPrincipalName + accountEnabled = $UserObject.accountEnabled + jitAdminEnabled = $UserObject.jitAdminEnabled + jitAdminExpiration = $UserObject.jitAdminExpiration + memberOf = $UserObject.memberOf # This should be an array of role objects + } + ) + } catch { + Write-LogMessage -Headers $User -API $APIName -message "Failed to process cached JIT admin row for Tenant $($row.TenantId), RowKey $($row.RowKey). Error: $($_.Exception.Message)" -Sev 'Warning' + # Optionally add a placeholder or skip if critical + } + } + $Metadata = @{ Info = 'Displaying cached JIT Admin data for all tenants.' } + } + $Body = @{ + Results = @($Results) + Metadata = $Metadata } } } else { diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 index 8aab1f89a830..6dc103ab667e 100644 --- a/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 @@ -133,7 +133,7 @@ function Test-CIPPAccessPermissions { $ApplicationToken = Get-GraphToken -returnRefresh $true -SkipCache $true -AsApp $true $ApplicationTokenDetails = Read-JwtAccessDetails -Token $ApplicationToken.access_token -erroraction SilentlyContinue | Select-Object - $LastUpdate = [DateTime]::SpecifyKind($GraphPermissions.Timestamp.DateTime, [DateTimeKind]::Utc) + $LastUpdate = [DateTime]::SpecifyKind($GraphPermissions.Timestamp.ToString('yyyy-MM-ddTHH:mm:ssZ'), [DateTimeKind]::Utc) $CpvTable = Get-CippTable -tablename 'cpvtenants' $CpvRefresh = Get-CippAzDataTableEntity @CpvTable -Filter "PartitionKey eq 'Tenant'" $TenantList = Get-Tenants -IncludeErrors | Where-Object { $_.customerId -ne $env:TenantID -and $_.Excluded -eq $false } From 732ad866f0309845a9759cbcad841efda91738ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 21 May 2025 22:29:29 +0200 Subject: [PATCH 086/149] feat:Make JIT admin support all tenants view --- .../Push-ExecJITAdminListAllTenants.ps1 | 20 +++---- .../Users/Invoke-ExecJITAdmin.ps1 | 60 ++++++++----------- 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecJITAdminListAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecJITAdminListAllTenants.ps1 index 2fae0e12a319..0f14c76645ab 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecJITAdminListAllTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecJITAdminListAllTenants.ps1 @@ -7,7 +7,6 @@ function Push-ExecJITAdminListAllTenants { $Tenant = Get-Tenants -TenantFilter $Item.customerId $DomainName = $Tenant.defaultDomainName - Write-Host "Processing push queue for JIT Admin for tenant: $DomainName" $Table = Get-CIPPTable -TableName CacheJITAdmin try { @@ -62,17 +61,18 @@ function Push-ExecJITAdminListAllTenants { accountEnabled = $currentUser.accountEnabled jitAdminEnabled = $jitAdminEnabled jitAdminExpiration = $jitAdminExpiration - memberOf = ($MemberOf | ConvertTo-Json -Depth 5 -Compress) # Store as JSON string + memberOf = ($MemberOf | ConvertTo-Json -Depth 5 -Compress) } } # Add to Azure Table foreach ($result in $Results) { $GUID = (New-Guid).Guid + Write-Host ($result | ConvertTo-Json -Depth 10 -Compress) $GraphRequest = @{ - JITAdminUser = ($result | ConvertTo-Json -Depth 10 -Compress) + JITAdminUser = [string]($result | ConvertTo-Json -Depth 10 -Compress) RowKey = [string]$GUID - PartitionKey = 'JITAdminUsers' # Use the specified partition key + PartitionKey = 'JITAdminUser' Tenant = [string]$DomainName UserId = [string]$result.id # Add UserId for easier querying if needed UserUPN = [string]$result.userPrincipalName # Add UserUPN for easier querying @@ -89,7 +89,6 @@ function Push-ExecJITAdminListAllTenants { } catch { $GUID = (New-Guid).Guid - $ErrorRecord = $_ | Select-Object * $ErrorMessage = "Could not process JIT Admin users for Tenant: $($DomainName). Error: $($_.Exception.Message)" if ($_.ScriptStackTrace) { $ErrorMessage += " StackTrace: $($_.ScriptStackTrace)" @@ -97,15 +96,14 @@ function Push-ExecJITAdminListAllTenants { $ErrorJson = ConvertTo-Json -InputObject @{ Tenant = $DomainName Error = $ErrorMessage - Exception = ($_.Exception | ConvertTo-Json -Depth 3 -Compress) - FullError = ($ErrorRecord | ConvertTo-Json -Depth 3 -Compress) + Exception = ($_.Exception.Message | ConvertTo-Json -Depth 3 -Compress) Timestamp = (Get-Date).ToString('s') } $GraphRequest = @{ - JITAdminUserError = [string]$ErrorJson - RowKey = [string]$GUID - PartitionKey = 'JITAdminUsers_Error' # Differentiate errors - Tenant = [string]$DomainName + JITAdminUser = [string]$ErrorJson + RowKey = [string]$GUID + PartitionKey = 'JITAdminUser' + Tenant = [string]$DomainName } Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null Write-Error ('Error processing JIT Admin for {0}: {1}' -f $DomainName, $_.Exception.Message) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 index 1e57e32559a8..e67fb1cb32d0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 @@ -17,7 +17,8 @@ function Invoke-ExecJITAdmin { if ($Request.Query.Action -eq 'List') { $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } | Select-Object -First 1 - if ($TenantFilter -ne 'AllTenants') { + if ($Request.Query.TenantFilter -ne 'AllTenants') { + # Single tenant logic $Query = @{ TenantFilter = $Request.Query.TenantFilter Endpoint = 'users' @@ -36,7 +37,6 @@ function Invoke-ExecJITAdmin { } ) } - # Use $TenantFilter consistently, which is derived from Body or Query params at line 15 $RoleResults = New-GraphBulkRequest -tenantid $Request.Query.TenantFilter -Requests @($BulkRequests) #Write-Information ($RoleResults | ConvertTo-Json -Depth 10 ) $Results = $Users | ForEach-Object { @@ -63,34 +63,30 @@ function Invoke-ExecJITAdmin { # AllTenants logic $Results = [System.Collections.Generic.List[object]]::new() $Metadata = @{} - # Assumed table name for JIT Admin cache. User might need to adjust. $Table = Get-CIPPTable -TableName CacheJITAdmin - $PartitionKey = 'JITAdminUsers' # Assumed partition key - - # Filter for recent data, e.g., last 60 minutes. Orchestrator populates this. + $PartitionKey = 'JITAdminUser' $Filter = "PartitionKey eq '$PartitionKey'" - $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-1) + $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-60) $QueueReference = '{0}-{1}' -f $Request.Query.TenantFilter, $PartitionKey # $TenantFilter is 'AllTenants' + Write-Information "QueueReference: $QueueReference" $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -notmatch 'Completed' -and $_.Status -notmatch 'Failed' } if ($RunningQueue) { $Metadata = [PSCustomObject]@{ QueueMessage = 'Still loading JIT Admin data for all tenants. Please check back in a few more minutes.' } - $Results.Add([PSCustomObject]@{ Waiting = $true }) - } elseif (!$dRows -and !$RunningQueue) { + } elseif (!$Rows -and !$RunningQueue) { $TenantList = Get-Tenants -IncludeErrors - $QueueLink = if ($Request.RequestUri) { $Request.RequestUri.ToString() -replace $Request.Query.Action, 'List' } else { '/identity/administration/users/jit-admin?Action=List&TenantFilter=AllTenants' } # Fallback link - $Queue = New-CippQueueEntry -Name 'JIT Admin List - All Tenants' -Link $QueueLink -Reference $QueueReference -TotalTasks ($TenantList | Measure-Object).Count + $Queue = New-CippQueueEntry -Name 'JIT Admin List - All Tenants' -Link '/identity/administration/jit-admin?tenantFilter=AllTenants' -Reference $QueueReference -TotalTasks ($TenantList | Measure-Object).Count $Metadata = [PSCustomObject]@{ QueueMessage = 'Loading JIT Admin data for all tenants. Please check back in a few minutes.' } $InputObject = [PSCustomObject]@{ - OrchestratorName = 'JITAdminListAllTenantsOrchestrator' # Assumed orchestrator name + OrchestratorName = 'JITAdminOrchestrator' QueueFunction = @{ - FunctionName = 'GetTenants' # Generic entry, durable function handles per-tenant logic + FunctionName = 'GetTenants' QueueId = $Queue.RowKey TenantParams = @{ IncludeErrors = $true @@ -100,32 +96,24 @@ function Invoke-ExecJITAdmin { SkipLog = $true } Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) - $Results.Add([PSCustomObject]@{ Waiting = $true }) } else { - # $dRows exist + # There is data in the cache, so we will use that + Write-Information "Found $($Rows.Count) rows in the cache" foreach ($row in $Rows) { - # Assuming $row.JITUserObject contains the serialized PSCustomObject for the user's JIT details - # And $row.TenantId (or $row.TenantDisplayName) contains the tenant identifier - try { - $UserObject = $row.JITUserObject | ConvertFrom-Json - $Results.Add( - [PSCustomObject]@{ - Tenant = $row.TenantId # Or TenantDisplayName, ensure orchestrator stores this - id = $UserObject.id - displayName = $UserObject.displayName - userPrincipalName = $UserObject.userPrincipalName - accountEnabled = $UserObject.accountEnabled - jitAdminEnabled = $UserObject.jitAdminEnabled - jitAdminExpiration = $UserObject.jitAdminExpiration - memberOf = $UserObject.memberOf # This should be an array of role objects - } - ) - } catch { - Write-LogMessage -Headers $User -API $APIName -message "Failed to process cached JIT admin row for Tenant $($row.TenantId), RowKey $($row.RowKey). Error: $($_.Exception.Message)" -Sev 'Warning' - # Optionally add a placeholder or skip if critical - } + $UserObject = $row.JITAdminUser | ConvertFrom-Json + $Results.Add( + [PSCustomObject]@{ + Tenant = $row.Tenant + id = $UserObject.id + displayName = $UserObject.displayName + userPrincipalName = $UserObject.userPrincipalName + accountEnabled = $UserObject.accountEnabled + jitAdminEnabled = $UserObject.jitAdminEnabled + jitAdminExpiration = $UserObject.jitAdminExpiration + memberOf = $UserObject.memberOf + } + ) } - $Metadata = @{ Info = 'Displaying cached JIT Admin data for all tenants.' } } $Body = @{ Results = @($Results) From 46cc031fe90a38dcffd6287075ddc706e79a03b9 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 May 2025 17:13:09 -0400 Subject: [PATCH 087/149] fix CA check --- .../Tenant/Conditional/Invoke-ExecCACheck.ps1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCACheck.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCACheck.ps1 index b18528966f52..31a2a7694476 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCACheck.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCACheck.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecCaCheck { +function Invoke-ExecCaCheck { <# .FUNCTIONALITY Entrypoint @@ -23,18 +23,18 @@ Function Invoke-ExecCaCheck { } $results = try { $CAContext = @{ - '@odata.type' = '#microsoft.graph.whatIfApplicationContext' + '@odata.type' = '#microsoft.graph.applicationContext' 'includeApplications' = @($IncludeApplications) } $ConditionalAccessWhatIfDefinition = @{ - 'conditionalAccessWhatIfSubject' = @{ - '@odata.type' = '#microsoft.graph.userSubject' + 'signInIdentity' = @{ + '@odata.type' = '#microsoft.graph.userSignIn' 'userId' = "$userId" } - 'conditionalAccessContext' = $CAContext - 'conditionalAccessWhatIfConditions' = @{} + 'signInContext' = $CAContext + 'signInConditions' = @{} } - $whatIfConditions = $ConditionalAccessWhatIfDefinition.conditionalAccessWhatIfConditions + $whatIfConditions = $ConditionalAccessWhatIfDefinition.signInConditions if ($Request.body.UserRiskLevel) { $whatIfConditions.userRiskLevel = $Request.body.UserRiskLevel.value } if ($Request.body.SignInRiskLevel) { $whatIfConditions.signInRiskLevel = $Request.body.SignInRiskLevel.value } if ($Request.body.ClientAppType) { $whatIfConditions.clientAppType = $Request.body.ClientAppType.value } From 3e8c11f6872b536dc223e767a53b895b531035fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 21 May 2025 23:45:51 +0200 Subject: [PATCH 088/149] feat: add allTenants support for transport rules page --- .../Push-ListTransportRulesAllTenants.ps1 | 42 ++++++++++++ .../Transport/Invoke-ListTransportRules.ps1 | 65 +++++++++++++++++-- 2 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListTransportRulesAllTenants.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListTransportRulesAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListTransportRulesAllTenants.ps1 new file mode 100644 index 000000000000..2db1afecabcd --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListTransportRulesAllTenants.ps1 @@ -0,0 +1,42 @@ +function Push-ListTransportRulesAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + param($Item) + + $Tenant = Get-Tenants -TenantFilter $Item.customerId + $DomainName = $Tenant.defaultDomainName + $Table = Get-CIPPTable -TableName CacheTransportRules + + try { + $TransportRules = New-ExoRequest -tenantid $DomainName -cmdlet 'Get-TransportRule' + $Results = foreach ($rule in $TransportRules) { + $GUID = (New-Guid).Guid + $Results = @{ + TransportRule = [string]($rule | ConvertTo-Json -Depth 10) + RowKey = [string]$GUID + PartitionKey = 'TransportRule' + Tenant = [string]$DomainName + } + Add-CIPPAzDataTableEntity @Table -Entity $Results -Force | Out-Null + } + + } catch { + $GUID = (New-Guid).Guid + $ErrorText = ConvertTo-Json -InputObject @{ + Tenant = $DomainName + Name = "Could not connect to Tenant: $($_.Exception.Message)" + State = 'Error' + Priority = 0 + Description = "Error retrieving transport rules: $($_.Exception.Message)" + } + $Results = @{ + TransportRule = [string]$ErrorText + RowKey = [string]$GUID + PartitionKey = 'TransportRule' + Tenant = [string]$DomainName + } + Add-CIPPAzDataTableEntity @Table -Entity $Results -Force | Out-Null + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRules.ps1 index 227bfd6fd8b8..3f4b5c65e019 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRules.ps1 @@ -13,21 +13,76 @@ Function Invoke-ListTransportRules { $APIName = $Request.Params.CIPPEndpoint $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $TenantFilter = $request.Query.tenantFilter + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter try { - $GraphRequest = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-TransportRule' + $Results = if ($TenantFilter -ne 'AllTenants') { + # Single tenant functionality + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-TransportRule' + } else { + # AllTenants functionality + $Table = Get-CIPPTable -TableName CacheTransportRules + $PartitionKey = 'TransportRule' + $Filter = "PartitionKey eq '$PartitionKey'" + $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-60) + $QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey + $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -notmatch 'Completed' -and $_.Status -notmatch 'Failed' } + + # If a queue is running, we will not start a new one + if ($RunningQueue) { + $Metadata = [PSCustomObject]@{ + QueueMessage = 'Still loading transport rules for all tenants. Please check back in a few more minutes' + } + } elseif (!$Rows -and !$RunningQueue) { + # If no rows are found and no queue is running, we will start a new one + $TenantList = Get-Tenants -IncludeErrors + $Queue = New-CippQueueEntry -Name 'Transport Rules - All Tenants' -Link '/email/transport/list-rules?tenantFilter=AllTenants' -Reference $QueueReference -TotalTasks ($TenantList | Measure-Object).Count + $Metadata = [PSCustomObject]@{ + QueueMessage = 'Loading transport rules for all tenants. Please check back in a few minutes' + } + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'TransportRuleOrchestrator' + QueueFunction = @{ + FunctionName = 'GetTenants' + QueueId = $Queue.RowKey + TenantParams = @{ + IncludeErrors = $true + } + DurableName = 'ListTransportRulesAllTenants' + } + SkipLog = $true + } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) | Out-Null + } else { + # Return cached data + $Rules = $Rows + foreach ($rule in $Rules) { + $RuleObj = $rule.TransportRule | ConvertFrom-Json + $RuleObj | Add-Member -MemberType NoteProperty -Name Tenant -Value $rule.Tenant -Force + $RuleObj + } + } + } $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage + $Body = $ErrorMessage + } + + # If the body is not set by an error, we will set it here + if (!$Body) { + $Body = [PSCustomObject]@{ + Results = @($Results) + Metadata = $Metadata + } } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = @($GraphRequest) + Body = $Body }) - } From 564071080d590a1f5278b2e88681df57bb54a99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 21 May 2025 23:46:06 +0200 Subject: [PATCH 089/149] Fix up and make a bit prettier --- .../Security/Invoke-ExecIncidentsList.ps1 | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 index dec4a61c2211..5a3991b4df41 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 @@ -19,9 +19,10 @@ Function Invoke-ExecIncidentsList { try { $GraphRequest = if ($TenantFilter -ne 'AllTenants') { - $incidents = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/incidents' -tenantid $TenantFilter -AsApp $true + # Single tenant functionality + $Incidents = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/incidents' -tenantid $TenantFilter -AsApp $true - foreach ($incident in $incidents) { + foreach ($incident in $Incidents) { [PSCustomObject]@{ Tenant = $TenantFilter Id = $incident.id @@ -40,6 +41,7 @@ Function Invoke-ExecIncidentsList { } } } else { + # AllTenants functionality $Table = Get-CIPPTable -TableName cachealertsandincidents $PartitionKey = 'Incident' $Filter = "PartitionKey eq '$PartitionKey'" @@ -51,9 +53,6 @@ Function Invoke-ExecIncidentsList { $Metadata = [PSCustomObject]@{ QueueMessage = 'Still loading data for all tenants. Please check back in a few more minutes' } - [PSCustomObject]@{ - Waiting = $true - } } elseif (!$Rows -and !$RunningQueue) { # If no rows are found and no queue is running, we will start a new one $TenantList = Get-Tenants -IncludeErrors @@ -73,13 +72,10 @@ Function Invoke-ExecIncidentsList { } SkipLog = $true } - Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) - [PSCustomObject]@{ - Waiting = $true - } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) | Out-Null } else { - $incidents = $Rows - foreach ($incident in $incidents) { + $Incidents = $Rows + foreach ($incident in $Incidents) { $IncidentObj = $incident.Incident | ConvertFrom-Json [PSCustomObject]@{ Tenant = $incident.Tenant @@ -101,19 +97,19 @@ Function Invoke-ExecIncidentsList { } } } catch { + $Body = Get-NormalizedError -Message $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden - $body = $_.Exception.message } - if (!$body) { + if (!$Body) { $StatusCode = [HttpStatusCode]::OK - $body = [PSCustomObject]@{ + $Body = [PSCustomObject]@{ Results = @($GraphRequest | Where-Object -Property id -NE $null | Sort-Object id -Descending) Metadata = $Metadata } } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = $body + Body = $Body }) } From dc0df585353a70e6afa8c123bc5ed2ab8e1fd286 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 May 2025 17:54:50 -0400 Subject: [PATCH 090/149] group template edit support also normalize property casing --- .../Groups/Invoke-AddGroupTemplate.ps1 | 22 +++++++++---------- .../Groups/Invoke-ListGroupTemplates.ps1 | 13 ++++++++--- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 index 8977007c3b4f..12925c3fafbf 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-AddGroupTemplate { +function Invoke-AddGroupTemplate { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -13,27 +13,27 @@ Function Invoke-AddGroupTemplate { $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $GUID = (New-Guid).GUID + $GUID = $Request.Body.GUID ?? (New-Guid).GUID try { - if (!$Request.body.displayname) { throw 'You must enter a displayname' } + if (!$Request.Body.displayname) { throw 'You must enter a displayname' } $object = [PSCustomObject]@{ - Displayname = $request.body.displayName - Description = $request.body.description - groupType = $request.body.groupType - MembershipRules = $request.body.membershipRules - allowExternal = $request.body.allowExternal - username = $request.body.username + displayName = $Request.Body.displayName + description = $Request.Body.description + groupType = $Request.Body.groupType + membershipRules = $Request.Body.membershipRules + allowExternal = $Request.Body.allowExternal + username = $Request.Body.username GUID = $GUID } | ConvertTo-Json $Table = Get-CippTable -tablename 'templates' $Table.Force = $true - Add-CIPPAzDataTableEntity @Table -Entity @{ + Add-CIPPAzDataTableEntity @Table -Force -Entity @{ JSON = "$object" RowKey = "$GUID" PartitionKey = 'GroupTemplate' } - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Created Group template named $($Request.body.displayname) with GUID $GUID" -Sev 'Debug' + Write-LogMessage -headers $Request.Headers -API $APINAME -message "Created Group template named $($Request.Body.displayname) with GUID $GUID" -Sev 'Debug' $body = [pscustomobject]@{'Results' = 'Successfully added template' } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupTemplates.ps1 index ec9510183266..2e9364e73535 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupTemplates.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ListGroupTemplates { +function Invoke-ListGroupTemplates { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -22,8 +22,15 @@ Function Invoke-ListGroupTemplates { $Filter = "PartitionKey eq 'GroupTemplate'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { $data = $_.JSON | ConvertFrom-Json - $data | Add-Member -MemberType NoteProperty -Name GUID -Value $_.RowKey -Force - $data + [PSCustomObject]@{ + displayName = $data.displayName + description = $data.description + groupType = $data.groupType + membershipRules = $data.membershipRules + allowExternal = $data.allowExternal + username = $data.username + GUID = $_.RowKey + } } | Sort-Object -Property displayName if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property GUID -EQ $Request.query.id } From 04c1cb773e4ae4d6e7f41886c7d352b9aafc35f0 Mon Sep 17 00:00:00 2001 From: Zac Richards <107489668+Zacgoose@users.noreply.github.com> Date: Thu, 22 May 2025 08:45:11 +0800 Subject: [PATCH 091/149] Review changes from John --- .../CIPPCore/Public/Functions/Get-TenantGroups.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 b/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 index 39a0d53e9383..ad4525a4d7de 100644 --- a/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 +++ b/Modules/CIPPCore/Public/Functions/Get-TenantGroups.ps1 @@ -43,12 +43,12 @@ function Get-TenantGroups { } if ($TenantFilter -and $TenantFilter -ne 'allTenants') { - $Results = New-Object System.Collections.ArrayList + $Results = [System.Collections.Generic.List[PSCustomObject]]::new() $Memberships = $AllMembers | Where-Object { $_.customerId -eq $Tenants.customerId } foreach ($Group in $Memberships) { $Group = $Groups | Where-Object { $_.RowKey -eq $Group.GroupId } if ($Group) { - $null = $Results.Add([PSCustomObject]@{ + $Results.Add([PSCustomObject]@{ Id = $Group.RowKey Name = $Group.Name Description = $Group.Description @@ -57,15 +57,15 @@ function Get-TenantGroups { } return $Results | Sort-Object Name } else { - $Results = New-Object System.Collections.ArrayList + $Results = [System.Collections.Generic.List[PSCustomObject]]::new() foreach ($Group in $Groups) { $Members = $AllMembers | Where-Object { $_.GroupId -eq $Group.RowKey } - $MembersList = New-Object System.Collections.ArrayList + $MembersList = [System.Collections.Generic.List[hashtable]]::new() if ($Members) { foreach ($Member in $Members) { $Tenant = $Tenants | Where-Object { $Member.customerId -eq $_.customerId } if ($Tenant) { - $null = $MembersList.Add(@{ + $MembersList.Add(@{ customerId = $Tenant.customerId displayName = $Tenant.displayName defaultDomainName = $Tenant.defaultDomainName @@ -76,7 +76,7 @@ function Get-TenantGroups { } else { $SortedMembers = @() } - $null = $Results.Add([PSCustomObject]@{ + $Results.Add([PSCustomObject]@{ Id = $Group.RowKey Name = $Group.Name Description = $Group.Description From e5cb86d73158f72a85d8e41502a701db5fa78f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 23 May 2025 12:37:13 +0200 Subject: [PATCH 092/149] Feat: Add option to set password never expires --- .../Users/Invoke-ExecPasswordNeverExpires.ps1 | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPasswordNeverExpires.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPasswordNeverExpires.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPasswordNeverExpires.ps1 new file mode 100644 index 000000000000..251fa31350d1 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPasswordNeverExpires.ps1 @@ -0,0 +1,41 @@ +function Invoke-ExecPasswordNeverExpires { + <# + .FUNCTIONALITY + Entrypoint + + .ROLE + Identity.User.ReadWrite + #> + Param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Body.tenantFilter + $UserId = $Request.Body.userId + $UserPrincipalName = $Request.Body.userPrincipalName # Only used for logging + $PasswordPolicy = $Request.Body.PasswordPolicy.value ?? $Request.Body.PasswordPolicy ?? 'None' + $PasswordPolicyName = $Request.Body.PasswordPolicy.label ?? $Request.Body.PasswordPolicy.value ?? $Request.Body.PasswordPolicy # Only used for logging + + if ([string]::IsNullOrWhiteSpace($UserId)) { exit } + try { + $Body = ConvertTo-Json -InputObject @{ passwordPolicies = $PasswordPolicy } -Depth 5 -Compress + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/users/$UserId" -tenantid $TenantFilter -Body $Body -type PATCH + $Result = "Successfully set PasswordPolicy for user $UserPrincipalName to $PasswordPolicyName" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev Info + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to set PasswordPolicy for user $UserPrincipalName to $PasswordPolicyName. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{ 'Results' = @($Result) } + }) +} From 424d89f3bf9a77cee50e7c8db8dc8a69befd18c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 23 May 2025 14:08:51 +0200 Subject: [PATCH 093/149] feat: add all missing ASR options fix: fix Check Signatures Before Scan feat: Add support for deploying ASR rules in audit mode fix: add a check if existing defender settings are incorrect --- .../MEM/Invoke-AddDefenderDeployment.ps1 | 99 +++++++++++-------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 index b2a0f4a714f2..f7e20a67660a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 @@ -14,15 +14,15 @@ Function Invoke-AddDefenderDeployment { $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $Tenants = ($Request.body.selectedTenants).value + $Tenants = ($Request.Body.selectedTenants).value if ('AllTenants' -in $Tenants) { $Tenants = (Get-Tenants -IncludeErrors).defaultDomainName } - $Compliance = $request.body.Compliance - $PolicySettings = $request.body.Policy - $ASR = $request.body.ASR - $EDR = $request.body.EDR - $results = foreach ($Tenant in $tenants) { + $Compliance = $Request.Body.Compliance + $PolicySettings = $Request.Body.Policy + $ASR = $Request.Body.ASR + $EDR = $Request.Body.EDR + $results = foreach ($tenant in $Tenants) { try { - $SettingsObj = @{ + $SettingsObject = @{ id = 'fc780465-2017-40d4-a0c5-307022471b92' androidEnabled = [bool]$Compliance.ConnectAndroid iosEnabled = [bool]$Compliance.ConnectIos @@ -35,18 +35,27 @@ Function Invoke-AddDefenderDeployment { androidMobileApplicationManagementEnabled = [bool]$Compliance.ConnectAndroidCompliance iosMobileApplicationManagementEnabled = [bool]$Compliance.appSync microsoftDefenderForEndpointAttachEnabled = [bool]$true - } | ConvertTo-Json -Compress + } + $SettingsObj = $SettingsObject | ConvertTo-Json -Compress try { $ExistingSettings = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/mobileThreatDefenseConnectors/fc780465-2017-40d4-a0c5-307022471b92' -tenantid $tenant + + # Check if any setting doesn't match + foreach ($key in $SettingsObject.Keys) { + if ($ExistingSettings.$key -ne $SettingsObject[$key]) { + $ExistingSettings = $false + break + } + } } catch { $ExistingSettings = $false } if ($ExistingSettings) { - "Defender Intune Configuration already active for $($Tenant). Skipping" + "Defender Intune Configuration already correct and active for $($tenant). Skipping" } else { - $SettingsRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/mobileThreatDefenseConnectors/' -tenantid $tenant -type POST -body $SettingsObj -AsApp $true - "$($Tenant): Successfully set Defender Compliance and Reporting settings" + $null = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/mobileThreatDefenseConnectors/' -tenantid $tenant -type POST -body $SettingsObj -AsApp $true + "$($tenant): Successfully set Defender Compliance and Reporting settings. Please remember to enable the Intune Connector in the Defender portal." } if ($PolicySettings) { @@ -75,7 +84,7 @@ Function Invoke-AddDefenderDeployment { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowscriptscanning'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowscriptscanning_1'; settingValueTemplateReference = @{settingValueTemplateId = 'ab9e4320-c953-4067-ac9a-be2becd06b4a' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = '000cf176-949c-4c08-a5d4-90ed43718db7' } } } } { $_.AllowUI } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowuseruiaccess' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowuseruiaccess_1' ; settingValueTemplateReference = @{settingValueTemplateId = '4b6c9739-4449-4006-8e5f-3049136470ea' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '0170a900-b0bc-4ccc-b7ce-dda9be49189b' } } } - } { $_.CheckSig } { + } { $_.CheckSigs } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_checkforsignaturesbeforerunningscan' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_checkforsignaturesbeforerunningscan_1' ; settingValueTemplateReference = @{settingValueTemplateId = '010779d1-edd4-441d-8034-89ad57a863fe' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = '4fea56e3-7bb6-4ad3-88c6-e364dd2f97b9' } } } } { $_.DisableCatchupFullScan } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_disablecatchupfullscan'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_disablecatchupfullscan_1' ; settingValueTemplateReference = @{settingValueTemplateId = '1b26092f-48c4-447b-99d4-e9c501542f1c' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f881b08c-f047-40d2-b7d9-3dde7ce9ef64' } } } @@ -90,7 +99,7 @@ Function Invoke-AddDefenderDeployment { $CheckExisting = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant Write-Host ($CheckExisting | ConvertTo-Json) if ('Default AV Policy' -in $CheckExisting.Name) { - "$($Tenant): AV Policy already exists. Skipping" + "$($tenant): AV Policy already exists. Skipping" } else { $PolBody = ConvertTo-Json -Depth 10 -Compress -InputObject @{ name = 'Default AV Policy' @@ -107,29 +116,35 @@ Function Invoke-AddDefenderDeployment { $PolicyRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $PolBody if ($PolicySettings.AssignTo -ne 'None') { $AssignBody = if ($PolicySettings.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($PolicySettings.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' } - $assign = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($PolicyRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $($PolicySettings.AssignTo)" -Sev 'Info' + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($PolicyRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody + Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($tenant) -message "Assigned policy $($DisplayName) to $($PolicySettings.AssignTo)" -Sev 'Info' } - "$($Tenant): Successfully set Default AV Policy settings" + "$($tenant): Successfully set Default AV Policy settings" } } if ($ASR) { + # Fallback to block mode + $Mode = $ASR.Mode ?? 'block' $ASRSettings = switch ($ASR) { - { $_.BlockAdobeChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_block' } } } - { $_.BlockWin32Macro } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_block' } } } - { $_.BlockCredentialStealing } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_block' } } } - { $_.BlockPSExec } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockprocesscreationsfrompsexecandwmicommands'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockprocesscreationsfrompsexecandwmicommands_block' } } } - { $_.WMIPersistence } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockpersistencethroughwmieventsubscription' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockpersistencethroughwmieventsubscription_block' } } } - { $_.BlockOfficeExes } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfromcreatingexecutablecontent' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfromcreatingexecutablecontent_block' } } } - { $_.BlockOfficeApps } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfrominjectingcodeintootherprocesses' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfrominjectingcodeintootherprocesses_block' } } } - { $_.BlockYoungExe } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion_block' } } } - { $_.blockJSVB } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent_block' } } } - { $_.blockOfficeComChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficecommunicationappfromcreatingchildprocesses' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficecommunicationappfromcreatingchildprocesses_block' } } } - { $_.blockOfficeChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_block' } } } - { $_.BlockUntrustedUSB } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuntrustedunsignedprocessesthatrunfromusb'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuntrustedunsignedprocessesthatrunfromusb_block' } } } - { $_.EnableRansomwareVac } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware_block' } } } - { $_.BlockExesMail } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablecontentfromemailclientandwebmail' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablecontentfromemailclientandwebmail_block' } } } - { $_.BlockUnsignedDrivers } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockabuseofexploitedvulnerablesigneddrivers'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockabuseofexploitedvulnerablesigneddrivers_block' } } } + { $_.BlockObfuscatedScripts } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutionofpotentiallyobfuscatedscripts' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutionofpotentiallyobfuscatedscripts_$Mode" } } } + { $_.BlockAdobeChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_$Mode" } } } + { $_.BlockWin32Macro } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros_$Mode" } } } + { $_.BlockCredentialStealing } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_$Mode" } } } + { $_.BlockPSExec } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockprocesscreationsfrompsexecandwmicommands'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockprocesscreationsfrompsexecandwmicommands_$Mode" } } } + { $_.WMIPersistence } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockpersistencethroughwmieventsubscription' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockpersistencethroughwmieventsubscription_$Mode" } } } + { $_.BlockOfficeExes } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfromcreatingexecutablecontent' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfromcreatingexecutablecontent_$Mode" } } } + { $_.BlockOfficeApps } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfrominjectingcodeintootherprocesses' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfrominjectingcodeintootherprocesses_$Mode" } } } + { $_.BlockYoungExe } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion_$Mode" } } } + { $_.blockJSVB } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent_$Mode" } } } + { $_.BlockWebshellForServers } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwebshellcreationforservers' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwebshellcreationforservers_$Mode" } } } + { $_.blockOfficeComChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficecommunicationappfromcreatingchildprocesses' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficecommunicationappfromcreatingchildprocesses_$Mode" } } } + { $_.BlockSystemTools } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuseofcopiedorimpersonatedsystemtools' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuseofcopiedorimpersonatedsystemtools_$Mode" } } } + { $_.blockOfficeChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_$Mode" } } } + { $_.BlockUntrustedUSB } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuntrustedunsignedprocessesthatrunfromusb'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuntrustedunsignedprocessesthatrunfromusb_$Mode" } } } + { $_.EnableRansomwareVac } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware_$Mode" } } } + { $_.BlockExesMail } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablecontentfromemailclientandwebmail' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablecontentfromemailclientandwebmail_$Mode" } } } + { $_.BlockUnsignedDrivers } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockabuseofexploitedvulnerablesigneddrivers'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockabuseofexploitedvulnerablesigneddrivers_$Mode" } } } + { $_.BlockSafeMode } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockrebootingmachineinsafemode'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = "device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockrebootingmachineinsafemode_$Mode" } } } } $ASRbody = ConvertTo-Json -Depth 15 -Compress -InputObject @{ @@ -144,14 +159,14 @@ Function Invoke-AddDefenderDeployment { settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' - groupSettingCollectionValue = @(@{children = $asrSettings }) + groupSettingCollectionValue = @(@{children = $ASRSettings }) settingInstanceTemplateReference = @{settingInstanceTemplateId = '19600663-e264-4c02-8f55-f2983216d6d7' } } }) } $CheckExististingASR = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant if ('ASR Default rules' -in $CheckExististingASR.Name) { - "$($Tenant): ASR Policy already exists. Skipping" + "$($tenant): ASR Policy already exists. Skipping" } else { Write-Host $ASRbody if (($ASRSettings | Measure-Object).Count -gt 0) { @@ -159,10 +174,10 @@ Function Invoke-AddDefenderDeployment { Write-Host ($ASRRequest.id) if ($ASR.AssignTo -and $ASR.AssignTo -ne 'none') { $AssignBody = if ($ASR.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($asr.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' } - $assign = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($ASRRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($ASRRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody + Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($tenant) -message "Assigned policy $($DisplayName) to $($ASR.AssignTo)" -Sev 'Info' } - "$($Tenant): Successfully added ASR Settings" + "$($tenant): Successfully added ASR Settings" } } } @@ -231,21 +246,21 @@ Function Invoke-AddDefenderDeployment { Write-Host ( $EDRbody) $CheckExististingEDR = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant | Where-Object -Property Name -EQ 'EDR Configuration' if ('EDR Configuration' -in $CheckExististingEDR.Name) { - "$($Tenant): EDR Policy already exists. Skipping" + "$($tenant): EDR Policy already exists. Skipping" } else { $EDRRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $EDRbody if ($ASR -and $ASR.AssignTo -ne 'none') { $AssignBody = if ($ASR.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($asr.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' } - $assign = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($EDRRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Assigned EDR policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($EDRRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody + Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($tenant) -message "Assigned EDR policy $($DisplayName) to $($ASR.AssignTo)" -Sev 'Info' } - "$($Tenant): Successfully added EDR Settings" + "$($tenant): Successfully added EDR Settings" } } } } catch { - "Failed to add policy for $($Tenant): $($_.Exception.Message)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Failed adding policy $($Displayname). Error: $($_.Exception.Message)" -Sev 'Error' + "Failed to add policy for $($tenant): $($_.Exception.Message)" + Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($tenant) -message "Failed adding policy $($DisplayName). Error: $($_.Exception.Message)" -Sev 'Error' continue } From e7fdbeebc16db56935f72604da5979fb6afb99a5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 23 May 2025 14:03:57 -0400 Subject: [PATCH 094/149] fix logging --- .../CIPPCore/Public/GraphHelper/Write-AlertMessage.ps1 | 2 +- .../Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 | 8 ++++---- .../Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 | 4 ++-- .../Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 | 2 +- .../Public/NinjaOne/Invoke-NinjaOneOrgMappingTenant.ps1 | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-AlertMessage.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-AlertMessage.ps1 index 5fa4f9633ff4..a7a19d9b6340 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-AlertMessage.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-AlertMessage.ps1 @@ -10,7 +10,7 @@ function Write-AlertMessage($message, $tenant = 'None', $tenantId = $null) { $ExistingMessage = Get-CIPPAzDataTableEntity @Table -Filter $Filter if (!$ExistingMessage) { Write-Host 'No duplicate message found, writing to log' - Write-LogMessage -message $message -tenant $tenant -sev 'Alert' -tenantId $tenantId -Headers'CIPP' -API 'Alerts' + Write-LogMessage -message $message -tenant $tenant -sev 'Alert' -tenantId $tenantId -API 'Alerts' } else { Write-Host 'Alerts: Duplicate entry found, not writing to log' diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 index bcd5735dcfca..0a980c96291c 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 @@ -28,7 +28,7 @@ function Invoke-NinjaOneDeviceWebhook { $Token = Get-NinjaOneToken -configuration $Configuration if (!$Token.access_token) { - Write-LogMessage -API 'NinjaOneSync' -tenant $tenantfilter -Headers'CIPP' -message 'Failed to get NinjaOne Token for Device Compliance Update' -Sev 'Error' + Write-LogMessage -API 'NinjaOneSync' -tenant $tenantfilter -message 'Failed to get NinjaOne Token for Device Compliance Update' -Sev 'Error' return } @@ -52,10 +52,10 @@ function Invoke-NinjaOneDeviceWebhook { $_.Exception.message } Write-Error "Failed NinjaOne Device Webhook for: $($Data | ConvertTo-Json -Depth 100) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" - Write-LogMessage -API 'NinjaOneSync' -Headers'CIPP' -message "Failed NinjaOne Device Webhook Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" -Sev 'Error' + Write-LogMessage -API 'NinjaOneSync' -message "Failed NinjaOne Device Webhook Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" -Sev 'Error' } } else { - Write-LogMessage -API 'NinjaOneSync' -Headers'CIPP' -message "$($DeviceM365.displayName) ($($M365DeviceID)) was not matched in Ninja for $($tenantfilter)" -Sev 'Info' + Write-LogMessage -API 'NinjaOneSync' -message "$($DeviceM365.displayName) ($($M365DeviceID)) was not matched in Ninja for $($tenantfilter)" -Sev 'Info' } } @@ -67,7 +67,7 @@ function Invoke-NinjaOneDeviceWebhook { $_.Exception.message } Write-Error "Failed NinjaOne Device Webhook for: $($Data | ConvertTo-Json -Depth 100) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" - Write-LogMessage -API 'NinjaOneSync' -Headers'CIPP' -message "Failed NinjaOne Device Webhook Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" -Sev 'Error' + Write-LogMessage -API 'NinjaOneSync' -message "Failed NinjaOne Device Webhook Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" -Sev 'Error' } diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 index fddf4c1666a4..6842752f197f 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 @@ -59,7 +59,7 @@ function Invoke-NinjaOneExtensionScheduler { } Add-AzDataTableEntity @Table -Entity $AddObject -Force - Write-LogMessage -API 'NinjaOneSync' -Headers'CIPP' -message "NinjaOne Daily Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' + Write-LogMessage -API 'NinjaOneSync' -message "NinjaOne Daily Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' } else { if ($LastRunTime -lt (Get-Date).AddMinutes(-90)) { @@ -95,7 +95,7 @@ function Invoke-NinjaOneExtensionScheduler { } if (($CatchupTenants | Measure-Object).count -gt 0) { - Write-LogMessage -API 'NinjaOneSync' -Headers'CIPP' -message "NinjaOne Synchronization Catchup Queued for $(($CatchupTenants | Measure-Object).count) Tenants" -Sev 'Info' + Write-LogMessage -API 'NinjaOneSync' -message "NinjaOne Synchronization Catchup Queued for $(($CatchupTenants | Measure-Object).count) Tenants" -Sev 'Info' } } diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 index d8e963a536c1..d6c8b7e1ad08 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 @@ -87,7 +87,7 @@ function Invoke-NinjaOneOrgMapping { IntegrationName = "$($MatchedOrg.name)" } Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force - Write-LogMessage -API 'NinjaOneAutoMap_Queue' -Headers'CIPP' -message "Added mapping from Organization name match for $($Tenant.customerId). to $($($MatchedOrg.name))" -Sev 'Info' + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -message "Added mapping from Organization name match for $($Tenant.customerId). to $($($MatchedOrg.name))" -Sev 'Info' } } diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMappingTenant.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMappingTenant.ps1 index 7db9841d7295..357f7877c445 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMappingTenant.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMappingTenant.ps1 @@ -66,7 +66,7 @@ function Invoke-NinjaOneOrgMappingTenant { IntegrationName = "$($MatchedOrg.name)" } Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force - Write-LogMessage -API 'NinjaOneAutoMap_Queue' -Headers'CIPP' -message "Added mapping from Device match for $($Tenant.displayName) to $($($MatchedOrg.name))" -Sev 'Info' + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -message "Added mapping from Device match for $($Tenant.displayName) to $($($MatchedOrg.name))" -Sev 'Info' } From 51c421d8135a7b70352028d0a06d0b41259633a2 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 23 May 2025 14:34:37 -0400 Subject: [PATCH 095/149] fix named location endpoint for restricted tenant users --- .../Tenant/Conditional/Invoke-AddNamedLocation.ps1 | 4 ++-- .../Tenant/Conditional/Invoke-ExecNamedLocation.ps1 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 index 27831ac9c557..dfb504bf6eea 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 @@ -1,9 +1,9 @@ using namespace System.Net -Function Invoke-AddNamedLocation { +function Invoke-AddNamedLocation { <# .FUNCTIONALITY - Entrypoint + Entrypoint,AnyTenant .ROLE Tenant.ConditionalAccess.ReadWrite #> diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecNamedLocation.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecNamedLocation.ps1 index f6eee67e208e..38653783e2e6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecNamedLocation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecNamedLocation.ps1 @@ -1,9 +1,9 @@ using namespace System.Net -Function Invoke-ExecNamedLocation { +function Invoke-ExecNamedLocation { <# .FUNCTIONALITY - Entrypoint + Entrypoint,AnyTenant .ROLE Tenant.ConditionalAccess.ReadWrite #> From 85181ac575113ffdf4da5985b7bd341972dc770a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 23 May 2025 14:44:49 -0400 Subject: [PATCH 096/149] fix support for addexconnector with limited tenants --- .../Transport/Invoke-AddExConnector.ps1 | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnector.ps1 index bbb77bfadd9f..5a3c95a0867a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnector.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnector.ps1 @@ -1,9 +1,9 @@ using namespace System.Net -Function Invoke-AddExConnector { +function Invoke-AddExConnector { <# .FUNCTIONALITY - Entrypoint + Entrypoint,AnyTenant .ROLE Exchange.Connector.ReadWrite #> @@ -19,6 +19,15 @@ Function Invoke-AddExConnector { $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, cippConnectorType, SenderRewritingEnabled if ($RequestParams.comment) { $RequestParams.comment = Get-CIPPTextReplacement -Text $RequestParams.comment -TenantFilter $Tenant } else { $RequestParams | Add-Member -NotePropertyValue 'no comment' -NotePropertyName comment -Force } $Tenants = ($Request.Body.selectedTenants).value + + $AllowedTenants = Test-CippAccess -Request $Request -TenantList + + if ($AllowedTenants -ne 'AllTenants') { + $AllTenants = Get-Tenants -IncludeErrors + $AllowedTenantList = $AllTenants | Where-Object { $_.customerId -in $AllowedTenants } + $Tenants = $Tenants | Where-Object { $_ -in $AllowedTenantList.defaultDomainName } + } + $Result = foreach ($TenantFilter in $Tenants) { try { $null = New-ExoRequest -tenantid $TenantFilter -cmdlet "New-$($ConnectorType)connector" -cmdParams $RequestParams From ffa67d48f5fcfe5a73304df344994177c9c7ed98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sat, 24 May 2025 12:47:13 +0200 Subject: [PATCH 097/149] fix: standardize variable casing and return more groupInfo for single groups --- .../Groups/Invoke-ListGroups.ps1 | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 index 8f7359353f4a..9c4123eecf39 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 @@ -15,34 +15,34 @@ Function Invoke-ListGroups { Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $TenantFilter = $Request.Query.TenantFilter - $selectstring = "id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,grouptypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName&`$expand=members(`$select=userPrincipalName)" + $SelectString = 'id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName&$expand=members($select=userPrincipalName)' $BulkRequestArrayList = [System.Collections.Generic.List[object]]::new() if ($Request.Query.GroupID) { - $selectstring = 'id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,userPrincipalName' + $SelectString = 'id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,userPrincipalName' $BulkRequestArrayList.add(@{ id = 1 method = 'GET' - url = "groups/$($Request.Query.GroupID)?`$select=$selectstring" + url = "groups/$($Request.Query.GroupID)?`$select=$SelectString" }) } if ($Request.Query.members) { - $selectstring = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' + $SelectString = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' $BulkRequestArrayList.add(@{ id = 2 method = 'GET' - url = "groups/$($Request.Query.GroupID)/members?`$top=999&select=$selectstring" + url = "groups/$($Request.Query.GroupID)/members?`$top=999&select=$SelectString" }) } if ($Request.Query.owners) { if ($Request.Query.groupType -ne 'Distribution List' -and $Request.Query.groupType -ne 'Mail-Enabled Security') { - $selectstring = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' + $SelectString = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' $BulkRequestArrayList.add(@{ id = 3 method = 'GET' - url = "groups/$($Request.Query.GroupID)/owners?`$top=999&select=$selectstring" + url = "groups/$($Request.Query.GroupID)/owners?`$top=999&select=$SelectString" }) } else { $OwnerIds = New-ExoRequest -cmdlet 'Get-DistributionGroup' -tenantid $TenantFilter -cmdParams @{Identity = $Request.Query.GroupID } -useSystemMailbox $true | Select-Object -ExpandProperty ManagedBy @@ -86,40 +86,32 @@ Function Invoke-ListGroups { if ($BulkRequestArrayList.Count -gt 0) { $RawGraphRequest = New-GraphBulkRequest -tenantid $TenantFilter -scope 'https://graph.microsoft.com/.default' -Requests @($BulkRequestArrayList) -asapp $true $GraphRequest = [PSCustomObject]@{ - groupInfo = ($RawGraphRequest | Where-Object { $_.id -eq 1 }).body + groupInfo = ($RawGraphRequest | Where-Object { $_.id -eq 1 }).body | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split '@' | Select-Object -Last 1 } }, + @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -Like '*Team*') { $true } else { $false } } }, + @{Name = 'calculatedGroupType'; Expression = { + if ($_.mailEnabled -and $_.securityEnabled) { 'Mail-Enabled Security' } + if (!$_.mailEnabled -and $_.securityEnabled) { 'Security' } + if ($_.groupTypes -contains 'Unified') { 'Microsoft 365' } + if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { 'Distribution List' } + } + }, @{Name = 'dynamicGroupBool'; Expression = { if ($_.groupTypes -contains 'DynamicMembership') { $true } else { $false } } } members = ($RawGraphRequest | Where-Object { $_.id -eq 2 }).body.value owners = ($RawGraphRequest | Where-Object { $_.id -eq 3 }).body.value allowExternal = (!$OnlyAllowInternal) sendCopies = $SendCopies } } else { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupID)/$($members)?`$top=999&select=$selectstring" -tenantid $TenantFilter | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split '@' | Select-Object -Last 1 } }, + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupID)/$($members)?`$top=999&select=$SelectString" -tenantid $TenantFilter | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split '@' | Select-Object -Last 1 } }, @{Name = 'membersCsv'; Expression = { $_.members.userPrincipalName -join ',' } }, @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -Like '*Team*') { $true }else { $false } } }, @{Name = 'calculatedGroupType'; Expression = { - - if ($_.mailEnabled -and $_.securityEnabled) { - 'Mail-Enabled Security' - } - if (!$_.mailEnabled -and $_.securityEnabled) { - 'Security' - } - if ($_.groupTypes -contains 'Unified') { - 'Microsoft 365' - } - if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { - 'Distribution List' - } + if ($_.mailEnabled -and $_.securityEnabled) { 'Mail-Enabled Security' } + if (!$_.mailEnabled -and $_.securityEnabled) { 'Security' } + if ($_.groupTypes -contains 'Unified') { 'Microsoft 365' } + if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { 'Distribution List' } } }, - @{Name = 'dynamicGroupBool'; Expression = { - if ($_.groupTypes -contains 'DynamicMembership') { - $true - } else { - $false - } - } - } + @{Name = 'dynamicGroupBool'; Expression = { if ($_.groupTypes -contains 'DynamicMembership') { $true } else { $false } } } $GraphRequest = @($GraphRequest | Sort-Object displayName) } From 2e2aaa8e2ac3277741a7e0b9b5c73f22bca160eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sat, 24 May 2025 14:43:58 +0200 Subject: [PATCH 098/149] feat: re-add remove from groups and streamline various variable names and such --- .../Administration/Users/Invoke-EditUser.ps1 | 110 ++++++++---------- 1 file changed, 50 insertions(+), 60 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 index c092fb305baf..e2f1dac8cffd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 @@ -11,11 +11,11 @@ Function Invoke-EditUser { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -headers $Request.headers -API $ApiName -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $ApiName -message 'Accessed this API' -Sev 'Debug' - $UserObj = $Request.body - if ($UserObj.id -eq '') { + $UserObj = $Request.Body + if ([string]::IsNullOrWhiteSpace($UserObj.id)) { $body = @{'Results' = @('Failed to edit user. No user ID provided') } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::BadRequest @@ -26,8 +26,8 @@ Function Invoke-EditUser { $Results = [System.Collections.Generic.List[object]]::new() $licenses = ($UserObj.licenses).value $Aliases = if ($UserObj.AddedAliases) { ($UserObj.AddedAliases) -split '\s' } - $AddToGroups = $Request.body.AddToGroups - $RemoveFromGroups = $Request.body.RemoveFromGroups + $AddToGroups = $Request.Body.AddToGroups + $RemoveFromGroups = $Request.Body.RemoveFromGroups #Edit the user @@ -69,18 +69,18 @@ Function Invoke-EditUser { } $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter -type PATCH -body $BodyToship -verbose - $null = $results.Add( 'Success. The user has been edited.' ) - Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Request.Headers -message "Edited user $($UserObj.DisplayName) with id $($UserObj.id)" -Sev Info + $null = $Results.Add( 'Success. The user has been edited.' ) + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Headers -message "Edited user $($UserObj.DisplayName) with id $($UserObj.id)" -Sev Info if ($UserObj.password) { $passwordProfile = [pscustomobject]@{'passwordProfile' = @{ 'password' = $UserObj.password; 'forceChangePasswordNextSignIn' = [boolean]$UserObj.MustChangePass } } | ConvertTo-Json $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter -type PATCH -body $PasswordProfile -verbose - $null = $results.Add("Success. The password has been set to $($UserObj.password)") - Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Request.Headers -message "Reset $($UserObj.DisplayName)'s Password" -Sev Info + $null = $Results.Add("Success. The password has been set to $($UserObj.password)") + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Headers -message "Reset $($UserObj.DisplayName)'s Password" -Sev Info } } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Request.Headers -message "User edit API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage - $null = $results.Add( "Failed to edit user. $($ErrorMessage.NormalizedError)") + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Headers -message "User edit API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $null = $Results.Add( "Failed to edit user. $($ErrorMessage.NormalizedError)") } @@ -89,8 +89,8 @@ Function Invoke-EditUser { if ($licenses -or $UserObj.removeLicenses) { if ($UserObj.sherwebLicense.value) { - $License = Set-SherwebSubscription -TenantFilter $UserObj.tenantFilter -SKU $UserObj.sherwebLicense.value -Add 1 - $null = $results.Add('Added Sherweb License, scheduling assignment') + $null = Set-SherwebSubscription -TenantFilter $UserObj.tenantFilter -SKU $UserObj.sherwebLicense.value -Add 1 + $null = $Results.Add('Added Sherweb License, scheduling assignment') $taskObject = [PSCustomObject]@{ TenantFilter = $UserObj.tenantFilter Name = "Assign License: $UserPrincipalName" @@ -118,12 +118,12 @@ Function Invoke-EditUser { $null = $results.Add( 'Success. User license is already correct.' ) } else { if ($UserObj.removeLicenses) { - $licResults = Set-CIPPUserLicense -UserId $UserObj.id -TenantFilter $UserObj.tenantFilter -RemoveLicenses $CurrentLicenses.assignedLicenses.skuId -Headers $Request.Headers + $licResults = Set-CIPPUserLicense -UserId $UserObj.id -TenantFilter $UserObj.tenantFilter -RemoveLicenses $CurrentLicenses.assignedLicenses.skuId -Headers $Headers $null = $results.Add($licResults) } else { #Remove all objects from $CurrentLicenses.assignedLicenses.skuId that are in $licenses $RemoveLicenses = $CurrentLicenses.assignedLicenses.skuId | Where-Object { $_ -notin $licenses } - $licResults = Set-CIPPUserLicense -UserId $UserObj.id -TenantFilter $UserObj.tenantFilter -RemoveLicenses $RemoveLicenses -AddLicenses $licenses -Headers $Request.headers + $licResults = Set-CIPPUserLicense -UserId $UserObj.id -TenantFilter $UserObj.tenantFilter -RemoveLicenses $RemoveLicenses -AddLicenses $licenses -Headers $headers $null = $results.Add($licResults) } @@ -133,7 +133,7 @@ Function Invoke-EditUser { } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Request.Headers -message "License assign API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Headers -message "License assign API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage $null = $results.Add( "We've failed to assign the license. $($ErrorMessage.NormalizedError)") } @@ -145,18 +145,18 @@ Function Invoke-EditUser { $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter -type 'patch' -body "{`"mail`": `"$Alias`"}" -Verbose } $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter -type 'patch' -body "{`"mail`": `"$UserPrincipalName`"}" -Verbose - Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Request.Headers -message "Added Aliases to $($UserObj.DisplayName)" -Sev Info + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Headers -message "Added Aliases to $($UserObj.DisplayName)" -Sev Info $null = $results.Add( 'Success. added aliases to user.') } } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Request.Headers -message "Alias API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -headers $Headers -message "Alias API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage $null = $results.Add( "Successfully edited user. The password is $password. We've failed to create the Aliases: $($ErrorMessage.NormalizedError)") } - if ($Request.body.CopyFrom.value) { - $CopyFrom = Set-CIPPCopyGroupMembers -Headers $User -CopyFromId $Request.body.CopyFrom.value -UserID $UserPrincipalName -TenantFilter $UserObj.tenantFilter + if ($Request.Body.CopyFrom.value) { + $CopyFrom = Set-CIPPCopyGroupMembers -Headers $Headers -CopyFromId $Request.Body.CopyFrom.value -UserID $UserPrincipalName -TenantFilter $UserObj.tenantFilter $null = $results.AddRange(@($CopyFrom)) } @@ -169,83 +169,73 @@ Function Invoke-EditUser { Write-Host "About to add $($UserObj.userPrincipalName) to $GroupName. Group ID is: $GroupID and type is: $GroupType" try { - if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { - Write-Host 'Adding to group via Add-DistributionGroupMember ' + Write-Host 'Adding to group via Add-DistributionGroupMember' $Params = @{ Identity = $GroupID; Member = $UserObj.id; BypassSecurityGroupManagerCheck = $true } $null = New-ExoRequest -tenantid $UserObj.tenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true - } else { - Write-Host 'Adding to group via Graph' $UserBody = [PSCustomObject]@{ '@odata.id' = "https://graph.microsoft.com/beta/directoryObjects/$($UserObj.id)" } $UserBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $UserBody $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$GroupID/members/`$ref" -tenantid $UserObj.tenantFilter -type POST -body $UserBodyJSON -Verbose - } - - Write-LogMessage -headers $Request.Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Added $($UserObj.DisplayName) to $GroupName group" -Sev Info + Write-LogMessage -headers $Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Added $($UserObj.DisplayName) to $GroupName group" -Sev Info $null = $results.Add("Success. $($UserObj.DisplayName) has been added to $GroupName") } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Request.Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Failed to add member $($UserObj.DisplayName) to $GroupName. Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage - $null = $results.Add("Failed to add member $($UserObj.DisplayName) to $GroupName : $($ErrorMessage.NormalizedError)") + $Message = "Failed to add member $($UserObj.DisplayName) to $GroupName. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $ApiName -tenant $UserObj.tenantFilter -message $Message -Sev Error -LogData $ErrorMessage + $null = $results.Add($Message) } - } } - if ($Request.body.setManager.value) { - $ManagerBody = [PSCustomObject]@{'@odata.id' = "https://graph.microsoft.com/beta/users/$($Request.body.setManager.value)" } - $ManagerBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $ManagerBody - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)/manager/`$ref" -tenantid $UserObj.tenantFilter -type PUT -body $ManagerBodyJSON -Verbose - Write-LogMessage -headers $Request.Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)" -Sev Info - $null = $results.Add("Success. Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)") - } - - if ($Request.body.setSponsor.value) { - $SponsorBody = [PSCustomObject]@{'@odata.id' = "https://graph.microsoft.com/beta/users/$($Request.body.setSponsor.value)" } - $SponsorBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $SponsorBody - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)/sponsors/`$ref" -tenantid $UserObj.tenantFilter -type POST -body $SponsorBodyJSON -Verbose - Write-LogMessage -headers $Request.Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Set $($UserObj.DisplayName)'s sponsor to $($Request.body.setSponsor.label)" -Sev Info - $null = $results.Add("Success. Set $($UserObj.DisplayName)'s sponsor to $($Request.body.setSponsor.label)") - } if ($RemoveFromGroups) { $RemoveFromGroups | ForEach-Object { - $GroupType = $_.value.groupType -join ',' - $GroupID = $_.value.groupid - $GroupName = $_.value.groupName + $GroupType = $_.addedFields.calculatedGroupType + $GroupID = $_.value + $GroupName = $_.label Write-Host "About to remove $($UserObj.userPrincipalName) from $GroupName. Group ID is: $GroupID and type is: $GroupType" try { - if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { - - Write-Host 'Removing From group via Remove-DistributionGroupMember ' + Write-Host 'Removing From group via Remove-DistributionGroupMember' $Params = @{ Identity = $GroupID; Member = $UserObj.id; BypassSecurityGroupManagerCheck = $true } $null = New-ExoRequest -tenantid $UserObj.tenantFilter -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true - } else { - Write-Host 'Removing From group via Graph' $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$GroupID/members/$($UserObj.id)/`$ref" -tenantid $UserObj.tenantFilter -type DELETE - } - - Write-LogMessage -headers $Request.Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Removed $($UserObj.DisplayName) from $GroupName group" -Sev Info + Write-LogMessage -headers $Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Removed $($UserObj.DisplayName) from $GroupName group" -Sev Info $null = $results.Add("Success. $($UserObj.DisplayName) has been removed from $GroupName") } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Request.Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Failed to remove member $($UserObj.DisplayName) from $GroupName. Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage - $null = $results.Add("Failed to remove member $($UserObj.DisplayName) from $GroupName : $($ErrorMessage.NormalizedError)") + $Message = "Failed to remove member $($UserObj.DisplayName) from $GroupName. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $ApiName -tenant $UserObj.tenantFilter -message $Message -Sev Error -LogData $ErrorMessage + $null = $results.Add($Message) } - } } + if ($Request.body.setManager.value) { + $ManagerBody = [PSCustomObject]@{'@odata.id' = "https://graph.microsoft.com/beta/users/$($Request.body.setManager.value)" } + $ManagerBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $ManagerBody + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)/manager/`$ref" -tenantid $UserObj.tenantFilter -type PUT -body $ManagerBodyJSON -Verbose + Write-LogMessage -headers $Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)" -Sev Info + $null = $results.Add("Success. Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)") + } + + if ($Request.body.setSponsor.value) { + $SponsorBody = [PSCustomObject]@{'@odata.id' = "https://graph.microsoft.com/beta/users/$($Request.body.setSponsor.value)" } + $SponsorBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $SponsorBody + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)/sponsors/`$ref" -tenantid $UserObj.tenantFilter -type POST -body $SponsorBodyJSON -Verbose + Write-LogMessage -headers $Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Set $($UserObj.DisplayName)'s sponsor to $($Request.body.setSponsor.label)" -Sev Info + $null = $results.Add("Success. Set $($UserObj.DisplayName)'s sponsor to $($Request.body.setSponsor.label)") + } + $body = @{'Results' = @($results) } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ From 65526336bc8878d90810b1a3a4b11add7154d2f5 Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Sun, 25 May 2025 00:02:19 +0200 Subject: [PATCH 099/149] Added api's for custom quarantine policies and global --- openapi.json | 312 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) diff --git a/openapi.json b/openapi.json index 9deb23f30eee..7fb2383fa0cc 100644 --- a/openapi.json +++ b/openapi.json @@ -8537,6 +8537,270 @@ } } }, + "/ListQuarantinePolicy": { + "get": { + "description": "ListQuarantinePolicy", + "summary": "ListQuarantinePolicy", + "tags": [ + "GET" + ], + "parameters": [ + { + "required": true, + "schema": { + "type": "string" + }, + "name": "tenantfilter", + "in": "query" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "Type", + "in": "query" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": {}, + "type": "object" + } + } + }, + "description": "Successful operation" + } + } + } + }, + "/AddQuarantinePolicy": { + "post": { + "description": "AddQuarantinePolicy", + "summary": "AddQuarantinePolicy", + "tags": [ + "POST" + ], + "parameters": [ + { + "required": true, + "schema": { + "type": "string" + }, + "name": "tenantfilter", + "in": "query" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "Name", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "BlockSender", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "Delete", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "Preview", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "ReleaseActionPreference", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "AllowSender", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "QuarantineNotification", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "IncludeMessagesFromBlockedSenderAddress", + "in": "body" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": {}, + "type": "object" + } + } + }, + "description": "Successful operation" + } + } + } + }, + "/EditQuarantinePolicy": { + "post": { + "description": "EditQuarantinePolicy", + "summary": "EditQuarantinePolicy", + "tags": [ + "POST" + ], + "parameters": [ + { + "required": true, + "schema": { + "type": "string" + }, + "name": "tenantfilter", + "in": "query" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "Type", + "in": "query" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "Identity", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "EndUserSpamNotificationFrequency", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "EndUserSpamNotificationCustomFromAddress", + "in": "body" + }, + { + "required": false, + "schema": { + "type": "boolean" + }, + "name": "OrganizationBrandingEnabled", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "BlockSender", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "Delete", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "Preview", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "ReleaseActionPreference", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "AllowSender", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "QuarantineNotification", + "in": "body" + }, + { + "required": true, + "schema": { + "type": "boolean" + }, + "name": "IncludeMessagesFromBlockedSenderAddress", + "in": "body" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": {}, + "type": "object" + } + } + }, + "description": "Successful operation" + } + } + } + }, "/RemoveExConnector": { "get": { "description": "RemoveExConnector", @@ -8584,6 +8848,54 @@ } } } + }, + "/RemoveQuarantinePolicy": { + "get": { + "description": "RemoveQuarantinePolicy", + "summary": "RemoveQuarantinePolicy", + "tags": [ + "GET" + ], + "parameters": [ + { + "required": true, + "schema": { + "type": "string" + }, + "name": "tenantfilter", + "in": "query" + }, + { + "required": true, + "schema": { + "type": "string" + }, + "name": "Identity", + "in": "body" + }, + { + "required": false, + "schema": { + "type": "string" + }, + "name": "Name", + "in": "body" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": {}, + "type": "object" + } + } + }, + "description": "Successful operation" + } + } + } } }, "openapi": "3.1.0", From bc9d1f11e41309e3c91261e4a7f9fd0b10ac7b46 Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Sun, 25 May 2025 00:04:15 +0200 Subject: [PATCH 100/149] Moved from StandardQuarantineTemplate to standalone Function, as it is now used by multiple functions --- .../Convert-QuarantinePermissionsValue.ps1 | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Modules/CIPPCore/Private/Convert-QuarantinePermissionsValue.ps1 diff --git a/Modules/CIPPCore/Private/Convert-QuarantinePermissionsValue.ps1 b/Modules/CIPPCore/Private/Convert-QuarantinePermissionsValue.ps1 new file mode 100644 index 000000000000..196664c4a288 --- /dev/null +++ b/Modules/CIPPCore/Private/Convert-QuarantinePermissionsValue.ps1 @@ -0,0 +1,49 @@ +function Convert-QuarantinePermissionsValue { + param ( + [Parameter(Mandatory = $true, Position=0)] + [ValidateNotNullOrEmpty()] + [ValidateScript( + {$_ -is [String] ? $true : $_ -is [Hashtable] ? $true : $false}, + ErrorMessage = "Input must be a string or hashtable." + )] + $InputObject + ) + + #Converts string value with EndUserQuarantinePermissions received from Get-QuarantinePolicy + if ($InputObject -is [String]) { + try { + # Remove square brackets and split into lines + $InputObject = $InputObject.Trim('[', ']') + $hashtable = @{} + $InputObject -split "`n" | ForEach-Object { + $key, $value = $_ -split ":\s*" + $hashtable[$key.Trim()] = [System.Convert]::ToBoolean($value.Trim()) + } + return $hashtable + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + throw "Convert-QuarantinePermissionsValue: Failed to convert string to hashtable. Error: $ErrorMessage" + } + } + + #Converts hashtable with selected end user quarantine permissions to decimal value used by EndUserQuarantinePermissionsValue property in New-QuarantinePolicy and Set-QuarantinePolicy + elseif ($InputObject -is [Hashtable]) { + try { + $EndUserQuarantinePermissionsValue = 0 + $EndUserQuarantinePermissionsValue += ([int]$InputObject.PermissionToViewHeader ?? 0 ) * 128 + $EndUserQuarantinePermissionsValue += ([int]$InputObject.PermissionToDownload ?? 0 ) * 64 + $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToAllowSender * 32 + $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToBlockSender * 16 + $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToRequestRelease * 8 + $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToRelease * 4 + $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToPreview * 2 + $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToDelete * 1 + return $EndUserQuarantinePermissionsValue + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + throw "Convert-QuarantinePermissionsValue: Failed to convert hashtable to QuarantinePermissionsValue. Error: $ErrorMessage" + } + } +} From 9b939c5094cfc659c758db1bef221d9a3d7f8654 Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Sun, 25 May 2025 00:06:06 +0200 Subject: [PATCH 101/149] Added endpoints for new quarantine policies page. --- .../Spamfilter/Invoke-AddQuarantinePolicy.ps1 | 68 ++++++++++++++++ .../Invoke-EditQuarantinePolicy.ps1 | 79 +++++++++++++++++++ .../Invoke-ListQuarantinePolicy.ps1 | 45 +++++++++++ .../Invoke-RemoveQuarantinePolicy.ps1 | 45 +++++++++++ 4 files changed, 237 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditQuarantinePolicy.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListQuarantinePolicy.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveQuarantinePolicy.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 new file mode 100644 index 000000000000..020f10fa53e5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 @@ -0,0 +1,68 @@ +using namespace System.Net + +Function Invoke-AddQuarantinePolicy { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $Tenants = ($Request.body.selectedTenants).value + + # If allTenants is selected, get all tenants from table and overwrite any other tenant selection + if ("AllTenants" -in $Tenants) { + $TenantTable = Get-CIPPTable -tablename 'Tenants' + $tenants = (Get-CIPPAzDataTableEntity @TenantTable -Filter "PartitionKey eq 'Tenants'").defaultDomainName + } + + $Result = foreach ($TenantFilter in $tenants) { + try { + $ReleaseActionPreference = $Request.Body.ReleaseActionPreference.value ?? $Request.Body.ReleaseActionPreference + + $EndUserQuarantinePermissions = @{ + PermissionToBlockSender = $Request.Body.BlockSender + PermissionToDelete = $Request.Body.Delete + PermissionToPreview = $Request.Body.Preview + PermissionToRelease = $ReleaseActionPreference -eq "Release" ? $true : $false + PermissionToRequestRelease = $ReleaseActionPreference -eq "RequestRelease" ? $true : $false + PermissionToAllowSender = $Request.Body.AllowSender + } + + $Params = @{ + Identity = $Request.Body.Name + EndUserQuarantinePermissions = $EndUserQuarantinePermissions + ESNEnabled = $Request.Body.QuarantineNotification + IncludeMessagesFromBlockedSenderAddress = $Request.Body.IncludeMessagesFromBlockedSenderAddress + action = "New" + tenantFilter = $TenantFilter + APIName = $APIName + } + + Set-CIPPQuarantinePolicy @Params + $Message = "Created Quarantine policy '$($Request.Body.Name)' for tenant '$($TenantFilter)'" + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Message -Sev Info + $Message + + } + catch { + $ErrorMessage = Get-CippException -Exception $_ + $Message = "Failed to create Quarantine policy '$($Request.Body.Name)' for tenant '$($TenantFilter)' - $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Message -Sev Error -LogData $ErrorMessage + $Message + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{Results = @($Result) } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditQuarantinePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditQuarantinePolicy.ps1 new file mode 100644 index 000000000000..a71d3700efae --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditQuarantinePolicy.ps1 @@ -0,0 +1,79 @@ +using namespace System.Net + +Function Invoke-EditQuarantinePolicy { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $TenantFilter = $Request.Query.TenantFilter ?? $Request.Body.TenantFilter + + if ($Request.Query.Type -eq "GlobalQuarantinePolicy") { + + $Frequency = $Request.Body.EndUserSpamNotificationFrequency.value ?? $Request.Body.EndUserSpamNotificationFrequency + # If request EndUserSpamNotificationFrequency it not set to a ISO 8601 timeformat, convert it to one. + # This happens if the user doesn't change the Notification Frequency value in the UI. Because of a "bug" with setDefaultValue function with the cippApiDialog, where "label" is set to both label and value. + $EndUserSpamNotificationFrequency = switch ($Frequency) { + "4 Hours" { "PT4H" } + "Daily" { "P1D" } + "Weekly" { "P7D" } + Default { $Frequency } + } + + $Params = @{ + Identity = $Request.Body.Identity + # Convert the requested frequency from ISO 8601 to a TimeSpan object + EndUserSpamNotificationFrequency = [System.Xml.XmlConvert]::ToTimeSpan($EndUserSpamNotificationFrequency) + EndUserSpamNotificationCustomFromAddress = $Request.Body.EndUserSpamNotificationCustomFromAddress + OrganizationBrandingEnabled = $Request.Body.OrganizationBrandingEnabled + } + } + else { + $ReleaseActionPreference = $Request.Body.ReleaseActionPreference.value ?? $Request.Body.ReleaseActionPreference + + $EndUserQuarantinePermissions = @{ + PermissionToBlockSender = $Request.Body.BlockSender + PermissionToDelete = $Request.Body.Delete + PermissionToPreview = $Request.Body.Preview + PermissionToRelease = $ReleaseActionPreference -eq "Release" ? $true : $false + PermissionToRequestRelease = $ReleaseActionPreference -eq "RequestRelease" ? $true : $false + PermissionToAllowSender = $Request.Body.AllowSender + } + + $Params = @{ + Identity = $Request.Body.Identity + EndUserQuarantinePermissions = $EndUserQuarantinePermissions + ESNEnabled = $Request.Body.QuarantineNotification + IncludeMessagesFromBlockedSenderAddress = $Request.Body.IncludeMessagesFromBlockedSenderAddress + action = $Request.Body.Action ?? "Set" + } + } + + try { + Set-CIPPQuarantinePolicy @Params -tenantFilter $TenantFilter -APIName $APIName + + $Result = "Updated Quarantine policy '$($Request.Body.Name)'" + $StatusCode = [HttpStatusCode]::OK + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info + } + catch { + $Result = "Failed to update Quarantine policy '$($Request.Body.Name)' - $($_)" + $StatusCode = [HttpStatusCode]::Forbidden + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Error -LogData $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListQuarantinePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListQuarantinePolicy.ps1 new file mode 100644 index 000000000000..55b13d960f3a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListQuarantinePolicy.ps1 @@ -0,0 +1,45 @@ +function Invoke-ListQuarantinePolicy { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter ?? $Request.body.TenantFilter + $QuarantinePolicyType = $Request.Query.Type ?? 'QuarantinePolicy' + + $Policies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-QuarantinePolicy' -cmdParams @{QuarantinePolicyType=$QuarantinePolicyType} | Select-Object -Property * -ExcludeProperty *odata*, *data.type* + + write-host $($Request | ConvertTo-Json -Depth 10) + + if ($QuarantinePolicyType -eq 'QuarantinePolicy') { + # Convert the string EndUserQuarantinePermissions to individual properties + $Policies | ForEach-Object { + $Permissions = Convert-QuarantinePermissionsValue -InputObject $_.EndUserQuarantinePermissions + foreach ($Perm in $Permissions.GetEnumerator()) { + $_ | Add-Member -MemberType NoteProperty -Name ($Perm.Key -replace "PermissionTo", "" ) -Value $Perm.Value + } + } + + # "convert" to values display in the UI and Builtin used for filtering + $Policies = $Policies | Select-Object -Property *, + @{ Name = 'QuarantineNotification'; Expression = { $_.ESNEnabled -eq $true ? $true : $false} }, + @{ Name = 'ReleaseActionPreference'; Expression = { $_.Release -eq $true ? "Release" : "RequestRelease"} }, + @{ Name = 'Builtin'; Expression = { $_.Guid -eq "00000000-0000-0000-0000-000000000000" ? $true : $false} } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Policies) + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveQuarantinePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveQuarantinePolicy.ps1 new file mode 100644 index 000000000000..986112ecd543 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveQuarantinePolicy.ps1 @@ -0,0 +1,45 @@ +using namespace System.Net + +Function Invoke-RemoveQuarantinePolicy { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.TenantFilter ?? $Request.Body.TenantFilter + $PolicyName = $Request.Query.Name ?? $Request.Body.Name + $Identity = $Request.Query.Identity ?? $Request.Body.Identity + + try { + $Params = @{ + Identity = ($Identity -eq "00000000-0000-0000-0000-000000000000" ? $PolicyName : $Identity) + } + + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Remove-QuarantinePolicy' -cmdParams $Params -useSystemMailbox $true + + $Result = "Deleted Quarantine policy '$($PolicyName)'" + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to remove Quarantine policy '$($PolicyName)' - $($ErrorMessage.NormalizedError -replace '\|Microsoft.Exchange.Management.Tasks.ValidationException\|', '')" + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::Forbidden + } + + $StatusCode = [HttpStatusCode]::OK + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) + +} From ea042494a56e1d3157a57ba1ba27a7285623595f Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Sun, 25 May 2025 00:07:27 +0200 Subject: [PATCH 102/149] New function for add/edit quarantine policies and global settings --- .../Public/Set-CIPPQuarantinePolicy.ps1 | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 diff --git a/Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 new file mode 100644 index 000000000000..665e35f57575 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 @@ -0,0 +1,109 @@ +function Set-CIPPQuarantinePolicy { + <# + .SYNOPSIS + Set/Add Quarantine policy, supports both custom and global Quarantine Policy + + .DESCRIPTION + Set/Add Quarantine policy, supports both custom and global Quarantine Policy + + .PARAMETER identity + Identity of the Quarantine policy to set, Name or GUID. + + .PARAMETER action + Which action to perform Create or Update. Valid values are Add, New, Create, Edit, Set, Update. + + .PARAMETER tenantFilter + Tenant to manage quarantine policy for. + + .PARAMETER EndUserQuarantinePermissions + End user quarantine permissions to set. This is a hashtable with the following keys: + PermissionToBlockSender + PermissionToDelete + PermissionToPreview + PermissionToRelease + PermissionToRequestRelease + PermissionToAllowSender + PermissionToViewHeader + PermissionToDownload + + .PARAMETER APIName + Name of the API executing the command. + + .PARAMETER ESNEnabled + Whether the quarantine notification is enabled or not. + + .PARAMETER IncludeMessagesFromBlockedSenderAddress + Whether to include messages from blocked sender address or not. + + #> + [CmdletBinding(DefaultParameterSetName = 'QuarantinePolicy')] + param( + [Parameter(Mandatory, ParameterSetName = 'QuarantinePolicy')] + [Parameter(Mandatory, ParameterSetName = 'GlobalQuarantinePolicy')] + [ValidateNotNullOrEmpty()] + [string]$identity, + + [Parameter(Mandatory, ParameterSetName = 'QuarantinePolicy')] + [ValidateSet("Add", "New", "Create", "Edit", "Set", "Update")] + [string]$action, + + [Parameter(Mandatory, ParameterSetName = 'QuarantinePolicy')] + [Hashtable]$EndUserQuarantinePermissions, + + [Parameter(Mandatory, ParameterSetName = 'QuarantinePolicy')] + [bool]$ESNEnabled, + + [Parameter(ParameterSetName = 'QuarantinePolicy')] + [bool]$IncludeMessagesFromBlockedSenderAddress = $false, + + [Parameter(Mandatory, ParameterSetName = 'GlobalQuarantinePolicy')] + [TimeSpan]$EndUserSpamNotificationFrequency, + + [Parameter(ParameterSetName = 'GlobalQuarantinePolicy')] + [string]$EndUserSpamNotificationCustomFromAddress = "", + + [Parameter(ParameterSetName = 'GlobalQuarantinePolicy')] + [bool]$OrganizationBrandingEnabled = $false, + + [Parameter(Mandatory)] + [string]$tenantFilter, + [string]$APIName = 'QuarantinePolicy' + ) + + try { + + switch ($PSCmdlet.ParameterSetName) { + "GlobalQuarantinePolicy" { + $cmdParams = @{ + Identity = $identity + EndUserSpamNotificationFrequency = $EndUserSpamNotificationFrequency.ToString() + EndUserSpamNotificationCustomFromAddress = $EndUserSpamNotificationCustomFromAddress + OrganizationBrandingEnabled = $OrganizationBrandingEnabled + # QuarantinePolicyType = 'GlobalQuarantinePolicy' + } + $cmdLet = 'Set-QuarantinePolicy' + } + "QuarantinePolicy" { + $cmdParams = @{ + EndUserQuarantinePermissionsValue = Convert-QuarantinePermissionsValue -InputObject $EndUserQuarantinePermissions + ESNEnabled = $ESNEnabled + IncludeMessagesFromBlockedSenderAddress = $IncludeMessagesFromBlockedSenderAddress + } + + switch ($action) { + {$_ -in @("Add", "New", "Create")} { $cmdParams.Add("Name", $identity) ; $cmdLet = 'New-QuarantinePolicy' } + {$_ -in @("Edit", "Set", "Update")} { $cmdParams.Add("Identity", $identity) ; $cmdLet = 'Set-QuarantinePolicy' } + Default { + throw "Invalid action specified. Valid actions are: Add, New, Edit, Set, Update." + } + } + } + } + + $null = New-ExoRequest -tenantid $tenantFilter -cmdlet $cmdLet -cmdParams $cmdParams -useSystemMailbox $true + + } catch { + $ErrorMessage = Get-CippException -Exception $_ + throw ($ErrorMessage.NormalizedError -replace '\|Microsoft.Exchange.Management.Tasks.ValidationException\|', '') + } +} From bf388a7cc349ed4e52b736a8115ce551f0be7ace Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Sun, 25 May 2025 00:08:57 +0200 Subject: [PATCH 103/149] Updated to use new Set-CIPPQuarantinePolicy function --- .../Invoke-CIPPStandardQuarantineTemplate.ps1 | 133 +++++------------- 1 file changed, 38 insertions(+), 95 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 index 05d7cdda04ae..68e3d2e3f560 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 @@ -41,50 +41,7 @@ function Invoke-CIPPStandardQuarantineTemplate { param($Tenant, $Settings) - - function Convert-HashtableToEndUserQuarantinePermissionsValue { - param ( - [hashtable]$InputHashtable - ) - #Converts hashtable with selected end user quarantine permissions to decimal value used by EndUserQuarantinePermissionsValue property in New-QuarantinePolicy and Set-QuarantinePolicy - try { - $EndUserQuarantinePermissionsValue = 0 - $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToViewHeader * 128 - $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToDownload * 64 - $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToAllowSender * 32 - $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToBlockSender * 16 - $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToRequestRelease * 8 - $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToRelease * 4 - $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToPreview * 2 - $EndUserQuarantinePermissionsValue += [int]$InputHashtable.PermissionToDelete * 1 - return $EndUserQuarantinePermissionsValue - } - catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - throw "Convert-HashtableToEndUserQuarantinePermissionsValue: Failed to hashtable QuarantinePermissionsValue. Error: $ErrorMessage" - } - } - - function Convert-StringToHashtable { - param ( - [string]$InputString - ) - #Converts string value with EndUserQuarantinePermissions received from Get-QuarantinePolicy - try { - # Remove square brackets and split into lines - $InputString = $InputString.Trim('[', ']') - $hashtable = @{} - $InputString -split "`n" | ForEach-Object { - $key, $value = $_ -split ":\s*" - $hashtable[$key.Trim()] = [System.Convert]::ToBoolean($value.Trim()) - } - return $hashtable - } - catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - throw "Convert-StringToHashtable: Failed to convert string to hashtable. Error: $ErrorMessage" - } - } + $APIName = 'Standards' try { # Get the current custom quarantine policies @@ -93,21 +50,13 @@ function Invoke-CIPPStandardQuarantineTemplate { # Compare the settings from standard with the current policies $CompareList = foreach ($Policy in $Settings) { try { - # prepare the cmdParams used in New-ExoRequest - $cmdParams = @{ - ESNEnabled = $Policy.ESNEnabled - IncludeMessagesFromBlockedSenderAddress = $Policy.IncludeMessagesFromBlockedSenderAddress - } - - # Create hashtable with desired EndUserQuarantinePermissions + # Create hashtable with desired Quarantine Setting $EndUserQuarantinePermissions = @{ PermissionToBlockSender = $Policy.PermissionToBlockSender PermissionToDelete = $Policy.PermissionToDelete - PermissionToDownload = $false PermissionToPreview = $Policy.PermissionToPreview - PermissionToRelease = if ($Policy.ReleaseAction -eq "PermissionToRelease") { $true } else { $false } - PermissionToRequestRelease = if ($Policy.ReleaseAction -eq "PermissionToRequestRelease") { $true } else { $false } - PermissionToViewHeader = $true + PermissionToRelease = $Policy.ReleaseAction -eq "PermissionToRelease" ? $true : $false + PermissionToRequestRelease = $Policy.ReleaseAction -eq "PermissionToRequestRelease" ? $true : $false PermissionToAllowSender = $Policy.PermissionToAllowSender } @@ -115,7 +64,7 @@ function Invoke-CIPPStandardQuarantineTemplate { if ($Policy.displayName.value -in $CurrentPolicies.Name) { #Get the current policy and convert EndUserQuarantinePermissions from string to hashtable for compare $ExistingPolicy = $CurrentPolicies | Where-Object -Property Name -eq $Policy.displayName.value - $ExistingPolicyEndUserQuarantinePermissions = Convert-StringToHashtable -InputString $ExistingPolicy.EndUserQuarantinePermissions -ErrorAction Stop + $ExistingPolicyEndUserQuarantinePermissions = Convert-QuarantinePermissionsValue -InputObject $ExistingPolicy.EndUserQuarantinePermissions -ErrorAction Stop #Compare the current policy $StateIsCorrect = ($ExistingPolicy.Name -eq $Policy.displayName.value) -and @@ -128,9 +77,11 @@ function Invoke-CIPPStandardQuarantineTemplate { [PSCustomObject]@{ missing = $false StateIsCorrect = $StateIsCorrect + Action = "None" displayName = $Policy.displayName.value EndUserQuarantinePermissions = $EndUserQuarantinePermissions - cmdParams = $cmdParams + ESNEnabled = $Policy.ESNEnabled + IncludeMessagesFromBlockedSenderAddress = $Policy.IncludeMessagesFromBlockedSenderAddress remediate = $Policy.remediate alert = $Policy.alert report = $Policy.report @@ -141,9 +92,11 @@ function Invoke-CIPPStandardQuarantineTemplate { [PSCustomObject]@{ missing = $false StateIsCorrect = $StateIsCorrect + Action = "Update" displayName = $Policy.displayName.value EndUserQuarantinePermissions = $EndUserQuarantinePermissions - cmdParams = $cmdParams + ESNEnabled = $Policy.ESNEnabled + IncludeMessagesFromBlockedSenderAddress = $Policy.IncludeMessagesFromBlockedSenderAddress remediate = $Policy.remediate alert = $Policy.alert report = $Policy.report @@ -155,9 +108,11 @@ function Invoke-CIPPStandardQuarantineTemplate { [PSCustomObject]@{ missing = $true StateIsCorrect = $false + Action = "Create" displayName = $Policy.displayName.value EndUserQuarantinePermissions = $EndUserQuarantinePermissions - cmdParams = $cmdParams + ESNEnabled = $Policy.ESNEnabled + IncludeMessagesFromBlockedSenderAddress = $Policy.IncludeMessagesFromBlockedSenderAddress remediate = $Policy.remediate alert = $Policy.alert report = $Policy.report @@ -166,7 +121,9 @@ function Invoke-CIPPStandardQuarantineTemplate { } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to compare Quarantine policy $($Policy.displayName.value), Error: $ErrorMessage" -sev 'Error' + $Message = "Failed to compare Quarantine policy $($Policy.displayName.value), Error: $ErrorMessage" + Write-LogMessage -API $APIName -tenant $tenant -message $Message -sev 'Error' + Return $Message } } @@ -175,43 +132,29 @@ function Invoke-CIPPStandardQuarantineTemplate { # Remediate each policy which is incorrect or missing foreach ($Policy in $CompareList | Where-Object { $_.remediate -EQ $true -and $_.StateIsCorrect -eq $false }) { try { - # Convert desired EndUserQuarantinePermissions to decimal value - $EndUserQuarantinePermissionsValue = Convert-HashtableToEndUserQuarantinePermissionsValue -InputHashtable $Policy.EndUserQuarantinePermissions -ErrorAction Stop - $cmdParams = $Policy.cmdParams - - # Create policy if missing - if ($Policy.missing) { - try { - #Add the rest of the desired settings to cmdParams - $cmdParams.Add('Name', $Policy.displayName) - $cmdParams.Add('EndUserQuarantinePermissionsValue', $EndUserQuarantinePermissionsValue) - - New-ExoRequest -tenantid $Tenant -cmdlet 'New-QuarantinePolicy' -cmdParams $cmdParams -UseSystemMailbox $true -ErrorAction Stop - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Custom Quarantine Policy $($Policy.displayName)" -sev Info - } - catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create Quarantine policy $($Policy.displayName), Error: $ErrorMessage" -sev 'Error' - } + # Parameters for splatting to Set-CIPPQuarantinePolicy + $Params = @{ + Action = $Policy.Action + Identity = $Policy.displayName + EndUserQuarantinePermissions = $Policy.EndUserQuarantinePermissions + ESNEnabled = $Policy.ESNEnabled + IncludeMessagesFromBlockedSenderAddress = $Policy.IncludeMessagesFromBlockedSenderAddress + tenantFilter = $Tenant + APIName = $APIName } - # Update policy if incorrect - else { - try { - #Add the rest of the desired settings to cmdParams - $cmdParams.Add('Identity', $Policy.displayName) - $cmdParams.Add('EndUserQuarantinePermissionsValue', $EndUserQuarantinePermissionsValue) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-QuarantinePolicy' -cmdParams $cmdParams -UseSystemMailbox $true -ErrorAction Stop - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Custom Quarantine Policy $($Policy.displayName)" -sev Info - } - catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Custom Quarantine Policy $($Policy.displayName)" -sev Error -LogData $_ - } + try { + Set-CIPPQuarantinePolicy @Params + Write-LogMessage -API $APIName -tenant $Tenant -message "$($Policy.Action)d Custom Quarantine Policy '$($Policy.displayName)'" -sev Info + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API $APIName -tenant $tenant -message "Failed to $($Policy.Action) Quarantine policy $($Policy.displayName), Error: $ErrorMessage" -sev 'Error' } } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Quarantine policy $($Policy.displayName), Error: $ErrorMessage" -sev 'Error' + Write-LogMessage -API $APIName -tenant $tenant -message "Failed to create or update Quarantine policy $($Policy.displayName), Error: $ErrorMessage" -sev 'Error' } } } @@ -219,18 +162,18 @@ function Invoke-CIPPStandardQuarantineTemplate { if ($true -in $Settings.alert) { foreach ($Policy in $CompareList | Where-Object -Property alert -EQ $true) { if ($Policy.StateIsCorrect) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Quarantine policy $($Policy.displayName) has the correct configuration." -sev Info + Write-LogMessage -API $APIName -tenant $Tenant -message "Quarantine policy $($Policy.displayName) has the correct configuration." -sev Info } else { if ($Policy.missing) { $CurrentInfo = $Policy | Select-Object -Property displayName, missing Write-StandardsAlert -message "Quarantine policy $($Policy.displayName) is missing." -object $CurrentInfo -tenant $Tenant -standardName 'QuarantineTemplate' -standardId $Settings.templateId - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Quarantine policy $($Policy.displayName) is missing." -sev info + Write-LogMessage -API $APIName -tenant $Tenant -message "Quarantine policy $($Policy.displayName) is missing." -sev info } else { $CurrentInfo = $CurrentPolicies | Where-Object -Property Name -eq $Policy.displayName | Select-Object -Property Name, ESNEnabled, IncludeMessagesFromBlockedSenderAddress, EndUserQuarantinePermissions Write-StandardsAlert -message "Quarantine policy $($Policy.displayName) does not match the expected configuration." -object $CurrentInfo -tenant $Tenant -standardName 'QuarantineTemplate' -standardId $Settings.templateId - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Quarantine policy $($Policy.displayName) does not match the expected configuration. We've generated an alert" -sev info + Write-LogMessage -API $APIName -tenant $Tenant -message "Quarantine policy $($Policy.displayName) does not match the expected configuration. We've generated an alert" -sev info } } } @@ -245,6 +188,6 @@ function Invoke-CIPPStandardQuarantineTemplate { } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Quarantine policy/policies, Error: $ErrorMessage" -sev 'Error' + Write-LogMessage -API $APIName -tenant $tenant -message "Failed to create or update Quarantine policy/policies, Error: $ErrorMessage" -sev 'Error' } } From ac8b589a14279217da12a8650ae91fcb1395b220 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 26 May 2025 16:39:06 +0200 Subject: [PATCH 104/149] latest dev update --- .../CIPP/Setup/Invoke-ExecCombinedSetup.ps1 | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 new file mode 100644 index 000000000000..fecc43d59d40 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 @@ -0,0 +1,71 @@ +using namespace System.Net + +Function Invoke-ExecCombinedSetup { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.AppSettings.ReadWrite. + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + #Make arraylist of Results + $Results = [System.Collections.ArrayList]::new() + try { + if ($request.body.selectedBaselines -and $request.body.baselineOption -eq 'downloadBaselines') { + #do a single download of the selected baselines. + foreach ($template in $request.body.selectedBaselines) { + $object = @{ + TenantFilter = 'No tenant' + Name = "Download Single Baseline: $($template.value)" + Command = @{ + value = 'New-CIPPTemplateRun' + } + Parameters = @{ + TemplateSettings = @{ + ca = $false + intuneconfig = $false + intunecompliance = $false + intuneprotection = $false + templateRepo = @{ + label = $Template.label + value = $template.value + addedFields = @{ + branch = 'main' + } + } + templateRepoBranch = @{ + label = 'main' + value = 'main' + } + standardsconfig = $true + groupTemplates = $true + policyTemplates = $true + caTemplates = $true + } + } + ScheduledTime = 0 + } + $null = Add-CIPPScheduledTask -task $object -hidden $false -DisallowDuplicateName $true -Headers $Request.Headers + $Results.add("Scheduled download of baseline: $($template.value)") + } + } + if ($Request.body.email -or $Request.body.webhook) { + $notificationConfig = $request.body + $notificationResults = Set-CIPPNotificationConfig @notificationConfig + $Results.add($notificationResults) + } + $Results.add('Setup is now complete. You may navigate away from this page and start using CIPP.') + #one more force of reauth so env vars update. + $auth = Get-CIPPAuthentication + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)"; severity = 'failed' } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} From 19ca56d57f8a17b9f1938ece0a3ff707b408b158 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 26 May 2025 18:32:48 +0200 Subject: [PATCH 105/149] updates to caches --- .../HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 | 3 ++- Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 index fecc43d59d40..2517ba27122c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 @@ -51,7 +51,8 @@ Function Invoke-ExecCombinedSetup { } } if ($Request.body.email -or $Request.body.webhook) { - $notificationConfig = $request.body + #create hashtable from pscustomobject + $notificationConfig = $request.body | Select-Object email, webhook, onepertenant, logsToInclude, sendtoIntegration, sev | ConvertTo-Json | ConvertFrom-Json -AsHashtable $notificationResults = Set-CIPPNotificationConfig @notificationConfig $Results.add($notificationResults) } diff --git a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 index acb67becb66e..d46ce84905ab 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 @@ -8,7 +8,7 @@ function Remove-CIPPCache { ) # Remove all tenants except excluded $TenantsTable = Get-CippTable -tablename 'Tenants' - $Filter = "PartitionKey eq 'Tenants' and Excluded eq false" + $Filter = "PartitionKey eq 'Tenants' and Excluded eq false and delegatedPrivilegeStatus eq 'granularDelegatedAdminPrivileges'" $ClearIncludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter -Property PartitionKey, RowKey if ($ClearIncludedTenants) { Remove-AzDataTableEntity -Force @TenantsTable -Entity $ClearIncludedTenants From 3de0eae9d486e7fdfcb21a9a656f3c742861047a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 26 May 2025 18:35:47 +0200 Subject: [PATCH 106/149] add goose code: add calculatedGroupType to user group output --- .../Administration/Users/Invoke-ListUserGroups.ps1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 index 88123afee17b..b32e828cfd9f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 @@ -22,7 +22,7 @@ Function Invoke-ListUserGroups { $UserID = $Request.Query.UserID - $URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole`&$orderby=displayName asc" + $URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole`&`$orderby=displayName asc" Write-Host $URI $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object id, @{ Name = 'DisplayName'; Expression = { $_.displayName } }, @@ -31,7 +31,14 @@ Function Invoke-ListUserGroups { @{ Name = 'SecurityGroup'; Expression = { $_.securityEnabled } }, @{ Name = 'GroupTypes'; Expression = { $_.groupTypes -join ',' } }, @{ Name = 'OnPremisesSync'; Expression = { $_.onPremisesSyncEnabled } }, - @{ Name = 'IsAssignableToRole'; Expression = { $_.isAssignableToRole } } + @{ Name = 'IsAssignableToRole'; Expression = { $_.isAssignableToRole } }, + @{ Name = 'calculatedGroupType'; Expression = { + if ($_.mailEnabled -and $_.securityEnabled) { 'Mail-Enabled Security' } + if (!$_.mailEnabled -and $_.securityEnabled) { 'Security' } + if ($_.groupTypes -contains 'Unified') { 'Microsoft 365' } + if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { 'Distribution List' } + } + } # Associate values to output bindings by calling 'Push-OutputBinding'. From 4777f16053cf751bc66707bfc87a53e704621738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 26 May 2025 18:45:25 +0200 Subject: [PATCH 107/149] casing --- .../Administration/Users/Invoke-ListUserGroups.ps1 | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 index b32e828cfd9f..62b52e039e08 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 @@ -14,17 +14,13 @@ Function Invoke-ListUserGroups { $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - - - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $UserID = $Request.Query.UserID - - + $TenantFilter = $Request.Query.tenantFilter + $UserID = $Request.Query.userId $URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole`&`$orderby=displayName asc" Write-Host $URI - $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object id, + + $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -Verbose | Select-Object id, @{ Name = 'DisplayName'; Expression = { $_.displayName } }, @{ Name = 'MailEnabled'; Expression = { $_.mailEnabled } }, @{ Name = 'Mail'; Expression = { $_.mail } }, From 8ef72dfbc0d17ac22e321de2fb45156992e5eb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 26 May 2025 18:54:48 +0200 Subject: [PATCH 108/149] another syntax thing --- .../Identity/Administration/Users/Invoke-ListUserGroups.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 index 62b52e039e08..dd44cf2ccc4a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 @@ -17,7 +17,7 @@ Function Invoke-ListUserGroups { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.tenantFilter $UserID = $Request.Query.userId - $URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole`&`$orderby=displayName asc" + $URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole&`$orderby=displayName asc" Write-Host $URI $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -Verbose | Select-Object id, From a143bbbc6e590292a246567c7985b36309ac0ffe Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 26 May 2025 22:32:50 +0200 Subject: [PATCH 109/149] keyvault --- .../Entrypoints/Invoke-ExecListAppId.ps1 | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index 1355939a6b3c..f0a9db411b84 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -21,8 +21,24 @@ Function Invoke-ExecListAppId { $env:ApplicationID = $Secret.ApplicationID $env:TenantID = $Secret.TenantID } else { - $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $env:WEBSITE_DEPLOYMENT_ID -Name 'ApplicationID').SecretValueText - $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $env:WEBSITE_DEPLOYMENT_ID -Name 'TenantID').SecretValueText + Write-Information 'Connecting to Azure' + Connect-AzAccount -Identity + $SubscriptionId = $env:WEBSITE_OWNER_NAME -split '\+' | Select-Object -First 1 + try { + $Context = Get-AzContext + if ($Context.Subscription) { + #Write-Information "Current context: $($Context | ConvertTo-Json)" + if ($Context.Subscription.Id -ne $SubscriptionId) { + Write-Information "Setting context to subscription $SubscriptionId" + $null = Set-AzContext -SubscriptionId $SubscriptionId + } + } + } catch { + Write-Information "ERROR: Could not set context to subscription $SubscriptionId." + } + $keyvaultname = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] + $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'ApplicationID').SecretValueText + $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'TenantID').SecretValueText } $Results = @{ applicationId = $env:ApplicationID From 9a7afc82b2ad138838b9f8e1fe5c1b62b62a4a66 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 26 May 2025 23:04:43 +0200 Subject: [PATCH 110/149] test --- .../Public/Entrypoints/Invoke-ExecListAppId.ps1 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index f0a9db411b84..81c5ac636bf8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -37,8 +37,14 @@ Function Invoke-ExecListAppId { Write-Information "ERROR: Could not set context to subscription $SubscriptionId." } $keyvaultname = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] - $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'ApplicationID').SecretValueText - $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'TenantID').SecretValueText + try { + $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'ApplicationID').SecretValueText + $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'TenantID').SecretValueText + } catch { + Write-LogMessage -message "Failed to retrieve secrets from KeyVault: $keyvaultname" -LogData (Get-CippException -Exception $_) -Sev 'Error' + $env:ApplicationID = (Get-CippException -Exception $_) + $env:TenantID = (Get-CippException -Exception $_) + } } $Results = @{ applicationId = $env:ApplicationID From a851aa4059cb21748ecf91a04b630c5cc7d74948 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 26 May 2025 23:20:22 +0200 Subject: [PATCH 111/149] fixes new appid --- .../HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 | 2 +- Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 index 184f8c12bbad..42e793a5e0f1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecTokenExchange.ps1 @@ -41,7 +41,7 @@ Function Invoke-ExecTokenExchange { Write-LogMessage -API $APIName -message 'Retrieved client secret from development secrets' -Sev 'Info' } else { try { - $ClientSecret = (Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText).SecretValue + $ClientSecret = (Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText) Write-LogMessage -API $APIName -message 'Retrieved client secret from key vault' -Sev 'Info' } catch { Write-LogMessage -API $APIName -message "Failed to retrieve client secret: $($_.Exception.Message)" -Sev 'Error' diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index 81c5ac636bf8..9618084d70e1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -38,8 +38,8 @@ Function Invoke-ExecListAppId { } $keyvaultname = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] try { - $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'ApplicationID').SecretValueText - $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'TenantID').SecretValueText + $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'ApplicationID') + $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'TenantID') } catch { Write-LogMessage -message "Failed to retrieve secrets from KeyVault: $keyvaultname" -LogData (Get-CippException -Exception $_) -Sev 'Error' $env:ApplicationID = (Get-CippException -Exception $_) From be7606c7ebefb018b1c74f49db598f96600e3054 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 26 May 2025 23:27:02 +0200 Subject: [PATCH 112/149] push --- Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index 9618084d70e1..9b1a407cb828 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -40,6 +40,7 @@ Function Invoke-ExecListAppId { try { $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'ApplicationID') $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'TenantID') + Write-Host "Retrieving secrets from KeyVault: $keyvaultname. The AppId is $($env:ApplicationID) and the TenantId is $($env:TenantID)" } catch { Write-LogMessage -message "Failed to retrieve secrets from KeyVault: $keyvaultname" -LogData (Get-CippException -Exception $_) -Sev 'Error' $env:ApplicationID = (Get-CippException -Exception $_) From c4343601aeda6bbb7bae414a9920d52329c9375d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 26 May 2025 23:33:28 +0200 Subject: [PATCH 113/149] why you no work. --- Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index 9b1a407cb828..94eb35a5c3d1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -36,12 +36,14 @@ Function Invoke-ExecListAppId { } catch { Write-Information "ERROR: Could not set context to subscription $SubscriptionId." } + $keyvaultname = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] try { $env:ApplicationID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'ApplicationID') $env:TenantID = (Get-AzKeyVaultSecret -AsPlainText -VaultName $keyvaultname -Name 'TenantID') - Write-Host "Retrieving secrets from KeyVault: $keyvaultname. The AppId is $($env:ApplicationID) and the TenantId is $($env:TenantID)" + Write-Information "Retrieving secrets from KeyVault: $keyvaultname. The AppId is $($env:ApplicationID) and the TenantId is $($env:TenantID)" } catch { + Write-Information "Retrieving secrets from KeyVault: $keyvaultname. The AppId is $($env:ApplicationID) and the TenantId is $($env:TenantID)" Write-LogMessage -message "Failed to retrieve secrets from KeyVault: $keyvaultname" -LogData (Get-CippException -Exception $_) -Sev 'Error' $env:ApplicationID = (Get-CippException -Exception $_) $env:TenantID = (Get-CippException -Exception $_) From b965f1fd872e3fe5d3ca08cf3e75cf6fff7cdade Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 11:22:07 +0200 Subject: [PATCH 114/149] correction for custom roles --- .../HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 | 2 +- .../HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 | 2 +- .../HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 | 2 +- .../HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 index 7764294b94a5..e629a1015dde 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecAddTenant { .FUNCTIONALITY Entrypoint,AnyTenant .ROLE - CIPP.AppSettings.ReadWrite. + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 index 2517ba27122c..6331d1e2fdc9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecCombinedSetup { .FUNCTIONALITY Entrypoint,AnyTenant .ROLE - CIPP.AppSettings.ReadWrite. + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 index e439329713fd..b2f62dabd4aa 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecCreateSAMApp { .FUNCTIONALITY Entrypoint,AnyTenant .ROLE - CIPP.AppSettings.ReadWrite. + CIPP.AppSettings.ReadWrite #> [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] [CmdletBinding()] diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 index 1e83d9d5db0d..5ae685d59fd5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecUpdateRefreshToken { .FUNCTIONALITY Entrypoint,AnyTenant .ROLE - CIPP.AppSettings.ReadWrite. + CIPP.AppSettings.ReadWrite #> [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] [CmdletBinding()] From d3e781a7d56decc6a8124310d513c2162ede1ba5 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 11:47:00 +0200 Subject: [PATCH 115/149] added appid detection to prevent cache hit --- .../CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 | 8 ++++++++ Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 index b2f62dabd4aa..1b82262019eb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 @@ -84,6 +84,14 @@ Function Invoke-ExecCreateSAMApp { Write-Information ($Secret | ConvertTo-Json -Depth 5) Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force } else { + $ConfigTable = Get-CippTable -tablename 'Config' + #update the ConfigTable with the latest appId, for caching compare. + $NewConfig = @{ + PartitionKey = 'AppCache' + RowKey = 'AppCache' + ApplicationId = $AppId.appId + } + Set-CIPPAzDataTableEntity @ConfigTable -Entity $NewConfig -Force | Out-Null Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $TenantId -AsPlainText -Force) Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appId -AsPlainText -Force) Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $AppPassword -AsPlainText -Force) diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index 5473f274f54c..0c333caad6dd 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -6,6 +6,15 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT if (!$scope) { $scope = 'https://graph.microsoft.com/.default' } if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } + $ConfigTable = Get-CippTable -tablename 'Config' + $Filter = "PartitionKey eq 'AppCache' and RowKey eq 'AppCache'" + $AppCache = Get-CIPPAzDataTableEntity @ConfigTable -Filter $Filter + #force auth update is appId is not the same as the one in the environment variable. + if ($AppCache.ApplicationId -and $env:ApplicationID -ne $AppCache.ApplicationId) { + Write-Host "Setting environment variable ApplicationID to $($AppCache.ApplicationId)" + $CIPPAuth = Get-CIPPAuthentication + } + #If the $env:<$tenantid> is set, use that instead of the refreshtoken for all tenants. $refreshToken = $env:RefreshToken if (!$tenantid) { $tenantid = $env:TenantID } From 2c01e6262f4930132ad5ef08acfce51f66e44ffa Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 11:47:44 +0200 Subject: [PATCH 116/149] ExecSamApp --- .../CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 index 1b82262019eb..d3d4db1d41bd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 @@ -84,18 +84,19 @@ Function Invoke-ExecCreateSAMApp { Write-Information ($Secret | ConvertTo-Json -Depth 5) Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force } else { - $ConfigTable = Get-CippTable -tablename 'Config' - #update the ConfigTable with the latest appId, for caching compare. - $NewConfig = @{ - PartitionKey = 'AppCache' - RowKey = 'AppCache' - ApplicationId = $AppId.appId - } - Set-CIPPAzDataTableEntity @ConfigTable -Entity $NewConfig -Force | Out-Null + Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $TenantId -AsPlainText -Force) Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appId -AsPlainText -Force) Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $AppPassword -AsPlainText -Force) } + $ConfigTable = Get-CippTable -tablename 'Config' + #update the ConfigTable with the latest appId, for caching compare. + $NewConfig = @{ + PartitionKey = 'AppCache' + RowKey = 'AppCache' + ApplicationId = $AppId.appId + } + Set-CIPPAzDataTableEntity @ConfigTable -Entity $NewConfig -Force | Out-Null $Results = @{'message' = "Succesfully $state the application registration. The application ID is $($AppId.appid). You may continue to the next step."; severity = 'success' } } From 94f10136d808642c4529e7258dff1b9920097362 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 11:55:01 +0200 Subject: [PATCH 117/149] typo --- .../HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 index d3d4db1d41bd..7d3dcfcf5819 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 @@ -96,7 +96,7 @@ Function Invoke-ExecCreateSAMApp { RowKey = 'AppCache' ApplicationId = $AppId.appId } - Set-CIPPAzDataTableEntity @ConfigTable -Entity $NewConfig -Force | Out-Null + Add-CIPPAzDataTableEntity @ConfigTable -Entity $NewConfig -Force | Out-Null $Results = @{'message' = "Succesfully $state the application registration. The application ID is $($AppId.appid). You may continue to the next step."; severity = 'success' } } From 58e3a362a120c21c6bab1e24fe6581569284b1dc Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 12:33:57 +0200 Subject: [PATCH 118/149] appIdTroubleshooting --- Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index 0c333caad6dd..0da8dfebaf5d 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -10,12 +10,12 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT $Filter = "PartitionKey eq 'AppCache' and RowKey eq 'AppCache'" $AppCache = Get-CIPPAzDataTableEntity @ConfigTable -Filter $Filter #force auth update is appId is not the same as the one in the environment variable. + Write-Host "My appId pre-launch is $($env:ApplicationID) and the one in the cache is $($AppCache.ApplicationId)" if ($AppCache.ApplicationId -and $env:ApplicationID -ne $AppCache.ApplicationId) { Write-Host "Setting environment variable ApplicationID to $($AppCache.ApplicationId)" $CIPPAuth = Get-CIPPAuthentication } - - #If the $env:<$tenantid> is set, use that instead of the refreshtoken for all tenants. + Write-Host "My appId post-launch is $($env:ApplicationID) and the one in the cache is $($AppCache.ApplicationId)" $refreshToken = $env:RefreshToken if (!$tenantid) { $tenantid = $env:TenantID } #Get list of tenants that have 'directTenant' set to true From 3af3902791f6c8d78da4d275e51517a931f22912 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 12:56:44 +0200 Subject: [PATCH 119/149] stupid bug --- .../HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 index 5ae685d59fd5..d142586ab8c9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -29,7 +29,7 @@ Function Invoke-ExecUpdateRefreshToken { } Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force } else { - if ($env:ApplicationId -eq $Request.body.tenantId) { + if ($env:TenantID -eq $Request.body.tenantId) { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) } else { $name = $Request.body.tenantId -replace '-', '_' From 0ca55a21174d0863a8c89bb15869e34a1a0e0fc6 Mon Sep 17 00:00:00 2001 From: Esco Date: Tue, 27 May 2025 13:08:12 +0200 Subject: [PATCH 120/149] feat: Allow exclude when Group is included --- Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index a40c6cb07463..31643c813caf 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -141,7 +141,7 @@ function Get-CIPPStandards { $excludedTenantValues = $template.excludedTenants | ForEach-Object { $FilterValue = $_.value if ($_.type -eq 'Group') { - ($TenantGroups | Where-Object { + ($TenantGroups | Where-Object { $_.Id -eq $FilterValue }).Members.defaultDomainName } else { @@ -158,7 +158,7 @@ function Get-CIPPStandards { if ($tenantFilterValues -contains 'AllTenants' -and -not ($excludedTenantValues -contains $TenantName)) { $AllTenantsApplicable = $true } - if ($tenantFilterValues -contains $TenantName) { + if ($tenantFilterValues -contains $TenantName -and -not ($excludedTenantValues -contains $TenantName)) { $TenantSpecificApplicable = $true } From ea12858814eae49eecdf703d8d6a39b9e208e98a Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Tue, 27 May 2025 14:39:14 +0200 Subject: [PATCH 121/149] Modified to calculate decimalValue from binary all values are now parameters and use parameterSetName --- .../Convert-QuarantinePermissionsValue.ps1 | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/Modules/CIPPCore/Private/Convert-QuarantinePermissionsValue.ps1 b/Modules/CIPPCore/Private/Convert-QuarantinePermissionsValue.ps1 index 196664c4a288..29cbff702118 100644 --- a/Modules/CIPPCore/Private/Convert-QuarantinePermissionsValue.ps1 +++ b/Modules/CIPPCore/Private/Convert-QuarantinePermissionsValue.ps1 @@ -1,16 +1,30 @@ function Convert-QuarantinePermissionsValue { + [CmdletBinding(DefaultParameterSetName = 'DecimalValue')] param ( - [Parameter(Mandatory = $true, Position=0)] + [Parameter(Mandatory, Position = 0, ParameterSetName = "StringValue")] [ValidateNotNullOrEmpty()] - [ValidateScript( - {$_ -is [String] ? $true : $_ -is [Hashtable] ? $true : $false}, - ErrorMessage = "Input must be a string or hashtable." - )] - $InputObject + [string]$InputObject, + + [Parameter(Position = 0, ParameterSetName = "DecimalValue")] + [int]$PermissionToViewHeader = 0, + [Parameter(Position = 1, ParameterSetName = "DecimalValue")] + [int]$PermissionToDownload = 0, + [Parameter(Mandatory, Position = 2, ParameterSetName = "DecimalValue")] + [int]$PermissionToAllowSender, + [Parameter(Mandatory, Position = 3, ParameterSetName = "DecimalValue")] + [int]$PermissionToBlockSender, + [Parameter(Mandatory, Position = 4, ParameterSetName = "DecimalValue")] + [int]$PermissionToRequestRelease, + [Parameter(Mandatory, Position = 5, ParameterSetName = "DecimalValue")] + [int]$PermissionToRelease, + [Parameter(Mandatory, Position = 6, ParameterSetName = "DecimalValue")] + [int]$PermissionToPreview, + [Parameter(Mandatory, Position = 7, ParameterSetName = "DecimalValue")] + [int]$PermissionToDelete ) #Converts string value with EndUserQuarantinePermissions received from Get-QuarantinePolicy - if ($InputObject -is [String]) { + if (($PSCmdlet.ParameterSetName) -eq "StringValue") { try { # Remove square brackets and split into lines $InputObject = $InputObject.Trim('[', ']') @@ -22,28 +36,36 @@ function Convert-QuarantinePermissionsValue { return $hashtable } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - throw "Convert-QuarantinePermissionsValue: Failed to convert string to hashtable. Error: $ErrorMessage" + throw "Convert-QuarantinePermissionsValue: Failed to convert string to hashtable." } } - #Converts hashtable with selected end user quarantine permissions to decimal value used by EndUserQuarantinePermissionsValue property in New-QuarantinePolicy and Set-QuarantinePolicy - elseif ($InputObject -is [Hashtable]) { + #Converts selected end user quarantine permissions to decimal value used by EndUserQuarantinePermissionsValue property in New-QuarantinePolicy and Set-QuarantinePolicy + elseif (($PSCmdlet.ParameterSetName) -eq "DecimalValue") { try { - $EndUserQuarantinePermissionsValue = 0 - $EndUserQuarantinePermissionsValue += ([int]$InputObject.PermissionToViewHeader ?? 0 ) * 128 - $EndUserQuarantinePermissionsValue += ([int]$InputObject.PermissionToDownload ?? 0 ) * 64 - $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToAllowSender * 32 - $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToBlockSender * 16 - $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToRequestRelease * 8 - $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToRelease * 4 - $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToPreview * 2 - $EndUserQuarantinePermissionsValue += [int]$InputObject.PermissionToDelete * 1 - return $EndUserQuarantinePermissionsValue + # both PermissionToRequestRelease and PermissionToRelease cannot be set to true at the same time + if($PermissionToRequestRelease -eq 1 -and $PermissionToRelease -eq 1) { + throw "PermissionToRequestRelease and PermissionToRelease cannot both be set to true." + } + + # Convert each permission to a binary string + $BinaryValue = [string]@( + $PermissionToViewHeader, + $PermissionToDownload, + $PermissionToAllowSender, + $PermissionToBlockSender, + $PermissionToRequestRelease, + $PermissionToRelease, + $PermissionToPreview, + $PermissionToDelete + ) -replace '\s','' + + # Convert the binary string to an Decimal value + return [convert]::ToInt32($BinaryValue,2) } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - throw "Convert-QuarantinePermissionsValue: Failed to convert hashtable to QuarantinePermissionsValue. Error: $ErrorMessage" + throw "Convert-QuarantinePermissionsValue: Failed to convert QuarantinePermissions to QuarantinePermissionsValue. Error: $ErrorMessage" } } } From cc25135e176acfc1f1413fddccee799d3b591625 Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Tue, 27 May 2025 14:44:29 +0200 Subject: [PATCH 122/149] Convert function are now called using splatting --- Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 | 2 +- .../Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 index 665e35f57575..b0fed36a0dc9 100644 --- a/Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPQuarantinePolicy.ps1 @@ -85,7 +85,7 @@ function Set-CIPPQuarantinePolicy { } "QuarantinePolicy" { $cmdParams = @{ - EndUserQuarantinePermissionsValue = Convert-QuarantinePermissionsValue -InputObject $EndUserQuarantinePermissions + EndUserQuarantinePermissionsValue = Convert-QuarantinePermissionsValue @EndUserQuarantinePermissions -ErrorAction Stop ESNEnabled = $ESNEnabled IncludeMessagesFromBlockedSenderAddress = $IncludeMessagesFromBlockedSenderAddress } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 index 68e3d2e3f560..c8f98fc6a7c2 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 @@ -64,7 +64,7 @@ function Invoke-CIPPStandardQuarantineTemplate { if ($Policy.displayName.value -in $CurrentPolicies.Name) { #Get the current policy and convert EndUserQuarantinePermissions from string to hashtable for compare $ExistingPolicy = $CurrentPolicies | Where-Object -Property Name -eq $Policy.displayName.value - $ExistingPolicyEndUserQuarantinePermissions = Convert-QuarantinePermissionsValue -InputObject $ExistingPolicy.EndUserQuarantinePermissions -ErrorAction Stop + $ExistingPolicyEndUserQuarantinePermissions = Convert-QuarantinePermissionsValue @EndUserQuarantinePermissions -ErrorAction Stop #Compare the current policy $StateIsCorrect = ($ExistingPolicy.Name -eq $Policy.displayName.value) -and From 0116284010c44438fcfa9c75b55e9ee826c9bb3a Mon Sep 17 00:00:00 2001 From: ngms-psh Date: Tue, 27 May 2025 14:45:15 +0200 Subject: [PATCH 123/149] Modified to use Get-Tenants instead of direct from table --- .../Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 index 020f10fa53e5..28503f12c001 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddQuarantinePolicy.ps1 @@ -16,10 +16,9 @@ Function Invoke-AddQuarantinePolicy { $Tenants = ($Request.body.selectedTenants).value - # If allTenants is selected, get all tenants from table and overwrite any other tenant selection + # If allTenants is selected, get all tenants and overwrite any other tenant selection if ("AllTenants" -in $Tenants) { - $TenantTable = Get-CIPPTable -tablename 'Tenants' - $tenants = (Get-CIPPAzDataTableEntity @TenantTable -Filter "PartitionKey eq 'Tenants'").defaultDomainName + $tenants = (Get-Tenants).defaultDomainName } $Result = foreach ($TenantFilter in $tenants) { From 869354a1f467fd7a110d09ac1fa921ce40927aac Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 15:57:16 +0200 Subject: [PATCH 124/149] add troubleshooting around kv secret add. --- .../CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 index d142586ab8c9..cecfeacec465 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -32,8 +32,14 @@ Function Invoke-ExecUpdateRefreshToken { if ($env:TenantID -eq $Request.body.tenantId) { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) } else { + Write-Host "$($env:TenantID) does not match $($Request.body.tenantId) - we're adding a new secret for the tenant." $name = $Request.body.tenantId -replace '-', '_' - Set-AzKeyVaultSecret -VaultName $kv -Name $name -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) + try { + Set-AzKeyVaultSecret -VaultName $kv -Name $name -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) + } catch { + Write-Host "Failed to set secret $name in KeyVault. $($_.Exception.Message)" + throw $_ + } } } $InstanceId = Start-UpdatePermissionsOrchestrator #start the CPV refresh immediately while wizard still runs. From 84e747da0d8cd7079f4c4a80b0155252df778dc2 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 16:43:43 +0200 Subject: [PATCH 125/149] changes for kv --- .../CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 | 2 +- Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 | 3 +-- Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 index cecfeacec465..6a8254483607 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -33,7 +33,7 @@ Function Invoke-ExecUpdateRefreshToken { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) } else { Write-Host "$($env:TenantID) does not match $($Request.body.tenantId) - we're adding a new secret for the tenant." - $name = $Request.body.tenantId -replace '-', '_' + $name = $Request.body.tenantId try { Set-AzKeyVaultSecret -VaultName $kv -Name $name -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force) } catch { diff --git a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 index e88452db366f..d741873403fa 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 @@ -57,10 +57,9 @@ function Get-CIPPAuthentication { $tenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter if ($tenants) { $tenants | ForEach-Object { - $name = $_.tenantId -replace '-', '_' + $name = $_.tenantId $secret = Get-AzKeyVaultSecret -VaultName $keyvaultname -Name $name -AsPlainText -ErrorAction Stop if ($secret) { - #set the name back to the original tenantId $name = $_.customerId Set-Item -Path env:$name -Value $secret -Force } diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index 0da8dfebaf5d..ac1ad36e954b 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -10,12 +10,10 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT $Filter = "PartitionKey eq 'AppCache' and RowKey eq 'AppCache'" $AppCache = Get-CIPPAzDataTableEntity @ConfigTable -Filter $Filter #force auth update is appId is not the same as the one in the environment variable. - Write-Host "My appId pre-launch is $($env:ApplicationID) and the one in the cache is $($AppCache.ApplicationId)" if ($AppCache.ApplicationId -and $env:ApplicationID -ne $AppCache.ApplicationId) { Write-Host "Setting environment variable ApplicationID to $($AppCache.ApplicationId)" $CIPPAuth = Get-CIPPAuthentication } - Write-Host "My appId post-launch is $($env:ApplicationID) and the one in the cache is $($AppCache.ApplicationId)" $refreshToken = $env:RefreshToken if (!$tenantid) { $tenantid = $env:TenantID } #Get list of tenants that have 'directTenant' set to true From 95f17b3847ea00c4a2a42e064ef298779b70cc81 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 27 May 2025 16:46:30 +0200 Subject: [PATCH 126/149] good catch john --- Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 index d741873403fa..6b5d2eb5b6e0 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAuthentication.ps1 @@ -57,10 +57,9 @@ function Get-CIPPAuthentication { $tenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter if ($tenants) { $tenants | ForEach-Object { - $name = $_.tenantId + $name = $_.customerId $secret = Get-AzKeyVaultSecret -VaultName $keyvaultname -Name $name -AsPlainText -ErrorAction Stop if ($secret) { - $name = $_.customerId Set-Item -Path env:$name -Value $secret -Force } } From bc71243c34e335c62a8551c21119c1d0843d030a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 10:53:28 -0400 Subject: [PATCH 127/149] direct tenant token refreshes --- .../Start-UpdateTokensTimer.ps1 | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 index 3418faa6bff1..0388ac8a504f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 @@ -7,12 +7,12 @@ function Start-UpdateTokensTimer { [CmdletBinding(SupportsShouldProcess = $true)] param() if ($PSCmdlet.ShouldProcess('Start-UpdateTokensTimer', 'Starting Update Tokens Timer')) { - + Write-Information 'Starting Update Tokens Timer' + Write-Information "Getting new refresh token for $($env:TenantId)" # Get the current universal time in the default string format. $currentUTCtime = (Get-Date).ToUniversalTime() try { $Refreshtoken = (Get-GraphToken -ReturnRefresh $true).Refresh_token - if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $Table = Get-CIPPTable -tablename 'DevSecrets' $Secret = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" @@ -39,6 +39,50 @@ function Start-UpdateTokensTimer { } catch { Write-LogMessage -API 'Update Tokens' -message 'Error updating refresh token, see Log Data for details. Will try again in 7 days.' -sev 'CRITICAL' -LogData (Get-CippException -Exception $_) } + + # Get new refresh token for each direct added tenant + $TenantList = Get-Tenants -IncludeAll | Where-Object { $_.Excluded -eq $false -and $_.delegatedPrivilegeStatus -eq 'directTenant' } + if ($TenantList.Count -eq 0) { + Write-Information 'No direct tenants found for refresh token update.' + } else { + Write-Information "Found $($TenantList.Count) direct tenants for refresh token update." + foreach ($Tenant in $TenantList) { + try { + Write-Information "Updating refresh token for tenant $($Tenant.displayName) - $($Tenant.customerId)" + $Refreshtoken = (Get-GraphToken -ReturnRefresh $true -TenantId $Tenant.customerId).Refresh_token + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $Table = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" + if ($Secret) { + $name = $Tenant.customerId -replace '-', '_' + $Secret | Add-Member -MemberType NoteProperty -Name $name -Value $Refreshtoken -Force + Add-AzDataTableEntity @Table -Entity $Secret -Force + } else { + Write-Warning "Could not update refresh token for tenant $($Tenant.displayName) ($($Tenant.customerId))." + Write-LogMessage -API 'Update Tokens' -tenant $Tenant.defaultDomainName -tenantid $Tenant.customerId -message "Could not update refresh token for tenant $($Tenant.displayName). Will try again in 7 days." -sev 'CRITICAL' + } + } else { + if ($env:MSI_SECRET) { + Disable-AzContextAutosave -Scope Process | Out-Null + $null = Connect-AzAccount -Identity + $SubscriptionId = $env:WEBSITE_OWNER_NAME -split '\+' | Select-Object -First 1 + $null = Set-AzContext -SubscriptionId $SubscriptionId + } + $KV = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] + if ($Refreshtoken) { + $name = $Tenant.customerId + Set-AzKeyVaultSecret -VaultName $KV -Name $name -SecretValue (ConvertTo-SecureString -String $Refreshtoken -AsPlainText -Force) + } else { + Write-Warning "Could not update refresh token for tenant $($Tenant.displayName) ($($Tenant.customerId))." + Write-LogMessage -API 'Update Tokens' -tenant $Tenant.defaultDomainName -tenantid $Tenant.customerId -message "Could not update refresh token for tenant $($Tenant.displayName). Will try again in 7 days." -sev 'CRITICAL' + } + } + } catch { + Write-LogMessage -API 'Update Tokens' -tenant $Tenant.defaultDomainName -tenantid $Tenant.customerId -message "Error updating refresh token for tenant $($Tenant.displayName), see Log Data for details. Will try again in 7 days." -sev 'CRITICAL' -LogData (Get-CippException -Exception $_) + } + } + } + # Write an information log with the current time. Write-Information "PowerShell timer trigger function ran! TIME: $currentUTCtime" From f93af7c91b91a668518191cc8837e2f66955e36a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 12:37:33 -0400 Subject: [PATCH 128/149] add automatic secret rotation --- .../Start-UpdateTokensTimer.ps1 | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 index 0388ac8a504f..9afe5278dffc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 @@ -37,15 +37,63 @@ function Start-UpdateTokensTimer { } } } catch { + Write-Warning "Error updating refresh token $($_.Exception.Message)." + Write-Information ($_.InvocationInfo.PositionMessage) Write-LogMessage -API 'Update Tokens' -message 'Error updating refresh token, see Log Data for details. Will try again in 7 days.' -sev 'CRITICAL' -LogData (Get-CippException -Exception $_) } + # Check application secret expiration for $env:ApplicationId and generate a new application secret if expiration is within 30 days. + try { + $AppId = $env:ApplicationID + $PasswordCredentials = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$AppId')?`$select=id,passwordCredentials" -NoAuthCheck $true -AsApp $true -ErrorAction Stop + # sort by latest expiration date and get the first one + $LastPasswordCredential = $PasswordCredentials.passwordCredentials | Sort-Object -Property endDateTime -Descending | Select-Object -First 1 + if ($LastPasswordCredential.endDateTime -lt (Get-Date).AddDays(30).ToUniversalTime()) { + Write-Information "Application secret for $AppId is expiring soon. Generating a new application secret." + $AppSecret = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/applications/$($PasswordCredentials.id)/addPassword" -Body '{"passwordCredential":{"displayName":"UpdateTokens"}}' -NoAuthCheck $true -AsApp $true -ErrorAction Stop + Write-Information "New application secret generated for $AppId. Expiration date: $($AppSecret.endDateTime)." + } else { + Write-Information "Application secret for $AppId is valid until $($LastPasswordCredential.endDateTime). No need to generate a new application secret." + } + + if ($AppSecret) { + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $Table = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" + $Secret.ApplicationSecret = $AppSecret.secretText + Add-AzDataTableEntity @Table -Entity $Secret -Force + } else { + Set-AzKeyVaultSecret -VaultName $KV -Name 'ApplicationSecret' -SecretValue (ConvertTo-SecureString -String $AppSecret.secretText -AsPlainText -Force) + } + } + + # Clean up expired application secrets + $ExpiredSecrets = $PasswordCredentials.passwordCredentials | Where-Object { $_.endDateTime -lt (Get-Date).ToUniversalTime() } + if ($ExpiredSecrets.Count -gt 0) { + Write-Information "Found $($ExpiredSecrets.Count) expired application secrets for $AppId. Removing them." + foreach ($Secret in $ExpiredSecrets) { + try { + New-GraphPostRequest -type DELETE -uri "https://graph.microsoft.com/v1.0/applications/$($PasswordCredentials.id)/removePassword" -Body "{`"keyId`":`"$($Secret.keyId)`"}" -NoAuthCheck $true -AsApp $true -ErrorAction Stop + Write-Information "Removed expired application secret with keyId $($Secret.keyId)." + } catch { + Write-LogMessage -API 'Update Tokens' -message "Error removing expired application secret with keyId $($Secret.keyId), see Log Data for details." -sev 'CRITICAL' -LogData (Get-CippException -Exception $_) + } + } + } else { + Write-Information "No expired application secrets found for $AppId." + } + } catch { + Write-Warning "Error updating application secret $($_.Exception.Message)." + Write-Information ($_.InvocationInfo.PositionMessage) + Write-LogMessage -API 'Update Tokens' -message 'Error updating application secret, will try again in 7 days' -sev 'CRITICAL' -LogData (Get-CippException -Exception $_) + } + # Get new refresh token for each direct added tenant $TenantList = Get-Tenants -IncludeAll | Where-Object { $_.Excluded -eq $false -and $_.delegatedPrivilegeStatus -eq 'directTenant' } if ($TenantList.Count -eq 0) { Write-Information 'No direct tenants found for refresh token update.' } else { - Write-Information "Found $($TenantList.Count) direct tenants for refresh token update." + Write-Information "Found $($TenantList.Count) direct tenant(s) for refresh token update." foreach ($Tenant in $TenantList) { try { Write-Information "Updating refresh token for tenant $($Tenant.displayName) - $($Tenant.customerId)" @@ -62,13 +110,6 @@ function Start-UpdateTokensTimer { Write-LogMessage -API 'Update Tokens' -tenant $Tenant.defaultDomainName -tenantid $Tenant.customerId -message "Could not update refresh token for tenant $($Tenant.displayName). Will try again in 7 days." -sev 'CRITICAL' } } else { - if ($env:MSI_SECRET) { - Disable-AzContextAutosave -Scope Process | Out-Null - $null = Connect-AzAccount -Identity - $SubscriptionId = $env:WEBSITE_OWNER_NAME -split '\+' | Select-Object -First 1 - $null = Set-AzContext -SubscriptionId $SubscriptionId - } - $KV = ($env:WEBSITE_DEPLOYMENT_ID -split '-')[0] if ($Refreshtoken) { $name = $Tenant.customerId Set-AzKeyVaultSecret -VaultName $KV -Name $name -SecretValue (ConvertTo-SecureString -String $Refreshtoken -AsPlainText -Force) @@ -84,7 +125,6 @@ function Start-UpdateTokensTimer { } # Write an information log with the current time. - Write-Information "PowerShell timer trigger function ran! TIME: $currentUTCtime" - + Write-Information "UpdateTokens completed: $currentUTCtime" } } From fd3834a598b0a154095059ca4281b1bc94e57f0a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 12:41:56 -0400 Subject: [PATCH 129/149] Update Start-UpdateTokensTimer.ps1 --- .../Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 index 9afe5278dffc..b5780a3f33c4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 @@ -65,6 +65,7 @@ function Start-UpdateTokensTimer { } else { Set-AzKeyVaultSecret -VaultName $KV -Name 'ApplicationSecret' -SecretValue (ConvertTo-SecureString -String $AppSecret.secretText -AsPlainText -Force) } + Write-LogMessage -API 'Update Tokens' -message "New application secret generated for $AppId. Expiration date: $($AppSecret.endDateTime)." -sev 'INFO' } # Clean up expired application secrets From d57feaa2b4fb6d4527d3402c48a348cf6cf6bcfc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 13:40:24 -0400 Subject: [PATCH 130/149] logbook improvements --- .../Public/Entrypoints/Invoke-ListLogs.ps1 | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 index 34f4009c8d1d..3b64a5ac01c4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ListLogs { +function Invoke-ListLogs { <# .FUNCTIONALITY Entrypoint @@ -25,17 +25,35 @@ Function Invoke-ListLogs { } } else { if ($request.Query.Filter -eq 'True') { - $LogLevel = if ($Request.query.Severity) { ($Request.query.Severity).split(',') } else { 'Info', 'Warn', 'Error', 'Critical', 'Alert' } - $PartitionKey = $Request.query.DateFilter + $LogLevel = if ($Request.Query.Severity) { ($Request.query.Severity).split(',') } else { 'Info', 'Warn', 'Error', 'Critical', 'Alert' } + $PartitionKey = $Request.Query.DateFilter $username = $Request.Query.User + + $StartDate = $Request.Query.StartDate ?? $Request.Query.DateFilter + $EndDate = $Request.Query.EndDate ?? $Request.Query.DateFilter + + if ($StartDate -and $EndDate) { + # Collect logs for each partition key date in range + $PartitionKeys = for ($Date = [datetime]::ParseExact($StartDate, 'yyyyMMdd', $null); $Date -le [datetime]::ParseExact($EndDate, 'yyyyMMdd', $null); $Date = $Date.AddDays(1)) { + $PartitionKey = $Date.ToString('yyyyMMdd') + "PartitionKey eq '$PartitionKey'" + } + $Filter = $PartitionKeys -join ' or ' + } elseif ($StartDate) { + $Filter = "PartitionKey eq '{0}'" -f $StartDate + } else { + $Filter = "PartitionKey eq '{0}'" -f (Get-Date -UFormat '%Y%m%d') + } } else { $LogLevel = 'Info', 'Warn', 'Error', 'Critical', 'Alert' $PartitionKey = Get-Date -UFormat '%Y%m%d' $username = '*' + $Filter = "PartitionKey eq '{0}'" -f $PartitionKey } $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList - $Filter = "PartitionKey eq '{0}'" -f $PartitionKey - $Rows = Get-AzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -In $LogLevel -and $_.user -like $username } + Write-Host "Getting logs for filter: $Filter, LogLevel: $LogLevel, Username: $username" + + $Rows = Get-AzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -in $LogLevel -and $_.user -like $username } foreach ($Row in $Rows) { if ($AllowedTenants -notcontains 'AllTenants') { $TenantList = Get-Tenants -IncludeErrors From 7027184ecec77a2ef6bb5d6cd61185fb17d05a12 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 17:25:45 -0400 Subject: [PATCH 131/149] fix group issues --- .../Administration/Groups/Invoke-AddGroup.ps1 | 6 +++--- .../Administration/Groups/Invoke-ListGroups.ps1 | 12 +++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 index 7f28273d5b8a..29c47135f18c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-AddGroup { +function Invoke-AddGroup { <# .FUNCTIONALITY Entrypoint @@ -38,11 +38,11 @@ Function Invoke-AddGroup { if ($GroupObject.groupType -eq 'm365') { $BodyParams | Add-Member -NotePropertyName 'groupTypes' -NotePropertyValue @('Unified') } - if ($GroupObject.owners -AND $GroupObject.groupType -in 'generic', 'azurerole', 'security') { + if ($GroupObject.owners) { $BodyParams | Add-Member -NotePropertyName 'owners@odata.bind' -NotePropertyValue (($GroupObject.owners) | ForEach-Object { "https://graph.microsoft.com/v1.0/users/$($_.value)" }) $BodyParams.'owners@odata.bind' = @($BodyParams.'owners@odata.bind') } - if ($GroupObject.members -AND $GroupObject.groupType -in 'generic', 'azurerole', 'security') { + if ($GroupObject.members) { $BodyParams | Add-Member -NotePropertyName 'members@odata.bind' -NotePropertyValue (($GroupObject.members) | ForEach-Object { "https://graph.microsoft.com/v1.0/users/$($_.value)" }) $BodyParams.'members@odata.bind' = @($BodyParams.'members@odata.bind') } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 index 8f7359353f4a..a24fc3ef8639 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ListGroups { +function Invoke-ListGroups { <# .FUNCTIONALITY Entrypoint @@ -95,18 +95,16 @@ Function Invoke-ListGroups { } else { $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupID)/$($members)?`$top=999&select=$selectstring" -tenantid $TenantFilter | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split '@' | Select-Object -Last 1 } }, @{Name = 'membersCsv'; Expression = { $_.members.userPrincipalName -join ',' } }, - @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -Like '*Team*') { $true }else { $false } } }, + @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -like '*Team*') { $true }else { $false } } }, @{Name = 'calculatedGroupType'; Expression = { - - if ($_.mailEnabled -and $_.securityEnabled) { + if ($_.groupTypes -contains 'Unified') { + 'Microsoft 365' + } elseif ($_.mailEnabled -and $_.securityEnabled) { 'Mail-Enabled Security' } if (!$_.mailEnabled -and $_.securityEnabled) { 'Security' } - if ($_.groupTypes -contains 'Unified') { - 'Microsoft 365' - } if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { 'Distribution List' } From 769cf0741a19db83d34e482e1aef836dabdcd7cd Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 17:43:48 -0400 Subject: [PATCH 132/149] improve logging --- .../HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 index e629a1015dde..794f34e613ab 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecAddTenant { +function Invoke-ExecAddTenant { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -63,7 +63,8 @@ Function Invoke-ExecAddTenant { # Add tenant to table Add-CIPPAzDataTableEntity @TenantsTable -Entity $NewTenant -Force | Out-Null - $Results = @{'message' = "Successfully added tenant $tenantId to the tenant list with directTenant status."; 'severity' = 'success' } + $Results = @{'message' = "Successfully added tenant $displayName ($defaultDomainName) to the tenant list with Direct Tenant status."; 'severity' = 'success' } + Write-LogMessage -tenant $defaultDomainName -tenantid $tenantId -API 'Add-Tenant' -message "Added tenant $displayName ($defaultDomainName) with Direct Tenant status." -Sev 'Info' } } catch { $Results = @{'message' = "Failed to add tenant: $($_.Exception.Message)"; 'state' = 'error'; 'severity' = 'error' } From 54d02c5e716781c334f4a12d1d27efae164ab7fa Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 18:14:33 -0400 Subject: [PATCH 133/149] cleanup classic api token usage --- Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 | 3 +-- .../CIPPCore/Public/GraphHelper/New-TeamsAPIGetRequest.ps1 | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 index ddfa6ad0408b..9383f7bf4245 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -26,8 +26,7 @@ function New-GraphGetRequest { if ($NoAuthCheck -eq $true -or $IsAuthorised) { if ($scope -eq 'ExchangeOnline') { - $AccessToken = Get-ClassicAPIToken -resource 'https://outlook.office365.com' -Tenantid $tenantid - $headers = @{ Authorization = "Bearer $($AccessToken.access_token)" } + $headers = Get-GraphToken -tenantid $tenantid -scope 'https://outlook.office365.com/.default' -AsApp $asapp -SkipCache $skipTokenCache } else { $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache } diff --git a/Modules/CIPPCore/Public/GraphHelper/New-TeamsAPIGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-TeamsAPIGetRequest.ps1 index 91dd8ce4a74b..31f1c662b994 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-TeamsAPIGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-TeamsAPIGetRequest.ps1 @@ -5,13 +5,13 @@ function New-TeamsAPIGetRequest($Uri, $tenantID, $Method = 'GET', $Resource = '4 #> if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - $token = Get-ClassicAPIToken -Tenant $tenantid -Resource $Resource + $token = Get-GraphToken -TenantID $tenantID -Scope "$Resource/.default" $NextURL = $Uri $ReturnedData = do { try { $Data = Invoke-RestMethod -ContentType "$ContentType;charset=UTF-8" -Uri $NextURL -Method $Method -Headers @{ - Authorization = "Bearer $($token.access_token)" + Authorization = $token.Authorization 'x-ms-client-request-id' = [guid]::NewGuid().ToString() 'x-ms-client-session-id' = [guid]::NewGuid().ToString() 'x-ms-correlation-id' = [guid]::NewGuid() @@ -29,4 +29,4 @@ function New-TeamsAPIGetRequest($Uri, $tenantID, $Method = 'GET', $Resource = '4 } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } -} \ No newline at end of file +} From 55201655af9f21969de0ecb918971897153b7d5f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 18:19:36 -0400 Subject: [PATCH 134/149] add sherweb to add user task --- Modules/CIPPCore/Public/New-CIPPUserTask.ps1 | 28 ++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 b/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 index 1e19ea9180fa..7675569baf19 100644 --- a/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 @@ -20,8 +20,32 @@ function New-CIPPUserTask { try { if ($UserObj.licenses.value) { - $LicenseResults = Set-CIPPUserLicense -UserId $CreationResults.Username -TenantFilter $UserObj.tenantFilter -AddLicenses $UserObj.licenses.value -Headers $Headers - $Results.Add($LicenseResults) + if ($UserObj.sherwebLicense.value) { + $License = Set-SherwebSubscription -TenantFilter $UserObj.tenantFilter -SKU $UserObj.sherwebLicense.value -Add 1 + $null = $results.Add('Added Sherweb License, scheduling assignment') + $taskObject = [PSCustomObject]@{ + TenantFilter = $UserObj.tenantFilter + Name = "Assign License: $UserPrincipalName" + Command = @{ + value = 'Set-CIPPUserLicense' + } + Parameters = [pscustomobject]@{ + userId = $UserObj.id + APIName = 'Sherweb License Assignment' + AddLicenses = $licenses + } + ScheduledTime = 0 #right now, which is in the next 15 minutes and should cover most cases. + PostExecution = @{ + Webhook = [bool]$Request.Body.PostExecution.webhook + Email = [bool]$Request.Body.PostExecution.email + PSA = [bool]$Request.Body.PostExecution.psa + } + } + Add-CIPPScheduledTask -Task $taskObject -hidden $false -Headers $Headers + } else { + $LicenseResults = Set-CIPPUserLicense -UserId $CreationResults.Username -TenantFilter $UserObj.tenantFilter -AddLicenses $UserObj.licenses.value -Headers $Headers + $Results.Add($LicenseResults) + } } } catch { Write-LogMessage -headers $Headers -API $APIName -tenant $($UserObj.tenantFilter) -message "Failed to assign the license. Error:$($_.Exception.Message)" -Sev 'Error' From e7cc8a0e4f9138ad70fb2786bb07295db53b6642 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 18:31:55 -0400 Subject: [PATCH 135/149] fix edit protection policies --- Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 index bc0264abe725..71564d7a732f 100644 --- a/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 @@ -23,6 +23,7 @@ function Set-CIPPIntunePolicy { $PolicyFile = $RawJSON | ConvertFrom-Json $Null = $PolicyFile | Add-Member -MemberType NoteProperty -Name 'description' -Value $description -Force $null = $PolicyFile | Add-Member -MemberType NoteProperty -Name 'displayName' -Value $displayname -Force + $PolicyFile = $PolicyFile | Select-Object * -ExcludeProperty 'apps' $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 20 $TemplateTypeURL = if ($TemplateType -eq 'windowsInformationProtectionPolicy') { 'windowsInformationProtectionPolicies' } else { "$($TemplateType)s" } $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter From 0ff54518104ef2157b6bb2835692d57df21e46db Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 18:45:51 -0400 Subject: [PATCH 136/149] update cpv to support directTenant --- .../Activity Triggers/Push-UpdatePermissionsQueue.ps1 | 4 +++- .../Start-UpdatePermissionsOrchestrator.ps1 | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdatePermissionsQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdatePermissionsQueue.ps1 index 6ab4496809db..cbe2d2cbb47c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdatePermissionsQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdatePermissionsQueue.ps1 @@ -16,7 +16,9 @@ function Push-UpdatePermissionsQueue { $Table = Get-CIPPTable -TableName cpvtenants $CPVRows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Tenant -EQ $Item.customerId - if (!$CPVRows -or $env:ApplicationID -notin $CPVRows.applicationId) { + $Tenant = Get-Tenants -TenantFilter $Item.customerId -IncludeErrors + + if ((!$CPVRows -or $env:ApplicationID -notin $CPVRows.applicationId) -and $Tenant.delegatedPrivilegeStatus -ne 'directTenant') { Write-LogMessage -tenant $Item.defaultDomainName -tenantId $Item.customerId -message 'A New tenant has been added, or a new CIPP-SAM Application is in use' -Sev 'Warn' -API 'NewTenant' Write-Information 'Adding CPV permissions' Set-CIPPCPVConsent -Tenantfilter $Item.customerId diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 index 26fab2b3200b..10caa27d3383 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 @@ -15,7 +15,7 @@ function Start-UpdatePermissionsOrchestrator { 'displayName' = '*Partner Tenant' } - $TenantList = Get-Tenants -IncludeAll | Where-Object { $_.Excluded -eq $false -and $_.delegatedPrivilegeStatus -eq 'directTenant' } + $TenantList = Get-Tenants -IncludeAll | Where-Object { $_.Excluded -eq $false } $Tenants = [System.Collections.Generic.List[object]]::new() foreach ($Tenant in $TenantList) { From b2972fc02f428e02e74e01e7896a33936fb3e737 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 19:16:39 -0400 Subject: [PATCH 137/149] update dnshealth --- .../Settings/Invoke-ExecCPVPermissions.ps1 | 4 +- .../1.0.7/MailProviders/Microsoft365.json | 10 - .../DNSHealth/{1.0.7 => 1.1.0}/DNSHealth.psd1 | 2 +- .../DNSHealth/{1.0.7 => 1.1.0}/DNSHealth.psm1 | 44 +-- .../MailProviders/AppRiver.json | 0 .../MailProviders/BarracudaESS.json | 0 .../MailProviders/Google.json | 0 .../1.1.0/MailProviders/HornetSecurity.json | 9 + .../MailProviders/Intermedia.json | 0 .../1.1.0/MailProviders/Microsoft365.json | 10 + .../MailProviders/Mimecast.json | 0 .../{1.0.7 => 1.1.0}/MailProviders/Null.json | 0 .../MailProviders/Proofpoint.json | 0 .../MailProviders/Reflexion.json | 0 .../MailProviders/Sophos.json | 0 .../MailProviders/SpamTitan.json | 0 .../1.1.0/MailProviders/SymantecCloud.json | 9 + .../MailProviders/_template.json | 0 .../{1.0.7 => 1.1.0}/PSGetModuleInfo.xml | 288 +++++++++--------- 19 files changed, 199 insertions(+), 177 deletions(-) delete mode 100644 Modules/DNSHealth/1.0.7/MailProviders/Microsoft365.json rename Modules/DNSHealth/{1.0.7 => 1.1.0}/DNSHealth.psd1 (99%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/DNSHealth.psm1 (99%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/AppRiver.json (100%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/BarracudaESS.json (100%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/Google.json (100%) create mode 100644 Modules/DNSHealth/1.1.0/MailProviders/HornetSecurity.json rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/Intermedia.json (100%) create mode 100644 Modules/DNSHealth/1.1.0/MailProviders/Microsoft365.json rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/Mimecast.json (100%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/Null.json (100%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/Proofpoint.json (100%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/Reflexion.json (100%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/Sophos.json (100%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/SpamTitan.json (100%) create mode 100644 Modules/DNSHealth/1.1.0/MailProviders/SymantecCloud.json rename Modules/DNSHealth/{1.0.7 => 1.1.0}/MailProviders/_template.json (100%) rename Modules/DNSHealth/{1.0.7 => 1.1.0}/PSGetModuleInfo.xml (80%) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 index a2e6fb31bd70..26e3b8414471 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecCPVPermissions { +function Invoke-ExecCPVPermissions { <# .FUNCTIONALITY Entrypoint @@ -15,7 +15,7 @@ Function Invoke-ExecCPVPermissions { Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $TenantFilter = $Request.Body.tenantFilter - $Tenant = Get-Tenants -IncludeAll | Where-Object -Property customerId -EQ $TenantFilter | Select-Object -First 1 + $Tenant = Get-Tenants -TenantFilter $TenantFilter -IncludeErrors if ($Tenant) { Write-Host "Our tenant is $($Tenant.displayName) - $($Tenant.defaultDomainName)" diff --git a/Modules/DNSHealth/1.0.7/MailProviders/Microsoft365.json b/Modules/DNSHealth/1.0.7/MailProviders/Microsoft365.json deleted file mode 100644 index 8b9e3a5dd072..000000000000 --- a/Modules/DNSHealth/1.0.7/MailProviders/Microsoft365.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Name": "Microsoft 365", - "MxMatch": "mail.protection.outlook.com|mx.microsoft", - "SpfInclude": "spf.protection.outlook.com", - "Selectors": ["selector1","selector2"], - "MinimumSelectorPass": 1, - "_MxComment": "https://docs.microsoft.com/en-us/microsoft-365/admin/get-help-with-domains/create-dns-records-at-any-dns-hosting-provider", - "_SpfComment": "https://docs.microsoft.com/en-us/microsoft-365/admin/get-help-with-domains/create-dns-records-at-any-dns-hosting-provider", - "_DkimComment": "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/use-dkim-to-validate-outbound-email?view=o365-worldwide" -} \ No newline at end of file diff --git a/Modules/DNSHealth/1.0.7/DNSHealth.psd1 b/Modules/DNSHealth/1.1.0/DNSHealth.psd1 similarity index 99% rename from Modules/DNSHealth/1.0.7/DNSHealth.psd1 rename to Modules/DNSHealth/1.1.0/DNSHealth.psd1 index 56383a3e37f3..651cc2720db7 100644 --- a/Modules/DNSHealth/1.0.7/DNSHealth.psd1 +++ b/Modules/DNSHealth/1.1.0/DNSHealth.psd1 @@ -12,7 +12,7 @@ RootModule = 'DNSHealth.psm1' # Version number of this module. - ModuleVersion = '1.0.7' + ModuleVersion = '1.1.0' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/Modules/DNSHealth/1.0.7/DNSHealth.psm1 b/Modules/DNSHealth/1.1.0/DNSHealth.psm1 similarity index 99% rename from Modules/DNSHealth/1.0.7/DNSHealth.psm1 rename to Modules/DNSHealth/1.1.0/DNSHealth.psm1 index 749a158a5fa6..cbefac309733 100644 --- a/Modules/DNSHealth/1.0.7/DNSHealth.psm1 +++ b/Modules/DNSHealth/1.1.0/DNSHealth.psm1 @@ -1179,7 +1179,7 @@ function Read-MXRecord { catch { Write-Verbose $_.Exception.Message } } - $ValidationPasses.Add('Mail exchanger record(s) are present for this domain.') | Out-Null + $ValidationPasses.Add('Mail exchanger records record(s) are present for this domain.') | Out-Null $MXRecords = $MXRecords | Sort-Object -Property Priority # Attempt to identify mail provider based on MX record @@ -2073,9 +2073,11 @@ function Read-WhoisRecord { $WhoisRegex = '^(?!(?:%|>>>|-+|#|[*]))[^\S\n]*(?.+?):(?:[\r\n]+)?(:?(?!([0-9]|[/]{2}))[^\S\r\n]*(?.+))?$' Write-Verbose "Querying WHOIS Server: $Server" - # TCP Client for Whois - $Client = New-Object System.Net.Sockets.TcpClient($Server, 43) + try { + # TCP Client for Whois + $Client = New-Object System.Net.Sockets.TcpClient($Server, 43) + # Open TCP connection and send query $Stream = $Client.GetStream() $ReferralServers = [System.Collections.Generic.List[string]]::new() @@ -2159,16 +2161,18 @@ function Read-WhoisRecord { $Results = $LastResult } } - } - - else { + } else { if ($Results._Raw -Match '(No match|Not Found|No Data)') { $first, $newquery = ($Query -split '\.') if (($newquery | Measure-Object).Count -gt 1) { $Query = $newquery -join '.' - $Results = Read-WhoisRecord -Query $Query -Server $Server -Port $Port - foreach ($s in $Results._ReferralServers) { - $ReferralServers.Add($s) | Out-Null + try { + $Results = Read-WhoisRecord -Query $Query -Server $Server -Port $Port + foreach ($s in $Results._ReferralServers) { + $ReferralServers.Add($s) | Out-Null + } + } catch { + $Results = $LastResult } } } @@ -2185,17 +2189,17 @@ function Read-WhoisRecord { $Stream.Dispose() } } - - # Collect referral server list - $Results._ReferralServers = $ReferralServers - + if ($ReferralServers) { + # Collect referral server list + $Results._ReferralServers = $ReferralServers + } # Convert to json and back to preserve object order $WhoisResults = $Results | ConvertTo-Json | ConvertFrom-Json # Return Whois results as PSObject $WhoisResults } -#EndRegion './Public/Records/Read-WhoisRecord.ps1' 175 +#EndRegion './Public/Records/Read-WhoisRecord.ps1' 179 #Region './Public/Resolver/Resolve-DnsHttpsQuery.ps1' -1 function Resolve-DnsHttpsQuery { @@ -2221,7 +2225,7 @@ function Resolve-DnsHttpsQuery { #> [cmdletbinding()] - Param( + param( [Parameter(Mandatory = $true)] [string]$Domain, @@ -2251,23 +2255,23 @@ function Resolve-DnsHttpsQuery { $Uri = $QueryTemplate -f $BaseUri, $Domain, $RecordType $x = 0 + $Exception = $null do { $x++ try { $Results = Invoke-RestMethod -Uri $Uri -Headers $Headers -ErrorAction Stop - } - - catch { + } catch { + $Exception = $_ Start-Sleep -Milliseconds 300 } } while (-not $Results -and $x -le 3) - if (!$Results) { throw $_ } + if (!$Results) { throw 'Exception querying resolver {0}: {1}' -f $Resolver.Resolver, $Exception.Exception.Message } if ($RecordType -eq 'txt' -and $Results.Answer) { if ($Resolver -eq 'Cloudflare' -or $Resolver -eq 'Quad9') { $Results.Answer | ForEach-Object { - $_.data = $_.data -replace '"' -replace '\s+', ' ' + $_.data = $_.data -replace '" "' -replace '"', '' } } $Results.Answer = $Results.Answer | Where-Object { $_.type -eq 16 } diff --git a/Modules/DNSHealth/1.0.7/MailProviders/AppRiver.json b/Modules/DNSHealth/1.1.0/MailProviders/AppRiver.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/AppRiver.json rename to Modules/DNSHealth/1.1.0/MailProviders/AppRiver.json diff --git a/Modules/DNSHealth/1.0.7/MailProviders/BarracudaESS.json b/Modules/DNSHealth/1.1.0/MailProviders/BarracudaESS.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/BarracudaESS.json rename to Modules/DNSHealth/1.1.0/MailProviders/BarracudaESS.json diff --git a/Modules/DNSHealth/1.0.7/MailProviders/Google.json b/Modules/DNSHealth/1.1.0/MailProviders/Google.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/Google.json rename to Modules/DNSHealth/1.1.0/MailProviders/Google.json diff --git a/Modules/DNSHealth/1.1.0/MailProviders/HornetSecurity.json b/Modules/DNSHealth/1.1.0/MailProviders/HornetSecurity.json new file mode 100644 index 000000000000..eb705d4e7033 --- /dev/null +++ b/Modules/DNSHealth/1.1.0/MailProviders/HornetSecurity.json @@ -0,0 +1,9 @@ +{ + "Name": "Hornet Security", + "MxMatch": "mx[0-9][0-9].hornetsecurity.com", + "SpfInclude": "spf.hornetsecurity.com", + "Selectors": [""], + "_MxComment": "https://www.hornetsecurity.com/en/onboarding-information/", + "_SpfComment": "https://www.hornetsecurity.com/en/onboarding-information/", + "_DkimComment": "https://support.hornetsecurity.com/hc/en-us/articles/15123377800593-How-to-set-up-DKIM" +} diff --git a/Modules/DNSHealth/1.0.7/MailProviders/Intermedia.json b/Modules/DNSHealth/1.1.0/MailProviders/Intermedia.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/Intermedia.json rename to Modules/DNSHealth/1.1.0/MailProviders/Intermedia.json diff --git a/Modules/DNSHealth/1.1.0/MailProviders/Microsoft365.json b/Modules/DNSHealth/1.1.0/MailProviders/Microsoft365.json new file mode 100644 index 000000000000..35fb2c66b9df --- /dev/null +++ b/Modules/DNSHealth/1.1.0/MailProviders/Microsoft365.json @@ -0,0 +1,10 @@ +{ + "Name": "Microsoft 365", + "MxMatch": "mail.protection.outlook.com|mx.microsoft", + "SpfInclude": "spf.protection.outlook.com", + "Selectors": ["selector1", "selector2"], + "MinimumSelectorPass": 1, + "_MxComment": "https://docs.microsoft.com/en-us/microsoft-365/admin/get-help-with-domains/create-dns-records-at-any-dns-hosting-provider", + "_SpfComment": "https://docs.microsoft.com/en-us/microsoft-365/admin/get-help-with-domains/create-dns-records-at-any-dns-hosting-provider", + "_DkimComment": "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/use-dkim-to-validate-outbound-email?view=o365-worldwide" +} diff --git a/Modules/DNSHealth/1.0.7/MailProviders/Mimecast.json b/Modules/DNSHealth/1.1.0/MailProviders/Mimecast.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/Mimecast.json rename to Modules/DNSHealth/1.1.0/MailProviders/Mimecast.json diff --git a/Modules/DNSHealth/1.0.7/MailProviders/Null.json b/Modules/DNSHealth/1.1.0/MailProviders/Null.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/Null.json rename to Modules/DNSHealth/1.1.0/MailProviders/Null.json diff --git a/Modules/DNSHealth/1.0.7/MailProviders/Proofpoint.json b/Modules/DNSHealth/1.1.0/MailProviders/Proofpoint.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/Proofpoint.json rename to Modules/DNSHealth/1.1.0/MailProviders/Proofpoint.json diff --git a/Modules/DNSHealth/1.0.7/MailProviders/Reflexion.json b/Modules/DNSHealth/1.1.0/MailProviders/Reflexion.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/Reflexion.json rename to Modules/DNSHealth/1.1.0/MailProviders/Reflexion.json diff --git a/Modules/DNSHealth/1.0.7/MailProviders/Sophos.json b/Modules/DNSHealth/1.1.0/MailProviders/Sophos.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/Sophos.json rename to Modules/DNSHealth/1.1.0/MailProviders/Sophos.json diff --git a/Modules/DNSHealth/1.0.7/MailProviders/SpamTitan.json b/Modules/DNSHealth/1.1.0/MailProviders/SpamTitan.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/SpamTitan.json rename to Modules/DNSHealth/1.1.0/MailProviders/SpamTitan.json diff --git a/Modules/DNSHealth/1.1.0/MailProviders/SymantecCloud.json b/Modules/DNSHealth/1.1.0/MailProviders/SymantecCloud.json new file mode 100644 index 000000000000..ebd375edd597 --- /dev/null +++ b/Modules/DNSHealth/1.1.0/MailProviders/SymantecCloud.json @@ -0,0 +1,9 @@ +{ + "Name": "Symantec Cloud", + "MxMatch": "cluster[0-9].{3,4}.messagelabs.com", + "SpfInclude": "spf.messagelabs.com", + "Selectors": [""], + "_MxComment": "https://knowledge.broadcom.com/external/article/161419/mail-exchanger-mx-record-setup-with-emai.html", + "_SpfComment": "https://knowledge.broadcom.com/external/article/161394/implement-spf-records-for-email-security.html", + "_DkimComment": "https://knowledge.broadcom.com/external/article/171225/configuring-dkim-signing-for-outbound-ma.html" +} diff --git a/Modules/DNSHealth/1.0.7/MailProviders/_template.json b/Modules/DNSHealth/1.1.0/MailProviders/_template.json similarity index 100% rename from Modules/DNSHealth/1.0.7/MailProviders/_template.json rename to Modules/DNSHealth/1.1.0/MailProviders/_template.json diff --git a/Modules/DNSHealth/1.0.7/PSGetModuleInfo.xml b/Modules/DNSHealth/1.1.0/PSGetModuleInfo.xml similarity index 80% rename from Modules/DNSHealth/1.0.7/PSGetModuleInfo.xml rename to Modules/DNSHealth/1.1.0/PSGetModuleInfo.xml index baad9e9643b8..e64f6f169372 100644 --- a/Modules/DNSHealth/1.0.7/PSGetModuleInfo.xml +++ b/Modules/DNSHealth/1.1.0/PSGetModuleInfo.xml @@ -1,144 +1,144 @@ - - - - Microsoft.PowerShell.Commands.PSRepositoryItemInfo - System.Management.Automation.PSCustomObject - System.Object - - - DNSHealth - 1.0.7 - Module - CIPP DNS Health Check Module - John Duprey - johnduprey - 2023 John Duprey -
2024-02-02T21:41:51-05:00
- - - - https://github.com/johnduprey/DNSHealth - - - - System.Object[] - System.Array - System.Object - - - PSModule - - - - - System.Collections.Hashtable - System.Object - - - - Command - - - - Read-DmarcPolicy - Read-MtaStsPolicy - Read-DkimRecord - Read-MtaStsRecord - Read-MXRecord - Read-NSRecord - Read-SPFRecord - Read-TlsRptRecord - Read-WhoisRecord - Resolve-DnsHttpsQuery - Set-DnsResolver - Test-DNSSEC - Test-HttpsCertificate - Test-MtaSts - - - - - Cmdlet - - - - - - - Function - - - - Read-DmarcPolicy - Read-MtaStsPolicy - Read-DkimRecord - Read-MtaStsRecord - Read-MXRecord - Read-NSRecord - Read-SPFRecord - Read-TlsRptRecord - Read-WhoisRecord - Resolve-DnsHttpsQuery - Set-DnsResolver - Test-DNSSEC - Test-HttpsCertificate - Test-MtaSts - - - - - DscResource - - - - Workflow - - - - RoleCapability - - - - - - - - - - - https://www.powershellgallery.com/api/v2 - PSGallery - NuGet - - - System.Management.Automation.PSCustomObject - System.Object - - - 2023 John Duprey - CIPP DNS Health Check Module - False - True - True - 0 - 78 - 27851 - 2/2/2024 9:41:51 PM -05:00 - 2/2/2024 9:41:51 PM -05:00 - 2/2/2024 9:41:51 PM -05:00 - PSModule PSFunction_Read-DmarcPolicy PSCommand_Read-DmarcPolicy PSFunction_Read-MtaStsPolicy PSCommand_Read-MtaStsPolicy PSFunction_Read-DkimRecord PSCommand_Read-DkimRecord PSFunction_Read-MtaStsRecord PSCommand_Read-MtaStsRecord PSFunction_Read-MXRecord PSCommand_Read-MXRecord PSFunction_Read-NSRecord PSCommand_Read-NSRecord PSFunction_Read-SPFRecord PSCommand_Read-SPFRecord PSFunction_Read-TlsRptRecord PSCommand_Read-TlsRptRecord PSFunction_Read-WhoisRecord PSCommand_Read-WhoisRecord PSFunction_Resolve-DnsHttpsQuery PSCommand_Resolve-DnsHttpsQuery PSFunction_Set-DnsResolver PSCommand_Set-DnsResolver PSFunction_Test-DNSSEC PSCommand_Test-DNSSEC PSFunction_Test-HttpsCertificate PSCommand_Test-HttpsCertificate PSFunction_Test-MtaSts PSCommand_Test-MtaSts PSIncludes_Function - False - 2024-02-02T21:41:51Z - 1.0.7 - John Duprey - false - Module - DNSHealth.nuspec|MailProviders\BarracudaESS.json|MailProviders\Reflexion.json|MailProviders\Null.json|MailProviders\SpamTitan.json|DNSHealth.psd1|MailProviders\Microsoft365.json|MailProviders\Sophos.json|MailProviders\Proofpoint.json|DNSHealth.psm1|MailProviders\_template.json|MailProviders\Google.json|MailProviders\Intermedia.json|MailProviders\AppRiver.json|MailProviders\Mimecast.json - a300d2b0-d468-46d1-88a3-e442a76b655b - 7.0 - - - C:\GitHub\CIPP Workspace\CIPP-API\Modules\DNSHealth\1.0.7 -
-
-
+ + + + Microsoft.PowerShell.Commands.PSRepositoryItemInfo + System.Management.Automation.PSCustomObject + System.Object + + + DNSHealth + 1.1.0 + Module + CIPP DNS Health Check Module + John Duprey + johnduprey + 2023 John Duprey +
2025-05-27T23:15:27-04:00
+ + + + https://github.com/johnduprey/DNSHealth + + + + System.Object[] + System.Array + System.Object + + + PSModule + + + + + System.Collections.Hashtable + System.Object + + + + Command + + + + Read-DmarcPolicy + Read-MtaStsPolicy + Read-DkimRecord + Read-MtaStsRecord + Read-MXRecord + Read-NSRecord + Read-SPFRecord + Read-TlsRptRecord + Read-WhoisRecord + Resolve-DnsHttpsQuery + Set-DnsResolver + Test-DNSSEC + Test-HttpsCertificate + Test-MtaSts + + + + + Function + + + + Read-DmarcPolicy + Read-MtaStsPolicy + Read-DkimRecord + Read-MtaStsRecord + Read-MXRecord + Read-NSRecord + Read-SPFRecord + Read-TlsRptRecord + Read-WhoisRecord + Resolve-DnsHttpsQuery + Set-DnsResolver + Test-DNSSEC + Test-HttpsCertificate + Test-MtaSts + + + + + Workflow + + + + + + + RoleCapability + + + + DscResource + + + + Cmdlet + + + + + + + + + + + https://www.powershellgallery.com/api/v2 + PSGallery + NuGet + + + System.Management.Automation.PSCustomObject + System.Object + + + 2023 John Duprey + CIPP DNS Health Check Module + False + True + True + 0 + 290 + 28670 + 5/27/2025 11:15:27 PM -04:00 + 5/27/2025 11:15:27 PM -04:00 + 5/27/2025 11:15:27 PM -04:00 + PSModule PSFunction_Read-DmarcPolicy PSCommand_Read-DmarcPolicy PSFunction_Read-MtaStsPolicy PSCommand_Read-MtaStsPolicy PSFunction_Read-DkimRecord PSCommand_Read-DkimRecord PSFunction_Read-MtaStsRecord PSCommand_Read-MtaStsRecord PSFunction_Read-MXRecord PSCommand_Read-MXRecord PSFunction_Read-NSRecord PSCommand_Read-NSRecord PSFunction_Read-SPFRecord PSCommand_Read-SPFRecord PSFunction_Read-TlsRptRecord PSCommand_Read-TlsRptRecord PSFunction_Read-WhoisRecord PSCommand_Read-WhoisRecord PSFunction_Resolve-DnsHttpsQuery PSCommand_Resolve-DnsHttpsQuery PSFunction_Set-DnsResolver PSCommand_Set-DnsResolver PSFunction_Test-DNSSEC PSCommand_Test-DNSSEC PSFunction_Test-HttpsCertificate PSCommand_Test-HttpsCertificate PSFunction_Test-MtaSts PSCommand_Test-MtaSts PSIncludes_Function + False + 2025-05-27T23:15:27Z + 1.1.0 + John Duprey + false + Module + DNSHealth.nuspec|MailProviders\Google.json|MailProviders\BarracudaESS.json|MailProviders\_template.json|MailProviders\Null.json|MailProviders\HornetSecurity.json|DNSHealth.psm1|MailProviders\Intermedia.json|MailProviders\Proofpoint.json|MailProviders\Reflexion.json|DNSHealth.psd1|MailProviders\SpamTitan.json|MailProviders\Mimecast.json|MailProviders\Sophos.json|MailProviders\Microsoft365.json|MailProviders\AppRiver.json|MailProviders\SymantecCloud.json + a300d2b0-d468-46d1-88a3-e442a76b655b + 7.0 + + + C:\GitHub\CIPP Workspace\CIPP-API\Modules\DNSHealth\1.1.0 +
+
+
From 02a318b06045cecd5a7e27c74977d19e7f1d5fb2 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 27 May 2025 19:40:52 -0400 Subject: [PATCH 138/149] fix cpv refresh for direct tenant --- Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 b/Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 index d8b09f367017..87737fd6d092 100644 --- a/Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 @@ -17,6 +17,9 @@ function Set-CIPPCPVConsent { if ($Tenant.customerId -ne $TenantFilter) { return @('Not a valid tenant') } + if ($Tenant.delegatedPrivilegeStatus -eq 'directTenant') { + return @('Application is already consented to this tenant') + } if ($ResetSP) { try { @@ -40,7 +43,7 @@ function Set-CIPPCPVConsent { 'DelegatedPermissionGrant.ReadWrite.All', 'Directory.ReadWrite.All', 'AppRoleAssignment.ReadWrite.All' - ) -Join ',' + ) -join ',' } ) } | ConvertTo-Json From 512464b7eb6a3d8edf739f0e55cf246706ebe59e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 28 May 2025 11:58:41 +0200 Subject: [PATCH 139/149] corrected token generation --- .../HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 index 794f34e613ab..0bd359ccb156 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecAddTenant.ps1 @@ -31,7 +31,7 @@ function Invoke-ExecAddTenant { # Create new tenant entry try { # Get tenant information from Microsoft Graph - $headers = @{ Authorization = "Bearer $($request.body.access_token)" } + $headers = @{ Authorization = "Bearer $($request.body.accessToken)" } $Organization = (Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/organization' -Headers $headers -Method GET -ContentType 'application/json' -ErrorAction Stop).value $displayName = $Organization.displayName $Domains = (Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/domains?$top=999' -Headers $headers -Method GET -ContentType 'application/json' -ErrorAction Stop).value From 2003b81b0e64f3dfea8a26d1df83ed06b5e97148 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 28 May 2025 12:42:04 +0200 Subject: [PATCH 140/149] removed troubleshooting info --- Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 index cd87d5cbe512..acdad77ac57a 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 @@ -14,10 +14,10 @@ function Get-Tenants { [switch]$CleanOld, [string]$TenantFilter ) - $caller = $MyInvocation.InvocationName - $scriptName = $MyInvocation.ScriptName - Write-Host "Called by: $caller" - Write-Host "In script: $scriptName" + #$caller = $MyInvocation.InvocationName + #$scriptName = $MyInvocation.ScriptName + #Write-Host "Called by: $caller" + #Write-Host "In script: $scriptName" $TenantsTable = Get-CippTable -tablename 'Tenants' $ExcludedFilter = "PartitionKey eq 'Tenants' and Excluded eq true" From 925b6bc18bc103edbf9d09e1ce21795929c60bb6 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 28 May 2025 13:10:34 +0200 Subject: [PATCH 141/149] fix bulk assign licenses --- .../Users/Invoke-AddUserBulk.ps1 | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 index afe3c9a5f4ea..7ff5e7e3cb6f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 @@ -67,21 +67,9 @@ function Invoke-AddUserBulk { if ($UsageLocation) { $UserBody.usageLocation = $UsageLocation.value ?? $UsageLocation Write-Information "- Usage location set to $($UsageLocation.label ?? $UsageLocation)" - if ($AssignedLicenses) { - $GuidPattern = '([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})' - $LicenseSkus = $AssignedLicenses.value ?? $AssignedLicenses | Where-Object { $_ -match $GuidPattern } - if (($LicenseSkus | Measure-Object).Count -gt 0) { - Write-Information "- Assigned licenses set to $(($AssignedLicenses.label ?? $AssignedLicenses) -join ', ')" - $Licenses = foreach ($Sku in $LicenseSkus) { - [PSCustomObject]@{ - skuId = $Sku - } - } - $UserBody.assignedLicenses = @($Licenses) - } - } } + # Convert businessPhones to array if not null or empty if (![string]::IsNullOrEmpty($User.businessPhones)) { $UserBody.businessPhones = @($User.businessPhones) @@ -137,6 +125,11 @@ function Invoke-AddUserBulk { }) } else { $Message = $Messages.Where({ $_.id -eq $BulkResult.id }) + if ($AssignedLicenses) { + $GuidPattern = '([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})' + $LicenseSkus = $AssignedLicenses.value ?? $AssignedLicenses | Where-Object { $_ -match $GuidPattern } + Set-CIPPUserLicense -User $BulkResult.id -AddLicenses $LicenseSkus + } $Results.Add(@{ resultText = $Message.resultText state = 'success' From 6fc2c428329303e650dfc6ace59bd30dee04a939 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 28 May 2025 13:19:06 +0200 Subject: [PATCH 142/149] fixes license assign --- .../Identity/Administration/Users/Invoke-AddUserBulk.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 index 7ff5e7e3cb6f..9a017652bd39 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 @@ -128,7 +128,7 @@ function Invoke-AddUserBulk { if ($AssignedLicenses) { $GuidPattern = '([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})' $LicenseSkus = $AssignedLicenses.value ?? $AssignedLicenses | Where-Object { $_ -match $GuidPattern } - Set-CIPPUserLicense -User $BulkResult.id -AddLicenses $LicenseSkus + Set-CIPPUserLicense -User $BulkResult.id -AddLicenses $LicenseSkus -TenantFilter $TenantFilter } $Results.Add(@{ resultText = $Message.resultText From fe393352845a6daee709484a8eb01b92950272db Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 28 May 2025 13:24:00 +0200 Subject: [PATCH 143/149] fixes https://github.com/KelvinTegelaar/CIPP/issues/4031 --- .../Invoke-CIPPStandardOauthConsent.ps1 | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 index f53d2a3b0762..f5b56fbcc994 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 @@ -37,24 +37,35 @@ function Invoke-CIPPStandardOauthConsent { $StateIsCorrect = if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -eq 'managePermissionGrantsForSelf.cipp-consent-policy') { $true } else { $false } if ($Settings.remediate -eq $true) { - $AllowedAppIdsForTenant = $settings.AllowedApps -split ',' + $AllowedAppIdsForTenant = $settings.AllowedApps -split ',' | ForEach-Object { $_.Trim() } try { - if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -notin @('managePermissionGrantsForSelf.cipp-consent-policy')) { - $Existing = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies/' -tenantid $tenant) | Where-Object -Property id -EQ 'cipp-consent-policy' - if (!$Existing) { - New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies' -Type POST -Body '{ "id":"cipp-consent-policy", "displayName":"Application Consent Policy", "description":"This policy controls the current application consent policies."}' -ContentType 'application/json' - #Replaced static web app appid with Office 365 Management by Microsoft's recommendation; this application is always consented, cannot be removed nor elevated as the portals run on this app id. - New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies/cipp-consent-policy/includes' -Type POST -Body '{"permissionClassification":"all","permissionType":"delegated","clientApplicationIds":["00b41c95-dab0-4487-9791-b9d2c32c80f2"]}' -ContentType 'application/json' + $Existing = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies/' -tenantid $tenant) | Where-Object -Property id -EQ 'cipp-consent-policy' + if (!$Existing) { + New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies' -Type POST -Body '{ "id":"cipp-consent-policy", "displayName":"Application Consent Policy", "description":"This policy controls the current application consent policies."}' -ContentType 'application/json' + # Replaced static web app appid with Office 365 Management by Microsoft's recommendation + New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies/cipp-consent-policy/includes' -Type POST -Body '{"permissionClassification":"all","permissionType":"delegated","clientApplicationIds":["00b41c95-dab0-4487-9791-b9d2c32c80f2"]}' -ContentType 'application/json' + } + + try { + $ExistingIncludes = New-GraphGetRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies/cipp-consent-policy/includes' + + $ExistingAppIds = foreach ($entry in $ExistingIncludes.value) { + $entry.clientApplicationIds } - try { - foreach ($AllowedApp in $AllowedAppIdsForTenant) { - Write-Host "$AllowedApp" + $ExistingAppIds = $ExistingAppIds | Sort-Object -Unique + + foreach ($AllowedApp in $AllowedAppIdsForTenant) { + if ($AllowedApp -and ($AllowedApp -notin $ExistingAppIds)) { + Write-Host "Adding missing approved app: $AllowedApp" New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies/cipp-consent-policy/includes' -Type POST -Body ('{"permissionType": "delegated","clientApplicationIds": ["' + $AllowedApp + '"]}') -ContentType 'application/json' New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies/cipp-consent-policy/includes' -Type POST -Body ('{ "permissionType": "Application", "clientApplicationIds": ["' + $AllowedApp + '"] }') -ContentType 'application/json' } - } catch { - "Could not add exclusions, probably already exist: $($_)" } + } catch { + "Could not add exclusions, probably already exist: $($_)" + } + + if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -notin @('managePermissionGrantsForSelf.cipp-consent-policy')) { New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' -Type PATCH -Body '{"permissionGrantPolicyIdsAssignedToDefaultUserRole":["managePermissionGrantsForSelf.cipp-consent-policy"]}' -ContentType 'application/json' } @@ -64,8 +75,8 @@ function Invoke-CIPPStandardOauthConsent { Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to apply Application Consent Mode Error: $ErrorMessage" -sev Error } } - if ($Settings.alert -eq $true) { + if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode is enabled.' -sev Info } else { @@ -73,6 +84,7 @@ function Invoke-CIPPStandardOauthConsent { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode is not enabled.' -sev Info } } + if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'OauthConsent' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant if ($StateIsCorrect) { From 4735be7613b04e9e38c9a014ff945a3e105de667 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 28 May 2025 09:26:43 -0400 Subject: [PATCH 144/149] add more tables to backup --- Modules/CIPPCore/Public/New-CIPPBackup.ps1 | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 index 4727cbe71914..ba9194085e0e 100644 --- a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 @@ -14,8 +14,17 @@ function New-CIPPBackup { 'CIPP' { try { $BackupTables = @( + 'AppPermissions' + 'AccessRoleGroups' + 'ApiClients' + 'CustomData' + 'CustomRoles' 'Config' + 'CommunityRepos' 'Domains' + 'GraphPresets' + 'GDAPRoles' + 'GDAPRoleTemplates' 'ExcludedLicenses' 'templates' 'standards' @@ -23,10 +32,11 @@ function New-CIPPBackup { 'Extensions' 'WebhookRules' 'ScheduledTasks' + 'TenantProperties' ) $CSVfile = foreach ($CSVTable in $BackupTables) { $Table = Get-CippTable -tablename $CSVTable - Get-AzDataTableEntity @Table | Select-Object * -ExcludeProperty DomainAnalyser, table, Timestamp, ETag | Select-Object *, @{l = 'table'; e = { $CSVTable } } + Get-AzDataTableEntity @Table | Select-Object * -ExcludeProperty DomainAnalyser, table, Timestamp, ETag, Results | Select-Object *, @{l = 'table'; e = { $CSVTable } } } $RowKey = 'CIPPBackup' + '_' + (Get-Date).ToString('yyyy-MM-dd-HHmm') $CSVfile From 41cc5575a98b15fb614813570099bb4e15130c21 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 28 May 2025 09:49:08 -0400 Subject: [PATCH 145/149] cleanup rule tweak --- .../Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 index de6d20e615d3..864e1017074d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 @@ -17,7 +17,7 @@ function Start-TableCleanup { @{ DataTableProps = @{ Context = (Get-CIPPTable -tablename 'AuditLogSearches').Context - Filter = "PartitionKey eq 'Search' and Timestamp lt datetime'$((Get-Date).AddDays(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'" + Filter = "PartitionKey eq 'Search' and Timestamp lt datetime'$((Get-Date).AddHours(-12).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'" First = 10000 Property = @('PartitionKey', 'RowKey', 'ETag') } From 8e64a0c09d4bae07cca0289ca87706e24ca7e729 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 28 May 2025 11:00:45 -0400 Subject: [PATCH 146/149] Update Invoke-ListLogs.ps1 --- Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 index 3b64a5ac01c4..b866b6289fe1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -53,7 +53,7 @@ function Invoke-ListLogs { $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList Write-Host "Getting logs for filter: $Filter, LogLevel: $LogLevel, Username: $username" - $Rows = Get-AzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -in $LogLevel -and $_.user -like $username } + $Rows = Get-AzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -in $LogLevel -and $_.Username -like $username } foreach ($Row in $Rows) { if ($AllowedTenants -notcontains 'AllTenants') { $TenantList = Get-Tenants -IncludeErrors From 083400f7c4e67ad5c7c010b4abd79fec92ae368d Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 28 May 2025 12:07:23 -0400 Subject: [PATCH 147/149] fix filters --- Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 index b866b6289fe1..7547f7b2f58c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -27,7 +27,7 @@ function Invoke-ListLogs { if ($request.Query.Filter -eq 'True') { $LogLevel = if ($Request.Query.Severity) { ($Request.query.Severity).split(',') } else { 'Info', 'Warn', 'Error', 'Critical', 'Alert' } $PartitionKey = $Request.Query.DateFilter - $username = $Request.Query.User + $username = $Request.Query.User ?? '*' $StartDate = $Request.Query.StartDate ?? $Request.Query.DateFilter $EndDate = $Request.Query.EndDate ?? $Request.Query.DateFilter From 7fe5d5ca999a6d352dcdf664a0227b1de11f25a3 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 28 May 2025 18:19:59 +0200 Subject: [PATCH 148/149] push version --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index 017f8006642e..ae9a76b9249a 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -7.5.3 +8.0.0 From b579ef996ede7c3805f729cd9e91a96ca38dc59a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 28 May 2025 12:45:01 -0400 Subject: [PATCH 149/149] cleanup duplicate auth checks --- .../Authentication/Get-CIPPAccessRole.ps1 | 24 +++- .../Settings/Invoke-ExecOffloadFunctions.ps1 | 114 ++++++++---------- .../CIPP/Settings/Invoke-ExecPartnerMode.ps1 | 113 ++++++++--------- .../CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 | 15 +-- .../CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 12 +- .../Standards/Invoke-ListDomainHealth.ps1 | 8 +- 6 files changed, 134 insertions(+), 152 deletions(-) diff --git a/Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1 index 88872027bd99..a43351bc11f7 100644 --- a/Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1 @@ -16,7 +16,27 @@ function Get-CIPPAccessRole { Internal #> [CmdletBinding()] - Param() + param($Request) - + $CacheAccessUserRoleTable = Get-CIPPTable -tablename 'cacheAccessUserRole' + $CachedRoles = Get-CIPPAzDataTableEntity @CacheAccessUserRoleTable -Filter "PartitionKey eq 'AccessUser' and RowKey eq '$($Request.Headers.'x-ms-client-principal-name')'" | Select-Object -ExpandProperty Role | ConvertFrom-Json + + $SwaCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) + $SwaRoles = $SwaCreds.userRoles + + # Combine SWA roles and cached roles into a single deduplicated list + $AllRoles = [System.Collections.Generic.List[string]]::new() + if ($null -ne $SwaRoles) { + $AllRoles.AddRange($SwaRoles) + } + if ($null -ne $CachedRoles) { + $AllRoles.AddRange($CachedRoles) + } + + # Remove duplicates and ensure we have a clean array + $CombinedRoles = $AllRoles | Select-Object -Unique + + # For debugging + Write-Information "Combined Roles: $($CombinedRoles -join ', ')" + return $CombinedRoles } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecOffloadFunctions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecOffloadFunctions.ps1 index a71f03f58f2e..369ec7196b8c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecOffloadFunctions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecOffloadFunctions.ps1 @@ -1,5 +1,5 @@ -Function Invoke-ExecOffloadFunctions { +function Invoke-ExecOffloadFunctions { <# .FUNCTIONALITY Entrypoint @@ -9,78 +9,68 @@ Function Invoke-ExecOffloadFunctions { [CmdletBinding()] param($Request, $TriggerMetadata) - $roles = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json).userRoles - if ('superadmin' -notin $roles) { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::Forbidden - Body = @{ error = 'You do not have permission to perform this action.' } - }) - return - } else { - $Table = Get-CippTable -tablename 'Config' + $Table = Get-CippTable -tablename 'Config' - if ($Request.Query.Action -eq 'ListCurrent') { - $CurrentState = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'OffloadFunctions' and RowKey eq 'OffloadFunctions'" - $VersionTable = Get-CippTable -tablename 'Version' - $Version = Get-CIPPAzDataTableEntity @VersionTable -Filter "RowKey ne 'Version'" - $MainVersion = $Version | Where-Object { $_.RowKey -eq $env:WEBSITE_SITE_NAME } - $OffloadVersions = $Version | Where-Object { $_.RowKey -match '-' } + if ($Request.Query.Action -eq 'ListCurrent') { + $CurrentState = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'OffloadFunctions' and RowKey eq 'OffloadFunctions'" + $VersionTable = Get-CippTable -tablename 'Version' + $Version = Get-CIPPAzDataTableEntity @VersionTable -Filter "RowKey ne 'Version'" + $MainVersion = $Version | Where-Object { $_.RowKey -eq $env:WEBSITE_SITE_NAME } + $OffloadVersions = $Version | Where-Object { $_.RowKey -match '-' } - $Alerts = [System.Collections.Generic.List[string]]::new() + $Alerts = [System.Collections.Generic.List[string]]::new() - $CanEnable = $false - if (!$OffloadVersions.Version) { - $Alerts.Add('No offloaded function apps have been registered. If you''ve just deployed one, this can take up to 15 minutes.') - } else { - $CanEnable = $true - } + $CanEnable = $false + if (!$OffloadVersions.Version) { + $Alerts.Add('No offloaded function apps have been registered. If you''ve just deployed one, this can take up to 15 minutes.') + } else { + $CanEnable = $true + } - foreach ($Offload in $OffloadVersions) { - $FunctionName = $Offload.RowKey - if ([semver]$Offload.Version -ne [semver]$MainVersion.Version) { - $CanEnable = $false - $Alerts.Add("The version of $FunctionName ($($Offload.Version)) does not match the current version of $($MainVersion.Version).") - } + foreach ($Offload in $OffloadVersions) { + $FunctionName = $Offload.RowKey + if ([semver]$Offload.Version -ne [semver]$MainVersion.Version) { + $CanEnable = $false + $Alerts.Add("The version of $FunctionName ($($Offload.Version)) does not match the current version of $($MainVersion.Version).") } + } - $VersionTable = $Version | Select-Object @{n = 'Name'; e = { $_.RowKey } }, @{n = 'Version'; e = { $_.Version } }, @{n = 'Default'; e = { $_.RowKey -notmatch '-' } } + $VersionTable = $Version | Select-Object @{n = 'Name'; e = { $_.RowKey } }, @{n = 'Version'; e = { $_.Version } }, @{n = 'Default'; e = { $_.RowKey -notmatch '-' } } - $CurrentState = if (!$CurrentState) { - [PSCustomObject]@{ - OffloadFunctions = $false - Version = @($VersionTable) - Alerts = $Alerts - CanEnable = $CanEnable - } - } else { - [PSCustomObject]@{ - OffloadFunctions = $CurrentState.state - Version = @($VersionTable) - Alerts = $Alerts - CanEnable = $CanEnable - } + $CurrentState = if (!$CurrentState) { + [PSCustomObject]@{ + OffloadFunctions = $false + Version = @($VersionTable) + Alerts = $Alerts + CanEnable = $CanEnable } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $CurrentState - }) } else { - Add-CIPPAzDataTableEntity @Table -Entity @{ - PartitionKey = 'OffloadFunctions' - RowKey = 'OffloadFunctions' - state = $request.Body.OffloadFunctions - } -Force - - if ($Request.Body.OffloadFunctions) { - $Results = 'Enabled Offload Functions' - } else { - $Results = 'Disabled Offload Functions' + [PSCustomObject]@{ + OffloadFunctions = $CurrentState.state + Version = @($VersionTable) + Alerts = $Alerts + CanEnable = $CanEnable } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ results = $Results } - }) } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $CurrentState + }) + } else { + Add-CIPPAzDataTableEntity @Table -Entity @{ + PartitionKey = 'OffloadFunctions' + RowKey = 'OffloadFunctions' + state = $request.Body.OffloadFunctions + } -Force + if ($Request.Body.OffloadFunctions) { + $Results = 'Enabled Offload Functions' + } else { + $Results = 'Disabled Offload Functions' + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ results = $Results } + }) } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 index 614ac38e610c..947c4ac50ef0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecPartnerMode { +function Invoke-ExecPartnerMode { <# .FUNCTIONALITY Entrypoint @@ -10,74 +10,67 @@ Function Invoke-ExecPartnerMode { [CmdletBinding()] param($Request, $TriggerMetadata) - $roles = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json).userRoles - if ('superadmin' -notin $roles) { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::Forbidden - Body = @{ error = 'You do not have permission to perform this action.' } - }) - return - } else { - $Table = Get-CippTable -tablename 'tenantMode' - if ($request.body.TenantMode) { - Add-CIPPAzDataTableEntity @Table -Entity @{ - PartitionKey = 'Setting' - RowKey = 'PartnerModeSetting' - state = $request.body.TenantMode - } -Force - if ($Request.Body.TenantMode -eq 'default') { - $Table = Get-CippTable -tablename 'Tenants' - $Tenant = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Tenants' and RowKey eq '$($env:TenantID)'" -Property RowKey, PartitionKey, customerId, displayName - if ($Tenant) { - try { - Remove-AzDataTableEntity -Force @Table -Entity $Tenant - } catch { - } + $Table = Get-CippTable -tablename 'tenantMode' + if ($request.body.TenantMode) { + Add-CIPPAzDataTableEntity @Table -Entity @{ + PartitionKey = 'Setting' + RowKey = 'PartnerModeSetting' + state = $request.body.TenantMode + } -Force + + if ($Request.Body.TenantMode -eq 'default') { + $Table = Get-CippTable -tablename 'Tenants' + $Tenant = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Tenants' and RowKey eq '$($env:TenantID)'" -Property RowKey, PartitionKey, customerId, displayName + if ($Tenant) { + try { + Remove-AzDataTableEntity -Force @Table -Entity $Tenant + } catch { } - } elseif ($Request.Body.TenantMode -eq 'PartnerTenantAvailable') { - $InputObject = [PSCustomObject]@{ - Batch = @( + } + } elseif ($Request.Body.TenantMode -eq 'PartnerTenantAvailable') { + $InputObject = [PSCustomObject]@{ + Batch = @( + @{ + FunctionName = 'UpdateTenants' + } + ) + OrchestratorName = 'UpdateTenants' + SkipLog = $true + } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ + results = @( @{ - FunctionName = 'UpdateTenants' + resultText = "Set Tenant mode to $($Request.body.TenantMode)" + state = 'success' } ) - OrchestratorName = 'UpdateTenants' - SkipLog = $true } - Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) - } - - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ - results = @( - @{ - resultText = "Set Tenant mode to $($Request.body.TenantMode)" - state = 'success' - } - ) - } - }) + }) - } + } - if ($request.query.action -eq 'ListCurrent') { - $CurrentState = Get-CIPPAzDataTableEntity @Table - $CurrentState = if (!$CurrentState) { - [PSCustomObject]@{ - TenantMode = 'default' - } - } else { - [PSCustomObject]@{ - TenantMode = $CurrentState.state - } + if ($request.query.action -eq 'ListCurrent') { + $CurrentState = Get-CIPPAzDataTableEntity @Table + $CurrentState = if (!$CurrentState) { + [PSCustomObject]@{ + TenantMode = 'default' + } + } else { + [PSCustomObject]@{ + TenantMode = $CurrentState.state } - - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $CurrentState - }) } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $CurrentState + }) } + } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 index bd4966322035..fa88684ca0f6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecDeviceCodeLogon.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecDeviceCodeLogon { +function Invoke-ExecDeviceCodeLogon { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -10,19 +10,6 @@ Function Invoke-ExecDeviceCodeLogon { [CmdletBinding()] param($Request, $TriggerMetadata) - $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) - if ('admin' -notin $UserCreds.userRoles) { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - ContentType = 'application/json' - StatusCode = [HttpStatusCode]::Forbidden - Body = @{ - error = 'Forbidden' - errorMessage = 'You do not have permission to perform this action' - } | ConvertTo-Json - }) - exit - } - $APIName = $Request.Params.CIPPEndpoint $Headers = $Request.Headers Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 index d921f78911e0..35c010ee5731 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecSAMSetup { +function Invoke-ExecSAMSetup { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -13,7 +13,7 @@ Function Invoke-ExecSAMSetup { [CmdletBinding()] param($Request, $TriggerMetadata) - $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) + if ($Request.Query.error) { Add-Type -AssemblyName System.Web Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ @@ -23,14 +23,6 @@ Function Invoke-ExecSAMSetup { }) exit } - if ('admin' -notin $UserCreds.userRoles) { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - ContentType = 'text/html' - StatusCode = [HttpStatusCode]::Forbidden - Body = 'Could not find an admin cookie in your browser, please confirm that you have the admin role in CIPP. Make sure you do not have an adblocker active, use a Chromium browser, and allow cookies. If our automatic refresh does not work, try pressing the URL bar and hitting enter. We will try to refresh ourselves in 3 seconds.' - }) - exit - } $APIName = $Request.Params.CIPPEndpoint $Headers = $Request.Headers diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainHealth.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainHealth.ps1 index c080fe78c7fe..cbe90862aac0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainHealth.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainHealth.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ListDomainHealth { +function Invoke-ListDomainHealth { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -38,8 +38,8 @@ Function Invoke-ListDomainHealth { } Set-DnsResolver -Resolver $Resolver - #UNDOREPLACE - $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) + + $UserRoles = Get-CIPPAccessPermissions -Request $Request $APIName = $Request.Params.CIPPEndpoint $Headers = $Request.Headers @@ -87,7 +87,7 @@ Function Invoke-ListDomainHealth { if ($Request.Query.Selector) { $DkimQuery.Selectors = ($Request.Query.Selector).trim() -split '\s*,\s*' - if ('admin' -in $UserCreds.userRoles -or 'editor' -in $UserCreds.userRoles) { + if ('admin' -in $UserRoles -or 'editor' -in $UserRoles) { $DkimSelectors = [string]($DkimQuery.Selectors | ConvertTo-Json -Compress) if ($DomainInfo) { $DomainInfo.DkimSelectors = $DkimSelectors