Windows 365 Cloud PC Self-Service Automated Request Process

Microsoft

How to automate Windows 365 Cloud PC self-service requests

(Windows 365, Azure Active Directory, Microsoft Forms, Power Automate, MS Graph)

 

Contributors:

Juan José Guirola Sr. (Next Generation Endpoint GBB for Americas)

Bobby Chang (Power Platform GBB for Americas)

Azim Manjee (Cloud Endpoint Technical Specialist)

 

Windows 365 simplifies how organizations offer Cloud PCs to their employees. As a cloud-based service from Microsoft, Windows 365 provides a personal, secure streamed experience from any supported device. It comes with all the productivity, security, and collaboration benefits of Microsoft 365. Windows 365 removes the need to manage a complex infrastructure and it integrates with existing cloud-based networking investments such as Azure Active Directory, Microsoft Endpoint Manager, and more.

As the workplace continues to shift toward hybrid work, Windows 365 gives more organizations the ability to issue a cloud-native, persistent Cloud PC that is available 24 hours a day, 7 days a week, all with the ease of assigning a license.

This simplified approach to provisioning Cloud PCs opens up the potential for automation and self-service scenarios. With Windows 365, you can provide your employees with Cloud PCs on demand, and here, we’ll show you how.

Prerequisites

The following items are required to provide automated, self-service Cloud PC request of Windows 365 deployment in a production environment: (For personal development and sandbox/testing scenario, you can use the Microsoft 365 Developer Plan and Power Apps Developer Plan).

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.

Before you begin

Before you set up automation and a self-service Cloud PC request process, identify and assign the target Azure AD group(s) for the Windows 365 Cloud PC license assignment and provisioning policy.

In our scenario, we have three Azure AD Groups (one Azure AD group for each of our three business segments), for both license and provisioning policy assignments. To configure group license assignments, see Assign licenses to users by group membership in Azure Active Directory. For information about how to target the groups for provisioning policies, see Create Windows 365 Cloud PC provisioning policies.

Once you have the group assignment, set up the self-service process starting with Microsoft Forms.

Create the request intake form

Establishing an intake process will not only allow your employees to request the Windows 365 Cloud PC on-demand, but also allow you to build in an approval process and a feedback loop once the license is provisioned and ready for access.

For our scenario, we are using Microsoft Forms as the intake form for requesting a Cloud PC. If your organization needs additional requirements around data validations and user experience in the form, we recommend leveraging Power Apps instead.

To create a form with Microsoft Forms, see the Microsoft Forms help and learning home page or Create a form with Microsoft Forms.

The following are the key components of our example form:

  • Purpose-specific title “Windows 365 Cloud PC Request Form”
  • Four questions to identify the requesting employee’s business segment, the type of Cloud PC they require, their region, and their contact number (aka mobile number)
  • Shared to people in the organization only, for security, tracking, and notification purposes

JJGuirola_0-1665696568426.png

 

Alt text: Example Windows 365 Cloud PC Request Form in Microsoft Forms.

Register MS Graph in Azure AD

Once the request form is complete, register MS Graph as an Enterprise application in Azure Active Directory.

  1. 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.

JJGuirola_1-1665696568430.png

 

Alt text: A screenshot of the Azure Active Directory blade in the Azure services portal.

  1. Select App registrations in the left navigation menu.
  2. Click New registration.

 

  1. Give the application a name, select Single Tenant for the supported account type, and then click Register.

JJGuirola_2-1665696568433.png

 

Alt text: A screenshot of the Register an application screen, showing the details that need to be identified for the new application.

  1.       Note.

 

JJGuirola_0-1665765722520.png

 

 

Alt text: A screenshot of the recently created application overview with the Application (client) ID and Directory (tenant) ID details highlighted.

  1. Click API permissions in the left navigation menu.
    • .
  1. 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
 
  JJGuirola_4-1665696568447.png

 


  • )

Alt text: A screenshot of the Select permissions setup.

  1. Once the permissions have been added, click Grant consent.
  2. Click Certificates & secrets in the left navigation menu, and then click New client secret.
    1. Important! Note this 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 provisioning process automation

In this section, we will build the Power Automate flows that will orchestrate the self-service process. This decision flow illustrates the end-to-end process of adding the requestor to proper AD security group, prompting an approval process, and then notifying requestor of their Cloud PC readiness.

JJGuirola_5-1665696568450.png

 

Alt text: A flowchart depicting the process for the automated provisioning process.

 

To begin, sign into Microsoft Power Automate with your Microsoft 365 organization credentials.

  1. From the left navigation menu, click + Create then:
    1. Click Automated cloud flow.
    2. Name the flow and choose the flow trigger, “When a new response is submitted” (Microsoft Forms) from list.
    3. Click Create.

JJGuirola_6-1665696568452.png

 

Alt text: A screenshot that shows the flow name and trigger selection options.

  1. In When a new response is submitted, select your form from the Form Id drop down, then:
    1. Click + New step.
    2. Search for “forms” in Choose an operation and select Get response details (Microsoft Forms) from Actions.
    3. For Get response details, select your form from the Form Id drop down and then select Response Id as Dynamic content.

JJGuirola_7-1665696568453.png

 

JJGuirola_8-1665696568454.png

 

Alt text: A screenshot of the criteria for the Get response details step.

  1. Click on + New step (To add variable for the Object ID of the targeted group in Azure AD).
    1. In Choose an operation, type variable.
    2. Select Initialize variable from Actions.
    3. Type VARGroup ID details screen.
    4. Give it a name, e.g., VARGroupID and select “String” as Type.
  2. Click + New step (To add variable for the “id” attribute value of the Cloud PC).
    1. Choose an operation, type variable.
    2. Select Initialize variable from Actions.
    3. Give it a name, e.g. VARCloudPCID and select “String” as Type.
  3. Click on + New step (To add variable for the “status” provisioning value of the Cloud PC).
    1. Search for VAR in Choose an operation.
    2. Select Initialize variable.
    3. Give it a name (e.g. VARProvisioningStatus) and select “String” as Type.
  4. Click on + New step (To add variable for your tenant ID).
    1. Choose an operation, type variable.
    2. Select Initialize variable from Actions.
    3. Give it a name (e.g., VARTenantGUID) and select “String” as Type.
      1.       Tenant ID/Tenant GUID is required for authentication against the CloudPC Microsoft.Graph API.
      2.       For information on getting your tenent ID, see How to find your Azure Active Directory tenent ID.For information on getting your tenent ID, see How to find your Azure Active Directory tenant ID.
  • In the Value field, enter your Tenant ID.
  1. Click on + New step (To add variable for your
    1. Choose an operation, type variable.
    2. Select Initialize variable from Actions.
    3. Give it a name (e.g., VARAppID) and select “String” as Type. (This AppID represents the App Registration Client GUID, which is required for authentication against the CloudPC Microsoft.Graph API).
    4. In the Value field, enter your App Registration Client ID.
  2. Click on + New step (To add variable for the “Secret,” which is your .
    1. Choose an operation, type variable.
    2. Select Initialize variable from Actions.
    3. Give it a name (e.g., VARSecretID) and select “String” as Type.
      1.       This is required for authentication against the CloudPC Microsoft.Graph API.
      2.       Refer to Step 6 in the “Register MS Graph in Azure AD” section of this document.
  • In the Value field, enter your Client Secret.

 

At this point, we need to determine the automated actions, based on the “Business Segment” value provided by requestor. This can be accomplished by applying a Switch action.

 

:

  1. Click on + New step.
    1. Search for “Switch” in Choose an operation and select Switch (Control).
    2. Next to On, select What Business Segment are you part of? from Dynamics content.
    3. Add as many “Cases” as needed to meet your specific needs. In our example, we have 3 Cases, which represent the 3 business segments: South Enterprise, LATAM, and Microsoft Federal.
  2. Within each Case, click Add an action
    1. Search for “variable” and select Set variable.
    2. Select VARGroupID from the Name drop down.
    3. Insert the Object ID of the desired targeted group for each “Case.”
      1.       Note: The Object ID can be retrieved by viewing the group properties in Azure AD.

JJGuirola_9-1665696568455.png

 

Alt text: A screenshot of options for setting the Case variables.

  1. Click on + New step (This step will initiate the approval process)
    1. Search for “approval” in Choose an operation and select Start and wait for an approval.
    2. Select Approve/Reject – Everyone must approve from the Approval type drop down.
    3. Enter the email addresses for approvers in the Assigned to field.
    4. Fill in the remaining fields as desired. In our example, we elected to use values gathered from the requestor.

JJGuirola_10-1665696568456.png

 

Alt text: A screenshot of the available settings for the approval process in Start and wait for an approval.

  1. Click on + New step. This step will set up the execution process determined by approval outcome.
  2. Search for “Condition” in Choose an operation and select Condition control.
  3. Select Outcome under Dynamic content as the value.
  4. Choose is equal to and type “Approve” for the value. You will be presented with two sub processes, If yes and If no. Add necessary flows for each.

JJGuirola_11-1665696568457.png

 

Alt text: A screenshot of the If yes and If no sub-process flow setup options.

For the If yes process:

  1. Click Add an action.
    1. Search for “Azure AD” in Choose an operation and select Get User.
    2. Select Responders’ Email for the User Id or Principal Name value.
  2. Click Add an action.
    1. Search for “Azure AD” in Choose an operation and select Add user to group.
    2. Select VARGroupID for Group Id and Id for User Id.
  3. Click Add an action.
    1. Search for “Send email” in Choose an operation and select Send an email (V2) Office 365 Outlook.
    2. Select VARGroupID for Group Id and Id for User Id.
    3. Rename to “Send an approved email.”
    4. Fill in all fields, as desired.

JJGuirola_12-1665696568459.png

 

Alt text: A screenshot of the Send an approval email setup.

  1. [Optional] If you want to added notification, click Add an action.
    1. You can add notification to your flow. In our example we are using Twilio, but you can choose to use other services. Follow your SMS provider’s instructions to properly configure in Power Automate Flow.
  2. Click Add an action.
    1. To pause the flow and allow the provisioning process to kick off in the backend, select Delay and configure the desired time. In our example, we’ve elected to delay the flow for 1 minute. Search for Delay in Choose an operation.
  3. Click Add an action.
    1. Important! To add the control to perform Graph API calls against tenant to monitor requestors Cloud PC provisioning status, search.
    2. In the Method field, select GET. Under URI, set it up exactly as illustrated below, placing the UserPrincipalName dynamic content inside the string:

 

https://graph.microsoft.com/beta/deviceManagement/virtualEndpoint/cloudPCs?$filter=userPrincipalName eq '@{outputs('Get_user')?['body/userPrincipalName']}' and status eq 'Provisioning'&$count=true

 

  1. For Authentication, select Active Directory OAuth.
    1. Leave the authority as default.
    2. Enter your TenantID variable under Tenant, https://graph.microsoft.com under Audience, the AppID under Client ID, and the Secret in the Secret section.

JJGuirola_13-1665696568462.png

 

Alt text: Example setup for Graph API controls to monitor requestor Cloud PC provisioning status.

  1. Click Add an action, and search for “Parse JSON.”
    1.  
 
  JJGuirola_14-1665696568463.png

 


  • Under (note in the UI you will also see Parse User CPCs), select Body for the Content field and insert the body of the HTTP request response into the Schema field. Use the following schema:

Alt text: A screenshot of completed content and schema details for Parse JSON.

 

{

    "type": "object",

    "properties": {

        "@@odata.context": {

            "type": "string"

        },

        "@@odata.count": {

            "type": "integer"

        },

        "value": {

            "type": "array",

            "items": {

                "type": "object",

                "properties": {

                    "id": {

                        "type": "string"

                    },

                    "displayName": {

                        "type": "string"

                    },

                    "imageDisplayName": {},

                    "provisioningPolicyId": {

                        "type": "string"

                    },

                    "provisioningPolicyName": {

                        "type": "string"

                    },

                    "onPremisesConnectionName": {

                        "type": "string"

                    },

                    "servicePlanId": {

                        "type": "string"

                    },

                    "servicePlanName": {

                        "type": "string"

                    },

                    "status": {

                        "type": "string"

                    },

                    "userPrincipalName": {

                        "type": "string"

                    },

                    "lastModifiedDateTime": {

                        "type": "string"

                    },

                    "managedDeviceId": {},

                    "managedDeviceName": {},

                    "aadDeviceId": {},

                    "gracePeriodEndDateTime": {},

                    "servicePlanType": {

                        "type": "string"

                    },

                    "statusDetails": {}

                },

                "required": [

                    "id",

                    "displayName",

                    "imageDisplayName",

                    "provisioningPolicyId",

                    "provisioningPolicyName",

                    "onPremisesConnectionName",

                    "servicePlanId",

                    "servicePlanName",

                    "status",

                    "userPrincipalName",

                    "lastModifiedDateTime",

                    "managedDeviceId",

                    "managedDeviceName",

                    "aadDeviceId",

                    "gracePeriodEndDateTime",

                    "servicePlanType",

                    "statusDetails"

                ]

            }

        }

    }

}

 

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:

 

  1. Click Add action and search for “Apply to each.”
    1. In the Output field, select Value from our Parse JSON step. A Do until step should appear., If it doesn’t, click Add an action and search for “Do until.”
 
  JJGuirola_15-1665696568466.png

 


Alt text: A screenshot of the Do until setup.

  1. In the Do until step, select the ProvisioningStatus variable is equal to string(‘provisioned’).
  1. Click and search for “Set Variable.”
    1. Configure the CPC-ID Variable to the ID of the item from the Parse JSON.  
  2. Click Add an action and search for “HTTP.”
    1. 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/@{variables('CPC-ID')}

Example:

JJGuirola_16-1665696568468.png

 

Alt text: Example setup for monitoring Cloud PC.

 

  1. Click Add an action, search for “Parse JSON.”
    1. Select Body for the Content field and insert the following into the Schema field:

 

   

{

    "type": "object",

    "properties": {

        "@@odata.context": {

            "type": "string"

        },

        "id": {

            "type": "string"

        },

        "displayName": {

            "type": "string"

        },

        "imageDisplayName": {

            "type": "string"

        },

        "provisioningPolicyId": {

            "type": "string"

        },

        "provisioningPolicyName": {

            "type": "string"

        },

        "onPremisesConnectionName": {

            "type": "string"

        },

        "servicePlanId": {

            "type": "string"

        },

        "servicePlanName": {

            "type": "string"

        },

        "status": {

            "type": "string"

        },

        "userPrincipalName": {

            "type": "string"

        },

        "lastModifiedDateTime": {

            "type": "string"

        },

        "managedDeviceId": {

            "type": "string"

        },

        "managedDeviceName": {

            "type": "string"

        },

        "aadDeviceId": {

            "type": "string"

        },

        "gracePeriodEndDateTime": {},

        "servicePlanType": {

            "type": "string"

        },

        "statusDetails": {}

    }

}

 

 

JJGuirola_17-1665696568469.png

 

Alt text: A screenshot of the Parse JSON schema.

 

  1. Click Add an action and search for “Set Variable.”
    1. Select ProvisioningStatus for the Name and configure the provisioning status variable to the status of the item from the Parse JSON.
  2. Click Add an action and search for “Delay.”
    1. Set a delay in an appropriate increment to recheck the status based on your typical Cloud PC provisioning time (e.g., 30 minutes is a normal time increment). In our example, we selected an increment of every 15 seconds. Consider throttling concerns to not overwhelm the API and cause timeouts.

 

Once you’re past the Do Until scope,

  1. Click Add an action and search for “Send an Email.”
    1.  
 
  JJGuirola_18-1665696568472.png

 


  • Create your “successful” provisioning email. In our example, we use several variables and dynamic content to ensure clarity. You can also embed links to the different clients available to the employee for accessing their Cloud PC.

Alt text: An example of a “successful” provisioning email setup.

  1. Click Add an action and search for “Send Text Message.”
    1. Create your “successful” provisioning SMS. In our example, we use several variables and dynamic content for clarity.

JJGuirola_19-1665696568474.png

 

Alt text: An example “successful” provisioning SMS message setup.

 

Once you’re past the Apply to Each scope,

  1. Click Add an action, and search for “Terminate.”
    1. Set the Status to Successful.
  2. Return to the Approval Conditon to setup the rejection or If no process. Scroll up in the workflow to access this setup.
    1. Click Add an action and search for “Send Email.”
    2. Create and carefully word the rejection email.

JJGuirola_20-1665696568475.png

 

Alt text: An example of a rejection email setup.

  1. Click Add an action and search for Terminate.
  2. Set the Status as Cancelled.

 

The entire Power Automate flow should look like the image below.

JJGuirola_21-1665696568477.png

 

Alt text: A Power Automatic flow diagram depicting the process described in this document.

 

Once you’ve completed adding in steps to your automation flow, you’re ready to test the solution. Select Test and execute the steps described in the User experience section of this document.

 

 

User experience

Once the self-service experience is configured, the employee or requestor should be able to generate a request. The following is an example of what the user can expect during their request experience.

  1. The requestor completes the Self-service user request form.

JJGuirola_22-1665696568481.png

 

Alt text: An example of a completed self-service request form filled in by an employee.

 

  1. The flow kicks off based on information entered in the form by the requestor. The approval process begins.

JJGuirola_23-1665696568483.png

 

Alt text: An illustration of the approval process flow.

 

  1. The Approver gets an email and Microsoft Teams notification to approve, reject, or reassign the request.

JJGuirola_24-1665696568486.png

 

Alt text: An example of an approval request.

  1. Once approved or rejected, the flow continues to add the user to the proper Azure AD Group, which in turn will assign the proper Windows 365 license and the correct provisioning policy.

JJGuirola_25-1665696568490.png

 

Alt text: An illustration of the If yes and If no process flows.

  1. If the request is approved, the approval email and SMS text will be sent to the requestor informing them that the request was approved.
  2. If the request is rejected, the rejection email will be sent.

JJGuirola_26-1665696568493.png

 

Alt text: An example of an approval email.

 

JJGuirola_27-1665696568500.png

 

Alt text: An example of an approval text message.

  1. Power Automate will monitor the provisioning status as it changes from “provisioning” to “provisioned.”
  2. Once the Cloud PC status changes to “provisioned,” the requestor will receive an email and SMS text message informing them that their Cloud PC has been provisioned and is ready to access.

JJGuirola_28-1665696568504.png

 

Alt text: An example email message informing the requestor that their Cloud PC has been provisioned.

 

JJGuirola_29-1665696568516.png

 

Alt text: An example text message informing the requestor that their Cloud PC has been provisioned.

 

 

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. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2 Replies
Fantastic workflow! Great job.