Maintain group membership - owned devices for user from specific group

I had a problem with runbook showing error: Invalid JWT access token

 

I found this https://github.com/microsoftgraph/msgraph-sdk-powershell/issues/3151

And I removed newest Microsoft.Graph.Authentication module, then imported older one: 2.25.0

Now there is no issue to connect to MS Graph from runbook

 

 

 

 

 

The roles are not necessarily needed when using system assigned MIs. This is because the authentication in this case is done by the app itself, no user is involved in the process, so only Application type permissions need to be assigned to the MI, not roles.

In general, when you perform API calls as an app you only need Application type permissions. Very rarely you also need roles. In case you perform the Graph API calls the situation is a bit different, the permissions are formed by the intersection of the Delegated permissions and the user's roles.

 

I will provide you some explanations about what the Mis are and how these work, along with some steps you can follow for assigning permissions to a system assigned MI for performing Graph API calls in a Runbook.

General aspects
You can use managed identities instead of secrets or certificates to request an access token from Azure AD when you authenticate as an application. This is the best approach that you can use because managed identities eliminate the need for developers to manage these credentials. Basically, you don't have to use a secret or a certificate anymore to authenticate to Azure AD and get an access token. You can check this article for more details: https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview


  1. Create your Automation Account and enable the system-assigned MI:

 

You can assign it a System-Assigned Identity via the Identity option under Settings. Switch Status from Off to On and hit Save.

 

After saving, you will get an Object ID. Copy this, as you will need it for the next step.

 

 

A screenshot of a computer screen

Description automatically generated

 

 

 

  1. Grant permissions to the System-assigned Managed Identity. You can use PowerShell, Postman, Graph Explorer or your own app for assigning the permissions to the app:

 

POST https://graph.microsoft.com/v1.0/servicePrincipals/ObjectID from the previous step/appRoleAssignments

Content-Type: application/json {

  "principalId": "ObjectID from the previous step",

  "resourceId": "ResourceID of Graph API *1",

  "appRoleId": "ID of the permission you want to assign *2"

}

 

*1 - can be found like this and in my case it's the one circled with red:

 

A screenshot of a computer

Description automatically generated

 

*2 - can be found here and should be for Application type, not Delegated

 

 

These permissions depend on the API call you want to perform. For example, if you want to use your Runbook to modify user's properties, then you would need to grant to your app some permissions like User.ReadWrite.All. Again, this is just an example, the permissions you will grant to your system assigned MI depend on what Graph API calls you will need to use in the automation.

Each Graph API call has a corresponding article in the documentation and the permissions required for that API call are mentioned in a table like this, at the beginning of the articles:

 

 

Keep in mind that for system assigned MIs you have to use Application type permissions.

PowerShell code:

# Ensures you do not inherit an AzContext in your runbook

Disable-AzContextAutosave -Scope Process

# Connect to Azure with system-assigned managed identity

$AzureContext = (Connect-AzAccount -Identity).context

 

# Get the access token for Microsoft Graph

$GraphToken = Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com/

$Identity = $GraphToken.token

$graphTokenConverted=($Identity | ConvertTo-SecureString -AsPlainText -Force) 

 

Connect-MgGraph -AccessToken $graphTokenConverted -NoWelcome

# Get the access token for Azure AD Graph

$AadToken = Get-AzAccessToken -ResourceUrl "https://graph.windows.net/

 

# Connect to Azure AD using the tokens

Import-Module -Name AzureAD.Standard.Preview

#get-az* cmdlets are working fine without additional connect-azureAD cmdlet below but other cmdlets like: Get-AzureADUserOwnedDevice is ending with "You must call the Connect-AzureAD cmdlet before calling any other cmdlets."

 

Connect-AzureAD -AccountId $AzureContext.Account.Id -TenantId $AzureContext.Tenant.Id -MsAccessToken $GraphToken.Token -AadAccessToken $AadToken.Token

 

#$users = Get-AzADGroup -ObjectId ’xxx’| Get-AzADGroupMember -all $True

$users = Get-AzureADGroup -ObjectId ’xxx’| Get-AzureADGroupMember -all $True

$devices = $users | % {Get-AzureADUserOwnedDevice -ObjectId $_.ObjectId}

$list = $devices | % {Get-AzureADDevice -ObjectId $_.ObjectId} | select DisplayName,AccountEnabled,DeviceOSType,IsManaged,ObjectId,DeviceId,ApproximateLastLogonTimeStamp

#last logon not older than 6 months

$t = get-date

 

#as result DeviceId is returned - NOT ObjectId !!

#$final = $list | % {if (($_.DeviceOSType -eq "Windows") -and ($_.AccountEnabled -eq "True") -and ($_.IsManaged -eq "True") -and ($_.ApproximateLastLogonTimeStamp -lt $t.addMonths(-6))) { $_.DeviceId}}

$final = $list | % {if (($_.DeviceOSType -eq "Windows") -and ($_.AccountEnabled -eq "True") -and ($_.IsManaged -eq "True"))  { $_.DeviceId}}

$final = $final | Select-Object -Unique

 

# Get the device details from Intune as IsManaged from Get-AzureADDevice does not reflect if it is managed by intune

$IsIntuneManaged = $final | % {Get-MgDeviceManagementManagedDevice -Filter "AzureAdDeviceId eq '$_'"} | select AzureAdDeviceId,ManagementAgent,LastSyncDateTime

$IsIntuneManagedTrue = $IsIntuneManaged | % {if ($_.ManagementAgent -eq "mdm") {$_.AzureAdDeviceId} }

 

$finalObjectId = $IsIntuneManagedTrue | % {Get-AzureAdDevice -Filter "deviceId eq guid'($_)'"} | select ObjectId

 

$AAD_PROD_Intune_IIT_Devices = "yyy"

$currentMembers = Get-AzureADGroup -ObjectId "$AAD_PROD_Intune_IIT_Devices" | Get-AzureADGroupMember -all $True

$newMembers = Compare-Object -ReferenceObject $finalObjectId.ObjectId -DifferenceObject $currentMembers.ObjectId -PassThru | Where-Object { $_.SideIndicator -eq "<=" }

Write-Output "SHOWING NEW MEMBERS: `n[$newMembers]"

 

if (($newMembers -ne $null) -and ($newMembers -ne '')) {

    $newMembers | % {Add-AzureADGroupMember -ObjectId "$AAD_PROD_Intune_IIT_Devices" -RefObjectId $_}

}

$sdtoolbox = "zzz"

$toRemove1 = Compare-Object -ReferenceObject $finalObjectId.ObjectId -DifferenceObject $currentMembers.ObjectId -PassThru | Where-Object { $_.SideIndicator -eq "=>" }

#except sdtoolbox service account

$toRemove2 = Compare-Object -ReferenceObject $sdtoolbox -DifferenceObject $toremove1 -PassThru  | Where-Object { $_.SideIndicator -eq "=>" }

Write-Output "SHOWING OBJECTS TO REMOVE: `n"

$toRemove2

 

if (($toRemove2) -ne $null -and ($toRemove2 -ne '')) {

    $toRemove2 | % {Remove-AzureADGroupMember -ObjectId "$AAD_PROD_Intune_IIT_Devices" -MemberId $_}

}

Write-Output "End of code"

Komentarze