How to Automate Windows 365 Cloud PC Last Login monitoring!
Automate Windows 365 Cloud PC Last Login monitoring!
(Windows 365, Azure Active Directory, Power Automate, MS Graph)
Contributors:
Juan José Guirola Sr. (Next Generation Endpoint GBB for Americas)
Bobby Chang (Power Platform GBB for Americas)
Enterprises of all sizes are adopting and aligning Windows 365 to solve several business-critical scenarios. Organizations appreciate the simplicity of the solution, rapid deployment, and enhanced end user experience; offering the opportunity to include new solutions to their services catalog!
Part of the simplicity of Windows 365 is that its management plane is Microsoft Intune. Leveraging the Windows 365 admin blade in Intune, administrators can perform the initial configuration of the service and perform on going monitoring of Cloud PCs deployed within the enterprise with several reports being made visible through the “Reports” blade, to include Device management, Endpoint Security, Endpoint Analytics, etc. We have recently introduced a new type of analytical report – Cloud PC utilization report (preview) – which brings visibility to Cloud PCs with low usage. This is a nice addition to the platform, and a much-needed report.
For some organizations, that level of reporting will suffice. But if you are looking for a more custom report that aligns to the specific goals and needs of your organization, then keep reading. This blog will describe how to use the Microsoft Power Platform to automate the reporting of Windows 365 based on your specific criteria and receive notifications via email when the criteria is met.
In our example, we are setting the criteria to report on Cloud PCs that have not been logged on to for 60 days or more. Let’s get started.
Prerequisites
The following items are required to automate the process and deploy in a production environment: (For personal development and sandbox/testing scenario, you can use the Microsoft 365 Developer Plan and Power Apps Developer Plan).
- Windows 365 Enterprise Licenses
- Azure Active Directory (Azure AD) Premium (P1/P2)
- Microsoft Endpoint Manager
- Power Automate per flow plan
- Microsoft Graph (Windows 365 Cloud PC MS Graph API in beta) Working with Windows 365 Cloud PCs using the Microsoft Graph API
Azure App Registration with the following permissions: CloudPC.Read.All. For enterprise production scenarios, we would recommend leveraging the Application Lifecycle Management (ALM) capabilities in Power Platform, in order to safely adopt future changes to your processes. However, this is outside of the scope of this blog post.
Register MS Graph in Azure AD
If you have followed our previous BLOG – How to automate Windows 365 Cloud PC self-service requests – you may have already performed these steps. If so, please proceed to the next section of this BLOG.
Register MS Graph as an Enterprise application in Azure Active Directory.
- Log into the Azure portal with appropriate permissions for making application registrations. Global Administrator privileges will provide the permissions to make application registrations; there are other options by following the custom role details in this documentation Custom role permissions for app registration - Azure AD - Microsoft Entra | Microsoft Docs. In the Azure services portal, click Azure Active Directory > Azure Active Directory.
Figure 1: A screenshot of the Azure Active Directory blade in the Azure services portal.
- Select App registrations in the left navigation menu.
- Click New registration.
- Give the application a name, select Single Tenant for the supported account type, and then click Register.
Figure 2 : A screenshot of the Register an application screen, showing the details that need to be identified for the new application.
- Note your Directory (tenant) ID and Application (client) ID GUIDs and then click on API Permissions.
Figure 3: A screenshot of the recently created application overview with the Application (client) ID and Directory (tenant) ID details highlighted.
- Click API permissions in the left navigation menu.
- Click Add a Permission.
- Select Microsoft.Graph and choose Application permissions. Ensure the following permissions are added:
- CloudPC.Read.All
- User.Read
- User.Read.All
- Group.Read.All
- Mail.Send (optional for sending messages via Graph
|
)
Figure 4: A screenshot of the Select permissions setup.
- Once the permissions have been added, click Grant consent.
- Click Certificates & secrets in the left navigation menu, and then click New client secret.
- Important! Note this secret key and store it somewhere safe, like a key vault. This key will only be visible upon creation. Once you navigate away, you will be unable to expose the key again and will have to generate a new key.
Create the Cloud PC Last Login Monitoring automation!
In this section, we will build the Power Automate flows that will orchestrate the Last Login monitoring reporting process. This decision flow illustrates the end-to-end process of retrieving Cloud PC attribute values from the Microsoft Graph leveraging the Windows 365 API and parse through the LastLoginResult value to compare against our criteria of 60 days or more.
Figure 5: A flowchart depicting the process for reporting Cloud PC Last Login.
To begin, sign into Microsoft Power Automate with your Microsoft 365 organization credentials.
- From the left navigation menu, click + Create then:
- Click Automated cloud flow.
- Name the flow and choose the flow trigger, “Recurrence” from list.
- Click Create.
- Set your desired Interval.
Figure 6: A screenshot that shows the Recurrence trigger.
- Click on + New step (To add variable for the UPN).
- In Choose an operation, type variable.
- Select Initialize variable from Actions.
- Type Init VARUPN details screen.
- Give it a name, e.g., VARUPN and select “String” as Type.
- Click + New step (To add variable for the “lastLoginResult” attribute value of the Cloud PC).
- Choose an operation, type variable.
- Select Initialize variable from Actions.
- Give it a name, e.g. lastLoginResult and select “String” as Type.
- Click on + New step (To add variable for the “Composed_LastLoginResult_Value” of the Cloud PC).
- Search for VAR in Choose an operation.
- Select Initialize variable.
- Give it a name (e.g. Composed_LastLoginResult) and select “String” as Type.
- Click on + New step (To add variable for CurrentDateTime).
- Choose an operation, type variable.
- Select Initialize variable from Actions.
- Give it a name (e.g., DateNow) and select “String” as Type.
- In the Value field, Add, Expression, in Fx type utcNow()
- Click on + New step (To add variable for DateDifference)
- Choose an operation, type variable.
- Select Initialize variable from Actions.
- Give it a name (e.g., DateDiff) and select “Integer” as Type.
- Click on + New step (To add variable for the “Criteria,” which in our example is 60 day +).
- Choose an operation, type variable.
- Select Initialize variable from Actions.
- Give it a name (e.g., More than 60 days) and select “String” as Type.
At this point, we need to determine the automated actions, based on the “LastLoginResult” value of the Cloud PC. This can be accomplished by parsing through each Cloud PC LastLoginRestult value and applying a “Condition” action.
Let’s add a GET step to the flow to gather Cloud PC attribute value:
- Click Add an action.
- Important! To add the control to perform Graph API calls against tenant to gather Cloud PC attribute value, search for HTTP.
- In the Method field, select GET. Under URI, set it up exactly as illustrated below:
https://graph.microsoft.com/beta/deviceManagement/virtualEndpoint/cloudPCs? $select=userprincipalname,id,displayName,managedDeviceName,Status,imageDisplayName,lastModifiedDateTime,lastRemoteActionResult,lastLoginResult
- For Authentication, select Active Directory OAuth.
- Leave the authority as default.
- Enter your Tenant ID under Tenant, https://graph.microsoft.com under Audience, the AppID under Client ID, and the Secret in the Secret section.
- For production scenarios, you should consider storing your secret in a Key Management solution, like Azure Key Vault
- If you are using Azure Key Vault, then you can first add the Get Secret action from the pre-built Azure Key Vault connector (https://learn.microsoft.com/en-us/connectors/keyvault/#actions) then securely pass your Secret into this step of your automation -
Figure 7: Example setup for Graph API controls to gather Cloud PC attribute value.
- Hide your Secret from the Power Automate run history
- Click on the … to the right of the Power Automate HTTP action
- Select Settings
- Turn the toggles to On for “Secure Inputs” and “Secure Outputs” in order to not display your Secret in plain text on the logs or run history
- Click Add an action, and search for “Parse JSON.”
- Under Parse JSON, select Body for the Content field and insert the body of the HTTP request response into the Schema field. Use the following schema:
Figure 8: A screenshot of completed content and schema details for Parse JSON.
{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"userPrincipalName": {
"type": "string"
},
"managedDeviceName": {
"type": "string"
},
"id": {
"type": "string"
},
"displayName": {
"type": "string"
},
"imageDisplayName": {
"type": "string"
},
"status": {
"type": "string"
},
"lastModifiedDateTime": {
"type": "string"
},
"lastRemoteActionResult": {},
"lastLoginResult": {}
},
"required": [
"id",
"userPrincipalName",
"displayName",
"imageDisplayName",
"managedDeviceName",
"status",
"lastModifiedDateTime",
"lastRemoteActionResult",
"lastLoginResult"
]
}
}
}
}
Note: You can also get this schema by using the Graph explorer to request from the same endpoint. Use the Generate from example button to generate the schema.
- Click Add action and search for “Apply to each.”
- In the Output field, select Value from our Parse JSON step. Click Add an action and search for “Compose.”
- In the Compose step, enter rungraph for: {id}
Figure 9: Compose control example.
- Click Add an action and search for “HTTP.”
- Configure the HTTP using the same variables for TenantID, APpID, and Secret, as in the previous HTTP action, but using the following URI:
https://graph.microsoft.com/beta/deviceManagement/virtualEndpoint/cloudPCs/@{items('Apply_to_each_2')?['id']}? $select=userprincipalname,id,displayName,managedDeviceName,Status,imageDisplayName,lastModifiedDateTime,lastLoginResult
Example:
Figure 10: Example setup for retrieving lastLoginResult value for each specific Cloud PC.
- Follow the same steps as previously outlined to hide your Secrets from the run history (Click on … > Select Settings > Turn toggles to On for “Secure Inputs” and “Secure Outputs”)
- Click Add an action, search for “Parse JSON.”
- Select Body for the Content field and insert the following into the Schema field:
{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"userPrincipalName": {
"type": "string"
},
"managedDeviceName": {
"type": "string"
},
"id": {
"type": "string"
},
"displayName": {
"type": "string"
},
"imageDisplayName": {
"type": "string"
},
"status": {
"type": "string"
},
"lastModifiedDateTime": {
"type": "string"
},
"lastRemoteActionResult": {},
"lastLoginResult": {}
},
"required": [
"id",
"userPrincialName",
"displayName",
"imageDisplayName",
"managedDeviceName",
"status",
"lastModifiedDateTime",
"lastRemoteActionResult",
"lastLoginResult"
]
}
}
}
}
Figure 11: A screenshot of the Parse JSON schema.
- Click Add an action and search for “Condition”.
- Select lastLoginResult under Parse JSON for the value.
- Select is not equal to for condition.
- Under Add dynamic content, type null as the expression.
Figure 12: lastLoginResult Condition Expression.
At this point we are ready to add logic to the flow based on meeting the criteria of the condition.
If yes -
- Click Add an action and search for “Set variable”.
- Insert a Name (e.g. lastLoginResult)
- For Value, select lastLoginResult under Parse JSON2 as the Dynamic content
- Click Add an action and search for “Compose”.
- Select Compose as the Data Operation.
- Enter the following expression in Inputs field:
split(variables('lastLoginResult-Value'),'"')
- Click Add an action and search for “Compose”.
- Select Compose as the Data Operation.
- Enter the following expression in Inputs field:
outputs('Compose_3')?[3]
- Click Add an action and search for “Set Variable”.
- Select Set Variable.
- Give it a Name (e.g. Composed_LastLoginResult_Value)
- Click on Add dynamic content to add Value
- Select Outputs under Compose 4 Step.
- Click Add an action and search for “Set Variable”.
- Select Set Variable.
- Give it a Name (e.g. DateDiff)
- Click on Add dynamic content to add Value
- Select Expression and enter the following expression
div(sub(ticks(variables('DateNow')),ticks(variables('Composed_LastLoginResult_Value'))),864000000000)
Now that we’ve been able to extract the proper number of days since lastlogin, let’s send out the email notifications.
- Click Add an action and search for “Condition”.
- Select DateDiff variable as the value.
- Select is greater than as condition.
- Enter 60 as the value (or whatever aligns to your criteria)
- Click Add an action and search for “Send an email”.
- Select Send an email v2.
- Provide a name (e.g. More than 60 Days Email notification)
- Enter the necessary information to the fields as necessary for your environment. See below as an example.
Figure 13: Sample email template.
Once you’re past the Apply to Each scope,
- Click Add an action, and search for “Terminate.”
- Set the Status to Succeeded.
- Return to the initial criteria Conditon to setup the the If no process. Scroll up in the workflow to access this setup.
- Click Add an action and search for “Set variable.”
- Select Set Variable.
- Enter a name (e.g. lastLoginResult-Value)
- Value enter Blank
The entire flow process should look like the image below.
Once you’ve completed adding in steps to your automation flow, you’re ready to test the solution. You can run a manual test or wait till the schedule task kicks off. Finally, you should receive an email like the one below:
Admin Email Notification
NOTE:
WE WILL UPDATE THIS ARTICLE IN THE NEAR FUTURE TO INCLUDE THE ADDITION OF UPDATING A TABLE IN POWER APPS AND A FRONT FACING APPLICATION WHERE ADMINS CAN TAKE ACTION TO RECLAIM WINDOWS 365 LICENSE! STAY TUNED!!!
Continue the conversation by joining us in the Microsoft 365 Tech Community! Whether you have product questions or just want to stay informed with updates on new releases, tools, and blogs, Microsoft 365 Tech Community is your go-to resource to stay connected.