Introduction

In this article you will learn how the Claims X-Ray NG application can be registered in Microsoft Entra ID using the Microsoft Graph PowerShell SDK. With only minor modifications, this guide can be used to register almost any SAML-based application in Entra ID using PowerShell.

The Claims X-Ray NG app is a free tool that can be used to test federated identity providers and simulate application migration scenarios. It can be deployed as a drop-in replacement of the now-defunct original Claims X-Ray application from Microsoft.

Claims X-Ray NG

App Registration

We will first need to install the Microsoft.Graph.Applications and Microsoft.Graph.Identity.SignIns PowerShell modules, including their dependencies:

Install-Module -Name Microsoft.Graph.Applications,Microsoft.Graph.Identity.SignIns -Scope AllUsers -Force

We can then connect to Microsoft Graph API while specifying all permissions required by the registration process:

Connect-MgGraph -NoWelcome -ContextScope Process -Scopes @(
   'User.Read',
   'Application.ReadWrite.All',
   'AppRoleAssignment.ReadWrite.All',
   'DelegatedPermissionGrant.ReadWrite.All',
   'Policy.Read.All',
   'Policy.ReadWrite.ApplicationConfiguration'
)

We are now ready to register the Claims X-Ray NG application in Entra ID:

[string] $appName = 'Claims X-Ray NG'
[string] $appDescription = 'Use the Claims X-Ray NG service to debug and troubleshoot problems with claims issuance.'
[string] $redirectUrl = 'https://claimsxray.net/api/sso'
[hashtable] $infoUrls = @{
    MarketingUrl      = 'https://claimsxray.net/#about'
    TermsOfServiceUrl = 'https://github.com/marcusca10/claimsxray-ng?tab=MIT-1-ov-file'
}

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphApplication] $registeredApp =
   New-MgApplication -DisplayName $appName `
                     -Description $appDescription `
                     -Web @{ RedirectUris = $redirectUrl } `
                     -DefaultRedirectUri $redirectUrl `
                     -GroupMembershipClaims All `
                     -Info $infoUrls

The previous command would always fail when used with the -SignInAudience and -IdentifierUris parameters. These application properties thus need to be configured separately, making the application single-tenant:

Update-MgApplication -ApplicationId $registeredApp.Id `
                     -SignInAudience 'AzureADMyOrg' `
                     -IdentifierUris 'urn:claimsxrayng'

It is time to configure the application logo. As the Claims X-Ray website only contains a logo in the SVG format, which is not supported by Entra ID, I had to first convert it to PNG:

Claims X-Ray Logo

The logo must be downloaded locally before it can be uploaded to Entra ID. Upon success, the temporary local copy of the logo can be deleted:

[string] $logoUrl = 'https://www.dsinternals.com/assets/images/claims-xray-logo.png'
[string] $tempLogoPath = New-TemporaryFile
Invoke-WebRequest -Uri $logoUrl -OutFile $tempLogoPath -UseBasicParsing -ErrorAction Stop
try {
    Set-MgApplicationLogo -ApplicationId $registeredApp.Id -ContentType 'image/png' -InFile $tempLogoPath
}
finally {
    # Cleanup
    Remove-Item -Path $tempLogoPath
}

Service Principal

Now that the application itself is registered, we can now register the corresponding service principal, which will appear in the Enterprise Applications section of the Microsoft Entra Admin Center:

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphServicePrincipal] $servicePrincipal =
   New-MgServicePrincipal -DisplayName $appName `
                          -AppId $registeredApp.AppId `
                          -AccountEnabled `
                          -ServicePrincipalType Application `
                          -PreferredSingleSignOnMode saml `
                          -ReplyUrls $redirectUrl `
                          -Notes $appDescription `
                          -Tags 'WindowsAzureActiveDirectoryIntegratedApp','WindowsAzureActiveDirectoryCustomSingleSignOnApplication'

Token-Signing Certificate

One of the requirements for a functional relying party trust is a token-signing certificate. For the sake of simplicity, we can generate a self-signed one, that will be valid for 2 years:

[datetime] $now = Get-Date
[string] $certificateDisplayName = 'CN={0} Entra ID Token Signing {1:yyyy}' -f $appName,$now
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphSelfSignedCertificate] $tokenSigningCertificate =
   Add-MgServicePrincipalTokenSigningCertificate -ServicePrincipalId $servicePrincipal.Id `
                                                 -DisplayName $certificateDisplayName `
                                                 -EndDateTime $now.AddYears(2)

The result will look like this in Entra Admin Center:

SAML Signing Certificate Screenshot

Application Permissions

As we want the Claims X-Ray NG app to receive information about signed-in users, we need to delegate the User.Read permission:

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphServicePrincipal] $microsoftGraph =
    Get-MgServicePrincipal -Filter "DisplayName eq 'Microsoft Graph'"

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphPermissionScope] $userReadScope =
    $microsoftGraph.Oauth2PermissionScopes | Where-Object Value -eq 'User.Read'

Update-MgApplication -ApplicationId $registeredApp.Id -RequiredResourceAccess @{
    ResourceAppId = $microsoftGraph.AppId
    ResourceAccess = @(@{
        id = $userReadScope.Id
        type = 'Scope'
    })
}

It would make sense to hide the corresponding consent prompt from end-users accessing the app:

 Screenshot

We can therefore give the required consent on behalf of the entire Entra ID Tenant in advance:

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphOAuth2PermissionGrant] $adminConsent =
    New-MgOauth2PermissionGrant -ClientId $servicePrincipal.Id `
                                -ConsentType AllPrincipals `
                                -ResourceId $microsoftGraph.Id `
                                -Scope 'User.Read'

This is how the results should look in the Entra Admin Center:

Admin Consent Screenshot

User Assignment

For users to see the application in the My Apps portal, they need to be assigned to the application. This is how we can assign ourselves to the app:

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphDirectoryObject] $currentUser =
    Invoke-GraphRequest -Method GET -Uri '/v1.0/me'

[string] $defaultAppAccessRole = [Guid]::Empty
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRoleAssignment] $appAssignment =
   New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $servicePrincipal.Id `
                                           -ResourceId $servicePrincipal.Id `
                                           -AppRoleId $defaultAppAccessRole `
                                           -PrincipalType User `
                                           -PrincipalId $currentUser.Id

Note that we have not declared any custom roles for the application, so we had to reference the default app role ID of 00000000-0000-0000-0000-000000000000.

The result can again be verified through the Entra Admin Center:

User Assignment Screenshot

For apps with role-based access control, custom roles can be defined instead of using the default one:

[hashtable] $adminRole = @{
    Id = '0125b1e2-4ed5-4994-b95e-e910ef068d69'
    DisplayName = 'Admin'
    Value = 'Admin'
    Description = 'Administrators of the app'
    AllowedMemberTypes = @('User')
    IsEnabled = $true
}

[hashtable] $userRole = @{
    Id = '8930568d-3a48-42a0-8dc0-8bcd56200954'
    DisplayName = 'User'
    Value = 'User'
    Description = 'Standard users of the app'
    AllowedMemberTypes = @('User')
    IsEnabled = $true
}

Update-MgApplication -ApplicationId $registeredApp.Id -AppRoles $adminRole,$userRole

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRoleAssignment] $adminAssignment =
   New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $servicePrincipal.Id `
                                           -ResourceId $servicePrincipal.Id `
                                           -AppRoleId $adminRole.Id `
                                           -PrincipalType User `
                                           -PrincipalId $currentUser.Id

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRoleAssignment] $userAssignment =
   New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $servicePrincipal.Id `
                                           -ResourceId $servicePrincipal.Id `
                                           -AppRoleId $userRole.Id `
                                           -PrincipalType User `
                                           -PrincipalId $currentUser.Id

As you can see in this example, each user can be assigned more than one role:

Custom Role Assignment

App Ownership

We can optionally configure the current user as the application owner:

[string] $currentUserOdataId = "https://graph.microsoft.com/v1.0/users/{$($currentUser.Id)}"
New-MgApplicationOwnerByRef -ApplicationId $registeredApp.Id -OdataId $currentUserOdataId
New-MgServicePrincipalOwnerByRef -ServicePrincipalId $servicePrincipal.Id -OdataId $currentUserOdataId

Assigning owners is a simple way to grant the ability to manage all aspects of the application:

Application Registration Owner

SAML Token Configuration

The built-in acct and groups claims are optional, so we need to explicitly enable them:

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphOptionalClaims] $optionalClaims = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphOptionalClaims]::DeserializeFromDictionary(@{
   Saml2Token = @(
      @{ Name = 'acct' },
      @{ Name = 'groups' }
   )
})

Update-MgApplication -ApplicationId $registeredApp.Id -OptionalClaims $optionalClaims

Here is how the change will show up in the UI:

Optional Claims Screenshot

Contrary to what the documentation says, the email and upn do not need to be configured here to appear in SAML tokens. Even the groups claim does not need to be specified if the default group identifier settings are sufficient.

It is also possible to define custom SAML claims for an application:

Custom Claims Screenshot

I have decided to map the Entra ID attributes to SAML claims as follows:

Claim Type Value
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier user.userprincipalname
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name user.userprincipalname
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn user.userprincipalname
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress user.mail
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname user.givenname
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname user.surname
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress user.streetaddress
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality user.city
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode user.postalcode
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/stateorprovince user.state
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country user.country
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone user.mobilephone
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/homephone user.telephonenumber
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/otherphone user.facsimiletelephonenumber
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/employeeid user.employeeid
http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID user.onpremisesimmutableid
http://schemas.microsoft.com/ws/2008/06/identity/claims/role user.assignedroles
http://schemas.microsoft.com/2012/01/requestcontext/claims/relyingpartytrustid application.objectid

Unfortunately, I have not found a way to configure these rules through the Graph API. Please let me know in case you were more successful than me.

As a workaround, we can override the application-specific claim issuance configuration by creating a Claims Mapping Policy and assigning it to the Claims X-Ray application:

[string] $allClaimsMapping = @'
{
   "ClaimsMappingPolicy": {
       "Version": 1,
       "IncludeBasicClaimSet": "true",
       "ClaimsSchema": [
           {
               "Source": "user",
               "ID": "userprincipalname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
           },
           {
               "Source": "user",
               "ID": "userprincipalname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
           },
           {
               "Source": "user",
               "ID": "userprincipalname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"
           },
           {
               "Source": "user",
               "ID": "mail",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
           },
           {
               "Source": "user",
               "ID": "givenname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
           },
           {
               "Source": "user",
               "ID": "surname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
           },
           {
               "Source": "user",
               "ID": "streetaddress",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress"
           },
           {
               "Source": "user",
               "ID": "city",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality"
           },
           {
               "Source": "user",
               "ID": "postalcode",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode"
           },
           {
               "Source": "user",
               "ID": "state",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/stateorprovince"
           },
           {
               "Source": "user",
               "ID": "country",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country"
           },
           {
               "Source": "user",
               "ID": "mobilephone",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone"
           },
           {
               "Source": "user",
               "ID": "telephonenumber",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/homephone"
           },
           {
               "Source": "user",
               "ID": "facsimiletelephonenumber",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/otherphone"
           },
           {
               "Source": "user",
               "ID": "employeeid",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/employeeid"
           },
           {
               "Source": "user",
               "ID": "onpremisesimmutableid",
               "SamlClaimType": "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID"
           },
           {
               "Source": "application",
               "ID": "objectid",
               "SamlClaimType": "http://schemas.microsoft.com/2012/01/requestcontext/claims/relyingpartytrustid"
           },
           {
               "Source": "user",
               "ID": "assignedroles",
               "SamlClaimType": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
           }
       ],
       "ClaimsTransformation": []
   }
}
'@

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphClaimsMappingPolicy] $allClaimsPolicy =
   New-MgPolicyClaimMappingPolicy -DisplayName 'Issue All Claims' -Definition $allClaimsMapping

New-MgServicePrincipalClaimMappingPolicyByRef -ServicePrincipalId $servicePrincipal.Id -OdataId "https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies/$($allClaimsPolicy.Id)"

Unfortunately, there is currently no user interface for viewing/editing the policies:

Claims Mapping Policy Screenshot

Testing the Sign-In

We are finally ready to log into the Claims X-Ray NG application and test the SAML claim issuance. This can be done by visiting the My Apps portal:

My Apps Portal Screenshot

Or we can simply run this PowerShell command, which will automatically open the Claims X-Ray NG application in the default browser:

Start-Process ('https://myapps.microsoft.com/signin/{0}?tenantId={1}' -f $servicePrincipal.AppId,$servicePrincipal.AppOwnerOrganizationId)

Limitations

  • Unlike production applications, the Claims X-Ray does not validate the token-signing certificates.
  • This article does not cover the assignment of a Conditional Access Policy, which could enforce MFA.

Fetching the New Objects

This is how we can list all Entra ID objects created by the PowerShell commands above:

Get-MgApplication -Filter "DisplayName eq 'Claims X-Ray NG'" | Format-List
Get-MgServicePrincipal -Filter "DisplayName eq 'Claims X-Ray NG'" | Format-List
Get-MgPolicyClaimMappingPolicy -Filter "DisplayName eq 'Issue All Claims'" | Format-List

End-to-End Script

To wrap things up, here is the full PowerShell script, concatenated from the code snippets above:

#Requires -Version 5
#Requires -Modules Microsoft.Graph.Applications,Microsoft.Graph.Identity.SignIns

# Note: The required modules can be installed using the following command:
# Install-Module -Name Microsoft.Graph.Applications,Microsoft.Graph.Identity.SignIns -Scope AllUsers -Force

# Connect to Entra ID
# Note: The -TenantId parameter is also required when using a Microsoft Account.
Connect-MgGraph -NoWelcome -ContextScope Process -Scopes @(
   'User.Read',
   'Application.ReadWrite.All',
   'AppRoleAssignment.ReadWrite.All',
   'DelegatedPermissionGrant.ReadWrite.All',
   'Policy.Read.All',
   'Policy.ReadWrite.ApplicationConfiguration'
)

# Register the application
[string] $appName = 'Claims X-Ray NG'
[string] $appDescription = 'Use the Claims X-Ray NG service to debug and troubleshoot problems with claims issuance.'
[string] $redirectUrl = 'https://claimsxray.net/api/sso'
[hashtable] $infoUrls = @{
    MarketingUrl      = 'https://claimsxray.net/#about'
    TermsOfServiceUrl = 'https://github.com/marcusca10/claimsxray-ng?tab=MIT-1-ov-file'
}

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphApplication] $registeredApp =
   New-MgApplication -DisplayName $appName `
                     -Description $appDescription `
                     -Web @{ RedirectUris = $redirectUrl } `
                     -DefaultRedirectUri $redirectUrl `
                     -GroupMembershipClaims All `
                     -Info $infoUrls

Update-MgApplication -ApplicationId $registeredApp.Id `
                     -SignInAudience 'AzureADMyOrg' `
                     -IdentifierUris 'urn:claimsxrayng'

# Configure application logo
[string] $logoUrl = 'https://www.dsinternals.com/assets/images/claims-xray-logo.png'
[string] $tempLogoPath = New-TemporaryFile
Invoke-WebRequest -Uri $logoUrl -OutFile $tempLogoPath -UseBasicParsing -ErrorAction Stop
try {
    Set-MgApplicationLogo -ApplicationId $registeredApp.Id -ContentType 'image/png' -InFile $tempLogoPath
}
finally {
    # Cleanup
    Remove-Item -Path $tempLogoPath
}

# Create the service principal
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphServicePrincipal] $servicePrincipal =
   New-MgServicePrincipal -DisplayName $appName `
                          -AppId $registeredApp.AppId `
                          -AccountEnabled `
                          -ServicePrincipalType Application `
                          -PreferredSingleSignOnMode saml `
                          -ReplyUrls $redirectUrl `
                          -Notes $appDescription `
                          -Tags 'WindowsAzureActiveDirectoryIntegratedApp','WindowsAzureActiveDirectoryCustomSingleSignOnApplication'

# Generate a new token-signing certificate
[datetime] $now = Get-Date
[string] $certificateDisplayName = 'CN={0} Entra ID Token Signing {1:yyyy}' -f $appName,$now
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphSelfSignedCertificate] $tokenSigningCertificate =
   Add-MgServicePrincipalTokenSigningCertificate -ServicePrincipalId $servicePrincipal.Id `
                                                 -DisplayName $certificateDisplayName `
                                                 -EndDateTime $now.AddYears(2)

# Delegate the User.Read permission
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphServicePrincipal] $microsoftGraph =
    Get-MgServicePrincipal -Filter "DisplayName eq 'Microsoft Graph'"

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphPermissionScope] $userReadScope =
    $microsoftGraph.Oauth2PermissionScopes | Where-Object Value -eq 'User.Read'

Update-MgApplication -ApplicationId $registeredApp.Id -RequiredResourceAccess @{
    ResourceAppId = $microsoftGraph.AppId
    ResourceAccess = @(@{
        id = $userReadScope.Id
        type = 'Scope'
    })
}

# Approve the User.Read permission on behalf of all tenant users
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphOAuth2PermissionGrant] $adminConsent =
    New-MgOauth2PermissionGrant -ClientId $servicePrincipal.Id `
                                -ConsentType AllPrincipals `
                                -ResourceId $microsoftGraph.Id `
                                -Scope 'User.Read'

# Assign the application to the current user
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphDirectoryObject] $currentUser =
    Invoke-GraphRequest -Method GET -Uri '/v1.0/me'

[string] $defaultAppAccessRole = [Guid]::Empty
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRoleAssignment] $appAssignment =
   New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $servicePrincipal.Id `
                                           -ResourceId $servicePrincipal.Id `
                                           -AppRoleId $defaultAppAccessRole `
                                           -PrincipalType User `
                                           -PrincipalId $currentUser.Id

# Define custom application roles
[hashtable] $adminRole = @{
    Id = '0125b1e2-4ed5-4994-b95e-e910ef068d69'
    DisplayName = 'Admin'
    Value = 'Admin'
    Description = 'Administrators of the app'
    AllowedMemberTypes = @('User')
    IsEnabled = $true
}

[hashtable] $userRole = @{
    Id = '8930568d-3a48-42a0-8dc0-8bcd56200954'
    DisplayName = 'User'
    Value = 'User'
    Description = 'Standard users of the app'
    AllowedMemberTypes = @('User')
    IsEnabled = $true
}

Update-MgApplication -ApplicationId $registeredApp.Id -AppRoles $adminRole,$userRole

# Assign the custom roles to the current user
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRoleAssignment] $adminAssignment =
   New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $servicePrincipal.Id `
                                           -ResourceId $servicePrincipal.Id `
                                           -AppRoleId $adminRole.Id `
                                           -PrincipalType User `
                                           -PrincipalId $currentUser.Id

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRoleAssignment] $userAssignment =
   New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $servicePrincipal.Id `
                                           -ResourceId $servicePrincipal.Id `
                                           -AppRoleId $userRole.Id `
                                           -PrincipalType User `
                                           -PrincipalId $currentUser.Id

# Configure application object owners
[string] $currentUserOdataId = "https://graph.microsoft.com/v1.0/users/{$($currentUser.Id)}"
New-MgApplicationOwnerByRef -ApplicationId $registeredApp.Id -OdataId $currentUserOdataId
New-MgServicePrincipalOwnerByRef -ServicePrincipalId $servicePrincipal.Id -OdataId $currentUserOdataId

# Configure optional claims
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphOptionalClaims] $optionalClaims = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphOptionalClaims]::DeserializeFromDictionary(@{
   Saml2Token = @(
      @{ Name = 'acct' },
      @{ Name = 'groups' }
   )
})

Update-MgApplication -ApplicationId $registeredApp.Id -OptionalClaims $optionalClaims

# Create a new claims mapping policy
[string] $allClaimsMapping = @'
{
   "ClaimsMappingPolicy": {
       "Version": 1,
       "IncludeBasicClaimSet": "true",
       "ClaimsSchema": [
           {
               "Source": "user",
               "ID": "userprincipalname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
           },
           {
               "Source": "user",
               "ID": "userprincipalname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
           },
           {
               "Source": "user",
               "ID": "userprincipalname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"
           },
           {
               "Source": "user",
               "ID": "mail",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
           },
           {
               "Source": "user",
               "ID": "givenname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
           },
           {
               "Source": "user",
               "ID": "surname",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
           },
           {
               "Source": "user",
               "ID": "streetaddress",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress"
           },
           {
               "Source": "user",
               "ID": "city",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality"
           },
           {
               "Source": "user",
               "ID": "postalcode",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode"
           },
           {
               "Source": "user",
               "ID": "state",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/stateorprovince"
           },
           {
               "Source": "user",
               "ID": "country",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country"
           },
           {
               "Source": "user",
               "ID": "mobilephone",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone"
           },
           {
               "Source": "user",
               "ID": "telephonenumber",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/homephone"
           },
           {
               "Source": "user",
               "ID": "facsimiletelephonenumber",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/otherphone"
           },
           {
               "Source": "user",
               "ID": "employeeid",
               "SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/employeeid"
           },
           {
               "Source": "user",
               "ID": "onpremisesimmutableid",
               "SamlClaimType": "http://schemas.microsoft.com/LiveID/Federation/2008/05/ImmutableID"
           },
           {
               "Source": "application",
               "ID": "objectid",
               "SamlClaimType": "http://schemas.microsoft.com/2012/01/requestcontext/claims/relyingpartytrustid"
           },
           {
               "Source": "user",
               "ID": "assignedroles",
               "SamlClaimType": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
           }
       ],
       "ClaimsTransformation": []
   }
}
'@

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphClaimsMappingPolicy] $allClaimsPolicy =
   New-MgPolicyClaimMappingPolicy -DisplayName 'Issue All Claims' -Definition $allClaimsMapping

# Assign the claims mapping policy to the application
New-MgServicePrincipalClaimMappingPolicyByRef -ServicePrincipalId $servicePrincipal.Id -OdataId "https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies/$($allClaimsPolicy.Id)"

# Open the Claims X-Ray app in a browser
# Note that it might take a minute for the application to become accessible.
Start-Process ('https://myapps.microsoft.com/signin/{0}?tenantId={1}' -f $servicePrincipal.AppId,$servicePrincipal.AppOwnerOrganizationId)