Compare commits

..

3 Commits
v1.08 ... v1.11

Author SHA1 Message Date
Pete Batard
cedf215a9d Enable Chinese/Korean additional downloads according to locale
* Also remove downloads that don't appear to work such as COEM and Windows 8 LE
* Also ensure that error messages from Microsoft's response are used on error
  and are properly translated to UTF-8
2019-03-21 16:06:07 +00:00
Pete Batard
dd73cef3b4 Fix Invalid JSON primitive error when Simplified Chinese locale is used
* Closes #7
* Also make sure our console output uses UTF-8
* Also harmonize the listing of all the Windows 10 releases
2019-03-19 12:52:12 +00:00
Pete Batard
9c19e1c671 Speed up initial UI display by performing query locale check in stage 1
* UI display should now only be constrained by the time it takes to launch PowerShell
2019-03-18 11:09:54 +00:00
2 changed files with 109 additions and 117 deletions

216
Fido.ps1
View File

@@ -1,5 +1,5 @@
#
# Fido v1.08 - Retail Windows ISO Downloader
# Fido v1.11 - Retail Windows ISO Downloader
# Copyright © 2019 Pete Batard <pete@akeo.ie>
# ConvertTo-ImageSource: Copyright © 2016 Chris Carter
#
@@ -34,12 +34,13 @@ param(
# (Optional) Disable IE First Run Customize so that Invoke-WebRequest
# doesn't throw an exception if the user has never launched IE.
# Note that this requires the script to run elevated.
[switch]$DisableFirstRunCustomize,
# (Optional) Toggle expert mode (additional ISOs to choose).
[switch]$Expert = $False
[switch]$DisableFirstRunCustomize
)
#endregion
try {
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
} catch {}
Write-Host Please Wait...
#region Assembly Types
@@ -69,6 +70,8 @@ Add-Type -AssemblyName PresentationFramework
#endregion
#region Data
$zh = 0x10000
$ko = 0x20000
$WindowsVersions = @(
@(
@("Windows 10", "Windows10ISO"),
@@ -76,100 +79,88 @@ $WindowsVersions = @(
"1809 R2 (Build 17763.107 - 2018.10)",
@("Windows 10 Home/Pro", 1060),
@("Windows 10 Education", 1056),
@("Windows 10 Home China ", -1061)
@("Windows 10 Home China ", ($zh + 1061))
),
@(
"1809 R1 (Build 17763.1 - 2018.09)",
@("Windows 10 Home/Pro", 1019),
@("Windows 10 Education", 1021),
@("Windows 10 Home China ", -1020)
@("Windows 10 Home China ", ($zh + 1020))
),
@(
"1803 (Build 17134.1 - 2018.04)",
@("Windows 10 Home/Pro", 651),
@("Windows 10 Education", 655),
@("Windows 10 Enterprise Eval", -629)
@("Windows 10 COEM 1803 Home China", -640),
@("Windows 10 COEM 1803", -639),
@("Windows 10 1803 Home China", -638),
@("Windows 10 1803", 637),
@("Windows 10 COEM 1803_1 Home China", -654),
@("Windows 10 COEM 1803_1", -653),
@("Windows 10 1803_1 Home China", -652)
@("Windows 10 Home China", ($zh + 652))
),
@(
"1709 (Build 16299.15 - 2017.09)",
@("Windows 10 Education 1709", 488),
@("Windows 10 COEM 1709 Home China", -487),
@("Windows 10 COEM 1709", -486),
@("Windows 10 1709 Home China", -485),
@("Windows 10 1709", 484)
@("Windows 10 Home/Pro", 484),
@("Windows 10 Education", 488),
@("Windows 10 Home China", ($zh + 485))
),
@(
"1703 (Build 15063.0 - 2017.03)",
@("Windows 10 1703 Education N", 424),
@("Windows 10 1703 Education", 423),
@("Windows 10 COEM 1703 Home China", -372),
@("Windows 10 COEM 1703 Single Language", 371),
@("Windows 10 COEM 1703 N", 370),
@("Windows 10 COEM 1703", 369),
@("Windows 10 1703 Home China (Redstone 2)", -364),
@("Windows 10 1703 Single Language (Redstone 2)", -363),
@("Windows 10 1703 N (Redstone 2)", 362),
@("Windows 10 1703 (Redstone 2)", 361)
"1703 [Redstone 2] (Build 15063.0 - 2017.03)",
@("Windows 10 Home/Pro", 361),
@("Windows 10 Home/Pro N", 362),
@("Windows 10 Single Language", 363),
@("Windows 10 Education", 423),
@("Windows 10 Education N", 424),
@("Windows 10 Home China", ($zh + 364))
),
@(
"1607 (Build 14393.0 - 2017.07)",
@("Windows 10 China Get Genuine (Redstone 1)", -247),
@("Windows 10 Single Language (Redstone 1)", 246),
@("Windows 10 N (Redstone 1)", 245),
@("Windows 10 (Redstone 1)", 244),
@("Windows 10 Education N (Redstone 1)", 243),
@("Windows 10 Education (Redstone 1)", 242)
"1607 [Redstone 1] (Build 14393.0 - 2017.07)",
@("Windows 10 Home/Pro", 244),
@("Windows 10 Home/Pro N", 245),
@("Windows 10 Single Language", 246),
@("Windows 10 Education", 242),
@("Windows 10 Education N", 243),
@("Windows 10 China Get Genuine", ($zh + 247))
),
@(
"1511 R3 (Build 10586.164 - 2016.04)",
@("Windows 10 China Get Genuine (Threshold 2, April 2016 Update)", -185),
@("Windows 10 Single Language (Threshold 2, April 2016 Update)", 184),
@("Windows 10 N (Threshold 2, April 2016 Update)", -183),
@("Windows 10 KN (Threshold 2, April 2016 Update)", -182),
@("Windows 10 Education N (Threshold 2, April 2016 Update)", 181),
@("Windows 10 Education KN (Threshold 2, April 2016 Update)", -180),
@("Windows 10 Education (Threshold 2, April 2016 Update)", 179),
@("Windows 10 (Threshold 2, April 2016 Update)", 178)
"1511 R3 [Threshold 2] (Build 10586.164 - 2016.04)",
@("Windows 10 Home/Pro", 178),
@("Windows 10 Home/Pro N", 183),
@("Windows 10 Single Language", 184),
@("Windows 10 Education", 179),
@("Windows 10 Education N", 181),
@("Windows 10 KN", ($ko + 182)),
@("Windows 10 Education KN", ($ko + 180)),
@("Windows 10 China Get Genuine", ($zh + 185))
),
@(
"1511 R2 (Build 10586.104 - 2016.02)",
@("Windows 10 Single Language (Threshold 2, February 2016 Update)", 116),
@("Windows 10 N (Threshold 2, February 2016 Update)", 115),
@("Windows 10 KN (Threshold 2, February 2016 Update)", -114),
@("Windows 10 China Get Genuine (Threshold 2, February 2016 Update)", -113),
@("Windows 10 Education N (Threshold 2, February 2016 Update)", 112),
@("Windows 10 Education KN (Threshold 2, February 2016 Update)", -111),
@("Windows 10 Education (Threshold 2, February 2016 Update)", 110),
@("Windows 10 (Threshold 2, February 2016 Update)", 109)
"1511 R2 [Threshold 2] (Build 10586.104 - 2016.02)",
@("Windows 10 Home/Pro", 109),
@("Windows 10 Home/Pro N", 115),
@("Windows 10 Single Language", 116),
@("Windows 10 Education", 110),
@("Windows 10 Education N", 112),
@("Windows 10 KN", ($ko + 114)),
@("Windows 10 Education KN", ($ko + 111)),
@("Windows 10 China Get Genuine", ($zh + 113))
),
@(
"1511 R1 (Build 10586.0 - 2015.11)",
@("Windows 10 Single Language (Threshold 2)", 106),
@("Windows 10 N (Threshold 2)", 105),
@("Windows 10 KN (Threshold 2)", -104),
@("Windows 10 China Get Genuine (Threshold 2)", -103),
@("Windows 10 Education N (Threshold 2)", 102),
@("Windows 10 Education KN (Threshold 2)", -101),
@("Windows 10 Education (Threshold 2)", 100),
@("Windows 10 (Threshold 2)", 99)
"1511 R1 [Threshold 2] (Build 10586.0 - 2015.11)",
@("Windows 10 Home/Pro", 99),
@("Windows 10 Home/Pro N", 105),
@("Windows 10 Single Language", 106),
@("Windows 10 Education", 100),
@("Windows 10 Education N", 102),
@("Windows 10 KN", ($ko + 104)),
@("Windows 10 Education KN", ($ko + 101)),
@("Windows 10 China Get Genuine", ($zh + 103))
),
@(
"1507 (Build 10240.16384 - 2015.07)",
@("Windows 10 Single Language (Threshold 1)", 82),
@("Windows 10 N (Threshold 1)", 81),
@("Windows 10 KN (Threshold 1)", -80),
@("Windows 10 (Threshold 1)", 79),
@("Windows 10 China Get Genuine (Threshold 1)", -78),
@("Windows 10 Education N (Threshold 1)", 77),
@("Windows 10 Education KN (Threshold 1)", -76),
@("Windows 10 Education (Threshold 1)", 75)
"1507 [Threshold 1] (Build 10240.16384 - 2015.07)",
@("Windows 10 Home/Pro", 79),
@("Windows 10 Home/Pro N", 81),
@("Windows 10 Single Language", 82),
@("Windows 10 Education", 75)
@("Windows 10 Education N", 77),
@("Windows 10 KN", ($ko + 80)),
@("Windows 10 Education KN", ($ko + 76)),
@("Windows 10 China Get Genuine", ($zh + 78))
)
),
@(
@@ -179,12 +170,8 @@ $WindowsVersions = @(
@("Windows 8.1", 52),
@("Windows 8.1 N", 55)
@("Windows 8.1 Single Language", 48),
@("Windows 8.1 Professional LE N", 71),
@("Windows 8.1 Professional LE KN", -70),
@("Windows 8.1 Professional LE K", -69),
@("Windows 8.1 Professional LE", 68),
@("Windows 8.1 KN", -62),
@("Windows 8.1 K", -61)
@("Windows 8.1 K", ($ko + 61)),
@("Windows 8.1 KN", ($ko + 62))
)
)
)
@@ -329,6 +316,17 @@ function ConvertTo-ImageSource
}
}
function Throw-Error([object]$Req, [string]$Alt)
{
$Err = $(GetElementById -Request $r -Id "errorModalMessage").innerText
if (-not $Err) {
$Err = $Alt
} else {
$Err = [System.Text.Encoding]::UTF8.GetString([byte[]][char[]]$Err)
}
throw $Err
}
# Translate a message string
function Get-Translation([string]$Text)
{
@@ -366,7 +364,7 @@ function GetElementById([object]$Request, [string]$Id)
function Error([string]$ErrorMessage)
{
Write-Host $ErrorMessage
Write-Host Error: $ErrorMessage
$XMLForm.Title = $(Get-Translation("Error")) + ": " + $ErrorMessage
Refresh-Control($XMLForm)
$Continue.Content = Get-Translation("Close")
@@ -438,14 +436,7 @@ if ($LocData -and (-not $LocData.StartsWith("en-US"))) {
}
$Locale = $Localized[0]
}
# Test if the Microsoft servers can handle our locale. If not, fall back to en-US.
$QueryLocale = $Locale
try {
$url = "https://www.microsoft.com/" + $QueryLocale + "/software-download/"
Invoke-WebRequest -UseBasicParsing -MaximumRedirection 0 -UserAgent $UserAgent $url | Out-Null
} catch {
$QueryLocale = "en-US"
}
# Make sure PowerShell 3.0 or later is used (for Invoke-WebRequest)
if ($PSVersionTable.PSVersion.Major -lt 3) {
@@ -513,6 +504,17 @@ $Continue.add_click({
switch ($Stage) {
1 { # Windows Version selection
$XMLForm.Title = Get-Translation($English[12])
Refresh-Control($XMLForm)
# Check if the locale we want is available - Fall back to en-US otherwise
try {
$url = "https://www.microsoft.com/" + $QueryLocale + "/software-download/"
Write-Host Querying $url
Invoke-WebRequest -UseBasicParsing -MaximumRedirection 0 -UserAgent $UserAgent $url | Out-Null
} catch {
$script:QueryLocale = "en-US"
}
$i = 0
$array = @()
foreach ($Version in $WindowsVersions[$WindowsVersion.SelectedValue.Index]) {
@@ -524,6 +526,7 @@ $Continue.add_click({
$script:WindowsRelease = Add-Entry $Stage "Release" $array
$Back.Content = Get-Translation($English[8])
$XMLForm.Title = $AppTitle
}
2 { # Windows Release selection => Populate Product Edition
@@ -531,8 +534,8 @@ $Continue.add_click({
foreach ($Release in $WindowsVersions[$WindowsVersion.SelectedValue.Index][$WindowsRelease.SelectedValue.Index])
{
if ($Release -is [array]) {
if ($Expert -or ($Release[1] -ge 0)) {
$array += @(New-Object PsObject -Property @{ Edition = $Release[0]; Id = $Release[1] })
if (($Release[1] -lt 0x10000) -or ($Locale.StartsWith("ko") -and ($Release[1] -band $ko)) -or ($Locale.StartsWith("zh") -and ($Release[1] -band $zh))) {
$array += @(New-Object PsObject -Property @{ Edition = $Release[0]; Id = $($Release[1] -band 0xFFFF) })
}
}
}
@@ -577,11 +580,7 @@ $Continue.add_click({
}
}
if ($array.Length -eq 0) {
$ErrorMessage = $(GetElementById -Request $r -Id "errorModalMessage").innerText
if ($ErrorMessage) {
Write-Host "$(Get-Translation("Error")): ""$ErrorMessage"""
}
throw "Could not parse languages"
Throw-Error -Req $r -Alt "Could not parse languages"
}
} catch {
Error($_.Exception.Message)
@@ -613,46 +612,29 @@ $Continue.add_click({
$Is64 = [Environment]::Is64BitOperatingSystem
$r = Invoke-WebRequest -UserAgent $UserAgent -WebSession $Session $url
if (-not $($r.AllElements | ? {$_.id -eq "expiration-time"})) {
$ErrorMessage = $(GetElementById -Request $r -Id "errorModalMessage").innerText
if ($ErrorMessage) {
Write-Host "$(Get-Translation("Error")): ""$ErrorMessage"""
}
throw Get-Translation($English[14])
Throw-Error -Req $r -Alt Get-Translation($English[14])
}
$html = $($r.AllElements | ? {$_.tagname -eq "input"}).outerHTML
# Need to fix the HTML and JSON data so that it is well-formed
$html = $html.Replace("class=product-download-hidden", "")
$html = $html.Replace("type=hidden", "")
$html = $html.Replace(">", "/>")
$html = $html.Replace(": I", ": ""I")
$html = $html.Replace(" }", """ }")
$html = $html.Replace("IsoX86", """x86""")
$html = $html.Replace("IsoX64", """x64""")
$html = "<inputs>" + $html + "</inputs>"
$xml = [xml]$html
foreach ($var in $xml.inputs.input) {
$json = $var.value | ConvertFrom-Json;
if ($json) {
$Type = $json.DownloadType
if ($Type -eq "IsoX64") {
$Type = "x64"
if ($Is64) {
$SelectedIndex = $i
}
} elseif ($Type -eq "IsoX86") {
$Type = "x86"
if (-not $Is64) {
$SelectedIndex = $i
}
if (($Is64 -and $json.DownloadType -eq "x64") -or (-not $Is64 -and $json.DownloadType -eq "x86")) {
$SelectedIndex = $i
}
$array += @(New-Object PsObject -Property @{ Type = $Type; Link = $json.Uri })
$array += @(New-Object PsObject -Property @{ Type = $json.DownloadType; Link = $json.Uri })
$i++
}
}
if ($array.Length -eq 0) {
$ErrorMessage = $(GetElementById -Request $r -Id "errorModalMessage").innerText
if ($ErrorMessage) {
Write-Host "$(Get-Translation("Error")): ""$ErrorMessage"""
}
throw "Could not retreive ISO download links"
Throw-Error -Req $r -Alt "Could not retreive ISO download links"
}
} catch {
Error($_.Exception.Message)

View File

@@ -63,3 +63,13 @@ make sure that you manually launch IE at least once and complete the setup.
Note that, if running this script elevated, this annoyance can be avoided by using the `-DisableFirstRunCustomize`
option (which basically __temporarily__ creates the key of the same name in the registry __if__ it doesn't already
exist, to bypass that behaviour).
Additional Notes
----------------
Because of it's intended usage with Rufus, this script is not designed to cover all possible retail ISO downloads, but
mostly those that the general public are likely to use. For instance, we currently have no plan to add support for
LTSB/LTSC Windows 10 ISOs downloads.
If you are interested in such downloads, you are kindly invited to visit the relevant download pages from Microsoft
such as [this one](https://www.microsoft.com/evalcenter/evaluate-windows-10-enterprise) for LTSC versions.