VDI Admin Quick Guide
Quick guide for setting up Domain Controller and Golden Image for VDI.
Prerequisites: - Windows Server 2022 image - Windows 10/11 Pro or Enterprise image - Meneja platform access - DC Internal IP address will be recorded during setup
Part 1: Domain Controller
Step 1: Create Domain Controller VM
- Create VM from Windows Server 2022 image
- Name:
VDI-DC - Specs: 4 CPU, 8GB RAM, 100GB disk
- Record the internal IP address
Step 2: Install Active Directory Domain Services
- Open Server Manager
- Click Manage → Add Roles and Features
- Click Next until Server Roles
- Select Active Directory Domain Services
- Click Add Features when prompted
- Click Next through remaining screens
- Click Install
- Wait for installation to complete
Step 3: Promote to Domain Controller
- In Server Manager, click the warning notification flag
- Click Promote this server to a domain controller
Configuration:
Deployment:
- Select: Add a new forest
- Domain name: corp.local (or your choice)
Domain Controller Options:
- Functional level: Windows Server 2016 or later
- Enable: DNS server
- Enable: Global Catalog
- Create DSRM password: Complex@Pass123! (record this)
NetBIOS name:
- Auto-fills as CORP (leave default)
Paths: - Leave defaults
Click Install
Server will reboot automatically. Wait 5-10 minutes for reboot to complete.
Step 4: Create Users and Profiles
After reboot, log in as: CORP\Administrator
Open PowerShell as Administrator:
Create Organizational Unit:
Import-Module ActiveDirectory
New-ADOrganizationalUnit -Name "VDI-Users" -Path "DC=corp,DC=local"
Create user accounts:
# Set password for all users
$password = ConvertTo-SecureString "TempPass123!" -AsPlainText -Force
# Create users (repeat for each user)
foreach ($username in @("user1", "user2", "user3")) {
New-ADUser -Name $username `
-SamAccountName $username `
-UserPrincipalName "$username@corp.local" `
-Path "OU=VDI-Users,DC=corp,DC=local" `
-AccountPassword $password `
-Enabled $true `
-PasswordNeverExpires $true
# Create profile folder
New-Item -ItemType Directory -Path "C:\Profiles\$username" -Force
Set-ADUser -Identity $username -ProfilePath "\\$env:COMPUTERNAME\Profiles$\$username"
}
Setup roaming profiles:
# Create profiles folder and share
New-Item -ItemType Directory -Path "C:\Profiles" -Force
New-SmbShare -Name "Profiles$" -Path "C:\Profiles" -FullAccess "Everyone"
Verify everything works:
Get-ADUser -Filter * -SearchBase "OU=VDI-Users,DC=corp,DC=local"
Get-SmbShare -Name "Profiles$"
Domain Controller setup complete.
Part 2: Golden Image
Step 1: Create Golden Image VM
- Create VM from Windows 10/11 Pro or Enterprise image
- Name:
VDI-GoldenImage - Specs: 4 CPU, 8GB RAM, 120GB disk (images already have correct disk size)
- Network 1: Internal (to reach DC)
- Network 2: Public (for RDP access)
Step 2: Configure DNS and Disable Updates
Open PowerShell as Administrator:
Disable Windows Update:
Set-Service -Name wuauserv -StartupType Disabled
Stop-Service -Name wuauserv
Configure DNS:
# Set DNS to DC's internal IP (replace with your DC IP)
Get-NetAdapter | Where-Object {$_.Status -eq "Up"} |
Set-DnsClientServerAddress -ServerAddresses "10.x.x.x" # Replace with DC IP
Verify DNS:
Get-DnsClientServerAddress
nslookup corp.local # Should resolve to DC IP
ping corp.local # Should respond
Step 3: Optimize for VDI
Disable unnecessary services:
# Hibernation
powercfg /h off
# Windows Search
Stop-Service -Name "WSearch" -Force
Set-Service -Name "WSearch" -StartupType Disabled
# Superfetch
Stop-Service -Name "SysMain" -Force
Set-Service -Name "SysMain" -StartupType Disabled
# Telemetry
Stop-Service -Name "DiagTrack" -Force
Set-Service -Name "DiagTrack" -StartupType Disabled
Enable Remote Desktop:
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name "fDenyTSConnections" -Value 0
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -Name "UserAuthentication" -Value 1
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"
Step 4: Cleanup
⚠️ CRITICAL: Verify NOT domain-joined:
(Get-WmiObject Win32_ComputerSystem).Domain
# Must show: WORKGROUP (not corp.local)
Clean up:
# Remove temp files
Remove-Item "$env:TEMP\*" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item "C:\Windows\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue
# Clear event logs
wevtutil el | ForEach-Object { wevtutil cl $_ 2>$null }
# Remove Windows Store apps (they cause Sysprep issues)
Get-AppxPackage -AllUsers | Remove-AppxPackage -ErrorAction SilentlyContinue
# Disable BitLocker if enabled
Disable-BitLocker -MountPoint "C:" -ErrorAction SilentlyContinue
Step 5: Create Unattend.xml
Create unattend.xml for automatic domain join:
notepad C:\Windows\System32\Sysprep\unattend.xml
Copy this XML into Notepad and Save:
Important: This file automates domain joining during first boot. Update the
<Password>field with your actual Domain Administrator password (in this example:Complex@Pass123!). This file will be consumed and removed automatically after the first VM boot.Note: This is one method for automated domain joining. Other mechanisms exist such as offline domain join (djoin.exe) or configuration management tools. Choose the method that fits your environment.
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="specialize">
<component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<Identification>
<Credentials>
<Domain>corp.local</Domain>
<Password>Complex@Pass123!</Password>
<Username>Administrator</Username>
</Credentials>
<JoinDomain>corp.local</JoinDomain>
</Identification>
</component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<TimeZone>UTC</TimeZone>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<InputLocale>en-US</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<HideLocalAccountScreen>true</HideLocalAccountScreen>
<ProtectYourPC>1</ProtectYourPC>
<SkipUserOOBE>true</SkipUserOOBE>
<SkipMachineOOBE>true</SkipMachineOOBE>
</OOBE>
</component>
</settings>
</unattend>
Verify file created:
Test-Path C:\Windows\System32\Sysprep\unattend.xml # Should return: True
Step 6: Flush Changes and Create Snapshot
Flush all filesystem changes:
# Sync filesystem
Write-VolumeCache C
# Verify no pending operations
Get-Volume | Format-Table DriveLetter, FileSystem, OperationalStatus
In Meneja:
1. Navigate to the VDI-GoldenImage VM
2. Select Disks tab
3. Select the boot disk
4. Click Create Snapshot
5. Name: pre-sysprep-snapshot
6. Click Create
Note: This snapshot allows you to roll back to this state for future updates or troubleshooting. You can create new template versions by reverting to this snapshot, making updates, and running Sysprep again.
Step 7: Run Sysprep
C:\Windows\System32\Sysprep\sysprep.exe /oobe /generalize /shutdown /mode:vm
VM will shut down automatically. DO NOT boot it again before converting to template.
What happens on VM created from template: - VM joins corp.local domain automatically (3-5 minutes) - Gets unique computer name (DESKTOP-XXXXXXX) - unattend.xml is consumed and removed - Skips all OOBE screens - Boots to domain login screen
Step 8: Convert to Template
In Meneja:
1. Navigate to the shutdown VDI-GoldenImage VM
2. Click Convert to Template
3. Enter template name: VDI-Win11-Template-v1
4. Click Convert
Golden Image template created successfully.
Testing
Test the Template
- Create VM from template
- Boot (wait 3-5 minutes for domain join)
- Login screen appears (no OOBE)
- Login:
CORP\user1+Complex@Pass123! - Verify domain:
(Get-WmiObject Win32_ComputerSystem).Domain→ showscorp.local - Test RDP from external machine
- Delete test VM
If login works, template is ready for VDI use.
Troubleshooting
Domain Controller
Can't promote to DC - password error:
$password = ConvertTo-SecureString "YourPassword123!" -AsPlainText -Force
Set-LocalUser -Name "Administrator" -Password $password
Can't import ActiveDirectory module: - Wait 5 minutes after reboot - Services need time to start
Users can't access profiles share:
# Check share exists
Get-SmbShare -Name "Profiles$"
# Fix permissions
icacls C:\Profiles /grant "Everyone:(OI)(CI)F"
Golden Image
Can't resolve domain name: - Check DNS is set to DC's internal IP - Network settings → Adapter → IPv4 → DNS
Sysprep fails - BitLocker:
Disable-BitLocker -MountPoint "C:"
# Wait for decryption to complete
Get-BitLockerVolume -MountPoint "C:"
Sysprep fails - Apps:
Get-AppxPackage -AllUsers | Remove-AppxPackage -ErrorAction SilentlyContinue
Domain join fails:
- Verify DNS points to DC: nslookup corp.local
- Ping DC: ping corp.local
- Check DC is running
Trust relationship error:
Cause: Golden image was domain-joined before Sysprep.
Fix: Create VM from snapshot, boot it, remove from domain, re-Sysprep:
Remove-Computer -WorkgroupName "WORKGROUP" -Force -Restart
# After restart, verify WORKGROUP, then run Sysprep again
RDP not working:
# Enable RDP
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 0
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"
Quick Commands
**Check domain:**
```powershell
Get-ADDomain
Get-ADUser -Filter * -SearchBase "OU=VDI-Users,DC=corp,DC=local"
Check DNS:
nslookup corp.local
Get-DnsClientServerAddress
Check RDP:
Get-ItemProperty 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections