Register New Applications With Microsoft Graph PowerShell

In this post, I will show you how to create new applications in Microsoft Entra using Microsoft Graph PowerShell and the Invoke-MgGraphRequest cmdlet. This allows you to create new app registrations without additional reliance on the Microsoft.Graph.Applications module.


To create app registrations in Microsoft Graph PowerShell you will first need to ensure you have the Microsoft.Graph.Authentication module installed. This allows you to use the Connect-MgGraph and Invoke-MgGraphRequest cmdlets.

You will also need access to a Global Administrator account to consent to the required permissions to the Microsoft Graph Command Line Tools application.

Register a new application

Let’s work through registering a new application in Microsoft Entra. We’ll start by registering a basic application and then slowly add features on top of that. Firstly, you must connect to Microsoft Graph PowerShell and consent to the Application.ReadWrite.All permission. 

Connect-MgGraph -Scope Application.ReadWrite.All

Now, we can define some baseline variables, which we can build out further. The below commands will register a new application in your tenant with the name you define in the $Name variable.

$Name = "Application Name"
$Uri = "Beta\Applications"
$body = @{
    DisplayName = "$Name"
    signInAudience = "AzureADMyOrg"
    requiredResourceAccess = @(
    servicePrincipalLockConfiguration = @{
        isEnabled = $true
        allProperties = $true
        credentialsWithUsageSign = $true
        credentialsWithUsageVerify = $true
        identifierUris = $false
        tokenEncryptionKeyId = $true
$payload = $body | ConvertTo-Json -Depth 4
Invoke-MgGraphRequest -Method POST -Uri $Uri -ContentType "application/json" -Body $payload

If you run the above code, the app registration will be created in your tenant and for use with your tenant only. I have also included the servicePrincipalLockConfiguration property in the configuration if you need to modify the signInAudiance and want additional security. Also, notice I have used the Invoke-MgGraphRequest cmdlet instead of New-MgApplication. This is because we will eventually turn our code into a PowerShell function, and I want to remove dependencies on all modules other than the authentication module. You can read more on that command here: How To Use Invoke-MgGraphRequest with PowerShell.

In the following few sections, we will build on top of the above code by configuring further application settings.

Adding a redirect URI

A Redirect URI is the location which a user will be sent after they are successfully authorised to the application. To add a Redirect URI to your application on creation, add the following code to your request body:

publicClient = @{
    redirectUris = @(

This will add a Mobile and desktop applications redirect URI with the location of http://localhost to your application. This would be the desired configuration to create an application which you can connect with via Microsoft Grah PowerShell.

Adding permissions

You can also add permissions to your application at the creation time using the following code block. In this instance, 00000003-0000-0000-c000-000000000000 represents the Microsoft Graph resource, and each hash table within the resourceAccess array represents a specific permission.

requiredResourceAccess = @(
        resourceAppId = "00000003-0000-0000-c000-000000000000"
        resourceAccess = @(
          id ="ebfcd32b-babb-40f4-a14b-42706e83bd28"
          type = "Scope"
          id = "e4aa47b9-9a69-4109-82ed-36ec70d85ff1"
          type = "Scope"

The type can either be of Scope or Role, depending on if you are adding Delegated permissions (Scope) or Application permissions (Role), and each permission has a unique ID.

To view all of the available permissions, the ID and the scope, use the following command:

Find-MgGraphPermission | Select Name, PermissionType, Id | Sort -Property Name

Adding multiple permissions programmatically 

Adding permissions, as we have seen above, can be pretty cumbersome. As you have seen, it requires a lot of code, especially if you need to have a handful of permissions at once or if you need to reuse the script and change up the permission each time. To solve this problem, I have written a few lines of code to generate this property for us.

Firstly, you will need to declare the permissions you need and the permission type:

$Scope = "User.Read.All", "User.ReadWrite.All", "Group.Read.All", "Group.ReadWrite.All"
$context = "Delegated"

I have stored a public list of permission which you will then need to download and store in memory:

#Download permissions list
if ($context -eq "Delegated") {
    $Permissions = Invoke-WebRequest -Method GET -Uri "" | ConvertFrom-Csv
    $Type = "Scope"
} Elseif ($context -eq "Application") {
    $Permissions = Invoke-WebRequest -Method GET -Uri "" | ConvertFrom-Csv
    $Type = "Role"

A permissions collection will then be generated, storing both the Id and Type of each permission:

$resourceAccess = [System.Collections.Generic.List[Object]]::new()
Foreach ($Perm in $Scope){
    $obj = [PSCustomObject][ordered]@{
        "id" = ($Permissions | Where {$_.Name -eq $perm}).id
        "Type" = $Type

The collection is then added to a temporary hashtable, which, in turn, is then added to the requiredResourceAccess property of the request body.

$resource = @{
    resourceAppId = "00000003-0000-0000-c000-000000000000"
    resourceAccess = $resourceAccess
$body.requiredResourceAccess += $resource

Adding a logo

Unfortunately, adding a logo at the time of creation using Invoke-MgGraphRequest is not supported. To get around this, you will need to first store the output of creating the application like so:

$Application = Invoke-MgGraphRequest -Method POST -Uri $Uri `
-ContentType "application/json" -Body $payload -OutputType PSObject

Then, you can use the PUT method while specifying the image’s path and the content type as an image. This will successfully update the logo of you application.

Invoke-MgGraphRequest -Uri "$Uri/$($" -Method PUT `
-InputFilePath "C:\Temp\images.png" -ContentType "image/png"

Alternatively, if you have a file hosted online that you want to download, you can use PowerShell to download and store it locally for a temporary period. Then it can be used to update the application like so:

#Temporary image path
$imgpath = "C:\Temp\Image.png"
#Image to download
$webimage = ""

#Download image
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($webimage, "$imgpath")

#Update image
Invoke-MgGraphRequest -Uri "$Uri/$($" -Method PUT `
-InputFilePath $imgpath -ContentType "image/png"

#Remove temporary image
Remove-Item -path $imgpath

Adding internal notes

Internal notes are a great way to provide detailed information to other admins on an application’s original purpose, scope and usage areas within your environment.  Of course, you shouldn’t store sensitive information within the internal notes section, but instead, store helpful information to help others understand the purpose of your application and its intended use case, that way if the scope of the application drifts from its original intent, it can be addressed or updated.

To add an internal note to your application, add the following code to your request body:

Notes = "This is a new note"

Adding application owners

According to Microsoft’s documentation, the user who created an application in Microsoft Entra automatically becomes the owner of said application. However, this is not true when creating applications with Microsoft Graph PowerShell. Instead, you must manually define the application owner after the application is created.

Use the below example to add an application owner using PowerShell, after storing the created application in the $Application variable like we saw earlier.

#Change the object Id for the user you wish to add as an owner
$owner = @{
    "" = ""

Invoke-MgGraphRequest -Method POST `
-Uri "$($`$ref" `
-ContentType "application/json" -Body $owner | ConvertTo-Json

Daniel Bradley

My name is Daniel Bradley and I work with Microsoft 365 and Azure as an Engineer and Consultant. I enjoy writing technical content for you and engaging with the community. All opinions are my own.

Leave a Reply