Manually Enabling Remediation Roles for Optimize365
This guide walks you through enabling the required Remediation Roles for Optimize365’s remediation app registration, allowing the platform to securely perform write and configuration changes across your Microsoft 365 environment.
The remediation app registration requires elevated roles beyond Global Reader. These roles enable Optimize365 to fix misconfigurations, enforce baselines, and apply security/compliance changes automatically.
You can enable the required permissions for Optimize365 using one of the following methods:
-
Manual Configuration via the Microsoft 365 Admin Portal
Follow step-by-step instructions to assign the necessary roles directly through the portal interface. -
Automated Setup via PowerShell Script
Run a pre-built script to streamline the setup process and assign all roles with minimal manual effort.
Prerequisites
- A Global Administrator user with access to Microsoft Entra-ID.
Why These Roles Are Required
Optimize365 remediation features go beyond visibility. They require write permissions to enforce security and compliance changes across Microsoft 365 services.
Without these roles, Optimize365 will be limited to read-only scanning.
The required roles are:
- Exchange Administrator
- Security Administrator
- Compliance Administrator
- Conditional Access Administrator
- Authentication Administrator
- SharePoint Administrator
- Teams Administrator
- User Administrator
- Application Administrator
- Privileged Role Administrator
- Authentication Policy Administrator
- Cloud Application Administrator
- Groups Administrator
- Privileged Authentication Administrator
- Security Operator
- Azure Information Protection Administrator
- Cloud Device Administrator
- Global Secure Access Administrator
- Compliance Data Administrator
Enabling Remediation Roles
Step 1: Verify & Assign Remediation Roles (Per Tenant)
Option 1
- Sign in to the Microsoft Entra admin center
- Browse to Entra ID > Roles & admins (Press Show more.. if you can’t see it)
- Select the Exchange Administrator role to open its details

- Select Add assignments and search for “Optimize365-Write” (AppId: e5099652-03bb-4940-8490-3b3ca8e75369) and press Add

- It will appear on the list once it has been added

⚠️ You must repeat steps 3–5 for each of the roles listed above (not just Exchange Administrator).
Option 2
Download the PowerShell script: assign-rem-roles.ps1
# Disconnect any existing sessions
Disconnect-MgGraph -ErrorAction SilentlyContinue
# Connect with required scopes
Connect-MgGraph -Scopes @(
"RoleManagement.ReadWrite.Directory",
"Directory.ReadWrite.All",
"Application.Read.All"
)
$appId = "e5099652-03bb-4940-8490-3b3ca8e75369"
$rolesToAssign = @(
"Exchange Administrator",
"Security Administrator",
"Compliance Administrator",
"Conditional Access Administrator",
"Authentication Administrator",
"SharePoint Administrator",
"Teams Administrator",
"User Administrator",
"Application Administrator",
"Privileged Role Administrator",
"Authentication Policy Administrator",
"Cloud Application Administrator",
"Groups Administrator",
"Privileged Authentication Administrator",
"Security Operator",
"Azure Information Protection Administrator",
"Cloud Device Administrator",
"Global Secure Access Administrator",
"Compliance Data Administrator"
)
$servicePrincipal = Get-MgServicePrincipal -Filter "appId eq '$appId'"
if (-not $servicePrincipal) {
Write-Host "❌ Service principal not found" -ForegroundColor Red
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
exit
}
Write-Host "✅ Found: $($servicePrincipal.DisplayName)`n" -ForegroundColor Green
$roleTemplates = Get-MgDirectoryRoleTemplate -All
$activatedRoles = Get-MgDirectoryRole -All
$assignmentResults = @()
foreach ($roleName in $rolesToAssign) {
$result = [PSCustomObject]@{
RoleName = $roleName
Status = "Unknown"
Action = ""
}
$roleTemplate = $roleTemplates | Where-Object { $_.DisplayName -eq $roleName }
if (-not $roleTemplate) {
$result.Status = "Failed"
$result.Action = "Template not found"
$assignmentResults += $result
continue
}
$role = $activatedRoles | Where-Object { $_.RoleTemplateId -eq $roleTemplate.Id }
if (-not $role) {
try {
$role = New-MgDirectoryRole -RoleTemplateId $roleTemplate.Id
$result.Action = "Activated"
} catch {
$result.Status = "Failed"
$result.Action = "Activation failed"
$assignmentResults += $result
continue
}
}
try {
$members = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -All
if ($members | Where-Object { $_.Id -eq $servicePrincipal.Id }) {
$result.Status = "Success"
$result.Action = "Already assigned"
} else {
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $role.Id -BodyParameter @{
"@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($servicePrincipal.Id)"
}
$result.Status = "Success"
$result.Action = "Newly assigned"
}
} catch {
$result.Status = "Failed"
$result.Action = "Assignment failed"
}
$assignmentResults += $result
}
Start-Sleep -Seconds 5
Write-Host "Verifying assignments...`n" -ForegroundColor Cyan
$uri = "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?`$filter=principalId eq '$($servicePrincipal.Id)'"
$roleAssignments = Invoke-MgGraphRequest -Method GET -Uri $uri
$verifiedRoles = @()
foreach ($assignment in $roleAssignments.value) {
$roleDefUri = "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions/$($assignment.roleDefinitionId)"
$roleDef = Invoke-MgGraphRequest -Method GET -Uri $roleDefUri
$verifiedRoles += $roleDef.displayName
}
$successCount = ($assignmentResults | Where-Object { $_.Status -eq "Success" }).Count
$failedCount = ($assignmentResults | Where-Object { $_.Status -eq "Failed" }).Count
$totalCount = $rolesToAssign.Count
$verifiedCount = ($verifiedRoles | Where-Object { $rolesToAssign -contains $_ }).Count
Write-Host ("=" * 60) -ForegroundColor Cyan
Write-Host "FINAL STATUS" -ForegroundColor Cyan
Write-Host ("=" * 60) -ForegroundColor Cyan
Write-Host "Total: $totalCount | Success: $successCount | Failed: $failedCount | Verified: $verifiedCount`n"
$assignmentResults | Format-Table -Property RoleName, Status, Action -AutoSize
if ($verifiedCount -eq $totalCount) {
Write-Host "✅ All $totalCount roles assigned and verified" -ForegroundColor Green
} elseif ($verifiedCount -gt 0) {
Write-Host "⚠️ Partial success: $verifiedCount/$totalCount verified" -ForegroundColor Yellow
} else {
Write-Host "⚠️ Roles assigned but verification incomplete" -ForegroundColor Yellow
}
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
Write-Host "`n✅ Disconnected" -ForegroundColor Green
## Need Help?
Contact [email protected] if you encounter any issues.