How to open/execute multiple sessions from csv file with multiple host entries

We were provided a script to help us migrate our VDI machines from an older Horizon environment to our newer one. This works good although it takes 10-15 minutes per VDI to migrate them, uninstall and install the new agent one by one and our goal would be to migrate at least 50 in a night and with this script that just isn’t feasible. Is there a way to take the source csv with the list of targeted VDIs to move and open a separate thread or window to execute for each host which would migrate the entire list simultaneously?

Below is a sample of the script. I’m guessing I would have to put my auth credentials in the script otherwise it will ask me for each instance but that is something I can work around.

 

Function Get-FileName($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "CSV (*.csv)| *.csv"
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
}

do {
$CSVfile = Get-FileName

#import the CSV and modify the custom object adding tracking fields
write-host "Importing VMs from $CSVfile"
$vMotionVMs = Import-Csv $CSVfile
}
until ($vMotionVMs.Name -notlike '')


Function upgradeAgent($vmname){

$fileName=$global:sourceAgentPath.split('\')[-1]
Write-Host $fileName
$destinationFilePath="$($global:destinationAgentDir)" #$($fileName)
$remoteExeFullPath = "$($global:destinationAgentDir)$($fileName)"
$sourceAgentPath = $global:sourceAgentPath
$desktopUsername = $DTcredential
$desktopPassword = $DTcredential
$agentLocalOptions = $global:agentLocalOptions
$rebootDelay = $global:rebootDelay

Write-Host "VM Name: $vmname"
Write-Host "Source Agent Path: $sourceAgentPath"
Write-Host "Destination Path: $destinationFilePath"
Write-Host "Guest Desktop User:" $DTcredential.username
Write-Host "Guest Desktop Password: ($($DTcredential.password.length) Characters)"

#Connect to Old H7.2 connection server
Write-Host "Connect to Old H7.2 connection server $OldHVCS..." -NoNewLine
Connect-HVServer -server $OldHVCS -Credential $VCcredential | out-null
Write-Host "Done."

do {
#Find desktop pool and user
Write-Host "Searching for $vmname on $OldHVCS..." -NoNewLine
#find user assigned to desktop and store in $OldhvUSer1 object
$Services1=$Global:DefaultHVServers.ExtensionData
$OldhvMachine1 = Get-HVMachine -MachineName $vmname
$OldhvUSer1 = $OldhvMachine1.base.user
$OldhvMachine1 = $OldhvMachine1.base.desktop 
$username = ($services1.AdUserOrGroup.AduserOrGroup_Get($OldhvUSer1)).base.displayname
$NewPoolname = ($Services1.Desktop.Desktop_Get($OldhvMachine1)).base.name
}
until ($NewPoolname -notlike '' -and $username -notlike '')

Write-Host "Done."

#remove Desktop VM from Old Pool
Write-host "Removing $vmname from $NewPoolname for $Username"
Remove-HVMachine -MachineNames $vmname -DeleteFromDisk:$false | out-null

#read-host "wait for removal"

#DisConnect Old H7.2 connection server 
Write-Host "DisConnect from Old H7.2 connection server $OldHVCS..." -NoNewLine
Disconnect-HVServer -Server $OldHVCS -force -Confirm:$false | out-null
Write-Host "Done."

#Making sure VMtools is running...

Write-Host "Making sure VMtools is running..." -NoNewLine

Do{
$status = Get-vm $vmname | %{ $_.guest |%{ $_.extensiondata.toolsrunningstatus } }
} until ($status –eq "guestToolsRunning")

Write-Host "Done."

#Making a snapshot...

#Write-Host "Making snapshot..." -NoNewLine

#New-Snapshot -VM $vmname -Name MigrationScript -Description "pre-agent removal/agent upgrade" -Quiesce | Out-Null

#Write-Host "Done."

#start the windows installer service
Write-Host "Making sure windows installer service is running..." -NoNewLine
Invoke-VMScript -ScriptText "Start-Service msiserver" –VM $vmname -GuestCredential $DTcredential -ScriptType Powershell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | OUT-NULL
Write-Host "Done."
#Write-Host "Waiting for MSIservice to stabilize"

#copy new agent to vm

Write-Host "Transfer New Agent to Guest OS..." -NoNewLine

try {
$NewAgentFile = get-item $sourceAgentPath
$NewAgentFile = $destinationFilePath + "\"+ $NewAgentFile.Name + " /s /v"
get-item $sourceAgentPath | copy-vmguestfile -destination $destinationFilePath -vm $vmname -LocalToGuest -force -GuestCredential $DTcredential
#get-item $sourceAgentPath | copy-vmguestfile -destination $destinationFilePath -vm $vmname -LocalToGuest -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | OUT-NULL
} catch {
Write-Host "Failed."
throw $error
return false;
}

Write-Host "Done."

#find regestry entry uninstall string for View Agent
Write-Host "Locating Registry entry for agent..." -NoNewLine
$script0 = {Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object {$_.DisplayName -match "VMware Horizon Agent" } | Select-Object -Property DisplayName, UninstallString, DisplayVersion | ConvertTo-CSV -NoTypeInformation}
$OldAgentUninstallString = Invoke-VMScript -VM $vmname -ScriptText $script0 -GuestCredential $DTcredential -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | ConvertFrom-CSV
Write-Host "Found Agent version" $OldAgentUninstallString.DisplayVersion

#$ArgumentList = "/c " + $OldAgentUninstallString.UninstallString + " /quiet /norestart"
$ArgumentList = "/c " + $OldAgentUninstallString.UninstallString + " /quiet /FORCErestart"
$script1= "Start-Process cmd -ArgumentList ""$ArgumentList"" -NoNewWindow"
$ArgumentList2 = " /qn VDM_VC_MANAGED_AGENT=1 ADDLOCAL=all"
#$ArgumentList2 = " /qn VDM_VC_MANAGED_AGENT=1 VDM_FLASH_URL_REDIRECTION=1 ADDLOCAL=Core,SVIAgent,ThinPrint,USB,FlashURLRedirection,RTAV"
$script2= $newAgentFile + '"' + $ArgumentList2 + '"'
$script3="shutdown -r -f -t $rebootDelay"

Write-Host "Executing Agent Uninstall..." -NoNewLine
try {
Invoke-VMScript -ScriptText $script1 –VM $vmname -GuestCredential $DTcredential -ScriptType Powershell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | out-null
} 
catch {
Write-Host "Failed."
throw $error[0]
return false;

}

Write-Host "Done."

#Making sure VMtools is stopped for the reboot...
Write-Host "Making sure VMtools stops (reboot)..." -NoNewLine
Do{
$status = Get-vm $vmname | %{ $_.guest |%{ $_.extensiondata.toolsrunningstatus } }
Start-Sleep -Seconds 10

} until ($status –eq "guestToolsNotRunning")

Write-Host "Rebooting."


Write-Host "Making sure VMtools is running again..." -NoNewLine

Do{
$status = Get-vm $vmname | %{ $_.guest |%{ $_.extensiondata.toolsrunningstatus } }
} until ($status –eq "guestToolsRunning")

Write-Host "Done."

#cleanup old agent directories
Write-Host "Cleanup old agent directories..." -NoNewLine
Invoke-VMScript -ScriptText "Remove-Item -path C:\ProgramData\VMware\VDM -recurse" –VM $vmname -GuestCredential $DTcredential -ScriptType powershell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | out-null
Invoke-VMScript -ScriptText "Remove-Item -path C:\ProgramData\VMware\logs -recurse" –VM $vmname -GuestCredential $DTcredential -ScriptType powershell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | out-null
Invoke-VMScript -ScriptText "Remove-Item -path 'C:\ProgramData\VMware\VMware Horizon View\' -recurse" –VM $vmname -GuestCredential $DTcredential -ScriptType powershell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | out-null
Invoke-VMScript -ScriptText "Remove-Item -path 'C:\ProgramData\VMware\VMware Blast\' -recurse" –VM $vmname -GuestCredential $DTcredential -ScriptType powershell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | out-null
Invoke-VMScript -ScriptText "Remove-Item -path 'C:\ProgramData\VMware\VMware Logon Monitor\' -recurse" –VM $vmname -GuestCredential $DTcredential -ScriptType powershell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | out-null
Invoke-VMScript -ScriptText "Remove-Item -path C:\ProgramData\Teradici\ -recurse" –VM $vmname -GuestCredential $DTcredential -ScriptType powershell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | out-null
Write-Host "Done."

#ready for new agent install
#Read-Host "Ready for install?"


#install new agent
#Write-Host $script2
Write-Host "Executing New Agent Install..." -NoNewLine
try {
Invoke-VMScript -ScriptText $script2 –VM $vmname -GuestCredential $DTcredential -ScriptType bat -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | out-null
} 
catch {
Write-Host "Failed."
throw $error[0]
return false;

}

Write-Host "Done."

#Making sure VMtools is stopped for the reboot...
Write-Host "Making sure VMtools stops (reboot)..." -NoNewLine
Do{
$status = Get-vm $vmname | %{ $_.guest |%{ $_.extensiondata.toolsrunningstatus } }
Start-Sleep -Seconds 10

} until ($status –eq "guestToolsNotRunning")

Write-Host "Rebooting."


Write-Host "Making sure VMtools is running again..." -NoNewLine

Do{
$status = Get-vm $vmname | %{ $_.guest |%{ $_.extensiondata.toolsrunningstatus } }
} until ($status –eq "guestToolsRunning")

Write-Host "Done."

#check for new agent version
$OldAgentUninstallString = Invoke-VMScript -VM $vmname -ScriptText $script0 -GuestCredential $DTcredential -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | ConvertFrom-CSV

Write-Host "Finished upgrading Agent to" $OldAgentUninstallString.DisplayVersion "on $vmname."

#Connect to New H7 connection server
Write-Host "Connect to New H7 connection server $NewHVCS..." -NoNewLine
Connect-HVServer -server $NewHVCS -Credential $VCcredential | out-null
Write-Host "Done."

$NewPoolname = "UC3-3_Legacy"
#add desktop to pool
Write-Host "Adding $vmname to $NewPoolname for $Username..." -NoNewLine
Add-HVDesktop -Machines $vmname -PoolName $NewPoolname | out-null
Start-Sleep -Seconds 30
Set-HVMachine -MachineName $vmname -User $Username | out-null

Write-Host "Done."

#DisConnect to New H7 connection server 
Write-Host "DisConnect from New H7 connection server $NewHVCS..." -NoNewLine
Disconnect-HVServer -Server $NewHVCS -force -Confirm:$false | out-null
Write-Host "Done."

}

#Loop through the CSV and populate $vms with the desktop objects

$vms = get-VM -name $vMotionVMs.name

if($vms -is [system.array] -and $vms.Count -gt 0){

Write-Host "$($vms.Count) VMs found with the search string $vmSearchString we will try to upgrade them."
foreach($vmObject in $vms){

upgradeAgent $vmObject.Name

}

}
elseif($vms.Name){

Write-Host "1 VM found with search string $vmSearchString."
upgradeAgent $vms.Name

}
else{

Write-Host "NO VMs FOUND WITH SEARCH STRING $vmSearchString."

}

 

Hmmm … that’s a big chunk of code … and you state that it’s working as designed … but you want it to work differently … usualy that’d be the point where I recommend to search for a trained technician or engineer to do the work for you when you’re not able to do it by yourself.

Some questions come to my mind when I read your request … you want to migrate about 50 VMs per night … what exactly is a night for you? 6pm to 6am? … you migrate 4 to 6 per hour … that would be 48 to 72 VMs per night … I’d say go for it. :wink:

If you still want to migrate some VMs at the same time - assumed your infrastructure can handle this load - what would stop you from splitting your source CSV file into 2 or 3 parts and run 3 Powershell consoles in parallel? :wink: