Setup an application for automation and scripts

When building automations and scripts and it needs authentication to our tenant the easiest and ugliest way is to elevate to global Admin and just grant to whatever consent that popups up. Of course that’s not the way to do it.
For automation we should start using managed identities. Building in azure automation , function apps its really good and secure.
For scripts and maybe snippets that we run occasionally and even by delegated admins that do not have the permissions on the admin account we can us an app registration.

Register an app in Entra and use either secure key or even better certificates. This post will show you how to easily create the app, use secure key and add permissions needed for the task.

So I have a local admin that need to be able to export devices from Graph to generate a report of non-compliant devices. Lets start with the app.

App registration

Open upp the Entra portal and head down to ‘App registrations’
Click ‘New Registration’

Type in a name and choose ‘Register’. No need to fill in anything else.

Now we have our app! Note the application ID and tenant ID.

Delegate permissions

In our app open up API permissions. Remove the the default permission “”. The click “Add a permission”.

Choose the “Application permissions” since we are not going to rely on a user.
In this case we need to give the rights to read managed devices in Intune. As always minimum required rights should be given so we are only add the “DeviceManagementmanagedDevices.Read.All”. You can search for device etc to easily find what you need.
This is case by case dependant on what you need for using your script.

After clicking “Add Permissions” We also need to do admin consent, otherwise the job will fail.

Create secure key

The last part is to generate a client secret we can use as an authentication. This should be considered as a username and password and thus protected as so. With that client secret and app id it give you the access to whatever permissions that has been granted and consented.

Click “New client secret” and choose a name for it. set the expiration as short as possible. Then click “Add”

Now we have our app. Get the value and stor it somewhere safe. This is the only time you can see it. Going out and in of the tab/portal will hide the key and it cannot be retrieved again. Lost it? Well then you need to create a new one.


An example

of a script that exports the devices with selected information:

#region Variables

$AppID = Read-Host "Enter AppID"
$AppSecret = Read-Host "Enter AppSecret"
$TenantId = Read-Host "Enter TenantId"


#region Functions
function Get-GraphAccessToken {
    try {
        $GraphHost = ""
        $Body = @{client_id = $AppID; client_secret = $AppSecret; grant_type = "client_credentials"; scope = "$GraphHost/.default"; }
        $OAuthReq = Invoke-RestMethod -Method Post -Uri "$TenantId/oauth2/v2.0/token" -Body $Body
        $GraphAccessToken = @{ "Authorization" = "Bearer $($OAuthReq.access_token)" }
        return $GraphAccessToken
    catch {
        Write-Error $_.Exception

function Invoke-GraphCall {
    param (
        [parameter(Mandatory = $false)]
        [ValidateSet('Get', 'Post', 'Delete')]
        [string]$Method = 'Get',

        [parameter(Mandatory = $false)]
        [hashtable]$GraphAccessToken = $script:GraphAccessToken,

        [parameter(Mandatory = $true)]

        [parameter(Mandatory = $false)]
        [string]$ContentType = 'Application/Json',

        [parameter(Mandatory = $false)]
    try {
        $params = @{
            Method      = $Method
            Headers     = $GraphAccessToken
            Uri         = $Uri
            ContentType = $ContentType
        if ($Body) {
            $params.Body = $Body | ConvertTo-Json -Depth 20
        if ($Method -eq "Get") {
            $request = Invoke-RestMethod @params
            $pages = $request.'@odata.nextLink'
            while ($null -ne $pages) {
                $addtional = Invoke-RestMethod -Method Get -Uri $pages -Headers $GraphAccessToken
                if ($pages) {
                    $pages = $addtional."@odata.nextLink"
                $request.value += $addtional.value
            return $request
        else {
            $request = Invoke-RestMethod @params
            return $request
    catch {
        Write-Warning $_.Exception.Message

#region Get GraphAccessToken
$script:GraphAccessToken = Get-GraphAccessToken

#region Get AllIntuneDevices

$AllManagedDevices = (Invoke-GraphCall -Uri "`$select=id,deviceName,userPrincipalName,azureADDeviceId,operatingSystem,joinType,complianceState,enrolledDateTime,lastSyncDateTime").value
Write-Output "AllIntuneDevices = $($"


Leave a Reply

Your email address will not be published. Required fields are marked *