New/Updated Language CAB Download PowerShell Script

Harze2k

New Member
Messages
4
Reaction score
2
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.

Screenshot 2024-11-13 130049.png

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.

Screenshot 2024-11-13 130313.png
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
 
Back
Top