FSLogix + Horizon + Entra Hybrid Join Configuration

Over time, I’ve tested many different setups for VMware Horizon environments — some more successful than others. But after countless rebuilds, troubleshooting sessions, and user feedback, I finally landed on what I consider my ideal configuration: a Horizon environment powered by FSLogix profiles and Entra Hybrid Joined virtual machines.

In this post, I’ll walk through how I’ve structured the configuration, step by step:

  1. Building the Horizon Master Image – the base OS, optimizations, and agents I include.
  2. Joining to Entra Hybrid – the configuration details that ensure smooth sign-in and device registration.
  3. Configuring the Desktop Pools – settings that keep login performance and flexibility balanced.
  4. Setting Up FSLogix Profiles – how I handle profile containers, exclusions, and storage.
  5. Final Tweaks and Recommendations – small but impactful adjustments that make the whole environment stable and fast.
  6. Sources

⚠️ Disclaimer:
I’m not a certified VMware professional. Everything described in this post is based on my own hands-on experience and the configuration that has proven reliable in my environment.
These recommendations come from extensive testing, trial and error, and real-world practice — not from official VMware training or certification materials.
Most of the configurations and procedures were developed by following tutorials, community discussions, and official guides or knowledge base articles from VMware, Microsoft, and other trusted sources.
All referenced sources can be found at the end of this post.

1. Building the Horizon Master Image

For the base image, we start with a clean, patched Windows 11 Enterprise image. After joining it to the domain, we install the following key components:

  • Omnissa Horizon Agent (selecting only the features needed for my pools)
  • FSLogix Apps
  • Latest Windows Updates
  • VMware Tools

💡 Tip:
Since the switch to Omnissa Horizon licensing, the Helpdesk Plugin is now included in the standard license package. That means you can enable it directly during the setup process without needing any additional licenses. Make sure to activate it in the Omnissa Horizin Agent configuration — it’s a powerful tool for monitoring user sessions and troubleshooting performance issues.

At the time of writing this post, our environment is running:

VMware Tools: 12.5.3 (Build 24819442)
Omnissa Horizon Agent: Version 2506

In previous years, we used the VMware OS Optimization Tool (OSOT) to remove unnecessary services and scheduled tasks from the master image. However, after experiencing a few stability issues with certain applications, we decided to move away from OSOT. Instead, we created a small custom cleanup script that we run right before shutting down the master image and taking a snapshot.

Our current script contains the following tasks:

  • Delete temporary files
  • Delete downloads of the currently logged-in user
  • Empty Recycle Bin
  • Start Disk Cleanup
  • Reset network settings
  • Optimize storage (optional, may take a while)

start cleanup.ps1

@echo off
:: Enable UTF-8 console output
chcp 65001 >nul

:: Start cleanup.ps1 with PowerShell in bypass mode
set SCRIPT=%~dp0cleanup.ps1
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT%"
pause

cleanup.ps1

[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8

Write-Host "Starting cleanup..." -ForegroundColor Cyan

# Delete temporary files
Write-Host "Deleting temporary files..." -ForegroundColor Yellow
Get-ChildItem -Path "C:\Windows\Temp" -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue

# Delete downloads of the currently logged-in user
Write-Host "Deleting Downloads folder of the logged-in user..." -ForegroundColor Yellow
$downloadPath = Join-Path $env:USERPROFILE "Downloads"
if (Test-Path $downloadPath) {
    Get-ChildItem -Path $downloadPath -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
    Write-Host "Downloads from $downloadPath have been cleaned." -ForegroundColor Green
} else {
    Write-Host "No Downloads folder found." -ForegroundColor Red
}

# Empty Recycle Bin
Write-Host "Emptying Recycle Bin..." -ForegroundColor Yellow
Clear-RecycleBin -Force -ErrorAction SilentlyContinue

# Start Disk Cleanup
Write-Host "Starting automatic Disk Cleanup..." -ForegroundColor Yellow
Start-Process -FilePath "cleanmgr.exe" -ArgumentList "/sagerun:1" -Wait

# Reset network settings
Write-Host "Network: Releasing IP addresses and flushing DNS cache..." -ForegroundColor Yellow
ipconfig /release
ipconfig /flushdns

# Optimize storage (optional, may take a while)
Write-Host "Performing storage optimization..." -ForegroundColor Yellow
compact.exe /compactos:always

Write-Host "Cleanup completed!" -ForegroundColor Green
2. Preparing the Horizon Master Image for Entra Hybrid Join

Before finalizing the hybrid join, we also onboarded our Horizon master image to Microsoft Defender for Endpoint to ensure every virtual desktop instance reports correctly to the security portal once it’s deployed.

We followed Microsoft’s official steps for onboarding non-persistent VDI environments, as described in their documentation:

🔗 Configure endpoints for VDI in Microsoft Defender for Endpoint

In our case we followed the “Single Entry Path”. Here’s a summary of the process we implemented:

Download the VDI onboarding package

From the Microsoft Defender portal, navigate to
Settings → Endpoints → Device Management → Onboarding.
Choose the correct operating system, select VDI onboarding scripts for non-persistent endpoints, and then download the .zip package.

Extract and copy the scripts

Unzip the package and copy its contents to:

C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup

If the folder isn’t visible, make sure hidden files and folders are enabled in File Explorer.

Copy the extracted files

Copy both Onboard-NonPersistentMachine and WindowsDefenderATPOnboardingScript.

Register the Startup Script via Group Policy

Open the Group Policy Editor (gpedit.msc) and navigate to:
Computer Configuration → Windows Settings → Scripts → Startup
Then: Use the PowerShell Scripts tab and add Onboard-NonPersistentMachine.ps1
(There’s no need to specify the other file, as it’s triggered automatically.)

⚙️ Important:
This Group Policy should be applied only to the Organizational Unit (OU) that contains your Instant Clone desktopsnot to the master image or any template VM.
The master image must remain clean and unregistered so that every new clone performs its own onboarding during first boot.
Applying the policy to the master image could cause duplicate device entries or stale registrations in Microsoft Defender for Endpoint and Microsoft Entra ID.

3. Configuring the Desktop Pools

For our deployment, we decided to use Instant Clones to ensure fast provisioning, easy updates, and minimal administrative overhead.
Below is a summary of the key pool settings we applied:

SettingValue / ConfigurationDescription / Purpose
Guest CustomizationClonePrepAutomates domain join and machine identity generation for each clone.
View Storage AcceleratorEnabledImproves read performance and reduces I/O load on the datastore.
Allow reuse of existing computer accountsEnabledPrevents unnecessary AD object recreation and supports stable hybrid join behavior.
Snapshot Update CycleEvery 7 daysEnsures regular image refresh and deployment of updates.
Cluster / HostvSAN-backed clusterDedicated to Horizon VDI workloads for optimized performance.
Pool TypeInstant Clone Desktop PoolProvides fast, space-efficient, and easily managed VMs.
vTPMEnabledRequired for Windows 11 compatibility and enhanced security.
Action at LogoffDelete and recreate VMGuarantees a clean non-persistent desktop for every session.
Allow users to restart their desktopsNoPrevents manual restarts that could interrupt provisioning cycles.
Session TypeDesktopStandard virtual desktop deployment type.
Display ProtocolHorizon Blast (default)Offers modern, high-performance graphics streaming.
Session CollaborationDisabledRestricts users from sharing desktop sessions.
Allow multiple client sessions per userNoEach user receives a unique, isolated desktop.
Allow PCoIP UltraNoEnvironment standardized on Horizon Blast only.
3D RendererManaged via vSphere ClientConfigured depending on workload and GPU availability.
Remote Power PolicyAlways OnKeeps desktops ready for quick connection.
Disconnect Session Timeout480 minutesControls session persistence for idle users.
Computer Naming PatternW11-vPC-xxx{n:fixed=3}Ensures consistent and predictable computer naming.
VM Access PolicyBlock direct vSphere accessPrevents administrators from connecting directly to the VM console, improving security.
4. Setting Up FSLogix Profiles

To handle user profile roaming in our Horizon environment, we use FSLogix Profile Containers. This provides a fast, reliable, and seamless profile experience for users logging into non-persistent Instant Clone desktops.

The FSLogix profile containers are stored on a Windows file server located on the same vSAN storage as the Horizon virtual machines.
This ensures minimal latency between desktop sessions and the profile store, improving both login times and session responsiveness.

Each user profile is mounted dynamically at logon as a VHDX container, giving the user a persistent experience while keeping the underlying desktop non-persistent.

All FSLogix settings are applied through Group Policy Objects (GPOs) to guarantee consistent configuration across all virtual desktops.
Below is a summary of our applied policy configuration, based on the settings shown in the screenshot:

General FSLogix Policies

GPO Path:
Computer Configuration → Administrative Templates → FSLogix

Policy NameSettingDescription
Cleanup Invalid SessionsEnabledEnsures stale FSLogix sessions are cleaned up automatically.
Roam Recycle BinDisabledKeeps the Recycle Bin local to reduce container size.
VHD Compact DiskEnabledCompacts profile containers automatically to reclaim disk space.

FSLogix / ODFC Containers

GPO Path:
Computer Configuration → Administrative Templates → FSLogix → ODFC Containers

Policy NameSettingDescription
Include Office ActivationDisabledUses standard Microsoft 365 activation instead of FSLogix ODFC.

FSLogix / Profile Containers

GPO Path:
Computer Configuration → Administrative Templates → FSLogix → Profile Containers

Policy NameSettingDescription
EnabledEnabledActivates FSLogix Profile Container functionality.
Initial AppX PackagesEnabledEnsures modern Windows apps initialize correctly.
Is Dynamic (VHD)EnabledCreates containers with dynamic disk sizing.
Keep Local Directory (after logoff)DisabledDeletes local profile remnants after logoff.
Outlook Cached ModeEnabledKeeps Outlook in Cached Exchange Mode within the profile container.
Redirect TypeEnabledStandard FSLogix redirection behavior.
Remove Orphaned OST Files on LogoffEnabledDeletes orphaned OST files to prevent corruption.
Roam IdentityEnabledRoams user identity (SID consistency).
Roam SearchDisabledKeeps Windows Search index local for better performance.
Set Temp Folders to Local PathEnabledRedirects TEMP, TMP, and INetCache folders to the local drive.
Size in MBsEnabled → 50,000 MBLimits container size to 50 GB.
VHD LocationsEnabled → \\<fileserver>\dfs\FSLogixDefines the path where FSLogix VHD/VHDX containers are stored.
Redirection XML Source FolderEnabled → \\<fileserver>\software$\FSLogixLocation of the XML redirection configuration.

FSLogix / Profile Containers / Container and Directory Naming

GPO Path:
Computer Configuration → Administrative Templates → FSLogix → Profile Containers -> Container and Directory Naming

Policy NameSettingDescription
Volume Type (VHD or VHDX)Enabled → VHDXUses VHDX for better performance and resilience.

To further refine our FSLogix configuration, we created a custom redirections.xml file that we linked through Group Policy (configured under
Computer Configuration → Administrative Templates → FSLogix → Profile Containers → Redirection XML Source Folder).

This XML file fine-tunes what parts of the user profile are excluded or included in the FSLogix container. The goal is to reduce container size, speed up logons, and avoid storing volatile authentication and cache data that should remain local.

We built the XML based on Microsoft’s official recommendations (Device identity and desktop virtualization) and several practical adjustments for hybrid-joined Horizon environments.

Below is the version we currently use:

<?xml version="1.0" encoding="UTF-8"?>

<FrxProfileFolderRedirection ExcludeCommonFolders="0">

  <Excludes>
    <!-- Browser Cache -->
    <Exclude Copy="0">AppData\Local\Microsoft\Edge\User Data\Default\Cache</Exclude>

    <!-- Microsoft Identity + Token Broker (AAD + M365 Sign-in) -->
    <Exclude Copy="0">AppData\Local\Microsoft\OneAuth</Exclude>
    <Exclude Copy="0">AppData\Local\Microsoft\TokenBroker</Exclude>
    <Exclude Copy="0">AppData\Local\Microsoft\IdentityCache</Exclude>
    <Exclude Copy="0">AppData\Local\Microsoft\Office\16.0\Identity</Exclude>
    <Exclude Copy="0">AppData\Local\Packages\Microsoft.AAD.BrokerPlugin_cw5n1h2txyewy</Exclude>
    <Exclude Copy="0">AppData\Local\Packages\Microsoft.Windows.CloudExperienceHost_cw5n1h2txyewy</Exclude>

    <!-- Office Authentication Caches -->
    <Exclude Copy="0">AppData\Local\Microsoft\CredentialManager</Exclude>
    <Exclude Copy="0">AppData\Roaming\Microsoft\Credentials</Exclude>

    <!-- Registry Keys -->
    <Exclude Copy="0">HKEY_CURRENT_USER\SOFTWARE\Microsoft\IdentityCRL</Exclude>
    <Exclude Copy="0">HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\AAD</Exclude>
    <Exclude Copy="0">HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WorkplaceJoin</Exclude>
    <Exclude Copy="0">HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\TokenBroker</Exclude>
  </Excludes>

  <Includes>
    <!-- Oracle/Sun Java -->
    <Include Copy="3">AppData\LocalLow\Sun\Java\Deployment\security</Include>

    <!-- Microsoft DPAPI Keys (important for password and M365 login persistence) -->
    <Include Copy="3">AppData\Roaming\Microsoft\Protect</Include>

    <!-- Edge User Data: keeps login data and local state -->
    <Include Copy="3">AppData\Local\Microsoft\Edge\User Data</Include>
  </Includes>

</FrxProfileFolderRedirection>

After setting up FSLogix and completing the hybrid join preparation, we added a few final optimizations to make the entire setup more stable and reliable in production.

5. Final Tweaks and Recommendations

To ensure that each Instant Clone correctly completes the Entra Hybrid Join process during its first startup, we created a dedicated GPO for the Horizon Agent.

This policy enforces that the Horizon Agent waits for the hybrid join process to finish before fully initializing the desktop session.
Without this setting, some machines could register inconsistently or fail to appear correctly in Microsoft Entra ID, especially in fast-provisioning environments like Instant Clones.

GPO Path:

Computer Configuration → Administrative Templates → Omnissa Horizon Agent Configuration / Agent Configuration

Policy NameSettingDescription
Configure Wait for Hybrid JoinEnabledHorizon Agent delays login until Entra Hybrid Join is successfull

By enabling this option, the Horizon Agent delays the login readiness state until the Entra Hybrid Join has completed successfully. This ensures that:

  • The machine is properly registered in Entra ID before user login.
  • Conditional Access and Defender onboarding policies are applied consistently.
  • FSLogix profile mounting occurs in a stable identity state.

As described in the official Omnissa documentation (Support for Azure Active Directory),
Microsoft Entra Connect performs synchronization tasks on an hourly schedule.
Because of this, a freshly provisioned desktop can remain in a “Pending” state for some time before it becomes fully available in Entra ID.

In practice, this can result in longer startup times for new or refreshed desktops.
In our environment, the delay typically ranges between 2 and 10 minutes, depending on synchronization timing and infrastructure load.
However, once the join is completed, the machine remains stable and consistently recognized across all connected Microsoft services.

Sources

Blogs:

Microsoft:

Omnissa:

In

Leave a Reply

Your email address will not be published. Required fields are marked *