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.

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.

it will unpack ESD files and you can add more URLs then those 2 i have included.
Anyway heres the script

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.

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