Migrating the home lab from ESXi to Hyper-V

Rich
9 min readMay 13, 2024

TL;DR how we migrated the home lab from the formerly free version of ESXi to Hyper-V.

Welcome to Part XVII of our Back to the Basics Series!

Part I: NTDS.dit vs SAM

Part II: Ownership Matters

Part III: Recovering from a Crash

Part IV: Setting up a Simple Honeypot Account

Part V: Automating DC Deployment

Part VI: Sometimes it’s the dumbest thing

Part VII: Merry Christmas, macros, & Base64

Part VIII: Why old 0 Days make great teaching tools

Part IX: PowerShell & PS1s without PowerShell.exe

Part X: Ownership & so called “effective permissions”

Part XI: Windows Event Forwarding & SACLs

Part XII: Poorly planned honeypots & other Bad Ideas

Part XIII: Setting up a simple honey token

Part XIV: Smartcards and Pass-the-Hash

Part XV: Forwarding logs to Sentinel & basic alerts

Part XVI: Automating VM deployments in Hyper-V

Part XVII: Migrating the lab from ESXi to Hyper-V

Background

As most know, Broadcom bought out VMware and almost immediately killed off the free version of ESXi. We had already been preparing for this as it was expected given Broadcom’s less than stellar reputation. We setup Hyper-V on a second refurbished server and automated provisioning VMs with it here.

We migrated the following from running in VMs in ESXi to Hyper-V in this project:

  • Entra Connect
  • Entra Cloud Sync
  • Windows Event Collector
  • Microsoft Exchange
  • DFSR
  • The FSMO roles

Please note that Microsoft has deprecated the term “FSMO” and now calls them “Operations Masters”. For simplicities sake we will use the term FSMO roles throughout this howto.

Please note that when I say we “spun up a VM in Hyper-V” I mean that we ran our automated process here that

  • Creates a VM running Windows Server with the specified name
  • Configures the VM’s networking configuration as specified
  • Joins the VM to our domain

Migrating Entra Connect & Cloud Sync

This role was formerly known as Azure AD Connect, and it still says that in the setup on Windows. As I’m sure everyone knows Microsoft recently renamed Azure AD to Entra ID.

There is an excellent walkthrough of the process here.

We simply followed that guide and:

  • Spun up a VM in Hyper-V named TestMEIDC
  • Exported the settings from our old TestAADC VM
  • Jotted down the AD account TestAADC is using
  • Installed MS Entra Connect in staging mode on TestMEIDC
  • Put TestAADC in staging mode
  • Made TestMEIDC the primary (no staging mode)
  • Installed the Cloud Sync Agent on TestMEIDC
  • Confirmed everything was syncing in the Azure portal
  • De-provisioned the TestAADC VM

That’s it, this part was all GUI based.

Migrating the Windows Event Collector

We went over initial setup of Windows Event Forwarding here. This is just what we did to migrate the WEC role to a new VM.

The GPO for Windows Event Forwarding was already set and I had created a group in AD named “Collectors” for Member Servers that hold the WEC role. Therefore we just had to spin up a VM named TestWECII and add it to the Collectors group.

Get-WindowsFeature | Where-Object {$_.Name -like "*RSAT*"} | Install-WindowsFeature
Add-ADGroupMember -Identity "Collectors" -Members "TestWECII"

Setup the subscription in Event Viewer on TestWECII, exactly the same way we did it on here. This takes about 15 seconds.

Verify:

$Events = Get-WinEvent -Path "$env:SystemRoot\System32\Winevt\Logs\ForwardedEvents.evtx" | Sort-Object MachineName -Unique

$Events | Select-Object TimeCreated, Id, MachineName

We ran the Azure Arc setup PS1 on TestWECII and confirmed it was G2G on the Azure portal. I am not yet paying for Sentinel full time, so I didn’t setup log forwarding from TestWECII to Azure yet. We used a Sentinel trial to run through how to do that here.

DFSR

We had already spun up BackupDC3 while getting Hyper-V up and running and ironing out our VM provisioning process. Hence we just had to add it to the DFSR that handles the lab’s share drive.

New-Item "C:\Test Share" -ItemType Directory
New-SMBShare -Name "Test Share" -Path "C:\Test Share"
Install-WindowsFeature -Name FS-DFS-Namespace, FS-DFS-Replication -IncludeManagementTools

Get-DfsReplicationGroup -GroupName "test.local\Mishky's Share\Test Share" | Get-DfsReplicatedFolder -FolderName "Test Share" | Add-DfsrMember -ComputerName BackupDC3
Add-DfsrConnection -GroupName "test.local\Mishky's Share\Test Share" -SourceComputerName TestDC -DestinationComputerName BackupDC3
Set-DfsrMembership -GroupName "test.local\Mishky's Share\Test Share" -FolderName "Test Share" -ComputerName BackupDC3 -ContentPath "C:\Test Share"

Confirm:

Get-DfsReplicationGroup -GroupName “test.local\Mishky’s Share\Test Share” | Get-DfsReplicatedFolder -FolderName “Test Share” | Get-DfsrMembership

Once DFSR had synced we changed the I drive mapping to BackupDC3 (It’s in the Default Domain Policy).

We then removed the 2 old DCs from DFSR.

Remove-DfsnFolderTarget -Path "\\test.local\Mishky's Share\Test Share" -TargetPath \\TestDC\Test Share
Remove-DfsnFolderTarget -Path "\\test.local\Mishky's Share\Test Share" -TargetPath \\BackupDC\Test Share
Get-DfsReplicationGroup -GroupName "test.local\Mishky's Share\Test Share" | Get-DfsReplicatedFolder -FolderName "Test Share" | Remove-DfsrMember -ComputerName TestDC, BackupDC

Confirm:

Get-DfsrMember -GroupName “test.local\mishky’s share\test share”

FSMO roles

We went over what the roles are and their explanation here.

Move-ADDirectoryServerOperationMasterRole -Identity BackupDC3 -OperationMasterRole pdcemulator, ridmaster, infrastructuremaster, schemamaster, domainnamingmaster

#Confirm
netdom query fsmo

On Mishka’s other domain that handles one desktop we had to spin up a new DC from scratch. This is actually quite simple.

Add-Computer -DomainName "sky.local"
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools
Install-ADDSDomainController -DomainName "sky.local" -InstallDns:$true

Move-ADDirectoryServerOperationMasterRole -Identity SkyDCII -OperationMasterRole pdcemulator, ridmaster, infrastructuremaster, schemamaster, domainnamingmaster

#Make sure it's using Microsoft for NTP
w32tm.exe /config /syncfromflags:manual /manualpeerlist:131.107.13.100,0x8 /reliable:yes /update
w32tm.exe /config /update

#Confirm
w32tm /query /configuration

Migrating Exchange

This turned out to be the tricky part of the entire project as I don’t know much about Exchange yet. We originally set it up in the lab as part of this project and put it to use here in order to compare & contrast Get-ADPermission, Get-Acl, and dsacls.

We fired up a VM named TestExchangeII and mounted the Exchange ISO to it.

Add-VMDvdDrive -VMName “TestExchangeII” -Path “C:\VM_Stuff_Share\ExchangeServer2019-x64-CU12.ISO”

Grab the three dependencies including .NET 4.8, then run Exchange Setup.

Migrate the mailboxes from the old Exchange VM to the new one.

$UserCredential = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://TestExchangeII.test.local/PowerShell/ -Authentication Kerberos -Credential $UserCredential
Import-PSSession $Session -DisableNameChecking

$DB = (Get-MailboxDatabase | Where-Object {$_.Server -eq "TestExchangeII"}).Name
$Emails = (Get-Mailbox).PrimarySmtpAddress
ForEach($Email in $Emails)
{
New-MoveRequest -Identity $Email -TargetDatabase $DB
}

Errors we hit migrating Exchange

mishky@test.local
Status: Failed
mishky@test.localSkipped item details
Data migrated: 48.76 MB ‎(51,125,505 bytes)‎
Migration rate: 0 B ‎(0 bytes)‎
Error: MigrationMRSPermanentException: Informational: The request has been temporarily postponed because Search is not up to date. The Microsoft Exchange Mailbox Replication service will attempt to continue processing the request after 5/11/2024 7:26:15 AM.
Report: mishky@test.localDownload the report for this user
Last successful sync date: 5/11/2024 10:11:15 AM

This was fixed by setting the service specified on TestExchangeII to automatic startup.

Get-Service | Where-Object {$_.DisplayName -like "*Microsoft Exchange Search Host Controller*"} | Set-Service -StartupType Automatic

Get-Service | Where-Object {$_.DisplayName -like "*Microsoft Exchange Search Host Controller*"} | Start-Service

We got another error while connecting to ECP.

A connection couldn’t be made to the Exchange server named TestExchangeII. Verify that the Microsoft Exchange Service Host service is started.

IT turns out I just had to generate a self signed cert in the ECP on TestExchangeII while TestExchange was still running.

BTW, the URLs to connect are

ECP: https://TestExchangeII/ecp

OWA: https://TestExchangeII/owa

I found it best to use Chrome on a domain joined VM to use these.

TestClientIII, our new domain workstation

Speaking of accessing Exchange from a domain joined VM, we setup a Windows 10 Pro domain client named TestClientIII on Hyper-V.

$VMName = "TestClient" ; New-VM -Name $VMName -Path "C:\Hyper-V_VMs\$VMName" -MemoryStartupBytes 8GB -Generation 2
Connect-VMNetworkAdapter -VMName $VMName -Name "Network Adapter" -SwitchName Testing
$vm = Get-Vm -Name $VMName
New-VHD -Path "C:\Hyper-V_VMs\TestClient\TestClient.vhdx" -SizeBytes 200GB
$vm | Add-VMHardDiskDrive -Path "C:\Hyper-V_VMs\TestClient\TestClient.vhdx"
Add-VMDvdDrive -VMName "TestClient" -Path "C:\VM_Stuff_Share\Windows10 from MS x64.iso"
Start-VM -Name "TestClient"
#On the Win10 VM
Add-Computer -DomainName "test.local"
New-Item -Path C:\Temp -ItemType Directory
Set-MpPreference -ExclusionPath C:\Temp

We then copy/pasted the files from \\TestClient\C$\Temp to \\TestClientIII\C$\Temp. These include:

  • BloodHound / Neo4j / BlueHound
  • John
  • Mimikatz
  • PowerSploit
  • nmap
  • Visual Studio
  • PowerShell 7

DNS & AD Cleanup

Using the old Entra Connect VM as an example, we remove it’s AD account and DNS record via:

Remove-ADComputer -Identity "TestAADC"
Remove-DnsServerResourceRecord -ZoneName "test.local" -ComputerName BackupDC3 -RRType "A" -Name "TestAADC"

Summary

In the future we are going to de-provision the 2 DCs that are left on ESXi, wipe that server, and install Hyper-V Server on it. We will then provision the DCs TestDC & BackupDC in Hyper-V and start learning how to do VM live migrations. There are some other things we need to learn about availability, redundancy, and so on.

Well that’s another project for another howto. This one has gotten plenty long enough already.

I don’t imagine anyone has actually read the entire thing, it’s more for Ctrl+F while looking for how to do a specific task. I went back over notes I had posted regarding topics like migrating FSMO roles while doing this project, so it helps me. If it helps anyone else out there then I’m flattered.

Time will tell whether Broadcom runs VMware completely into the ground. What I am hearing so far does not sound good for the future of VMware in general. Regardless, we started getting ready to jump ship when we saw the iceberg coming. I wish everyone left on board good luck. They’re going to need it.

References

Moving MS Entra Connect to a new server: https://learn.microsoft.com/en-us/answers/questions/1287797/how-to-migrate-azure-ad-connect-to-a-new-server

https://4sysops.com/archives/migrate-microsoft-entra-connect-azure-ad-connect-to-a-new-server/

Cloud Sync: https://answers.microsoft.com/en-us/msoffice/forum/all/migrate-microsoft-entra-cloud-sync-from-one-server/e003b09f-294b-4f86-b681-b20036aabd2b

Broadcom: https://kicksec.io/broadcom-acquires-vmware/

Generate an answer file for any Windows OS: https://www.windowsafg.com/win10x86_x64_uefi.html

Windows Event Forwarding: https://happycamper84.medium.com/windows-event-forwarding-sacls-5f048f70f63c

DFSR: https://happycamper84.medium.com/transferring-windows-server-roles-to-a-new-server-part-i-dfs-a021d9ee1650

Migrate FSMO roles: https://happycamper84.medium.com/transferring-windows-server-roles-to-a-new-server-part-ii-fsmo-d0a84ca85f2

Working with ISOs in Hyper-V: https://www.thomasmaurer.ch/2020/08/add-iso-dvd-drive-to-a-hyper-v-vm-using-powershell/

Migrate Exchange: https://www.techcrafters.com/portal/en/kb/articles/how-to-move-an-existing-exchange-server-to-a-new-computer#Decommissioning_the_old_Exchange_server

Query .NET version installed: https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed

New-VHD: https://learn.microsoft.com/en-us/powershell/module/hyper-v/new-vhd?view=windowsserver2022-ps

Reddit on Broadcom: https://www.reddit.com/r/vmware/comments/1cmgm4x/called_vmware_support_and_engineer_was_crying/

Connect to Exchange Shell Remotely: https://learn.microsoft.com/en-us/powershell/exchange/connect-to-exchange-servers-using-remote-powershell?view=exchange-ps

Move Exchange mailboxes: https://learn.microsoft.com/en-us/exchange/architecture/mailbox-servers/manage-mailbox-moves?view=exchserver-2019

Migrate Exchange servers: https://www.reddit.com/r/exchangeserver/comments/1amigjr/exchange_migration_from_one_server_to_another/

Hosting DCs in Hyper-V: https://redmondmag.com/articles/2018/02/27/hyper-v-chicken-and-egg.aspx

Exchange mailbox move error fix: https://community.spiceworks.com/t/exchange-2016-to-2019-all-mailbox-move-requests-fail/793199

Exchange X-FEServer error: https://www.google.com/search?q=X-FEServer+error&oq=X-FEServer+error&gs_lcrp=EgZjaHJvbWUyCggAEEUYFhgeGDkyCAgBEAAYFhgeMggIAhAAGBYYHjIICAMQABgWGB4yDQgEEAAYhgMYgAQYigUyDQgFEAAYhgMYgAQYigUyDQgGEAAYhgMYgAQYigUyCggHEAAYgAQYogQyCggIEAAYgAQYogTSAQgzMzM4ajBqNKgCALACAQ&sourceid=chrome&ie=UTF-8

Get-ExchangeCertificate: https://support.microsoft.com/en-us/topic/you-can-t-access-owa-or-ecp-after-you-install-exchange-server-2016-cu6-88b3fe67-5f97-a8a2-8ed8-70034ff15761

--

--

Rich

I work various IT jobs & like Windows domain security as a hobby. Most of what’s here is my notes from auditing or the lab.