tasks/90-DockerDesktop.ps1

@{
    Id             = 'DockerDesktop'
    DisplayName    = 'Docker Desktop'
    Description    = 'Junction-mounts ~/.docker, then relocates the docker-desktop WSL distro and patches settings-store.json'
    WingetPackages = @('Docker.DockerDesktop')
    Action         = {
        [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
        param(
            [Parameter(Mandatory)]
            [System.Collections.IDictionary] $Paths
        )

        Write-Header -Name 'Docker Desktop'

        # Step 1: junction ~/.docker so Docker Desktop's user data, CLI
        # config, and contexts live on the configured drive.
        $junctionParams = @{
            LinkPath   = (Join-Path $HOME '.docker')
            TargetPath = $Paths.DockerHome
            Name       = 'Docker'
        }
        New-DevJunction @junctionParams

        # Step 2: relocate the docker-desktop WSL distro and keep Docker
        # Desktop's settings-store.json in sync.
        $target = Get-DockerDesktopWslHomeConfig
        if (-not $target) {
            Write-Status -Level Skip -Message ' [SKIP] DockerDesktop.WslHome not configured.'
            return
        }

        if (-not (Get-Command wsl -ErrorAction SilentlyContinue)) {
            Write-Status -Level Skip -Message ' [SKIP] WSL is not installed; run the Wsl task first.'
            return
        }

        if (-not (Get-DockerDesktopInstallPath)) {
            Write-Status -Level Skip -Message ' [SKIP] Docker Desktop is not installed.'
            return
        }

        # Settings-store.json and the docker-desktop distro registration
        # only appear after Docker Desktop has been launched at least
        # once. If we just installed Docker via winget on this run (or
        # the user hasn't started it yet), bootstrap it here: launch,
        # wait for state, and let the migration below shut it down
        # and move the data.
        $settingsPath    = Get-DockerSettingsStorePath
        $currentBasePath = Get-WslDistroBasePath -Name 'docker-desktop'
        if (-not $settingsPath -or -not $currentBasePath) {
            Start-DockerDesktopAndWait
            if ($WhatIfPreference) { return }
            $settingsPath    = Get-DockerSettingsStorePath
            $currentBasePath = Get-WslDistroBasePath -Name 'docker-desktop'
            if (-not $settingsPath -or -not $currentBasePath) {
                throw 'Docker Desktop bootstrap completed but settings file or distro registration is still missing.'
            }
        }

        $currentSettingsValue = Get-DockerCustomWslDistroDir -SettingsPath $settingsPath

        # Mirror Docker's existing subfolder convention. If Docker stores
        # the distro inside a child folder of CustomWslDistroDir today
        # (e.g. ".docker-desktop\DockerDesktopWSL"), preserve that child
        # folder name at the new parent. Otherwise put the distro right
        # at the configured target.
        $newSettingsValue = $target
        $newBasePath      = if ($currentSettingsValue -and
                                $currentBasePath -and
                                $currentBasePath -ine $currentSettingsValue -and
                                $currentBasePath.StartsWith($currentSettingsValue, [System.StringComparison]::OrdinalIgnoreCase)) {
            $relative = $currentBasePath.Substring($currentSettingsValue.Length).TrimStart('\', '/')
            if ($relative) { Join-Path $target $relative } else { $target }
        }
        else {
            $target
        }

        $settingsMatches = ($currentSettingsValue -and ($currentSettingsValue -ieq $newSettingsValue))
        $basePathMatches = ($currentBasePath      -ieq $newBasePath)

        if ($settingsMatches -and $basePathMatches) {
            Write-Status -Level Info -Message " [INFO] docker-desktop is already at $newBasePath."
            return
        }

        Stop-DockerDesktopProcesses

        if (-not $basePathMatches) {
            if ($PSCmdlet.ShouldProcess('docker-desktop', "wsl --manage --move $newBasePath")) {
                Write-Status -Level Info -Message " [INFO] Moving docker-desktop -> $newBasePath"
                wsl --manage docker-desktop --move "$newBasePath\" 2>&1 | Format-ToolOutput
                if ($LASTEXITCODE -ne 0) {
                    throw ("wsl --manage docker-desktop --move failed with exit code {0}." -f $LASTEXITCODE)
                }
            }
        }

        if (-not $settingsMatches) {
            Set-DockerCustomWslDistroDir -SettingsPath $settingsPath -NewValue $newSettingsValue
            Write-Status -Level Info -Message " [INFO] settings-store.json: CustomWslDistroDir -> $newSettingsValue"
        }

        Write-Status -Level Info -Message ' [INFO] docker-desktop relocated. Restart Docker Desktop manually to verify.'
    }
}