Files
Fido/Fido.ps1
2021-01-30 02:55:42 +00:00

759 lines
26 KiB
PowerShell
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#
# Fido v1.18 - Retail Windows ISO Downloader
# Copyright © 2019-2021 Pete Batard <pete@akeo.ie>
# ConvertTo-ImageSource: Copyright © 2016 Chris Carter
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# NB: You must have a BOM on your .ps1 if you want Powershell to actually
# realise it should use Unicode for the UI rather than ISO-8859-1.
#region Parameters
param(
# (Optional) The title to display on the application window.
[string]$AppTitle = "Fido - Retail Windows ISO Downloader",
# (Optional) '|' separated UI localization strings.
[string]$LocData,
# (Optional) Path to a file that should be used for the UI icon.
[string]$Icon,
# (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
)
#endregion
try {
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
} catch {}
Write-Host Please Wait...
#region Assembly Types
$code = @"
[DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
internal static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr handle, int state);
// Extract an icon from a DLL
public static Icon ExtractIcon(string file, int number, bool largeIcon)
{
IntPtr large, small;
ExtractIconEx(file, number, out large, out small, 1);
try {
return Icon.FromHandle(largeIcon ? large : small);
} catch {
return null;
}
}
"@
if ($host.version -ge "7.0") {
Add-Type -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
$zh = 0x10000
$ko = 0x20000
$WindowsVersions = @(
@(
@("Windows 10", "Windows10ISO"),
@(
"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),
@("Windows 10 Education", 1805),
@("Windows 10 Home China ", ($zh + 1806))
),
@(
"20H1 (Build 19041.264 - 2020.05)",
@("Windows 10 Home/Pro", 1626),
@("Windows 10 Education", 1625),
@("Windows 10 Home China ", ($zh + 1627))
),
@(
"19H2 (Build 18363.418 - 2019.11)",
@("Windows 10 Home/Pro", 1429),
@("Windows 10 Education", 1431),
@("Windows 10 Home China ", ($zh + 1430))
),
@(
"19H1 (Build 18362.356 - 2019.09)",
@("Windows 10 Home/Pro", 1384),
@("Windows 10 Education", 1386),
@("Windows 10 Home China ", ($zh + 1385))
),
@(
"19H1 (Build 18362.30 - 2019.05)",
@("Windows 10 Home/Pro", 1214),
@("Windows 10 Education", 1216),
@("Windows 10 Home China ", ($zh + 1215))
),
@(
"1809 R2 (Build 17763.107 - 2018.10)",
@("Windows 10 Home/Pro", 1060),
@("Windows 10 Education", 1056),
@("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 ", ($zh + 1020))
),
@(
"1803 (Build 17134.1 - 2018.04)",
@("Windows 10 Home/Pro", 651),
@("Windows 10 Education", 655),
@("Windows 10 1803", 637),
@("Windows 10 Home China", ($zh + 652))
),
@(
"1709 (Build 16299.15 - 2017.09)",
@("Windows 10 Home/Pro", 484),
@("Windows 10 Education", 488),
@("Windows 10 Home China", ($zh + 485))
),
@(
"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 [Redstone 1] (Build 14393.0 - 2016.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 [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 [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 [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 [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))
)
),
@(
@("Windows 8.1", "windows8ISO"),
@(
"Update 3 (build 9600)",
@("Windows 8.1", 52),
@("Windows 8.1 N", 55)
@("Windows 8.1 Single Language", 48),
@("Windows 8.1 K", ($ko + 61)),
@("Windows 8.1 KN", ($ko + 62))
)
)
)
#endregion
#region Functions
function Select-Language([string]$LangName)
{
# Use the system locale to try select the most appropriate language
[string]$SysLocale = [System.Globalization.CultureInfo]::CurrentUICulture.Name
if (($SysLocale.StartsWith("ar") -and $LangName -like "*Arabic*") -or `
($SysLocale -eq "pt-BR" -and $LangName -like "*Brazil*") -or `
($SysLocale.StartsWith("ar") -and $LangName -like "*Bulgar*") -or `
($SysLocale -eq "zh-CN" -and $LangName -like "*Chinese*" -and $LangName -like "*simp*") -or `
($SysLocale -eq "zh-TW" -and $LangName -like "*Chinese*" -and $LangName -like "*trad*") -or `
($SysLocale.StartsWith("hr") -and $LangName -like "*Croat*") -or `
($SysLocale.StartsWith("cz") -and $LangName -like "*Czech*") -or `
($SysLocale.StartsWith("da") -and $LangName -like "*Danish*") -or `
($SysLocale.StartsWith("nl") -and $LangName -like "*Dutch*") -or `
($SysLocale -eq "en-US" -and $LangName -eq "English") -or `
($SysLocale.StartsWith("en") -and $LangName -like "*English*" -and ($LangName -like "*inter*" -or $LangName -like "*ingdom*")) -or `
($SysLocale.StartsWith("et") -and $LangName -like "*Eston*") -or `
($SysLocale.StartsWith("fi") -and $LangName -like "*Finn*") -or `
($SysLocale -eq "fr-CA" -and $LangName -like "*French*" -and $LangName -like "*Canad*") -or `
($SysLocale.StartsWith("fr") -and $LangName -eq "French") -or `
($SysLocale.StartsWith("de") -and $LangName -like "*German*") -or `
($SysLocale.StartsWith("el") -and $LangName -like "*Greek*") -or `
($SysLocale.StartsWith("he") -and $LangName -like "*Hebrew*") -or `
($SysLocale.StartsWith("hu") -and $LangName -like "*Hungar*") -or `
($SysLocale.StartsWith("id") -and $LangName -like "*Indones*") -or `
($SysLocale.StartsWith("it") -and $LangName -like "*Italia*") -or `
($SysLocale.StartsWith("ja") -and $LangName -like "*Japan*") -or `
($SysLocale.StartsWith("ko") -and $LangName -like "*Korea*") -or `
($SysLocale.StartsWith("lv") -and $LangName -like "*Latvia*") -or `
($SysLocale.StartsWith("lt") -and $LangName -like "*Lithuania*") -or `
($SysLocale.StartsWith("ms") -and $LangName -like "*Malay*") -or `
($SysLocale.StartsWith("nb") -and $LangName -like "*Norw*") -or `
($SysLocale.StartsWith("fa") -and $LangName -like "*Persia*") -or `
($SysLocale.StartsWith("pl") -and $LangName -like "*Polish*") -or `
($SysLocale -eq "pt-PT" -and $LangName -eq "Portuguese") -or `
($SysLocale.StartsWith("ro") -and $LangName -like "*Romania*") -or `
($SysLocale.StartsWith("ru") -and $LangName -like "*Russia*") -or `
($SysLocale.StartsWith("sr") -and $LangName -like "*Serbia*") -or `
($SysLocale.StartsWith("sk") -and $LangName -like "*Slovak*") -or `
($SysLocale.StartsWith("sl") -and $LangName -like "*Slovenia*") -or `
($SysLocale -eq "es-ES" -and $LangName -eq "Spanish") -or `
($SysLocale.StartsWith("es") -and $Locale -ne "es-ES" -and $LangName -like "*Spanish*") -or `
($SysLocale.StartsWith("sv") -and $LangName -like "*Swed*") -or `
($SysLocale.StartsWith("th") -and $LangName -like "*Thai*") -or `
($SysLocale.StartsWith("tr") -and $LangName -like "*Turk*") -or `
($SysLocale.StartsWith("uk") -and $LangName -like "*Ukrain*") -or `
($SysLocale.StartsWith("vi") -and $LangName -like "*Vietnam*")) {
return $True
}
return $False
}
function Add-Entry([int]$pos, [string]$Name, [array]$Items, [string]$DisplayName)
{
$Title = New-Object System.Windows.Controls.TextBlock
$Title.FontSize = $WindowsVersionTitle.FontSize
$Title.Height = $WindowsVersionTitle.Height;
$Title.Width = $WindowsVersionTitle.Width;
$Title.HorizontalAlignment = "Left"
$Title.VerticalAlignment = "Top"
$Margin = $WindowsVersionTitle.Margin
$Margin.Top += $pos * $dh
$Title.Margin = $Margin
$Title.Text = Get-Translation($Name)
$XMLGrid.Children.Insert(2 * $Stage + 2, $Title)
$Combo = New-Object System.Windows.Controls.ComboBox
$Combo.FontSize = $WindowsVersion.FontSize
$Combo.Height = $WindowsVersion.Height;
$Combo.Width = $WindowsVersion.Width;
$Combo.HorizontalAlignment = "Left"
$Combo.VerticalAlignment = "Top"
$Margin = $WindowsVersion.Margin
$Margin.Top += $pos * $script:dh
$Combo.Margin = $Margin
$Combo.SelectedIndex = 0
if ($Items) {
$Combo.ItemsSource = $Items
if ($DisplayName) {
$Combo.DisplayMemberPath = $DisplayName
} else {
$Combo.DisplayMemberPath = $Name
}
}
$XMLGrid.Children.Insert(2 * $Stage + 3, $Combo)
$XMLForm.Height += $dh;
$Margin = $Continue.Margin
$Margin.Top += $dh
$Continue.Margin = $Margin
$Margin = $Back.Margin
$Margin.Top += $dh
$Back.Margin = $Margin
return $Combo
}
function Refresh-Control([object]$Control)
{
$Control.Dispatcher.Invoke("Render", [Windows.Input.InputEventHandler] { $Continue.UpdateLayout() }, $null, $null)
}
function Send-Message([string]$PipeName, [string]$Message)
{
[System.Text.Encoding]$Encoding = [System.Text.Encoding]::UTF8
$Pipe = New-Object -TypeName System.IO.Pipes.NamedPipeClientStream -ArgumentList ".", $PipeName, ([System.IO.Pipes.PipeDirection]::Out), ([System.IO.Pipes.PipeOptions]::None), ([System.Security.Principal.TokenImpersonationLevel]::Impersonation)
try {
$Pipe.Connect(1000)
} catch {
Write-Host $_.Exception.Message
}
$bRequest = $Encoding.GetBytes($Message)
$cbRequest = $bRequest.Length;
$Pipe.Write($bRequest, 0, $cbRequest);
$Pipe.Dispose()
}
# From https://www.powershellgallery.com/packages/IconForGUI/1.5.2
# Copyright © 2016 Chris Carter. All rights reserved.
# License: https://creativecommons.org/licenses/by-sa/4.0/
function ConvertTo-ImageSource
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[System.Drawing.Icon]$Icon
)
Process {
foreach ($i in $Icon) {
[System.Windows.Interop.Imaging]::CreateBitmapSourceFromHIcon(
$i.Handle,
(New-Object System.Windows.Int32Rect -Args 0,0,$i.Width, $i.Height),
[System.Windows.Media.Imaging.BitmapSizeOptions]::FromEmptyOptions()
)
}
}
}
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)
{
if (-not $English -contains $Text) {
Write-Host "Error: '$Text' is not a translatable string"
return "(Untranslated)"
}
if ($Localized) {
if ($Localized.Length -ne $English.Length) {
Write-Host "Error: '$Text' is not a translatable string"
}
for ($i = 0; $i -lt $English.Length; $i++) {
if ($English[$i] -eq $Text) {
if ($Localized[$i]) {
return $Localized[$i]
} else {
return $Text
}
}
}
}
return $Text
}
# Some PowerShells don't have Microsoft.mshtml assembly (comes with MS Office?)
# so we can't use ParsedHtml or IHTMLDocument[2|3] features there...
function GetElementById([object]$Request, [string]$Id)
{
try {
return $Request.ParsedHtml.IHTMLDocument3_GetElementByID($Id)
} catch {
return $Request.AllElements | ? {$_.id -eq $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--
}
function Get-RandomDate()
{
[DateTime]$Min = "1/1/2008"
[DateTime]$Max = [DateTime]::Now
$RandomGen = new-object random
$RandomTicks = [Convert]::ToInt64( ($Max.ticks * 1.0 - $Min.Ticks * 1.0 ) * $RandomGen.NextDouble() + $Min.Ticks * 1.0 )
$Date = new-object DateTime($RandomTicks)
return $Date.ToString("yyyyMMdd")
}
#endregion
#region Form
[xml]$XAML = @"
<Window xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" Height = "162" Width = "384" ResizeMode = "NoResize">
<Grid Name = "XMLGrid">
<Button Name = "Continue" FontSize = "16" Height = "26" Width = "160" HorizontalAlignment = "Left" VerticalAlignment = "Top" Margin = "14,78,0,0"/>
<Button Name = "Back" FontSize = "16" Height = "26" Width = "160" HorizontalAlignment = "Left" VerticalAlignment = "Top" Margin = "194,78,0,0"/>
<TextBlock Name = "WindowsVersionTitle" FontSize = "16" Width="340" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="16,8,0,0"/>
<ComboBox Name = "WindowsVersion" FontSize = "14" Height = "24" Width = "340" HorizontalAlignment = "Left" VerticalAlignment="Top" Margin = "14,34,0,0" SelectedIndex = "0"/>
<CheckBox Name = "Check" FontSize = "14" Width = "340" HorizontalAlignment = "Left" VerticalAlignment="Top" Margin = "14,0,0,0" Visibility="Collapsed" />
</Grid>
</Window>
"@
#endregion
#region Globals
$ErrorActionPreference = "Stop"
$dh = 58;
$Stage = 0
$ltrm = ""
$MaxStage = 4
$SessionId = [guid]::NewGuid()
$ExitCode = 100
$Locale = "en-US"
$DFRCKey = "HKLM:\Software\Policies\Microsoft\Internet Explorer\Main\"
$DFRCName = "DisableFirstRunCustomize"
$DFRCAdded = $False
$RequestData = @{}
$RequestData["GetLangs"] = @("a8f8f489-4c7f-463a-9ca6-5cff94d8d041", "getskuinformationbyproductedition" )
$RequestData["GetLinks"] = @("cfa9e580-a81e-4a4b-a846-7b21bf4e2e5b", "GetProductDownloadLinksBySku" )
# Create a semi-random Linux User-Agent string
$FirefoxVersion = Get-Random -Minimum 30 -Maximum 60
$FirefoxDate = Get-RandomDate
$UserAgent = "Mozilla/5.0 (X11; Linux i586; rv:$FirefoxVersion.0) Gecko/$FirefoxDate Firefox/$FirefoxVersion.0"
#endregion
# Localization
$EnglishMessages = "en-US|Version|Release|Edition|Language|Architecture|Download|Continue|Back|Close|Cancel|Error|Please wait...|" +
"Download using a browser|Temporarily banned by Microsoft for requesting too many downloads - Please try again later...|" +
"PowerShell 3.0 or later is required to run this script.|Do you want to go online and download it?"
[string[]]$English = $EnglishMessages.Split('|')
[string[]]$Localized = $null
if ($LocData -and (-not $LocData.StartsWith("en-US"))) {
$Localized = $LocData.Split('|')
if ($Localized.Length -ne $English.Length) {
Write-Host "Error: Missing or extra translated messages provided ($($Localized.Length)/$($English.Length))"
exit 101
}
$Locale = $Localized[0]
}
$QueryLocale = $Locale
# Make sure PowerShell 3.0 or later is used (for Invoke-WebRequest)
if ($PSVersionTable.PSVersion.Major -lt 3) {
Write-Host Error: PowerShell 3.0 or later is required to run this script.
$Msg = "$(Get-Translation($English[15]))`n$(Get-Translation($English[16]))"
if ([System.Windows.MessageBox]::Show($Msg, $(Get-Translation("Error")), "YesNo", "Error") -eq "Yes") {
Start-Process -FilePath https://www.microsoft.com/download/details.aspx?id=34595
}
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
}
}
# Form creation
$XMLForm = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $XAML))
$XAML.SelectNodes("//*[@Name]") | ForEach-Object { Set-Variable -Name ($_.Name) -Value $XMLForm.FindName($_.Name) -Scope Script }
$XMLForm.Title = $AppTitle
if ($Icon) {
$XMLForm.Icon = $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")) {
$XMLForm.FlowDirection = "RightToLeft"
}
$WindowsVersionTitle.Text = Get-Translation("Version")
$Continue.Content = Get-Translation("Continue")
$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 })
$i++
}
$WindowsVersion.ItemsSource = $array
$WindowsVersion.DisplayMemberPath = "Version"
# Button Action
$Continue.add_click({
$script:Stage++
$XMLGrid.Children[2 * $Stage + 1].IsEnabled = $False
$Continue.IsEnabled = $False
$Back.IsEnabled = $False
Refresh-Control($Continue)
Refresh-Control($Back)
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]) {
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
$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
}
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 -SessionVariable "Session" $url
# Go through an XML conversion to keep all PowerShells happy...
if (-not $($r.AllElements | ? {$_.id -eq "product-languages"})) {
if ($host.version -ge "7.0") {
throw "This PowerShell version can not parse HTML"
} else {
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)
break
}
$script:Language = Add-Entry $Stage "Language" $array "DisplayLanguage"
$Language.SelectedIndex = $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)
break
}
$script:Arch = Add-Entry $Stage "Architecture" $array "Type"
if ($PipeName) {
$XMLForm.Height += $dh / 2;
$Margin = $Continue.Margin
$top = $Margin.Top
$Margin.Top += $dh /2
$Continue.Margin = $Margin
$Margin = $Back.Margin
$Margin.Top += $dh / 2
$Back.Margin = $Margin
$Margin = $Check.Margin
$Margin.Top = $top - 2
$Check.Margin = $Margin
$Check.Content = Get-Translation($English[13])
$Check.Visibility = "Visible"
}
$Arch.SelectedIndex = $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
$XMLForm.Close()
}
}
$Continue.IsEnabled = $True
if ($Stage -ge 0) {
$Back.IsEnabled = $True
}
})
$Back.add_click({
if ($Stage -eq 0) {
$XMLForm.Close()
} else {
$XMLGrid.Children.RemoveAt(2 * $Stage + 3)
$XMLGrid.Children.RemoveAt(2 * $Stage + 2)
$XMLGrid.Children[2 * $Stage + 1].IsEnabled = $True
$dh2 = $dh
if ($Stage -eq 4 -and $PipeName) {
$Check.Visibility = "Collapsed"
$dh2 += $dh / 2
}
$XMLForm.Height -= $dh2;
$Margin = $Continue.Margin
$Margin.Top -= $dh2
$Continue.Margin = $Margin
$Margin = $Back.Margin
$Margin.Top -= $dh2
$Back.Margin = $Margin
$script:Stage = $Stage - 1
$XMLForm.Title = $AppTitle
if ($Stage -eq 0) {
$Back.Content = Get-Translation("Close")
} else {
$Continue.Content = Get-Translation("Continue")
Refresh-Control($Continue)
}
}
})
# Display the dialog
$XMLForm.Add_Loaded( { $XMLForm.Activate() } )
$XMLForm.ShowDialog() | Out-Null
# Clean up & exit
if ($DFRCAdded) {
Remove-ItemProperty -Path $DFRCKey -Name $DFRCName
}
exit $ExitCode