Windows Virtual Desktop - Stop VM on Command

We have recently announced the preview of a new feature in Windows Virtual Desktop allowing users to start their deallocated personal VM, more info is available in this blog post, and the announcment is here

This allows users to power on the VM at just the time they need it. It also enables IT to reduce costs as much as possible as it is only powered on at the time the end user needs it.

But how do you get the VM into a deallocated state in like manner, i.e. how can a user power off their VM?

We do have an existing autoscaling tool, but that only supports pooled host pools today. We do have an "autoscaling service" under development which will bring support for personal host pools.

There are other options available in Azure, such as each VM's Auto-Shutdown feature in VM section of the portal:

However, this is set per VM, it also will just shut down the VM at the set time regardless of whether a user is still using this VM, or if they logged of at 6 PM meaning a waster hour of cost.

There is also the Start/Stop VM's during off hours marketplace offering, with guidance here.

You could also use a PowerApp to achieve this, I wrote a blog on how to power on and off a personal VM. However now that we have the built-in ability to power on a personal VM we are halfway there and only need to be able to power off a VM, so this might be a bit excessive.

So now that we have the user powering on their VM, we want something that also enables the user to power off their VM, and most importantly - at just the time they need to. 

What if you could ask Alexa to deallocate your VM? 

That's where Alexa and IFTTT, PowerShell and Azure Function Apps come in, in a combined process I'm calling: "Stop VM on Command".

This article will take you through the steps to create a new Azure Function App and integrate it with both IFTTT and Amazon Alexa to deallocate your personal desktop.  However, you could actually use this to take any PowerShell action so you could use this to power off all powered on VM's or power on all deallocated vms in your subscription or just those in a Resource group or a specific region. Essentially this will show that you can run any PowerShell command you want from Alexa, it is not limited to just deallocating a single WVD session host. That is just the use case here.

The process is that we instruct Alexa to shut down our VM. Alexa will call IFTTT which itself will call our Function App, which is configured with a PowerShell script to deallocate our VM. This is secured using a new Managed Identity.

This will result in issuing a voice command to Alexa which will then deallocate the VM as per (sound on):


So, this assumes that you have an Alexa. I am just going to use the Alexa app to show this working.

Azure Function App

So, step 1 is to create a new Azure Function App. As you would expect there are multiple ways to create a Function app, via the portal, PowerShell or directly from VS Code. For simplicity we will do it via the portal.

In the Azure portal click on + Create a resource and in the Marketplace search for Function App:

Click on Create.

Select your resource group and provide a globally unique Function App Name.
In Publish, select Code.
In Runtime stack, select PowerShell Core with a version of 7.0.
Finally select your region.

Click on Next : Hosting >

On the Hosting tab, either create a new Storage account or accept the default new one.
The Operating System will default to Windows
In the Plan type decide which plan you want. Consumption (Serverless) will be the cheapest, but you can use other plans, such as Functions Premium or an App Service plan, where you can also re-use existing ones.

Click on Next : Monitoring >

If you would like to configure Application Insights for this Function App you can do so here:

Click on : Tags > Where you can add your tags as required.

Click on Review + Create and then Create.

So, we now have a new Function App, we now need to a specific function to take the action.

In your new Function App, in the Functions section select Functions,

At the top click on + Add

Development environment should be set to Develop in portal.
We now need to select a template, and it needs to be an HTTP trigger so that IFTTT can call it directly.
Click on HTTP trigger, in the Template details give this Function a name or leave the default and Add at the bottom.

Now we have the trigger we need to add some code to it.

From within the HTTPTrigger1 (or whatever you named yours) in the Developer section click on Code + Test.
Now it is in here that you would add any PowerShell that does anything, that you want actioned when this Function is called. So, you could develop a script that powered off all VM's in a region etc. etc.

To get started and keep it simple we are going to add a single line to power off our own personal session host.

Replace everything down from and including the line:

# Interact with query parameters or the body of the request.

with your PowerShell command. In my case I just want this to shut down my individual VM, hence enter your equivalent of: 

Stop-AzVM -Name personal-1 -ResourceGroupName personal-desktop -Force -NoWait

But this is where you could add your other PowerShell cmds.
For example if you did want to stop all running VM's you would enter something like:

Get-AzVM -Status | Where PowerState -e "VM running" | Stop-AzVM

Click on Save at the top, and you should see Connected in the Logs section at the bottom:


We now need to set up a Managed Identity for this Function App that also has the RBAC permissions required at the correct scope to perform the PowerShell action. This enables the Function App to perform the actions on the Virtual Machine(s). 

Back in the Azure Portal go to your Function App and in Settings go to Identity.
In the System assigned tab in the Status section click On and click Save at the top, and Yes. This will go off and register this Function App as a Managed Identity within Azure Active Directory

You can confirm this has been created by going to Azure Active Directory > Enterprise applications. Then in the Application type drop down select Managed Identities and click on Apply to the right. In the resulting list will be a Managed Identity with the same name as your Function App.

Now we need to provide the Managed Identity with the RBAC permissions to power off this VM. The minimum permission that is required is the Virtual Machine Contributor role.

You can assign this at either the Management group, Subscription, the Resource Group that contains your VM or the VM itself, depending on how much access you want this Managed Identity to have across other VMs. Best practices dictate to provide the least privilege as possible. 

So, select your scope, I am going to assign this to the Resource Group that contains my personal desktop VMs.

You can do this at the resource group itself, or you can add this just by clicking on Azure Role assignments in in the screen from above. 

Click on + Add role assignment (Preview). In the screen to the right, in the Scope drop down select Resource Group, then in the Resource group drop down select the resource group that contains the VM's in question, not the resource group that contains your Function app (unless they are the same). 
Finally, in Role select Virtual Machine Contributor, then click on Save at the bottom.

Now before moving onto integrating with Alexa, lets test the Function App can correctly deallocate the VM.
Back in the Function App, in the Functions section, click on Functions and then click on your HTTP Trigger.
Go to Code + Test.
Click on Test/Run at the top:

Click on Run at the bottom right.
This will now connect to the log-streaming service and then it will action your PowerShell.

You will see some blue text indicating that the Function was called and executed.
Now check your VM is deallocating or is already deallocated.
You can do this easily via PowerShell with: 

Get-AzVM -ResourceGroupNmae <ResourceGroup> -Status

Now to integrate with Alexa.

To enable Alexa to call this Function we need to use If This Then That which is nicely integrated with the Alexa app.
You will need to set up an IFTTT account at:

Once you have your account created click on Create to start creating the IFTTT applet.
You will be given this interface:

Click on Add in If This

Scroll down and select the Amazon Alexa service

You will need to login using your Amazon credentials to link IFTTT and Alexa.

We want the "Say a specific phrase" trigger:

This trigger will listen to you say "Alexa," and the phrase you want, such as "Shutdown my desktop"

In the next screen enter your phrase you would like to say for this trigger.
Text must all be in lowercase, and it seems some words are confusing for Alexa such as "VM" and "session" at least in my testing. But Alexa will let you know if it does not understand what you have asked.

Click on Create Trigger

So now we have added our phrase we now need IFTTT to take the "That" action, which is call our Azure Function.

Click on the Add in the Than That box


We are looking for webhooks which is at the bottom so enter it in the search field:

Click on Webhooks.

Then click on the Make a web request box:

So now we need our Azure Function URL.

Go back to the Azure portal, go to the Function App, go to your HTTP Trigger, and on the Overview or Code + Test tabs is an icon called Get Function Url:

Click on this and it will display the Function URL, click on the Copy button, then go back to IFTTT.
Paste in the URL.
Leave Method as Get.
Change Content Type to application/json.
Click on Create action at the bottom.

Click on Continue, then review the details and click on Finish.

So now we have IFTTT configured to call our Function App which stops the VM.
So the final step is to configure Alexa to call this IFTTT applet. I am showing this on the Alexa iOS app so screens may differ.

In the Alexa app press More, and then Routines

Press the + to create a new routine.
Give the routine a name.
In the When this happens section click on + and select Voice, and then enter the exact text you want Alexa to listen out for:

In the Add Action section click on the +, scroll down to IFTTT, this will then show you the available IFTTT applets you have created. Select your shut down my desktop applet that you created in the earlier step. Click on Next.

You should now have this:

Click on Save at the top right. You may need to wait for approx. one minute for this to update.

Now to test Alexa.

You can either click on the Play icon to the right on your, but that won't test Alexa actioning this based upon your voice command.

So, go back to Home in the app and press Tap to talk to Alexa

And say your voice command such as "Alexa, trigger shutdown my desktop."

This will now action the whole chain and your VM will now be deallocated.

You can check the activity logs of this applet by click on in the View activity button in IFTTT.


Popular posts from this blog

Reassign a WVD Personal Session Host

AVD and Azure Active Directory Domain Join public preview

How to deploy a Windows Virtual Desktop host pool using Infrastructure as code from Azure DevOps