This post is part of a series of posts showing how you might move an existing VDI deployment to Azure Virtual Desktop on Azure Stack HCI.
This particular post contains the Powershell script examples used as part of the blog series, with two code samples:
- ControlWrapper.txt – this is the core engine PowerShell that I cut and pasted into a PowerShell window to actually run the migration
- RemoteAVDInstall.PS1 – this script was called by the “ControlWrapper.txt” to install the AVD Agent and Bootloader by executing Invoke-Command -FilePath $ScriptPath -ComputerName $ADComputer.DNSHostName
ControlWrapper.txt
# Remote commands on VMs run by enabling WinRM as detailed here: https://woshub.com/enable-winrm-management-gpo/
# all required files assumed to be in $WorkDIR
#################################################################################
#Make sure you have the necessary PowerShell modules installed and available:
#################################################################################
#Install-Module AZ
#Install-Module -Name Microsoft.RDInfra.RDPowerShell
#Install-Windowsfeature Hyper-V-PowerShell
#Install-Windowsfeature Hyper-V-Tools
################################
# RDS and HCI Settings
################################
$RDSBroker = "RDSInfra.gbbgov.us"
$HCI_VM_Share = "\\fslogix\VMs"
$HCI_VM_path = "C:\ClusterStorage\Volume1\shares\VMs"
$HCI_Node = "HCI.gbbgov.us"
$WorkPath = "\\rdsinfra\installs"
$ScriptPath = $WorkPath + "\RemoteAVDInstall.PS1"
$WorkDIR = $WorkPath + "\*.*"
$BootLoader = "Microsoft.RDInfra.RDAgentBootLoader.Installer-x64.msi"
$AVDAgent = "Microsoft.RDInfra.RDAgent.Installer-x64-1.0.7255.1400.msi"
$AVDHostPool = "migration"
$PoolKeyFile = "HostpoolRegistrationKey.txt"
$RegistryPath = "HKLM:\Software\Microsoft\RDInfraAgent"
$KeyPath = "HKLM:\Software\Microsoft\RDInfraAgent\RegistrationToken"
################################
# Azure Settings
################################
$AZResourceGroup = "WVD"
$AZSubscriptionID = "11111111-1111-1111-1111-111111111111"
$AZLocation = "USGov Virginia"
#added below for working with Azure Gov
#$ISGov = $false
$ISGov = $true
################################
# Grab Start date & time
################################
$StartDate = get-date
##################################################################################
# Log Into Azure to (later) assign user to their previously assigned VMs in AVD
##################################################################################
if ($ISGov) {
Connect-AzAccount -EnvironmentName AzureUSGovernment
} else {
Connect-AzAccount
}
#Select the target subscription for the current session
Select-AzSubscription -SubscriptionId $AZSubscriptionID
##################################################################################
# Generate / Download New Hostpool Registration Key (have host pool already!)
##################################################################################
#$KeyExpirationTime = $((Get-Date).ToUniversalTime().AddDays(20).ToString('yyyy-MM-ddTHH:mm:ss.fffffffZ'))
#New-AzWvdRegistrationInfo -ExpirationTime $KeyExpirationTime -HostPoolName $AVDHostPool -ResourceGroupName $AZResourceGroup -SubscriptionId $AZSubscriptionID
$PoolKey = Get-AzWvdRegistrationInfo -HostPoolName $AVDHostPool -ResourceGroupName $AZResourceGroup -SubscriptionId $AZSubscriptionID
$PoolKeyPath = $WorkPath + "\" + $PoolKeyFile
$PoolKey.token | Out-file -FilePath $PoolKeyPath
##################################################################################
# Collect RDS Deployment information
##################################################################################
$Collection = Get-RDRemoteDesktop -ConnectionBroker $RDSBroker
# get the User / VM mapping
$Details = Get-RDPersonalVirtualDesktopAssignment -CollectionName $Collection.CollectionName -ConnectionBroker $RDSBroker
Write "VMs to be migrated (with assigned users)"
$details
# find the Hyper-V Hosts use for Personal VMs
$Servers = Get-RDServer -Role "RDS-Virtualization" -ConnectionBroker $RDSBroker
#I only have one host... so...
$Server = $Servers[0]
##################################################################################
# Migrate ASSIGNED VMs from RDS Virtualization Host to HCI
##################################################################################
foreach ($Item in $Details)
{
$VM = get-VM -Name $Item.VirtualDesktopName -Computername $Server.Server
#$VM = get-VM -Name "Per-10" -Computername $Server.Server
$VMName = $VM.name
$ADComputer = get-ADComputer $VM.name
write "#######################################"
write "# Processing: $VMname"
write "#######################################"
write "#######################################"
write "#Start VM if it is Saved
write "#######################################"
if($VM.State -eq "Saved")
{
Start-VM -Name $VMName -Computername $Server.Server
Start-Sleep -seconds 30 #let VM wake up
}
write "#######################################"
write "#Stop VM if it is Running
write "#######################################"
if($VM.State -eq "Running")
{
Stop-VM -Name $VMName -Computername $Server.Server -Force
}
write "#######################################"
write "#Export VM from RDS Virt Host to HCI Cluster"
write "#######################################"
Export-VM -Name $VMName -Computername $Server.Server -Path $HCI_VM_Share
$VM_find_location = $HCI_VM_Share + "\" + $VMName + "\*.vmcx"
$File = get-childitem -path $VM_find_location -Recurse
$FileLocation = $HCI_VM_Path + "\" + $VMName + "\" + $File.name
write "#######################################"
write "#Import VM $VMname in HCI Cluster $HCI_Node"
write "#######################################"
Invoke-Command -ComputerName $HCI_Node -ScriptBlock {
Get-ChildItem -Path $Using:FileLocation -Recurse | Import-VM -Register | Get-VM | Add-ClusterVirtualMachineRole
}
write "#######################################"
write "#Start VM $VMName on HCI Cluster $HCI_Node"
write "#######################################"
Start-VM -Name $VMName -Computername $HCI_Node
Start-Sleep -seconds 60 #let VM wake up
write "#######################################"
write "#Copy install files to local VM $VMname"
write "#######################################"
Pause
$DestinationPath = -Join("\\", $ADComputer.DNSHostName, "\C$\Installs")
write "Destination path: $Destinationpath"
If (!(test-path $DestinationPath)) { md $DestinationPath }
Copy-Item $WorkDIR -Destination $DestinationPath
write "#######################################"
write "# Call Local Agent Install Script on $VMname"
write "#######################################"
Invoke-Command -FilePath $ScriptPath -ComputerName $ADComputer.DNSHostName
write "#######################################"
write "# Assign User to AVD VM $VMname"
write "#######################################"
$User = $item.user -split "\\"
#$User = $item[0].user -split "\\"
$ADUser = get-ADuser -Identity $user[1]
###################################################################
Start-Sleep -seconds 60 #Wait for VM to be registered in AVD host pool (may need longer)
###################################################################
Update-AzWvdSessionHost -HostPoolName $AVDHostPool -ResourceGroupName $AZResourceGroup -SubscriptionId $AZSubscriptionID -Name $ADComputer.DNSHostName -AssignedUser $ADUser.UserPrincipalName
write "#######################################"
write "# Remove VM $VMname from RDS deployment"
write "#######################################"
Remove-RDVirtualDesktopFromCollection -CollectionName $Collection.CollectionName -VirtualDesktopName @($VMName) -ConnectionBroker $RDSBroker -Force
}
$EndDate = get-date
$executionminutes = ($EndDate - $Startdate).minutes
write "#######################################"
Write "Start time: $startdate"
Write "Elapsed minutes: $executionminutes"
write "#######################################"
RemoteAVDInstall.PS1
# Remote commands on VMs run by enabling WinRM as detailed here: https://woshub.com/enable-winrm-management-gpo/
# all required files assumed to be in $WorkDIR
$WorkDIR = "C:\installs\"
$PoolKeyFile = "HostpoolRegistrationKey.txt"
#set paths for files
$PoolKeyFile = -join($WorkDIR, $PoolKeyFile)
$RegistryPath = "HKLM:\Software\Microsoft\RDInfraAgent"
$KeyPath = "HKLM:\Software\Microsoft\RDInfraAgent\RegistrationToken"
#Get the Host Poll Registration key from the downloaded file
$Key = Get-Content -Path $PoolKeyFile -Raw
# AVD Agent install process
# https://learn.microsoft.com/en-us/azure/virtual-desktop/troubleshoot-agent#step-4-reinstall-the-agent-and-boot-loader
# Jam Host Pool Key into registry
If (-NOT (Test-Path $RegistryPath)) { New-Item -Path $RegistryPath }
# Install required agents and restart bootloader
Invoke-Command -ScriptBlock {&cmd.exe /c MSIEXEC /I C:\Installs\AVDAgent.msi /qn}
Invoke-Command -ScriptBlock {&cmd.exe /c MSIEXEC /I C:\Installs\Bootloader.msi /qn}
Set-ItemProperty -Path $RegistryPath -Name "RegistrationToken" -Value $Key
restart-service -Name RDAgentBootLoader