I think i dropped a terrible script for this a few years back... So am back again! Less terrible since powershell is basically what i do now haha.
View attachment 13226
There is me just testing it out with what i think is the latest build not counting those advanced boys with crazy build numbers!
It got a custom logger, custom random http headers function and it will try as best as it can to get your cab files downloaded.
View attachment 13227
it will unpack ESD files and you can add more URLs then those 2 i have included.
Anyway heres the script
View attachment 13226
There is me just testing it out with what i think is the latest build not counting those advanced boys with crazy build numbers!
It got a custom logger, custom random http headers function and it will try as best as it can to get your cab files downloaded.
View attachment 13227
it will unpack ESD files and you can add more URLs then those 2 i have included.
Anyway heres the script
function Download-LanguageCAB { [CmdletBinding()] param ( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$FolderPath, [Parameter(Mandatory)][ValidateSet("amd64")][string]$Arch, [Parameter(Mandatory)][ValidateSet("10", "11")][string]$Os, [ValidatePattern("^\d{5}\.\d+$")][string]$Build, [Parameter(Mandatory)][ValidatePattern("^[a-z]{2}-[a-z]{2}$")][string]$Language, [ValidateNotNullOrEmpty()][string[]]$UUPUrls = @('www.uupdump.net', 'www.uupdump.cn'), [switch]$ESDToCAB, [switch]$RemoveESD ) begin { function Download-File { [CmdletBinding()] param ( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$DownloadLink, [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$OutputFile, [Parameter(Mandatory = $false)][string]$FileName ) [net.SecurityProtocolType]::Tls12 -bor [net.SecurityProtocolType]::Tls13 if ([string]::IsNullOrEmpty($fileName)) { [string]$fileName = $(Split-Path $outputFile -Leaf) } try { $httpClient = Get-RandomHeader -GetHTTPClient [System.IO.File]::WriteAllBytes($outputFile, (($httpClient.SendAsync((New-Object System.Net.Http.HttpRequestMessage([System.Net.Http.HttpMethod]::Get, $downloadLink)))).Result).Content.ReadAsByteArrayAsync().Result) $httpClient.Dispose() New-Log "Successfully downloaded $fileName with HttpClient." -Level SUCCESS return $true } catch { New-Log "Will download with Invoke-RestMethod instead." -Level WARNING Invoke-RestMethod -Uri $downloadLink -OutFile $outputFile } } function Convert-EsdToCab { param ( [string]$EsdFile, [string]$WorkingDir, [string]$ImageX, [string]$Cabarc, [string]$Sxs, [switch]$RemoveESD ) $pack = [System.IO.Path]::GetFileNameWithoutExtension($EsdFile) $cabFile = Join-Path $WorkingDir "$pack.cab" if (Test-Path $cabFile) { New-Log "$cabFile already exists, skipping." return } $tempDir = Join-Path "C:\" "temp$([System.IO.Path]::GetRandomFileName())" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { & $ImageX /APPLY $EsdFile 1 $tempDir /NOACL ALL /NOTADMIN /TEMP $env:TEMP | Out-Null New-Log "Successfully extracted esd file $EsdFile with ImageX." -Level SUCCESS New-Log "Next step (converting) will take some time.." } catch { New-Log "============================================================" New-Log "Extracting with ImageX had an error." -Level ERROR New-Log "============================================================" } Push-Location $tempDir New-Item -ItemType Directory -Path "_sxs" -Force | Out-Null Get-ChildItem -Filter "*.manifest" | ForEach-Object { try { & $Sxs $_.Name "_sxs\$($_.Name)" | Out-Null } catch { [bool]$sxSExpandError = $true New-Log "============================================================" New-Log "Converting with SxSExpand had an error." -Level ERROR New-Log "============================================================" } } if (!($sxSExpandError)) { New-Log "Successfully converted all files in $EsdFile with SxSExpand." -Level SUCCESS New-Log "Next step (adding to cab archive) will take some time.." } if (Test-Path "_sxs\*.manifest") { Move-Item "_sxs\*" . -Force } Remove-Item "_sxs" -Recurse -Force try { & $Cabarc -m LZX:21 -r -p N "$cabFile" *.* | Out-Null } catch { [bool]$cabarcError = $true New-Log "============================================================" New-Log "Adding to cab archive with Cabarc had an error." -Level ERROR New-Log "============================================================" } if (!($cabarcError)) { New-Log "Successfully added all files to $pack.cab with Cabarc." -Level SUCCESS } if ($LASTEXITCODE -eq 0) { New-Log "==========================================================" New-Log "Successfully expanded, converted and created the cab file." New-Log "==========================================================" } Set-Location -Path $WorkingDir Start-Sleep 5 Remove-Item $tempDir -Recurse -Force -Confirm:$false -ErrorAction SilentlyContinue | Out-Null if ($RemoveESD.IsPresent) { Remove-Item -Path ".\$pack.esd" -Force -Confirm:$false -ErrorAction SilentlyContinue | Out-Null } } Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Harze2k/Shared-PowerShell-Functions/main/New-Log.ps1" -UseBasicParsing -MaximumRedirection 1 | Select-Object -ExpandProperty Content | Invoke-Expression Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Harze2k/Shared-PowerShell-Functions/main/Get-RandomHeader.ps1" -UseBasicParsing -MaximumRedirection 1 | Select-Object -ExpandProperty Content | Invoke-Expression try { if (-not (Test-Path "$folderPath\$build")) { New-Log "Creating folder: $folderPath\$build" New-Item -Path "$folderPath\$build" -ItemType Directory -Force | Out-Null } } catch { New-Log "Failed to create or access folder: "$folderPath\$build"." -Level ERROR return } } process { $lang = ($Language -split '-')[0] $headers = Get-RandomHeader New-Log "Using build: $build" -Level DEBUG foreach ($UUPUrl in $UUPUrls) { try { $WebResponse = (Invoke-WebRequest -Uri "https://$UUPUrl/known.php?q=windows+$($Os)+$($Build)" -UseBasicParsing -MaximumRedirection 1 -Method GET -Headers $headers -ErrorAction Stop).Links if ($WebResponse.Count -eq 0 -or [string]::IsNullOrEmpty($WebResponse)) { $WebResponse = (Invoke-RestMethod -Uri "https://$UUPUrl/known.php?q=windows+$($Os)+$($Build)" -MaximumRedirection 1 -Method Get -Headers $headers).Links if ($WebResponse.Count -eq 0 -or [string]::IsNullOrEmpty($WebResponse)) { continue } } New-Log "Got webResponse from $UUPUrl." -Level SUCCESS Break } catch { New-Log "Failed to get WebResponse from $UUPUrl." -Level ERROR } } if ($null -eq $WebResponse -or $WebResponse.Count -eq 0) { New-Log "Failed to get WebResponse. Aborting." -Level WARNING return } foreach ($UUPUrl in $UUPUrls) { try { $UpdateID = (($WebResponse | Where-Object { $_.href -match "(./selectlang.php\?id|selectlang.php\?id)" }).href).split("=")[1] New-Log "Using UpdateId: $UpdateID" -Level DEBUG $Links = (Invoke-WebRequest -Uri "https://$UUPUrl/get.php?id=$UpdateID&pack=$Language&edition=core" -UseBasicParsing -MaximumRedirection 2 -Method GET -Headers $headers -ErrorAction Stop).Links if ($Links.Count -eq 0 -or [string]::IsNullOrEmpty($Links)) { $Links = (Invoke-RestMethod -Uri "https://$UUPUrl/get.php?id=$UpdateID&pack=$Language&edition=core" -MaximumRedirection 2 -Method Get -Headers $headers).Links if ($Links.Count -eq 0 -or [string]::IsNullOrEmpty($Links)) { continue } } New-Log "Got links response from $UUPUrl." -Level SUCCESS Break } catch { New-Log "Failed to get download links from $UUPUrl." -Level ERROR continue } } if ($null -eq $Links -or $Links.Count -eq 0) { New-Log "Failed to get links to parse. Will not download any files. Aborting." -Level WARNING return } $downloadLinks = $true if ($Links) { New-Log "========================================================" New-Log "Start of finding and downloading language cab/esd files." New-Log "========================================================" foreach ($link in ($Links.outerHTML -match ".*(LanguagePack|LanguageFeatures).*$lang-.*")) { $URL = $link.Split('"')[1] $Filename = $link.Split('>')[1].Split('<')[0] -replace '\s', '' $FilenameWithoutExtension = [IO.Path]::GetFileNameWithoutExtension($Filename) $FileExtension = [IO.Path]::GetExtension($Filename) $NewFilename = "$FilenameWithoutExtension-$Build$FileExtension" $OutFile = Join-Path "$folderPath\$build" $NewFilename if (!(Test-Path $OutFile)) { $downloadLinks = Download-File -DownloadLink $URL -OutputFile $OutFile -FileName $NewFilename } else { New-Log "$NewFilename was already downloaded, skipping." -Level DEBUG } } } else { New-Log "No links found to download. Aborting." -Level WARNING return } if (!(Test-Path "$folderPath\$build\esd2cab_CLI.cmd")) { New-Log "Downloading ESD2CAB cmd tool." -Level DEBUG try { Invoke-WebRequest -Uri 'https://github.com/abbodi1406/WHD/raw/master/scripts/ESD2CAB-CAB2ESD-2.zip' -UseBasicParsing -MaximumRedirection 1 -Method GET -OutFile "$folderPath\$build\ESD2CAB.zip" -ErrorAction Stop Start-Sleep 1 Expand-Archive -Path "$folderPath\$build\ESD2CAB.zip" -DestinationPath $folderPath\$build -Force -ErrorAction Stop } catch { New-Log "Failed to download ESD2CAB cmd tool." -Level ERROR $downloadLinks = $false } } if ($ESDToCAB -and $downloadLinks) { Set-Location -Path "$folderPath\$build" $bits = if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") { "x64" } else { "x86" } $requiredFiles = @("image$bits.exe", "cabarc.exe", "SxSExpand.exe") foreach ($file in $requiredFiles) { if (-not (Test-Path "bin\$file")) { New-Log -Message "$file is not detected." -Level ERROR return } } $ImageX = Resolve-Path "bin\image$bits.exe" $Cabarc = Resolve-Path "bin\cabarc.exe" $Sxs = Resolve-Path "bin\SxSExpand.exe" $esdFile = Get-ChildItem -Path . -Include "*Windows*LanguagePack*$language*.esd" -Recurse if ([string]::IsNullOrEmpty($esdFile)) { New-Log -Message "No .esd file detected." -Level WARNING return } if ($RemoveESD.IsPresent) { Remove-Item -Path ".\$pack.esd" -Force -Confirm:$false -ErrorAction SilentlyContinue | Out-Null Convert-EsdToCab -EsdFile $esdFile.Name -WorkingDir "$folderPath\$build" -ImageX $imageX -Cabarc $cabarc -Sxs $sxs -RemoveESD } else { Convert-EsdToCab -EsdFile $esdFile.Name -WorkingDir "$folderPath\$build" -ImageX $imageX -Cabarc $cabarc -Sxs $sxs } New-Log -Message "All downloads andconversions completed." -Level SUCCESS } elseif ($ESDToCAB -and !($downloadLinks)) { New-Log "Either the download of the CABs failed or the esd to cab tool failed to download. Will abort." -Level WARNING } }}$currentBuild = ((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name 'CurrentBuild').CurrentBuild) + '.' + ((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name 'UBR').UBR)$build = '26100.2314'Download-LanguageCAB -FolderPath "C:\Temp\LanguageCAB" -Arch "amd64" -Os "11" -Language "sv-se" -RemoveESD -ESDToCAB -UUPUrls @('www.uupdump.net', 'www.uupdump.cn') -Build $build