Getting Windows Native Docker Containers Working — The Hard Way

Posted April 26, 2026 | Machine: Windows 11 build 26200


The Goal

I wanted to run Windows-native Docker containers on my Windows 11 machine. Not Linux containers running inside a WSL2 VM — actual Windows containers that run directly on the Windows kernel via Hyper-V. Native containers are significantly more efficient: no full Linux VM, no gigabyte-sized Linux base images, and direct integration with Windows-only runtimes like .NET Framework, IIS, MSMQ, and COM+.

Sounds simple. It was not.

This post documents everything I did — every failed attempt, every diagnostic command, every dead end — before I found the actual root cause and fixed it. If you are hitting a wall with Docker Desktop on Windows, something in here will probably save you hours.


The First Sign of Trouble: Installer Silently Fails

Docker Desktop had been installed and uninstalled a few times on this machine. When I went to do a clean reinstall, the installer would launch, show a progress bar for a few seconds, and then disappear. No error dialog. No log in the obvious places. Just... gone.

Re-running it produced the same result.

At this point I assumed it was a straightforward "junk left over from a previous install" problem, so I went through a full manual cleanup.


Attempt 1: Full Manual Uninstall and Cleanup

Phase 1 — Stop and Uninstall

# Stop Docker Desktop if running
Stop-Process -Name "Docker Desktop" -Force -ErrorAction SilentlyContinue

# Stop Docker service
Stop-Service com.docker.service -ErrorAction SilentlyContinue

Then uninstalled Docker Desktop via Apps → Installed apps and rebooted.

Phase 2 — Remove All Leftovers

After the reboot, in Administrator PowerShell:

# Kill any Docker processes still holding file handles
Stop-Process -Name "Docker Desktop","com.docker.backend","com.docker.proxy","vpnkit","dockerd" -Force -ErrorAction SilentlyContinue
Stop-Service com.docker.service -ErrorAction SilentlyContinue

# Fix ownership/ACLs on protected paths so removal doesn't fail silently
$protectedPaths = @(
    "C:\ProgramData\DockerDesktop",
    "C:\ProgramData\Docker"
)

foreach ($pp in $protectedPaths) {
    if (Test-Path $pp) {
        Write-Host "Resetting ownership/ACLs on $pp"
        takeown /F $pp /A /R /D Y | Out-Null
        icacls $pp /inheritance:e /T /C | Out-Null
        icacls $pp /grant:r "SYSTEM:(OI)(CI)F" "Administrators:(OI)(CI)F" /T /C | Out-Null
    }
}

# Remove all Docker folder remnants
$paths = @(
    "C:\Program Files\Docker",
    "C:\ProgramData\DockerDesktop",
    "C:\ProgramData\Docker",
    "$env:APPDATA\Docker",
    "$env:LOCALAPPDATA\Docker",
    "$env:LOCALAPPDATA\Docker Desktop",
    "$env:USERPROFILE\.docker"
)

foreach ($p in $paths) {
    if (Test-Path $p) {
        Write-Host "Removing $p"
        Remove-Item $p -Recurse -Force -ErrorAction SilentlyContinue
    }
}

# Verify what remains
$paths | ForEach-Object { "{0} => {1}" -f $_, (Test-Path $_) }

Note: Deleting $env:USERPROFILE\.docker removes local Docker login tokens and contexts. Expected for a clean reset.

I also cleaned up any old Hyper-V VM artifacts:

Get-VM -Name "DockerDesktopVM" -ErrorAction SilentlyContinue | Remove-VM -Force

Phase 3 — Remove Docker from WSL Distros

In each WSL distro (Ubuntu, etc.):

sudo systemctl stop docker 2>/dev/null || true
sudo apt-get purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker.io docker-doc docker-compose podman-docker
sudo apt-get autoremove -y --purge
sudo rm -rf /var/lib/docker /var/lib/containerd /etc/docker ~/.docker

Phase 4 — Verify Complete Removal

Windows checks before reboot:

Get-Command docker -ErrorAction SilentlyContinue
Get-Service com.docker.service -ErrorAction SilentlyContinue

$paths = @(
    "C:\ProgramData\DockerDesktop",
    "C:\ProgramData\Docker",
    "$env:APPDATA\Docker",
    "$env:LOCALAPPDATA\Docker",
    "$env:LOCALAPPDATA\Docker Desktop",
    "$env:USERPROFILE\.docker"
)
$paths | ForEach-Object { "$_ => " + (Test-Path $_) }

Windows checks after reboot:

# Service should be gone
Get-Service com.docker.service -ErrorAction SilentlyContinue

# Docker CLI should not resolve
where.exe docker 2>$null
Get-Command docker -All -ErrorAction SilentlyContinue

# Context store should be absent
Test-Path "$env:USERPROFILE\.docker\contexts"

# No Docker uninstall entry in registry
Get-ItemProperty `
    "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*", `
    "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" `
    -ErrorAction SilentlyContinue |
    Where-Object { $_.DisplayName -match "Docker" } |
    Select-Object DisplayName,DisplayVersion,Publisher

WSL checks:

command -v docker || echo "docker CLI not found"
command -v dockerd || echo "dockerd not found"
ls -la /var/lib/docker 2>/dev/null || echo "/var/lib/docker removed"
ls -la /var/lib/containerd 2>/dev/null || echo "/var/lib/containerd removed"

Everything came back clean. All paths gone, no service, no registry entry. Rebooted again and ran the Docker Desktop installer as Administrator.

Same result. Installer launched and silently vanished.


Attempt 2: Diagnosing "Windows Containers Disabled"

After eventually getting Docker installed via a different approach, I hit the next wall immediately when I tried to switch to Windows containers:

switching to windows engine: windows containers have been disabled for this installation

This message is maddeningly vague. It doesn't tell you whether the problem is Windows configuration, Docker's settings, or something else entirely. I went through every check.

Check 1 — Windows Features

Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V | Select-Object FeatureName,State
Get-WindowsOptionalFeature -Online -FeatureName Containers | Select-Object FeatureName,State
Get-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform | Select-Object FeatureName,State
Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux | Select-Object FeatureName,State
bcdedit /enum | findstr /i hypervisorlaunchtype

All Enabled. Hypervisor launch type Auto. Nothing wrong here. If yours are disabled:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All -All -NoRestart
Enable-WindowsOptionalFeature -Online -FeatureName Containers -All -NoRestart
shutdown /r /t 0

Check 2 — Docker Policy Files

# Check for admin policy file
$admin = "C:\ProgramData\DockerDesktop\admin-settings.json"
if (Test-Path $admin) { Get-Content $admin }

# Check user settings for disable flags
$user = "$env:APPDATA\Docker\settings.json"
if (Test-Path $user) { Get-Content $user }

Looking for disableWindowsContainers: true. Nothing — no policy file, no disable flag.

Check 3 — Registry Policy Keys

No Docker-related policy keys in the registry. No group policy forcing a block. Personal machine, not domain-joined.

Check 4 — Restart Service and Force Daemon Switch

Start-Service com.docker.service
Get-Service com.docker.service | Select-Object Name,Status,StartType

& "$Env:ProgramFiles\Docker\Docker\Docker Desktop.exe"
& "$Env:ProgramFiles\Docker\Docker\DockerCli.exe" -SwitchDaemon

docker context ls
docker info --format "{{.OSType}}"

Still linux. Same disabled error on -SwitchDaemon.


Attempt 3: In-Place Reinstall

The recommended next step for the "windows containers disabled" error is an in-place reinstall — run the new installer over the existing installation without uninstalling first. This sometimes re-initializes the Windows engine capability that gets stuck in a WSL-only state.

Downloaded the latest installer, ran it as Administrator over the existing install, rebooted.

Same error.


Attempt 4: Full Clean Reinstall (Again)

Went back through the entire Phase 1–4 process above. Confirmed every path was removed. Rebooted twice. Installed from scratch.

When it came time to switch daemons:

& "$Env:ProgramFiles\Docker\Docker\DockerCli.exe" -SwitchDaemon

Same error.


The Actual Root Cause: Corrupted ACL on C:\ProgramData\DockerDesktop

After all of this, I went back and looked more carefully at what was happening during installation. The installer was failing, but silently — the C:\ProgramData\DockerDesktop folder was being left behind by the uninstaller, and the ACL permissions on it were in a corrupted state.

Specifically: the folder had (I) (inherited-only) permissions for SYSTEM and Administrators. Inherited-only ACEs can be stripped by operations that reset inheritance — and that's exactly what happens across repeated install/uninstall cycles. Eventually the installer can no longer write to the folder or take ownership of it, and exits silently.

The specific error the Docker installer was hitting (though it never shows it to the user):

C:\ProgramData\DockerDesktop must be owned by an elevated account

The fix is to manually repair ownership and ACLs before running the installer.


The Fix: Permission Repair Script v1

I wrote a script to stop all Docker processes, take ownership of the folder, wipe and reset the ACL, and re-grant the correct permissions to SYSTEM and Administrators before attempting a reinstall.

How to Run It

Because this is an unsigned .ps1 script, you cannot double-click it. This command launches it as Administrator without permanently changing your system execution policy — it bypasses the policy for this one invocation only:

Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"C:\admin-PS\fix-docker-desktop-permissions-v1.ps1`"" -Verb RunAs

A UAC prompt will appear — click Yes. The script logs everything to a timestamped .log file in the same folder (docker_desktop_permission_fix_<timestamp>.log).

The Script

$LogFile = "$PSScriptRoot\docker_desktop_permission_fix_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"

$DockerFolder = "C:\ProgramData\DockerDesktop"

Write-Host "`n[1] Checking admin rights..."
$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
    [Security.Principal.WindowsBuiltInRole]::Administrator
)

if (-not $IsAdmin) {
    Write-Host "ERROR: This script must be run as Administrator."
    exit 1
}

Start-Transcript -Path $LogFile -Force

Write-Host "=== Docker Desktop Permission Repair Started ==="
Write-Host "Log file: $LogFile"

Write-Host "OK: Running as Administrator."

Write-Host "`n[2] Stopping Docker services/processes..."
$services = @(
    "com.docker.service",
    "docker"
)

foreach ($svc in $services) {
    try {
        Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
        Write-Host "Stopped service if present: $svc"
    }
    catch {
        Write-Host "Could not stop service: $svc"
        Write-Host $_
    }
}

$processes = @(
    "Docker Desktop",
    "Docker Desktop Installer",
    "com.docker.backend",
    "com.docker.service",
    "vpnkit",
    "dockerd",
    "docker"
)

foreach ($proc in $processes) {
    try {
        Get-Process -Name $proc -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
        Write-Host "Stopped process if present: $proc"
    }
    catch {
        Write-Host "Could not stop process: $proc"
        Write-Host $_
    }
}

Write-Host "Shutting down WSL to release file locks..."
wsl --shutdown

Start-Sleep -Seconds 3

Write-Host "`n[3] Checking DockerDesktop folder..."
if (Test-Path $DockerFolder) {
    Write-Host "Folder exists: $DockerFolder"

    Write-Host "`nCurrent permissions before repair:"
    icacls $DockerFolder

    Write-Host "`nTaking temporary ownership..."
    takeown /F $DockerFolder /R /D Y

    Write-Host "`nResetting permissions..."
    icacls $DockerFolder /reset /T /C

    Write-Host "`nGranting required permissions..."
    icacls $DockerFolder /grant "SYSTEM:(OI)(CI)F" /T /C
    icacls $DockerFolder /grant "Administrators:(OI)(CI)F" /T /C

    Write-Host "`nSetting owner to Administrators group..."
    takeown /F $DockerFolder /R /A /D Y

    Write-Host "`nPermissions after repair:"
    icacls $DockerFolder
}
else {
    Write-Host "Folder does not exist. Docker installer should recreate it:"
    Write-Host $DockerFolder
}

Write-Host "`n[4] Verifying owner..."
if (Test-Path $DockerFolder) {
    $Acl = Get-Acl $DockerFolder
    Write-Host "Current owner: $($Acl.Owner)"

    if ($Acl.Owner -match "SYSTEM|Administrators") {
        Write-Host "OK: Owner appears valid."
    }
    else {
        Write-Host "WARNING: Owner may still be invalid."
    }
}

Write-Host "`n[5] Checking installer in Downloads..."
$Installer = Get-ChildItem "$env:USERPROFILE\Downloads" -Filter "Docker Desktop Installer*.exe" -ErrorAction SilentlyContinue |
    Sort-Object LastWriteTime -Descending |
    Select-Object -First 1

if ($Installer) {
    Write-Host "Found installer:"
    Write-Host $Installer.FullName

    Write-Host "`nReady to run installer manually:"
    Write-Host "Right-click this file and choose Run as administrator:"
    Write-Host $Installer.FullName
}
else {
    Write-Host "No Docker Desktop Installer found in Downloads."
}

Write-Host "`n[6] Final recommendation..."
Write-Host "Now rerun Docker Desktop Installer as Administrator."
Write-Host "If it still fails, send me this log:"
Write-Host $LogFile

Write-Host "`n=== Docker Desktop Permission Repair Finished ==="

Stop-Transcript

What the Script Does, Stage by Stage

Stage What Happens
[1] Admin check Reads the current Windows identity token. Exits immediately with code 1 if not elevated.
[2] Stop everything Stops com.docker.service and docker Windows services, then kills 7 Docker-related processes by name. Runs wsl --shutdown to release any WSL file locks, then waits 3 seconds.
[3] Repair permissions Takes recursive ownership (takeown /R), resets all ACEs to inherited defaults (icacls /reset /T), explicitly grants SYSTEM and Administrators full control with OI+CI inherit flags, then re-assigns ownership to the Administrators group (takeown /A).
[4] Verify Reads the ACL back with Get-Acl and confirms owner is SYSTEM or Administrators.
[5] Find installer Searches %USERPROFILE%\Downloads for the newest Docker Desktop Installer*.exe.
[6] Recommend Prints the path to the installer and instructs you to run it as Administrator.

The Log Output (What Success Looks Like)

After a successful run, the key lines in the log are:

OK: Running as Administrator.
...
SUCCESS: The file (or folder): "C:\ProgramData\DockerDesktop" now owned by the administrators group.
...
Permissions after repair:
C:\ProgramData\DockerDesktop BUILTIN\Administrators:(OI)(CI)(F)
                             NT AUTHORITY\SYSTEM:(OI)(CI)(F)
...
Current owner: BUILTIN\Administrators
OK: Owner appears valid.

The important distinction between the before and after states is that SYSTEM and Administrators went from having only inherited permissions (marked (I)) to having explicit permissions. Inherited-only entries can be stripped by an installer or OS operation that resets inheritance — explicit entries cannot.


Revised Script: v2 — Logs to Desktop, Sets SYSTEM as Owner

After v1 worked I refined it. Key differences:

  • Log goes to your Desktop so it's easy to find and share
  • Owner is set to SYSTEM via icacls /setowner — closer to what a clean Docker install sets
  • Adds docker-users to the list of services to stop
  • Calls Stop-Transcript before exit 1 so the log is always flushed on early failure
  • Removes wsl --shutdown (not needed when moving to Hyper-V backend)

Run this in PowerShell as Administrator. It logs everything to your Desktop.

$LogFile = "$env:USERPROFILE\Desktop\docker_desktop_permission_fix_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"

Start-Transcript -Path $LogFile -Force

Write-Host "=== Docker Desktop Permission Repair Started ==="
Write-Host "Log file: $LogFile"

$DockerFolder = "C:\ProgramData\DockerDesktop"

Write-Host "`n[1] Checking admin rights..."
$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
    [Security.Principal.WindowsBuiltInRole]::Administrator
)

if (-not $IsAdmin) {
    Write-Host "ERROR: This script must be run as Administrator."
    Stop-Transcript
    exit 1
}

Write-Host "OK: Running as Administrator."

Write-Host "`n[2] Stopping Docker services/processes..."
$services = @(
    "com.docker.service",
    "docker",
    "docker-users"
)

foreach ($svc in $services) {
    try {
        Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
        Write-Host "Stopped service if present: $svc"
    }
    catch {
        Write-Host "Could not stop service: $svc"
        Write-Host $_
    }
}

$processes = @(
    "Docker Desktop",
    "Docker Desktop Installer",
    "com.docker.backend",
    "com.docker.service",
    "vpnkit",
    "dockerd",
    "docker"
)

foreach ($proc in $processes) {
    try {
        Get-Process -Name $proc -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
        Write-Host "Stopped process if present: $proc"
    }
    catch {
        Write-Host "Could not stop process: $proc"
        Write-Host $_
    }
}

Start-Sleep -Seconds 3

Write-Host "`n[3] Checking DockerDesktop folder..."
if (Test-Path $DockerFolder) {
    Write-Host "Folder exists: $DockerFolder"

    Write-Host "`nCurrent permissions before repair:"
    icacls $DockerFolder

    Write-Host "`nTaking temporary ownership..."
    takeown /F $DockerFolder /R /D Y

    Write-Host "`nResetting permissions..."
    icacls $DockerFolder /reset /T /C

    Write-Host "`nGranting required permissions..."
    icacls $DockerFolder /grant "SYSTEM:(OI)(CI)F" /T /C
    icacls $DockerFolder /grant "Administrators:(OI)(CI)F" /T /C

    Write-Host "`nRemoving normal user ownership risk by setting owner to SYSTEM..."
    icacls $DockerFolder /setowner "SYSTEM" /T /C

    Write-Host "`nPermissions after repair:"
    icacls $DockerFolder
}
else {
    Write-Host "Folder does not exist. Docker installer should recreate it:"
    Write-Host $DockerFolder
}

Write-Host "`n[4] Verifying owner..."
if (Test-Path $DockerFolder) {
    $Acl = Get-Acl $DockerFolder
    Write-Host "Current owner: $($Acl.Owner)"

    if ($Acl.Owner -match "SYSTEM|Administrators") {
        Write-Host "OK: Owner appears valid."
    }
    else {
        Write-Host "WARNING: Owner may still be invalid."
    }
}

Write-Host "`n[5] Checking installer in Downloads..."
$Installer = Get-ChildItem "$env:USERPROFILE\Downloads" -Filter "Docker Desktop Installer*.exe" -ErrorAction SilentlyContinue |
    Sort-Object LastWriteTime -Descending |
    Select-Object -First 1

if ($Installer) {
    Write-Host "Found installer:"
    Write-Host $Installer.FullName

    Write-Host "`nReady to run installer manually:"
    Write-Host "Right-click this file and choose Run as administrator:"
    Write-Host $Installer.FullName
}
else {
    Write-Host "No Docker Desktop Installer found in Downloads."
}

Write-Host "`n[6] Final recommendation..."
Write-Host "Now rerun Docker Desktop Installer as Administrator."
Write-Host "If it still fails, send me this log:"
Write-Host $LogFile

Write-Host "`n=== Docker Desktop Permission Repair Finished ==="

Stop-Transcript

After it runs, check your Desktop for the .log file. Confirm it ended with OK: Owner appears valid.

v1 vs v2 at a Glance

v1 v2
Log location Script folder Desktop
Final owner BUILTIN\Administrators NT AUTHORITY\SYSTEM
Services stopped com.docker.service, docker + docker-users
WSL shutdown Yes Removed (Hyper-V path)
Early exit log flush No Stop-Transcript before exit 1

If the Installer Still Fails After the Permission Repair

If the installer still hits the ownership error after running the repair script, remove the folder entirely and recreate it clean before reinstalling:

$target = "C:\ProgramData\DockerDesktop"
Remove-Item $target -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path $target -Force | Out-Null
icacls $target /setowner "Administrators"
icacls $target /grant:r "SYSTEM:(OI)(CI)F" "Administrators:(OI)(CI)F"
"Owner: $((Get-Acl $target).Owner)"

Then reboot, copy the installer to a local path, and run it elevated:

Start-Process "C:\Temp\Docker Desktop Installer.exe" -Verb RunAs

Step Two: Enabling Hyper-V for Windows Native Containers

With Docker Desktop successfully installed, Linux containers work immediately via the WSL2 backend. To switch to Windows native containers you need the Hyper-V backend.

System Requirements

Should I use Hyper-V or WSL? Docker Desktop's functionality remains consistent on both WSL and Hyper-V, without a preference for either architecture. Hyper-V and WSL have their own advantages and disadvantages, depending on your specific setup and your planned use case.

For the Hyper-V backend, x86_64:

  • Windows 10 64-bit: Enterprise, Pro, or Education — version 22H2 (build 19045) or higher
  • Windows 11 64-bit: Enterprise, Pro, or Education — version 23H2 (build 22631) or higher
  • The Hyper-V and Containers Windows features must be enabled
  • Hardware prerequisites:
  • 64-bit processor with Second Level Address Translation (SLAT)
  • 8 GB system RAM minimum
  • Hardware virtualization enabled in BIOS/UEFI settings

Note: Hyper-V is not available on Windows Home edition — you need Pro, Enterprise, or Education. If you're on Home, WSL2 is your only option.

My machine is running Windows 11 build 26200, which is well above the 23H2 minimum. The hardware requirements were already met. The only thing left was enabling the Windows features.

Enabling Hyper-V and Containers Features

Run this in an elevated PowerShell prompt:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All -All -NoRestart
Enable-WindowsOptionalFeature -Online -FeatureName Containers -All -NoRestart

Then reboot — this is mandatory. These are kernel-level features:

Restart-Computer

Switching Docker Desktop to Hyper-V Backend

After rebooting and reinstalling Docker Desktop, switch the backend:

  1. Open Docker Desktop
  2. Go to Settings → General
  3. Uncheck "Use the WSL 2 based engine"
  4. Click Apply & Restart

Then switch to Windows containers via CLI:

& "$Env:ProgramFiles\Docker\Docker\DockerCli.exe" -SwitchDaemon
docker info --format "{{.OSType}}"

Or right-click the Docker tray icon → Switch to Windows containers...


Verification: Confirm Both Modes Work

Linux Mode

docker info --format "{{.OSType}}"   # should print: linux
docker context ls
docker run --rm hello-world

Windows Mode

& "$Env:ProgramFiles\Docker\Docker\DockerCli.exe" -SwitchDaemon
docker info --format "{{.OSType}}"   # should print: windows
docker context ls
docker run --rm mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd /c echo Windows container OK

Switch Back and Confirm Dual-Mode Health

& "$Env:ProgramFiles\Docker\Docker\DockerCli.exe" -SwitchDaemon
docker info --format "{{.OSType}}"   # back to: linux
docker run --rm hello-world

Why Bother With Windows Native Containers?

For most developers doing web/API work, Linux containers are fine and WSL2 is the simpler path. But Windows native containers are worth the extra setup if you are:

  • Running .NET Framework (not .NET Core/5+) applications that require the full Windows runtime
  • Deploying to Windows Server environments and want dev/prod parity
  • Working with IIS, MSMQ, COM+, or other Windows-only components
  • Building images that need direct access to Windows APIs or the Windows registry
  • Running workloads where the overhead of a Linux VM is genuinely a problem

The base images (mcr.microsoft.com/windows/servercore, mcr.microsoft.com/windows/nanoserver) are large — servercore is several gigabytes — but they are the same runtime your Windows Server hosts use, which makes the containerization story much more coherent for Windows-native stacks.


Summary: The Full Checklist

Cleanup and permission repair (do this first): - [ ] Stop all Docker services and processes - [ ] Remove Docker Desktop via Apps → Installed apps, reboot - [ ] Remove all leftover Docker folders (see Phase 2 above) - [ ] Run the permission repair script as Administrator - [ ] Confirm log shows OK: Owner appears valid

Reinstall: - [ ] Reboot - [ ] Run Docker Desktop Installer as Administrator - [ ] Confirm docker run --rm hello-world works in Linux mode

Switch to Windows native containers: - [ ] Enable Hyper-V and Containers Windows features, reboot - [ ] In Docker Desktop Settings → General, disable WSL2 engine - [ ] Run -SwitchDaemon or tray → Switch to Windows containers - [ ] Confirm docker info --format "{{.OSType}}" returns windows - [ ] Run a Windows container smoke test


What I Learned

The silent installer failure and the "windows containers disabled" error were both downstream symptoms of the same root cause: corrupted ACL state on C:\ProgramData\DockerDesktop left behind by a previous uninstall. Because Docker's installer never surfaces this error to the user, it looks like a complete mystery — you can check Windows features, check policies, check registry keys, do multiple full clean reinstalls — and nothing changes because the leftover folder is still there with broken permissions.

The actual fix is five icacls and takeown commands. The hard part is knowing that's what you're looking for.

If you are fighting the same problem, start with the permission repair script before anything else. It takes 10 seconds to run and it's the only thing that actually fixed it.


Machine: Windows 11 build 26200 | Scripts: fix-docker-desktop-permissions-v1.ps1 (v1 + v2) | Date: April 26, 2026