Note: PowerShell integration requires a ShareGate Migrate Pro or Enterprise subscription. It is not available on the Essentials plan.
This article is for the ShareGate Migrate PowerShell integration only. Application-only authentication lets you run mailbox migrations from PowerShell without a signed-in user account. Instead of user credentials, ShareGate Migrate authenticates using an Azure app registration. This is well-suited for automated or scheduled migrations in enterprise environments.
During setup, you'll capture two values to pass to ShareGate's PowerShell commands: the Application (client) ID and the Directory (tenant) ID.
Before you begin
ShareGate Migrate Pro or Enterprise subscription
Global Administrator access on both the source and destination Microsoft 365 tenants, needed to create the app registration and grant admin consent
Single-tenant vs multi-tenant
Knowing the difference between two terms will help you choose the right setup:
An app registration is the blueprint of the application. It lives in the home tenant (the tenant where you create it) and defines the app's identity, API permissions, and certificates.
An enterprise application (also called a service principal) is the local instance of that app inside a specific tenant. This is what you grant admin consent on and assign roles to.
Choose based on how many tenants you migrate:
Single-tenant: the app is used only in the tenant where you register it. Under Supported account types, choose My organization only. To migrate between two tenants, repeat the full setup in each tenant.
Multi-tenant: one app registration in your home tenant, reused across several tenants. This is the common choice for consultants, managed service providers, and source-to-destination migrations. Under Supported account types, choose Multiple Entra ID tenants and keep Allow all tenants selected. You then consent the app in each additional tenant and assign the Exchange Administrator role there. See Set up additional tenants below.
With a multi-tenant app, you build the credential object once and pass a different -TenantId to Connect-MicrosoftOnline for each tenant.
Set up the app registration
Do this in your home tenant. For a single-tenant app, repeat in each tenant you migrate to or from. For a multi-tenant app, do it once and then follow Set up additional tenants below.
Option 1: Manual setup in the Azure portal
Step 1: Create the app registration
Sign in to the Microsoft Entra admin center as a Global Administrator.
Go to Entra ID > App registrations > New registration.
Give the app a name (for example, ShareGate Mailbox Migration).
Under Supported account types, choose the option that matches your scenario. See Single-tenant vs multi-tenant above.
Leave the Redirect URI empty for now.
Click Register.
On the Overview page, copy the Application (client) ID and the Directory (tenant) ID. You'll use these with
New-AzureApplicationandConnect-MicrosoftOnline. Also note the Display name or Object ID for the role assignment in Step 4.
Step 2: Add a reply URL
Note: This step is required for multi-tenant apps. Admin consent won't complete without at least one reply URL. https://go.sharegate.com/vmen is a ShareGate landing page that confirms consent succeeded.
In your app registration, go to Authentication and click + Add Redirect URI.
In the Web platform pane, under Redirect URI, enter
https://go.sharegate.com/vmen.Click Configure.
Step 3: Add API permissions
Choose one of the two methods below.
Option A: Manually via the Azure portal
Go to API permissions > Add a permission.
Add each of the Application permissions listed below (not Delegated). You add the Microsoft Graph permissions and the Office 365 Exchange Online permissions separately.
Click Grant admin consent for [your tenant] and confirm.
Microsoft Graph permissions:
| Mail items |
| Calendar events |
| Contacts |
| Mailbox settings |
| Mailbox listing, user profiles |
| License validation |
| Domain validation |
Office 365 Exchange Online permissions:
Note: These permissions are found under Office 365 Exchange Online, not Microsoft Graph. Use Exchange.ManageAsApp, not Exchange.ManageAsAppV2.
| Archive and group mailboxes (EWS) |
| Mailbox management |
Option B: Via the app manifest
This lets you add all permissions at once by pasting a JSON snippet, avoiding manual selection errors.
In your app registration, go to Manifest.
Find the
requiredResourceAccessarray and replace it with the following:"requiredResourceAccess": [
{
"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{ "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" },
{ "id": "dc890d15-9560-4a4c-9b7f-a736ec74ec40", "type": "Role" }
]
},
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{ "id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99", "type": "Role" },
{ "id": "6918b873-d17a-4dc1-b314-35f528134491", "type": "Role" },
{ "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" },
{ "id": "e2a3a72e-5f79-4c64-b1b1-878b674786c9", "type": "Role" },
{ "id": "6931bccd-447a-43d1-b442-00a195474933", "type": "Role" },
{ "id": "498476ce-e0fe-48b0-b801-37ba7e2685c6", "type": "Role" },
{ "id": "df021288-bdef-4463-88db-98f22de89214", "type": "Role" }
]
}
]Click Save.
Go to API permissions and click Grant admin consent for [your tenant] and confirm.
Step 4: Assign the Exchange Administrator role
Note: This step is required for archive management, litigation holds, and mailbox size operations.
Exchange Administrator is a directory-level role, so you can't assign it directly from the app registration's Roles and administrators page. The steps below take you to the directory-level assignment view.
In your app registration, go to Roles and administrators.
In the line that reads "Directory-level roles have inherited access to this resource and can only be assigned at the directory level here," click here to open directory-level role assignment.
Search for and select Exchange Administrator.
Click + Add assignments, then Select member(s).
Search for your app registration's Display name or Object ID, select it, and click Select.
Click Next, then Assign.
Option 2: Quick setup with PowerShell (recommended)
This script automates everything in Option 1: it creates the app registration, adds the reply URL, grants all required permissions, and assigns the Exchange Administrator role. It does not create a credential. You do that in Add a credential below.
First, install the Microsoft Graph PowerShell SDK (one time):
Install-Module Microsoft.Graph -Scope CurrentUser
Then run the following, signed in as a Global Administrator of the home tenant. Set $multiTenant = $true for a multi-tenant app.
$ErrorActionPreference = 'Stop'
$displayName = 'ShareGate Mailbox Migration'
$multiTenant = $false # set to $true to allow the app to be consented in other tenants
$replyUrl = 'https://go.sharegate.com/vmen'
$signInAudience = if ($multiTenant) { 'AzureADMultipleOrgs' } else { 'AzureADMyOrg' }
# Well-known resource app IDs
$graphAppId = '00000003-0000-0000-c000-000000000000' # Microsoft Graph
$exoAppId = '00000002-0000-0ff1-ce00-000000000000' # Office 365 Exchange Online
# Application permissions to grant
$graphRoleIds = @(
'e2a3a72e-5f79-4c64-b1b1-878b674786c9', # Mail.ReadWrite
'ef54d2bf-783f-4e0f-bca1-3210c0444d99', # Calendars.ReadWrite
'6918b873-d17a-4dc1-b314-35f528134491', # Contacts.ReadWrite
'6931bccd-447a-43d1-b442-00a195474933', # MailboxSettings.ReadWrite
'df021288-bdef-4463-88db-98f22de89214', # User.Read.All
'7ab1d382-f21e-4acd-a863-ba3e13f7da61', # Directory.Read.All
'498476ce-e0fe-48b0-b801-37ba7e2685c6' # Organization.Read.All
)
$exoRoleIds = @(
'dc50a0fb-09a3-484d-be87-e023b12c6440', # full_access_as_app
'dc890d15-9560-4a4c-9b7f-a736ec74ec40' # Exchange.ManageAsApp
)
$exchangeAdminRoleId = '29232cdf-9323-42fd-ade2-1d097af3e4de' # Exchange Administrator (built-in)
# 1. Sign in
Connect-MgGraph -Scopes 'Application.ReadWrite.All','AppRoleAssignment.ReadWrite.All','RoleManagement.ReadWrite.Directory'
# 2. Create the app registration
$requiredResourceAccess = @(
@{ ResourceAppId = $graphAppId; ResourceAccess = @($graphRoleIds | ForEach-Object { @{ Id = $_; Type = 'Role' } }) },
@{ ResourceAppId = $exoAppId; ResourceAccess = @($exoRoleIds | ForEach-Object { @{ Id = $_; Type = 'Role' } }) }
)
$app = New-MgApplication -DisplayName $displayName -SignInAudience $signInAudience `
-Web @{ RedirectUris = @($replyUrl) } `
-RequiredResourceAccess $requiredResourceAccess
# 3. Create the service principal
$sp = New-MgServicePrincipal -AppId $app.AppId
Start-Sleep -Seconds 10 # let the service principal replicate
# 4. Grant admin consent
$graphSp = Get-MgServicePrincipal -Filter "appId eq '$graphAppId'"
$exoSp = Get-MgServicePrincipal -Filter "appId eq '$exoAppId'"
foreach ($roleId in $graphRoleIds) {
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -PrincipalId $sp.Id -ResourceId $graphSp.Id -AppRoleId $roleId | Out-Null
}
foreach ($roleId in $exoRoleIds) {
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -PrincipalId $sp.Id -ResourceId $exoSp.Id -AppRoleId $roleId | Out-Null
}
# 5. Assign the Exchange Administrator role
New-MgRoleManagementDirectoryRoleAssignment -PrincipalId $sp.Id -RoleDefinitionId $exchangeAdminRoleId -DirectoryScopeId '/' | Out-Null
# 6. Output the values you'll use with ShareGate
[pscustomobject]@{
DisplayName = $displayName
ApplicationId = $app.AppId
TenantId = (Get-MgContext).TenantId
} | Format-List
Copy the ApplicationId and TenantId from the output. You'll use them when you connect. For a multi-tenant app, this configures your home tenant only. Follow Set up additional tenants below for each additional tenant.
Set up additional tenants
Note: This section applies to multi-tenant apps only. The app registration and its credential live in your home tenant. To use the app in another tenant, an administrator of that tenant must consent to it and assign the Exchange Administrator role. Repeat for each additional tenant.
1. Grant admin consent in the additional tenant
An administrator of the additional tenant opens the following URL in a browser, replaces the placeholders, and signs in as a Global Administrator of that tenant:
https://login.microsoftonline.com/<additional-tenant-id-or-domain>/adminconsent?client_id=<application-client-id>
After reviewing and accepting the permissions, the browser redirects to the ShareGate confirmation page. This provisions the app's enterprise application (service principal) in that tenant.
2. Assign the Exchange Administrator role in the additional tenant
While signed in to the additional tenant:
Go to Entra ID > Roles & admins.
Search for and select Exchange Administrator.
Click + Add assignments, then Select member(s).
Search for the app by its Display name or Application (client) ID, select it, and click Select.
Click Next, then Assign.
Add a credential
New-AzureApplication supports two certificate-based authentication methods. Choose one.
Option A: Certificate (from file)
Go to Certificates & secrets > Certificates > Upload certificate.
Upload your
.ceror.pempublic key file.Keep the private key (
.pfx) accessible from PowerShell at runtime.
Option B: Certificate thumbprint (Windows Certificate Store)
Install the certificate (with private key) into the Windows Certificate Store on the machine running the migration.
Go to Certificates & secrets > Certificates > Upload certificate and upload the public key.
Note the thumbprint. You'll pass it directly to
New-AzureApplication.
Note: For a multi-tenant app, upload the credential once to the app registration in your home tenant. The same credential works for every tenant the app is consented in.
Connect from ShareGate
Build a credential object with New-AzureApplication, then connect with Connect-MicrosoftOnline. Pass the target tenant with -TenantId.
# Build a credential object from a certificate thumbprint
$azureApp = New-AzureApplication -ClientId <application-client-id> -Thumbprint <certificate-thumbprint>
# Connect to a tenant
Connect-MicrosoftOnline -TenantId <directory-tenant-id> -AzureApplication $azureApp
With a multi-tenant app, reuse the same $azureApp object and change -TenantId for each tenant:
Connect-MicrosoftOnline -TenantId <source-tenant-id> -AzureApplication $azureApp
Connect-MicrosoftOnline -TenantId <destination-tenant-id> -AzureApplication $azureApp
Note: If your security policy prevents granting one of the required permissions, add -AllowMissingPermissions to Connect-MicrosoftOnline to connect anyway. Operations that rely on the missing permission will fail with Forbidden errors. This switch only relaxes the permission check after authentication succeeds. It won't resolve a failed sign-in.
Known limitations
Group calendars are not supported under application-only authentication. This is a Microsoft Graph API limitation that affects all migration tools.
