@@ -492,9 +492,15 @@ function Test-WslFileTransferIntegrity {
492492function Get-DebianRootfs {
493493 <#
494494 . SYNOPSIS
495- Downloads and extracts the Debian rootfs tarball from Microsoft's .appx package.
495+ Downloads Debian 13 Trixie rootfs from official WSL distribution.
496+ . DESCRIPTION
497+ Downloads the architecture-specific .wsl file from salsa.debian.org,
498+ verifies the SHA256 checksum, and returns the path to the tarball.
499+ The .wsl format is a direct tarball ready for wsl --import.
496500 . OUTPUTS
497- Returns the path to the extracted rootfs.tar file.
501+ Returns the path to the downloaded .wsl tarball file.
502+ . LINK
503+ https://github.com/microsoft/WSL/blob/master/distributions/DistributionInfo.json
498504 #>
499505 [Diagnostics.CodeAnalysis.SuppressMessageAttribute (' PSUseSingularNouns' , ' ' ,
500506 Justification = ' Rootfs is singular - abbreviation for root filesystem' )]
@@ -503,114 +509,62 @@ function Get-DebianRootfs {
503509 [string ]$OutputPath
504510 )
505511
506- $appxUrl = " https://aka.ms/wsl-debian-gnulinux"
507- $randomSuffix = Get-Random - Maximum 999999
512+ # Architecture-specific URLs and checksums from Microsoft WSL distribution catalog
513+ $debianUrls = @ {
514+ ' x64' = @ {
515+ Url = ' https://salsa.debian.org/debian/WSL/-/jobs/7949331/artifacts/raw/Debian_WSL_AMD64_v1.22.0.0.wsl'
516+ SHA256 = ' 543123ccc5f838e63dac81634fb0223dc8dcaa78fdb981387d625feb1ed168c7'
517+ }
518+ ' ARM64' = @ {
519+ Url = ' https://salsa.debian.org/debian/WSL/-/jobs/7949331/artifacts/raw/Debian_WSL_ARM64_v1.22.0.0.wsl'
520+ SHA256 = ' 5701f1add55f8cf3b56528109a6220ae5c89f2189d7ae97b9a4b5302b80e967c'
521+ }
522+ }
508523
509- # Use LOCALAPPDATA for temp files - guaranteed to be on local system drive
510- $tempBase = Join-Path $env: LOCALAPPDATA " DevContainersSetup\temp"
511- if (-not (Test-Path $tempBase )) {
512- New-Item - ItemType Directory - Path $tempBase - Force | Out-Null
524+ $systemArch = Get-SystemArchitecture
525+ Write-LogDebug " System architecture: $systemArch "
526+
527+ if (-not $debianUrls.ContainsKey ($systemArch )) {
528+ throw " Unsupported architecture: $systemArch . Supported: x64, ARM64"
513529 }
514530
515- $appxPath = Join-Path $tempBase " debian-appx-$randomSuffix .zip"
516- $extractPath = Join-Path $tempBase " debian-extract-$randomSuffix "
531+ $archInfo = $debianUrls [$systemArch ]
532+ $downloadUrl = $archInfo.Url
533+ $expectedHash = $archInfo.SHA256
517534
518- try {
519- Write-LogInfo " Downloading Debian rootfs from Microsoft..."
520- Write-LogDebug " URL: $appxUrl "
535+ Write-LogInfo " Downloading Debian 13 Trixie ($systemArch )..."
536+ Write-LogDebug " URL: $downloadUrl "
521537
538+ try {
522539 $downloadStart = Get-Date
523- Invoke-WebRequest - Uri $appxUrl - OutFile $appxPath - UseBasicParsing - ErrorAction Stop
540+ $ProgressPreference = ' SilentlyContinue'
541+ Invoke-WebRequest - Uri $downloadUrl - OutFile $OutputPath - UseBasicParsing - ErrorAction Stop
524542 $downloadTime = (Get-Date ) - $downloadStart
525- $appxSize = (Get-Item $appxPath ).Length
526- Write-LogDebug " Downloaded $ ( [Math ]::Round($appxSize / 1 MB , 1 )) MB in $ ( [Math ]::Round($downloadTime.TotalSeconds , 1 )) s"
527-
528- Write-LogInfo " Extracting rootfs from package..."
529- Expand-Archive - Path $appxPath - DestinationPath $extractPath - Force - ErrorAction Stop
530-
531- # Check if this is an appxbundle (contains nested .appx files for different architectures)
532- $nestedAppx = Get-ChildItem - Path $extractPath - Filter " *.appx" - ErrorAction SilentlyContinue |
533- Where-Object { $_.Name -notmatch ' scale-\d+' } # Exclude display scaling variants
534-
535- if ($nestedAppx ) {
536- # This is an appxbundle - need to extract the architecture-specific appx first
537- Write-LogInfo " Detected appxbundle structure, extracting architecture-specific package..."
538-
539- $systemArch = Get-SystemArchitecture
540- Write-LogDebug " System architecture: $systemArch "
541-
542- # Find the matching architecture appx (case-insensitive match)
543- $archAppx = $nestedAppx | Where-Object { $_.Name -match " _$systemArch \.appx$" } | Select-Object - First 1
544-
545- if (-not $archAppx ) {
546- # Fallback: try to find any x64 or ARM64 appx
547- $archAppx = $nestedAppx | Where-Object { $_.Name -match ' _(x64|ARM64)\.appx$' } | Select-Object - First 1
548- if ($archAppx ) {
549- Write-LogWarn " Using fallback appx: $ ( $archAppx.Name ) "
550- }
551- }
543+ $fileSize = (Get-Item $OutputPath ).Length
544+ Write-LogDebug " Downloaded $ ( [Math ]::Round($fileSize / 1 MB , 1 )) MB in $ ( [Math ]::Round($downloadTime.TotalSeconds , 1 )) s"
552545
553- if (-not $archAppx ) {
554- throw " No architecture-specific appx found for $systemArch . Available packages: $ ( $nestedAppx.Name -join ' , ' ) "
555- }
556-
557- Write-LogDebug " Extracting inner package: $ ( $archAppx.Name ) "
558-
559- # Extract the inner appx to get the actual rootfs
560- $innerExtractPath = Join-Path $extractPath " inner-appx"
561- Expand-Archive - Path $archAppx.FullName - DestinationPath $innerExtractPath - Force - ErrorAction Stop
562-
563- # Update search path to look inside the inner extraction
564- $extractPath = $innerExtractPath
565- }
566-
567- # Find the rootfs tarball (install.tar.gz in Debian's .appx)
568- $rootfsGz = Get-ChildItem - Path $extractPath - Filter " install.tar.gz" - Recurse - ErrorAction SilentlyContinue |
569- Select-Object - First 1
570-
571- if (-not $rootfsGz ) {
572- $rootfsGz = Get-ChildItem - Path $extractPath - Filter " *.tar.gz" - Recurse - ErrorAction SilentlyContinue |
573- Select-Object - First 1
574- }
575-
576- if (-not $rootfsGz ) {
577- throw " No rootfs tarball found in package. Contents: $ ( Get-ChildItem $extractPath - Recurse - Name | Out-String ) "
578- }
546+ # Verify SHA256 checksum
547+ Write-LogInfo " Verifying SHA256 checksum..."
548+ $actualHash = (Get-FileHash - Path $OutputPath - Algorithm SHA256).Hash.ToLower()
579549
580- Write-LogDebug " Found rootfs: $ ( $rootfsGz.Name ) ($ ( [Math ]::Round($rootfsGz.Length / 1 MB , 1 )) MB)"
581-
582- # Decompress .tar.gz to .tar using .NET GzipStream
583- Write-LogInfo " Decompressing rootfs..."
584- $gzipInput = [System.IO.File ]::OpenRead($rootfsGz.FullName )
585- $gzipStream = New-Object System.IO.Compression.GzipStream($gzipInput , [System.IO.Compression.CompressionMode ]::Decompress)
586- $tarOutput = [System.IO.File ]::Create($OutputPath )
587-
588- try {
589- $gzipStream.CopyTo ($tarOutput )
590- }
591- finally {
592- $tarOutput.Close ()
593- $gzipStream.Close ()
594- $gzipInput.Close ()
550+ if ($actualHash -ne $expectedHash.ToLower ()) {
551+ throw " SHA256 checksum mismatch!`n Expected: $expectedHash `n Actual: $actualHash "
595552 }
553+ Write-LogSuccess " Checksum verified"
596554
597- if (-not (Test-Path $OutputPath )) {
598- throw " Failed to create rootfs tarball at: $OutputPath "
555+ # Verify file size is reasonable (minimal rootfs can be as small as ~10MB)
556+ if ($fileSize -lt 10 MB ) {
557+ throw " Rootfs file suspiciously small ($ ( [Math ]::Round($fileSize / 1 MB , 1 )) MB)"
599558 }
600559
601- $tarSize = (Get-Item $OutputPath ).Length
602- Write-LogDebug " Decompressed rootfs: $ ( [Math ]::Round($tarSize / 1 MB , 1 )) MB"
603-
604- if ($tarSize -lt 100 MB ) {
605- throw " Rootfs tarball suspiciously small ($ ( [Math ]::Round($tarSize / 1 MB , 1 )) MB)"
606- }
607-
608- Write-LogSuccess " Debian rootfs ready ($ ( [Math ]::Round($tarSize / 1 MB , 0 )) MB)"
560+ Write-LogSuccess " Debian 13 Trixie rootfs ready ($ ( [Math ]::Round($fileSize / 1 MB , 0 )) MB)"
609561 return $OutputPath
610562 }
611- finally {
612- Remove-Item $appxPath - Force - ErrorAction SilentlyContinue
613- Remove-Item $extractPath - Recurse - Force - ErrorAction SilentlyContinue
563+ catch {
564+ if (Test-Path $OutputPath ) {
565+ Remove-Item $OutputPath - Force - ErrorAction SilentlyContinue
566+ }
567+ throw
614568 }
615569}
616570
@@ -1134,9 +1088,9 @@ function Get-NextAvailableDistroName {
11341088function Install-WslDistroViaImport {
11351089 <#
11361090 . SYNOPSIS
1137- Creates a new Debian WSL distribution by downloading rootfs directly from Microsoft .
1091+ Creates a new Debian WSL distribution by downloading rootfs from official source .
11381092 . DESCRIPTION
1139- Downloads the Debian .appx package from Microsoft, extracts the rootfs tarball ,
1093+ Downloads the Debian .wsl tarball, verifies the checksum ,
11401094 and imports it as a new WSL distribution with the specified name.
11411095 . OUTPUTS
11421096 Returns the name of the created distribution.
@@ -1163,7 +1117,7 @@ function Install-WslDistroViaImport {
11631117 }
11641118
11651119 $randomSuffix = Get-Random - Maximum 999999
1166- $tempTarPath = Join-Path $tempBase " debian-rootfs-$randomSuffix .tar "
1120+ $tempTarPath = Join-Path $tempBase " debian-rootfs-$randomSuffix .wsl "
11671121 $installPath = Join-Path $env: LOCALAPPDATA " WSL\$TargetDistroName "
11681122
11691123 if (Test-Path $installPath ) {
@@ -2079,7 +2033,7 @@ OPTIONS:
20792033 -Help Show this help message
20802034
20812035SUPPORTED DISTRIBUTIONS:
2082- Debian Debian 13 Trixie - support until 2030
2036+ Debian Debian 13 Trixie
20832037
20842038EXAMPLES:
20852039 # Standard setup with Debian
0 commit comments