So last year Guy Leech asked if if I had a script to identify machines running on an old snapshot. I Created a script for that here. This week Madan Kumar asked for a script that finds these same VDI desktops but that also cleans them out if needed. For this I have created the Horizon_cleanup_old_images.ps1 script (yes I suck at making up names).
If you run a get-help for the script you’ll see this:
By default the script only requires a Connectionserverfqdn and poolname as it works on a per pool level. It will try to give the users a gracefully logoff and has options to force the logoff ( in case their sessions is locked) or to delete the machine. And if you just want to have a preview there’s an option for that as well.
Optional arguments are:
-credential: this can be created with get-credential or can be retrieved from a stored credentials xml file, just make sure that it looks like domain\username and password
-deletedesktops: if used it will forcefully try to logoff the users but always deletes the desktop
-forcedlogoff: A normal logoff doesn’t work when the sessions is locked so you might need to force it
-preview: no actions are taken, just the information will be displayed to screen.
Let’s use the script
d:\git\scripts\Horizon_cleanup_old_image.ps1 -Credential $creds -ConnectionServerFQDN pod2cbr1.loft.lab -poolname "Pod02-Pool02" -preview
Yes I use write-host but it’s all 1 liners so shouldn’t be too slow and I like colors but as you see with the preview mode it shows what would happen. One of these sessions is locked so let’s see what happens when I log them off.
yes an error but I think it’s clear why, the graceful logoff worked for 2 users but not the third one, I will add the forced option now.
That looks good and when I look at the desktop pool everything is fine there as well.
And that’s being confirmed by the script
Now I will use the delete option for my other desktop pool.
First again with the preview option
and without
and seen from the Horizon Admin
As linked above the script can be found on github but also below this line.
<# .SYNOPSIS Cleans up desktops running on an image that's not the default for a desktop pool .DESCRIPTION This script uses the Horizon soap api's to pull data about machines inside a desktop pool that are running on a snapshot or base vm that's not currently configiured on the desktop pool. By default it logs off the users but there are options to forcefully logoff the user or delete the machines. .EXAMPLE .\Horizon_cleanup_old_image.ps1 -Credential $creds -ConnectionServerFQDN pod2cbr1.loft.lab -poolname "Pod02 Pool02" -delete -preview .PARAMETER Credential Mandatory: Yes Type: PSCredential Object with credentials for the connection server with domain\username and password .PARAMETER ConnectionServerFQDN Mandatory: No Default: String FQDN of the connection server to connect to .PARAMETER Poolname Mandatory: Yes Type: string Display name of the Desktop Pool to check .PARAMETER Deletedesktops Mandatory: No Enables the deleteion of the desktops, this includes an attempt to forcefully logoff the users. .PARAMETER Forcedlogoff Mandatory: No Enables the forcefully logging off of the users. .PARAMETER Preview Mandatory: No Makes the script run in preview mode and not undertake any actions. .NOTES Created by: Wouter Kursten First version: 27-06-2021 .COMPONENT VMWare PowerCLI #> [CmdletBinding()] param ( [Parameter(Mandatory=$false, HelpMessage='Credential object as domain\username with password' )] [PSCredential] $Credential, [Parameter(Mandatory=$true, HelpMessage='FQDN of the connectionserver' )] [ValidateNotNullOrEmpty()] [string] $ConnectionServerFQDN, [parameter(Mandatory = $true, HelpMessage = "Display Name of the desktop pool to logoff the users.")] [string]$poolname = $false, [Parameter(Mandatory=$false, HelpMessage='Deletes the desktops instead of forcing the logoff' )] [switch] $deletedesktops, [Parameter(Mandatory=$false, HelpMessage='Gives a preview only, no action will be undertaken.' )] [switch] $preview, [Parameter(Mandatory=$false, HelpMessage='Forcefully logs off the users in case the desktop is locked or disconnected.' )] [switch] $forcedlogoff ) if($Credential){ $creds = $credential } else{ $creds = get-credential } $ErrorActionPreference = 'Stop' # Preview info if($preview){ write-host "Running in preview mode no actions will be taken" -foregroundcolor Magenta } # Loading powercli modules Import-Module VMware.VimAutomation.HorizonView Import-Module VMware.VimAutomation.Core $hvserver1=connect-hvserver $ConnectionServerFQDN -credential $creds $Services1= $hvServer1.ExtensionData # --- Get Services for interacting with the Horizon API Service --- $Services1= $hvServer1.ExtensionData # --- Get Desktop pool $poolqueryservice=new-object vmware.hv.queryserviceservice $pooldefn = New-Object VMware.Hv.QueryDefinition $pooldefn.queryentitytype='DesktopSummaryView' $pooldefn.Filter= New-Object VMware.Hv.QueryFilterEquals -property @{'MemberName'='desktopSummaryData.displayName'; 'value'=$poolname} try{ $poolqueryResults = $poolqueryService.QueryService_Create($Services1, $pooldefn) $poolqueryservice.QueryService_DeleteAll($services1) $results = $poolqueryResults.results } catch{ write-error "There was an error retreiving details for $poolname" } # we need more details of the pool though and check if we even got one if($results.count -eq 1){ $pool = $Services1.Desktop.Desktop_Get($results.id) } else{ write-host "No pool found with name $poolname" -foregroundcolor Red break } # Search for machine details $queryservice=new-object vmware.hv.queryserviceservice $defn = New-Object VMware.Hv.QueryDefinition $defn.queryentitytype='MachineDetailsView' $defn.filter = New-Object VMware.Hv.QueryFilterEquals -Property @{ 'memberName' = 'desktopData.id'; 'value' = $pool.id } [array]$queryResults = $queryService.QueryService_Create($Services1, $defn) $services1.QueryService.QueryService_DeleteAll() # Process the results if ($queryResults.results.count -ge 1){ [array]$poolmachines=$queryResults.results [array]$wrongsnaps=$poolmachines | where-object {$_.managedmachinedetailsdata.baseimagesnapshotpath -notlike $pool.automateddesktopdata.VirtualCenternamesdata.snapshotpath -OR $_.managedmachinedetailsdata.baseimagepath -notlike $pool.automateddesktopdata.VirtualCenternamesdata.parentvmpath} # If there are desktops on a wrong snapsot we need to do something with that info if($wrongsnaps.count -ge 1){ if($deletedesktops){ write-host "Removing:" $wrongsnaps.data.name -foregroundcolor yellow $deletespec = new-object vmware.hv.machinedeletespec $deletespec.DeleteFromDisk = $true $deletespec.ForceLogoffSession = $true if(!$preview){ $Services1.Machine.Machine_DeleteMachines($wrongsnaps.id, $deletespec) } } else{ write-host "Logging users off from:" $wrongsnaps.data.name -foregroundcolor yellow [array]$sessiondata = $wrongsnaps.sessiondata write-host "Users being logged off are:" $sessiondata.username -foregroundcolor yellow if(!$preview){ if($forcedlogoff){ write-host "Forcefully logging off users" -foregroundcolor yellow $services1.session.Session_LogoffSessionsForced($sessiondata.id) } else{ write-host "Gracefully logging off users" -foregroundcolor yellow $services1.session.Session_LogoffSessions($sessiondata.id) } } } } else{ write-host "No machines found on a wrong snapshot" -foregroundcolor Green } } else{ write-host "No machines found in $poolname" -foregroundcolor red }
Pingback: Script to cleanup desktops running on old snapshot