Azure Virtual Desktop

Configure FSLogix Profiles on Azure Files with Entra ID Kerberos: Permissions, Registry, and Exclusions Done Right

A user signs into your Azure Virtual Desktop pool, the desktop loads, and their profile is gone — fresh Start menu, no Outlook signature, no OneDrive, no browser history. Next login they get a different session host and a different empty profile. This is what FSLogix exists to solve: on pooled, non-persistent session hosts a user can land on any VM, so their profile must live on shared storage and be attached at logon, not baked into C:. FSLogix packages the entire profile into a VHDX container it mounts as a virtual disk at sign-in and detaches at sign-out — wherever the user lands, their profile follows. That container needs a home that’s fast, redundant and SMB-accessible, and Azure Files is the natural fit.

The hard part was never FSLogix itself — it is authentication and permissions. Putting containers on Azure Files used to mean standing up domain controllers (or Entra Domain Services) just so the share could authenticate SMB sessions with Kerberos. Microsoft Entra ID Kerberos removes that: your Entra-joined hosts mount an Azure Files SMB share and authenticate directly against Entra ID, no domain controller in the path. That simplification introduces a two-layer permission model that trips up almost everyone the first time: share-level RBAC (who may connect, granted as Azure roles) and NTFS/file-level permissions (what they may do once connected, set with icacls). Get one layer right and the other wrong and FSLogix silently fails to create or load the container — symptom: again, an empty profile.

This is a step-by-step implementation guide. You will configure a complete FSLogix-on-Azure-Files setup using Entra ID Kerberos from scratch — storage account, Kerberos identity, both permission layers, the FSLogix registry, and the exclusions that keep containers small — three ways: the portal, the az CLI, and a Bicep template you can commit. Every step states its expected output and how to validate it, and the article ends with the exact registry keys, the permission matrix, the exclusion list, a troubleshooting playbook, and a teardown. By the end you won’t be guessing why a profile is empty; you’ll know which permission layer, or which registry value, is wrong, and fix it in minutes.

What problem this solves

On a single, persistent desktop the profile lives on the local disk and nobody thinks about it. On pooled Azure Virtual Desktop — many users sharing a fleet of disposable session hosts — that collapses: a user is load-balanced to whichever host has capacity, so their profile cannot live on any one host’s C: drive. The classic answers (roaming profiles, mandatory profiles, UPDs) are slow, fragile, and notorious for corruption with modern apps like OneDrive, Teams and the new Outlook. FSLogix replaces all of it with one idea: the profile is a VHDX file on an SMB share, attached as a disk at logon so Windows sees a normal local profile, detached at logout.

What breaks without getting storage and permissions right: FSLogix tries to create the container and can’t — the host can’t authenticate (Kerberos misconfigured), or authenticates but lacks NTFS rights to create the file, or the quota is full. The default failure mode is to fall back to a temporary local profile — the user logs in to a working-but-empty desktop, does work, logs out, and it evaporates. No error, no crash. The most common ticket in an AVD estate is “my files disappeared”, and behind it is almost always one of: the container never attached, attached read-only, or got reset because the two permission layers disagreed.

Who hits this: anyone running pooled AVD or Windows 365 at scale, migrating off file-server UPD/roaming profiles, and especially teams adopting the cloud-only identity model — Entra-joined hosts with no domain controller. That last group is exactly who Entra ID Kerberos is for, and the configuration this guide builds. Done right, you get a profile system that survives host reimaging, scales to thousands of users on one storage account, and needs no AD at all.

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should understand the AVD building blocks: a host pool is a set of session-host VMs that users connect to through the AVD control plane. If that’s new, read Azure Virtual Desktop Architecture: Control Plane and Session Hosts Explained and Deploy Your First AVD Pooled Host Pool End to End first. Know the Azure Files basics — mounting an SMB share, quotas, tiers — from Azure Files SMB Share: Mount on Windows and Linux Quickstart. Comfort with az in Cloud Shell, reading JSON, and Windows NTFS/registry basics will make the lab smooth.

This sits in the AVD / End-User Compute track — the storage and identity layer beneath a host pool. Which pool model you run — see AVD Host Pool: Personal vs Pooled — Deciding the Right Model — is upstream: FSLogix matters most for pooled pools (personal desktops keep profiles locally). It pairs with Azure Storage Redundancy: LRS, ZRS, GRS, RA-GRS Explained (the share’s redundancy is a real availability call) and with Managed Identity: System-Assigned vs User-Assigned Patterns (the identity concepts underpinning how Kerberos authenticates).

The identity options for Azure Files, and which this guide uses:

Auth method for Azure Files SMB Needs a domain controller? Host join type Best for This guide?
Microsoft Entra ID Kerberos No Entra-joined (cloud-only) Cloud-only AVD/W365, no AD Yes
On-prem AD DS authentication Yes (your own DCs) AD-joined / Hybrid-joined Estates that already run AD No
Microsoft Entra Domain Services Managed DC (Azure-hosted) Entra DS-joined Wanted Kerberos but no AD to extend No
Storage account key (no identity) No Any One-off mounts, never for FSLogix profiles No

The point of Entra ID Kerberos is the top row: no domain controller, cloud-only hosts, profiles authenticated straight to Entra ID.

Core concepts

Five mental models make every later step and every failure obvious.

A profile is a VHDX, attached at logon. FSLogix packages C:\Users\<user> into a single VHDX on the SMB share. At sign-in it mounts the VHDX as a disk and redirects the profile to it, so Windows and every app see an ordinary local profile; at sign-out it flushes and detaches. The file is foldered per user and created on first login. Everything here is about FSLogix being able to create, attach and write that one file.

Authentication and authorization are two layers. A host must first authenticate (prove who it is), then be authorized (be allowed to read/write). With Entra ID Kerberos, authentication is a Kerberos ticket from Entra ID — no DC. Authorization is itself two sub-layers: share-level RBAC (Azure roles for whether an identity may connect) and NTFS permissions (Windows ACLs for what they may do). Both must allow the operation — the double-gate is the number-one source of “it authenticated but the profile is empty” confusion.

Entra ID Kerberos puts the storage account in Entra ID as an app. Enabling Kerberos registers an app / service principal for the account, which needs admin consent for the Graph permissions it uses to issue tickets. When a host mounts the share it asks Entra ID for a ticket for that account, presents it to Azure Files, and is authenticated. No consent (or unreachable endpoints) → logon failure at mount, before any NTFS check.

FSLogix is driven entirely by the registry. No UI. The agent reads values under HKLM\SOFTWARE\FSLogix\Profiles to decide whether it’s enabled, where containers live, the disk format, and how to behave on failure. You set these via Group Policy, Intune, a script, or by hand in the lab. Get Enabled and VHDLocations right and you have a working system; the rest is behaviour tuning.

Exclusions keep the container small and avoid double-syncing. By default the whole profile goes into the VHDX — including caches you don’t want and cloud-synced data (OneDrive, Teams) already in the cloud. Profile exclusions (via redirections.xml) leave chosen folders out. The classic call: keep OneDrive in for a smooth experience but exclude transient caches. It’s about size and performance, not correctness — but a bloated container is slow to attach and a recurring cost.

The vocabulary in one table

Pin down every moving part before the steps (the glossary repeats these for lookup):

Concept One-line definition Where it lives Why it matters here
FSLogix agent Windows service that attaches profile VHDXs On each session host The thing doing the work
Profile container The user’s profile packaged as a VHDX On the Azure Files share The file that must be created/attached
VHDLocations UNC path(s) where containers live Registry value Points FSLogix at the share
Azure Files share SMB share hosting the VHDX files Storage account The redundant home for profiles
Entra ID Kerberos Cloud Kerberos auth for Azure Files Storage account + tenant Authenticates hosts with no DC
Storage account app The SP representing the account in Entra App registration Needs admin consent for tickets
Share-level RBAC Azure roles to connect to the share IAM on the storage account Layer 1 of authorization
NTFS permissions ACLs inside the file system Set via icacls Layer 2 of authorization
Default share-level permission A baseline role for all authenticated users Storage account file setting Avoids per-user role assignment
redirections.xml The profile exclusion/inclusion list On the share or local Controls container size
CloudCache Local cache layered over remote VHDX(s) Registry (CCDLocations) Resilience / multi-region option

Core concept: the two-layer permission model (read this twice)

If you remember one thing, remember this. Every FSLogix-on-Azure-Files permission problem is one of these two layers being wrong, and they live in different places with different tools.

Layer 1 — share-level RBAC (authorization to connect). Azure role assignments on the storage account (Access control / IAM) decide whether an Entra identity may establish an SMB session at all. Three built-in roles, and the difference between them is exactly what bites FSLogix admins.

Built-in role (share-level) What it grants over SMB Who you assign it to FSLogix relevance
Storage File Data SMB Share Reader Read-only access to files/dirs Auditors, read-only apps Too little — container can’t be written
Storage File Data SMB Share Contributor Read, write, delete on files/dirs The AVD users (their profiles) The baseline users need
Storage File Data SMB Share Elevated Contributor Contributor plus modify NTFS ACLs Admins setting up permissions Needed to run icacls to set NTFS

The trap: people assign users Reader (or nothing) and the container attaches read-only or not at all. Users get Contributor; the admin who sets NTFS permissions needs Elevated Contributor (changing ACLs is itself a permission). Rather than assign Contributor to every user, set a Default share-level permission so all authenticated Entra identities get a baseline role (typically Contributor) automatically — overriding per-identity only when needed.

Layer 2 — NTFS / file-level permissions (authorization to act on the file). Once connected, Windows ACLs decide what each identity may do. FSLogix’s requirement: each user can create their own profile folder and files, but not traverse into others’ folders. The canonical layout, set with icacls:

Identity NTFS permission on the share root Applies to Why
Creator Owner Modify Subfolders and files only The user who creates a folder owns and controls it
Authenticated Users (or your AVD users group) Modify, this folder only (no inherit) This folder only Lets users create their own folder, not see others’
Administrators / FSLogix admins Full control This folder, subfolders, files Admin management and cleanup

The effect: a user can create \\<account>.file.core.windows.net\profiles\<their-SID> and write their VHDX, but cannot open another user’s folder — privacy and correctness. Both layers exist because RBAC is the Azure-plane gate (does this identity get an SMB session) and NTFS is the OS-plane gate (what can they do once in). Skipping either fails closed — not open — and FSLogix falls back to a temp profile.

The division of labour, side by side:

Dimension Share-level RBAC (Layer 1) NTFS permissions (Layer 2)
Configured in Storage account → Access control (IAM) The file system, via icacls / Windows Explorer
Tool Azure portal / az role assignment / Bicep icacls from an Elevated-Contributor-mounted drive
Controls Whether you can connect to the share What you can do once connected
Granularity The whole share Per folder / per file
Default behaviour Set via “Default share-level permission” Inherited from parent unless overridden
Symptom when wrong Mount fails / read-only / access denied at connect Container attaches but can’t write / can read others

Step-by-step deep section: enabling Entra ID Kerberos correctly

Entra ID Kerberos makes the no-domain-controller story work, with three sub-steps people miss: enable the feature, grant admin consent to the app it creates, and configure the clients. Miss the consent and every mount fails with a logon error.

Sub-step A — enable the feature. On the account’s File shares → Active Directory blade, select Microsoft Entra Kerberos as the source. This registers the account as an app and sets directoryServiceOptions = AADKERB.

Sub-step B — grant admin consent. The app registration requests Microsoft Graph openid / profile / User.Read delegated permissions so it can issue tickets on behalf of signed-in users. A Global Administrator must grant admin consent in Entra ID → App registrations → (the storage account app) → API permissions → Grant admin consent. Until then, hosts can’t get tickets and you get STATUS_LOGON_FAILURE at mount.

Sub-step C — configure the clients. Entra-joined hosts must use cloud Kerberos. Current Windows 11 multi-session images support it, but you may need to set CloudKerberosTicketRetrievalEnabled = 1 via policy so the client retrieves cloud tickets. With the policy set, retrieval is automatic.

The lab below walks all of this with “done-when” checks. One thing easy to overlook in a network-locked environment is egress — the endpoints the host must reach:

Endpoint / port Used for Failure if blocked
login.microsoftonline.com (443) Entra auth + ticket retrieval No Kerberos ticket → mount logon failure
<account>.file.core.windows.net (445) SMB to the share Can’t reach the share at all
TCP 445 outbound SMB traffic Mount times out (ISPs often block 445)
Entra/Graph endpoints (443) App consent, identity Consent/identity operations fail

A note that saves hours: TCP 445 is frequently blocked by ISPs and corporate egress. Azure hosts reach Azure Files over the backbone fine, but if a mount from a laptop hangs, that’s 445, not permissions — test from a VM in Azure.

Step-by-step deep section: the FSLogix registry that actually matters

FSLogix is configured by values under HKLM\SOFTWARE\FSLogix\Profiles — two to turn it on, a few more to behave well. The canonical set, with default, valid values and gotcha:

Registry value (...\FSLogix\Profiles) Type What it does Default Set it to Gotcha
Enabled DWORD Turns profile containers on 0 (off) 1 Without this, FSLogix does nothing — most common “it’s not working”
VHDLocations MULTI_SZ UNC path(s) to the profile share (none) \\<acct>.file.core.windows.net\<share> Wrong/missing path → temp profile fallback
VolumeType SZ Disk format of the container VHDX (modern) VHDX VHDX supports dynamic + larger; prefer over VHD
FlipFlopProfileDirectoryName DWORD Folder name order: %username%%sid% vs %sid%%username% 0 1 Set to 1 so folders sort by username — operational nicety
SizeInMBs DWORD Max container size (dynamic grows to this) 30000 (~30 GB) 30000 or per policy Too small → container fills, profile can’t save
IsDynamic DWORD Dynamically-expanding vs fixed VHDX 1 (dynamic) 1 Dynamic saves space; fixed pre-allocates
DeleteLocalProfileWhenVHDShouldApply DWORD Remove a stale local profile that blocks the container 0 1 (with care) Deletes a local profile — only when you’re sure no real data is local
ProfileType DWORD Normal vs concurrent (RW/RO) access 0 (normal) 0 Non-zero only for specific RW+RO concurrent designs
LockedRetryCount / LockedRetryInterval DWORD Retries if the VHDX is locked 12 / 5 leave default Tune only for known contention
ReAttachIntervalSeconds / ReAttachRetryCount DWORD Re-attach attempts after a transient drop defaults leave default Raises resilience to brief share blips

The minimum is Enabled=1 plus VHDLocations; the behaviour-tuning set is applied together in lab Step 10 below. Where these come from in production — pick one source of truth, never two (if a GPO and the golden image set the same value, last-writer-wins gives you invisible drift; for cloud-only AVD, standardize on Intune and disable the rest):

Delivery mechanism Best for How it lands Caution
Group Policy (FSLogix ADMX) AD/Hybrid estates GPO writes the registry Needs AD; not the cloud-only story
Intune (settings catalog / config profile) Cloud-only Entra estates MDM writes the registry The right fit for Entra-joined AVD
Image bake-in (script in the golden image) Static config across a pool Set once, captured in image Re-bake to change values
Deployment script (CSE / DSC) One-off or IaC-driven Script runs at provision Drift if hosts diverge
Manual (regedit/PowerShell) Labs and testing only You type it Never for production fleets

Step-by-step deep section: profile exclusions and container hygiene

By default the entire profile goes into the VHDX — including transient caches that bloat the container and cloud-synced data already in the cloud. The tool is redirections.xml (referenced via RedirXMLSourceFolder), listing folders to exclude or include. Exclusions are about size and performance, not correctness — but a 28 GB container that takes 40 seconds to attach is a recurring complaint.

The judgement calls that matter:

Profile data Default (in container) Recommended Why
OneDrive synced folder In container Keep in container Smooth re-login; avoids re-sync storm each logon
Teams cache (classic) In container Often exclude transient cache Large, regenerates; bloats the disk
Outlook OST / search In container Keep (cached mode) Re-downloading a large OST every login is worse
Browser caches (temp) In container Exclude Pure transient bloat
%temp% / Windows temp In container Exclude Never needs to persist
Windows Defender/AV caches In container Exclude Large, regenerates, can cause locks

A minimal redirections.xml excluding transient bloat (tailor to your apps):

<?xml version="1.0"  encoding="UTF-8"?>
<FrxProfileFolderRedirection ExcludeCommonFolders="0">
  <Excludes>
    <Exclude Copy="0">AppData\Local\Temp</Exclude>
    <Exclude Copy="0">AppData\Local\Microsoft\Edge\User Data\Default\Cache</Exclude>
    <Exclude Copy="0">AppData\Local\Google\Chrome\User Data\Default\Cache</Exclude>
  </Excludes>
  <Includes>
    <!-- Explicitly keep things you care about even if a parent is excluded -->
  </Includes>
</FrxProfileFolderRedirection>

Point FSLogix at the folder holding it:

Set-ItemProperty -Path "HKLM:\SOFTWARE\FSLogix\Profiles" -Name "RedirXMLSourceFolder" `
  -Type String -Value "\\stfslogixlab.file.core.windows.net\profiles\redir"

Five hygiene rules keep attach times low and quotas sane: exclude transient caches (smaller VHDX → faster attach); keep cloud-synced data in the container (no re-sync storm); set a realistic SizeInMBs ceiling and use dynamic VHDX (pay for used space); schedule compaction on newer FSLogix (containers otherwise only grow); and don’t redirect everything — over-exclusion strips app state and defeats the point.

Architecture at a glance

Picture the path a profile takes at sign-in, because every later failure maps to one hop on it. A user authenticates to Entra ID and is brokered to a pooled session host — an Entra-joined Windows 11 multi-session VM with the FSLogix agent and its registry pointed (via VHDLocations) at an Azure Files SMB share. To attach the profile, the host asks Entra ID for a Kerberos ticket for the storage account (the app you consented to) and opens an SMB (port 445) session to the share. Two gates apply in order: share-level RBAC decides the session is allowed (the user has SMB Share Contributor, directly or via the default share-level permission), then NTFS ACLs decide the user may create and write their own folder (Creator Owner + users this-folder-only). FSLogix then creates or attaches Profile.vhdx, mounts it, and redirects C:\Users\<user> into it. At sign-out it flushes and detaches; the next login on any host repeats the dance and the profile follows.

Hold three things from that walk. First, the order is fixed: authenticate (Kerberos) → authorize to connect (RBAC) → authorize to act (NTFS) → attach (FSLogix). A failure at any gate falls back to a temp local profile, never forward — so an empty profile means “stopped at one of these gates” and your job is to find which. Second, the two authorization gates live in different planes (Azure IAM vs the Windows file system), set with different tools (az role assignment vs icacls) — which is why “I gave them access” is ambiguous until you say which. Third, the storage account is an Entra app; if its admin consent is missing you never reach the RBAC gate — the ticket request fails first. Keep that pipeline — ticket, connect, RBAC, NTFS, attach — as your probe order throughout.

Real-world scenario

Brightpath Legal runs a 600-seat pooled AVD estate for document-heavy legal teams across two Indian offices, entirely cloud-only: Entra-joined Windows 11 multi-session hosts, no on-prem AD, no Entra Domain Services. They were on UPD-on-a-file-server from an old RDS farm — profiles corrupted weekly and a single file VM was a scaling dead end. The brief to the two-person platform team: move to FSLogix on Azure Files with Entra ID Kerberos, no new AD, under a tight profile-storage budget (~₹14,000/month).

The build went cleanly until first user testing. They enabled Entra ID Kerberos on a Premium file share, set the default share-level permission to Contributor, set the FSLogix registry (Enabled=1, VHDLocations), and logged in a pilot user. The desktop loaded — with an empty profile. No error. The user worked, logged out, lost everything. Classic temp-profile fallback.

The diagnosis walked the pipeline in order. Kerberos? The FSLogix/SMB event logs showed the mount failing before any file operation — STATUS_LOGON_FAILURE. That ruled out NTFS and pointed at authentication. The storage account’s app registration in Entra: admin consent had not been granted — they’d enabled the feature but skipped the consent click. One Global Admin, one Grant admin consent, and the mount succeeded — straight into the second failure: the container attached read-only, FSLogix logging it couldn’t write. The default permission was correct (Contributor), but the NTFS root ACL was at the storage default, with no Modify for the users group to create their folder. The admin re-mounted with an Elevated Contributor assignment and ran the canonical icacls. Next login: created, read-write, persisted.

A week later, containers ballooned. The legal teams live in Outlook cached mode and OneDrive; with no exclusions every cache went into the VHDX — average 22 GB, attach 35–50 s, Premium quota climbing. They added a redirections.xml excluding transient browser/Teams caches (but kept OneDrive and the Outlook OST to avoid a re-sync storm), set SizeInMBs to a 30 GB ceiling with dynamic VHDX, and enabled compaction. Containers fell to ~9 GB, attach to ~8 s. Seeing the real IOPS profile, they moved Premium → transaction-optimized, landing the bill at ₹12,400/month.

Eight months on, the estate runs on a single storage account, has survived multiple golden-image re-bakes (profiles untouched — they live on the share), and scaled 50 → 600 seats with zero profile-infrastructure change. The post-mortem note: “Empty profile = stopped at a gate. Walk them in order — ticket, connect, write — never blame FSLogix until all three are clear.”

The incident as a pipeline walk — the order of checks is the method:

Stage Symptom What they checked Finding Fix
1 Empty profile, no error SMB/FSLogix event log Mount failed: STATUS_LOGON_FAILURE (auth problem — not NTFS)
2 Logon failure Storage account app in Entra Admin consent not granted Grant admin consent
3 Now mounts, still empty FSLogix log: write denied Container attached read-only NTFS root ACL missing Modify
4 Read-only NTFS ACL on the share Default ACL, no user Modify icacls canonical layout
5 Works, but huge & slow Container size, attach time 22 GB, every cache included redirections.xml exclusions
6 Tuned Tier vs real IOPS Premium over-provisioned Move to transaction-optimized

Advantages and disadvantages

The cleanest cloud-only profile design Azure offers, trading AD’s familiarity for a two-layer permission discipline. Weigh it honestly:

Advantages (why this model wins) Disadvantages (why it bites)
No domain controller — cloud-only Entra-joined hosts, nothing to patch or scale Newer than AD DS auth; some images/policies need the cloud-Kerberos toggle set
Azure Files gives built-in redundancy (LRS/ZRS) and scales to thousands of profiles on one account Two authorization layers (RBAC and NTFS) — getting one right and the other wrong fails closed silently
Profiles survive host reimaging entirely — golden-image rebuilds never touch user data A failed gate falls back to a temp profile with no error — data loss looks like “it worked”
FSLogix is the industry-standard, app-compatible profile solution (OneDrive/Teams/Outlook friendly) All config is registry-driven — no UI; misconfiguration is a silent empty profile
Container size and tier are tunable for cost (dynamic VHDX, transaction-optimized tier, exclusions) Containers only grow unless you exclude caches and schedule compaction
Admin consent + RBAC + NTFS map to clean, auditable least-privilege roles Setup ordering is unforgiving — skip admin consent and nothing mounts
Works for Windows 365 Cloud PCs and AVD alike TCP 445 egress and specific endpoints must be reachable — network locks break it subtly

This model is right for any cloud-only or cloud-first AVD/W365 estate that wants rid of profile servers and AD plumbing. It is not the pick if you run heavy on-prem AD and want one Kerberos model across file servers and Azure Files — there, AD DS auth is more uniform. The disadvantages are about discipline and ordering, not capability: do the steps in sequence, set the registry from one source, apply exclusions, and the model is rock-solid.

Hands-on lab

This is the centerpiece. You’ll build a complete FSLogix-on-Azure-Files setup with Entra ID Kerberos end to end — storage account and SMB share, Kerberos enabled and consented, both permission layers, the FSLogix registry, a redirections file, validation, and teardown — three ways (portal, az CLI, Bicep). Run the CLI parts in Cloud Shell (Bash) except where a step must run on a Windows host (PowerShell), called out explicitly.

Lab prerequisites. A subscription where you are Owner, Global Administrator in the tenant (to grant admin consent), and one Entra-joined Windows 11 multi-session host you can RDP into — simplest via a one-host pool from Deploy Your First AVD Pooled Host Pool End to End. Everything else the lab creates. Region: centralindia.

The lab at a glance:

Phase Steps Where Outcome
A — Storage & share 1–3 Cloud Shell / portal Account + profiles SMB share
B — Entra ID Kerberos 4–5 CLI + Entra portal Kerberos enabled + admin consent
C — Permissions (both layers) 6–8 IAM + session host RBAC + NTFS set
D — FSLogix on the host 9–11 Session host (PowerShell) Agent + registry + redirections
E — Validate 12–13 Session host Container attaches read-write
F — Teardown 14 Cloud Shell Everything deleted

Phase A — storage account and SMB share

Step 1 — variables and resource group.

RG=rg-fslogix-lab
LOC=centralindia
ST=stfslogixlab$RANDOM   # storage account names are global + lowercase, 3–24 chars
SHARE=profiles
az group create -n $RG -l $LOC -o table

Expected: a resource-group row with provisioningState: Succeeded.

Step 2 — create the storage account (Standard, with large file shares enabled; the directory/Kerberos option follows in Step 4).

az storage account create -n $ST -g $RG -l $LOC \
  --sku Standard_LRS --kind StorageV2 \
  --enable-large-file-share \
  --https-only true \
  -o table

Expected: an account row, provisioningState: Succeeded, kind: StorageV2. (Use Standard_ZRS for zone redundancy; LRS is fine for a lab.)

Step 3 — create the file share with a quota (100 GB here; size for users × container-size in production).

az storage share-rg create --storage-account $ST -g $RG \
  --name $SHARE --quota 100 --access-tier TransactionOptimized -o table

Expected: a share named profiles. Validate it exists:

az storage share-rg show --storage-account $ST -g $RG --name $SHARE \
  --query "{name:name, quota:properties.shareQuota, tier:properties.accessTier}" -o table

Portal (Steps 1–3): Create a resource → Storage account (Standard, LRS/ZRS, Central India, large file shares enabled) → File shares → + File shareprofiles, set quota and tier.

Phase B — enable Entra ID Kerberos and grant consent

Step 4 — enable Microsoft Entra ID Kerberos. Sets identity-based auth to AADKERB and registers the account as an app.

az storage account update -n $ST -g $RG \
  --enable-files-aadkerb true -o table

Expected: the update succeeds. Validate the directory option flipped:

az storage account show -n $ST -g $RG \
  --query "azureFilesIdentityBasedAuthentication.directoryServiceOptions" -o tsv
# Expected output:  AADKERB

Portal equivalent: Storage account → File shares → Active Directory: Not configured → Set up → Microsoft Entra Kerberos → Save.

Step 5 — grant admin consent to the storage account app (the step everyone forgets). Enabling Kerberos created an app registration that needs its Graph permissions consented — a portal/Entra action (no single az command for the consent click):

  1. In the portal go to Microsoft Entra ID → App registrations → All applications.
  2. Search for the app named like [Storage Account] <your-account-name>.file.core.windows.net.
  3. Open it → API permissions. You’ll see Microsoft Graph permissions (e.g. openid, profile, User.Read) with status “Not granted”.
  4. Click Grant admin consent for <tenant>Yes.

Expected/validate: every permission row shows a green tick and “Granted for <tenant>. Mandatory — until it’s green, every mount fails with a logon error and nothing downstream works.

Phase B is done when two things are true: directoryServiceOptions reads AADKERB (Step 4) and the app’s API permissions show “Granted for <tenant>” in green (Step 5).

Phase C — both permission layers

Step 6 — Layer 1: assign share-level RBAC. Give your AVD users Contributor and yourself Elevated Contributor (to set NTFS in Step 8), scoped to the account.

ST_ID=$(az storage account show -n $ST -g $RG --query id -o tsv)

# The AVD users group (replace with your group's object id)
USERS_GROUP_OID=<object-id-of-your-avd-users-group>
az role assignment create --assignee-object-id $USERS_GROUP_OID \
  --assignee-principal-type Group \
  --role "Storage File Data SMB Share Contributor" \
  --scope $ST_ID -o table

# Yourself, elevated, to set NTFS ACLs
ME_OID=$(az ad signed-in-user show --query id -o tsv)
az role assignment create --assignee-object-id $ME_OID \
  --assignee-principal-type User \
  --role "Storage File Data SMB Share Elevated Contributor" \
  --scope $ST_ID -o table

Expected: two role-assignment JSON/table rows. Validate:

az role assignment list --scope $ST_ID \
  --query "[].{who:principalName, role:roleDefinitionName}" -o table

Step 7 — (recommended) set a default share-level permission so all authenticated Entra identities get a baseline role without per-user assignments — the scalable pattern for hundreds of users.

az storage account update -n $ST -g $RG \
  --default-share-permission StorageFileDataSmbShareContributor -o table

Expected: succeeds. Validate it reads back as StorageFileDataSmbShareContributor:

az storage account show -n $ST -g $RG \
  --query "azureFilesIdentityBasedAuthentication.defaultSharePermission" -o tsv

With a default share-level permission of StorageFileDataSmbShareContributor you can skip the per-group assignment in Step 6 for the users — keep Elevated Contributor on yourself for NTFS work. The valid values map to the same RBAC roles from the Layer-1 table: None, StorageFileDataSmbShareReader, ...Contributor (the FSLogix baseline), and ...ElevatedContributor (usually too broad as a default).

Step 8 — Layer 2: set NTFS permissions. Do this from a machine that has mounted the share with your Elevated-Contributor identity — typically the session host (PowerShell). Mount using your Entra identity (the OS uses your Kerberos ticket; no key):

# On the Entra-joined session host, as your (Elevated Contributor) user:
net use Z: \\stfslogixlab.file.core.windows.net\profiles

Expected: The command completed successfully. Now apply the canonical FSLogix NTFS layout to the share root (Z:\):

# Users can create their own folder (this folder only, no inherit into siblings)
icacls Z:\ /grant "YourTenant\AVD Users:(M)"
# Creator Owner gets Modify on what they create (subfolders + files)
icacls Z:\ /grant "Creator Owner:(OI)(CI)(IO)(M)"
# Admins full control
icacls Z:\ /grant "BUILTIN\Administrators:(OI)(CI)(F)"
# Remove broad inherited rights you don't want users to have on each other's folders
icacls Z:\ /remove:g "Authenticated Users"

Expected: Successfully processed 1 files for each. Validate the resulting ACL:

icacls Z:\

You should see your users group with (M) on this folder, CREATOR OWNER with (OI)(CI)(IO)(M), and Administrators (F). The flag cheat-sheet so the icacls lines aren’t magic:

icacls flag Meaning
(M) Modify (read/write/delete, not change-permissions)
(F) Full control
(OI) Object inherit (applies to files)
(CI) Container inherit (applies to subfolders)
(IO) Inherit only (the entry itself doesn’t apply to this folder)
/remove:g Remove a granted ACE for the principal

Phase D — FSLogix on the session host

Step 9 — install the FSLogix agent (it ships in current Windows 11 multi-session/AVD images; install only if absent):

# On the session host (PowerShell as admin) — only if FSLogix isn't already present
# Download from aka.ms/fslogix-latest, extract, then:
.\x64\Release\FSLogixAppsSetup.exe /install /quiet /norestart

Expected: the frxsvc (FSLogix Apps Service) is installed. Validate:

Get-Service frxsvc | Select-Object Status, Name, DisplayName
# Expected: Status = Running

Step 10 — set the FSLogix registry (the heart of the config), on the host as admin:

$key = "HKLM:\SOFTWARE\FSLogix\Profiles"
New-Item -Path $key -Force | Out-Null
Set-ItemProperty -Path $key -Name "Enabled"                              -Type DWord       -Value 1
Set-ItemProperty -Path $key -Name "VHDLocations"                         -Type MultiString -Value "\\stfslogixlab.file.core.windows.net\profiles"
Set-ItemProperty -Path $key -Name "VolumeType"                           -Type String      -Value "VHDX"
Set-ItemProperty -Path $key -Name "FlipFlopProfileDirectoryName"         -Type DWord       -Value 1
Set-ItemProperty -Path $key -Name "SizeInMBs"                            -Type DWord       -Value 30000
Set-ItemProperty -Path $key -Name "IsDynamic"                            -Type DWord       -Value 1
Set-ItemProperty -Path $key -Name "DeleteLocalProfileWhenVHDShouldApply" -Type DWord       -Value 1

Expected: no errors. Validate the values landed:

Get-ItemProperty -Path $key | Select-Object Enabled, VHDLocations, VolumeType, SizeInMBs
# Expected: Enabled=1, VHDLocations points at your share, VolumeType=VHDX, SizeInMBs=30000

Step 11 — (optional) add the redirections.xml exclusions. Create a redir folder on the share, drop redirections.xml there, and point FSLogix at it:

New-Item -ItemType Directory -Path "Z:\redir" -Force | Out-Null
# Save the redirections.xml from the earlier section into Z:\redir\redirections.xml
Set-ItemProperty -Path $key -Name "RedirXMLSourceFolder" -Type String `
  -Value "\\stfslogixlab.file.core.windows.net\profiles\redir"

FSLogix reads it at the next logon.

Phase E — validate an attached container end to end

Step 12 — sign in as a test user and confirm the container attaches read-write. Add a test user (in the AVD Users group / covered by the default permission) to the host pool’s app group, then sign in as that user via the AVD client. After the desktop loads:

az storage file list --account-name $ST --share-name $SHARE \
  --auth-mode login -o table
# Expected: a folder named after the test user's SID/username, plus the 'redir' folder

Step 13 — confirm FSLogix loaded the profile (not a temp fallback). Check the FSLogix log and event log on the host:

# FSLogix logs live here:
Get-Content "C:\ProgramData\FSLogix\Logs\Profile\*.log" -Tail 40
# Look for: "Loading Profile" / "Attached VHD" / "VirtualDisk attach succeeded"
# A line like "ProfileType ... TEMP" or "falling back" means it did NOT attach — go to troubleshooting.

Also confirm in the FSLogix event log:

Get-WinEvent -LogName "Microsoft-FSLogix-Apps/Operational" -MaxEvents 20 |
  Format-Table TimeCreated, Id, LevelDisplayName, Message -Wrap

Expected: events showing the container located, attached, and loaded — no temp-profile/fallback warning. A fallback maps straight to the troubleshooting table: logon failure → Kerberos/consent, write-denied → NTFS, access-denied at connect → RBAC.

The validation checklist — what “working” looks like at each layer:

Check Where “Good” signal “Bad” signal → section
Share mounts net use on host “completed successfully” logon failure → Kerberos/consent
Per-user folder created az storage file list folder + Profile.vhdx exists nothing created → NTFS/RBAC
Disk attached Disk Management / Get-Disk extra VHDX disk present no disk → attach error
FSLogix log C:\ProgramData\FSLogix\Logs “attach succeeded” “TEMP”/“fallback” → troubleshooting
Profile persists log out / log in data survives empty again → read-only/quota

Phase F — teardown

Step 14 — delete everything so the lab costs nothing. Remove the role assignments, then the resource group:

# Remove the role assignments you created (optional; deleting the RG removes scoped ones)
az role assignment delete --scope $ST_ID \
  --role "Storage File Data SMB Share Elevated Contributor" --assignee $ME_OID 2>/dev/null

# Delete the whole resource group (storage account + share) — irreversible
az group delete -n $RG --yes --no-wait

On the session host, undo the FSLogix registry if you’ll reuse the host:

Remove-Item -Path "HKLM:\SOFTWARE\FSLogix\Profiles" -Recurse -Force
net use Z: /delete

Expected: the resource group enters Deleting. Confirm it’s gone:

az group exists -n $RG     # Expected: false (after a minute or two)

The storage account’s app registration in Entra can be removed manually from App registrations if you want a fully clean tenant.

The Bicep version (commit this instead of clicking)

For repeatable, reviewed infrastructure, here is storage + Kerberos + default-permission + share + RBAC as Bicep. NTFS (icacls) and the FSLogix registry stay outside IaC — they run inside the OS, delivered via Intune/CSE.

@description('Region for the FSLogix profile storage')
param location string = resourceGroup().location

@description('Globally-unique storage account name (lowercase, 3-24 chars)')
param storageAccountName string

@description('Object ID of the AVD users group that gets SMB Contributor')
param avdUsersGroupObjectId string

var shareName = 'profiles'

resource sa 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageAccountName
  location: location
  sku: { name: 'Standard_LRS' }   // or Standard_ZRS for zone redundancy
  kind: 'StorageV2'
  properties: {
    supportsHttpsTrafficOnly: true
    largeFileSharesState: 'Enabled'
    minimumTlsVersion: 'TLS1_2'
    azureFilesIdentityBasedAuthentication: {
      directoryServiceOptions: 'AADKERB'                 // Entra ID Kerberos
      defaultSharePermission: 'StorageFileDataSmbShareContributor'  // baseline for all users
    }
  }
}

resource fileService 'Microsoft.Storage/storageAccounts/fileServices@2023-05-01' = {
  parent: sa
  name: 'default'
}

resource profileShare 'Microsoft.Storage/storageAccounts/fileServices/shares@2023-05-01' = {
  parent: fileService
  name: shareName
  properties: {
    shareQuota: 100                 // GB; size for users x container size in prod
    accessTier: 'TransactionOptimized'
    enabledProtocols: 'SMB'
  }
}

// Layer 1 RBAC: AVD users group -> SMB Share Contributor on the account
resource usersContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(sa.id, avdUsersGroupObjectId, 'smb-contributor')
  scope: sa
  properties: {
    // Storage File Data SMB Share Contributor
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions',
      '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')
    principalId: avdUsersGroupObjectId
    principalType: 'Group'
  }
}

output storageAccountName string = sa.name
output profileShareUnc string = '\\\\${sa.name}.file.core.windows.net\\${shareName}'

Deploy it and read the UNC straight into your FSLogix VHDLocations:

az deployment group create -g rg-fslogix-lab \
  --template-file fslogix.bicep \
  --parameters storageAccountName=stfslogixlab$RANDOM \
               avdUsersGroupObjectId=<your-group-object-id> \
  --query "properties.outputs.profileShareUnc.value" -o tsv

What Bicep cannot do here: the admin consent (Step 5) and the NTFS icacls (Step 8) aren’t ARM operations — consent is an Entra tenant action, NTFS lives in the file system. Template the storage plane; script the OS/identity plane.

Common mistakes & troubleshooting

Most of your first-time effort goes here. Every failure below ends in the same visible symptom — an empty or non-persisting profile — so you diagnose by walking the pipeline (ticket → connect → write → attach) and matching the log line. The playbook, ordered by how often it bites:

# Symptom Root cause Confirm (exact place / command) Fix
1 Empty profile, no error; mount fails STATUS_LOGON_FAILURE Admin consent not granted on the storage account app Entra → App registrations → (account app) → API permissions shows “Not granted” Grant admin consent (Step 5)
2 Container attaches read-only; FSLogix log “write denied” NTFS ACL missing user Modify (Layer 2) icacls Z:\ shows no Modify for users group Apply canonical icacls (Step 8)
3 “You do not have permission to access” at connect Share-level RBAC missing (Layer 1) az role assignment list --scope <acct> lacks Contributor; default permission None Assign Contributor / set default permission
4 Mount hangs / times out from a non-Azure machine TCP 445 blocked by ISP/egress Test-NetConnection <acct>.file.core.windows.net -Port 445 fails Test from an Azure VM; use Private Endpoint
5 Profile loads but is a temp profile every login Enabled=0, wrong VHDLocations, or stale local profile blocking FSLogix log “TEMP”/“fallback”; check registry Set Enabled=1, fix UNC, set DeleteLocalProfileWhenVHDShouldApply=1
6 Profile can’t save / disk full mid-session SizeInMBs too small or share quota exhausted Container at ceiling; az storage share-rg show quota near full Raise SizeInMBs; raise share quota; add exclusions
7 Logins take 30–60 s Bloated container (no exclusions) / Premium-vs-tier mismatch Container 20 GB+; attach time in FSLogix log Add redirections.xml; enable compaction
8 0x0000000e / attach error in event log VHDX locked by another session or a crashed prior session FSLogix event log attach failure; another host holds the file Ensure single-session profile; clear stale lock; check ProfileType
9 Kerberos works for hybrid users, fails for cloud-only users Client not retrieving cloud Kerberos tickets CloudKerberosTicketRetrievalEnabled not set on host Set the policy/registry to 1 on all hosts
10 icacls itself fails “Access is denied” You mounted as Contributor, not Elevated Your role on the account is Contributor only Re-assign Elevated Contributor, re-mount, retry
11 Works on one host, temp profile on another Registry driftVHDLocations only on some hosts Compare Get-ItemProperty ...FSLogix\Profiles across hosts Deliver registry from one source (Intune)
12 Container created but app settings still reset Over-exclusion — you excluded folders apps need redirections.xml excludes AppData\Roaming\... app state Narrow exclusions to transient caches only

Three reading habits that save the most time:

Distinction The trap How to tell them apart
Auth failure vs NTFS failure Both end in an empty profile A logon failure in the SMB/FSLogix log = auth (Kerberos/consent); a write-denied = NTFS
RBAC vs NTFS “access denied” Both say “denied” RBAC denial happens at connect (can’t even mount); NTFS denial happens after mount on a file op
Temp-profile fallback vs real load The desktop looks fine either way The FSLogix log explicitly says TEMP/fallback, and no VHDX disk is attached in Disk Management

The diagnostic order to internalize: (1) does the share mount (net use)? No → Kerberos/consent/445. Yes → (2) does a per-user folder + Profile.vhdx get created? No → RBAC or NTFS. Yes → (3) is it read-write (Disk Management + FSLogix log)? No → NTFS Modify / quota. Yes → it works; any remaining “lost settings” is exclusions.

Best practices

Crisp, production-grade rules from estates that run this at scale:

Security notes

Built on least-privilege identity, the posture is good if you keep the layers tight:

Cost & sizing

What drives the bill is the file share: capacity (GB across all containers), the tier (Premium provisioned IOPS vs Standard pay-as-you-go), redundancy (LRS < ZRS < GRS), and egress (negligible — traffic stays on the backbone). FSLogix is free and Entra ID Kerberos adds no cost. The lever is right-tiering and keeping containers small.

Cost driver What it is How to right-size Rough figure
Share capacity (Standard) GB stored, pay-as-you-go Exclusions + dynamic VHDX + compaction ~₹4–6 / GB / month (transaction-optimized)
Transactions (Standard) Per-operation charges Fewer, larger I/O; right tier Small for typical profile I/O
Provisioned share (Premium) You pay for provisioned GB/IOPS Only if you measured high IOPS need Higher baseline; over-provisioned easily
Redundancy uplift LRS → ZRS → GRS Pick the lowest that meets your RPO ZRS modest uplift; GRS ~2×
Per-container size Avg VHDX GB × users Exclusions; SizeInMBs ceiling 5–10 GB/user typical with exclusions

The tier decision — most FSLogix estates do not need Premium:

File tier When it’s right for FSLogix Watch out
Transaction-optimized (Standard) Most pooled AVD profile workloads Transaction charges if I/O is very chatty
Hot (Standard) General-purpose, balanced Slightly higher storage, lower transactions
Premium (provisioned) Very large/IOPS-heavy estates that measured the need Easy to over-provision and overpay

A worked example: 600 users × 9 GB average after exclusions = ~5.4 TB. On a transaction-optimized Standard share at ~₹5/GB that’s roughly ₹27,000/month before transactions — most estates land lower because dynamic VHDX bills used, not max, space. The classic over-spend is putting that workload on Premium “to be safe”, provisioning IOPS it never uses. Free-tier note: there’s no free tier for Azure Files sized for profiles — the lab stays cheap only because it’s tiny; delete it.

Size the quota for users × average-container-GB × headroom (1.3–1.5×), enable large file shares, and alert on share-used. Under-sizing the quota or SizeInMBs causes mid-session “can’t save” failures — size generously; it’s cheap relative to a data-loss ticket.

Interview & exam questions

Mapped to AZ-140 (Azure Virtual Desktop Specialty) and the storage/identity portions of AZ-104.

Q1. Why does pooled AVD need FSLogix when personal desktops don’t? Pooled hosts are non-persistent and load-balanced, so a user can land on any host and must not depend on a local C: profile. FSLogix stores the profile as a VHDX on shared storage and attaches it at logon, so it follows the user to whichever host they get. Personal desktops keep the profile locally because the user always returns to the same VM.

Q2. What are the two authorization layers for FSLogix on Azure Files, and what does each control? Share-level RBAC (Azure roles like Storage File Data SMB Share Contributor) controls whether an identity may connect to the share at all. NTFS permissions (set with icacls) control what they may do once connected. Both must allow the operation; either being wrong fails closed.

Q3. Which RBAC role do AVD users need, and which does the admin setting permissions need? Users need Storage File Data SMB Share Contributor. The admin who sets NTFS ACLs needs Storage File Data SMB Share Elevated Contributor, because modifying NTFS permissions is itself privileged and plain Contributor cannot do it.

Q4. What does Microsoft Entra ID Kerberos give you over AD DS authentication for Azure Files? It authenticates SMB sessions using Kerberos tickets issued by Entra ID with no domain controller required — ideal for cloud-only, Entra-joined hosts. AD DS authentication requires you to run domain controllers (your own or via Entra Domain Services).

Q5. After enabling Entra ID Kerberos, mounts fail with a logon error. Most likely cause? Admin consent has not been granted to the storage account’s app registration in Entra ID. Enabling the feature creates the app with Graph permissions “not granted”; a Global Admin must consent before any host can obtain a ticket.

Q6. Name the two registry values that are mandatory to turn FSLogix on. Enabled (DWORD = 1) and VHDLocations (MULTI_SZ, the UNC path to the share), both under HKLM\SOFTWARE\FSLogix\Profiles. Without Enabled=1 FSLogix does nothing; without a correct VHDLocations it can’t find the share and falls back to a temp profile.

Q7. A user’s container attaches read-only. Which layer is wrong and how do you confirm? The NTFS layer (Layer 2) — the user lacks Modify. Confirm with icacls on the share root (no Modify for the users group) and the FSLogix log showing write-denied. RBAC is fine because the mount succeeded; the failure is a file operation after connecting.

Q8. Why keep OneDrive inside the container but exclude transient caches? Excluding OneDrive forces a full re-sync every login (network storm, slow first use); keeping it preserves the synced state for a fast experience. Transient caches (browser/Teams temp) are excluded because they regenerate and only bloat the disk.

Q9. What’s the difference between dynamic and fixed VHDX, and which is preferred? A dynamic VHDX grows with actual data up to SizeInMBs (you pay for used space); a fixed VHDX pre-allocates the full size. Dynamic is preferred for cost — most profiles use a fraction of their ceiling — with periodic compaction to reclaim freed space.

Q10. A mount hangs from your laptop but works on the session host. Why? TCP port 445 (SMB) is frequently blocked by ISP/corporate egress, so the laptop can’t reach Azure Files, while the in-Azure host reaches it over the backbone. Validate mounts from an Azure VM, or use a Private Endpoint.

Q11. What is the symptom when FSLogix can’t attach a container, and why is it dangerous? It falls back to a temporary local profile — a working but empty desktop with no error; the user works and loses it at logout. It’s dangerous because it looks like success, so you must alert on FSLogix fallback/temp events to catch silent data loss.

Q12. How do you grant share access to hundreds of users without hundreds of role assignments? Set the account’s default share-level permission to Contributor, granting all authenticated Entra identities that baseline automatically. Use explicit per-identity assignments only for exceptions, and keep Elevated Contributor for admins.

Quick check

  1. Which two registry values are the bare minimum to enable FSLogix profile containers?
  2. You enabled Entra ID Kerberos but every mount returns a logon failure. What did you most likely skip?
  3. A container attaches but is read-only. Which permission layer is wrong — RBAC or NTFS?
  4. Why should OneDrive stay inside the container while browser caches are excluded?
  5. Which RBAC role does an admin need to run icacls to set NTFS permissions on the share?

Answers

  1. Enabled = 1 and VHDLocations (the UNC path to the share), both under HKLM\SOFTWARE\FSLogix\Profiles.
  2. Granting admin consent to the storage account’s app registration in Entra ID — without it, hosts can’t get Kerberos tickets and the mount fails with STATUS_LOGON_FAILURE.
  3. NTFS (Layer 2). RBAC let the mount succeed; the user lacks Modify to write the file, so the failure is on a file operation after connecting.
  4. Keeping OneDrive in the container avoids a full re-sync storm every login; browser caches are pure transient bloat that regenerates, so excluding them keeps the VHDX small and attach fast.
  5. Storage File Data SMB Share Elevated Contributor — modifying NTFS ACLs is privileged and plain Contributor can’t do it.

Glossary

Next steps

AzureFSLogixAzure FilesEntra ID KerberosAVDProfile ContainersSMBIdentity
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading