Relocate VM & keep assigned user

I was scrolling reddit the other night and start reading this post.
User was searching after a easy way to change pool for persistent VMs and then re-assign the assigned user to that VM but in a new pool.

As I heavily relay on automation for my work I’m use to write code against VMWare Horizon REST APIs. So let’s take my skills in to action and write some code for the community to share!

I did not have a PowerShell module ready for this so I have made a module with a collection of function that we need for this script to work, I have flagged this module as beta as I have very limited error handling in it. But I’ll work with this module and make it better and also add more functions to it.

First you need to install my module that I have named vOperator, I have published the module at PSGallery but also at GitHub.

You can install it by writing the following in PowerShell

 Install-Module -Name vOperator -AllowPrerelease

So, after you have installed the module we also need to use it so I made a script for it I’ll try to break it down for you below, if you just want to download the script you can find it at GitHub
(Keep in mind that this is something that I have done to show how it’s done and that it works, I have not made any error handling or well not any good one anyway)

First we need to connect to any connection server on a POD to get the auth information. We also need to store it so we can re-use it during the script.

$hvConnect = Connect-hvSrv -hvFQDN $hvFQDN -Cred $Cred -Domain $Domain

Then what we need to do is to collect information about the pool you want to move your VMs from and information about the pool where you want to move your VMs. And of course we also need to collect information about all of the VMs that are in the FromPool

$FromPoolInfo = $hvConnect | Get-hvDesktopPool -FilterValue $FromPoolName
$ToPoolInfo = $hvConnect | Get-hvDesktopPool -FilterValue $ToPoolName
$GetPoolVM = $hvConnect | Get-hvVM -FilterName "desktop_pool_id" -FilterValue $($FromPoolInfo.ReturnValue.Id)

As we don’t need all of the information that we have gathered we can create a new PSCustomObject for it and also export it as a JSON file if you ever need to look back to it or revert it we can just import the JSON file and then revert the changes.
VMWare can be a little tricky if you not use to play with the APIs, it’s not always clear what ID they want. That’s why I collect both VM ID from Horizon and from the vCenter.
For me that running everything on a Mac it’s important to make things universal that’s why I have added that it will only try to resolve the SID to clear text if PowerShell are running on a Windows computer.

# Filter and save all of the data in to our own object
$FilteredVM = foreach ($_vm in $GetPoolVM.ReturnValue) {
    [PSCustomObject]@{
        vm_name                = $_vm.Name
        vm_id                  = $_vm.Id
        vcenter_vm_id          = $_vm.managed_machine_data.vm_moid
        user_ids               = $_vm.user_ids
        username               = if ($PSVersionTable.Platform -like "Win32NT") {
            foreach ($_sid in $_vm.user_ids) {
                $convertSID = New-Object System.Security.Principal.SecurityIdentifier($_sid)
                $Userobj = $convertSID.Translate([System.Security.Principal.NTAccount])
                $Userobj.Value.Split("\") | Select-Object -Last 1
            }
        }
        from_desktop_pool_name = $FromPoolName
        from_desktop_pool_id   = $FromPoolInfo.ReturnValue.Id
        to_desktop_pool_name   = $ToPoolName
        to_desktop_pool_id     = $ToPoolInfo.ReturnValue.Id
    }
}

# Making the path OS universal
$SaveJSONPath = Join-Path -Path $PathToSaveJson -ChildPath "VMs.json"

# Let's write this out and save it in a json file so we can use it later if needed
$FilteredVM | ConvertTo-Json | Out-File -FilePath $SaveJSONPath -Force

Now it’s time to execute everything!

# Removes VM from pool add them to the new pool and then assign users to the VMs
foreach ($_vm in $FilteredVM) {
    # Remove VM from old pool
    $RemoveVM = $hvConnect | Set-hvVMPool -VM $_vm.vm_id -DesktopPool $_vm.from_desktop_pool_id -Action Remove -UseID
    if ($RemoveVM.ReturnCode -eq 0 -and $RemoveVM.ReturnValue.status_code -eq 204) {
        # Add VM to new pool
        $AddVM = $hvConnect | Set-hvVMPool -VM $_vm.vcenter_vm_id -DesktopPool $_vm.to_desktop_pool_id -Action Add -UseID
        if ($AddVM.ReturnCode -eq 0 -and $AddVM.ReturnValue.status_code -eq 204) {
            # Assign user to the VM in the new pool again
            $Assign = $hvConnect | Set-hvVMUserAssignment -VM $_vm.vcenter_vm_id -UserName $($_vm.user_ids | Out-String) -Action assign
            $Assign.ReturnValue
            continue
        }
        else {
            $AddVM.ReturnValue
            continue
        }
    }
    else {
        $RemoveVM.ReturnValue
        continue
    }
}

This was a quick blogpost but I’m hoping you get the point and can work with this. Also I’ll continue to build on the vOperator module and make it production ready with many more functions for Horizon, AppVolume, vSphere and so on. And also include the “scripts” and convert them to full blown functions or classes when that’s needed.

Have a nice day!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.