# # Fido v1.17 - Retail Windows ISO Downloader # Copyright © 2019-2020 Pete Batard # 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 . # # 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.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 = @"