AVD Start and Stop VMs (WVD)

Estimated reading time: 5 minutes

AVD Auto Start VM when user connecting

Set permissions for AVD start VMs

Firstly need add permissions AVD (WVD) services for start VM if they stoped.

Go to on portal.azure.com -> Home -> Subscription -> < Subscription name > -> Access control (IAM)

Press +Add -> Add custom role

Role name: WVDStartVMonConnect
and press “Next”

On permissions step press +Add permissions and select the permissions you want to grant for this role. Like mentioned above you need:

  • Microsoft.Compute/virtualMachines/start/action
  • Microsoft.Compute/virtualMachines/read

press Review + create and create
Once the task is completed, you will get the following notification. press Ok button.

Go to again Home -> Subscription -> < Subscription name > -> Access control (IAM)
and press “Add role assigment”

Role: WVDStartVMonConnect
Select: Windows Virtual Desktop and double click for select, press Save button

Now you just need to pick the recently created role, which is WVDStartVMOnConnect in my case, and assign access to Windows Virtual Desktop as a service. Once this is done, the role assignment completed successfully.

Setup settings on AVD Hostpool settings

All you need to do is to log into the Azure Portal using: https://portal.azure.com and navigate to the Azure Virtual Desktop -> Host pools -> select hostpool.

Go to Properties and select “Start VM on connect” to “YES”

Also select correct “Load balancing algorithm”:

Breadth-first load balancing distributes new user sessions across all available session hosts in the host pool.

Depth-first load balancing distributes new user sessions to an available session host with the highest number of connections but has not reached its maximum session limit threshold.

Setup “Max session limit” per VM

press “Save” button.
Configurations done.

AVD Auto Stop VM when no active sessions on VM

Resource group: (create new) WVD-AUTOMATION
Function App name: WVD-AUTOMATION-FUNCTIONS
Runtime stack: PowerShell Core

and press “Next:Hosting”

and press “Next:Monitoring”

press “Review + Create” and “Create”

Go to resource “WVD-AUTOMATION-FUNCTIONS” - > Identity

Switch “Status” to “On”

press “Save” you will get information like “Enable system assigned ....”, press “Yes”

Go to “App file” and select file requirements.psd1
uncomment line ‘Az’ = ‘6.*’ and press “Save”

select host.json file and add

,
"logging": {
"logLevel": {
"default": "Trace"
}
}

for logging details trace mode, press “Save”

go to “Overview” and press “Restart”

Select function.json file for setup time run script (CRON RULE), run script every 3 hours.

{
  "bindings": [
    {
      "name": "Timer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 0 */3 * * *"
    }
  ]
}

Next, go to the Session Host VM Resource Group. It is possible to deploy Session Host to a Resource Group different from the Windows Virtual Desktop Host Pool. Be sure to set RBAC permissions on the VM Resource Group.

Open Access Control (IAM) from the Resource Group.

Click Add a Role Assignment

Set: Role: as Contributor

and select the Managed Identity setup in the previous step “WVD-AUTOMATION-FUNCTIONS”.

Click Save when finished.

Create the Functions Go to the functions “WVD-AUTOMATION-FUNCTIONS” -> Functions -> +Add

select Time trigger and press “Add” button

Click in “Code + Test”
change PowerShell script: and change 2 params:

  • HostPool = “WVDHostpool”;
  • HostPoolRG = “RG-US-WVD-HOSTPOOL-WEST”
# Input bindings are passed in via param block.
# For the Function App
param($Timer)

######## Variables ##########
## Update "HostPool" value with your host pool, and "HostPoolRG" with the value of the host pool resource group.
## See the next step if working with multiple host pools.
$allHostPools = @()
$allHostPools += (@{
        HostPool   = "WVDHostpool";
        HostPoolRG = "RG-US-WVD-HOSTPOOL-WEST"
    })

# If using multiple host pools, Copy the block the code below and pasted it above this line.  Update with the host pool name and resource group.
# Repeat for each additional host pool.
<#
$allHostPools += (@{
        HostPool   = "<HostPoolName>";
        HostPoolRG = "<HostPoolResourceGroup>"
    })
#>

########## Script Execution ##########
$count = 0
while ($count -lt $allHostPools.Count) {
    $pool = $allHostPools[$count].HostPool
    $poolRg = $allHostPools[$count].HostPoolRG
    Write-Output "This is the key (pool) $pool"
    write-output "this is the value (rg) $poolRg"
    # Get the active Session hosts
    try {
        $activeShs = (Get-AzWvdUserSession -ErrorAction Stop -HostPoolName $pool -ResourceGroupName $poolRg).name
    }
    catch {
        $ErrorMessage = $_.Exception.message
        Write-Error ("Error getting a list of user sessions: " + $ErrorMessage)
        Break
    }
    
    $allActive = @()
    foreach ($activeSh in $activeShs) {
        $activeSh = ($activeSh -split { $_ -eq '.' -or $_ -eq '/' })[1]
        if ($activeSh -notin $allActive) {
            $allActive += $activeSh
        }
    }
    # Get the Session Hosts
    # Exclude servers in drain mode and do not allow new connections
    try {
        $runningSessionHosts = (Get-AzWvdSessionHost -ErrorAction Stop -HostPoolName $Pool -ResourceGroupName $PoolRg | Where-Object { $_.AllowNewSession -eq $true } )
    }
    catch {
        $ErrorMessage = $_.Exception.message
        Write-Error ("Error getting a list of running session hosts: " + $ErrorMessage)
        Break
    }
    $availableSessionHosts = ($runningSessionHosts | Where-Object { $_.Status -eq "Available" })
    #Evaluate the list of running session hosts against 
    foreach ($sessionHost in $availableSessionHosts) {
        $sessionHostName = (($sessionHost).name -split { $_ -eq '.' -or $_ -eq '/' })[1]
        if ($sessionHostName -notin $allActive) {
            Write-Host "Server $sessionHostName is not active, shut down"
             try {
                 # Stop the VM
                 Write-Output "Stopping Session Host $sessionHostName"
                 Get-azvm -ErrorAction Stop -Name $sessionHostName | Stop-AzVM -ErrorAction Stop -Force -NoWait
             }
            catch {
                $ErrorMessage = $_.Exception.message
                Write-Error ("Error stopping the VM: " + $ErrorMessage)
                Break
            }
        }
        else {
            write-host "Server $sessionHostName has an active session, won't shut down"
        }
    }
    $count += 1
}

Press Save and Test/Run for testing script

azure, avd, wvd, deploy