Windows Virtual Desktop Image Management Automated – Part 4 – WVD Clean up unused resources

The current situation, we have created new disks, snapshots, virtual machines, networks, images and session hosts. All the resources has been added to the existing WVD hostpool. Now it is time to cleanup the old resources, to keep everything nice and clean. In this part we will take care of removing components related to the old image version.

This post is a part of the series Windows Virtual Desktop Image Management Automated.

  1. Create WVD image version based on existing config with PowerShell – Part 1
  2. Save WVD image with Sysprep as Image Gallery version – Part 2
  3. Create WVD Sessionhosts based on Shared Image Gallery version – Part 3
  4. WVD housekeeping, removing all unused sessionhosts, disks and images – Part 4
  5. Monitor Image Versions with Azure Monitor – Part 5
  6. Enroll MSIX packages automated – Part 6 – (coming soon)

Table of content

  1. Tags, tags, tags
  2. Get the resources
  3. Cleanup
  4. What if you don’t use tags

Tags, tags, tags

After deploying the entire environment you have created a new disk, a snapshot, Azure virtual machines, network interfaces, an image and session hosts. This a quite a lot of resources and you will need to do a good job keeping all these resources up-to-date. Well, there is a better housekeeping solution.
I work a lot with tags. By tagging resources consequent you can find the relationship between resources by just one single click on a tag.

Let’s say you have the Azure VM resources with the ImageVersion. By clicking the tag you will get every resources which is in relation with that specific ImageVersion.

virtual machine

By clicking the tag you will see the related disks, virtual machines, network interfaces and other resources with this tag value.


Now we know how to get all the related resources based on a tag lets fill the automation part.

Get the resources

In the Azure portal you can click the tag you need and do your job (per tag). Because PowerShell doesn’t know the latest version, we need to find the latest images version used in the WVD hostpool.

WVD Hostpool

By knowing the WVD hostpool every other component can be find due some reverse engineering.

    [parameter(mandatory = $true, ValueFromPipelineByPropertyName)]$hostpoolName,
    [parameter(mandatory = $true, ValueFromPipelineByPropertyName)]$deleteResources

import-module az.desktopvirtualization
import-module az.compute

# Getting the hostpool first
$hostpool = Get-AzWvdHostPool | ? { $_.Name -eq $hostpoolname } 
if ($null -eq $hostpool){
    "Hostpool $hostpoolname not found"
# Creating VM configuration based on existing VM's in specific hostpool, selecting first one
$hostpoolRg = ($hostpool).id.split("/")[4]
Write-Output "Hostpool resourcegroup is $hostpoolRg"
Shared Image Gallery

To get the Shared Image Gallery information we need to know the sessionhost first. Sessionhost (actually an Azure VM) information contains storage information where the image information is stored.

# Get one of the current production VM's for getting the share image gallery info
$sessionHosts = Get-AzWvdSessionHost -ResourceGroupName $hostpoolRg -HostPoolName $
$existingSessionHost = ($sessionHosts.Name.Split("/")[-1]).Split(".")[0]
$productionVm = Get-AzVM -Name $existingSessionHost

The next part will use the Azure VM information to get the Shared Image Gallery information and will search for the oldest version. By sorting on published date and grabbing the first result you will get the oldest version.

# Source:
# Creating image version based on the image created few steps ago
$imageReference = ((get-azvm -Name $productionVm[-1].name -ResourceGroupName $productionVm[-1].ResourceGroupName).storageprofile.ImageReference).id
$galleryImageDefintion = get-AzGalleryImageDefinition -ResourceId $imageReference
$galleryName = $imageReference.Split("/")[-3]
$gallery = Get-AzGallery -Name $galleryName
$versions = Get-AzGalleryImageVersion -ResourceGroupName $gallery.ResourceGroupName -GalleryName $gallery.Name -GalleryImageDefinitionName $galleryImageDefintion.Name
$oldestVersion = $($versions | Sort-Object PublishedDate).name[0]
"Found version $oldestVersion"


Knowing the oldest version we can search for any resource with the ImageVersion Tag where the value has the oldest version in it.
If the parameter $deleteResources is $true the resources will be deleted. Else the WhatIf will be used.

$tag = @{ImageVersion = $oldestVersion}
foreach ($resource in (Get-AzResource -Tag $tag)) {
    if ($deleteResources) {
        Remove-AzResource -ResourceId $resource.ResourceId -Force
        Remove-AzResource -ResourceId $resource.ResourceId -WhatIf

What if you don’t use tags

Every resource related to tag ImageVersion has been deleted. I can imagine you don’t use tags at this moment. Don’t worry, there is a way to remove resources without the use of tags. In the foreach loop the script searches for a specific tag. If you don’t use tags this way searching for them is quite difficult :), so we need to find an another way.
There is a way by searching Azure virtual machines on a specific storage profile. The ImageReference object contains an image version which can be used. By filtering that object you will get virtual machine only. By using the objects in the virtual machine you can find

foreach ($resource in (get-azvm | ? {$_.storageprofile.ImageReference.ExactVersion -eq $oldestVersion})) {
    if ($deleteResources) {
        Remove-AzResource -ResourceId $resource.ResourceId -Force
        Remove-AzResource -ResourceId $resource.ResourceId -WhatIf

Good luck and take care. This script will DELETE resources, i’m not responsible for any accidentally delete.

Leave a Reply

Your email address will not be published. Required fields are marked *