Compare commits

..

4 Commits
v1.0 ... v1.04

Author SHA1 Message Date
Pete Batard
4cebdef31a Use translated messages for the PS 3.0 prompt
* Also use "Close" instead of "Cancel" for the initial 'Back' button
2019-03-12 13:58:06 +00:00
Pete Batard
bd9475773c Improve compatibility with vanilla Windows platforms
* Add a notice about PowerShell 3.0 being required.
* Enable script to run on platforms without Microsoft.mshtml assembly.
* Add a -DisableFirstRunCustomize option to prevent an exception when
  the script is run on a platform where IE has never been launched.
* Also display a notice about Microsoft anti bulk download
2019-03-11 17:24:22 +00:00
Pete Batard
c6ac4acc4a Fix dialog not appearing on top when launched
* For ye who might be looking for this important piece of information:
  In System.Windows.Windows, the equivalent of System.Windows.Forms.Add_Shown()
  is System.Windows.Windows.Add_Loaded(). You can thank me later...
2019-03-06 18:11:12 +00:00
Pete Batard
ef9e43d1eb Remove testing/debug options and simplify parameter handling
* Also let external app close cookie prompt when a pipe is provided
  and use a more explicit Continue/Back scheme for button labels.
* Also add signature script
2019-03-05 12:19:30 +00:00
4 changed files with 219 additions and 134 deletions

1
.gitattributes vendored
View File

@@ -1,2 +1,3 @@
* text=auto * text=auto
*.ps1 eol=crlf *.ps1 eol=crlf
*.sh eol=lf

5
.gitignore vendored
View File

@@ -258,4 +258,7 @@ paket-files/
# Python Tools for Visual Studio (PTVS) # Python Tools for Visual Studio (PTVS)
__pycache__/ __pycache__/
*.pyc *.pyc
# Signatures
*.sig

317
Fido.ps1
View File

@@ -1,5 +1,5 @@
# #
# Fido - Retail Windows ISO Downloader # Fido v1.04 - Retail Windows ISO Downloader
# Copyright © 2019 Pete Batard <pete@akeo.ie> # Copyright © 2019 Pete Batard <pete@akeo.ie>
# ConvertTo-ImageSource: Copyright © 2016 Chris Carter # ConvertTo-ImageSource: Copyright © 2016 Chris Carter
# #
@@ -22,21 +22,21 @@
#region Parameters #region Parameters
param( 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. # (Optional) Name of a pipe the download URL should be sent to.
# If not provided, a browser window is opened instead. # If not provided, a browser window is opened instead.
[string]$PipeName, [string]$PipeName,
# (Optional) '|' separated UI localization strings. # (Optional) Disable IE First Run Customize so that Invoke-WebRequest
[string]$LocData, # doesn't throw an exception if the user has never launched IE.
# (Optional) Path to the file that should be used for the UI icon. # Note that this requires the script to run elevated.
[string]$Icon, [switch]$DisableFirstRunCustomize,
# (Optional) The title to display on the application window # (Optional) Toggle expert mode (additional ISOs to choose).
[string]$AppTitle = "Fido - Retail Windows ISO Downloader", [switch]$Expert = $False
# (Optional) Whether to show the "Download in a browser" checkbox
[switch]$ShowBrowserOption = $True,
# (Optional) Test/Debug options
[switch]$Debug = $False,
[switch]$Expert = $False,
[switch]$Testing = $False
) )
#endregion #endregion
@@ -61,8 +61,6 @@ $code = @"
if (!File.Exists(muiPath)) if (!File.Exists(muiPath))
muiPath = Environment.SystemDirectory + @"\en-US\" + dll + ".mui"; muiPath = Environment.SystemDirectory + @"\en-US\" + dll + ".mui";
IntPtr hMui = LoadLibrary(muiPath); IntPtr hMui = LoadLibrary(muiPath);
if (hMui == null)
return "";
StringBuilder szString = new StringBuilder(MAX_PATH); StringBuilder szString = new StringBuilder(MAX_PATH);
LoadString(hMui, (uint)index, szString, MAX_PATH); LoadString(hMui, (uint)index, szString, MAX_PATH);
return szString.ToString(); return szString.ToString();
@@ -296,9 +294,9 @@ function Add-Entry([int]$pos, [string]$Name, [array]$Items, [string]$DisplayName
$XMLGrid.Children.Insert(2 * $Stage + 3, $Combo) $XMLGrid.Children.Insert(2 * $Stage + 3, $Combo)
$XMLForm.Height += $dh; $XMLForm.Height += $dh;
$Margin = $Confirm.Margin $Margin = $Continue.Margin
$Margin.Top += $dh $Margin.Top += $dh
$Confirm.Margin = $Margin $Continue.Margin = $Margin
$Margin = $Back.Margin $Margin = $Back.Margin
$Margin.Top += $dh $Margin.Top += $dh
$Back.Margin = $Margin $Back.Margin = $Margin
@@ -308,7 +306,7 @@ function Add-Entry([int]$pos, [string]$Name, [array]$Items, [string]$DisplayName
function Refresh-Control([object]$Control) function Refresh-Control([object]$Control)
{ {
$Control.Dispatcher.Invoke("Render", [Windows.Input.InputEventHandler] { $Confirm.UpdateLayout() }, $null, $null) $Control.Dispatcher.Invoke("Render", [Windows.Input.InputEventHandler] { $Continue.UpdateLayout() }, $null, $null)
} }
function Send-Message([string]$PipeName, [string]$Message) function Send-Message([string]$PipeName, [string]$Message)
@@ -316,7 +314,6 @@ function Send-Message([string]$PipeName, [string]$Message)
[System.Text.Encoding]$Encoding = [System.Text.Encoding]::UTF8 [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) $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 { try {
Write-Host Connecting to $PipeName
$Pipe.Connect(1000) $Pipe.Connect(1000)
} catch { } catch {
Write-Host $_.Exception.Message Write-Host $_.Exception.Message
@@ -373,17 +370,39 @@ function Get-Translation([string]$Text)
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) function Error([string]$ErrorMessage)
{ {
Write-Host $ErrorMessage Write-Host $ErrorMessage
$XMLForm.Title = $(Get-Translation("Error")) + ": " + $ErrorMessage $XMLForm.Title = $(Get-Translation("Error")) + ": " + $ErrorMessage
Refresh-Control($XMLForm) Refresh-Control($XMLForm)
$Confirm.Content = Get-Translation("Close") $Continue.Content = Get-Translation("Close")
Refresh-Control($Confirm) Refresh-Control($Continue)
$UserInput = [System.Windows.MessageBox]::Show($XMLForm.Title, $(Get-Translation("Error")), "OK", "Error") $UserInput = [System.Windows.MessageBox]::Show($XMLForm.Title, $(Get-Translation("Error")), "OK", "Error")
$script:ExitCode = $Stage $script:ExitCode = $Stage
$script:Stage = -1 $script:Stage = -1
$Confirm.IsEnabled = $True $Continue.IsEnabled = $True
}
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 #endregion
@@ -391,7 +410,7 @@ function Error([string]$ErrorMessage)
[xml]$XAML = @" [xml]$XAML = @"
<Window xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" Height = "162" Width = "384" ResizeMode = "NoResize"> <Window xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" Height = "162" Width = "384" ResizeMode = "NoResize">
<Grid Name = "XMLGrid"> <Grid Name = "XMLGrid">
<Button Name = "Confirm" FontSize = "16" Height = "26" Width = "160" HorizontalAlignment = "Left" VerticalAlignment = "Top" Margin = "14,78,0,0"/> <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"/> <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"/> <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"/> <ComboBox Name = "WindowsVersion" FontSize = "14" Height = "24" Width = "340" HorizontalAlignment = "Left" VerticalAlignment="Top" Margin = "14,34,0,0" SelectedIndex = "0"/>
@@ -408,23 +427,22 @@ $MaxStage = 4
$SessionId = "" $SessionId = ""
$ExitCode = -1 $ExitCode = -1
$Locale = "en-US" $Locale = "en-US"
$DFRCKey = "HKLM:\Software\Policies\Microsoft\Internet Explorer\Main\"
$DFRCName = "DisableFirstRunCustomize"
$DFRCAdded = $False
$RequestData = @{} $RequestData = @{}
$RequestData["GetLangs"] = @("a8f8f489-4c7f-463a-9ca6-5cff94d8d041", "GetSkuInformationByProductEdition" ) $RequestData["GetLangs"] = @("a8f8f489-4c7f-463a-9ca6-5cff94d8d041", "getskuinformationbyproductedition" )
$RequestData["GetLinks"] = @("cfa9e580-a81e-4a4b-a846-7b21bf4e2e5b", "GetProductDownloadLinksBySku" ) $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 #endregion
# Localization # Localization
$EnglishMessages = "en-US|Version|Release|Edition|Language|Architecture|Download|Confirm|Modify|Close|Cancel|Error|Please wait...|Download using a browser" $EnglishMessages = "en-US|Version|Release|Edition|Language|Architecture|Download|Continue|Back|Close|Cancel|Error|Please wait...|" +
if ($Testing) { "Download using a browser|Temporarily banned by Microsoft for requesting too many downloads - Please try again later...|" +
$LocData = "fr-FR|||Édition|Langue de produit||Télécharger|Confirmer|Modifier|Fermer|Annuler|Erreur|Veuillez patienter...|Télécharger avec un navigateur" "PowerShell 3.0 or later is required to run this script.|Do you want to go online and download it?"
$TestLangs = '{"languages":[
{ "language":"English", "text":"Anglais", "id":"100" },
{ "language":"English (International)", "text":"Anglais (International)", "id":"101" },
{ "language":"French", "text":"Français", "id":"102" },
{ "language":"French (Canadian)", "text":"Français (Canadien)", "id":"103" }
]}'
}
[string[]]$English = $EnglishMessages.Split('|') [string[]]$English = $EnglishMessages.Split('|')
[string[]]$Localized = $null [string[]]$Localized = $null
if ($LocData -and (-not $LocData.StartsWith("en-US"))) { if ($LocData -and (-not $LocData.StartsWith("en-US"))) {
@@ -436,6 +454,30 @@ if ($LocData -and (-not $LocData.StartsWith("en-US"))) {
$Locale = $Localized[0] $Locale = $Localized[0]
} }
# 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 -1
}
# 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 -ErrorActionPreference "Stop"
} 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 # Form creation
$XMLForm = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $XAML)) $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 } $XAML.SelectNodes("//*[@Name]") | ForEach-Object { Set-Variable -Name ($_.Name) -Value $XMLForm.FindName($_.Name) -Scope Script }
@@ -449,8 +491,8 @@ if ($Locale.StartsWith("ar") -or $Locale.StartsWith("fa") -or $Locale.StartsWit
$XMLForm.FlowDirection = "RightToLeft" $XMLForm.FlowDirection = "RightToLeft"
} }
$WindowsVersionTitle.Text = Get-Translation("Version") $WindowsVersionTitle.Text = Get-Translation("Version")
$Confirm.Content = Get-Translation("Confirm") $Continue.Content = Get-Translation("Continue")
$Back.Content = Get-Translation("Cancel") $Back.Content = Get-Translation("Close")
# Populate the Windows versions # Populate the Windows versions
$i = 0 $i = 0
@@ -463,16 +505,16 @@ $WindowsVersion.ItemsSource = $array
$WindowsVersion.DisplayMemberPath = "Version" $WindowsVersion.DisplayMemberPath = "Version"
# Button Action # Button Action
$Confirm.add_click({ $Continue.add_click({
if ($script:Stage++ -lt 0) { if ($script:Stage++ -lt 0) {
Get-Process -Id $pid | Foreach-Object { $_.CloseMainWindow() | Out-Null } Get-Process -Id $pid | Foreach-Object { $_.CloseMainWindow() | Out-Null }
return return
} }
$XMLGrid.Children[2 * $Stage + 1].IsEnabled = $False $XMLGrid.Children[2 * $Stage + 1].IsEnabled = $False
$Confirm.IsEnabled = $False $Continue.IsEnabled = $False
$Back.IsEnabled = $False $Back.IsEnabled = $False
Refresh-Control($Confirm) Refresh-Control($Continue)
Refresh-Control($Back) Refresh-Control($Back)
switch ($Stage) { switch ($Stage) {
@@ -485,21 +527,21 @@ $Confirm.add_click({
$url += $WindowsVersion.SelectedValue.PageType $url += $WindowsVersion.SelectedValue.PageType
Write-Host Querying $url Write-Host Querying $url
if (-not $Testing) { try {
try { # Note: We can't use -UseBasicParsing since we need JS to create the session-id
$r = Invoke-WebRequest -SessionVariable "Session" $url # TODO: Use -Headers @{"Cache-Control"="no-cache"}?
$script:SessionId = $r.ParsedHtml.IHTMLDocument3_GetElementById("session-id").Value $r = Invoke-WebRequest -UserAgent $UserAgent -SessionVariable "Session" $url
if (-not $SessionId) { $script:SessionId = $(GetElementById -Request $r -Id "session-id").Value
$ErrorMessage = $r.ParsedHtml.IHTMLDocument3_GetElementByID("errorModalMessage").innerHtml if (-not $SessionId) {
if ($ErrorMessage) { $ErrorMessage = $(GetElementById -Request $r -Id "errorModalMessage").InnerText
Write-Host "$(Get-Translation("Error")): ""$ErrorMessage""" if ($ErrorMessage) {
} Write-Host "$(Get-Translation("Error")): ""$ErrorMessage"""
throw "Could not read Session ID"
} }
} catch { throw "Could not read Session ID"
Error($_.Exception.Message)
return
} }
} catch {
Error($_.Exception.Message)
return
} }
$i = 0 $i = 0
@@ -530,8 +572,6 @@ $Confirm.add_click({
} }
3 { # Product Edition selection => Request and populate Languages 3 { # Product Edition selection => Request and populate Languages
# Get the Product Edition
$url = "https://www.microsoft.com/" + $Locale + "/api/controls/contentinclude/html" $url = "https://www.microsoft.com/" + $Locale + "/api/controls/contentinclude/html"
$url += "?pageId=" + $RequestData["GetLangs"][0] $url += "?pageId=" + $RequestData["GetLangs"][0]
$url += "&host=www.microsoft.com" $url += "&host=www.microsoft.com"
@@ -545,41 +585,35 @@ $Confirm.add_click({
$array = @() $array = @()
$i = 0 $i = 0
$SelectedIndex = 0 $SelectedIndex = 0
if (-not $Testing) { try {
try { $r = Invoke-WebRequest -UserAgent $UserAgent -WebSession $Session $url
$r = Invoke-WebRequest -WebSession $Session $url # Go through an XML conversion to keep all PowerShells happy...
foreach ($var in $r.ParsedHtml.IHTMLDocument3_GetElementByID("product-languages")) { if (-not $($r.AllElements | ? {$_.id -eq "product-languages"})) {
if ($Debug) { throw "Unexpected server response"
Write-Host $var.value $var.text
}
$json = $var.value | ConvertFrom-Json;
if ($json) {
$array += @(New-Object PsObject -Property @{ DisplayLanguage = $var.text; Language = $json.language; Id = $json.id })
if (Select-Language($json.language)) {
$SelectedIndex = $i
}
$i++
}
}
if ($array.Length -eq 0) {
$ErrorMessage = $r.ParsedHtml.IHTMLDocument3_GetElementByID("errorModalMessage").innerHtml
if ($ErrorMessage) {
Write-Host "$(Get-Translation("Error")): ""$ErrorMessage"""
}
throw "Could not parse languages"
}
} catch {
Error($_.Exception.Message)
return
} }
} else { $html = $($r.AllElements | ? {$_.id -eq "product-languages"}).InnerHTML
foreach ($var in $(ConvertFrom-Json InputObject $TestLangs).languages) { $html = "<options>" + $html.Replace("selected value", "value") + "</options>"
$array += @(New-Object PsObject -Property @{ DisplayLanguage = $var.text; Language = $var.language; Id = $var.id }) $xml = [xml]$html
if (Select-Language($var.language)) { foreach ($var in $xml.options.option) {
$SelectedIndex = $i $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++
} }
$i++
} }
if ($array.Length -eq 0) {
$ErrorMessage = $(GetElementById -Request $r -Id "errorModalMessage").innerText
if ($ErrorMessage) {
Write-Host "$(Get-Translation("Error")): ""$ErrorMessage"""
}
throw "Could not parse languages"
}
} catch {
Error($_.Exception.Message)
return
} }
$script:Language = Add-Entry $Stage "Language" $array "DisplayLanguage" $script:Language = Add-Entry $Stage "Language" $array "DisplayLanguage"
$Language.SelectedIndex = $SelectedIndex $Language.SelectedIndex = $SelectedIndex
@@ -600,12 +634,28 @@ $Confirm.add_click({
$i = 0 $i = 0
$SelectedIndex = 0 $SelectedIndex = 0
$array = @() $array = @()
if (-not $Testing) { try {
try { $r = Invoke-WebRequest -UserAgent $UserAgent -WebSession $Session $url
$r = Invoke-WebRequest -WebSession $Session $url if (-not $($r.AllElements | ? {$_.id -eq "expiration-time"})) {
foreach ($var in $r.ParsedHtml.IHTMLDocument3_GetElementsByTagName("span") | Where-Object { $_.className -eq "product-download-type" }) { $ErrorMessage = $(GetElementById -Request $r -Id "errorModalMessage").innerText
$Link = $var.ParentNode | Select -Expand href if ($ErrorMessage) {
$Type = $var.innerText Write-Host "$(Get-Translation("Error")): ""$ErrorMessage"""
}
throw Get-Translation($English[14])
}
$html = $($r.AllElements | ? {$_.tagname -eq "input"}).outerHTML
# Need to fix the HTML and JSON data so that it is well-formed
$html = $html.Replace("class=product-download-hidden", "")
$html = $html.Replace("type=hidden", "")
$html = $html.Replace(">", "/>")
$html = $html.Replace(": I", ": ""I")
$html = $html.Replace(" }", """ }")
$html = "<inputs>" + $html + "</inputs>"
$xml = [xml]$html
foreach ($var in $xml.inputs.input) {
$json = $var.value | ConvertFrom-Json;
if ($json) {
$Type = $json.DownloadType
# Maybe Microsoft will provide public ARM/ARM64 retail ISOs one day... # Maybe Microsoft will provide public ARM/ARM64 retail ISOs one day...
if ($Type -like "*arm64*") { if ($Type -like "*arm64*") {
$Type = "Arm64" $Type = "Arm64"
@@ -628,36 +678,29 @@ $Confirm.add_click({
$SelectedIndex = $i $SelectedIndex = $i
} }
} }
$array += @(New-Object PsObject -Property @{ Type = $Type; Link = $Link }) $array += @(New-Object PsObject -Property @{ Type = $Type; Link = $json.Uri })
$i++ $i++
} }
if ($array.Length -eq 0) { }
$ErrorMessage = $r.ParsedHtml.IHTMLDocument3_GetElementByID("errorModalMessage").innerHtml if ($array.Length -eq 0) {
if ($ErrorMessage) { $ErrorMessage = $(GetElementById -Request $r -Id "errorModalMessage").innerText
Write-Host "$(Get-Translation("Error")): ""$ErrorMessage""" if ($ErrorMessage) {
} Write-Host "$(Get-Translation("Error")): ""$ErrorMessage"""
throw "Could not retreive ISO download links"
} }
} catch { throw "Could not retreive ISO download links"
Error($_.Exception.Message)
return
}
} else {
$array += @(New-Object PsObject -Property @{ Type = "x86"; Link = "https://software-download.microsoft.com/sg/Win10_1809Oct_English_x86.iso" })
$i++
$array += @(New-Object PsObject -Property @{ Type = "x64"; Link = "https://software-download.microsoft.com/sg/Win10_1809Oct_English_x64.iso" })
if ($ENV:PROCESSOR_ARCHITECTURE -eq "AMD64") {
$SelectedIndex = $i
} }
} catch {
Error($_.Exception.Message)
return
} }
$script:Arch = Add-Entry $Stage "Architecture" $array "Type" $script:Arch = Add-Entry $Stage "Architecture" $array "Type"
if (($PipeName -or $Testing) -and $ShowBrowserOption) { if ($PipeName) {
$XMLForm.Height += $dh / 2; $XMLForm.Height += $dh / 2;
$Margin = $Confirm.Margin $Margin = $Continue.Margin
$top = $Margin.Top $top = $Margin.Top
$Margin.Top += $dh /2 $Margin.Top += $dh /2
$Confirm.Margin = $Margin $Continue.Margin = $Margin
$Margin = $Back.Margin $Margin = $Back.Margin
$Margin.Top += $dh / 2 $Margin.Top += $dh / 2
$Back.Margin = $Margin $Back.Margin = $Margin
@@ -668,7 +711,7 @@ $Confirm.add_click({
$Check.Visibility = "Visible" $Check.Visibility = "Visible"
} }
$Arch.SelectedIndex = $SelectedIndex $Arch.SelectedIndex = $SelectedIndex
$Confirm.Content = Get-Translation("Download") $Continue.Content = Get-Translation("Download")
} }
5 { # Arch selection => Return selected download link 5 { # Arch selection => Return selected download link
@@ -682,7 +725,7 @@ $Confirm.add_click({
$XMLForm.Close() $XMLForm.Close()
} }
} }
$Confirm.IsEnabled = $True $Continue.IsEnabled = $True
if ($Stage -ge 0) { if ($Stage -ge 0) {
$Back.IsEnabled = $True; $Back.IsEnabled = $True;
} }
@@ -696,44 +739,52 @@ $Back.add_click({
$XMLGrid.Children.RemoveAt(2 * $Stage + 2) $XMLGrid.Children.RemoveAt(2 * $Stage + 2)
$XMLGrid.Children[2 * $Stage + 1].IsEnabled = $True $XMLGrid.Children[2 * $Stage + 1].IsEnabled = $True
$dh2 = $dh $dh2 = $dh
if ($Stage -eq 4 -and $ShowBrowserOption) { if ($Stage -eq 4 -and $PipeName) {
$Check.Visibility = "Collapsed" $Check.Visibility = "Collapsed"
$dh2 += $dh / 2 $dh2 += $dh / 2
} }
$XMLForm.Height -= $dh2; $XMLForm.Height -= $dh2;
$Margin = $Confirm.Margin $Margin = $Continue.Margin
$Margin.Top -= $dh2 $Margin.Top -= $dh2
$Confirm.Margin = $Margin $Continue.Margin = $Margin
$Margin = $Back.Margin $Margin = $Back.Margin
$Margin.Top -= $dh2 $Margin.Top -= $dh2
$Back.Margin = $Margin $Back.Margin = $Margin
$script:Stage = $Stage - 1 $script:Stage = $Stage - 1
if ($Stage -eq 0) { if ($Stage -eq 0) {
$Back.Content = Get-Translation("Cancel") $Back.Content = Get-Translation("Close")
} elseif ($Stage -eq 3) { } elseif ($Stage -eq 3) {
$Confirm.Content = Get-Translation("Confirm") $Continue.Content = Get-Translation("Continue")
} }
} }
}) })
# We need a job in the background to close the obnoxious "Do you want to accept this cookie?" Windows alerts if (-not $PipeName) {
$ClosePrompt = { # We need a job in the background to close the obnoxious "Do you want to accept this cookie?" Windows alerts
param($PromptTitle) $ClosePrompt = {
while ($True) { param($PromptTitle)
Get-Process | Where-Object { $_.MainWindowTitle -match $PromptTitle } | ForEach-Object { $_.CloseMainWindow() } while ($True) {
Start-Sleep -Milliseconds 100 Get-Process | Where-Object { $_.MainWindowTitle -match $PromptTitle } | ForEach-Object { $_.CloseMainWindow() }
Start-Sleep -Milliseconds 100
}
} }
# Get the localized version of the 'Windows Security Warning' title of the cookie prompt
$SecurityWarningTitle = [Gui.Utils]::GetMuiString("urlmon.dll", 2070)
if (-not $SecurityWarningTitle) {
$SecurityWarningTitle = "Windows Security Warning"
}
$Job = Start-Job -ScriptBlock $ClosePrompt -ArgumentList $SecurityWarningTitle
} }
# Get the localized version of the 'Windows Security Warning' title of the cookie prompt
$SecurityWarningTitle = [Gui.Utils]::GetMuiString("urlmon.dll", 2070)
if (-not $SecurityWarningTitle) {
$SecurityWarningTitle = "Windows Security Warning"
}
$Job = Start-Job -ScriptBlock $ClosePrompt -ArgumentList $SecurityWarningTitle
# Display the dialog # Display the dialog
$XMLForm.Add_Loaded( { $XMLForm.Activate() } )
$XMLForm.ShowDialog() | Out-Null $XMLForm.ShowDialog() | Out-Null
# Clean up & exit # Clean up & exit
Stop-Job -Job $Job if (-not $PipeName) {
Stop-Job -Job $Job
}
if ($DFRCAdded) {
Remove-ItemProperty -Path $DFRCKey -Name $DFRCName
}
exit $ExitCode exit $ExitCode

30
sign.sh Normal file
View File

@@ -0,0 +1,30 @@
#!/bin/bash
# This script creates the RSA-2048 signatures for our downloadable content
PRIVATE_KEY=/d/Secured/Akeo/Rufus/private.pem
PUBLIC_KEY=/d/Secured/Akeo/Rufus/public.pem
# Create or update a signature
sign_file() {
if [ -f $FILE.sig ]; then
SIZE=$(stat -c%s $FILE.sig)
openssl dgst -sha256 -verify $PUBLIC_KEY -signature $FILE.sig $FILE >/dev/null 2>&1
if [ ! $? -eq 0 ]; then
echo Updating signature for $FILE
openssl dgst -sha256 -sign $PRIVATE_KEY -passin pass:$PASSWORD -out $FILE.sig $FILE
fi
else
# No signature => create a new one
echo Creating signature for $FILE
openssl dgst -sha256 -sign $PRIVATE_KEY -passin pass:$PASSWORD -out $FILE.sig $FILE
fi
}
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
openssl dgst -sha256 -sign $PRIVATE_KEY -passin pass:$PASSWORD $PUBLIC_KEY >/dev/null 2>&1 || { echo Invalid pass phrase; exit 1; }
find . -maxdepth 1 -name "*.ps1" | while read FILE; do sign_file; done
# Clear the PASSWORD variable just in case
PASSWORD=`head -c 50 /dev/random | base64`