@@ -1,5 +1,5 @@
#
# Fido v1.39 - Feature ISO Downloader, for retail Windows images and UEFI Shell
# Fido v1.44 - Feature ISO Downloader, for retail Windows images and UEFI Shell
# Copyright © 2019-2023 Pete Batard <pete@akeo.ie>
# Command line support: Copyright © 2021 flx5
# ConvertTo-ImageSource: Copyright © 2016 Chris Carter
@@ -24,7 +24,7 @@
#region Parameters
param (
# (Optional) The title to display on the application window.
[ string ] $AppTitle = " Fido - Retail Windows ISO Downloader " ,
[ string ] $AppTitle = " Fido - Feature ISO Downloader " ,
# (Optional) '|' separated UI localization strings.
[ string ] $LocData ,
# (Optional) Path to a file that should be used for the UI icon.
@@ -45,9 +45,7 @@ param(
# (Optional) Only display the download URL [Toggles commandline mode]
[ switch ] $GetUrl = $False ,
# (Optional) Increase verbosity
[ switch ] $Verbose = $False ,
# (Optional) Disable the progress bar
[ switch ] $DisableProgress = $False
[ switch ] $Verbose = $False
)
#endregion
@@ -60,6 +58,28 @@ if ($Win -or $Rel -or $Ed -or $Lang -or $Arch -or $GetUrl) {
$Cmd = $True
}
# Return a decimal Windows version that we can then check for platform support.
# Note that because we don't want to have to support this script on anything
# other than Windows, this call returns 0.0 for PowerShell running on Linux/Mac.
function Get-Platform-Version ( )
{
$version = 0.0
$platform = [ string][System.Environment ] :: OSVersion . Platform
# This will filter out non Windows platforms
if ( $platform . StartsWith ( " Win " ) ) {
# Craft a decimal numeric version of Windows
$version = [ System.Environment ] :: OSVersion . Version . Major * 1.0 + [ System.Environment ] :: OSVersion . Version . Minor * 0.1
}
return $version
}
$winver = Get-Platform -Version
# The default TLS for Windows 8.x doesn't work with Microsoft's servers so we must force it
if ( $winver -lt 10.0 ) {
[ Net.ServicePointManager ] :: SecurityProtocol = [ Net.SecurityProtocolType ] :: Tls -bor [ Net.SecurityProtocolType ] :: Tls11 -bor [ Net.SecurityProtocolType ] :: Tls12
}
#region Assembly Types
$code = @"
[ D l l I m p o r t ( " s h e l l 3 2 . d l l " , C h a r S e t = C h a r S e t . A u t o , S e t L a s t E r r o r = t r u e , B e s t F i t M a p p i n g = f a l s e , T h r o w O n U n m a p p a b l e C h a r = t r u e ) ]
@@ -313,7 +333,7 @@ $WindowsVersions = @(
)
) ,
@ (
@ ( " UEFI Shell 2.0 " , " UEFI_SHELL 2.0 " ) ,
@ ( " UEFI Shell 2.0 " , " UEFI_SHELL 2.0 " ) ,
@ (
" 4.632 [20100426] " ,
@ ( " Release " , 0 )
@@ -617,30 +637,25 @@ if ($Cmd) {
# 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? "
" Download using a browser|Download of Windows ISOs is unavailable due to Microsoft having altered their website to prevent it .| " +
" PowerShell 3.0 or later is required to run this script.|Do you want to go online and download it?| " +
" This feature is not available on this platform. "
[ 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
# Adjust the $Localized array if we have more or fewer strings than in $EnglishMessages
if ($Localized . Length -lt $English . Length ) {
while ( $Localized . Length -ne $English . Length ) {
$Localized + = $English [ $Localized . Length ]
}
} elseif ( $Localized . Length -gt $English . Length ) {
$Localized = $LocData . Split ( '|' ) [ 0 . . ( $English . Length - 1 ) ]
}
$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
}
# Convert a size in bytes to a human readable string
function Size-To-Human-Readable([uint64]$size )
{
@@ -654,7 +669,8 @@ function Size-To-Human-Readable([uint64]$size)
}
# Check if the locale we want is available - Fall back to en-US otherwise
function Check-Locale {
function Check-Locale
{
try {
$url = " https://www.microsoft.com/ " + $QueryLocale + " /software-download/ "
if ( $Verbosity -ge 2 ) {
@@ -712,7 +728,15 @@ function Get-Windows-Languages([int]$SelectedVersion, [int]$SelectedEdition)
} else {
# Microsoft download protection now requires the sessionId to be whitelisted through vlscppe.microsoft.com/tags
$url = " https://vlscppe.microsoft.com/tags?org_id=y6jn8c31&session_id= " + $SessionId
Invoke-WebRequest -UseBasicParsing -MaximumRedirection 0 -UserAgent $UserAgent $url | Out-Null
if ( $Verbosity -ge 2 ) {
Write-Host Querying $url
}
try {
Invoke-WebRequest -UseBasicParsing -MaximumRedirection 0 -UserAgent $UserAgent $url | Out-Null
} catch {
Error ( $_ . Exception . Message )
return @ ( )
}
$url = " https://www.microsoft.com/ " + $QueryLocale + " /api/controls/contentinclude/html "
$url + = " ?pageId= " + $RequestData [ " GetLangs " ] [ 0 ]
$url + = " &host=www.microsoft.com "
@@ -731,7 +755,8 @@ function Get-Windows-Languages([int]$SelectedVersion, [int]$SelectedEdition)
if ( $r -match " errorModalMessage " ) {
Throw-Error -Req $r -Alt " Could not retrieve languages from server "
}
$pattern = '(?s)<select id="product-languages">(.*)?</select>'
$r = $r -replace " `n " -replace " `r "
$pattern = '.*<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 " )
@@ -782,7 +807,7 @@ function Get-Windows-Download-Links([int]$SelectedVersion, [int]$SelectedRelease
$xml = New-Object System . Xml . XmlDocument
if ( $Verbosity -ge 2 ) {
Write-Host Querying $url
}
}
$xml . Load ( $url )
$sep = " "
$archs = " "
@@ -814,26 +839,15 @@ function Get-Windows-Download-Links([int]$SelectedVersion, [int]$SelectedRelease
try {
$Is64 = [ Environment ] :: Is64BitOperatingSystem
# Must add a referer for POST requests , else Microsoft's servers will deny them
# Must add a referer for this request, else Microsoft's servers will deny i t
$ref = " https://www.microsoft.com/software-download/windows11 "
$w r = [ System.Net.WebRequest ] :: Create ( $url )
# Windows 7 PowerShell doesn't support 'Invoke-WebRequest -Headers @{"Referer" = $ref}'
# (produces "The 'Referer' header must be modified using the appropriate property or method")
# so we use StreamReader() with GetResponseStream() and do this whole gymkhana instead...
$wr . Method = " POST "
$wr . Referer = $ref
$wr . UserAgent = $UserAgent
$wr . ContentLength = 0
$sr = New-Object System . IO . StreamReader ( $wr . GetResponse ( ) . GetResponseStream ( ) )
$r = $sr . ReadToEnd ( )
$r = Invoke-WebRequest -Method Post -Headers @ { " Referer " = $ref } -UseBasicParsing -UserAgent $UserAgent -WebSession $Session $url
if ( $r -match " errorModalMessage " ) {
$regex = New-Object Text . RegularExpressions . Regex '<p id="errorModalMessage">(.+?)<\/p>'
$m = $regex . Match ( $r )
# Make the typical error message returned by Microsoft's servers more presentable
$Alt = $m . Groups [ 1 ] -replace " <[^>]+> " -replace " \s+ " , " "
$Alt + = " " + $SessionId
$Alt = [ regex ] :: Match ( $r , '<p id="errorModalMessage">(.+?)<\/p>' ) . Groups [ 1 ] . Value -replace " <[^>]+> " -replace " \s+ " , " " -replace " \?\?\? " , " - "
if ( -not $Alt ) {
$Alt = " Could not retrieve architectures from server "
} else {
$Alt + = " " + $SessionId + " . "
}
Throw-Error -Req $r -Alt $Alt
}
@@ -883,10 +897,7 @@ function Process-Download-Link([string]$Url)
$tmp_size = [ uint64 ] :: Parse ( $str_size )
$Size = Size-To -Human -Readable $tmp_size
Write-Host " Downloading ' $File ' ( $Size )... "
if ( $DisableProgress ) {
$ProgressPreference = 'SilentlyContinue'
}
Invoke-WebRequest -UseBasicParsing -Uri $Url -OutFile $File
Start-BitsTransfer -Source $Url -Destination $File
} else {
Write-Host Download Link : $Url
Start-Process -FilePath $Url
@@ -907,6 +918,12 @@ if ($Cmd) {
$winLanguageName = $null
$winLink = $null
# Windows 7 and non Windows platforms are too much of a liability
if ( $winver -le 6.1 ) {
Error ( Get-Translation ( " This feature is not available on this platform. " ) )
exit 403
}
$i = 0
$Selected = " "
if ( $Win -eq " List " ) {
@@ -1065,7 +1082,7 @@ $XMLForm.Title = $AppTitle
if ( $Icon ) {
$XMLForm . Icon = $Icon
} else {
$XMLForm . Icon = [ Gui.Utils ] :: ExtractIcon ( " shell32 .dll" , -41 , $true ) | ConvertTo-ImageSource
$XMLForm . Icon = [ Gui.Utils ] :: ExtractIcon ( " imageres .dll" , -5205 , $true ) | ConvertTo-ImageSource
}
if ( $Locale . StartsWith ( " ar " ) -or $Locale . StartsWith ( " fa " ) -or $Locale . StartsWith ( " he " ) ) {
$XMLForm . FlowDirection = " RightToLeft "
@@ -1074,6 +1091,12 @@ $WindowsVersionTitle.Text = Get-Translation("Version")
$Continue . Content = Get-Translation ( " Continue " )
$Back . Content = Get-Translation ( " Close " )
# Windows 7 and non Windows platforms are too much of a liability
if ( $winver -le 6.1 ) {
Error ( Get-Translation ( " This feature is not available on this platform. " ) )
exit 403
}
# Populate the Windows versions
$i = 0
$versions = @ ( )
@@ -1203,8 +1226,8 @@ exit $ExitCode
# SIG # Begin signature block
# MIIkWQYJKoZIhvcNAQcCoIIkSjCCJEYCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB4DCsid0Hcotrs
# wgTJd2lY28Qu5omAVl5T1mk2BP1C1q CCElkwggVvMIIEV6ADAgECAhBI/JO0YFWU
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDCpZpntjuU2uHY
# z3/0OsY2UtUKjz1UjCN6T8dRzpny96 CCElkwggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
@@ -1307,23 +1330,23 @@ exit $ExitCode
# aWMgQ29kZSBTaWduaW5nIENBIEVWIFIzNgIRAL+xUAG79ZLUlip3l+pzb6MwDQYJ
# YIZIAWUDBAIBBQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYK
# KwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG
# 9w0BCQQxIgQgZJjDDP2YWPPmGrEuHBNI0duArydubM/gmnG4BcpOG8c wDQYJKoZI
# hvcNAQEBBQAEggIAeMyrcbmpsFeC8p7Hw21CgIxWszJ1tkiFmVcEuf5TU5NSUwYA
# NsT/TaKGDc0mn313EiA3OM2yBwWdJFQsF0O87carfF3FXoKNU90f/IbyzhiOuGXo
# sT2LeKGy57hdmi+j0pcf1DorfKKQ3XQ45RI1USCedKBxaC0ZVGl1PCHogtxxwvyG
# tV5J90NS0ztTtuL2M2JCBobE6v7p6AWxkffzb97JygXY8yKc5E7XWuUEtU7Lkv6t
# bARG9idcAi151yNkReF+iZh1ZrS7+awhnWqmzxJ1XTf2lvZObl7YfK7CekLtjxzO
# M1Q1iLRzbIeMX8B9Z0S6TUtKDPAzWiIKUUWBaad/ojG3uZl7fA6WEgB2mt0CQNOG
# UAre5uYpqTpvNXCksAYcjmYmQcd2NenXSq4gnIbiPQdFXl/AMpFE127Cd7R7H/vP
# 6a4mbsfuPuQD9sHK79hGVl86iiCq00Jur3asfbV1RGKCJZTiQXzmXRaHD8Ce8a0h
# 2PmukEnTDNJv1t3gKMojBmT7KDXS8v6idRXVnovGrf0+0WXOCau3nBWfBAZB8A8r
# GUS0k9JyqilE6aAE8no59wqvXIDMKLLP6Br8czBcTIAaAoMAjvfJeYCsNJZH5ICz
# wEPxpQyGLzL/Z2LzdNUFs+j9m1zQ7a4d2ln5G5vDa/Qbs5IwGm4PRix2tqy hgg49
# 9w0BCQQxIgQgH+Kly8R4u5iFMlpWglzfc5lMDQgs38C2FS0CujFgfdM wDQYJKoZI
# hvcNAQEBBQAEggIAqDdE38CiBnf6ksVoNbp+EAUi5M1rD/b885OIuaXqUUjCMOaR
# R34hPylb/Lc9CbCJ1aiqjhyap/hnNryeXBSkr+HIfP5UyDGXjCsfFFwyPVyRPd72
# BKM8tYfuUvZbIvWmsFUJfe24VTEGTbh5XTM5s6RgQCQZ4V/M6ePCH6LxiHuIufWL
# DCaKS6/AO0icPkF0CtQQiGk/z0nlrp6T6IppDkGS7yAYip5/flBxmQsRCkNlL9mw
# XTL63kd1ar9cZTR1knAXwM2qXfkkOxGX8OGQ04P01/wWjEBMoYBUmUbHIWKgcg1T
# QmXZEObFJHRkNMfPU+F+oc/kDwd4SXCv6x7E6XOgxB4C9B9sE88ZEOOv26FTS4fa
# +VVFPffxfmdQT+pKch8j3h/OGgJM2OAqnEoK8KTZYlCoJO781YfAjertrewXKHv/
# HzlJ7gu5t3Ji7WrzoCusHEszv+LYl3TupZ2VZNmQDY57/br3LxNHOxRmjFAigI6z
# 3OyVwOx6L+onBr+jg5LGkA+XPhTjdAhBJ2bI9ayUYURKv5/jNUbyk6RZHUncTKUj
# Oze0eaX15F/UpGbJZaR9wCCj28jCk4zxbqSTqQcSjxM8zfp23fcxd2NICtd8UhFt
# pGfR1jleAJsKuDJts+k8WcfT2SaEGQmmklM/wIusRaIWn6KHr8wAFBgz8hu hgg49
# MIIOOQYKKwYBBAGCNwMDATGCDikwgg4lBgkqhkiG9w0BBwKggg4WMIIOEgIBAzEN
# MAsGCWCGSAFlAwQCATCCAQ8GCyqGSIb3DQEJEAEEoIH/BIH8MIH5AgEBBgtghkgB
# hvhFAQcXAzAxMA0GCWCGSAFlAwQCAQUABCDJlO4Qu/KVPQXhqzZUwkQuxnuXzr+y
# ALuw9uhTw5x50QIVAI5lXv0dlojOQ5uU1re1l1WZ0wZjGA8yMDIzMDEwODIyMDQ0
# N FowAwIBHqCBhqSBgzCBgDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVj
# hvhFAQcXAzAxMA0GCWCGSAFlAwQCAQUABCBIdB9A36e59U63AWbaDgc60655s3pE
# PaBLt9XKx9DWuQIVAKmmRn4m0Gad1QsRv95QHHuKDBOzGA8yMDIzMDMwNzEyMTEz
# M FowAwIBHqCBhqSBgzCBgDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVj
# IENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTEw
# LwYDVQQDEyhTeW1hbnRlYyBTSEEyNTYgVGltZVN0YW1waW5nIFNpZ25lciAtIEcz
# oIIKizCCBTgwggQgoAMCAQICEHsFsdRJaFFE98mJ0pwZnRIwDQYJKoZIhvcNAQEL
@@ -1386,13 +1409,13 @@ exit $ExitCode
# BgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBU
# cnVzdCBOZXR3b3JrMSgwJgYDVQQDEx9TeW1hbnRlYyBTSEEyNTYgVGltZVN0YW1w
# aW5nIENBAhB71OWvuswHP6EBIwQiQU0SMAsGCWCGSAFlAwQCAaCBpDAaBgkqhkiG
# 9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIzMDEwODIyMDQ0
# N FowLwYJKoZIhvcNAQkEMSIEIJCXdWNCvCOkl1MVXUM64ID5Hk3rlqG10XOEU4X6
# lgId MDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEIMR0znYAfQI5Tg2l5N58FMaA+eKC
# ATz+9lPvXbcf32H4MAsGCSqGSIb3DQEBAQSCAQCIgN/3Y1woMyQD3RfjYoePc1VS
# M3RbvhneaXXr6LSxRh/MJd04waviGo0j/8hdoMzmyDBTVJdGuY7K2jZGFg82y5H6
# qQAcgkTT0KyXTkT6MwjBor1nRG5IY/20NXtXIOfN3KmRQnZy+lLH3rXguxEEFObw
# DNHTB3sAAxaJdJQhKKqw1cuExubwLEzKbU+HFvNavyd3iTf3Free1eYQYmO5LliK
# SYWJ4CbawK2qu0U/e5xznALGZ5NdJ3tZAFK3w0ZF0W9m6CfNW0TmjG6ae8RF4J+4
# SWGCh2KrY4PVhyKxKiB3z5rCHYGkCrNJJdlOkoaUVBa/MQ+SildBrHvnhZZ1
# 9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIzMDMwNzEyMTEz
# M FowLwYJKoZIhvcNAQkEMSIEIBi+xZssYhAdmjF0gLXZv2WCNOM3iW02zqjWyiHi
# 3ZVh MDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEIMR0znYAfQI5Tg2l5N58FMaA+eKC
# ATz+9lPvXbcf32H4MAsGCSqGSIb3DQEBAQSCAQAQ/Kq0P6rLFJ66lXNqtLxRuZtB
# MUMdYUhBiKy3RCJwf1SMi4nhV/aHEw43hQz+GsxrxENwy24VFfxOg6kguqI1Qm0b
# w5+rCqFykHUntTAsIND27MthzzXn69wkoFv0n2IKjq05KuUEXgEy+eemStG1G0tU
# efXWl2eFR+8ItErCzAi7Dt7R76vhRG7Sj1Ik2PlltdnK0+SuSdLfeVbTrrYQ2Kub
# ueVJWMFFE4CX0LvFJ6fdytVVqTD8GXNj/bdt2La5zLEobYoQXHzXwJHXGY+Nj9d8
# 5fiYgMP7RA04944Xjkoc761EySwFWPHNJjg8DTSAz+NKrnFdvb9K3hoik1wT
# SIG # End signature block