docsMicrosoft365 ConnectorsManually Assign Remediation Roles

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:

  1. Manual Configuration via the Microsoft 365 Admin Portal
    Follow step-by-step instructions to assign the necessary roles directly through the portal interface.

  2. 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

  1. Sign in to the Microsoft Entra admin center
  2. Browse to Entra ID > Roles & admins (Press Show more.. if you can’t see it)
  3. Select the Exchange Administrator role to open its details

Role-Remediation-Step01

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

Role-Remediation-Step02

  1. It will appear on the list once it has been added

Role-Remediation-Step03

⚠️ 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.