Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell

Let us discuss Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell. This article will completely differ from my other articles, where I mostly explain behind-the-scenes logic.

But in this article, I will explain the logic and steps involved in creating a script to accomplish an objective.

Index
Problem Statement
Solution Required – Intune Policy Assignment Classification
Back to Graph API – the worker behind Microsoft clouds
Meeting the pre-requisites
Getting the auth token and connecting to Graph
Checking the assignment for an individual policy
Handling multiple assignments
Getting the Group Name using the groupId as retrieved
Does the Group object have the required parameter to support user/device-based classification?
Then how do we classify if a Group is a User/Device group?
What if the device contains both users and devices as
members?
Additional considerations when working with client App
Visualizing the data tree to help retrieval of data from the returned value of a Graph call
Intune Policy Assignment Classification – The Script
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell – Table.1

Problem Statement

When you check the assignment for a policy (config/compliance/app) from the Intune portal, the group name is shown under deployments.

Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell - Fig.1
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell – Fig.1

The Assignments blade only shows the names of the Groups (and Intents, in the case of Applications) to which the policy is deployed. But it does not tell us the Group Type—whether a User group or Device group—which is sometimes necessary.

Patch My PC
[sibwp_form id=2]

Unless you have a specific naming scheme to distinguish between a Device group and a User group, asserting whether the deployment targets users or devices isn’t easy.

In such a case, you must open the portal in another tab or browser window, navigate to the Groups blade, check for the group Member, and confirm the deployment type.

So is there a way we can achieve this?

Solution Required Intune Policy Assignment Classification

Get the assignment details with distinguished classification – User or Device-based deployment.

Adaptiva

Back to Graph API – the worker behind Microsoft clouds

This is a very legitimate ask and made me search the GitHub repo to check if any function is already available. But I got nothing, so I started working on the script.

Well, it’s pretty obvious that I would resort to Graph API to retrieve the policy assignment and then distinguish the deployment type—user or Device.

For those who are not quite familiar with the Graph API, I will briefly explain the working details for easy understanding.

PS Script Logic

Meeting the pre-requisites

Unless and untill you create all the logic and functions yourself, it’s always good to check if there is already a function/cmdlet available in GitHub or PS repository that you can use in your script and then build upon it to customize the output as you want.

This saves us a lot of time writing code for things that have already been taken care of and can be used by installing and importing the module to the current PS session and calling that function.

The script that we will create will work by implementing the functions from modules already available on GitHub.

The modules in context are MSGraphFunctions and Microsoft.Graph.Intune

Thus you would need to install these above modules in the PS.

Install-Module -Name MSGraphFunctions
Install-Module -Name Microsoft.Graph.Intune

Post-install, you need to import them to the current PS session to use the functions available in the above modules.

Import-Module -Name MSGraphFunctions
Import-Module -Name Microsoft.Graph.Intune

Getting the auth token and connecting to Graph

With the modules installed and imported to the current PS session, we now need to connect to the cloud service.

There are many ways to connect to Microsoft cloud services. However, this script requires two-click functions, as shown below.

Connect-Graph   #Retrieves Auth Token with Delegated User Permissions
Connect-MSGraph #Connects with an authenticated account to use Microsoft Graph cmdlet requests
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell - Fig.2
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell – Fig.2

Once connected, the real work starts…

Graph API calls are based on REST methods, so we have GET, POST, DELETE, PATCH, and PUT operations. I will not explain these as you can get good documentation of REST methods online.

Using the Graph to retrieve policy

The first step is to retrieve the policy we are concerned about.

If we are working on Compliance Policies, we can get all the compliance policies in Graph Explorer with the GET call below.

https://graph.microsoft.com/beta/deviceManagement/deviceCompliancePolicies

Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell - Fig.3
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell – Fig.3

Graph Explorer is a handy browser-based tool to run your Graph calls, but it does not support commands in batch. It is a single-line command executor. We love to use PS to connect to Graph and use its scripting abilities to execute a series of commands constructed with logic to achieve the goal as required.

The above Graph Explorer call returns all the configured compliance policy details in the response. However, this information cannot be stored in a variable and used programmatically later.

So, let’s return to our PS session connected to Graph services. We achieve this by utilizing the function below implemented in the MSGraphFunctions module.

$deviceCompliancePolicies = Get-GraphDeviceCompliancePolicy 

Within the function, it is essentially the same Graph GET call to the URI mentioned above, and all the policy details as returned are stored in the variable.

Checking the assignment for an individual policy

In Graph Explorer, if we need to check a policy’s assignment, we first need to access the particular policy using its GUID and then check its assignment.

This is essentially a GET Graph call to the below URI.

https://graph.microsoft.com/beta/deviceManagement/deviceCompliancePolicies/<policyGUID>/assignments

Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell - Fig.4
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell – Fig.4

In the PS aspect, we have the variable $deviceCompliancePolicies from the last step, which stores all the Compliance policies.

But to get the assignment details, we would need to get to each policy object individually to fetch the policy GUID with which we can get the assignment.

This is achieved using a for each loop. Then, we can get the assignment details of each policy and keep them in a variable, as shown below.

foreach ($policy in $deviceCompliancePolicies) 
{
 $assignments = Get-GraphDeviceCompliancePolicyAssignment -Id $policy.id
} 

Within the function, it is essentially making the same call as we created above in Graph Explorer.

$uri =
"https://graph.microsoft.com/$apiVersion/deviceManagement/deviceCompliancePolicies/$id/assignments"
$query = Invoke-RestMethod -Uri $uri -Headers $authHeader -Method Get -ErrorAction Stop
$query.Value 

Checking the content of the $assignment variable

If you check using Graph Explorer for the response of the GET call, the value as returned is

{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#deviceManagement/deviceCompliancePolicies('<policyGUID>')/assignments",
     "value": [
         {
             "id": "dfc4f58e-8421-40d3-90f1-02e108dc202d_6239fcb0-190e-431f-b618-b1510d71986a",
             "target": {
                 "@odata.type": "#microsoft.graph.groupAssignmentTarget",
                 "groupId": "6239fcb0-190e-431f-b618-b1510d71986a"
             }
         },
         {
             "id": "dfc4f58e-8421-40d3-90f1-02e108dc202d_a837c8b2-2c69-404f-9081-c088730c8abc",
             "target": {
                 "@odata.type": "#microsoft.graph.groupAssignmentTarget",
                 "groupId": "a837c8b2-2c69-404f-9081-c088730c8abc"
             }
         }
     ]
 } 

Notice that it returns the Azure AD Group object’s GUID rather than its name. This is because the backend works on GUIDs rather than human-friendly names.

Also, if a policy has multiple assignments like the above, which is very likely, our script needs to accommodate that.

Handling multiple assignments

For multiple group assignments, there will be more than 1Value returned. Thus based on the count, we can have a logic implied like below

if($assignments.count -gt 1)
{
  foreach ($assignment in $assignments)
      {
        $groupId=$assignment.target.groupid 
      }
}  

Getting the Group Name using the groupId as retrieved

The variable $assignment will store the value for a particular assignment. Referring to Graph Explorer, that will be like

{
"id": "Assignment GUID",
"source": "direct",
"sourceId": "dfc4f58e-8421-40d3-90f1-02e108dc202d",
"target": {
           "@odata.type": "#microsoft.graph.groupAssignmentTarget",
           "groupId": "6239fcb0-190e-431f-b618-b1510d71986a"
          }
}

What we are interested in here is the value of groupId. So we need to extract this from all the other values as stored in $assignment and store it to a new variable like shown below

$groupId=$assignment.target.groupId   

With the groupId available from above, we can get the Group details as required using a GET Graph call to URI https://graph.microsoft.com/beta/Groups/<groupId> and then retrieve the Group Name using the displayName parameter from the value as returned. This is what is implemented in PS as

$groupName= (Get-AADGroup -groupId $g).displayname

The function is essentially performing the below

$uri = "https://graph.microsoft.com/$graphApiVersion/Groups?`$filter=id
eq '$id'"
(Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).Value 

Till this was easy logic, but here we come to a roadblock…

Does the Group object have the required parameter to support user/device-based classification?

A Group object in Azure has the below properties/parameters

Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell - Fig.5
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell – Fig.5

As you can see, a Group has only two classifications based on type – Static or Dynamic. It has no sort based on membership – User or Device

Then how do we classify if a Group is a User/Device group?

To tell if the group is a User group or a Device group, you need to check one step further – the Members of the Group.

From a Graph Explorer perspective, that would be a GET Graph call to URI https://graph.microsoft.com/beta/Groups/<groupId>/members

Device and User member type has unique value identified via the "@odata.type" as returned in the Value

User ->  "@odata.type":"#microsoft.graph.user",
Device ->  "@odata.type":"#microsoft.graph.device",

We can implement a logic to determine the Group Type – whether it is a User or Device group.

In the PS aspect, we are doing that as

$groupType=(Get-AADGroupMember -groupId $groupId).'@odata.type'.split('.')[-1]

What if the device contains both users and devices as members?

Such a situation should not be ideal, and this is especially true when we talk about device management solutions. The user group and Device group should be separate and unique.

Still, if you have such a group to which a policy is deployed, then due to obvious reasons, the script/logic fails.

Still, you can be creative and come up with something like this (You will not find this in the sample script I provided below)

$Members =  (Get-AADGroupMember -groupId $groupId)
foreach ($member in $Members) {
  $groupType = $member.'@odata.type'.split('.')[-1]
     if ($memberType -eq "user")
        {
          #Statement for this is User group
        }
     elseif ($memberType -eq "device")
        {
          #Statement for this is a Device group
        }
     else
        {
          #Statement for this is a mixed group
        }
}

Additional considerations when working with client App

For applications, there are some extra parameters to be considered.

One such is the deployment Intent – Required/Available/Uninstall. The script can also accommodate this by retrieving the intent parameter as returned in the response value to the assignment check Graph call and storing in $assignment a variable.

$intent=$assignment.intent 

For Win32 apps, the App_Install_Context is one such parameter that is of more importance now since, from Windows 10 1903, ESP can track Win32 apps.

If you have read this, you would have already understood the concept

  • A Graph Get a call to URI https://graph.microsoft.com/beta/deviceAppManagement/mobileApps
  • Store the value as returned to a variable. This would return all the apps as configured in the tenant.
  • So the next step would be to have a logic to cycle through each app from all the apps as returned and stored in the variable from above. This would be a foreach loop.
  • Then it is easy to retrieve the application name using the displayName parameter from the returned value.
  • Also, to get the application type, you would be retrieving the "@odata.type"
  • You can check the logic based on the application type to see if it is a Win32 app. Then you can check for the App_Install_Context, which is the below parameter as present in the value returned for a Win32 app.
"installExperience": 
{
         "runAsAccount": "system/user",
         "deviceRestartBehavior": "basedonreturncode/allow/suppress/force"
}

Visualizing the data tree to help retrieval of data from the returned value of a Graph call

This is what I apply when I work with Graph.

Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell - Fig.6
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell – Fig.6

If you can get to traverse the data as returned, you can get the data to work using simple logic.

Intune Policy Assignment Classification – The Script

With all this knowledge, let’s get to the complete script.

The script shared below is a sample script that will get you only the deployment details of Client Apps. However, with the knowledge acquired by reading this post, you could use it to apply to all other Intune policies as well, as per your requirements.

 $details=@()
  
 $clientApps = Get-GraphClientApp
  
 foreach ($clientApp in $clientApps) #Getting each app from all apps as returned above
 {
 $appName = $clientApp.displayName #Getting the App Name from returned value
  
 $clientAppType = $clientApp.'@odata.type'.split('.')[-1]  #Getting the App Type splitting the @odata.type as returned
  
 <#
 This is the logic to check the app intent of a Win32 LOB app
 #>     
  
 if($clientAppType -eq "Win32LobApp") 
         {
         $installcontext= (Get-GraphClientApp -Id $clientApp.id).installExperience.runAsAccount
         } 
 else 
         { 
         $installcontext="Available for Win32 app type only"
         }
             
 $assignments = Get-GraphClientAppAssignment -Id $clientApp.id #Getting the assignment for the particular app
  
 <#
 The if ($assignments) logic is implemented to skip apps with null assignments
 #>
     if ($assignments)
     
     {
 <#
 This logic is implemented for apps with multiple assignments
 #>
   
     if($assignments.count -gt 1) {
        
        foreach ($assignment in $assignments)  #Getting each assignment for all assignments as returned
        { 
       
             $intent=$assignment.intent            #Getting the intent of the assignment - Required/Available/Uninstall
             $groupId=$assignment.target.groupid   #Getting the groupId to which the assignment is made
             $groupName=(Get-AADGroup -groupId $groupId).displayname   #Getting the groupName using the groupId as obtained above
             $groupType=(Get-AADGroupMember -groupId $groupId).'@odata.type'.split('.')[-1]   #Getting the odata type for associated group member
  
       
       #This part is the output section
  
                 $details+=[PSCustomObject]@{
                 App_Name=$appName
                 AppType=$clientAppType
                 App_Intent =$intent
                 Group_Name=$groupName
                 Group_Type=$groupType
                 App_Install_context=$installcontext
        }
        }
        }     
             
    else
        {
         
         $intent=$assignments.intent   
         $group = $assignments.target.groupId
         $groupname= (Get-AADGroup -groupId $group).displayname
         $groupType=(Get-AADGroupMember -groupId $group).'@odata.type'.split('.')[-1]
  
       #This part is the output section
  
                 $details+=[PSCustomObject]@{
                 App_Name=$appName
                 AppType=$clientAppType
                 APP_Intent =$intent
                 Group_Name=$groupName
                 Group_Type=$groupType
                 App_Install_context=$installcontext
        } 
        }
        } 
 }
  
 $details #Complete output is stored to this variable 

Using the Convert-CSV cmdlet, you can export all the data stored in the $details variable, which stores the entire script output.

The output of the script

Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell - Fig.7
Intune Policy Assignment Classification Easy Secrets of using Graph API with PowerShell – Fig.7

I hope this article will be helpful for many who are thinking of starting to use Graph API with PowerShell.

That’s all for today. I will be back with another topic on Intune soon. Until then, read something new every day and learn something new every day.

Resources

We are on WhatsApp. To get the latest step-by-step guides and news updates, Join our Channel. Click here –HTMD WhatsApp.

Author

Joymalya Basu Roy is an experienced professional in the IT services field with almost 5 years of experience working with Microsft Intune. He is currently working as a Senior Consultant – Architect with Atos India. He is an ex-MSFT where he worked as a Premiere Support Engineer for Microsoft Intune. He was also associated with Wipro and TCS in the early stages of his career. He is awarded the Microsoft MVP award for Enterprise Mobility in 2021. You can find all his latest posts on his own blog site MDM Tech Space at https://joymalya.com

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.