This document outlines the implementation roadmap for advanced Windows migration features in hyper2kvm. Based on comprehensive analysis of the current codebase, this plan extends existing production-ready Windows capabilities with enterprise-focused enhancements.
Current State: hyper2kvm v0.2.0 has excellent Windows migration fundamentals:
Proposed Enhancement: Add enterprise Windows features for license management, Active Directory integration, application compatibility, and performance optimization.
Files: hyper2kvm/fixers/windows/virtio/
Status: Fully implemented (2,500+ lines)
Capabilities:
Configuration:
windows:
virtio:
drivers:
- name: viostor
type: storage
start: BOOT # 0 = boot-critical
pci_ids: ["1af4:1001", "1af4:1042"]
- name: netkvm
type: network
start: AUTO # 2 = auto-start
Files: hyper2kvm/fixers/windows/registry/
Status: Fully implemented (1,800+ lines)
Capabilities:
Files: hyper2kvm/fixers/windows/registry/firstboot.py
Status: Fully implemented (200+ lines)
Capabilities:
C:\hyper2kvm\firstboot.done)C:\Windows\Temp\hyper2kvm-firstboot.logFiles: hyper2kvm/fixers/windows/network_fixer.py
Status: Fully implemented (600+ lines)
Capabilities:
Business Value: High - Prevents activation issues post-migration Implementation Complexity: Medium Estimated Effort: 3-5 days
Requirements:
Implementation Approach:
def extract_license_info(guestfs, root): “"”Extract Windows license/activation state from offline registry.”””
# Read from SOFTWARE hive
software_path = detect_windows_hive(guestfs, root, "SOFTWARE")
keys_to_read = [
# Digital Product Key (Windows 8+)
r"Microsoft\Windows NT\CurrentVersion\DigitalProductId",
r"Microsoft\Windows NT\CurrentVersion\DigitalProductId4",
# Product key location (older Windows)
r"Microsoft\Windows NT\CurrentVersion\ProductId",
# License type
r"Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform\Activation",
# KMS information
r"Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform\KeyManagementServiceName",
r"Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform\KeyManagementServicePort",
]
license_data = {}
hive = download_and_open_hive(guestfs, software_path)
for key_path in keys_to_read:
try:
value = read_registry_value(hive, key_path)
license_data[key_path] = value
except KeyError:
continue
return {
"product_key": decode_product_key(license_data),
"license_type": detect_license_type(license_data),
"kms_server": license_data.get("KeyManagementServiceName"),
"kms_port": license_data.get("KeyManagementServicePort"),
"activation_state": determine_activation_state(license_data),
} ```
def decode_product_key(license_data):
"""Decode encrypted Windows product key from registry binary."""
# Extract DigitalProductId4 (Windows 8+) or DigitalProductId (Windows 7)
dpid = license_data.get("DigitalProductId4") or license_data.get("DigitalProductId")
if not dpid:
return None
# Windows 8+ uses 3-byte encoded key starting at offset 808
# Algorithm: Microsoft's base-24 encoding with "BCDFGHJKMPQRTVWXY2346789"
key_offset = 808 if "DigitalProductId4" in license_data else 52
key_bytes = dpid[key_offset:key_offset + 15]
key_chars = "BCDFGHJKMPQRTVWXY2346789"
# Decode using Microsoft's algorithm (simplified)
decoded = decode_base24(key_bytes, key_chars)
# Format as XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
return format_product_key(decoded)
$LogFile = “C:\hyper2kvm\license-reactivation.log”
function Write-Log { param($Message) $Timestamp = Get-Date -Format “yyyy-MM-dd HH:mm:ss” “$Timestamp - $Message” | Out-File -Append -FilePath $LogFile }
Write-Log “=== Windows License Reactivation Started ===”
$LicenseInfo = Get-Content “C:\hyper2kvm\license\license-info.json” | ConvertFrom-Json
switch ($LicenseInfo.Type) { “MAK” { Write-Log “Detected MAK license - installing key” slmgr.vbs /ipk $LicenseInfo.ProductKey slmgr.vbs /ato } “KMS” { Write-Log “Detected KMS license - configuring KMS server” slmgr.vbs /skms “$($LicenseInfo.KMSServer):$($LicenseInfo.KMSPort)” slmgr.vbs /ato } “OEM” { Write-Log “Detected OEM license - activation may require manual intervention” # OEM licenses are hardware-locked, may need phone activation } “Retail” { Write-Log “Detected Retail license - installing key” slmgr.vbs /ipk $LicenseInfo.ProductKey slmgr.vbs /ato } }
$ActivationStatus = slmgr.vbs /dli Write-Log “Activation result: $ActivationStatus”
Write-Log “=== License Reactivation Complete ===”
**Integration Point**:
```python
# In hyper2kvm/fixers/windows/fixer.py
def fix_windows(self, guestfs, root):
# ... existing driver injection ...
# NEW: License preservation
if self.config.windows.preserve_license:
from .license import extractor, reactivator
license_info = extractor.extract_license_info(guestfs, root)
# Stage license metadata for first-boot
reactivator.stage_reactivation_script(
guestfs,
root,
license_info
)
# Add reactivation to first-boot service
self.firstboot.add_command(
r"powershell.exe -ExecutionPolicy Bypass -File C:\hyper2kvm\license\reactivate-license.ps1"
)
Configuration:
windows:
license:
preserve: true
reactivate: true
# Optional: Override detected license type
force_type: KMS # KMS, MAK, Retail, OEM
kms_server: kms.example.com
kms_port: 1688
Testing Requirements:
Risks & Mitigations:
Business Value: Medium - Critical for enterprise environments Implementation Complexity: Low Estimated Effort: 1-2 days
Requirements:
Implementation:
def update_kms_configuration(guestfs, root, kms_server, kms_port=1688):
"""Update KMS server configuration in SOFTWARE hive."""
software_hive = detect_windows_hive(guestfs, root, "SOFTWARE")
hive = download_and_open_hive(guestfs, software_hive)
base_path = r"Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform"
set_registry_value(
hive,
f"{base_path}\\KeyManagementServiceName",
kms_server,
"REG_SZ"
)
set_registry_value(
hive,
f"{base_path}\\KeyManagementServicePort",
str(kms_port),
"REG_SZ"
)
upload_and_verify_hive(guestfs, software_hive, hive)
Business Value: Very High - Critical for enterprise Windows Implementation Complexity: High Estimated Effort: 5-8 days
Current Limitation: Domain-joined VMs lose membership after migration due to:
Challenges:
Proposed Approach: Automated domain rejoin post-migration
Implementation:
def extract_domain_info(guestfs, root): “"”Extract Active Directory membership info from offline registry.”””
system_hive = detect_windows_hive(guestfs, root, "SYSTEM")
software_hive = detect_windows_hive(guestfs, root, "SOFTWARE")
hive_system = download_and_open_hive(guestfs, system_hive)
hive_software = download_and_open_hive(guestfs, software_hive)
# Read domain membership from SYSTEM hive
controlset = detect_current_controlset(hive_system)
domain_keys = {
"domain_name": read_reg(hive_system, f"{controlset}\\Control\\ComputerName\\ComputerName\\Domain"),
"computer_name": read_reg(hive_system, f"{controlset}\\Control\\ComputerName\\ActiveComputerName\\ComputerName"),
"dns_domain": read_reg(hive_software, r"Microsoft\Windows\CurrentVersion\Group Policy\History\NetworkName"),
"dc_name": read_reg(hive_software, r"Microsoft\Windows\CurrentVersion\Group Policy\History\DCName"),
}
return {
"is_domain_joined": bool(domain_keys.get("domain_name")),
"domain": domain_keys.get("domain_name"),
"computer_name": domain_keys.get("computer_name"),
"dns_domain": domain_keys.get("dns_domain"),
"last_dc": domain_keys.get("dc_name"),
} ```
$LogFile = “C:\hyper2kvm\ad\rejoin-domain.log” $ConfigFile = “C:\hyper2kvm\ad\domain-info.json”
function Write-Log { param($Message) $Timestamp = Get-Date -Format “yyyy-MM-dd HH:mm:ss” “$Timestamp - $Message” | Out-File -Append -FilePath $LogFile }
Write-Log “=== Domain Rejoin Started ===”
if (-not (Test-Path $ConfigFile)) { Write-Log “ERROR: Domain config not found at $ConfigFile” exit 1 }
| $DomainInfo = Get-Content $ConfigFile | ConvertFrom-Json |
if ($DomainInfo.CredentialFile) { $CredPath = “C:\hyper2kvm\ad\credentials.xml” $Credential = Import-Clixml -Path $CredPath
Write-Log "Rejoining domain: $($DomainInfo.Domain)"
try {
# Remove from domain first (clean break)
Remove-Computer -UnjoinDomainCredential $Credential -Force -Restart:$false
# Rejoin domain
Add-Computer `
-DomainName $DomainInfo.Domain `
-Credential $Credential `
-OUPath $DomainInfo.OUPath `
-Force `
-Restart:$false
Write-Log "SUCCESS: Rejoined domain $($DomainInfo.Domain)"
# Schedule reboot
shutdown.exe /r /t 60 /c "Restarting to complete domain rejoin"
} catch {
Write-Log "ERROR: Failed to rejoin domain: $_"
} }
elseif ($DomainInfo.UnattendedJoinFile) { Write-Log “Using unattended join file (djoin.exe)”
$JoinFile = "C:\hyper2kvm\ad\unattended-join.txt"
# Execute offline domain join
djoin.exe /RequestODJ /LoadFile $JoinFile /WindowsPath C:\Windows /LocalOS
if ($LASTEXITCODE -eq 0) {
Write-Log "SUCCESS: Applied offline domain join"
shutdown.exe /r /t 60
} else {
Write-Log "ERROR: djoin.exe failed with exit code $LASTEXITCODE"
} }
else { Write-Log “MANUAL ACTION REQUIRED: Rejoin domain manually” Write-Log “Domain: $($DomainInfo.Domain)” Write-Log “Computer Name: $($DomainInfo.ComputerName)” Write-Log “OU Path: $($DomainInfo.OUPath)”
# Create desktop reminder
$ReminderPath = "C:\Users\Public\Desktop\REJOIN-DOMAIN.txt"
@" IMPORTANT: This VM was migrated and needs to rejoin the domain.
Domain: $($DomainInfo.Domain) Computer Name: $($DomainInfo.ComputerName) Organizational Unit: $($DomainInfo.OUPath)
Steps:
After rejoining, delete this file. “@ | Out-File -FilePath $ReminderPath
Write-Log "Created reminder file at $ReminderPath" }
Write-Log “=== Domain Rejoin Complete ===”
3. **Offline Domain Join Support (djoin.exe)**:
**Pre-Migration Workflow** (on source domain controller):
```powershell
# Domain admin provisions computer object ahead of time
djoin.exe /provision /domain example.com /machine VM01 /savefile vm01-join.txt
Migration Integration:
def stage_unattended_domain_join(guestfs, root, unattended_join_file):
"""Stage offline domain join file for djoin.exe."""
# Upload pre-provisioned join file
join_content = read_file(unattended_join_file)
guestfs.write(f"{root}/hyper2kvm/ad/unattended-join.txt", join_content)
domain_info = {
"UnattendedJoinFile": True,
"Method": "djoin.exe"
}
write_json(guestfs, f"{root}/hyper2kvm/ad/domain-info.json", domain_info)
Configuration:
windows:
active_directory:
enabled: true
# Option 1: Automated rejoin with credentials
rejoin:
method: credential # credential, unattended, manual
domain: example.com
ou_path: "OU=Migrated,OU=Servers,DC=example,DC=com"
credential_source: vault # vault, config, prompt
vault_path: "secret/windows/domain-join"
# Option 2: Offline domain join (requires pre-provisioning)
unattended_join:
file: /path/to/vm01-join.txt # From djoin.exe /provision
# Option 3: Manual rejoin (just extract metadata)
manual:
create_reminder: true
Security Considerations:
Limitations:
Business Value: Medium - Prevents AD bloat Implementation Complexity: Low Estimated Effort: 1 day
Approach: Provide pre-migration script to disable/delete old computer object
# Pre-migration script (run on domain controller)
# File: scripts/windows/cleanup-ad-computer.ps1
param(
[Parameter(Mandatory=$true)]
[string]$ComputerName,
[Parameter(Mandatory=$false)]
[ValidateSet("Disable", "Delete")]
[string]$Action = "Disable"
)
$Computer = Get-ADComputer -Identity $ComputerName -ErrorAction SilentlyContinue
if (-not $Computer) {
Write-Host "Computer $ComputerName not found in AD"
exit 1
}
switch ($Action) {
"Disable" {
Disable-ADAccount -Identity $Computer
Write-Host "Disabled computer object: $ComputerName"
# Add description
Set-ADComputer -Identity $Computer -Description "Disabled - Migrated on $(Get-Date -Format 'yyyy-MM-dd')"
}
"Delete" {
Remove-ADComputer -Identity $Computer -Confirm:$false
Write-Host "Deleted computer object: $ComputerName"
}
}
Business Value: High - Prevents post-migration failures Implementation Complexity: Medium Estimated Effort: 3-4 days
Scope: Detect applications that may break due to hardware changes
Detection Targets:
Implementation:
# File: hyper2kvm/fixers/windows/appcompat/detector.py
def detect_hardware_dependent_apps(guestfs, root):
"""Scan for applications with hardware dependencies."""
findings = []
# 1. Scan installed applications from registry
software_hive = detect_windows_hive(guestfs, root, "SOFTWARE")
hive = download_and_open_hive(guestfs, software_hive)
uninstall_keys = [
r"Microsoft\Windows\CurrentVersion\Uninstall",
r"Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
]
for uninstall_key in uninstall_keys:
apps = enumerate_registry_keys(hive, uninstall_key)
for app in apps:
app_info = read_app_metadata(hive, f"{uninstall_key}\\{app}")
# Check against known hardware-dependent vendors
if is_hardware_dependent(app_info):
findings.append({
"app": app_info["DisplayName"],
"vendor": app_info.get("Publisher"),
"version": app_info.get("DisplayVersion"),
"risk": assess_migration_risk(app_info),
"recommendation": get_mitigation_steps(app_info),
})
# 2. Scan for license manager services
system_hive = detect_windows_hive(guestfs, root, "SYSTEM")
hive_system = download_and_open_hive(guestfs, system_hive)
license_services = [
"lmgrd", # FlexLM
"rlm", # Reprise License Manager
"hasplms", # Sentinel HASP
]
controlset = detect_current_controlset(hive_system)
services_path = f"{controlset}\\Services"
for service in license_services:
if service_exists(hive_system, f"{services_path}\\{service}"):
findings.append({
"type": "license_service",
"service": service,
"risk": "HIGH",
"recommendation": "Update license server configuration post-migration",
})
# 3. Scan for dongle drivers
dongle_drivers = [
"akshasp", # Aladdin HASP
"sentinel", # SafeNet Sentinel
"haspvlib", # HASP virtual library
"cmstick", # CodeMeter stick
]
for driver in dongle_drivers:
driver_path = f"{root}/Windows/System32/drivers/{driver}.sys"
if guestfs.exists(driver_path):
findings.append({
"type": "dongle_driver",
"driver": driver,
"risk": "CRITICAL",
"recommendation": "Ensure dongle is attached to target hypervisor or use network dongle",
})
return findings
def is_hardware_dependent(app_info):
"""Check if application is known to have hardware dependencies."""
hardware_dependent_vendors = [
"Autodesk",
"Adobe Systems",
"Bentley",
"Dassault",
"Siemens",
"PTC",
"Ansys",
"MathWorks",
]
publisher = app_info.get("Publisher", "")
for vendor in hardware_dependent_vendors:
if vendor.lower() in publisher.lower():
return True
return False
Output Report:
{
"hardware_dependent_apps": [
{
"app": "AutoCAD 2022",
"vendor": "Autodesk",
"version": "24.1",
"risk": "HIGH",
"recommendation": "Reactivate license after migration - Autodesk licenses are hardware-locked"
},
{
"type": "license_service",
"service": "lmgrd",
"risk": "HIGH",
"recommendation": "Update license server configuration in C:\\Flexlm\\license.dat"
},
{
"type": "dongle_driver",
"driver": "akshasp",
"risk": "CRITICAL",
"recommendation": "Ensure HASP dongle is attached to target hypervisor"
}
]
}
Business Value: Very High - SQL Server is extremely common Implementation Complexity: High Estimated Effort: 5-7 days
Challenges:
Implementation:
# File: hyper2kvm/fixers/windows/appcompat/sqlserver.py
def detect_sql_server_instances(guestfs, root):
"""Detect SQL Server installations and configurations."""
software_hive = detect_windows_hive(guestfs, root, "SOFTWARE")
hive = download_and_open_hive(guestfs, software_hive)
instances = []
# SQL Server registry path
sql_base_keys = [
r"Microsoft\Microsoft SQL Server",
r"Wow6432Node\Microsoft\Microsoft SQL Server",
]
for base_key in sql_base_keys:
instance_names_key = f"{base_key}\\Instance Names\\SQL"
if not key_exists(hive, instance_names_key):
continue
instance_map = read_registry_values(hive, instance_names_key)
for instance_name, instance_id in instance_map.items():
instance_config = extract_instance_config(
hive,
base_key,
instance_id
)
instances.append({
"name": instance_name,
"id": instance_id,
"version": instance_config.get("Version"),
"edition": instance_config.get("Edition"),
"data_path": instance_config.get("DefaultData"),
"log_path": instance_config.get("DefaultLog"),
"backup_path": instance_config.get("BackupDirectory"),
"tcp_port": instance_config.get("TcpPort"),
"service_account": extract_service_account(guestfs, root, instance_name),
})
return instances
def generate_sql_reconfiguration_script(instances):
"""Generate T-SQL script for post-migration reconfiguration."""
script_lines = ["-- SQL Server Post-Migration Reconfiguration Script", ""]
for instance in instances:
script_lines.extend([
f"-- Instance: {instance['name']}",
"USE master;",
"GO",
"",
"-- Update linked servers (replace old hostname)",
"EXEC sp_droplinkedsrvlogin @rmtsrvname = 'OLD_SERVER', @locallogin = NULL;",
"EXEC sp_dropserver 'OLD_SERVER';",
"EXEC sp_addlinkedserver @server = 'NEW_SERVER';",
"",
"-- Reconfigure Always On Availability Groups (if applicable)",
"-- ALTER AVAILABILITY GROUP [AG_Name] REMOVE LISTENER 'OldListener';",
"-- ALTER AVAILABILITY GROUP [AG_Name] ADD LISTENER 'NewListener' (WITH IP((N'10.0.0.100', N'255.255.255.0')), PORT=1433);",
"",
"-- Update Replication (if applicable)",
"-- exec sp_changedistpublisher @publisher = 'OldServer', @property = 'working_directory', @value = '\\\\NewServer\\repldata';",
"",
])
return "\n".join(script_lines)
First-Boot Integration:
# File: templates/windows/reconfigure-sqlserver.ps1
$LogFile = "C:\hyper2kvm\sql\reconfiguration.log"
$ScriptFile = "C:\hyper2kvm\sql\reconfigure-instance.sql"
function Write-Log {
param($Message)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$Timestamp - $Message" | Out-File -Append -FilePath $LogFile
}
Write-Log "=== SQL Server Reconfiguration Started ==="
# Read instance metadata
$InstanceInfo = Get-Content "C:\hyper2kvm\sql\instances.json" | ConvertFrom-Json
foreach ($Instance in $InstanceInfo.Instances) {
Write-Log "Processing instance: $($Instance.Name)"
# Connect to instance
$ServerInstance = if ($Instance.Name -eq "MSSQLSERVER") {
"(local)"
} else {
"(local)\$($Instance.Name)"
}
try {
# Execute reconfiguration script
Invoke-Sqlcmd `
-ServerInstance $ServerInstance `
-InputFile $ScriptFile `
-ErrorAction Stop
Write-Log "SUCCESS: Reconfigured instance $($Instance.Name)"
} catch {
Write-Log "ERROR: Failed to reconfigure $($Instance.Name): $_"
}
}
Write-Log "=== SQL Server Reconfiguration Complete ==="
Configuration:
windows:
applications:
sql_server:
enabled: true
detect: true
reconfigure: true
# Update linked servers
linked_servers:
replace_hostname: true
old_hostname: oldserver.example.com
new_hostname: newserver.example.com
# Update Always On AG listeners
availability_groups:
- name: AG_Primary
listener_old: oldlistener.example.com
listener_new: newlistener.example.com
ip: 10.0.0.100
# Tempdb relocation (optional)
tempdb:
relocate: false
data_path: "D:\\MSSQL\\TEMPDB"
log_path: "D:\\MSSQL\\TEMPDB"
Business Value: Medium - Improves memory management Implementation Complexity: Low Estimated Effort: 1 day
Status: Driver injection already implemented, just needs auto-start configuration
Enhancement:
windows:
virtio:
drivers:
- name: balloon
type: memory
start: AUTO # Already supported
auto_configure: true # NEW: Auto-configure balloon service
# Balloon configuration
config:
memory_stats_interval: 10 # Report stats every 10 seconds
free_page_reporting: true # Enable free page reporting
Registry Configuration:
def configure_balloon_driver(hive_system, controlset):
"""Configure VirtIO balloon driver parameters."""
balloon_params_key = f"{controlset}\\Services\\balloon\\Parameters"
# Create Parameters key if missing
ensure_key_exists(hive_system, balloon_params_key)
# Set memory stats interval (in seconds)
set_registry_value(
hive_system,
f"{balloon_params_key}\\MemoryStatsInterval",
10,
"REG_DWORD"
)
# Enable free page reporting
set_registry_value(
hive_system,
f"{balloon_params_key}\\FreePageReporting",
1,
"REG_DWORD"
)
Business Value: Medium - Improves storage performance on SSDs Implementation Complexity: Low Estimated Effort: 1 day
Implementation:
# File: templates/windows/enable-trim.ps1
$LogFile = "C:\hyper2kvm\storage\trim-enablement.log"
function Write-Log {
param($Message)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$Timestamp - $Message" | Out-File -Append -FilePath $LogFile
}
Write-Log "=== TRIM/Discard Enablement Started ==="
# Check if disks support TRIM
$Disks = Get-PhysicalDisk | Where-Object { $_.MediaType -eq "SSD" -or $_.MediaType -eq "UnSpecified" }
foreach ($Disk in $Disks) {
Write-Log "Checking disk: $($Disk.FriendlyName)"
# Enable TRIM on volume
$Volumes = Get-Partition -DiskNumber $Disk.DeviceId | Get-Volume
foreach ($Volume in $Volumes) {
if ($Volume.FileSystemType -eq "NTFS" -or $Volume.FileSystemType -eq "ReFS") {
Write-Log "Enabling TRIM on volume $($Volume.DriveLetter)"
# Enable TRIM via fsutil
fsutil behavior set DisableDeleteNotify 0
# Verify TRIM is enabled
$TrimStatus = fsutil behavior query DisableDeleteNotify
Write-Log "TRIM status: $TrimStatus"
}
}
}
# Schedule regular TRIM optimization
Write-Log "Scheduling weekly TRIM optimization"
Optimize-Volume -DriveLetter C -ReTrim -Verbose
# Enable scheduled optimization task
$Task = Get-ScheduledTask -TaskName "ScheduledDefrag" -ErrorAction SilentlyContinue
if ($Task) {
Enable-ScheduledTask -TaskName "ScheduledDefrag"
Write-Log "Enabled scheduled disk optimization task"
}
Write-Log "=== TRIM Enablement Complete ==="
Business Value: Medium - Reduces interrupt latency Implementation Complexity: Medium Estimated Effort: 2-3 days
Background: Message Signaled Interrupts (MSI/MSI-X) reduce latency vs legacy line-based interrupts
Implementation:
def configure_msi_interrupts(hive_system, controlset):
"""Enable MSI/MSI-X for VirtIO devices."""
# Enable MSI for VirtIO SCSI/storage
viostor_params = f"{controlset}\\Services\\viostor\\Parameters"
set_registry_value(hive_system, f"{viostor_params}\\MSISupported", 1, "REG_DWORD")
# Enable MSI for VirtIO network
netkvm_params = f"{controlset}\\Services\\netkvm\\Parameters"
set_registry_value(hive_system, f"{netkvm_params}\\MSISupported", 1, "REG_DWORD")
# Global MSI policy (prefer MSI over line-based)
msi_policy = f"{controlset}\\Control\\PnP\\Pci"
set_registry_value(hive_system, f"{msi_policy}\\MSIPolicy", 1, "REG_DWORD")
Business Value: Low - Only relevant for Hyper-V → KVM migrations Implementation Complexity: Low Estimated Effort: 1 day
Purpose: Remove Hyper-V synthetic devices and enlightenments that don’t apply to KVM
Implementation:
def remove_hyperv_enlightenments(hive_system, controlset):
"""Remove Hyper-V specific drivers and enlightenments."""
hyperv_services = [
"storflt", # Hyper-V storage filter
"vmbus", # Hyper-V VMBus
"storvsc", # Hyper-V storage VSC
"netvsc", # Hyper-V network VSC
"hyperkbd", # Hyper-V keyboard
"hypervideo", # Hyper-V video
"vmgid", # Hyper-V generation ID
"vmicheartbeat",# Hyper-V heartbeat IC
"vmickvpexchange", # Hyper-V KVP IC
"vmicshutdown", # Hyper-V shutdown IC
"vmictimesync", # Hyper-V time sync IC
"vmicvss", # Hyper-V VSS IC
]
for service in hyperv_services:
service_key = f"{controlset}\\Services\\{service}"
if key_exists(hive_system, service_key):
# Set to disabled (do not delete - may cause boot issues)
set_registry_value(hive_system, f"{service_key}\\Start", 4, "REG_DWORD")
| Feature | Business Value | Complexity | Effort (days) | Priority | Phase |
|---|---|---|---|---|---|
| License Key Extraction | High | Medium | 3-5 | P1 | 1 |
| Domain Rejoin Automation | Very High | High | 5-8 | P1 | 1 |
| App Compatibility Detection | High | Medium | 3-4 | P2 | 2 |
| SQL Server Reconfiguration | Very High | High | 5-7 | P2 | 2 |
| VirtIO Balloon Config | Medium | Low | 1 | P3 | 3 |
| TRIM Enablement | Medium | Low | 1 | P3 | 3 |
| MSI Interrupt Config | Medium | Medium | 2-3 | P3 | 3 |
| KMS Server Update | Medium | Low | 1-2 | P3 | 3 |
| Hyper-V Removal | Low | Low | 1 | P4 | 4 |
| Computer Object Cleanup | Medium | Low | 1 | P4 | 4 |
Total Estimated Effort: 23-32 days (engineering time)
Goal: Enable enterprise Windows migrations with license and AD support
Deliverables:
Testing Requirements:
Goal: Detect and mitigate application-specific issues
Deliverables:
Testing Requirements:
Goal: Optimize Windows performance on KVM
Deliverables:
Testing Requirements:
Goal: Complete remaining features and documentation
Deliverables:
windows:
# License & Activation
license:
preserve: true # Extract and preserve license key
reactivate: true # Auto-reactivate on first boot
force_type: null # Override: KMS, MAK, Retail, OEM
kms_server: kms.example.com # KMS server override
kms_port: 1688 # KMS port override
# Active Directory
active_directory:
enabled: true
# Automated rejoin with credentials
rejoin:
method: credential # credential, unattended, manual
domain: example.com
ou_path: "OU=Migrated,OU=Servers,DC=example,DC=com"
credential_source: vault # vault, config, prompt
vault_path: "secret/windows/domain-join"
# Service account for domain join
service_account:
username: "DOMAIN\\svc_migration"
password_vault: "secret/windows/svc_migration"
# Offline domain join (requires pre-provisioning)
unattended_join:
enabled: false
file: /path/to/djoin-output.txt
# Manual rejoin (metadata only)
manual:
create_reminder: true # Desktop reminder file
# Application Compatibility
applications:
# App detection
detect_hardware_dependent: true
generate_report: true
report_path: /tmp/app-compat-report.json
# SQL Server specific
sql_server:
enabled: true
detect: true
reconfigure: true
linked_servers:
replace_hostname: true
old_hostname: oldserver.example.com
new_hostname: newserver.example.com
availability_groups:
- name: AG_Primary
listener_old: oldlistener.example.com
listener_new: newlistener.example.com
ip: 10.0.0.100
tempdb:
relocate: false
data_path: "D:\\MSSQL\\TEMPDB"
# Performance Optimization
performance:
# VirtIO balloon
balloon:
auto_configure: true
memory_stats_interval: 10
free_page_reporting: true
# TRIM/discard
trim:
enable: true
schedule_optimization: true
# MSI interrupts
msi:
enable: true
devices: [storage, network]
# Hyper-V cleanup
hyperv:
remove_enlightenments: true # Only for Hyper-V → KVM
| Risk | Impact | Mitigation | |——|——–|———–| | License key decryption fails | Cannot reactivate Windows | Implement version-specific decoders with fallbacks | | Domain rejoin fails | VM not accessible to domain users | Provide manual rejoin instructions, test extensively | | SQL Server corruption | Database downtime | Read-only detection, generate scripts for manual execution | | Credential exposure | Security breach | Use vault integration, encrypted storage, audit logging |
| Risk | Impact | Mitigation | |——|——–|———–| | App compatibility false positives | Unnecessary warnings | Refine detection rules, allow user overrides | | Performance degradation | Poor user experience | Extensive benchmarking, configurable optimizations | | MSI interrupt conflicts | Device malfunction | Make MSI optional, test on diverse hardware |
| Risk | Impact | Mitigation | |——|——–|———–| | TRIM not supported | Reduced SSD lifespan | Detect SSD support before enabling | | Balloon driver overhead | Minor performance impact | Make balloon optional, document trade-offs |
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId4
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform\Activation
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform\KeyManagementServiceName
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform\KeyManagementServicePort
HKLM\SYSTEM\ControlSet001\Control\ComputerName\ComputerName\Domain
HKLM\SYSTEM\ControlSet001\Control\ComputerName\ActiveComputerName\ComputerName
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History\NetworkName
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History\DCName
HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL
HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\{InstanceID}\Setup\SQLPath
HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\{InstanceID}\MSSQLServer\DefaultData
HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\{InstanceID}\MSSQLServer\DefaultLog
HKLM\SYSTEM\ControlSet001\Services\viostor\Parameters\MSISupported
HKLM\SYSTEM\ControlSet001\Services\netkvm\Parameters\MSISupported
HKLM\SYSTEM\ControlSet001\Services\balloon\Parameters\MemoryStatsInterval
HKLM\SYSTEM\ControlSet001\Control\PnP\Pci\MSIPolicy
C:\ProgramData\Autodesk\AdskLicensingService\LicPath.txtC:\Flexlm\license.datSERVER line with new hostname/MACDocument Version: 1.0 Last Updated: 2026-02-04 Status: Draft - Pending Implementation