Compare commits

..

14 Commits
v1.17 ... v1.23

Author SHA1 Message Date
Pete Batard
2ee5f896d3 Add UEFI Shell bootable ISO downloads 2021-08-24 16:43:44 +02:00
Pete Batard
28725b287c Update README.md 2021-08-19 23:00:56 +02:00
Pete Batard
b7331f7873 Fix download of Windows 10 1507
* This versions uses weird SkuIds ('FQC-08932', 'FQC-08929', ...) that aren't integers...
* Closes pbatard/rufus#1769
2021-08-19 22:48:59 +02:00
Pete Batard
6160db3c66 Improve download handling for commandline
* Report the download size and handle errors
* Also improve exit code and verbosity handling
2021-08-15 13:44:38 +02:00
flx5
8b40c85d76 Add Commandline support
* Also fix a regression introduced by previous commit
* Closes #15
* Closes #24
2021-08-07 23:32:09 +02:00
Pete Batard
f70836e6c1 Split stages into separate function calls
* This is based on work done by flx5 in branch https://github.com/flx5/Fido
2021-08-06 22:39:34 +02:00
Pete Batard
af17001505 Add Windows 7 en-US ISO downloads
* Because why not?
2021-06-10 11:42:44 +01:00
Pete Batard
43adf47d5d Sign our script
* Because why not, and some folks might have policies where this could help.
2021-05-26 17:32:36 +01:00
Pete Batard
99f6f246b8 Add Windows 10 21H1 19043.985 builds
* https://support.microsoft.com/en-us/topic/windows-10-update-history-1b6aac92-bf01-42b5-b158-f80c6d93eb11
2021-05-22 17:34:07 +01:00
Pete Batard
36e9b4420c Remove DisableFirstRunCustomize related options
* No longer needed, since we are not invoking IE behind the scenes any more.
* Also update "fake" Firefox version range.
2021-05-22 13:35:51 +01:00
Pete Batard
6d630f83f2 Switch to basic parsing everywhere and perform our own DOM handling
* Addresses #19
* Also fix PowerShell 7.1.3 warnings
2021-05-13 14:10:12 +01:00
Pete Batard
ee0393cb74 Update version and copyright year 2021-01-30 02:55:42 +00:00
isos4all
a8abb94a16 Add Windows 10 20H2 19042.631 builds
* Microsoft updated 20H2 in December. Make sure we enable those downloads too.
* Closes #21
2021-01-30 02:53:59 +00:00
Pete Batard
15a48fe24f Fix script failure with PowerShell 7.x
* Won't help though, since Microsoft forcibly removed the ability to
  parse HTML in newer PowerShell, which we need...
* Also fix session variable not being set.
* Closes #19
2020-11-16 17:26:11 +00:00
3 changed files with 734 additions and 179 deletions

837
Fido.ps1
View File

@@ -1,6 +1,7 @@
#
# Fido v1.17 - Retail Windows ISO Downloader
# Copyright © 2019-2020 Pete Batard <pete@akeo.ie>
# Fido v1.23 - Retail Windows ISO Downloader
# Copyright © 2019-2021 Pete Batard <pete@akeo.ie>
# Command line support: Copyright © 2021 flx5
# ConvertTo-ImageSource: Copyright © 2016 Chris Carter
#
# This program is free software: you can redistribute it and/or modify
@@ -31,17 +32,31 @@ param(
# (Optional) Name of a pipe the download URL should be sent to.
# If not provided, a browser window is opened instead.
[string]$PipeName,
# (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) Specify Windows version (e.g. "Windows 10") [Toggles commandline mode]
[string]$Win,
# (Optional) Specify Windows release (e.g. "21H1") [Toggles commandline mode]
[string]$Rel,
# (Optional) Specify Windows edition (e.g. "Pro") [Toggles commandline mode]
[string]$Ed,
# (Optional) Specify Windows language [Toggles commandline mode]
[string]$Lang,
# (Optional) Specify Windows architecture [Toggles commandline mode]
[string]$Arch,
# (Optional) Only display the download URL [Toggles commandline mode]
[switch]$GetUrl = $False,
# (Optional) Increase verbosity
[switch]$Verbose = $False
)
#endregion
try {
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
} catch {}
Write-Host Please Wait...
$Cmd = $False
if ($Win -or $Rel -or $Ed -or $Lang -or $Arch -or $GetUrl) {
$Cmd = $True
}
#region Assembly Types
$code = @"
@@ -63,10 +78,17 @@ $code = @"
}
"@
Add-Type -MemberDefinition $code -Namespace Gui -UsingNamespace "System.IO", "System.Text", "System.Drawing", "System.Globalization" -ReferencedAssemblies System.Drawing -Name Utils -ErrorAction Stop
Add-Type -AssemblyName PresentationFramework
# Hide the powershell window: https://stackoverflow.com/a/27992426/1069307
[Gui.Utils]::ShowWindow(([System.Diagnostics.Process]::GetCurrentProcess() | Get-Process).MainWindowHandle, 0) | Out-Null
if (!$Cmd) {
Write-Host Please Wait...
if ($host.version -ge "7.0") {
Add-Type -WarningAction Ignore -IgnoreWarnings -MemberDefinition $code -Namespace Gui -UsingNamespace System.Runtime, System.IO, System.Text, System.Drawing, System.Globalization -ReferencedAssemblies System.Drawing.Common -Name Utils -ErrorAction Stop
} else {
Add-Type -MemberDefinition $code -Namespace Gui -UsingNamespace System.IO, System.Text, System.Drawing, System.Globalization -ReferencedAssemblies System.Drawing -Name Utils -ErrorAction Stop
}
Add-Type -AssemblyName PresentationFramework
# Hide the powershell window: https://stackoverflow.com/a/27992426/1069307
[Gui.Utils]::ShowWindow(([System.Diagnostics.Process]::GetCurrentProcess() | Get-Process).MainWindowHandle, 0) | Out-Null
}
#endregion
#region Data
@@ -75,6 +97,18 @@ $ko = 0x20000
$WindowsVersions = @(
@(
@("Windows 10", "Windows10ISO"),
@(
"21H1 (Build 19043.985 - 2021.05)",
@("Windows 10 Home/Pro", 2033),
@("Windows 10 Education", 2032),
@("Windows 10 Home China ", ($zh + 2034))
),
@(
"20H2 (Build 19042.631 - 2020.12)",
@("Windows 10 Home/Pro", 1882),
@("Windows 10 Education", 1884),
@("Windows 10 Home China ", ($zh + 1883))
),
@(
"20H2 (Build 19042.508 - 2020.10)",
@("Windows 10 Home/Pro", 1807),
@@ -197,14 +231,72 @@ $WindowsVersions = @(
@("Windows 8.1", "windows8ISO"),
@(
"Update 3 (build 9600)",
@("Windows 8.1", 52),
@("Windows 8.1 Standard", 52),
@("Windows 8.1 N", 55)
@("Windows 8.1 Single Language", 48),
@("Windows 8.1 K", ($ko + 61)),
@("Windows 8.1 KN", ($ko + 62))
)
),
@(
@("Windows 7", "WIN7"),
@(
"with SP1 (build 7601)",
@("Windows 7 Ultimate", 0),
@("Windows 7 Professional", 1),
@("Windows 7 Home Premium", 2)
)
),
@(
@("UEFI Shell v2", "UEFI_SHELL"),
@(
"21H1 (edk2-stable202105)",
@("Release", 0),
@("Debug", 1)
),
@(
"20H2 (edk2-stable202011)",
@("Release", 0),
@("Debug", 1)
)
)
)
$Windows7Versions = @(
# 0: Windows 7 Ultimate
@(
# Need a dummy to prevent PS from coalescing single array entries
@(""),
@("English (US)", "en-us",
@(
@("x64", "https://download.microsoft.com/download/5/1/9/5195A765-3A41-4A72-87D8-200D897CBE21/7601.24214.180801-1700.win7sp1_ldr_escrow_CLIENT_ULTIMATE_x64FRE_en-us.iso"),
@("x86", "https://download.microsoft.com/download/1/E/6/1E6B4803-DD2A-49DF-8468-69C0E6E36218/7601.24214.180801-1700.win7sp1_ldr_escrow_CLIENT_ULTIMATE_x86FRE_en-us.iso")
)
)
),
# 1: Windows 7 Profesional
@(
@(""),
@("English (US)", "en-us",
@(
@("x64", "https://download.microsoft.com/download/0/6/3/06365375-C346-4D65-87C7-EE41F55F736B/7601.24214.180801-1700.win7sp1_ldr_escrow_CLIENT_PROFESSIONAL_x64FRE_en-us.iso"),
@("x86", "https://download.microsoft.com/download/C/0/6/C067D0CD-3785-4727-898E-60DC3120BB14/7601.24214.180801-1700.win7sp1_ldr_escrow_CLIENT_PROFESSIONAL_x86FRE_en-us.iso")
)
)
),
# 2: Windows 7 Home Premium
@(
@(""),
@("English (US)", "en-us",
@(
@("x64", "https://download.microsoft.com/download/E/A/8/EA804D86-C3DF-4719-9966-6A66C9306598/7601.24214.180801-1700.win7sp1_ldr_escrow_CLIENT_HOMEPREMIUM_x64FRE_en-us.iso"),
@("x86", "https://download.microsoft.com/download/E/D/A/EDA6B508-7663-4E30-86F9-949932F443D0/7601.24214.180801-1700.win7sp1_ldr_escrow_CLIENT_HOMEPREMIUM_x86FRE_en-us.iso")
)
)
)
)
#endregion
#region Functions
@@ -306,7 +398,7 @@ function Add-Entry([int]$pos, [string]$Name, [array]$Items, [string]$DisplayName
function Refresh-Control([object]$Control)
{
$Control.Dispatcher.Invoke("Render", [Windows.Input.InputEventHandler] { $Continue.UpdateLayout() }, $null, $null)
$Control.Dispatcher.Invoke("Render", [Windows.Input.InputEventHandler] { $Continue.UpdateLayout() }, $null, $null) | Out-Null
}
function Send-Message([string]$PipeName, [string]$Message)
@@ -395,11 +487,15 @@ function GetElementById([object]$Request, [string]$Id)
function Error([string]$ErrorMessage)
{
Write-Host Error: $ErrorMessage
$XMLForm.Title = $(Get-Translation("Error")) + ": " + $ErrorMessage
Refresh-Control($XMLForm)
$XMLGrid.Children[2 * $script:Stage + 1].IsEnabled = $True
$UserInput = [System.Windows.MessageBox]::Show($XMLForm.Title, $(Get-Translation("Error")), "OK", "Error")
$script:ExitCode = $script:Stage--
if (!$Cmd) {
$XMLForm.Title = $(Get-Translation("Error")) + ": " + $ErrorMessage
Refresh-Control($XMLForm)
$XMLGrid.Children[2 * $script:Stage + 1].IsEnabled = $True
$UserInput = [System.Windows.MessageBox]::Show($XMLForm.Title, $(Get-Translation("Error")), "OK", "Error")
$script:ExitCode = $script:Stage--
} else {
$script:ExitCode = 2
}
}
function Get-RandomDate()
@@ -430,23 +526,34 @@ function Get-RandomDate()
#region Globals
$ErrorActionPreference = "Stop"
$dh = 58;
$dh = 58
$Stage = 0
$SelectedIndex = 0
$ltrm = ""
if ($Cmd) {
$ltrm = ""
}
$MaxStage = 4
$SessionId = [guid]::NewGuid()
$ExitCode = 100
$Locale = "en-US"
$DFRCKey = "HKLM:\Software\Policies\Microsoft\Internet Explorer\Main\"
$DFRCName = "DisableFirstRunCustomize"
$DFRCAdded = $False
$RequestData = @{}
# This GUID applies to all visitors, regardless of their locale
$RequestData["GetLangs"] = @("a8f8f489-4c7f-463a-9ca6-5cff94d8d041", "getskuinformationbyproductedition" )
$RequestData["GetLinks"] = @("cfa9e580-a81e-4a4b-a846-7b21bf4e2e5b", "GetProductDownloadLinksBySku" )
# This GUID applies to visitors of the en-US download page. Other locales may get a different GUID.
$RequestData["GetLinks"] = @("a224afab-2097-4dfa-a2ba-463eb191a285", "GetProductDownloadLinksBySku" )
# Create a semi-random Linux User-Agent string
$FirefoxVersion = Get-Random -Minimum 30 -Maximum 60
$FirefoxVersion = Get-Random -Minimum 50 -Maximum 90
$FirefoxDate = Get-RandomDate
$UserAgent = "Mozilla/5.0 (X11; Linux i586; rv:$FirefoxVersion.0) Gecko/$FirefoxDate Firefox/$FirefoxVersion.0"
$Verbosity = 2
if ($Cmd) {
if ($GetUrl) {
$Verbosity = 0
} elseif (!$Verbose) {
$Verbosity = 1
}
}
#endregion
# Localization
@@ -475,18 +582,370 @@ if ($PSVersionTable.PSVersion.Major -lt 3) {
exit 102
}
# If asked, disable IE's first run customize prompt as it interferes with Invoke-WebRequest
if ($DisableFirstRunCustomize) {
try {
# Only create the key if it doesn't already exist
Get-ItemProperty -Path $DFRCKey -Name $DFRCName
} catch {
if (-not (Test-Path $DFRCKey)) {
New-Item -Path $DFRCKey -Force | Out-Null
}
Set-ItemProperty -Path $DFRCKey -Name $DFRCName -Value 1
$DFRCAdded = $True
# Convert a size in bytes to a human readable string
function Size-To-Human-Readable([uint64]$size)
{
$suffix = "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
$i = 0
while ($size -gt 1kb) {
$size = $size / 1kb
$i++
}
"{0:N1} {1}" -f $size, $suffix[$i]
}
# Check if the locale we want is available - Fall back to en-US otherwise
function Check-Locale {
try {
$url = "https://www.microsoft.com/" + $QueryLocale + "/software-download/"
if ($Verbosity -ge 2) {
Write-Host Querying $url
}
Invoke-WebRequest -UseBasicParsing -MaximumRedirection 0 -UserAgent $UserAgent $url | Out-Null
} catch {
$script:QueryLocale = "en-US"
}
}
# Return an array of releases (e.g. 20H2, 21H1, ...) for the selected Windows version
function Get-Windows-Releases([int]$SelectedVersion)
{
$i = 0
$releases = @()
foreach ($version in $WindowsVersions[$SelectedVersion]) {
if (($i -ne 0) -and ($version -is [array])) {
$releases += @(New-Object PsObject -Property @{ Release = $ltrm + $version[0].Replace(")", ")" + $ltrm); Index = $i })
}
$i++
}
return $releases
}
# Return an array of editions (e.g. Home, Pro, etc) for the selected Windows release
function Get-Windows-Editions([int]$SelectedVersion, [int]$SelectedRelease)
{
$editions = @()
foreach ($release in $WindowsVersions[$SelectedVersion][$SelectedRelease])
{
if ($release -is [array]) {
if (($release[1] -lt 0x10000) -or ($Locale.StartsWith("ko") -and ($release[1] -band $ko)) -or ($Locale.StartsWith("zh") -and ($release[1] -band $zh))) {
$editions += @(New-Object PsObject -Property @{ Edition = $release[0]; Id = $($release[1] -band 0xFFFF) })
}
}
}
return $editions
}
# Return an array of languages for the selected edition
function Get-Windows-Languages([int]$SelectedVersion, [int]$SelectedEdition)
{
$languages = @()
$i = 0;
if ($WindowsVersions[$SelectedVersion][0][1] -eq "WIN7") {
foreach ($entry in $Windows7Versions[$SelectedEdition]) {
if ($entry[0] -ne "") {
$languages += @(New-Object PsObject -Property @{ DisplayLanguage = $entry[0]; Language = $entry[1]; Id = $i })
}
$i++
}
} elseif ($WindowsVersions[$SelectedVersion][0][1] -eq "UEFI_SHELL") {
$languages += @(New-Object PsObject -Property @{ DisplayLanguage = "English (US)"; Language = "en-us"; Id = 0 })
} else {
$url = "https://www.microsoft.com/" + $QueryLocale + "/api/controls/contentinclude/html"
$url += "?pageId=" + $RequestData["GetLangs"][0]
$url += "&host=www.microsoft.com"
$url += "&segments=software-download," + $WindowsVersions[$SelectedVersion][0][1]
$url += "&query=&action=" + $RequestData["GetLangs"][1]
$url += "&sessionId=" + $SessionId
$url += "&productEditionId=" + [Math]::Abs($SelectedEdition)
$url += "&sdVersion=2"
if ($Verbosity -ge 2) {
Write-Host Querying $url
}
$script:SelectedIndex = 0
try {
$r = Invoke-WebRequest -UseBasicParsing -UserAgent $UserAgent -SessionVariable "Session" $url
if ($r -match "errorModalMessage") {
Throw-Error -Req $r -Alt "Could not retrieve languages from server"
}
$pattern = '(?s)<select id="product-languages">(.*)?</select>'
$html = [regex]::Match($r, $pattern).Groups[1].Value
# Go through an XML conversion to keep all PowerShells happy...
$html = $html.Replace("selected value", "value")
$html = "<options>" + $html + "</options>"
$xml = [xml]$html
foreach ($var in $xml.options.option) {
$json = $var.value | ConvertFrom-Json;
if ($json) {
$languages += @(New-Object PsObject -Property @{ DisplayLanguage = $var.InnerText; Language = $json.language; Id = $json.id })
if (Select-Language($json.language)) {
$script:SelectedIndex = $i
}
$i++
}
}
if ($languages.Length -eq 0) {
Throw-Error -Req $r -Alt "Could not parse languages"
}
} catch {
Error($_.Exception.Message)
return @()
}
}
return $languages
}
# Return an array of download links for each supported arch
function Get-Windows-Download-Links([int]$SelectedVersion, [int]$SelectedRelease, [int]$SelectedEdition, [string]$SkuId, [string]$LanguageName)
{
$links = @()
if ($WindowsVersions[$SelectedVersion][0][1] -eq "WIN7") {
foreach ($Version in $Windows7Versions[$SelectedEdition][$SkuId][2]) {
$links += @(New-Object PsObject -Property @{ Type = $Version[0]; Link = $Version[1] })
}
} elseif ($WindowsVersions[$SelectedVersion][0][1] -eq "UEFI_SHELL") {
$tag = $WindowsVersions[$SelectedVersion][$SelectedRelease][0].SubString(0,4)
$url = "https://github.com/pbatard/UEFI-Shell/releases/download/" + $tag + "/UEFI-Shell_" + $tag
if ($SelectedEdition -eq 0) {
$url += "_RELEASE.iso"
} else {
$url += "_DEBUG.iso"
}
# TODO: Read the supported archs from the release (from an XML file or something)
$links += @(New-Object PsObject -Property @{ Type = "X64, IA32, AARCH64, ARM"; Link = $url })
} else {
$url = "https://www.microsoft.com/" + $QueryLocale + "/api/controls/contentinclude/html"
$url += "?pageId=" + $RequestData["GetLinks"][0]
$url += "&host=www.microsoft.com"
$url += "&segments=software-download," + $WindowsVersions[$SelectedVersion][0][1]
$url += "&query=&action=" + $RequestData["GetLinks"][1]
$url += "&sessionId=" + $SessionId
$url += "&skuId=" + $SkuId
$url += "&language=" + $LanguageName
$url += "&sdVersion=2"
if ($Verbosity -ge 2) {
Write-Host Querying $url
}
$i = 0
$script:SelectedIndex = 0
try {
$Is64 = [Environment]::Is64BitOperatingSystem
$r = Invoke-WebRequest -Method Post -UseBasicParsing -UserAgent $UserAgent -WebSession $Session $url
if ($r -match "errorModalMessage") {
Throw-Error -Req $r -Alt "Could not retrieve architectures from server"
}
$pattern = '(?s)(<input.*?></input>)'
ForEach-Object { [regex]::Matches($r, $pattern) } | ForEach-Object { $html += $_.Groups[1].value }
# 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("&nbsp;", " ")
$html = $html.Replace("IsoX86", "&quot;x86&quot;")
$html = $html.Replace("IsoX64", "&quot;x64&quot;")
$html = "<inputs>" + $html + "</inputs>"
$xml = [xml]$html
foreach ($var in $xml.inputs.input) {
$json = $var.value | ConvertFrom-Json;
if ($json) {
if (($Is64 -and $json.DownloadType -eq "x64") -or (-not $Is64 -and $json.DownloadType -eq "x86")) {
$script:SelectedIndex = $i
}
$links += @(New-Object PsObject -Property @{ Type = $json.DownloadType; Link = $json.Uri })
$i++
}
}
if ($links.Length -eq 0) {
Throw-Error -Req $r -Alt "Could not retrieve ISO download links"
}
} catch {
Error($_.Exception.Message)
return @()
}
}
return $links
}
# Process the download URL by either sending it through the pipe or by opening the browser
function Process-Download-Link([string]$Url)
{
try {
if ($PipeName -and -not $Check.IsChecked) {
Send-Message -PipeName $PipeName -Message $Url
} else {
if ($Cmd) {
$pattern = '.*\/(.*\.iso).*'
$File = [regex]::Match($Url, $pattern).Groups[1].Value
$Size = Size-To-Human-Readable (Invoke-WebRequest -UseBasicParsing -Uri $Url -Method Head).Headers.'Content-Length'
Write-Host "Downloading '$File' ($Size)..."
Invoke-WebRequest -UseBasicParsing -Uri $Url -OutFile $File
} else {
Write-Host Download Link: $Url
Start-Process -FilePath $Url
}
}
} catch {
Error($_.Exception.Message)
return 404
}
return 0
}
if ($Cmd) {
$winVersionId = $null
$winReleaseId = $null
$winEditionId = $null
$winLanguageId = $null
$winLanguageName = $null
$winLink = $null
$i = 0
$Selected = ""
if ($Win -eq "List") {
Write-Host "Please select a Windows Version (-Win):"
}
foreach($version in $WindowsVersions) {
if ($Win -eq "List") {
Write-Host " -" $version[0][0]
} elseif ($version[0][0] -match $Win) {
$Selected += $version[0][0]
$winVersionId = $i
break;
}
$i++
}
if ($winVersionId -eq $null) {
if ($Win -ne "List") {
Write-Host "Invalid Windows version provided."
Write-Host "Use '-Win List' for a list of available Windows versions."
}
exit 1
}
# Windows Version selection
$releases = Get-Windows-Releases $winVersionId
if ($Rel -eq "List") {
Write-Host "Please select a Windows Release (-Rel) for ${Selected} (or use 'Latest' for most recent):"
}
foreach ($release in $releases) {
if ($Rel -eq "List") {
Write-Host " -" $release.Release
} elseif (!$Rel -or $release.Release.StartsWith($Rel) -or $Rel -eq "Latest") {
if (!$Rel -and $Verbosity -ge 1) {
Write-Host "No release specified (-Rel). Defaulting to '$($release.Release)'."
}
$Selected += " " + $release.Release
$winReleaseId = $release.Index
break;
}
}
if ($winReleaseId -eq $null) {
if ($Rel -ne "List") {
Write-Host "Invalid Windows release provided."
Write-Host "Use '-Rel List' for a list of available $Selected releases or '-Rel Latest' for latest."
}
exit 1
}
# Windows Release selection => Populate Product Edition
$editions = Get-Windows-Editions $winVersionId $winReleaseId
if ($Ed -eq "List") {
Write-Host "Please select a Windows Edition (-Ed) for ${Selected}:"
}
foreach($edition in $editions) {
if ($Ed -eq "List") {
Write-Host " -" $edition.Edition
} elseif (!$Ed -or $edition.Edition -match $Ed) {
if (!$Ed -and $Verbosity -ge 1) {
Write-Host "No edition specified (-Ed). Defaulting to '$($edition.Edition)'."
}
$Selected += "," + $edition.Edition -replace "Windows [0-9\.]*", ""
$winEditionId = $edition.Id
break;
}
}
if ($winEditionId -eq $null) {
if ($Ed -ne "List") {
Write-Host "Invalid Windows edition provided."
Write-Host "Use '-Ed List' for a list of available editions or remove the -Ed parameter to use default."
}
exit 1
}
# Product Edition selection => Request and populate Languages
$languages = Get-Windows-Languages $winVersionId $winEditionId
if (!$languages) {
exit 3
}
if ($Lang -eq "List") {
Write-Host "Please select a Language (-Lang) for ${Selected}:"
}
$i = 0
foreach ($language in $languages) {
if ($Lang -eq "List") {
Write-Host " -" $language.Language
} elseif ((!$Lang -and $script:SelectedIndex -eq $i) -or ($Lang -and $language.Language -match $Lang)) {
if (!$Lang -and $Verbosity -ge 1) {
Write-Host "No language specified (-Lang). Defaulting to '$($language.Language)'."
}
$Selected += ", " + $language.Language
$winLanguageId = $language.Id
$winLanguageName = $language.Language
break;
}
$i++
}
if ($winLanguageId -eq $null -or $winLanguageName -eq $null) {
if ($Lang -ne "List") {
Write-Host "Invalid Windows language provided."
Write-Host "Use '-Lang List' for a list of available languages or remove the option to use system default."
}
exit 1
}
# Language selection => Request and populate Arch download links
$links = Get-Windows-Download-Links $winVersionId $winReleaseId $winEditionId $winLanguageId $winLanguageName
if (!$links) {
exit 3
}
if ($Arch -eq "List") {
Write-Host "Please select an Architecture (-Arch) for ${Selected}:"
}
$i = 0
foreach ($link in $links) {
if ($Arch -eq "List") {
Write-Host " -" $link.Type
} elseif ((!$Arch -and $script:SelectedIndex -eq $i) -or ($Arch -and $link.Type -match $Arch)) {
if (!$Arch -and $Verbosity -ge 1) {
Write-Host "No architecture specified (-Arch). Defaulting to '$($link.Type)'."
}
$Selected += ", " + $link.Type
$winLink = $link
break;
}
$i++
}
if ($winLink -eq $null) {
if ($Arch -ne "List") {
Write-Host "Invalid Windows architecture provided."
Write-Host "Use '-Arch List' for a list of available architectures or remove the option to use system default."
}
exit 1
}
# Arch selection => Return selected download link
if ($GetUrl) {
Return $winLink.Link
$ExitCode = 0
} else {
Write-Host "Selected: $Selected"
$ExitCode = Process-Download-Link $winLink.Link
}
# Clean up & exit
exit $ExitCode
}
# Form creation
@@ -498,7 +957,7 @@ if ($Icon) {
} else {
$XMLForm.Icon = [Gui.Utils]::ExtractIcon("shell32.dll", -41, $true) | ConvertTo-ImageSource
}
if ($Locale.StartsWith("ar") -or $Locale.StartsWith("fa") -or $Locale.StartsWith("he")) {
if ($Locale.StartsWith("ar") -or $Locale.StartsWith("fa") -or $Locale.StartsWith("he")) {
$XMLForm.FlowDirection = "RightToLeft"
}
$WindowsVersionTitle.Text = Get-Translation("Version")
@@ -507,12 +966,12 @@ $Back.Content = Get-Translation("Close")
# Populate the Windows versions
$i = 0
$array = @()
foreach($Version in $WindowsVersions) {
$array += @(New-Object PsObject -Property @{ Version = $Version[0][0]; PageType = $Version[0][1]; Index = $i })
$versions = @()
foreach($version in $WindowsVersions) {
$versions += @(New-Object PsObject -Property @{ Version = $version[0][0]; PageType = $version[0][1]; Index = $i })
$i++
}
$WindowsVersion.ItemsSource = $array
$WindowsVersion.ItemsSource = $versions
$WindowsVersion.DisplayMemberPath = "Version"
# Button Action
@@ -529,143 +988,40 @@ $Continue.add_click({
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"
if ($WindowsVersion.SelectedValue.Version.StartsWith("Windows") -and $WindowsVersion.SelectedValue.Version -ne "Windows 7") {
Check-Locale
}
$i = 0
$array = @()
foreach ($Version in $WindowsVersions[$WindowsVersion.SelectedValue.Index]) {
if (($i -ne 0) -and ($Version -is [array])) {
$array += @(New-Object PsObject -Property @{ Release = $ltrm + $Version[0].Replace(")", ")" + $ltrm); Index = $i })
}
$i++
}
$script:WindowsRelease = Add-Entry $Stage "Release" $array
$releases = Get-Windows-Releases $WindowsVersion.SelectedValue.Index
$script:WindowsRelease = Add-Entry $Stage "Release" $releases
$Back.Content = Get-Translation($English[8])
$XMLForm.Title = $AppTitle
}
2 { # Windows Release selection => Populate Product Edition
$array = @()
foreach ($Release in $WindowsVersions[$WindowsVersion.SelectedValue.Index][$WindowsRelease.SelectedValue.Index])
{
if ($Release -is [array]) {
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) })
}
}
}
$script:ProductEdition = Add-Entry $Stage "Edition" $array
$editions = Get-Windows-Editions $WindowsVersion.SelectedValue.Index $WindowsRelease.SelectedValue.Index
$script:ProductEdition = Add-Entry $Stage "Edition" $editions
}
3 { # Product Edition selection => Request and populate Languages
3 { # Product Edition selection => Request and populate languages
$XMLForm.Title = Get-Translation($English[12])
Refresh-Control($XMLForm)
$url = "https://www.microsoft.com/" + $QueryLocale + "/api/controls/contentinclude/html"
$url += "?pageId=" + $RequestData["GetLangs"][0]
$url += "&host=www.microsoft.com"
$url += "&segments=software-download," + $WindowsVersion.SelectedValue.PageType
$url += "&query=&action=" + $RequestData["GetLangs"][1]
$url += "&sessionId=" + $SessionId
$url += "&productEditionId=" + [Math]::Abs($ProductEdition.SelectedValue.Id)
$url += "&sdVersion=2"
Write-Host Querying $url
$array = @()
$i = 0
$SelectedIndex = 0
try {
$r = Invoke-WebRequest -UserAgent $UserAgent -WebSession $Session $url
# Go through an XML conversion to keep all PowerShells happy...
if (-not $($r.AllElements | ? {$_.id -eq "product-languages"})) {
throw "Unexpected server response"
}
$html = $($r.AllElements | ? {$_.id -eq "product-languages"}).InnerHTML
$html = $html.Replace("selected value", "value")
$html = $html.Replace("&", "&amp;")
$html = "<options>" + $html + "</options>"
$xml = [xml]$html
foreach ($var in $xml.options.option) {
$json = $var.value | ConvertFrom-Json;
if ($json) {
$array += @(New-Object PsObject -Property @{ DisplayLanguage = $var.InnerText; Language = $json.language; Id = $json.id })
if (Select-Language($json.language)) {
$SelectedIndex = $i
}
$i++
}
}
if ($array.Length -eq 0) {
Throw-Error -Req $r -Alt "Could not parse languages"
}
} catch {
Error($_.Exception.Message)
$languages = Get-Windows-Languages $WindowsVersion.SelectedValue.Index $ProductEdition.SelectedValue.Id
if ($languages.Length -eq 0) {
break
}
$script:Language = Add-Entry $Stage "Language" $array "DisplayLanguage"
$Language.SelectedIndex = $SelectedIndex
$script:Language = Add-Entry $Stage "Language" $languages "DisplayLanguage"
$Language.SelectedIndex = $script:SelectedIndex
$XMLForm.Title = $AppTitle
}
4 { # Language selection => Request and populate Arch download links
$XMLForm.Title = Get-Translation($English[12])
Refresh-Control($XMLForm)
$url = "https://www.microsoft.com/" + $QueryLocale + "/api/controls/contentinclude/html"
$url += "?pageId=" + $RequestData["GetLinks"][0]
$url += "&host=www.microsoft.com"
$url += "&segments=software-download," + $WindowsVersion.SelectedValue.PageType
$url += "&query=&action=" + $RequestData["GetLinks"][1]
$url += "&sessionId=" + $SessionId
$url += "&skuId=" + $Language.SelectedValue.Id
$url += "&language=" + $Language.SelectedValue.Language
$url += "&sdVersion=2"
Write-Host Querying $url
$i = 0
$SelectedIndex = 0
$array = @()
try {
$Is64 = [Environment]::Is64BitOperatingSystem
$r = Invoke-WebRequest -UserAgent $UserAgent -WebSession $Session $url
if (-not $($r.AllElements | ? {$_.id -eq "expiration-time"})) {
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("&nbsp;", " ")
$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) {
if (($Is64 -and $json.DownloadType -eq "x64") -or (-not $Is64 -and $json.DownloadType -eq "x86")) {
$SelectedIndex = $i
}
$array += @(New-Object PsObject -Property @{ Type = $json.DownloadType; Link = $json.Uri })
$i++
}
}
if ($array.Length -eq 0) {
Throw-Error -Req $r -Alt "Could not retrieve ISO download links"
}
} catch {
Error($_.Exception.Message)
$links = Get-Windows-Download-Links $WindowsVersion.SelectedValue.Index $WindowsRelease.SelectedValue.Index $ProductEdition.SelectedValue.Id $Language.SelectedValue.Id $Language.SelectedValue.Language
if ($links.Length -eq 0) {
break
}
$script:Arch = Add-Entry $Stage "Architecture" $array "Type"
$script:Architecture = Add-Entry $Stage "Architecture" $links "Type"
if ($PipeName) {
$XMLForm.Height += $dh / 2;
$Margin = $Continue.Margin
@@ -681,19 +1037,13 @@ $Continue.add_click({
$Check.Content = Get-Translation($English[13])
$Check.Visibility = "Visible"
}
$Arch.SelectedIndex = $SelectedIndex
$Architecture.SelectedIndex = $script:SelectedIndex
$Continue.Content = Get-Translation("Download")
$XMLForm.Title = $AppTitle
}
5 { # Arch selection => Return selected download link
if ($PipeName -and -not $Check.IsChecked) {
Send-Message -PipeName $PipeName -Message $Arch.SelectedValue.Link
} else {
Write-Host Download Link: $Arch.SelectedValue.Link
Start-Process -FilePath $Arch.SelectedValue.Link
}
$script:ExitCode = 0
$script:ExitCode = Process-Download-Link $Architecture.SelectedValue.Link
$XMLForm.Close()
}
}
@@ -738,7 +1088,158 @@ $XMLForm.Add_Loaded( { $XMLForm.Activate() } )
$XMLForm.ShowDialog() | Out-Null
# Clean up & exit
if ($DFRCAdded) {
Remove-ItemProperty -Path $DFRCKey -Name $DFRCName
}
exit $ExitCode
# SIG # Begin signature block
# MIIcQgYJKoZIhvcNAQcCoIIcMzCCHC8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAU0UbnjQJMRkcW
# 9/SYEZb3CBUSWmQAyJcWC8Q647QEXaCCCy4wggVGMIIELqADAgECAhAkaSZj72wM
# Cjsjz6MQw2SbMA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAkdCMRswGQYDVQQI
# ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoT
# EUNPTU9ETyBDQSBMaW1pdGVkMSMwIQYDVQQDExpDT01PRE8gUlNBIENvZGUgU2ln
# bmluZyBDQTAeFw0xODAzMTYwMDAwMDBaFw0yMjAzMTYyMzU5NTlaMIGTMQswCQYD
# VQQGEwJJRTERMA8GA1UEEQwIRjkyIEQ2NjcxFDASBgNVBAgMC0NvLiBEb25lZ2Fs
# MRAwDgYDVQQHDAdNaWxmb3JkMRUwEwYDVQQJDAwyNCBHcmV5IFJvY2sxGDAWBgNV
# BAoMD0FrZW8gQ29uc3VsdGluZzEYMBYGA1UEAwwPQWtlbyBDb25zdWx0aW5nMIIB
# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAucIiMwsQe8seN3s519ZbhFfX
# XswzuieRtmXeB9nVlsU2s5UFZ3pdNSh9upBdHB08LC0zCiowvXxljlKrxVEP+sxZ
# 54AGNqcGdPDyKFVugkFXOLmVo0YI2HQ1H6Sig7ML229vAeXoOqze0xZfBJ3L5Z0S
# rs/Tr+X1pN/UcjiIrT2ka3wXi/Rw/qUPwfAEpzHLPEgGT3z04vfb13Y2GZ6tR5LY
# 7g2jFWZVB4AeeH0oVoPoHFjWWzh2sutbeWDV784MrMEvokFFBalQSq2Hdjbz0wCw
# WvlnJXpAwexdLWsUuDNqihK+u5TqCa0s5wQa9g7j4Lnh/gE2gT82ZpvG4FWpQQID
# AQABo4IBqTCCAaUwHwYDVR0jBBgwFoAUKZFg/4pN+uv5pmq4z/nmS71JzhIwHQYD
# VR0OBBYEFHqk0HHXrPqMfyjl4r9RvfCV36uOMA4GA1UdDwEB/wQEAwIHgDAMBgNV
# HRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG+EIBAQQEAwIE
# EDBGBgNVHSAEPzA9MDsGDCsGAQQBsjEBAgEDAjArMCkGCCsGAQUFBwIBFh1odHRw
# czovL3NlY3VyZS5jb21vZG8ubmV0L0NQUzBDBgNVHR8EPDA6MDigNqA0hjJodHRw
# Oi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDb2RlU2lnbmluZ0NBLmNybDB0
# BggrBgEFBQcBAQRoMGYwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQuY29tb2RvY2Eu
# Y29tL0NPTU9ET1JTQUNvZGVTaWduaW5nQ0EuY3J0MCQGCCsGAQUFBzABhhhodHRw
# Oi8vb2NzcC5jb21vZG9jYS5jb20wGgYDVR0RBBMwEYEPc3VwcG9ydEBha2VvLmll
# MA0GCSqGSIb3DQEBCwUAA4IBAQA3dG72Ftdt3/AXoxMDovsxatdFghcKHjl01+8x
# 6iguabtan9Lqz2yulzj4px2KCUV64VPhRytaS15YHZDJH7Q9BlTvcgNpSujs3fkQ
# KdSmHs+MrNMetpAT6WH185J1z/3rRLc/LpESc6tipocAkA7uPualGIkBJNFEwqiT
# aTjR3h3zGZs2aEJJ2X8DgBEg9zgZNUzr6zsprHyCODAtmO89owAywKQbu/ZczsVE
# mPJKgJ511BZlyTLW5elvB17QX95vqoit0ZGhbMTHKtJxojyUZZC7Y+cV6E6/HbQA
# tvcFWa5BzljDyRC70uFeEPV8t6ine6ytd98BWaF13IB8jqYQMIIF4DCCA8igAwIB
# AgIQLnyHzA6TSlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UEBhMC
# R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9y
# ZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBS
# U0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5MDAwMDAwWhcNMjgw
# NTA4MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5j
# aGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGlt
# aXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0G
# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR3elnMRHrzB79MR2z
# uWJXP5O8W+OfHiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvthe4YJs+P9omidHCyd
# v3Lj5HWg5TUjjsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3e9V5kAoUGFEs5v7B
# EvAcP2FhCoyi3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQc5hc9IVKaw+A3V7W
# vf2pL8Al9fl4141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPiXzjbxghdR7ODQfAu
# ADcUuRKqeZJSzYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmLAgaff9ULAgMBAAGj
# ggFRMIIBTTAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs2TIy1DAdBgNVHQ4E
# FgQUKZFg/4pN+uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB
# /wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYDVR0gBAowCDAGBgRV
# HSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NP
# TU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUw
# YzA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNB
# QWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2Nh
# LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4MbU2x8U6ST6/COCwE
# zMVjEasJY6+rotcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQciGlEcOtTh6Qm/5iR0
# rx57FjFuI+9UUS1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHfWGshqknUfDdOvf+2
# dVRAGDZXZxHNTwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HITfK7ZU2o94VFB696
# aSdlkClAi997OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46BLqioXwfy2M6FafU
# FRunUkcyqfS/ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gbqjSm/Iz13X9ljIwx
# VzHQNuxHoc/Li6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm5LLY5TjCqO3GgZw1
# a6lYYUoKl7RLQrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQFhv/K53b0CDKieoo
# fjKOGd97SDMe12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5sL6iPDAZQ+4wns3bJ
# 9ObXwzTijIchhmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55ZmjoIs2475iFTZYR
# PAmK0H+8KCgT+2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6Q++6Z2H/fUnguzB9
# XIDj5hY5S6cxghBqMIIQZgIBATCBkTB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS
# R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
# T01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25p
# bmcgQ0ECECRpJmPvbAwKOyPPoxDDZJswDQYJYIZIAWUDBAIBBQCgfDAQBgorBgEE
# AYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3
# AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgJBgYMTvD/pIJ2ds3
# kPJ6Yy1Qofs3TQ3VUw1Mi2soK9swDQYJKoZIhvcNAQEBBQAEggEAA5RNsTmrYt2w
# iRt4jnqkBZ7YvSpPWeSutJgX1c3Tzwm8RTUJRMu8yu8b410cHAZ6jkrZ6oRJW+n2
# tgzNCK4vbBDUgFbOYU5BEOpmDU1vuga17ary5rN3/AHOSE/TuHLt/a7Az6AHj9sG
# 28OJxM68ZAs5VBH1XFzpI9t9OWlIAFQ6vgPQhXUyu9/NTQ7WfMob7A2sVfTRTTF/
# ZE7r52v0iDmoUi5wz/c0lbRQWlIEzt8B8SbkQULx6cHRHKy+SDCkjxJI/TqXdvnn
# IbF+eloX413aq5W6/8mVpYoKlLRbbS94X1PgKMHxtS/0Ya4Mpbyr+9pjG6YhidA8
# G30mjrHDj6GCDiswgg4nBgorBgEEAYI3AwMBMYIOFzCCDhMGCSqGSIb3DQEHAqCC
# DgQwgg4AAgEDMQ0wCwYJYIZIAWUDBAIBMIH+BgsqhkiG9w0BCRABBKCB7gSB6zCB
# 6AIBAQYLYIZIAYb4RQEHFwMwITAJBgUrDgMCGgUABBRle6XLfAF1irMqXfHR3RfL
# AxIw0gIUMj3OWqGgsLUt+ICmTL9aGS/WQqEYDzIwMjEwODI0MTQ0MjM1WjADAgEe
# oIGGpIGDMIGAMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9y
# YXRpb24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxMTAvBgNVBAMT
# KFN5bWFudGVjIFNIQTI1NiBUaW1lU3RhbXBpbmcgU2lnbmVyIC0gRzOgggqLMIIF
# ODCCBCCgAwIBAgIQewWx1EloUUT3yYnSnBmdEjANBgkqhkiG9w0BAQsFADCBvTEL
# MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
# ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2ln
# biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJp
# U2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x
# NjAxMTIwMDAwMDBaFw0zMTAxMTEyMzU5NTlaMHcxCzAJBgNVBAYTAlVTMR0wGwYD
# VQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1
# c3QgTmV0d29yazEoMCYGA1UEAxMfU3ltYW50ZWMgU0hBMjU2IFRpbWVTdGFtcGlu
# ZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALtZnVlVT52Mcl0a
# gaLrVfOwAa08cawyjwVrhponADKXak3JZBRLKbvC2Sm5Luxjs+HPPwtWkPhiG37r
# pgfi3n9ebUA41JEG50F8eRzLy60bv9iVkfPw7mz4rZY5Ln/BJ7h4OcWEpe3tr4eO
# zo3HberSmLU6Hx45ncP0mqj0hOHE0XxxxgYptD/kgw0mw3sIPk35CrczSf/KO9T1
# sptL4YiZGvXA6TMU1t/HgNuR7v68kldyd/TNqMz+CfWTN76ViGrF3PSxS9TO6AmR
# X7WEeTWKeKwZMo8jwTJBG1kOqT6xzPnWK++32OTVHW0ROpL2k8mc40juu1MO1DaX
# hnjFoTcCAwEAAaOCAXcwggFzMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG
# AQH/AgEAMGYGA1UdIARfMF0wWwYLYIZIAYb4RQEHFwMwTDAjBggrBgEFBQcCARYX
# aHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9k
# LnN5bWNiLmNvbS9ycGEwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRw
# Oi8vcy5zeW1jZC5jb20wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL3Muc3ltY2Iu
# Y29tL3VuaXZlcnNhbC1yb290LmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAoBgNV
# HREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMzAdBgNVHQ4EFgQU
# r2PWyqNOhXLgp7xB8ymiOH+AdWIwHwYDVR0jBBgwFoAUtnf6aUhHn1MS1cLqBzJ2
# B9GXBxkwDQYJKoZIhvcNAQELBQADggEBAHXqsC3VNBlcMkX+DuHUT6Z4wW/X6t3c
# T/OhyIGI96ePFeZAKa3mXfSi2VZkhHEwKt0eYRdmIFYGmBmNXXHy+Je8Cf0ckUfJ
# 4uiNA/vMkC/WCmxOM+zWtJPITJBjSDlAIcTd1m6JmDy1mJfoqQa3CcmPU1dBkC/h
# Hk1O3MoQeGxCbvC2xfhhXFL1TvZrjfdKer7zzf0D19n2A6gP41P3CnXsxnUuqmaF
# BJm3+AZX4cYO9uiv2uybGB+queM6AL/OipTLAduexzi7D1Kr0eOUA2AKTaD+J20U
# Mvw/l0Dhv5mJ2+Q5FL3a5NPD6itas5VYVQR9x5rsIwONhSrS/66pYYEwggVLMIIE
# M6ADAgECAhB71OWvuswHP6EBIwQiQU0SMA0GCSqGSIb3DQEBCwUAMHcxCzAJBgNV
# BAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMW
# U3ltYW50ZWMgVHJ1c3QgTmV0d29yazEoMCYGA1UEAxMfU3ltYW50ZWMgU0hBMjU2
# IFRpbWVTdGFtcGluZyBDQTAeFw0xNzEyMjMwMDAwMDBaFw0yOTAzMjIyMzU5NTla
# MIGAMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24x
# HzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxMTAvBgNVBAMTKFN5bWFu
# dGVjIFNIQTI1NiBUaW1lU3RhbXBpbmcgU2lnbmVyIC0gRzMwggEiMA0GCSqGSIb3
# DQEBAQUAA4IBDwAwggEKAoIBAQCvDoqq+Ny/aXtUF3FHCb2NPIH4dBV3Z5Cc/d5O
# Ap5LdvblNj5l1SQgbTD53R2D6T8nSjNObRaK5I1AjSKqvqcLG9IHtjy1GiQo+Bty
# UT3ICYgmCDr5+kMjdUdwDLNfW48IHXJIV2VNrwI8QPf03TI4kz/lLKbzWSPLgN4T
# TfkQyaoKGGxVYVfR8QIsxLWr8mwj0p8NDxlsrYViaf1OhcGKUjGrW9jJdFLjV2wi
# v1V/b8oGqz9KtyJ2ZezsNvKWlYEmLP27mKoBONOvJUCbCVPwKVeFWF7qhUhBIYfl
# 3rTTJrJ7QFNYeY5SMQZNlANFxM48A+y3API6IsW0b+XvsIqbAgMBAAGjggHHMIIB
# wzAMBgNVHRMBAf8EAjAAMGYGA1UdIARfMF0wWwYLYIZIAYb4RQEHFwMwTDAjBggr
# BgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGRoX
# aHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDov
# L3RzLWNybC53cy5zeW1hbnRlYy5jb20vc2hhMjU2LXRzcy1jYS5jcmwwFgYDVR0l
# AQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMHcGCCsGAQUFBwEBBGsw
# aTAqBggrBgEFBQcwAYYeaHR0cDovL3RzLW9jc3Aud3Muc3ltYW50ZWMuY29tMDsG
# CCsGAQUFBzAChi9odHRwOi8vdHMtYWlhLndzLnN5bWFudGVjLmNvbS9zaGEyNTYt
# dHNzLWNhLmNlcjAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIw
# NDgtNjAdBgNVHQ4EFgQUpRMBqZ+FzBtuFh5fOzGqeTYAex0wHwYDVR0jBBgwFoAU
# r2PWyqNOhXLgp7xB8ymiOH+AdWIwDQYJKoZIhvcNAQELBQADggEBAEaer/C4ol+i
# mUjPqCdLIc2yuaZycGMv41UpezlGTud+ZQZYi7xXipINCNgQujYk+gp7+zvTYr9K
# lBXmgtuKVG3/KP5nz3E/5jMJ2aJZEPQeSv5lzN7Ua+NSKXUASiulzMub6KlN97QX
# WZJBw7c/hub2wH9EPEZcF1rjpDvVaSbVIX3hgGd+Yqy3Ti4VmuWcI69bEepxqUH5
# DXk4qaENz7Sx2j6aescixXTN30cJhsT8kSWyG5bphQjo3ep0YG5gpVZ6DchEWNzm
# +UgUnuW/3gC9d7GYFHIUJN/HESwfAD/DSxTGZxzMHgajkF9cVIs+4zNbgg/Ft4YC
# TnGf6WZFP3YxggJaMIICVgIBATCBizB3MQswCQYDVQQGEwJVUzEdMBsGA1UEChMU
# U3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5l
# dHdvcmsxKDAmBgNVBAMTH1N5bWFudGVjIFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EC
# EHvU5a+6zAc/oQEjBCJBTRIwCwYJYIZIAWUDBAIBoIGkMBoGCSqGSIb3DQEJAzEN
# BgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjEwODI0MTQ0MjM1WjAvBgkq
# hkiG9w0BCQQxIgQg+8r+miUYUaWD81auvyH5duQKFpfNCvFn1LPKV9UJT3EwNwYL
# KoZIhvcNAQkQAi8xKDAmMCQwIgQgxHTOdgB9AjlODaXk3nwUxoD54oIBPP72U+9d
# tx/fYfgwCwYJKoZIhvcNAQEBBIIBAAa8bZCJyW7ZsiHiXpxlBvzBAK+5Ft4xMw7i
# XPST6hrNYVCpFgW1L70Euu0naSwfYmmipY1ZoPZZjVe2ANf5HZQUEgvhWgZXx6nL
# Zzltbb8Oy3lZlDqxd97hxPwEXIPsmdjoC1JS6KO8FHppcBIqTBCbgPyi+KYOHIxO
# 5tAaG3lzF2JF2IjpYworOaNIfV/o6D+myj5XVSbRrV9t+3DFm0DGKnc3PmW4avrP
# pvUtJZOMkeKdEbZRQ/mgQ0iesdQU86oQhcLksow0E/bs3H+KEY6GZ+CgXSr2PvH0
# VBI7GTotS2/Eggjqggimya0o+zlJ3Viagm7h6r7ZNwfiWFnNk7U=
# SIG # End signature block

View File

@@ -50,25 +50,77 @@ redirect you __away__ from the pages that allow you to download retail ISOs):
* https://www.microsoft.com/software-download/Windows8ISO
* https://www.microsoft.com/software-download/Windows10ISO
After visiting those with a full browser (Internet Explorer, running through the `Invoke-WebRequest` PowerShell Cmdlet),
to confirm that they are accessible, the script then queries the web API from the Microsoft servers to first request the
language selection available for the version of Windows selected by the user, and then request the actual download links
for all the architectures available for that specific combination of version + language.
After checking access to these URLs, to confirm that they are accessible, the script first queries the web API from the
Microsoft servers, to request the language selection available for the version of Windows selected, and then requests
the actual download links for all the architectures available for that language + version.
Requirements
------------
PowerShell 3.0 or later is required. However the script will detect if you are using an older version and point you to
PowerShell 3.0 or later is required. However the script should detect if you are using an older version and point you to
the relevant PowerShell 3.0 download page if needed (which should only ever occur if you are running a vanilla version
of Windows 7).
Also, because Internet Explorer is being invoked behind the scenes, if you haven't gone through the first time setup for
Internet Explorer, you may receive an error about this when running the script. If that is the case, then you should
make sure that you manually launch IE at least once and complete the setup.
Note that the current version of the script does not need Internet Explorer to be installed and should also work with
PowerShell 7.
Note however that, if you are running the script elevated, you can work around the above annoyance by using the
`-DisableFirstRunCustomize` option which basically __temporarily__ creates a key of the same name in the registry __if__
it doesn't already exist, to bypass the first time setup error.
Commandline mode
----------------
Fido supports commandline mode whereas, whenever one of the following options is provided, a GUI is not instantiated
and you can instead generate the ISO download from within a PowerShell console or script.
The options are:
- `Win`: Specify Windows version (e.g. _"Windows 10"_). Abbreviated version should work as well (e.g `-Win 10`) as long
as it is unique enough. If this option isn't specified, the most recent version of Windows is automatically selected.
You can obtain a list of supported versions by specifying `-Win List`.
- `Rel`: Specify Windows release (e.g. _"21H1"_). If this option isn't specified, the most recent release for the chosen
version of Windows is automatically selected. You can also use `-Rel Latest` to force the most recent to be used.
You can obtain a list of supported versions by specifying `-Rel List`.
- `Ed`: Specify Windows edition (e.g. _"Pro/Home"_). Abbreviated editions should work as well (e.g `-Ed Pro`) as long
as it is unique enough. If this option isn't specified, the most recent version of Windows is automatically selected.
You can obtain a list of supported versions by specifying `-Ed List`.
- `Lang`: Specify Windows language (e.g. _"Arabic"_). Abbreviated or part of a language (e.g. `-Lang Int` for
`English International`) should work as long as it's unique enough. If this option isn't specified, the script attempts
to select the same language as the system locale.
You can obtain a list of supported languages by specifying `-Lang List`.
- `Arch`: Specify Windows architecture (e.g. _"x64"_). If this option isn't specified, the script attempts to use the same
architecture as the one from the current system.
- `GetUrl`: By default, the script attempts to automatically launch the download. But when using the `-GetUrl` switch,
the script only displays the download URL, which can then be piped into another command or into a file.
Examples of a commandline download:
```
PS C:\Projects\Fido> .\Fido.ps1 -Win 10
No release specified (-Rel). Defaulting to '21H1 (Build 19043.985 - 2021.05)'.
No edition specified (-Ed). Defaulting to 'Windows 10 Home/Pro'.
No language specified (-Lang). Defaulting to 'English International'.
No architecture specified (-Arch). Defaulting to 'x64'.
Selected: Windows 10 21H1 (Build 19043.985 - 2021.05), Home/Pro, English International, x64
Downloading 'Win10_21H1_EnglishInternational_x64.iso' (5.0 GB)...
PS C:\Projects\Fido> .\Fido.ps1 -Win 10 -Rel List
Please select a Windows Release (-Rel) for Windows 10 (or use 'Latest' for most recent):
- 21H1 (Build 19043.985 - 2021.05)
- 20H2 (Build 19042.631 - 2020.12)
- 20H2 (Build 19042.508 - 2020.10)
- 20H1 (Build 19041.264 - 2020.05)
- 19H2 (Build 18363.418 - 2019.11)
- 19H1 (Build 18362.356 - 2019.09)
- 19H1 (Build 18362.30 - 2019.05)
- 1809 R2 (Build 17763.107 - 2018.10)
- 1809 R1 (Build 17763.1 - 2018.09)
- 1803 (Build 17134.1 - 2018.04)
- 1709 (Build 16299.15 - 2017.09)
- 1703 [Redstone 2] (Build 15063.0 - 2017.03)
- 1607 [Redstone 1] (Build 14393.0 - 2016.07)
- 1511 R3 [Threshold 2] (Build 10586.164 - 2016.04)
- 1511 R2 [Threshold 2] (Build 10586.104 - 2016.02)
- 1511 R1 [Threshold 2] (Build 10586.0 - 2015.11)
- 1507 [Threshold 1] (Build 10240.16384 - 2015.07)
PS C:\Projects\Fido> .\Fido.ps1 -Win 10 -Rel 20H2 -Ed Edu -Lang Fre -Arch x86 -GetUrl
https://software-download.microsoft.com/db/Win10_Edu_20H2_v2_French_x32.iso?t=c48b32d3-4cf3-46f3-a8ad-6dd9568ff4eb&e=1629113408&h=659cdd60399584c5dc1d267957924fbd
```
Additional Notes
----------------

View File

@@ -20,6 +20,8 @@ sign_file() {
fi
}
# Update the Authenticode signature
cmd.exe /c '"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool" sign /v /sha1 9ce9a71ccab3b38a74781b975f1c228222cf7d3b /fd SHA256 /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp Fido.ps1'
read -s -p "Enter pass phrase for `realpath $PRIVATE_KEY`: " PASSWORD
echo
# Confirm that the pass phrase is valid by trying to sign a dummy file